def connect_storage(self): """Prepare for using the storage.""" target_ports = self.conf.vsp_target_ports compute_target_ports = self.conf.vsp_compute_target_ports pair_target_ports = self.conf.vsp_horcm_pair_target_ports super(VSPHORCMISCSI, self).connect_storage() result = self.run_raidcom('get', 'port') for port in _ISCSI_PORT_PATTERN.findall(result[1]): if (target_ports and port in target_ports and self._set_target_portal(port)): self.storage_info['controller_ports'].append(port) if (compute_target_ports and port in compute_target_ports and (port in self.storage_info['portals'] or self._set_target_portal(port))): self.storage_info['compute_ports'].append(port) if pair_target_ports and port in pair_target_ports: self.storage_info['pair_ports'].append(port) self.check_ports_info() if pair_target_ports and not self.storage_info['pair_ports']: msg = utils.output_log(MSG.RESOURCE_NOT_FOUND, resource="Pair target ports") raise exception.VSPError(msg) utils.output_log(MSG.SET_CONFIG_VALUE, object='pair target port list', value=self.storage_info['pair_ports']) utils.output_log(MSG.SET_CONFIG_VALUE, object='port-<IP address:port> list', value=self.storage_info['portals'])
def check_param(self): """Check parameter values and consistency among them.""" utils.check_opt_value(self.conf, _INHERITED_VOLUME_OPTS) utils.check_opts(self.conf, common_opts) utils.check_opts(self.conf, self.driver_info['volume_opts']) if (self.conf.vsp_default_copy_method == 'THIN' and not self.conf.vsp_thin_pool): msg = utils.output_log(MSG.INVALID_PARAMETER, param='vsp_thin_pool') raise exception.VSPError(msg) if self.conf.vsp_ldev_range: self.storage_info['ldev_range'] = self._range2list( 'vsp_ldev_range') if (not self.conf.vsp_target_ports and not self.conf.vsp_compute_target_ports): msg = utils.output_log(MSG.INVALID_PARAMETER, param='vsp_target_ports or ' 'vsp_compute_target_ports') raise exception.VSPError(msg) for opt in _REQUIRED_COMMON_OPTS: if not self.conf.safe_get(opt): msg = utils.output_log(MSG.INVALID_PARAMETER, param=opt) raise exception.VSPError(msg) if self.storage_info['protocol'] == 'iSCSI': self.check_param_iscsi()
def terminate_connection(self, volume, connector): """Terminate connection between the server and the volume.""" targets = { 'info': {}, 'list': [], 'iqns': {}, } mapped_targets = { 'list': [], } unmap_targets = {} ldev = utils.get_ldev(volume) if ldev is None: utils.output_log(MSG.INVALID_LDEV_FOR_UNMAPPING, volume_id=volume['id']) return self.find_targets_from_storage(targets, connector, self.storage_info['ports']) if not targets['list']: utils.output_log(MSG.NO_CONNECTED_TARGET) self.find_mapped_targets_from_storage( mapped_targets, ldev, self.storage_info['ports']) unmap_targets['list'] = self.get_unmap_targets_list( targets['list'], mapped_targets['list']) unmap_targets['list'].sort(reverse=True) self.unmap_ldev(unmap_targets, ldev) if self.storage_info['protocol'] == 'FC': target_wwn = [ self.storage_info['wwns'][port_gid[:utils.PORT_ID_LENGTH]] for port_gid in unmap_targets['list']] return {'driver_volume_type': self.driver_info['volume_type'], 'data': {'target_wwn': target_wwn}}
def create_cloned_volume(self, volume, src_vref): """Create a clone of the specified volume and return its properties.""" ldev = utils.get_ldev(src_vref) # When 'ldev' is 0, it should be true. # Therefore, it cannot remove 'is not None'. if ldev is None: msg = utils.output_log(MSG.INVALID_LDEV_FOR_VOLUME_COPY, type='volume', id=src_vref['id']) raise exception.VSPError(msg) size = volume['size'] metadata = utils.get_volume_metadata(volume) if size < src_vref['size']: msg = utils.output_log(MSG.INVALID_VOLUME_SIZE_FOR_COPY, type='volume', volume_id=volume['id']) raise exception.VSPError(msg) elif (size > src_vref['size'] and not self.check_vvol(ldev) and self.get_copy_method(metadata) == "THIN"): msg = utils.output_log(MSG.INVALID_VOLUME_SIZE_FOR_TI, copy_method=utils.THIN, type='volume', volume_id=volume['id']) raise exception.VSPError(msg) sync = size > src_vref['size'] new_ldev = self._copy_ldev(ldev, src_vref['size'], metadata, sync) if sync: self.delete_pair(new_ldev) self.extend_ldev(new_ldev, src_vref['size'], size) return { 'provider_location': six.text_type(new_ldev), }
def _terminate_connection(self, volume, connector): """Disconnect the specified volume from the server.""" try: self.terminate_connection(volume, connector) except exception.VSPError: utils.output_log(MSG.UNMAP_LDEV_FAILED, ldev=utils.get_ldev(volume))
def check_ports_info(self): """Check if available storage ports exist.""" if (self.conf.vsp_target_ports and not self.storage_info['ports']): msg = utils.output_log(MSG.RESOURCE_NOT_FOUND, resource="Target ports") raise exception.VSPError(msg) utils.output_log(MSG.SET_CONFIG_VALUE, object='target port list', value=self.storage_info['ports'])
def output_param_to_log(self): """Output configuration parameter values to the log file.""" utils.output_log(MSG.OUTPUT_PARAMETER_VALUES, config_group=self.conf.config_group) name, version = self.get_storage_cli_info() utils.output_storage_cli_info(name, version) utils.output_opt_info(self.conf, _INHERITED_VOLUME_OPTS) utils.output_opts(self.conf, common_opts) utils.output_opts(self.conf, self.driver_info['volume_opts'])
def get_volume_stats(self, refresh=False): """Return properties, capabilities and current states of the driver.""" if refresh: if self.storage_info['output_first']: self.storage_info['output_first'] = False utils.output_log(MSG.DRIVER_READY_FOR_USE, config_group=self.conf.config_group) self._update_volume_stats() return self._stats
def connect_storage(self): """Prepare for using the storage.""" self.storage_info['pool_id'] = self.get_pool_id() # When 'pool_id' is 0, it should be true. # Therefore, it cannot remove 'is None'. if self.storage_info['pool_id'] is None: msg = utils.output_log(MSG.POOL_NOT_FOUND, pool=self.conf.vsp_pool) raise exception.VSPError(msg) utils.output_log(MSG.SET_CONFIG_VALUE, object='DP Pool ID', value=self.storage_info['pool_id'])
def create_volume(self, volume): """Create a volume and return its properties.""" try: ldev = self.create_ldev(volume['size']) except exception.VSPError: with excutils.save_and_reraise_exception(): utils.output_log(MSG.CREATE_LDEV_FAILED) return { 'provider_location': six.text_type(ldev), }
def check_param_iscsi(self): """Check iSCSI-related parameter values and consistency among them.""" if self.conf.vsp_use_chap_auth: if not self.conf.vsp_auth_user: msg = utils.output_log(MSG.INVALID_PARAMETER, param='vsp_auth_user') raise exception.VSPError(msg) if not self.conf.vsp_auth_password: msg = utils.output_log(MSG.INVALID_PARAMETER, param='vsp_auth_password') raise exception.VSPError(msg)
def __init__(self, *args, **kwargs): """Initialize instance variables.""" utils.output_log(MSG.DRIVER_INITIALIZATION_START, driver=self.__class__.__name__, version=self.get_version()) super(VSPFCDriver, self).__init__(*args, **kwargs) self.configuration.append_config_values(common.common_opts) self.configuration.append_config_values(fc_opts) self.common = utils.import_object( self.configuration, _DRIVER_INFO, kwargs.get('db'))
def _copy_on_host(self, src_ldev, size): """Create a copy of the specified LDEV via host.""" dest_ldev = self.create_ldev(size) try: self._copy_with_dd(src_ldev, dest_ldev, size) except Exception: with excutils.save_and_reraise_exception(): try: self._delete_ldev(dest_ldev) except exception.VSPError: utils.output_log(MSG.DELETE_LDEV_FAILED, ldev=dest_ldev) return dest_ldev
def get_copy_method(self, metadata): """Return copy method(FULL or THIN).""" method = metadata.get('copy_method', self.conf.vsp_default_copy_method) if method not in _COPY_METHOD: msg = utils.output_log(MSG.INVALID_PARAMETER_VALUE, meta='copy_method') raise exception.VSPError(msg) if method == 'THIN' and not self.conf.vsp_thin_pool: msg = utils.output_log(MSG.INVALID_PARAMETER, param='vsp_thin_pool') raise exception.VSPError(msg) return method
def _detach_ldev(self, attach_info, ldev, properties): """Detach the specified LDEV from the server.""" volume = { 'provider_location': six.text_type(ldev), } connector = attach_info['connector'] try: connector.disconnect_volume( attach_info['conn']['data'], attach_info['device']) except Exception as ex: utils.output_log(MSG.DISCONNECT_VOLUME_FAILED, ldev=ldev, reason=six.text_type(ex)) self._terminate_connection(volume, properties)
def delete_volume(self, volume): """Delete the specified volume.""" ldev = utils.get_ldev(volume) # When 'ldev' is 0, it should be true. # Therefore, it cannot remove 'is not None'. if ldev is None: utils.output_log(MSG.INVALID_LDEV_FOR_DELETION, method='delete_volume', id=volume['id']) return try: self._delete_ldev(ldev) except exception.VSPBusy: raise exception.VolumeIsBusy(volume_name=volume['name'])
def get_copy_method(self, metadata): """Return copy method(FULL or THIN).""" method = metadata.get( 'copy_method', self.conf.vsp_default_copy_method) if method not in _COPY_METHOD: msg = utils.output_log(MSG.INVALID_PARAMETER_VALUE, meta='copy_method') raise exception.VSPError(msg) if method == 'THIN' and not self.conf.vsp_thin_pool: msg = utils.output_log(MSG.INVALID_PARAMETER, param='vsp_thin_pool') raise exception.VSPError(msg) return method
def delete_snapshot(self, snapshot): """Delete the specified snapshot.""" ldev = utils.get_ldev(snapshot) # When 'ldev' is 0, it should be true. # Therefore, it cannot remove 'is None'. if ldev is None: utils.output_log(MSG.INVALID_LDEV_FOR_DELETION, method='delete_snapshot', id=snapshot['id']) return try: self._delete_ldev(ldev) except exception.VSPBusy: raise exception.SnapshotIsBusy(snapshot_name=snapshot['name'])
def delete_snapshot(self, snapshot): """Delete the specified snapshot.""" ldev = utils.get_ldev(snapshot) # When 'ldev' is 0, it should be true. # Therefore, it cannot remove 'is None'. if ldev is None: utils.output_log( MSG.INVALID_LDEV_FOR_DELETION, method='delete_snapshot', id=snapshot['id']) return try: self._delete_ldev(ldev) except exception.VSPBusy: raise exception.SnapshotIsBusy(snapshot_name=snapshot['name'])
def connect_storage(self): """Prepare for using the storage.""" target_ports = self.conf.vsp_target_ports super(VSPHORCMFC, self).connect_storage() result = self.run_raidcom('get', 'port') for port, wwn in _FC_PORT_PATTERN.findall(result[1]): if target_ports and port in target_ports: self.storage_info['ports'].append(port) self.storage_info['wwns'][port] = wwn self.check_ports_info() utils.output_log(MSG.SET_CONFIG_VALUE, object='port-wwn list', value=self.storage_info['wwns'])
def extend_volume(self, volume, new_size): """Extend the specified volume to the specified size.""" ldev = utils.get_ldev(volume) # When 'ldev' is 0, it should be true. # Therefore, it cannot remove 'is None'. if ldev is None: msg = utils.output_log(MSG.INVALID_LDEV_FOR_EXTENSION, volume_id=volume['id']) raise exception.VSPError(msg) if self.check_vvol(ldev): msg = utils.output_log(MSG.INVALID_VOLUME_TYPE_FOR_EXTEND, volume_id=volume['id']) raise exception.VSPError(msg) self.delete_pair(ldev) self.extend_ldev(ldev, volume['size'], new_size)
def copy_on_storage(self, pvol, size, metadata, sync): """Create a copy of the specified LDEV on the storage.""" is_thin = self.get_copy_method(metadata) == "THIN" svol = self.create_ldev(size, is_vvol=is_thin) try: self.create_pair_on_storage(pvol, svol, is_thin) if sync: self.wait_full_copy_completion(pvol, svol) except exception.VSPError: with excutils.save_and_reraise_exception(): try: self._delete_ldev(svol) except exception.VSPError: utils.output_log(MSG.DELETE_LDEV_FAILED, ldev=svol) return svol
def connect_storage(self): """Prepare for using the storage.""" target_ports = self.conf.vsp_target_ports super(VSPHORCMISCSI, self).connect_storage() result = self.run_raidcom('get', 'port') for port in _ISCSI_PORT_PATTERN.findall(result[1]): if (target_ports and port in target_ports and self._set_target_portal(port)): self.storage_info['ports'].append(port) self.check_ports_info() utils.output_log(MSG.SET_CONFIG_VALUE, object='port-<IP address:port> list', value=self.storage_info['portals'])
def create_mapping_targets(self, targets, connector): """Create server-storage connection for all specified storage ports.""" hba_ids = self.get_hba_ids_from_connector(connector) for port in targets['info'].keys(): if targets['info'][port]: continue try: self._create_target(targets, port, connector, hba_ids) except exception.VSPError: utils.output_log(self.driver_info['msg_id']['target'], port=port) if not targets['list']: self.find_targets_from_storage(targets, connector, targets['info'].keys())
def set_hba_ids(self, port, gid, hba_ids): """Connect all specified HBAs with the specified port.""" registered_wwns = [] for wwn in hba_ids: try: self.run_raidcom( 'add', 'hba_wwn', '-port', '-'.join([port, gid]), '-hba_wwn', wwn) registered_wwns.append(wwn) except exception.VSPError: utils.output_log(MSG.ADD_HBA_WWN_FAILED, port=port, gid=gid, wwn=wwn) if not registered_wwns: msg = utils.output_log(MSG.NO_HBA_WWN_ADDED_TO_HOST_GRP, port=port, gid=gid) raise exception.VSPError(msg)
def _create_target(self, targets, port, connector, hba_ids): """Create a host group or an iSCSI target on the storage port.""" target_name, gid = self.create_target_to_storage(port, connector, hba_ids) utils.output_log(MSG.OBJECT_CREATED, object='a target', details='port: %(port)s, gid: %(gid)s, target_name: ' '%(target)s' % {'port': port, 'gid': gid, 'target': target_name}) try: self.set_target_mode(port, gid) self.set_hba_ids(port, gid, hba_ids) except exception.VSPError: with excutils.save_and_reraise_exception(): self.delete_target_from_storage(port, gid) targets['info'][port] = True targets['list'].append((port, gid))
def get_properties_iscsi(self, targets, multipath): """Check if specified iSCSI targets exist and store their IQNs.""" if not multipath: target_list = targets['list'][:1] else: target_list = targets['list'][:] for target in target_list: if target not in targets['iqns']: port, gid = target result = self.run_raidcom('get', 'host_grp', '-port', port) match = re.search( r"^CL\w-\w+ +%s +\S+ +(?P<iqn>\S+) +\w+ +\w +\d+ " % gid, result[1], re.M) if not match: msg = utils.output_log(MSG.RESOURCE_NOT_FOUND, resource='Target IQN') raise exception.VSPError(msg) targets['iqns'][target] = match.group('iqn') LOG.debug('Found iqn of the iSCSI target. (port: %(port)s, ' 'gid: %(gid)s, target iqn: %(iqn)s)', {'port': port, 'gid': gid, 'iqn': match.group('iqn')}) return super(VSPHORCMISCSI, self).get_properties_iscsi( targets, multipath)
def initialize_connection(self, volume, connector): """Initialize connection between the server and the volume.""" targets = { 'info': {}, 'list': [], 'lun': {}, 'iqns': {}, } ldev = utils.get_ldev(volume) # When 'ldev' is 0, it should be true. # Therefore, it cannot remove 'is None'. if ldev is None: msg = utils.output_log(MSG.INVALID_LDEV_FOR_CONNECTION, volume_id=volume['id']) raise exception.VSPError(msg) if (self.find_targets_from_storage(targets, connector, self.storage_info['ports']) and self.conf.vsp_group_request): self.create_mapping_targets(targets, connector) utils.require_target_existed(targets) targets['list'].sort() for port in self.storage_info['ports']: targets['lun'][port] = False target_lun = int(self.map_ldev(targets, ldev)) return { 'driver_volume_type': self.driver_info['volume_type'], 'data': self.get_properties(targets, connector, target_lun), }
def get_properties_iscsi(self, targets, multipath): """Check if specified iSCSI targets exist and store their IQNs.""" if not multipath: target_list = targets['list'][:1] else: target_list = targets['list'][:] for target in target_list: if target not in targets['iqns']: port, gid = target result = self.run_raidcom('get', 'host_grp', '-port', port) match = re.search( r"^CL\w-\w+ +%s +\S+ +(?P<iqn>\S+) +\w+ +\w +\d+ " % gid, result[1], re.M) if not match: msg = utils.output_log(MSG.RESOURCE_NOT_FOUND, resource='Target IQN') raise exception.VSPError(msg) targets['iqns'][target] = match.group('iqn') LOG.debug( 'Found iqn of the iSCSI target. (port: %(port)s, ' 'gid: %(gid)s, target iqn: %(iqn)s)', { 'port': port, 'gid': gid, 'iqn': match.group('iqn') }) return super(VSPHORCMISCSI, self).get_properties_iscsi(targets, multipath)
def create_mapping_targets(self, targets, connector): """Create server-storage connection for all specified storage ports.""" hba_ids = self.get_hba_ids_from_connector(connector) for port in targets['info'].keys(): if targets['info'][port]: continue try: self._create_target(targets, port, connector, hba_ids) except exception.VSPError: utils.output_log( self.driver_info['msg_id']['target'], port=port) if not targets['list']: self.find_targets_from_storage( targets, connector, targets['info'].keys())
def initialize_connection(self, volume, connector): """Initialize connection between the server and the volume.""" targets = { 'info': {}, 'list': [], 'lun': {}, 'iqns': {}, } ldev = utils.get_ldev(volume) # When 'ldev' is 0, it should be true. # Therefore, it cannot remove 'is None'. if ldev is None: msg = utils.output_log(MSG.INVALID_LDEV_FOR_CONNECTION, volume_id=volume['id']) raise exception.VSPError(msg) if (self.find_targets_from_storage( targets, connector, self.storage_info['ports']) and self.conf.vsp_group_request): self.create_mapping_targets(targets, connector) utils.require_target_existed(targets) targets['list'].sort() for port in self.storage_info['ports']: targets['lun'][port] = False target_lun = int(self.map_ldev(targets, ldev)) return { 'driver_volume_type': self.driver_info['volume_type'], 'data': self.get_properties(targets, connector, target_lun), }
def get_hba_ids_from_connector(self, connector): """Return the HBA ID stored in the connector.""" if self.driver_info['hba_id'] in connector: return connector[self.driver_info['hba_id']] msg = utils.output_log(MSG.RESOURCE_NOT_FOUND, resource=self.driver_info['hba_id_type']) raise exception.VSPError(msg)
def unmanage(self, volume): """Prepare the volume for removing it from Cinder management.""" ldev = utils.get_ldev(volume) # When 'ldev' is 0, it should be true. # Therefore, it cannot remove 'is None'. if ldev is None: utils.output_log(MSG.INVALID_LDEV_FOR_DELETION, method='unmanage', id=volume['id']) return if self.check_vvol(ldev): utils.output_log( MSG.INVALID_LDEV_TYPE_FOR_UNMANAGE, volume_id=volume['id'], volume_type=utils.NORMAL_LDEV_TYPE) raise exception.VolumeIsBusy(volume_name=volume['name']) try: self.delete_pair(ldev) except exception.VSPBusy: raise exception.VolumeIsBusy(volume_name=volume['name'])
def set_hba_ids(self, port, gid, hba_ids): """Connect all specified HBAs with the specified port.""" registered_wwns = [] for wwn in hba_ids: try: self.run_raidcom('add', 'hba_wwn', '-port', '-'.join([port, gid]), '-hba_wwn', wwn) registered_wwns.append(wwn) except exception.VSPError: utils.output_log(MSG.ADD_HBA_WWN_FAILED, port=port, gid=gid, wwn=wwn) if not registered_wwns: msg = utils.output_log(MSG.NO_HBA_WWN_ADDED_TO_HOST_GRP, port=port, gid=gid) raise exception.VSPError(msg)
def manage_existing_get_size(self, existing_ref): """Return the size[GB] of the specified volume.""" ldev = _str2int(existing_ref.get('source-id')) # When 'ldev' is 0, it should be true. # Therefore, it cannot remove 'is None'. if ldev is None: msg = utils.output_log(MSG.INVALID_LDEV_FOR_MANAGE) raise exception.ManageExistingInvalidReference( existing_ref=existing_ref, reason=msg) return self.get_ldev_size_in_gigabyte(ldev, existing_ref)
def _range2list(self, param): """Analyze a 'xxx-xxx' string and return a list of two integers.""" values = [_str2int(value) for value in self.conf.safe_get(param).split('-')] if (len(values) != 2 or values[0] is None or values[1] is None or values[0] > values[1]): msg = utils.output_log(MSG.INVALID_PARAMETER, param=param) raise exception.VSPError(msg) return values
def _range2list(self, param): """Analyze a 'xxx-xxx' string and return a list of two integers.""" values = [ _str2int(value) for value in self.conf.safe_get(param).split('-') ] if (len(values) != 2 or values[0] is None or values[1] is None or values[0] > values[1]): msg = utils.output_log(MSG.INVALID_PARAMETER, param=param) raise exception.VSPError(msg) return values