def get_iscsi_properties(self, volume): if not volume['provider_location']: err = _("Param volume['provider_location'] is invalid.") raise exception.InvalidParameterValue(err=err) iqn, trg_id = self.get_iqn_and_trgid(volume['provider_location']) iscsi_properties = { 'target_discovered': False, 'target_iqn': iqn, 'target_portal': '%(ip)s:%(port)d' % { 'ip': self.get_ip(), 'port': self.iscsi_port }, 'volume_id': volume['id'], 'access_mode': 'rw', 'discard': False } ips = self.config.safe_get('iscsi_secondary_ip_addresses') if ips: target_portals = [iscsi_properties['target_portal']] for ip in ips: target_portals.append('%(ip)s:%(port)d' % { 'ip': ip, 'port': self.iscsi_port }) iscsi_properties.update(target_portals=target_portals) count = len(target_portals) iscsi_properties.update( target_iqns=[iscsi_properties['target_iqn']] * count) iscsi_properties.update(target_lun=0) iscsi_properties.update( target_luns=[iscsi_properties['target_lun']] * count) if 'provider_auth' in volume: auth = volume['provider_auth'] if auth: try: (auth_method, auth_username, auth_password) = auth.split() iscsi_properties['auth_method'] = auth_method iscsi_properties['auth_username'] = auth_username iscsi_properties['auth_password'] = auth_password except Exception: LOG.error(_LE('Invalid provider_auth: %s'), auth) return iscsi_properties
def get_iqn_and_trgid(self, location): if not location: err = _('Param [location] is invalid.') raise exception.InvalidParameterValue(err=err) result = location.split(' ') if len(result) < 2: raise exception.InvalidInput(reason=location) data = result[0].split(',') if len(data) < 2: raise exception.InvalidInput(reason=location) iqn = result[1] trg_id = data[1] return iqn, int(trg_id, 10)
def _target_create(self, identifier): if not identifier: err = _('Param [identifier] is invalid.') raise exception.InvalidParameterValue(err=err) # 0 for no auth, 1 for single chap, 2 for mutual chap auth_type = 0 chap_username = '' chap_password = '' provider_auth = '' if self.config.safe_get('use_chap_auth') and self.config.use_chap_auth: auth_type = 1 chap_username = (self.config.safe_get('chap_username') or volutils.generate_username(12)) chap_password = (self.config.safe_get('chap_password') or volutils.generate_password()) provider_auth = ' '.join(('CHAP', chap_username, chap_password)) trg_prefix = self.config.safe_get('target_prefix') trg_name = (self.TARGET_NAME_PREFIX + '%s') % identifier iqn = trg_prefix + trg_name try: out = self.exec_webapi('SYNO.Core.ISCSI.Target', 'create', 1, name=trg_name, iqn=iqn, auth_type=auth_type, user=chap_username, password=chap_password, max_sessions=0) self.check_response(out) except Exception: with excutils.save_and_reraise_exception(): LOG.exception('Failed to _target_create. [%s]', identifier) if not self.check_value_valid(out, ['data', 'target_id']): msg = _('Failed to get target_id of target [%s]') % trg_name raise exception.VolumeDriverException(message=msg) trg_id = out['data']['target_id'] return iqn, trg_id, provider_auth
def create(self, req, body): """Creates a new snapshot.""" kwargs = {} context = req.environ['cinder.context'] self.assert_valid_body(body, 'snapshot') snapshot = body['snapshot'] kwargs['metadata'] = snapshot.get('metadata', None) try: volume_id = snapshot['volume_id'] except KeyError: msg = _("'volume_id' must be specified") raise exc.HTTPBadRequest(explanation=msg) try: volume = self.volume_api.get(context, volume_id) except exception.VolumeNotFound as error: raise exc.HTTPNotFound(explanation=error.msg) force = snapshot.get('force', False) msg = _LI("Create snapshot from volume %s") LOG.info(msg, volume_id, context=context) self.validate_name_and_description(snapshot) # NOTE(thingee): v2 API allows name instead of display_name if 'name' in snapshot: snapshot['display_name'] = snapshot.pop('name') try: force = strutils.bool_from_string(force, strict=True) except ValueError as error: msg = _("Invalid value for 'force': '%s'") % error.message raise exception.InvalidParameterValue(err=msg) if force: new_snapshot = self.volume_api.create_snapshot_force( context, volume, snapshot.get('display_name'), snapshot.get('description'), **kwargs) else: new_snapshot = self.volume_api.create_snapshot( context, volume, snapshot.get('display_name'), snapshot.get('description'), **kwargs) req.cache_db_snapshot(new_snapshot) return self._view_builder.detail(req, new_snapshot)
def _get_backup_base_name(self, volume_id, backup_id=None, diff_format=False): """Return name of base image used for backup. Incremental backups use a new base name so we support old and new style format. """ # Ensure no unicode if diff_format: return strutils.safe_encode("volume-%s.backup.base" % (volume_id)) else: if backup_id is None: msg = _("Backup id required") raise exception.InvalidParameterValue(msg) return strutils.safe_encode("volume-%s.backup.%s" % (volume_id, backup_id))
def __init__(self, source_helper, target_device): self._source_helper = source_helper connection_type = target_device.get('connection_type') if connection_type == storage.XIV_CONNECTION_TYPE_FC: self._target_helper = ( helper.DS8KReplicationTargetHelper(target_device)) elif connection_type == storage.XIV_CONNECTION_TYPE_FC_ECKD: self._target_helper = ( helper.DS8KReplicationTargetECKDHelper(target_device)) else: raise exception.InvalidParameterValue( err=(_("Param [connection_type] %s in replication_device " "is invalid.") % connection_type)) self._target_helper.backend['lss_ids_for_cg'] = ( self._source_helper.backend['lss_ids_for_cg']) self._mm_manager = MetroMirrorManager(self._source_helper, self._target_helper)
def _get_lss_ids_for_cg(self): lss_range = self._get_value('lss_range_for_cg') if lss_range: lss_range = lss_range.replace(' ', '').split('-') if len(lss_range) == 1: begin = int(lss_range[0], 16) end = begin else: begin = int(lss_range[0], 16) end = int(lss_range[1], 16) if begin > 0xFF or end > 0xFF or begin > end: raise exception.InvalidParameterValue( err=_('Param [lss_range_for_cg] is invalid, it ' 'should be within 00-FF.')) self.backend['lss_ids_for_cg'] = set( ('%02x' % i).upper() for i in range(begin, end + 1)) else: self.backend['lss_ids_for_cg'] = set()
def create(self, req, body): """Creates a new snapshot.""" kwargs = {} context = req.environ['cinder.context'] if not self.is_valid_body(body, 'snapshot'): raise exc.HTTPBadRequest() snapshot = body['snapshot'] kwargs['metadata'] = snapshot.get('metadata', None) volume_id = snapshot['volume_id'] volume = self.volume_api.get(context, volume_id) force = snapshot.get('force', False) msg = _("Create snapshot from volume %s") LOG.audit(msg, volume_id, context=context) # NOTE(thingee): v2 API allows name instead of display_name if 'name' in snapshot: snapshot['display_name'] = snapshot.get('name') del snapshot['name'] if not utils.is_valid_boolstr(force): msg = _("Invalid value '%s' for force. ") % force raise exception.InvalidParameterValue(err=msg) if utils.bool_from_str(force): new_snapshot = self.volume_api.create_snapshot_force( context, volume, snapshot.get('display_name'), snapshot.get('description'), **kwargs) else: new_snapshot = self.volume_api.create_snapshot( context, volume, snapshot.get('display_name'), snapshot.get('description'), **kwargs) retval = _translate_snapshot_detail_view(context, new_snapshot) return {'snapshot': retval}
def create(self, req, body): """Creates a new snapshot.""" kwargs = {} context = req.environ['cinder.context'] if not self.is_valid_body(body, 'snapshot'): raise exc.HTTPUnprocessableEntity() snapshot = body['snapshot'] kwargs['metadata'] = snapshot.get('metadata', None) try: volume_id = snapshot['volume_id'] except KeyError: msg = _("'volume_id' must be specified") raise exc.HTTPBadRequest(explanation=msg) try: volume = self.volume_api.get(context, volume_id) except exception.NotFound: raise exc.HTTPNotFound() force = snapshot.get('force', False) msg = _("Create snapshot from volume %s") LOG.info(msg, volume_id, context=context) if not utils.is_valid_boolstr(force): msg = _("Invalid value '%s' for force. ") % force raise exception.InvalidParameterValue(err=msg) if strutils.bool_from_string(force): new_snapshot = self.volume_api.create_snapshot_force( context, volume, snapshot.get('display_name'), snapshot.get('display_description'), **kwargs) else: new_snapshot = self.volume_api.create_snapshot( context, volume, snapshot.get('display_name'), snapshot.get('display_description'), **kwargs) req.cache_db_snapshot(new_snapshot) retval = _translate_snapshot_detail_view(context, new_snapshot) return {'snapshot': retval}
def do_setup(self, context): """Sets up and verify Hitachi HNAS storage connection.""" self.context = context self._check_fs_list() version_info = self.backend.get_version() LOG.info(_LI("HNAS iSCSI driver.")) LOG.info(_LI("HNAS model: %(mdl)s"), {'mdl': version_info['model']}) LOG.info(_LI("HNAS version: %(version)s"), {'version': version_info['version']}) LOG.info(_LI("HNAS hardware: %(hw)s"), {'hw': version_info['hardware']}) LOG.info(_LI("HNAS S/N: %(sn)s"), {'sn': version_info['serial']}) service_list = self.config['services'].keys() for svc in service_list: svc = self.config['services'][svc] pool = {} pool['pool_name'] = svc['volume_type'] pool['service_label'] = svc['volume_type'] pool['fs'] = svc['hdp'] self.pools.append(pool) LOG.debug("Configured pools: %(pool)s", {'pool': self.pools}) evs_info = self.backend.get_evs_info() LOG.info(_LI("Configured EVSs: %(evs)s"), {'evs': evs_info}) for svc in self.config['services'].keys(): svc_ip = self.config['services'][svc]['iscsi_ip'] if svc_ip in evs_info.keys(): LOG.info(_LI("iSCSI portal found for service: %(svc_ip)s"), {'svc_ip': svc_ip}) self.config['services'][svc]['evs'] = ( evs_info[svc_ip]['evs_number']) self.config['services'][svc]['iscsi_port'] = '3260' self.config['services'][svc]['port'] = '0' else: LOG.error( _LE("iSCSI portal not found " "for service: %(svc)s"), {'svc': svc_ip}) raise exception.InvalidParameterValue(err=svc_ip) LOG.info(_LI("HNAS iSCSI Driver loaded successfully."))
def _parse_ns_output(self, switch_data): """Parses name server data. Parses nameserver raw data and adds the device port wwns to the list :returns: List -- list of device port wwn from ns info """ return_list = [] for line in switch_data: if not (" NL " in line or " N " in line): continue linesplit = line.split(';') if len(linesplit) > 2: node_port_wwn = linesplit[2] return_list.append(node_port_wwn) else: msg = _("Malformed nameserver string: %s") % line LOG.error(msg) raise exception.InvalidParameterValue(err=msg) return return_list
def setup(self, ctxt): LOG.info("Initiating connection to IBM DS8K storage system.") connection_type = self.configuration.safe_get('connection_type') replication_devices = self.configuration.safe_get('replication_device') if connection_type == storage.XIV_CONNECTION_TYPE_FC: if not replication_devices: self._helper = helper.DS8KCommonHelper(self.configuration, self._connector_obj) else: self._helper = (helper.DS8KReplicationSourceHelper( self.configuration, self._connector_obj)) elif connection_type == storage.XIV_CONNECTION_TYPE_FC_ECKD: self._helper = helper.DS8KECKDHelper(self.configuration, self._connector_obj) else: err = (_("Param [connection_type] %s is invalid.") % connection_type) raise exception.InvalidParameterValue(err=err) if replication_devices: self._do_replication_setup(replication_devices, self._helper)
def show_target(self, tid, iqn=None, **kwargs): conf_file = self.ctl_conf if iqn is None: raise exception.InvalidParameterValue( err=_('valid iqn needed for show_target')) if os.path.exists(conf_file): with utils.temporary_chown(conf_file): try: ctl_conf_text = open(conf_file, 'r+') full_txt = ctl_conf_text.readlines() for line in full_txt: if re.search(iqn, line): ctl_conf_text.close() return finally: ctl_conf_text.close() raise exception.NotFound()
def _get_lun_status(self, lun_name): if not lun_name: err = _('Param [lun_name] is invalid.') raise exception.InvalidParameterValue(err=err) try: lun_info = self._get_lun_info(lun_name, ['status', 'is_action_locked']) except Exception: with excutils.save_and_reraise_exception(): LOG.exception('Failed to _get_lun_status. [%s]', lun_name) if not self.check_value_valid(lun_info, ['status'], string_types): raise exception.MalformedResponse(cmd='_get_lun_status', reason=_('status not found')) if not self.check_value_valid(lun_info, ['is_action_locked'], bool): raise exception.MalformedResponse(cmd='_get_lun_status', reason=_('action_locked ' 'not found')) return lun_info['status'], lun_info['is_action_locked']
def file_clone(self, fs_label, src, name): """Clones NFS files to a new one named 'name'. Clone primitive used to support all NFS snapshot/cloning functions. :param fs_label: file system label of the new file :param src: source file :param name: target path of the new created file """ fs_list = self._get_fs_list() fs = fs_list.get(fs_label) if not fs: LOG.error("Can't find file %(file)s in FS %(label)s", {'file': src, 'label': fs_label}) msg = _('FS label: %(fs_label)s') % {'fs_label': fs_label} raise exception.InvalidParameterValue(err=msg) self._run_cmd("console-context", "--evs", fs['evsid'], 'file-clone-create', '-f', fs_label, src, name) LOG.debug('file_clone: fs:%(fs_label)s %(src)s/src: -> %(name)s/dst', {'fs_label': fs_label, 'src': src, 'name': name})
def get_all(self, context, search_opts=None, marker=None, limit=None, offset=None, sort_keys=None, sort_dirs=None): context.authorize(policy.GET_ALL_POLICY) search_opts = search_opts or {} all_tenants = search_opts.pop('all_tenants', '0') if not strutils.is_valid_boolstr(all_tenants): msg = _("all_tenants must be a boolean, got '%s'.") % all_tenants raise exception.InvalidParameterValue(err=msg) if context.is_admin and strutils.bool_from_string(all_tenants): backups = objects.BackupList.get_all(context, search_opts, marker, limit, offset, sort_keys, sort_dirs) else: backups = objects.BackupList.get_all_by_project( context, context.project_id, search_opts, marker, limit, offset, sort_keys, sort_dirs ) return backups
def _get_lun_info(self, lun_name, additional=None): if not lun_name: err = _('Param [lun_name] is invalid.') raise exception.InvalidParameterValue(err=err) params = {'uuid': lun_name} if additional is not None: params['additional'] = additional try: out = self.exec_webapi('SYNO.Core.ISCSI.LUN', 'get', 1, **params) self.check_response(out, uuid=lun_name) except Exception: with excutils.save_and_reraise_exception(): LOG.exception('Failed to _get_lun_info. [%s]', lun_name) if not self.check_value_valid(out, ['data', 'lun'], object): raise exception.MalformedResponse(cmd='_get_lun_info', reason=_('lun info not found')) return out['data']['lun']
def _lun_map_unmap_target(self, volume_name, is_map, trg_id): if 0 > trg_id: err = _('trg_id is invalid: %d.') % trg_id raise exception.InvalidParameterValue(err=err) try: lun_uuid = self._get_lun_uuid(volume_name) out = self.exec_webapi('SYNO.Core.ISCSI.LUN', 'map_target' if is_map else 'unmap_target', 1, uuid=lun_uuid, target_ids=['%d' % trg_id]) self.check_response(out) except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_LE('Failed to _lun_map_unmap_target.' '[%(action)s][%(vol)s].'), {'action': ('map_target' if is_map else 'unmap_target'), 'vol': volume_name})
def _clear_volume(self, volume, is_snapshot=False): # zero out old volumes to prevent data leaking between users # TODO(ja): reclaiming space should be done lazy and low priority if is_snapshot: # if the volume to be cleared is a snapshot of another volume # we need to clear out the volume using the -cow instead of the # directly volume path. We need to skip this if we are using # thin provisioned LVs. # bug# lp1191812 dev_path = self.local_path(volume) + "-cow" else: dev_path = self.local_path(volume) # TODO(jdg): Maybe we could optimize this for snaps by looking at # the cow table and only overwriting what's necessary? # for now we're still skipping on snaps due to hang issue if not os.path.exists(dev_path): msg = (_('Volume device file path %s does not exist.') % dev_path) LOG.error(msg) raise exception.VolumeBackendAPIException(data=msg) size_in_g = (volume.get('volume_size') if is_snapshot else volume.get('size')) if size_in_g is None: msg = (_("Size for volume: %s not found, cannot secure delete.") % volume['id']) LOG.error(msg) raise exception.InvalidParameterValue(msg) # clear_volume expects sizes in MiB, we store integer GiB # be sure to convert before passing in vol_sz_in_meg = size_in_g * units.Ki volutils.clear_volume( vol_sz_in_meg, dev_path, volume_clear=self.configuration.volume_clear, volume_clear_size=self.configuration.volume_clear_size)
def _create_client(self): san_ip = self._get_value('san_ip') try: clear_pass = cryptish.decrypt(self._get_value('san_password')) except TypeError: raise exception.InvalidParameterValue( err=_('Param [san_password] is invalid.')) verify = self._get_certificate(san_ip) try: self._client = restclient.RESTScheduler( san_ip, self._get_value('san_login'), clear_pass, self._connector_obj, verify) except restclient.TimeoutException: raise restclient.APIException( data=(_("Can't connect to %(host)s") % {'host': san_ip})) self.backend['rest_version'] = self._get_version()['bundle_version'] LOG.info("Connection to DS8K storage system %(host)s has been " "established successfully, the version of REST is %(rest)s.", {'host': self._get_value('san_ip'), 'rest': self.backend['rest_version']})
def _get_snapshot_status(self, snapshot_uuid): if not snapshot_uuid: err = _('Param [snapshot_uuid] is invalid.') raise exception.InvalidParameterValue(err=err) try: snapshot_info = self._get_snapshot_info( snapshot_uuid, ['status', 'is_action_locked']) except Exception: with excutils.save_and_reraise_exception(): LOG.exception('Failed to _get_snapshot_info. [%s]', snapshot_uuid) if not self.check_value_valid(snapshot_info, ['status'], string_types): raise exception.MalformedResponse(cmd='_get_snapshot_status', reason=_('status not found')) if not self.check_value_valid(snapshot_info, ['is_action_locked'], bool): raise exception.MalformedResponse(cmd='_get_snapshot_status', reason=_('action_locked ' 'not found')) return snapshot_info['status'], snapshot_info['is_action_locked']
def test_query_aggr_options(self): na_server = netapp_api.NaServer('127.0.0.1') body = etree.XML("""<results status="passed"> <options> <aggr-option-info> <name>ha_policy</name> <value>cfo</value> </aggr-option-info> <aggr-option-info> <name>raidtype</name> <value>raid_dp</value> </aggr-option-info> </options> </results>""") self.mock_object(ssc_cmode.netapp_api, 'invoke_api', mock.Mock(return_value=[netapp_api.NaElement(body)])) aggr_attribs = ssc_cmode.query_aggr_options(na_server, 'aggr0') if aggr_attribs: self.assertEqual('cfo', aggr_attribs['ha_policy']) self.assertEqual('raid_dp', aggr_attribs['raid_type']) else: raise exception.InvalidParameterValue("Incorrect aggr options")
def update(self, req, id, body): """Update Quota for a particular tenant This works for hierarchical and non-hierarchical projects. For hierarchical projects only immediate parent admin or the CLOUD admin are able to perform an update. :param req: request :param id: target project id that needs to be updated :param body: key, value pair that that will be applied to the resources if the update succeeds """ context = req.environ['cinder.context'] authorize_update(context) self.validate_string_length(id, 'quota_set_name', min_length=1, max_length=255) self.assert_valid_body(body, 'quota_set') # Get the optional argument 'skip_validation' from body, # if skip_validation is False, then validate existing resource. skip_flag = body.get('skip_validation', True) if not utils.is_valid_boolstr(skip_flag): msg = _("Invalid value '%s' for skip_validation.") % skip_flag raise exception.InvalidParameterValue(err=msg) skip_flag = strutils.bool_from_string(skip_flag) target_project_id = id bad_keys = [] # NOTE(ankit): Pass #1 - In this loop for body['quota_set'].items(), # we figure out if we have any bad keys. for key, value in body['quota_set'].items(): if (key not in QUOTAS and key not in NON_QUOTA_KEYS): bad_keys.append(key) continue if len(bad_keys) > 0: msg = _("Bad key(s) in quota set: %s") % ",".join(bad_keys) raise webob.exc.HTTPBadRequest(explanation=msg) # Saving off this value since we need to use it multiple times use_nested_quotas = QUOTAS.using_nested_quotas() if use_nested_quotas: # Get the parent_id of the target project to verify whether we are # dealing with hierarchical namespace or non-hierarchical namespace target_project = quota_utils.get_project_hierarchy( context, target_project_id, parents_as_ids=True) parent_id = target_project.parent_id if parent_id: # Get the children of the project which the token is scoped to # in order to know if the target_project is in its hierarchy. context_project = quota_utils.get_project_hierarchy( context, context.project_id, subtree_as_ids=True, is_admin_project=context.is_admin) self._authorize_update_or_delete(context_project, target_project.id, parent_id) # NOTE(ankit): Pass #2 - In this loop for body['quota_set'].keys(), # we validate the quota limits to ensure that we can bail out if # any of the items in the set is bad. Meanwhile we validate value # to ensure that the value can't be lower than number of existing # resources. quota_values = QUOTAS.get_project_quotas(context, target_project_id, defaults=False) valid_quotas = {} reservations = [] for key in body['quota_set'].keys(): if key in NON_QUOTA_KEYS: continue value = utils.validate_integer(body['quota_set'][key], key, min_value=-1, max_value=db.MAX_INT) # Can't skip the validation of nested quotas since it could mess up # hierarchy if parent limit is less than childrens' current usage if not skip_flag or use_nested_quotas: self._validate_existing_resource(key, value, quota_values) if use_nested_quotas: try: reservations += self._update_nested_quota_allocated( context, target_project, quota_values, key, value) except exception.OverQuota as e: if reservations: db.reservation_rollback(context, reservations) raise webob.exc.HTTPBadRequest(explanation=e.message) valid_quotas[key] = value # NOTE(ankit): Pass #3 - At this point we know that all the keys and # values are valid and we can iterate and update them all in one shot # without having to worry about rolling back etc as we have done # the validation up front in the 2 loops above. for key, value in valid_quotas.items(): try: db.quota_update(context, target_project_id, key, value) except exception.ProjectQuotaNotFound: db.quota_create(context, target_project_id, key, value) except exception.AdminRequired: raise webob.exc.HTTPForbidden() if reservations: db.reservation_commit(context, reservations) return {'quota_set': self._get_quotas(context, target_project_id)}
def get_device_mapping_from_network(self, initiator_wwn_list, target_wwn_list): """Provides the initiator/target map for available SAN contexts. Looks up nameserver of each fc SAN configured to find logged in devices and returns a map of initiator and target port WWNs for each fabric. :param initiator_wwn_list: List of initiator port WWN :param target_wwn_list: List of target port WWN :returns: List -- device wwn map in following format .. code-block:: default { <San name>: { 'initiator_port_wwn_list': ('200000051e55a100', '200000051e55a121'..) 'target_port_wwn_list': ('100000051e55a100', '100000051e55a121'..) } } :raises Exception: when connection to fabric is failed """ device_map = {} formatted_target_list = [] formatted_initiator_list = [] fabric_map = {} fabric_names = self.configuration.fc_fabric_names fabrics = None if not fabric_names: raise exception.InvalidParameterValue( err=_("Missing Fibre Channel SAN configuration " "param - fc_fabric_names")) fabrics = [x.strip() for x in fabric_names.split(',')] LOG.debug("FC Fabric List: %s", fabrics) if fabrics: for t in target_wwn_list: formatted_target_list.append(fczm_utils.get_formatted_wwn(t)) for i in initiator_wwn_list: formatted_initiator_list.append( fczm_utils.get_formatted_wwn(i)) for fabric_name in fabrics: fabric_ip = self.fabric_configs[fabric_name].safe_get( 'fc_fabric_address') # Get name server data from fabric and find the targets # logged in nsinfo = '' try: LOG.debug("Getting name server data for " "fabric %s", fabric_ip) conn = self._get_southbound_client(fabric_name) nsinfo = conn.get_nameserver_info() except exception.FCSanLookupServiceException: with excutils.save_and_reraise_exception(): LOG.error( "Failed collecting name server info from" " fabric %s", fabric_ip) except Exception as e: msg = _("SSH connection failed " "for %(fabric)s with error: %(err)s") % { 'fabric': fabric_ip, 'err': e } LOG.error(msg) raise exception.FCSanLookupServiceException(message=msg) LOG.debug("Lookup service:nsinfo-%s", nsinfo) LOG.debug("Lookup service:initiator list from " "caller-%s", formatted_initiator_list) LOG.debug("Lookup service:target list from " "caller-%s", formatted_target_list) visible_targets = [ x for x in nsinfo if x in formatted_target_list ] visible_initiators = [ x for x in nsinfo if x in formatted_initiator_list ] if visible_targets: LOG.debug("Filtered targets is: %s", visible_targets) # getting rid of the : before returning for idx, elem in enumerate(visible_targets): elem = str(elem).replace(':', '') visible_targets[idx] = elem else: LOG.debug("No targets are in the nameserver for SAN %s", fabric_name) if visible_initiators: # getting rid of the : before returning ~sk for idx, elem in enumerate(visible_initiators): elem = str(elem).replace(':', '') visible_initiators[idx] = elem else: LOG.debug( "No initiators are in the nameserver " "for SAN %s", fabric_name) fabric_map = { 'initiator_port_wwn_list': visible_initiators, 'target_port_wwn_list': visible_targets } device_map[fabric_name] = fabric_map LOG.debug("Device map for SAN context: %s", device_map) return device_map
def get_device_mapping_from_network(self, initiator_wwn_list, target_wwn_list): """Provides the initiator/target map for available SAN contexts. Looks up fcns database of each fc SAN configured to find logged in devices and returns a map of initiator and target port WWNs for each fabric. :param initiator_wwn_list: List of initiator port WWN :param target_wwn_list: List of target port WWN :returns: List -- device wwn map in following format { <San name>: { 'initiator_port_wwn_list': ('200000051e55a100', '200000051e55a121'..) 'target_port_wwn_list': ('100000051e55a100', '100000051e55a121'..) } } :raises: Exception when connection to fabric is failed """ device_map = {} formatted_target_list = [] formatted_initiator_list = [] fabric_map = {} fabric_names = self.configuration.fc_fabric_names if not fabric_names: raise exception.InvalidParameterValue( err=_("Missing Fibre Channel SAN configuration " "param - fc_fabric_names")) fabrics = [x.strip() for x in fabric_names.split(',')] LOG.debug("FC Fabric List: %s", fabrics) if fabrics: for t in target_wwn_list: formatted_target_list.append(zm_utils.get_formatted_wwn(t)) for i in initiator_wwn_list: formatted_initiator_list.append(zm_utils.get_formatted_wwn(i)) for fabric_name in fabrics: self.switch_ip = self.fabric_configs[fabric_name].safe_get( 'cisco_fc_fabric_address') self.switch_user = self.fabric_configs[fabric_name].safe_get( 'cisco_fc_fabric_user') self.switch_pwd = self.fabric_configs[fabric_name].safe_get( 'cisco_fc_fabric_password') self.switch_port = self.fabric_configs[fabric_name].safe_get( 'cisco_fc_fabric_port') zoning_vsan = self.fabric_configs[fabric_name].safe_get( 'cisco_zoning_vsan') # Get name server data from fabric and find the targets # logged in nsinfo = '' LOG.debug("show fcns database for vsan %s", zoning_vsan) nsinfo = self.get_nameserver_info(zoning_vsan) LOG.debug("Lookup service:fcnsdatabase-%s", nsinfo) LOG.debug("Lookup service:initiator list from caller-%s", formatted_initiator_list) LOG.debug("Lookup service:target list from caller-%s", formatted_target_list) visible_targets = [ x for x in nsinfo if x in formatted_target_list ] visible_initiators = [ x for x in nsinfo if x in formatted_initiator_list ] if visible_targets: LOG.debug("Filtered targets is: %s", visible_targets) # getting rid of the : before returning for idx, elem in enumerate(visible_targets): elem = str(elem).replace(':', '') visible_targets[idx] = elem else: LOG.debug( "No targets are in the fcns database" " for vsan %s", zoning_vsan) if visible_initiators: # getting rid of the : before returning ~sk for idx, elem in enumerate(visible_initiators): elem = str(elem).replace(':', '') visible_initiators[idx] = elem else: LOG.debug( "No initiators are in the fcns database" " for vsan %s", zoning_vsan) fabric_map = { 'initiator_port_wwn_list': visible_initiators, 'target_port_wwn_list': visible_targets } device_map[zoning_vsan] = fabric_map LOG.debug("Device map for SAN context: %s", device_map) return device_map
def update(self, req, id, body): """Update Quota for a particular tenant This works for hierarchical and non-hierarchical projects. For hierarchical projects only immediate parent admin or the CLOUD admin are able to perform an update. :param req: request :param id: target project id that needs to be updated :param body: key, value pair that that will be applied to the resources if the update succeeds """ context = req.environ['cinder.context'] authorize_update(context) self.validate_string_length(id, 'quota_set_name', min_length=1, max_length=255) self.assert_valid_body(body, 'quota_set') # Get the optional argument 'skip_validation' from body, # if skip_validation is False, then validate existing resource. skip_flag = body.get('skip_validation', True) if not utils.is_valid_boolstr(skip_flag): msg = _("Invalid value '%s' for skip_validation.") % skip_flag raise exception.InvalidParameterValue(err=msg) skip_flag = strutils.bool_from_string(skip_flag) target_project_id = id bad_keys = [] # NOTE(ankit): Pass #1 - In this loop for body['quota_set'].items(), # we figure out if we have any bad keys. for key, value in body['quota_set'].items(): if (key not in QUOTAS and key not in NON_QUOTA_KEYS): bad_keys.append(key) continue if len(bad_keys) > 0: msg = _("Bad key(s) in quota set: %s") % ",".join(bad_keys) raise webob.exc.HTTPBadRequest(explanation=msg) # Get the parent_id of the target project to verify whether we are # dealing with hierarchical namespace or non-hierarchical namespace. target_project = self._get_project(context, target_project_id) parent_id = target_project.parent_id if parent_id: # Get the children of the project which the token is scoped to # in order to know if the target_project is in its hierarchy. context_project = self._get_project(context, context.project_id, subtree_as_ids=True) self._authorize_update_or_delete(context_project, target_project.id, parent_id) parent_project_quotas = QUOTAS.get_project_quotas( context, parent_id) # NOTE(ankit): Pass #2 - In this loop for body['quota_set'].keys(), # we validate the quota limits to ensure that we can bail out if # any of the items in the set is bad. Meanwhile we validate value # to ensure that the value can't be lower than number of existing # resources. quota_values = QUOTAS.get_project_quotas(context, target_project_id, defaults=False) valid_quotas = {} allocated_quotas = {} for key in body['quota_set'].keys(): if key in NON_QUOTA_KEYS: continue if not skip_flag: self._validate_existing_resource(key, value, quota_values) if parent_id: value = self._validate_quota_limit(body['quota_set'], key, quota_values, parent_project_quotas) original_quota = 0 if quota_values.get(key): original_quota = quota_values[key]['limit'] allocated_quotas[key] = ( parent_project_quotas[key].get('allocated', 0) + value - original_quota) else: value = self._validate_quota_limit(body['quota_set'], key) valid_quotas[key] = value # NOTE(ankit): Pass #3 - At this point we know that all the keys and # values are valid and we can iterate and update them all in one shot # without having to worry about rolling back etc as we have done # the validation up front in the 2 loops above. for key, value in valid_quotas.items(): try: db.quota_update(context, target_project_id, key, value) except exception.ProjectQuotaNotFound: db.quota_create(context, target_project_id, key, value) except exception.AdminRequired: raise webob.exc.HTTPForbidden() # If hierarchical projects, update child's quota first # and then parents quota. In future this needs to be an # atomic operation. if parent_id: if key in allocated_quotas.keys(): try: db.quota_allocated_update(context, parent_id, key, allocated_quotas[key]) except exception.ProjectQuotaNotFound: parent_limit = parent_project_quotas[key]['limit'] db.quota_create(context, parent_id, key, parent_limit, allocated=allocated_quotas[key]) return { 'quota_set': self._get_quotas(context, target_project_id, parent_project_id=parent_id) }
def do_setup(self, context): """Perform internal driver setup.""" version_info = self.backend.get_version() LOG.info("HNAS NFS driver.") LOG.info("HNAS model: %(mdl)s", {'mdl': version_info['model']}) LOG.info("HNAS version: %(ver)s", {'ver': version_info['version']}) LOG.info("HNAS hardware: %(hw)s", {'hw': version_info['hardware']}) LOG.info("HNAS S/N: %(sn)s", {'sn': version_info['serial']}) self.context = context self._load_shares_config( getattr(self.configuration, self.driver_prefix + '_shares_config')) LOG.info("Review shares: %(shr)s", {'shr': self.shares}) elist = self.backend.get_export_list() # Check for all configured exports for svc_name, svc_info in self.config['services'].items(): server_ip = svc_info['hdp'].split(':')[0] mountpoint = svc_info['hdp'].split(':')[1] # Ensure export are configured in HNAS export_configured = False for export in elist: if mountpoint == export['name'] and server_ip in export['evs']: svc_info['export'] = export export_configured = True # Ensure export are reachable try: out, err = self._execute('showmount', '-e', server_ip) except processutils.ProcessExecutionError: LOG.exception("NFS server %(srv)s not reachable!", {'srv': server_ip}) raise export_list = out.split('\n')[1:] export_list.pop() mountpoint_not_found = mountpoint not in map( lambda x: x.split()[0], export_list) if (len(export_list) < 1 or mountpoint_not_found or not export_configured): LOG.error( "Configured share %(share)s is not present" "in %(srv)s.", { 'share': mountpoint, 'srv': server_ip }) msg = _('Section: %(svc_name)s') % {'svc_name': svc_name} raise exception.InvalidParameterValue(err=msg) LOG.debug("Loading services: %(svc)s", {'svc': self.config['services']}) service_list = self.config['services'].keys() for svc in service_list: svc = self.config['services'][svc] pool = {} pool['pool_name'] = svc['pool_name'] pool['service_label'] = svc['pool_name'] pool['fs'] = svc['hdp'] self.pools.append(pool) LOG.debug("Configured pools: %(pool)s", {'pool': self.pools}) LOG.info("HNAS NFS Driver loaded successfully.")
def update(self, req, id, body): context = req.environ['cinder.context'] authorize_update(context) self.validate_string_length(id, 'quota_set_name', min_length=1, max_length=255) project_id = id self.assert_valid_body(body, 'quota_set') # Get the optional argument 'skip_validation' from body, # if skip_validation is False, then validate existing resource. skip_flag = body.get('skip_validation', True) if not utils.is_valid_boolstr(skip_flag): msg = _("Invalid value '%s' for skip_validation.") % skip_flag raise exception.InvalidParameterValue(err=msg) skip_flag = strutils.bool_from_string(skip_flag) bad_keys = [] # NOTE(ankit): Pass #1 - In this loop for body['quota_set'].items(), # we figure out if we have any bad keys. for key, value in body['quota_set'].items(): if (key not in QUOTAS and key not in NON_QUOTA_KEYS): bad_keys.append(key) continue if len(bad_keys) > 0: msg = _("Bad key(s) in quota set: %s") % ",".join(bad_keys) raise webob.exc.HTTPBadRequest(explanation=msg) # NOTE(ankit): Pass #2 - In this loop for body['quota_set'].keys(), # we validate the quota limits to ensure that we can bail out if # any of the items in the set is bad. Meanwhile we validate value # to ensure that the value can't be lower than number of existing # resources. quota_values = QUOTAS.get_project_quotas(context, project_id) valid_quotas = {} for key in body['quota_set'].keys(): if key in NON_QUOTA_KEYS: continue valid_quotas[key] = self.validate_integer(body['quota_set'][key], key, min_value=-1, max_value=db.MAX_INT) if not skip_flag: self._validate_existing_resource(key, value, quota_values) # NOTE(ankit): Pass #3 - At this point we know that all the keys and # values are valid and we can iterate and update them all in one shot # without having to worry about rolling back etc as we have done # the validation up front in the 2 loops above. for key, value in valid_quotas.items(): try: db.quota_update(context, project_id, key, value) except exception.ProjectQuotaNotFound: db.quota_create(context, project_id, key, value) except exception.AdminRequired: raise webob.exc.HTTPForbidden() return {'quota_set': self._get_quotas(context, id)}
def create(self, req, body): """Creates a new snapshot.""" # cinderclient中传入的值: # body = {'snapshot': {'volume_id': volume_id, # 'force': force, # 'name': name, # 'description': description, # 'metadata': snapshot_metadata}} kwargs = {} context = req.environ['cinder.context'] # 检查body是否合法, body需要满足以下条件: # 1.body存在 # 2.'snapshot' in body # 3.body['snapshot']是个字典 self.assert_valid_body(body, 'snapshot') snapshot = body['snapshot'] kwargs['metadata'] = snapshot.get('metadata', None) try: volume_id = snapshot['volume_id'] except KeyError: msg = _("'volume_id' must be specified") raise exc.HTTPBadRequest(explanation=msg) try: volume = self.volume_api.get(context, volume_id) except exception.VolumeNotFound as error: raise exc.HTTPNotFound(explanation=error.msg) force = snapshot.get('force', False) msg = _LI("Create snapshot from volume %s") LOG.info(msg, volume_id, context=context) # 对name和description做如下修改和判定: # 1.如果name不为None, 去除name首尾的空白字符 # 2.检查name的长度, 要求0<len<255 # 3.如果description不为None, 检查description的长度, 要求0<len<255 self.validate_name_and_description(snapshot) # NOTE(thingee): v2 API allows name instead of display_name if 'name' in snapshot: snapshot['display_name'] = snapshot.pop('name') try: force = strutils.bool_from_string(force, strict=True) except ValueError as error: msg = _("Invalid value for 'force': '%s'") % error.message raise exception.InvalidParameterValue(err=msg) # 如果force为True, 调用volume_api.create_snapshot_force # 如果force为False, 调用volume_api.create_snapshot if force: new_snapshot = self.volume_api.create_snapshot_force( context, volume, snapshot.get('display_name'), snapshot.get('description'), **kwargs) else: new_snapshot = self.volume_api.create_snapshot( context, volume, snapshot.get('display_name'), snapshot.get('description'), **kwargs) req.cache_db_snapshot(new_snapshot) return self._view_builder.detail(req, new_snapshot)