watcher.decision_engine.model.collector.cinder

Source code for watcher.decision_engine.model.collector.cinder

# -*- encoding: utf-8 -*-
# Copyright 2017 NEC Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import six

from oslo_log import log

from watcher.common import cinder_helper
from watcher.common import exception
from watcher.decision_engine.model.collector import base
from watcher.decision_engine.model import element
from watcher.decision_engine.model import model_root
from watcher.decision_engine.model.notification import cinder

LOG = log.getLogger(__name__)


[docs]class CinderClusterDataModelCollector(base.BaseClusterDataModelCollector): """Cinder cluster data model collector The Cinder cluster data model collector creates an in-memory representation of the resources exposed by the storage service. """ def __init__(self, config, osc=None): super(CinderClusterDataModelCollector, self).__init__(config, osc) @property def notification_endpoints(self): """Associated notification endpoints :return: Associated notification endpoints :rtype: List of :py:class:`~.EventsNotificationEndpoint` instances """ return [ cinder.CapacityNotificationEndpoint(self), cinder.VolumeCreateEnd(self), cinder.VolumeDeleteEnd(self), cinder.VolumeUpdateEnd(self), cinder.VolumeAttachEnd(self), cinder.VolumeDetachEnd(self), cinder.VolumeResizeEnd(self) ]
[docs] def execute(self): """Build the storage cluster data model""" LOG.debug("Building latest Cinder cluster data model") builder = ModelBuilder(self.osc) return builder.execute()
[docs]class ModelBuilder(object): """Build the graph-based model This model builder adds the following data" - Storage-related knowledge (Cinder) """ def __init__(self, osc): self.osc = osc self.model = model_root.StorageModelRoot() self.cinder = osc.cinder() self.cinder_helper = cinder_helper.CinderHelper(osc=self.osc) def _add_physical_layer(self): """Add the physical layer of the graph. This includes components which represent actual infrastructure hardware. """ for snode in self.cinder_helper.get_storage_node_list(): self.add_storage_node(snode) for pool in self.cinder_helper.get_storage_pool_list(): pool = self._build_storage_pool(pool) self.model.add_pool(pool) storage_name = getattr(pool, 'name') try: storage_node = self.model.get_node_by_name( storage_name) # Connect the instance to its compute node self.model.map_pool(pool, storage_node) except exception.StorageNodeNotFound: continue
[docs] def add_storage_node(self, node): # Build and add base node. storage_node = self.build_storage_node(node) self.model.add_node(storage_node)
[docs] def add_storage_pool(self, pool): storage_pool = self._build_storage_pool(pool) self.model.add_pool(storage_pool)
[docs] def build_storage_node(self, node): """Build a storage node from a Cinder storage node :param node: A storage node :type node: :py:class:`~cinderclient.v2.services.Service` """ # node.host is formatted as host@backendname since ocata, # or may be only host as of ocata backend = "" try: backend = node.host.split('@')[1] except IndexError: pass volume_type = self.cinder_helper.get_volume_type_by_backendname( backend) # build up the storage node. node_attributes = { "host": node.host, "zone": node.zone, "state": node.state, "status": node.status, "volume_type": volume_type} storage_node = element.StorageNode(**node_attributes) return storage_node
def _build_storage_pool(self, pool): """Build a storage pool from a Cinder storage pool :param pool: A storage pool :type pool: :py:class:`~cinderlient.v2.capabilities.Capabilities` """ # build up the storage pool. node_attributes = { "name": pool.name, "total_volumes": pool.total_volumes, "total_capacity_gb": pool.total_capacity_gb, "free_capacity_gb": pool.free_capacity_gb, "provisioned_capacity_gb": pool.provisioned_capacity_gb, "allocated_capacity_gb": pool.allocated_capacity_gb} storage_pool = element.Pool(**node_attributes) return storage_pool def _add_virtual_layer(self): """Add the virtual layer to the graph. This layer is the virtual components of the infrastructure. """ self._add_virtual_storage() def _add_virtual_storage(self): volumes = self.cinder_helper.get_volume_list() for vol in volumes: volume = self._build_volume_node(vol) self.model.add_volume(volume) pool_name = getattr(vol, 'os-vol-host-attr:host') if pool_name is None: # The volume is not attached to any pool continue try: pool = self.model.get_pool_by_pool_name( pool_name) self.model.map_volume(volume, pool) except exception.PoolNotFound: continue def _build_volume_node(self, volume): """Build an volume node Create an volume node for the graph using cinder and the `volume` cinder object. :param instance: Cinder Volume object. :return: A volume node for the graph. """ attachments = [{k: v for k, v in six.iteritems(d) if k in ( 'server_id', 'attachment_id')} for d in volume.attachments] volume_attributes = { "uuid": volume.id, "size": volume.size, "status": volume.status, "attachments": attachments, "name": volume.name or "", "multiattach": volume.multiattach, "snapshot_id": volume.snapshot_id or "", "project_id": getattr(volume, 'os-vol-tenant-attr:tenant_id'), "metadata": volume.metadata, "bootable": volume.bootable} return element.Volume(**volume_attributes)
[docs] def execute(self): """Instantiates the graph with the openstack cluster data. The graph is populated along 2 layers: virtual and physical. As each new layer is built connections are made back to previous layers. """ self._add_physical_layer() self._add_virtual_layer() return self.model
Creative Commons Attribution 3.0 License

Except where otherwise noted, this document is licensed under Creative Commons Attribution 3.0 License. See all OpenStack Legal Documents.