
All the flake8 issues have been resolved with this commit. Change-Id: I637f82c484b3dbecc4827731a13f79c2ba2b9240 Closes-Bug: #1346759
831 lines
32 KiB
Python
831 lines
32 KiB
Python
# Copyright 2013 IBM Corp.
|
|
import logging
|
|
import exception
|
|
import os
|
|
import sys
|
|
import threading
|
|
import time
|
|
|
|
from eventlet.semaphore import Semaphore
|
|
from glanceclient.openstack.common import importutils
|
|
from powervc.common import config
|
|
from powervc.common import constants
|
|
from powervc.common.exception import StorageConnectivityGroupNotFound
|
|
from powervc.common.gettextutils import _
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
CONF = config.CONF
|
|
DEFAULT_TTL = 600
|
|
|
|
|
|
class TimeLivedCache(object):
|
|
"""
|
|
The base class to provide the functionality of a timed cache.
|
|
The default refresh time is 10 mins.
|
|
"""
|
|
def __init__(self, ttl=DEFAULT_TTL):
|
|
self._cache = {}
|
|
self._last_updated = -1
|
|
self._lock = threading.Lock()
|
|
self.ttl = ttl
|
|
|
|
def _cache_resources(self):
|
|
"""
|
|
Refreshes the cached values if the cached time has expired,
|
|
or if there are no cached values.
|
|
"""
|
|
now = round(time.time())
|
|
if now - self._last_updated < self.ttl and len(self._cache) != 0:
|
|
return
|
|
with self._lock:
|
|
if now - self._last_updated < self.ttl:
|
|
return
|
|
self._cache = self._get_cache()
|
|
LOG.debug(_("Updated %s at %s. Last update: %s") %
|
|
(str(self), now, self._last_updated))
|
|
self._last_updated = now
|
|
|
|
def _get_cache(self):
|
|
tmp_cache = {}
|
|
resources = self._get_resources()
|
|
if resources:
|
|
for resource in resources:
|
|
tmp_cache[self._id_for_resource(resource)] = resource
|
|
return tmp_cache
|
|
|
|
def list(self):
|
|
"""
|
|
Returns the cached values
|
|
"""
|
|
self._cache_resources()
|
|
return self._cache.values()
|
|
|
|
def _id_for_resource(self, resource):
|
|
raise NotImplementedError()
|
|
|
|
def _get_resources(self):
|
|
raise NotImplementedError()
|
|
|
|
|
|
class GreenTimeLivedCache(TimeLivedCache):
|
|
"""
|
|
Extend the TimeLivedCache to use green thread.
|
|
"""
|
|
def __init__(self, ttl=DEFAULT_TTL):
|
|
super(GreenTimeLivedCache, self).__init__(ttl)
|
|
# Replace with the semaphore.
|
|
self._lock = Semaphore()
|
|
|
|
|
|
class VolumeCache(GreenTimeLivedCache):
|
|
"""
|
|
Caches the volumes
|
|
"""
|
|
def __init__(self, driver, ttl=DEFAULT_TTL):
|
|
assert driver
|
|
self._driver = driver
|
|
super(VolumeCache, self).__init__(ttl)
|
|
|
|
def _get_resources(self):
|
|
return self._driver.cache_volume_data()
|
|
|
|
def _get_cache(self):
|
|
return self._get_resources()
|
|
|
|
def set_by_id(self, pvc_id, local_id):
|
|
with self._lock:
|
|
self._cache[pvc_id] = local_id
|
|
|
|
def get_by_id(self, pvc_id, default=None):
|
|
self._cache_resources()
|
|
if (len(self._cache) != 0):
|
|
if pvc_id in self._cache:
|
|
LOG.info(_("Found volume id equals: '%s'" % pvc_id))
|
|
return self._cache[pvc_id]
|
|
LOG.info(_("No volume found which equals: '%s'" % pvc_id))
|
|
return default
|
|
|
|
|
|
class SCGCache(GreenTimeLivedCache):
|
|
"""
|
|
Caches the SCGs.
|
|
"""
|
|
def __init__(self, nova, ttl=DEFAULT_TTL):
|
|
assert nova
|
|
self._nova = nova
|
|
super(SCGCache, self).__init__(ttl)
|
|
|
|
def __str__(self):
|
|
return _("Storage Connectivity Group Cache")
|
|
|
|
def _id_for_resource(self, resource):
|
|
return resource.display_name
|
|
|
|
def _get_resources(self):
|
|
"""
|
|
Calls the api to get all SCGs
|
|
"""
|
|
return self._nova.storage_connectivity_groups.list(detailed=True)
|
|
|
|
def by_name(self, name, default=None):
|
|
"""
|
|
Returns the SCG by name
|
|
"""
|
|
self._cache_resources()
|
|
if (len(self._cache) != 0):
|
|
if name in self._cache:
|
|
LOG.info(_("Found scg which name equals: '%s'" % name))
|
|
return self._cache[name]
|
|
LOG.info(_("No scg found which equals name: '%s'" % name))
|
|
return default
|
|
|
|
def by_id(self, scg_id, default=None):
|
|
"""
|
|
Returns the SCG by id
|
|
"""
|
|
self._cache_resources()
|
|
if (len(self._cache) != 0):
|
|
for scg in self.list():
|
|
if scg.id == scg_id:
|
|
LOG.info(_("Found scg which equals id: '%s'" % scg_id))
|
|
return scg
|
|
LOG.info(_("No scg found which equals id: '%s'" % scg_id))
|
|
return default
|
|
|
|
__lock = threading.Lock()
|
|
__utils = None
|
|
|
|
|
|
def get_utils():
|
|
"""
|
|
Returns a singleton Utils object
|
|
"""
|
|
global __lock
|
|
global __utils
|
|
if __utils is not None:
|
|
return __utils
|
|
with __lock:
|
|
if __utils is not None:
|
|
return __utils
|
|
__utils = Utils()
|
|
return __utils
|
|
|
|
|
|
class Utils(object):
|
|
"""
|
|
This Utils class leverages the pvcnovaclient and pvccinderclient
|
|
to retrieve the Storage Connectivity Group, Storage Providers and
|
|
Storage Templates information, etc.
|
|
|
|
Usage sample:
|
|
username = 'root'
|
|
password = 'passw0rd'
|
|
tenant = 'ibm-default'
|
|
auth_url = 'https://z3-9-5-127-193.rch.nimbus.kstart.ibm.com/\
|
|
powervc/openstack/admin/v3'
|
|
cacert = '/home/osadmin/z3-9-5-127-193.rch.nimbus.kstart.ibm.com'
|
|
|
|
utils = utils.Utils(username=username,
|
|
api_key=password,
|
|
project_id=tenant,
|
|
auth_url=auth_url,
|
|
insecure=False,
|
|
cacert=cacert)
|
|
sps = utils.get_scg_accessible_storage_providers()
|
|
sts = utils.get_scg_accessible_storage_templates()
|
|
volumes = utils.get_scg_accessible_volumes()
|
|
"""
|
|
def __init__(self):
|
|
factory = importutils.import_module('powervc.common.client.factory')
|
|
self._novaclient = factory.POWERVC.new_client(
|
|
str(constants.SERVICE_TYPES.compute))
|
|
self._cinderclient = factory.POWERVC.new_client(
|
|
str(constants.SERVICE_TYPES.volume))
|
|
self._localkeystoneclient = factory.LOCAL.new_client(
|
|
str(constants.SERVICE_TYPES.identity))
|
|
self.scg_cache = self.get_scg_cache(self._novaclient)
|
|
|
|
def get_scg_cache(self, novaclient):
|
|
"""
|
|
Return the SCGCache object.
|
|
"""
|
|
return SCGCache(novaclient)
|
|
|
|
def get_all_scgs(self):
|
|
"""
|
|
Get all Storage Connectivity Groups from PowerVC
|
|
|
|
:returns: A list of all Storage Connectivity Groups on PowerVC
|
|
"""
|
|
return self.scg_cache.list()
|
|
|
|
def get_our_scg_list(self):
|
|
"""
|
|
If SCG names are specified in our configuration, see if the scgs exist.
|
|
If they do not exist, raise an exception. If they exist, return the scg
|
|
list for the name specified. If no SCG name is specified, return
|
|
[] for the scg list.
|
|
|
|
:returns: The StorageConnectivityGroup object list if found, else []
|
|
:raise StorageConnectivityGroupNotFound: if the Storage Connectivity
|
|
Groups could not be found on PowerVC
|
|
"""
|
|
our_scg_list = []
|
|
scg_to_use_list = CONF['powervc'].storage_connectivity_group
|
|
for scg_to_use in scg_to_use_list:
|
|
if scg_to_use:
|
|
scg = self.scg_cache.by_name(scg_to_use)
|
|
if scg is not None:
|
|
LOG.debug(_('PowerVC Storage Connectivity Group \'%s\' '
|
|
'found.'), scg.display_name)
|
|
our_scg = scg
|
|
our_scg_list.append(our_scg)
|
|
else:
|
|
# If a SCG is specified and it's not found on the PowerVC,
|
|
# raise an exception.
|
|
LOG.error(_('The PowerVC Storage Connectivity Group'
|
|
' \'%s\' was not found.'), scg_to_use)
|
|
raise StorageConnectivityGroupNotFound(scg=scg_to_use)
|
|
else:
|
|
LOG.error(_('No Storage Connectivity Group is specified in '
|
|
'the configuration settings.'))
|
|
return our_scg_list
|
|
|
|
def validate_scgs(self):
|
|
"""
|
|
Validate the SCG name specified in the configuration,
|
|
Return validated SCG list if successful
|
|
Return [] if SCGs are not specified in the configuration file OR
|
|
SCG specified is not found in PowerVC.
|
|
"""
|
|
validated_scgs = []
|
|
try:
|
|
validated_scgs = self.get_our_scg_list()
|
|
except StorageConnectivityGroupNotFound:
|
|
return []
|
|
return validated_scgs
|
|
|
|
def get_scg_by_scgName(self, scg_name):
|
|
"""
|
|
Get the SCG by scgName
|
|
"""
|
|
return self.scg_cache.by_name(scg_name)
|
|
|
|
def get_scg_by_scgUUID(self, scg_uuid):
|
|
"""
|
|
Get the SCG by uuid
|
|
"""
|
|
return self.scg_cache.by_id(scg_uuid)
|
|
|
|
def get_scg_id_by_scgName(self, scg_name):
|
|
"""
|
|
Get the SCG_ID by scg_name
|
|
"""
|
|
if scg_name == "":
|
|
return ""
|
|
# If no scg_name is found, None is returned.
|
|
scg = self.get_scg_by_scgName(scg_name)
|
|
if scg is not None:
|
|
return scg.id
|
|
return ""
|
|
|
|
def get_multi_scg_accessible_servers(self, scg_uuid_list, scg_name_list,
|
|
detailed=True, search_opts=None):
|
|
"""
|
|
Get accessible virtual servers by specified SCG UUID list
|
|
or SCG Name list,
|
|
If both SCG UUID and SCG Name are specified specified, UUID is prior,
|
|
If none of SCG UUID and Name specified, get all servers
|
|
"""
|
|
class WrapServer():
|
|
def __init__(self, server):
|
|
self.server = server
|
|
|
|
def __eq__(self, other):
|
|
if isinstance(other, WrapServer):
|
|
return self.server.id == other.server.id
|
|
else:
|
|
return False
|
|
|
|
def __hash__(self):
|
|
return hash(self.server.id)
|
|
|
|
wrap_servers = set()
|
|
if scg_uuid_list:
|
|
for scg_uuid in scg_uuid_list:
|
|
scg_servers = self.get_scg_accessible_servers(scg_uuid,
|
|
None,
|
|
detailed,
|
|
search_opts)
|
|
wrap_scg_servers = [WrapServer(scg_server)
|
|
for scg_server in scg_servers]
|
|
wrap_servers.update(wrap_scg_servers)
|
|
return [wrap_server.server for wrap_server in wrap_servers]
|
|
|
|
if not scg_name_list:
|
|
scg_name_list = CONF.powervc.storage_connectivity_group
|
|
|
|
if scg_name_list:
|
|
for scg_name in scg_name_list:
|
|
scg_servers = self.get_scg_accessible_servers(None,
|
|
scg_name,
|
|
detailed,
|
|
search_opts)
|
|
wrap_scg_servers = [WrapServer(scg_server)
|
|
for scg_server in scg_servers]
|
|
wrap_servers.update(wrap_scg_servers)
|
|
return [wrap_server.server for wrap_server in wrap_servers]
|
|
|
|
def get_scg_accessible_servers(self, scgUUID=None, scgName=None,
|
|
detailed=True, search_opts=None):
|
|
"""
|
|
Get accessible virtual servers by specified SCG UUID or scgName,
|
|
If both SCG UUID and SCG Name are specified specified, UUID is prior,
|
|
If none of SCG UUID and Name specified, get all servers
|
|
"""
|
|
scg = None
|
|
# If no scgUUID specified.
|
|
if not scgUUID:
|
|
if scgName:
|
|
# If scgName specified, then search by scgName
|
|
scg = self.get_scg_by_scgName(scgName)
|
|
else:
|
|
# If scgName not specified, return None
|
|
scg = None
|
|
else:
|
|
LOG.debug("Specified scgUUID: '%s'" % scgUUID)
|
|
# retrieve scg by scgUUID
|
|
scg = self.scg_cache.by_id(scgUUID)
|
|
|
|
if not scg:
|
|
# If no scg, then it's a IVM based PowerVC,
|
|
# return all servers
|
|
return self._novaclient.manager.list_all_servers(
|
|
detailed, search_opts)
|
|
|
|
# accessible_storage_servers to return
|
|
accessible_storage_servers = []
|
|
all_servers = self._novaclient.manager.list_all_servers(
|
|
detailed, search_opts)
|
|
|
|
# Filter the servers for the SCG
|
|
for server in all_servers:
|
|
server_scg = getattr(server, 'storage_connectivity_group_id', None)
|
|
if server_scg and server_scg == scg.id:
|
|
accessible_storage_servers.append(server)
|
|
elif server_scg is None:
|
|
# onboarding VMs
|
|
accessible_storage_servers.append(server)
|
|
|
|
LOG.info("All accessible_storage_servers: %s" %
|
|
accessible_storage_servers)
|
|
|
|
return accessible_storage_servers
|
|
|
|
def get_multi_scg_accessible_storage_providers(self,
|
|
scg_uuid_list,
|
|
scg_name_list,
|
|
detailed=True,
|
|
search_opts=None):
|
|
"""
|
|
Get accessible storage providers by specified SCG UUID list
|
|
or SCG Name list,
|
|
If both SCG UUID and SCG Name are specified specified, UUID is prior,
|
|
"""
|
|
class WrapProvider():
|
|
def __init__(self, provider):
|
|
self.provider = provider
|
|
|
|
def __eq__(self, other):
|
|
if isinstance(other, WrapProvider):
|
|
return self.provider.id == other.provider.id
|
|
else:
|
|
return False
|
|
|
|
def __hash__(self):
|
|
return hash(self.provider.id)
|
|
|
|
wrap_providers = set()
|
|
if scg_uuid_list:
|
|
for scg_uuid in scg_uuid_list:
|
|
scg_providers = self.get_scg_accessible_storage_providers(
|
|
scg_uuid, None, detailed, search_opts)
|
|
wrap_scg_providers = [WrapProvider(scg_provider)
|
|
for scg_provider in scg_providers]
|
|
wrap_providers.update(wrap_scg_providers)
|
|
return [wrap_provider.provider for wrap_provider in wrap_providers]
|
|
|
|
if not scg_name_list:
|
|
scg_name_list = CONF.powervc.storage_connectivity_group
|
|
|
|
if scg_name_list:
|
|
for scg_name in scg_name_list:
|
|
scg_providers = self.get_scg_accessible_storage_providers(
|
|
None, scg_name, detailed, search_opts)
|
|
wrap_scg_providers = [WrapProvider(scg_provider)
|
|
for scg_provider in scg_providers]
|
|
wrap_providers.update(wrap_scg_providers)
|
|
return [wrap_provider.provider for wrap_provider in wrap_providers]
|
|
|
|
def get_scg_accessible_storage_providers(self, scgUUID=None, scgName=None,
|
|
detailed=True, search_opts=None):
|
|
"""
|
|
Get accessible storage providers by specified SCG UUID or scgName,
|
|
If both SCG UUID and SCG Name are specified specified, UUID is prior,
|
|
If none of SCG UUID and Name specified, get the first SCG from powerVC
|
|
"""
|
|
scg = None
|
|
# If no scgUUID specified.
|
|
if not scgUUID:
|
|
if scgName:
|
|
# If scgName specified, then search by scgName
|
|
scg = self.get_scg_by_scgName(scgName)
|
|
else:
|
|
# If scgName not specified, return None
|
|
scg = None
|
|
else:
|
|
LOG.debug(_("Specified scgUUID: '%s'" % scgUUID))
|
|
# retrieve scg by scgUUID
|
|
scg = self.scg_cache.by_id(scgUUID)
|
|
|
|
if not scg:
|
|
# If no scg, then it's a IVM based PowerVC,
|
|
# return all storage providers
|
|
return (self._cinderclient.storage_providers.
|
|
list_all_providers(detailed, search_opts))
|
|
|
|
# accessible_storage_providers to return
|
|
accessible_storage_providers = []
|
|
|
|
# retrieve fc_storage_access
|
|
fc_storage_access = getattr(scg, 'fc_storage_access', False) or False
|
|
LOG.info(_("scg['fc_storage_access']: '%s'" % fc_storage_access))
|
|
|
|
# retrieve provider_id in vios_cluster
|
|
provider_id = None
|
|
vios_cluster = getattr(scg, 'vios_cluster', {})
|
|
if vios_cluster:
|
|
provider_id = vios_cluster.get('provider_id', '')
|
|
LOG.info(_("scg['vios_cluster']['provider_id']: '%s'" %
|
|
(provider_id)))
|
|
|
|
# retrieve all the storage-providers
|
|
storage_providers = (self._cinderclient.storage_providers.
|
|
list_all_providers(detailed, search_opts))
|
|
LOG.info(_("storage_providers: %s" % storage_providers))
|
|
# Loop over the storage providers, if the 'storage_hostname' matches
|
|
# SCG['vios_cluster']['provider_id'], or if SCG['fc_storage_access']
|
|
# is "True" AND the provider's storage_type is "fc", then add to list
|
|
for storage_provider in storage_providers:
|
|
storage_hostname = getattr(storage_provider,
|
|
'storage_hostname', '')
|
|
storage_type = getattr(storage_provider,
|
|
'storage_type', '')
|
|
LOG.info(_("storage_provider['storage_hostname']: '%s'" %
|
|
(storage_hostname)))
|
|
if storage_hostname and storage_hostname == provider_id:
|
|
LOG.info(_("Add to accessible_storage_providers: %s" %
|
|
(storage_provider)))
|
|
accessible_storage_providers.append(storage_provider)
|
|
elif fc_storage_access and (constants.SCG_SUPPORTED_STORAGE_TYPE ==
|
|
storage_type):
|
|
LOG.info(_("Add to accessible_storage_providers: %s" %
|
|
(storage_provider)))
|
|
accessible_storage_providers.append(storage_provider)
|
|
# TODO as currently provider_id and storage_type are not
|
|
# implemented
|
|
else:
|
|
accessible_storage_providers.append(storage_provider)
|
|
|
|
LOG.info(_("All accessible_storage_providers: %s" %
|
|
(accessible_storage_providers)))
|
|
|
|
return accessible_storage_providers
|
|
|
|
def get_multi_scg_accessible_storage_templates(self,
|
|
scg_uuid_list,
|
|
scg_name_list):
|
|
"""
|
|
Get accessible storage templates by specified SCG UUID list
|
|
or SCG Name list,
|
|
If both SCG UUID and SCG Name are specified specified, UUID is prior,
|
|
"""
|
|
class WrapType():
|
|
def __init__(self, volume_type):
|
|
self.type = volume_type
|
|
|
|
def __eq__(self, other):
|
|
if isinstance(other, WrapType):
|
|
return self.type.id == other.type.id
|
|
else:
|
|
return False
|
|
|
|
def __hash__(self):
|
|
return hash(self.type.id)
|
|
|
|
wrap_types = set()
|
|
if scg_uuid_list:
|
|
for scg_uuid in scg_uuid_list:
|
|
scg_types = self.get_scg_accessible_storage_templates(
|
|
scg_uuid, None)
|
|
wrap_scg_types = [WrapType(scg_type) for scg_type in scg_types]
|
|
wrap_types.update(wrap_scg_types)
|
|
return [wrap_type.type for wrap_type in wrap_types]
|
|
|
|
if not scg_name_list:
|
|
scg_name_list = CONF.powervc.storage_connectivity_group
|
|
|
|
if scg_name_list:
|
|
for scg_name in scg_name_list:
|
|
scg_types = self.get_scg_accessible_storage_templates(
|
|
None, scg_name)
|
|
wrap_scg_types = [WrapType(scg_type) for scg_type in scg_types]
|
|
wrap_types.update(wrap_scg_types)
|
|
return [wrap_type.type for wrap_type in wrap_types]
|
|
|
|
def get_scg_accessible_storage_templates(self, scgUUID=None, scgName=None):
|
|
"""
|
|
Get accessible storage templates by specified SCG UUID or scgName,
|
|
If both SCG UUID and SCG Name are specified specified, UUID is prior,
|
|
If none of SCG UUID and Name specified, get the first SCG from powerVC
|
|
"""
|
|
scg = None
|
|
# If no scgUUID specified.
|
|
if not scgUUID:
|
|
if scgName:
|
|
# If scgName specified, then search by scgName
|
|
scg = self.get_scg_by_scgName(scgName)
|
|
else:
|
|
# If scgName not specified, get the SCG from the value
|
|
# configured in powervc.conf
|
|
scg = self.get_configured_scg()
|
|
else:
|
|
LOG.debug(_("Specified scgUUID: '%s'" % scgUUID))
|
|
# retrieve scg by scgUUID
|
|
scg = self.scg_cache.by_id(scgUUID)
|
|
if not scg:
|
|
# If no scg, then it's a IVM based PowerVC,
|
|
# return all volumes
|
|
return (self._cinderclient.volume_types.
|
|
list_all_storage_templates())
|
|
|
|
# accessible_storage_templates to return
|
|
accessible_storage_templates = []
|
|
#filter out all the accessible storage template uuid
|
|
volume_types = scg.list_all_volume_types()
|
|
volume_type_ids = []
|
|
for vol_type in volume_types:
|
|
volume_type_ids.append(vol_type.__dict__.get("id"))
|
|
all_volume_types = \
|
|
self._cinderclient.volume_types.list_all_storage_templates()
|
|
for storage_template in all_volume_types:
|
|
if(storage_template.__dict__.get("id") in volume_type_ids):
|
|
accessible_storage_templates.append(storage_template)
|
|
|
|
LOG.info(_('accessible_storage_templates: %s' %
|
|
(accessible_storage_templates)))
|
|
return accessible_storage_templates
|
|
|
|
def get_multi_scg_accessible_volumes(self,
|
|
scg_uuid_list,
|
|
scg_name_list,
|
|
detailed=True,
|
|
search_opts=None):
|
|
"""
|
|
Get accessible storage providers by specified SCG UUID list
|
|
or SCG Name list,
|
|
If both SCG UUID and SCG Name are specified specified, UUID is prior,
|
|
"""
|
|
class WrapVolume():
|
|
def __init__(self, volume):
|
|
self.volume = volume
|
|
|
|
def __eq__(self, other):
|
|
if isinstance(other, WrapVolume):
|
|
return self.volume.id == other.volume.id
|
|
else:
|
|
return False
|
|
|
|
def __hash__(self):
|
|
return hash(self.volume.id)
|
|
|
|
wrap_volumes = set()
|
|
if scg_uuid_list:
|
|
for scg_uuid in scg_uuid_list:
|
|
scg_volumes = self.get_scg_accessible_volumes(scg_uuid,
|
|
None,
|
|
detailed,
|
|
search_opts)
|
|
wrap_scg_volumes = [WrapVolume(scg_volume)
|
|
for scg_volume in scg_volumes]
|
|
wrap_volumes.update(wrap_scg_volumes)
|
|
return [wrap_volume.volume for wrap_volume in wrap_volumes]
|
|
|
|
if not scg_name_list:
|
|
scg_name_list = CONF.powervc.storage_connectivity_group
|
|
|
|
if scg_name_list:
|
|
for scg_name in scg_name_list:
|
|
scg_volumes = self.get_scg_accessible_volumes(None,
|
|
scg_name,
|
|
detailed,
|
|
search_opts)
|
|
wrap_scg_volumes = [WrapVolume(scg_volume)
|
|
for scg_volume in scg_volumes]
|
|
wrap_volumes.update(wrap_scg_volumes)
|
|
return [wrap_volume.volume for wrap_volume in wrap_volumes]
|
|
|
|
def get_scg_accessible_volumes(self, scgUUID=None, scgName=None,
|
|
detailed=True, search_opts=None):
|
|
"""
|
|
Get SCG accessible volumes providers by specified SCG UUID or scgName,
|
|
If both SCG UUID and SCG Name are specified specified, UUID is prior,
|
|
If none of SCG UUID and Name specified, get the first SCG from powerVC
|
|
"""
|
|
scg = None
|
|
# If no scgUUID specified.
|
|
if not scgUUID:
|
|
if scgName:
|
|
# If scgName specified, then search by scgName
|
|
scg = self.get_scg_by_scgName(scgName)
|
|
else:
|
|
# If scgName not specified, get the SCG from the value
|
|
# configured in powervc.conf
|
|
scg = self.get_configured_scg()
|
|
else:
|
|
LOG.debug(_("Specified scgUUID: '%s'" % scgUUID))
|
|
# retrieve scg by scgUUID
|
|
scg = self.scg_cache.by_id(scgUUID)
|
|
if not scg:
|
|
# If no scg, then it's a IVM based PowerVC,
|
|
# return all volumes
|
|
return (self._cinderclient.volumes.list_all_volumes())
|
|
|
|
# accessible_storage_volumes to return
|
|
accessible_storage_volumes = []
|
|
volumes = scg.list_all_volumes()
|
|
volume_ids = []
|
|
for vol in volumes:
|
|
volume_ids.append(vol.__dict__.get("id"))
|
|
all_volumes = \
|
|
self._cinderclient.volumes.list_all_volumes(detailed, search_opts)
|
|
for storage_volume in all_volumes:
|
|
if(storage_volume.__dict__.get("id") in volume_ids):
|
|
metadata = storage_volume.__dict__.get("metadata")
|
|
if(metadata is not None):
|
|
is_boot_volume = metadata.get("is_boot_volume")
|
|
# Filter out the boot volumes
|
|
if(is_boot_volume != "True"):
|
|
accessible_storage_volumes.append(storage_volume)
|
|
else:
|
|
accessible_storage_volumes.append(storage_volume)
|
|
|
|
LOG.info(_('accessible_storage_volumes: %s' % (
|
|
accessible_storage_volumes)))
|
|
return accessible_storage_volumes
|
|
|
|
def get_image_scgs(self, imageUUID):
|
|
"""
|
|
Get the Storage Connectivity Groups for the specified image.
|
|
|
|
:param: imageUUID The UUID of the image
|
|
:returns: The Storage Connectivity Groups for the specified image or an
|
|
empty list if none are found.
|
|
"""
|
|
if imageUUID is not None:
|
|
return self._novaclient.storage_connectivity_groups.list_for_image(
|
|
imageUUID)
|
|
else:
|
|
return []
|
|
|
|
def get_scg_image_ids(self, scgUUID):
|
|
"""
|
|
Get the SCGImage identifiers for the specified Storage Connectivity
|
|
Group.
|
|
|
|
:param: scgUUID The UUID of the StorageConnectvityGroup
|
|
:returns: The list of SCGImage identifiers for the specified Storage
|
|
Connectivity Group or an empty list if none are found.
|
|
"""
|
|
if scgUUID is not None:
|
|
return self._novaclient.scg_images.list_ids(scgUUID)
|
|
else:
|
|
return []
|
|
|
|
def get_local_staging_project_id(self):
|
|
"""
|
|
Get the local hosting OS staging project Id. If a staging
|
|
project name is not found, a exception.StagingProjectNotFound
|
|
exception will be raised. If no staging project is specified in
|
|
the conf, the default value will be used as specified in constants.
|
|
|
|
:returns: The local hosting OS staging project Id
|
|
"""
|
|
ks_client = self._localkeystoneclient
|
|
stagingname = CONF.powervc.staging_project_name or \
|
|
constants.DEFAULT_STAGING_PROJECT_NAME
|
|
try:
|
|
projects = []
|
|
if hasattr(ks_client, 'tenants'):
|
|
# For keystone V2
|
|
projects = ks_client.tenants.list()
|
|
elif hasattr(ks_client, 'projects'):
|
|
# For keystone V3
|
|
projects = ks_client.projects.list()
|
|
for tenant in projects:
|
|
projectname = tenant.name
|
|
projectid = tenant.id
|
|
if projectname == stagingname:
|
|
LOG.debug(_('The staging_project_name %s has id %s'),
|
|
stagingname, projectid)
|
|
return projectid
|
|
except Exception as e:
|
|
LOG.debug(_('An error occurred getting the tenant list: %s.'), e)
|
|
LOG.debug(_('Unable to find staging project: %s'), stagingname)
|
|
raise exception.StagingProjectNotFound(name=stagingname)
|
|
|
|
def get_local_staging_user_id(self):
|
|
"""
|
|
Get the local hosting OS staging user Id which defaults to
|
|
constants.DEFAULT_STAGING_USERNAME if not set in the conf.
|
|
If a staging user name is not found, a StagingUserNotFound
|
|
exception will be raised.
|
|
|
|
:returns: The local hosting OS staging user Id
|
|
"""
|
|
ks_client = self._localkeystoneclient
|
|
staginguser = CONF.powervc.staging_user or \
|
|
constants.DEFAULT_STAGING_USER_NAME
|
|
try:
|
|
for user in ks_client.users.list():
|
|
username = user.name
|
|
userid = user.id
|
|
if staginguser == username:
|
|
LOG.debug(_('The staging_user %s has id %s'),
|
|
staginguser, userid)
|
|
return userid
|
|
except Exception as e:
|
|
LOG.debug(_('An error occurred getting the user list: %s'), e)
|
|
LOG.debug(_('Unable to find staging user: %s'), staginguser)
|
|
raise exception.StagingUserNotFound(name=staginguser)
|
|
|
|
|
|
def import_relative_module(relative_import_str, import_str):
|
|
"""
|
|
Imports a module relative to another. Can be used when more
|
|
than 1 module of the given name exists in the python path
|
|
to resolve any discrepency in multiple paths.
|
|
|
|
:param relative_import_str: a module import string which
|
|
neighbors the actual import. for example 'glanceclient'.
|
|
:param import_str: the module import string. for example
|
|
'tests.utils'
|
|
|
|
example:
|
|
utils = import_relative_module('glanceclient', 'tests.utils')
|
|
fapi = utils.FakeAPI(...)
|
|
"""
|
|
mod = importutils.import_module(relative_import_str)
|
|
mpath = os.path.dirname(os.path.dirname(os.path.realpath(mod.__file__)))
|
|
if not sys.path[0] is mpath:
|
|
sys.path.insert(0, mpath)
|
|
return importutils.import_module(import_str)
|
|
|
|
|
|
class StagingCache(object):
|
|
"""
|
|
Provides a lazy cache around the local staging user and project.
|
|
Consumers can use the staging_user_and_project property to retrieve the
|
|
(user_id, project_id) pair for the staging user. These values are
|
|
lazily fetched at most once
|
|
"""
|
|
|
|
def __init__(self):
|
|
super(StagingCache, self).__init__()
|
|
self.utils = get_utils()
|
|
self.staging_user = None
|
|
self.staging_project = None
|
|
|
|
@property
|
|
def is_valid(self):
|
|
uid, pid = self.get_staging_user_and_project()
|
|
return uid is not None and pid is not None
|
|
|
|
def get_staging_user_and_project(self, raise_on_invalid=False):
|
|
try:
|
|
if not self.staging_user:
|
|
self.staging_user = self.utils.get_local_staging_user_id()
|
|
if not self.staging_project:
|
|
self.staging_project = \
|
|
self.utils.get_local_staging_project_id()
|
|
return (self.staging_user, self.staging_project)
|
|
except exception.StagingProjectNotFound as e:
|
|
if raise_on_invalid:
|
|
raise e
|
|
return (None, None)
|
|
except exception.StagingUserNotFound as e:
|
|
if raise_on_invalid:
|
|
raise e
|
|
return (None, None)
|