def _remap_standard_boolean_extra_specs(self, extra_specs): """Replace standard boolean extra specs with NetApp-specific ones.""" specs = copy.deepcopy(extra_specs) for (key, netapp_key) in self.STANDARD_BOOLEAN_EXTRA_SPECS_MAP.items(): if key in specs: bool_value = share_types.parse_boolean_extra_spec(key, specs[key]) specs[netapp_key] = "true" if bool_value else "false" del specs[key] return specs
def _remap_standard_boolean_extra_specs(self, extra_specs): """Replace standard boolean extra specs with NetApp-specific ones.""" specs = copy.deepcopy(extra_specs) for (key, netapp_key) in self.STANDARD_BOOLEAN_EXTRA_SPECS_MAP.items(): if key in specs: bool_value = share_types.parse_boolean_extra_spec(key, specs[key]) specs[netapp_key] = 'true' if bool_value else 'false' del specs[key] return specs
def test_parse_boolean_extra_spec(self, spec_value, expected): result = share_types.parse_boolean_extra_spec('fake_key', spec_value) self.assertEqual(expected, result)
def manage_existing(self, share, driver_options): """Manages a share that exists on backend.""" if share['share_proto'].lower() == 'nfs': # 10.0.0.1:/share/example LOG.info( "Share %(shr_path)s will be managed with ID " "%(shr_id)s.", { 'shr_path': share['export_locations'][0]['path'], 'shr_id': share['id'] }) old_path_info = share['export_locations'][0]['path'].split( ':/share/') if len(old_path_info) == 2: ip = old_path_info[0] share_name = old_path_info[1] else: msg = _("Incorrect path. It should have the following format: " "IP:/share/share_name.") raise exception.ShareBackendException(msg=msg) else: msg = _('Invalid NAS protocol: %s') % share['share_proto'] raise exception.InvalidInput(reason=msg) if ip != self.configuration.qnap_share_ip: msg = _("The NAS IP %(ip)s is not configured.") % {'ip': ip} raise exception.ShareBackendException(msg=msg) existing_share = self.api_executor.get_share_info( self.configuration.qnap_poolname, vol_label=share_name) if existing_share is None: msg = _("The share %s trying to be managed was not found on " "backend.") % share['id'] raise exception.ManageInvalidShare(reason=msg) extra_specs = share_types.get_extra_specs_from_share(share) qnap_thin_provision = share_types.parse_boolean_extra_spec( 'thin_provisioning', extra_specs.get("thin_provisioning") or extra_specs.get('capabilities:thin_provisioning') or 'true') qnap_compression = share_types.parse_boolean_extra_spec( 'compression', extra_specs.get("compression") or extra_specs.get('capabilities:compression') or 'true') qnap_deduplication = share_types.parse_boolean_extra_spec( 'dedupe', extra_specs.get("dedupe") or extra_specs.get('capabilities:dedupe') or 'false') qnap_ssd_cache = share_types.parse_boolean_extra_spec( 'qnap_ssd_cache', extra_specs.get("qnap_ssd_cache") or extra_specs.get("capabilities:qnap_ssd_cache") or 'false') LOG.debug( 'qnap_thin_provision: %(qnap_thin_provision)s ' 'qnap_compression: %(qnap_compression)s ' 'qnap_deduplication: %(qnap_deduplication)s ' 'qnap_ssd_cache: %(qnap_ssd_cache)s', { 'qnap_thin_provision': qnap_thin_provision, 'qnap_compression': qnap_compression, 'qnap_deduplication': qnap_deduplication, 'qnap_ssd_cache': qnap_ssd_cache }) if (qnap_deduplication and not qnap_thin_provision): msg = _("Dedupe cannot be enabled without thin_provisioning.") LOG.debug('Dedupe cannot be enabled without thin_provisioning.') raise exception.InvalidExtraSpec(reason=msg) vol_no = existing_share.find('vol_no').text vol = self.api_executor.get_specific_volinfo(vol_no) vol_size_gb = math.ceil(float(vol.find('size').text) / units.Gi) share_dict = { 'sharename': share_name, 'old_sharename': share_name, 'thin_provision': qnap_thin_provision, 'compression': qnap_compression, 'deduplication': qnap_deduplication, 'ssd_cache': qnap_ssd_cache, 'share_proto': share['share_proto'] } self.api_executor.edit_share(share_dict) _metadata = {} _metadata['volID'] = vol_no _metadata['volName'] = share_name _metadata['thin_provision'] = qnap_thin_provision _metadata['compression'] = qnap_compression _metadata['deduplication'] = qnap_deduplication _metadata['ssd_cache'] = qnap_ssd_cache self.private_storage.update(share['id'], _metadata) LOG.info( "Share %(shr_path)s was successfully managed with ID " "%(shr_id)s.", { 'shr_path': share['export_locations'][0]['path'], 'shr_id': share['id'] }) export_locations = self._get_location_path( share_name, share['share_proto'], self.configuration.qnap_share_ip, vol_no) return {'size': vol_size_gb, 'export_locations': export_locations}
def create_share(self, context, share, share_server=None): """Create a new share.""" LOG.debug('share: %s', share.__dict__) extra_specs = share_types.get_extra_specs_from_share(share) LOG.debug('extra_specs: %s', extra_specs) qnap_thin_provision = share_types.parse_boolean_extra_spec( 'thin_provisioning', extra_specs.get("thin_provisioning") or extra_specs.get('capabilities:thin_provisioning') or 'true') qnap_compression = share_types.parse_boolean_extra_spec( 'compression', extra_specs.get("compression") or extra_specs.get('capabilities:compression') or 'true') qnap_deduplication = share_types.parse_boolean_extra_spec( 'dedupe', extra_specs.get("dedupe") or extra_specs.get('capabilities:dedupe') or 'false') qnap_ssd_cache = share_types.parse_boolean_extra_spec( 'qnap_ssd_cache', extra_specs.get("qnap_ssd_cache") or extra_specs.get("capabilities:qnap_ssd_cache") or 'false') LOG.debug( 'qnap_thin_provision: %(qnap_thin_provision)s ' 'qnap_compression: %(qnap_compression)s ' 'qnap_deduplication: %(qnap_deduplication)s ' 'qnap_ssd_cache: %(qnap_ssd_cache)s', { 'qnap_thin_provision': qnap_thin_provision, 'qnap_compression': qnap_compression, 'qnap_deduplication': qnap_deduplication, 'qnap_ssd_cache': qnap_ssd_cache }) share_proto = share['share_proto'] # User could create two shares with the same name on horizon. # Therefore, we should not use displayname to create shares on NAS. create_share_name = self._gen_random_name("share") # If share name exists, need to change to another name. created_share = self.api_executor.get_share_info( self.configuration.qnap_poolname, vol_label=create_share_name) LOG.debug('created_share: %s', created_share) if created_share is not None: msg = (_("The share name %s is used by other share on NAS.") % create_share_name) LOG.error(msg) raise exception.ShareBackendException(msg=msg) if (qnap_deduplication and not qnap_thin_provision): msg = _("Dedupe cannot be enabled without thin_provisioning.") LOG.debug('Dedupe cannot be enabled without thin_provisioning.') raise exception.InvalidExtraSpec(reason=msg) self.api_executor.create_share(share, self.configuration.qnap_poolname, create_share_name, share_proto, qnap_thin_provision=qnap_thin_provision, qnap_compression=qnap_compression, qnap_deduplication=qnap_deduplication, qnap_ssd_cache=qnap_ssd_cache) created_share = self._get_share_info(create_share_name) volID = created_share.find('vol_no').text # Use private_storage to record volume ID and Name created in the NAS. LOG.debug('volID: %(volID)s ' 'volName: %(create_share_name)s', { 'volID': volID, 'create_share_name': create_share_name }) _metadata = { 'volID': volID, 'volName': create_share_name, 'thin_provision': qnap_thin_provision, 'compression': qnap_compression, 'deduplication': qnap_deduplication, 'ssd_cache': qnap_ssd_cache } self.private_storage.update(share['id'], _metadata) return self._get_location_path(create_share_name, share['share_proto'], self.configuration.qnap_share_ip, volID)
def manage_existing(self, share, driver_options): """Manages a share that exists on backend.""" if share['share_proto'].lower() == 'nfs': # 10.0.0.1:/share/example LOG.info("Share %(shr_path)s will be managed with ID " "%(shr_id)s.", {'shr_path': share['export_locations'][0]['path'], 'shr_id': share['id']}) old_path_info = share['export_locations'][0]['path'].split( ':/share/') if len(old_path_info) == 2: ip = old_path_info[0] share_name = old_path_info[1] else: msg = _("Incorrect path. It should have the following format: " "IP:/share/share_name.") raise exception.ShareBackendException(msg=msg) else: msg = _('Invalid NAS protocol: %s') % share['share_proto'] raise exception.InvalidInput(reason=msg) if ip != self.configuration.qnap_share_ip: msg = _("The NAS IP %(ip)s is not configured.") % {'ip': ip} raise exception.ShareBackendException(msg=msg) existing_share = self.api_executor.get_share_info( self.configuration.qnap_poolname, vol_label=share_name) if existing_share is None: msg = _("The share %s trying to be managed was not found on " "backend.") % share['id'] raise exception.ManageInvalidShare(reason=msg) extra_specs = share_types.get_extra_specs_from_share(share) qnap_thin_provision = share_types.parse_boolean_extra_spec( 'thin_provisioning', extra_specs.get("thin_provisioning") or extra_specs.get('capabilities:thin_provisioning') or 'true') qnap_compression = share_types.parse_boolean_extra_spec( 'compression', extra_specs.get("compression") or extra_specs.get('capabilities:compression') or 'true') qnap_deduplication = share_types.parse_boolean_extra_spec( 'dedupe', extra_specs.get("dedupe") or extra_specs.get('capabilities:dedupe') or 'false') qnap_ssd_cache = share_types.parse_boolean_extra_spec( 'qnap_ssd_cache', extra_specs.get("qnap_ssd_cache") or extra_specs.get("capabilities:qnap_ssd_cache") or 'false') LOG.debug('qnap_thin_provision: %(qnap_thin_provision)s ' 'qnap_compression: %(qnap_compression)s ' 'qnap_deduplication: %(qnap_deduplication)s ' 'qnap_ssd_cache: %(qnap_ssd_cache)s', {'qnap_thin_provision': qnap_thin_provision, 'qnap_compression': qnap_compression, 'qnap_deduplication': qnap_deduplication, 'qnap_ssd_cache': qnap_ssd_cache}) if (qnap_deduplication and not qnap_thin_provision): msg = _("Dedupe cannot be enabled without thin_provisioning.") LOG.debug('Dedupe cannot be enabled without thin_provisioning.') raise exception.InvalidExtraSpec(reason=msg) vol_no = existing_share.find('vol_no').text vol = self.api_executor.get_specific_volinfo(vol_no) vol_size_gb = math.ceil(float(vol.find('size').text) / units.Gi) share_dict = { 'sharename': share_name, 'old_sharename': share_name, 'thin_provision': qnap_thin_provision, 'compression': qnap_compression, 'deduplication': qnap_deduplication, 'ssd_cache': qnap_ssd_cache, 'share_proto': share['share_proto'] } self.api_executor.edit_share(share_dict) _metadata = {} _metadata['volID'] = vol_no _metadata['volName'] = share_name _metadata['thin_provision'] = qnap_thin_provision _metadata['compression'] = qnap_compression _metadata['deduplication'] = qnap_deduplication _metadata['ssd_cache'] = qnap_ssd_cache self.private_storage.update(share['id'], _metadata) LOG.info("Share %(shr_path)s was successfully managed with ID " "%(shr_id)s.", {'shr_path': share['export_locations'][0]['path'], 'shr_id': share['id']}) export_locations = self._get_location_path( share_name, share['share_proto'], self.configuration.qnap_share_ip, vol_no) return {'size': vol_size_gb, 'export_locations': export_locations}
def create_share(self, context, share, share_server=None): """Create a new share.""" LOG.debug('share: %s', share.__dict__) extra_specs = share_types.get_extra_specs_from_share(share) LOG.debug('extra_specs: %s', extra_specs) qnap_thin_provision = share_types.parse_boolean_extra_spec( 'thin_provisioning', extra_specs.get("thin_provisioning") or extra_specs.get('capabilities:thin_provisioning') or 'true') qnap_compression = share_types.parse_boolean_extra_spec( 'compression', extra_specs.get("compression") or extra_specs.get('capabilities:compression') or 'true') qnap_deduplication = share_types.parse_boolean_extra_spec( 'dedupe', extra_specs.get("dedupe") or extra_specs.get('capabilities:dedupe') or 'false') qnap_ssd_cache = share_types.parse_boolean_extra_spec( 'qnap_ssd_cache', extra_specs.get("qnap_ssd_cache") or extra_specs.get("capabilities:qnap_ssd_cache") or 'false') LOG.debug('qnap_thin_provision: %(qnap_thin_provision)s ' 'qnap_compression: %(qnap_compression)s ' 'qnap_deduplication: %(qnap_deduplication)s ' 'qnap_ssd_cache: %(qnap_ssd_cache)s', {'qnap_thin_provision': qnap_thin_provision, 'qnap_compression': qnap_compression, 'qnap_deduplication': qnap_deduplication, 'qnap_ssd_cache': qnap_ssd_cache}) share_proto = share['share_proto'] # User could create two shares with the same name on horizon. # Therefore, we should not use displayname to create shares on NAS. create_share_name = self._gen_random_name("share") # If share name exists, need to change to another name. created_share = self.api_executor.get_share_info( self.configuration.qnap_poolname, vol_label=create_share_name) LOG.debug('created_share: %s', created_share) if created_share is not None: msg = (_("The share name %s is used by other share on NAS.") % create_share_name) LOG.error(msg) raise exception.ShareBackendException(msg=msg) if (qnap_deduplication and not qnap_thin_provision): msg = _("Dedupe cannot be enabled without thin_provisioning.") LOG.debug('Dedupe cannot be enabled without thin_provisioning.') raise exception.InvalidExtraSpec(reason=msg) self.api_executor.create_share( share, self.configuration.qnap_poolname, create_share_name, share_proto, qnap_thin_provision=qnap_thin_provision, qnap_compression=qnap_compression, qnap_deduplication=qnap_deduplication, qnap_ssd_cache=qnap_ssd_cache) created_share = self._get_share_info(create_share_name) volID = created_share.find('vol_no').text # Use private_storage to record volume ID and Name created in the NAS. LOG.debug('volID: %(volID)s ' 'volName: %(create_share_name)s', {'volID': volID, 'create_share_name': create_share_name}) _metadata = {'volID': volID, 'volName': create_share_name, 'thin_provision': qnap_thin_provision, 'compression': qnap_compression, 'deduplication': qnap_deduplication, 'ssd_cache': qnap_ssd_cache} self.private_storage.update(share['id'], _metadata) return self._get_location_path(create_share_name, share['share_proto'], self.configuration.qnap_share_ip, volID)