def datastore_create(self, type, label, varray, cos, size, token, mountpoint): if ((varray) and (not common.is_uri(varray))): from virtualarray import VirtualArray obj = VirtualArray(self.__ipAddr, self.__port) nbhinst = obj.varray_show(varray) varray = nbhinst['id'] if (not common.is_uri(cos)): from cos import Cos obj = Cos(self.__ipAddr, self.__port) # check this cosinst = obj.cos_show(cos, 'object') cos_uri = cosinst['id'] parms = { 'name': label, 'object_cos': cos_uri, } if (size): parms['size'] = size if (varray): parms['varray'] = varray if (mountpoint): parms['mount_point'] = mountpoint if (not token): token = 'cli-create-' + cos body = json.dumps(parms) uri = self.URI_DATA_STORE_LIST + "/" + type qparms = {'task': token} if (qparms): for qk in qparms.iterkeys(): if (qparms[qk] is not None): uri += '&' if ('?' in uri) else '?' uri += qk + '=' + qparms[qk] (s, h) = common.service_json_request(self.__ipAddr, self.__port, "POST", uri, body) o = common.json_decode(s)
def datastore_create(self, type, label, varray, cos, size, token, mountpoint): if ((varray) and (not common.is_uri(varray))): from virtualarray import VirtualArray obj = VirtualArray(self.__ipAddr, self.__port) nbhinst = obj.varray_show(varray) varray = nbhinst['id'] if(not common.is_uri(cos)): from cos import Cos obj = Cos(self.__ipAddr, self.__port) # check this cosinst = obj.cos_show(cos, 'object') cos_uri = cosinst['id'] parms = { 'name': label, 'object_cos': cos_uri, } if (size): parms['size'] = size if (varray): parms['varray'] = varray if (mountpoint): parms['mount_point'] = mountpoint if (not token): token = 'cli-create-' + cos body = json.dumps(parms) uri = self.URI_DATA_STORE_LIST + "/" + type qparms = {'task': token} if (qparms): for qk in qparms.iterkeys(): if (qparms[qk] is not None): uri += '&' if ('?' in uri) else '?' uri += qk + '=' + qparms[qk] (s, h) = common.service_json_request(self.__ipAddr, self.__port, "POST", uri, body) o = common.json_decode(s)
class EMCViPRDriverCommon(object): OPENSTACK_TAG = 'OpenStack' def __init__(self, protocol, default_backend_name, configuration=None): self.protocol = protocol self.configuration = configuration self.configuration.append_config_values(volume_opts) self.check_for_vipr_cli_path() self.init_vipr_cli_components() self.stats = { 'driver_version': '1.0', 'free_capacity_gb': 'unknown', 'reserved_percentage': '0', 'storage_protocol': protocol, 'total_capacity_gb': 'unknown', 'vendor_name': 'EMC', 'volume_backend_name': self.configuration.volume_backend_name or default_backend_name } self.volume_api = cinder_volume.API() def check_for_vipr_cli_path(self): if (self.configuration.vipr_cli_path is None): message = "vipr_cli_path is not set in cinder configuration" raise exception.VolumeBackendAPIException(data=message) if (os.path.exists(self.configuration.vipr_cli_path)): sys.path.append(self.configuration.vipr_cli_path) else: message = self.configuration.vipr_cli_path + " path does not" + \ " exist in the system. Please check/add/change" + \ " vipr_cli_path" + \ " in cinder configuration with valid ViPR" + \ " CLI installation path" raise exception.VolumeBackendAPIException(data=message) def init_vipr_cli_components(self): import common as vipr_utils vipr_utils.COOKIE = None from exportgroup import ExportGroup from host import Host from hostinitiators import HostInitiator from snapshot import Snapshot from virtualarray import VirtualArray from volume import Volume # instantiate a few vipr cli objects for later use self.volume_obj = Volume(self.configuration.vipr_hostname, self.configuration.vipr_port) self.exportgroup_obj = ExportGroup(self.configuration.vipr_hostname, self.configuration.vipr_port) self.host_obj = Host(self.configuration.vipr_hostname, self.configuration.vipr_port) self.hostinitiator_obj = HostInitiator( self.configuration.vipr_hostname, self.configuration.vipr_port) self.varray_obj = VirtualArray(self.configuration.vipr_hostname, self.configuration.vipr_port) self.snapshot_obj = Snapshot(self.configuration.vipr_hostname, self.configuration.vipr_port) def check_for_setup_error(self): # validate all of the vipr_* configuration values if (self.configuration.vipr_hostname is None): message = "vipr_hostname is not set in cinder configuration" raise exception.VolumeBackendAPIException(data=message) if (self.configuration.vipr_port is None): message = "vipr_port is not set in cinder configuration" raise exception.VolumeBackendAPIException(data=message) if (self.configuration.vipr_username is None): message = "vipr_username is not set in cinder configuration" raise exception.VolumeBackendAPIException(data=message) if (self.configuration.vipr_password is None): message = "vipr_password is not set in cinder configuration" raise exception.VolumeBackendAPIException(data=message) if (self.configuration.vipr_tenant is None): message = "vipr_tenant is not set in cinder configuration" raise exception.VolumeBackendAPIException(data=message) if (self.configuration.vipr_project is None): message = "vipr_project is not set in cinder configuration" raise exception.VolumeBackendAPIException(data=message) if (self.configuration.vipr_varray is None): message = "vipr_varray is not set in cinder configuration" raise exception.VolumeBackendAPIException(data=message) def authenticate_user(self): global AUTHENTICATED from authentication import Authentication # we should check to see if we are already authenticated before blindly # doing it again if (AUTHENTICATED is False): obj = Authentication(self.configuration.vipr_hostname, self.configuration.vipr_port) # cookiedir = os.getcwd() cookiedir = self.configuration.vipr_cookiedir obj.authenticate_user(self.configuration.vipr_username, self.configuration.vipr_password, cookiedir, None) AUTHENTICATED = True @retry_wrapper def create_volume(self, vol): self.authenticate_user() name = self._get_volume_name(vol) size = int(vol['size']) * 1073741824 from common import SOSError vpool = self._get_vpool(vol) self.vpool = vpool['ViPR:VPOOL'] try: res = self.volume_obj.create( self.configuration.vipr_tenant + "/" + self.configuration.vipr_project, name, size, self.configuration.vipr_varray, self.vpool, protocol=None, # no longer specified in volume # creation sync=True, number_of_volumes=1, thin_provisioned=None, consistencygroup=None) except SOSError as e: if (e.err_code == SOSError.SOS_FAILURE_ERR): raise SOSError( SOSError.SOS_FAILURE_ERR, "Volume " + name + ": Tag failed\n" + e.err_text) else: raise e @retry_wrapper def setTags(self, vol): self.authenticate_user() name = self._get_volume_name(vol) from common import SOSError # first, get the current tags that start with the OPENSTACK_TAG # eyecatcher removeTags = [] currentTags = self.volume_obj.getTags(self.configuration.vipr_tenant + "/" + self.configuration.vipr_project + "/" + name) for cTag in currentTags: if (cTag.startswith(self.OPENSTACK_TAG)): removeTags.append(cTag) try: if (len(removeTags) > 0): self.volume_obj.tag( self.configuration.vipr_tenant + "/" + self.configuration.vipr_project + "/" + name, None, removeTags) except SOSError as e: if (e.err_code == SOSError.SOS_FAILURE_ERR): LOG.debug("SOSError adding the tag: " + e.err_text) # now add the tags for the volume addTags = [] # put all the openstack volume properties into the ViPR volume try: for prop, value in vars(vol).iteritems(): try: # don't put the status in, it's always the status before # the current transaction if (not prop.startswith("status")): addTags.append(self.OPENSTACK_TAG + ":" + prop + ":" + value) except Exception: pass except Exception: pass try: self.volume_obj.tag( self.configuration.vipr_tenant + "/" + self.configuration.vipr_project + "/" + name, addTags, None) except SOSError as e: if (e.err_code == SOSError.SOS_FAILURE_ERR): LOG.debug("SOSError adding the tag: " + e.err_text) return (self.volume_obj.getTags(self.configuration.vipr_tenant + "/" + self.configuration.vipr_project + "/" + name)) @retry_wrapper def create_cloned_volume(self, vol, src_vref): """Creates a clone of the specified volume.""" self.authenticate_user() name = self._get_volume_name(vol) srcname = self._get_volume_name(src_vref) number_of_volumes = 1 from common import SOSError try: res = self.volume_obj.clone(self.configuration.vipr_tenant + "/" + self.configuration.vipr_project, name, number_of_volumes, srcname, None, sync=True) except SOSError as e: if (e.err_code == SOSError.SOS_FAILURE_ERR): raise SOSError( SOSError.SOS_FAILURE_ERR, "Volume " + name + ": clone failed\n" + e.err_text) else: raise e @retry_wrapper def expand_volume(self, vol, new_size): """expands the volume to new_size specified.""" self.authenticate_user() volume_name = self._get_volume_name(vol) import common as vipr_utils size_in_bytes = vipr_utils.to_bytes(str(new_size) + "G") from common import SOSError try: self.volume_obj.expand( self.configuration.vipr_tenant + "/" + self.configuration.vipr_project + "/" + volume_name, size_in_bytes, True) except SOSError as e: if (e.err_code == SOSError.SOS_FAILURE_ERR): raise SOSError( SOSError.SOS_FAILURE_ERR, "Volume " + volume_name + ": expand failed\n" + e.err_text) else: raise e @retry_wrapper def create_volume_from_snapshot(self, snapshot, volume): """Creates volume from given snapshot ( snapshot clone to volume ).""" self.authenticate_user() src_snapshot_name = snapshot['name'] src_vol_ref = self.volume_api.get(context.get_admin_context(), snapshot['volume_id']) src_vol_name = self._get_volume_name(src_vol_ref) new_volume_name = self._get_volume_name(volume) number_of_volumes = 1 from common import SOSError try: self.volume_obj.clone(self.configuration.vipr_tenant + "/" + self.configuration.vipr_project, new_volume_name, number_of_volumes, src_vol_name, src_snapshot_name, sync=True) except SOSError as e: if (e.err_code == SOSError.SOS_FAILURE_ERR): raise SOSError( SOSError.SOS_FAILURE_ERR, "Snapshot " + src_snapshot_name + ": clone failed\n" + e.err_text) else: raise e @retry_wrapper def delete_volume(self, vol): self.authenticate_user() name = self._get_volume_name(vol) from common import SOSError try: self.volume_obj.delete(self.configuration.vipr_tenant + "/" + self.configuration.vipr_project + "/" + name, volume_name_list=None, sync=True) except SOSError as e: if e.err_code == SOSError.NOT_FOUND_ERR: LOG.info("Volume " + name + " no longer exists; volume deletion is" + " considered success.") elif e.err_code == SOSError.SOS_FAILURE_ERR: raise SOSError( SOSError.SOS_FAILURE_ERR, "Volume " + name + ": Delete failed\n" + e.err_text) else: raise e @retry_wrapper def list_volume(self): import common as vipr_utils from common import SOSError try: uris = self.volume_obj.list_volumes( self.configuration.vipr_tenant + "/" + self.configuration.vipr_project) if (len(uris) > 0): output = [] for uri in uris: output.append(self.volume_obj.show_by_uri(uri)) return vipr_utils.format_json_object(output) else: return except SOSError as e: raise e @retry_wrapper def create_snapshot(self, snapshot): self.authenticate_user() from common import SOSError try: snapshotname = snapshot['name'] vol = snapshot['volume'] volumename = self._get_volume_name(vol) projectname = self.configuration.vipr_project tenantname = self.configuration.vipr_tenant storageresType = 'block' storageresTypename = 'volumes' resourceUri = self.snapshot_obj.storageResource_query( storageresType, fileshareName=None, volumeName=volumename, cgName=None, project=projectname, tenant=tenantname) inactive = False rptype = None sync = True self.snapshot_obj.snapshot_create(storageresType, storageresTypename, resourceUri, snapshotname, inactive, rptype, sync) return except SOSError as e: if (e.err_code == SOSError.SOS_FAILURE_ERR): raise SOSError( SOSError.SOS_FAILURE_ERR, "Snapshot: " + snapshotname + ", Create Failed\n" + e.err_text) else: raise e @retry_wrapper def delete_snapshot(self, snapshot): self.authenticate_user() snapshotname = snapshot['name'] from common import SOSError try: vol = snapshot['volume'] volumename = self._get_volume_name(vol) projectname = self.configuration.vipr_project tenantname = self.configuration.vipr_tenant storageresType = 'block' storageresTypename = 'volumes' resourceUri = self.snapshot_obj.storageResource_query( storageresType, fileshareName=None, volumeName=volumename, cgName=None, project=projectname, tenant=tenantname) if resourceUri is None: LOG.info("Snapshot " + snapshotname + " is not found; snapshot deletion" + " is considered successful.") else: self.snapshot_obj.snapshot_delete(storageresType, storageresTypename, resourceUri, snapshotname, sync=True) return except SOSError as e: if (e.err_code == SOSError.SOS_FAILURE_ERR): raise SOSError( SOSError.SOS_FAILURE_ERR, "Snapshot " + snapshotname + ": Delete Failed\n") else: raise e @retry_wrapper def initialize_connection(self, volume, protocol, initiatorNodes, initiatorPorts, hostname): from common import SOSError try: self.authenticate_user() volumename = self._get_volume_name(volume) foundgroupname = self._find_exportgroup(initiatorPorts) if (foundgroupname is None): for i in xrange(len(initiatorPorts)): # check if this initiator is contained in any ViPR Host # object LOG.debug("checking for initiator port:" + initiatorPorts[i]) foundhostname = self._find_host(initiatorPorts[i]) if (foundhostname is None): hostfound = self._host_exists(hostname) if (hostfound is None): # create a host so it can be added to the export # group hostfound = hostname self.host_obj.create( hostname, platform.system(), hostname, self.configuration.vipr_tenant, port=None, username=None, passwd=None, usessl=None, osversion=None, cluster=None, datacenter=None, vcenter=None, autodiscovery=True) LOG.info("Created host " + hostname) # add the initiator to the host self.hostinitiator_obj.create(hostfound, protocol, initiatorNodes[i], initiatorPorts[i]) LOG.info("Initiator " + initiatorPorts[i] + " added to host " + hostfound) foundhostname = hostfound else: LOG.info("Found host " + foundhostname) # create an export group for this host foundgroupname = foundhostname + 'SG' # create a unique name foundgroupname = foundgroupname + '-' + \ ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(6)) res = self.exportgroup_obj.exportgroup_create( foundgroupname, self.configuration.vipr_project, self.configuration.vipr_tenant, self.configuration.vipr_varray, 'Host', foundhostname) LOG.debug("adding the volume to the exportgroup : " + volumename) res = self.exportgroup_obj.exportgroup_add_volumes( True, foundgroupname, self.configuration.vipr_tenant, self.configuration.vipr_project, [volumename], None, None) return self._find_device_info(volume, initiatorPorts) except SOSError as e: raise SOSError( SOSError.SOS_FAILURE_ERR, "Attach volume (" + self._get_volume_name(volume) + ") to host (" + hostname + ") initiator (" + initiatorPorts[0] + ") failed: " + e.err_text) @retry_wrapper def terminate_connection(self, volume, protocol, initiatorNodes, initiatorPorts, hostname): from common import SOSError try: self.authenticate_user() volumename = self._get_volume_name(volume) tenantproject = self.configuration.vipr_tenant + \ '/' + self.configuration.vipr_project voldetails = self.volume_obj.show(tenantproject + '/' + volumename) volid = voldetails['id'] # find the exportgroups exports = self.volume_obj.get_exports_by_uri(volid) exportgroups = set() itls = exports['itl'] for itl in itls: itl_port = itl['initiator']['port'] if (itl_port in initiatorPorts): exportgroups.add(itl['export']['id']) for exportgroup in exportgroups: res = self.exportgroup_obj.exportgroup_remove_volumes_by_uri( exportgroup, volid, True, None, None, None, None) else: LOG.info("No export group found for the host: " + hostname + "; this is considered already detached.") return itls except SOSError as e: raise SOSError( SOSError.SOS_FAILURE_ERR, "Detaching volume " + volumename + " from host " + hostname + " failed: " + e.err_text) @retry_wrapper def _find_device_info(self, volume, initiator_ports): '''Returns the device_info in a list of itls that have the matched initiator (there could be multiple targets, hence a list): [ { "hlu":9, "initiator":{...,"port":"20:00:00:25:B5:49:00:22"}, "export":{...}, "device":{...,"wwn":"600601602B802D00B62236585D0BE311"}, "target":{...,"port":"50:06:01:6A:46:E0:72:EF"}, "san_zone_name":"..." }, { "hlu":9, "initiator":{...,"port":"20:00:00:25:B5:49:00:22"}, "export":{...}, "device":{...,"wwn":"600601602B802D00B62236585D0BE311"}, "target":{...,"port":"50:06:01:62:46:E0:72:EF"}, "san_zone_name":"..." } ] ''' volumename = self._get_volume_name(volume) fullname = self.configuration.vipr_project + '/' + volumename vol_uri = self.volume_obj.volume_query(fullname) ''' The itl info shall be available at the first try since now export is a synchronous call. We are trying a few more times to accommodate any delay on filling in the itl info after the export task is completed. ''' itls = [] for x in xrange(10): exports = self.volume_obj.get_exports_by_uri(vol_uri) LOG.debug(_("Volume exports: %s") % exports) for itl in exports['itl']: itl_port = itl['initiator']['port'] if (itl_port in initiator_ports): found_device_number = itl['hlu'] if (found_device_number is not None and found_device_number != '-1'): # 0 is a valid number for found_device_number. # Only loop if it is None or -1 LOG.debug("Found Device Number: " + str(found_device_number)) itls.append(itl) if itls: break else: LOG.debug("Device Number not found yet." + " Retrying after 10 seconds...") time.sleep(10) if itls is None: # No device number found after 10 tries; return an empty itl LOG.info("No device number has been found after 10 tries;" + "this likely indicates an unsuccessful attach of" + "volume " + volumename + " to" + " initiator " + str(initiator_ports)) return itls def _get_volume_name(self, vol): try: name = vol['display_name'] except Exception as exp: name = None if (name is None or len(name) == 0): name = vol['name'] return name def _get_vpool(self, volume): vpool = {} ctxt = context.get_admin_context() type_id = volume['volume_type_id'] if type_id is not None: volume_type = volume_types.get_volume_type(ctxt, type_id) specs = volume_type.get('extra_specs') for key, value in specs.iteritems(): vpool[key] = value return vpool @retry_wrapper def _find_exportgroup(self, initiator_ports): '''Find the export group to which the given initiator ports are the same as the initiators in the group ''' foundgroupname = None grouplist = self.exportgroup_obj.exportgroup_list( self.configuration.vipr_project, self.configuration.vipr_tenant) for groupid in grouplist: groupdetails = self.exportgroup_obj.exportgroup_show( groupid, self.configuration.vipr_project, self.configuration.vipr_tenant) if groupdetails is not None: if (groupdetails['inactive']): continue initiators = groupdetails['initiators'] if initiators is not None: inits_eg = set() for initiator in initiators: inits_eg.add(initiator['initiator_port']) if (inits_eg == set(initiator_ports)): foundgroupname = groupdetails['name'] if foundgroupname is not None: # Check the associated varray if groupdetails['varray']: varray_uri = groupdetails['varray']['id'] varray_details = self.varray_obj.varray_show( varray_uri) if (varray_details['name'] == self.configuration.vipr_varray): LOG.debug("Found exportgroup " + foundgroupname) break # Not the right varray foundgroupname = None return foundgroupname @retry_wrapper def _find_host(self, initiator_port): '''Find the host, if exists, to which the given initiator belong.''' foundhostname = None hosts = self.host_obj.list_by_tenant(self.configuration.vipr_tenant) for host in hosts: initiators = self.host_obj.list_initiators(host['id']) for initiator in initiators: if (initiator_port == initiator['name']): foundhostname = host['name'] break if foundhostname is not None: break return foundhostname @retry_wrapper def _host_exists(self, host_name): '''Check if a Host object with the given hostname already exists in ViPR ''' hosts = self.host_obj.search_by_name(host_name) if (len(hosts) > 0): for host in hosts: hostname = host['match'] if (host_name == hostname): return hostname return hostname LOG.debug("no host found for:" + host_name) return None @retry_wrapper def update_volume_stats(self): """Retrieve stats info.""" LOG.debug(_("Updating volume stats")) self.authenticate_user() import common as vipr_utils from common import SOSError try: vols = self.volume_obj.list_volumes( self.configuration.vipr_tenant + "/" + self.configuration.vipr_project) vpairs = set() if (len(vols) > 0): for vol in vols: if (vol): vpair = (vol["vpool"]["id"], vol["varray"]["id"]) if (vpair not in vpairs): vpairs.add(vpair) if (len(vpairs) > 0): free_gb = 0.0 used_gb = 0.0 provisioned_gb = 0.0 precent_used = 0.0 percent_provisioned = 0.0 for vpair in vpairs: if (vpair): (s, h) = vipr_utils.service_json_request( self.configuration.vipr_hostname, self.configuration.vipr_port, "GET", URI_VPOOL_VARRAY_CAPACITY.format( vpair[0], vpair[1]), body=None) capacity = vipr_utils.json_decode(s) free_gb += float(capacity["free_gb"]) used_gb += float(capacity["used_gb"]) provisioned_gb += float(capacity["provisioned_gb"]) self.stats['free_capacity_gb'] = free_gb self.stats['total_capacity_gb'] = free_gb + used_gb self.stats['reserved_percentage'] = 100 * \ provisioned_gb / (free_gb + used_gb) return self.stats except SOSError as e: raise e