예제 #1
0
파일: gpfs.py 프로젝트: dinghb/manila
    def manage_existing(self, share, driver_options):

        old_export = share['export_location'].split(':')
        try:
            ces_ip = old_export[0]
            old_export_location = old_export[1]
        except IndexError:
            msg = _('Incorrect export path. Expected format: '
                    'IP:/gpfs_mount_point_base/share_id.')
            LOG.exception(msg)
            raise exception.ShareBackendException(msg=msg)

        if ces_ip not in self.configuration.gpfs_nfs_server_list:
            msg = _('The CES IP %s is not present in the '
                    'configuration option "gpfs_nfs_server_list".') % ces_ip
            raise exception.ShareBackendException(msg=msg)

        fsdev = self._get_gpfs_device()
        if not self._is_share_valid(fsdev, old_export_location):
            err_msg = _('Given share path %s does not have a valid '
                        'share.') % old_export_location
            raise exception.ManageInvalidShare(reason=err_msg)

        share_name = self._get_share_name(fsdev, old_export_location)

        out = self._get_helper(share)._has_client_access(old_export_location)
        if out:
            err_msg = _('Clients have access to %s share currently. Evict any '
                        'clients before trying again.') % share_name
            raise exception.ManageInvalidShare(reason=err_msg)

        share_size, new_export_location = self._manage_existing(
            fsdev, share, share_name)
        return {"size": share_size, "export_locations": new_export_location}
예제 #2
0
파일: qnap.py 프로젝트: stackhpc/manila
    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)

        _metadata = {}
        vol_no = existing_share.find('vol_no').text
        _metadata['volID'] = vol_no
        _metadata['volName'] = share_name
        self.private_storage.update(share['id'], _metadata)

        # Test to get value from private_storage.
        volID = self.private_storage.get(share['id'], 'volID')
        LOG.debug('volID: %s', volID)
        volName = self.private_storage.get(share['id'], 'volName')
        LOG.debug('volName: %s', volName)

        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']})

        vol = self.api_executor.get_specific_volinfo(vol_no)
        vol_size_gb = int(vol.find('size').text) / units.Gi
        export_locations = self._get_location_path(
            share_name,
            share['share_proto'],
            self.configuration.qnap_share_ip)

        return {'size': vol_size_gb, 'export_locations': export_locations}
예제 #3
0
    def _validate_volume_for_manage(self, volume, vserver_client):
        """Ensure volume is a candidate for becoming a share."""

        # Check volume info, extra specs validity
        if volume['type'] != 'rw' or volume['style'] != 'flex':
            msg = _('Volume %(volume)s must be a read-write flexible volume.')
            msg_args = {'volume': volume['name']}
            raise exception.ManageInvalidShare(reason=msg % msg_args)

        if vserver_client.volume_has_luns(volume['name']):
            msg = _('Volume %(volume)s must not contain LUNs.')
            msg_args = {'volume': volume['name']}
            raise exception.ManageInvalidShare(reason=msg % msg_args)

        if vserver_client.volume_has_junctioned_volumes(volume['name']):
            msg = _('Volume %(volume)s must not have junctioned volumes.')
            msg_args = {'volume': volume['name']}
            raise exception.ManageInvalidShare(reason=msg % msg_args)
예제 #4
0
    def _get_mounted_share_size(self, mount_path, server_details):
        try:
            size = self._get_mount_stats_by_index(mount_path, server_details,
                                                  BLOCK_DEVICE_SIZE_INDEX)
        except Exception as e:
            msg = _("Cannot calculate size of share %(path)s : %(error)s") % {
                'path': mount_path,
                'error': six.text_type(e)
            }
            raise exception.ManageInvalidShare(reason=msg)

        return size
예제 #5
0
    def _verify_share_to_manage(self, name, details):
        lcfg = self.configuration

        if lcfg.zfssa_manage_policy == 'loose':
            return

        if 'custom:manila_managed' not in details:
            msg = (_("Unknown if the share: %s to be managed is "
                     "already being managed by Manila. Aborting manage "
                     "share. Please add 'manila_managed' custom schema "
                     "property to the share and set its value to False."
                     "Alternatively, set Manila config property "
                     "'zfssa_manage_policy' to 'loose' to remove this "
                     "restriction.") % name)
            LOG.error(msg)
            raise exception.ManageInvalidShare(reason=msg)

        if details['custom:manila_managed'] is True:
            msg = (_("Share %s is already being managed by Manila.") % name)
            LOG.error(msg)
            raise exception.ManageInvalidShare(reason=msg)
예제 #6
0
        def get_volume():
            if 'volume_id' in driver_options:
                try:
                    return self.volume_api.get(self.admin_context,
                                               driver_options['volume_id'])
                except exception.VolumeNotFound as e:
                    raise exception.ManageInvalidShare(reason=six.text_type(e))

            # NOTE(vponomaryov): Manila can only combine volume name by itself,
            # nowhere to get volume ID from. Return None since Cinder volume
            # names are not unique or fixed, hence, they can not be used for
            # sure.
            return None
예제 #7
0
파일: generic.py 프로젝트: yuyuyu101/manila
    def _get_mounted_share_size(self, mount_path, server_details):
        share_size_cmd = ['df', '-PBG', mount_path]
        output, __ = self._ssh_exec(server_details, share_size_cmd)
        lines = output.split('\n')

        try:
            size = int(lines[1].split()[1][:-1])
        except Exception as e:
            msg = _("Cannot calculate size of share %(path)s : %(error)s") % {
                'path': mount_path,
                'error': six.text_type(e)
            }
            raise exception.ManageInvalidShare(reason=msg)

        return size
예제 #8
0
    def manage_existing(self, share, driver_options):
        LOG.debug("Managing share in HSP: %(shr_id)s.",
                  {'shr_id': share['id']})

        ip, share_name = share['export_locations'][0]['path'].split(':')

        try:
            hsp_share = self.hsp.get_share(name=share_name.strip('/'))
        except exception.HSPItemNotFoundException:
            msg = _("The share %s trying to be managed was not found on "
                    "backend.") % share['id']
            raise exception.ManageInvalidShare(reason=msg)

        self.hsp.rename_file_system(hsp_share['properties']['file-system-id'],
                                    share['id'])

        original_name = hsp_share['properties']['file-system-name']
        private_storage_content = {
            'old_name': original_name,
            'new_name': share['id'],
        }
        self.private_storage.update(share['id'], private_storage_content)

        LOG.debug("Filesystem %(original_name)s was renamed to %(name)s.", {
            'original_name': original_name,
            'name': share['id']
        })

        file_system = self.hsp.get_file_system(share['id'])

        LOG.info(
            _LI("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 = [{
            "path": share['export_locations'][0]['path'],
            "metadata": {},
            "is_admin_only": False,
        }]

        return {
            'size': file_system['properties']['quota'] / units.Gi,
            'export_locations': export_locations
        }
예제 #9
0
    def _manage_existing(self, share_id):
        """Manages a share that exists on backend.

        :param share_id: ID of share that will be managed.
        :returns: Returns a dict with size of share managed
        and its location (your path in file-system).
        """
        self._ensure_share(share_id)

        share_size = self.hnas.get_share_quota(share_id)
        if share_size is None:
            msg = (_("The share %s trying to be managed does not have a "
                     "quota limit, please set it before manage.") % share_id)
            raise exception.ManageInvalidShare(msg)

        path = self.hnas_evs_ip + ':/shares/' + share_id

        return {'size': share_size, 'export_locations': [path]}
예제 #10
0
파일: gpfs.py 프로젝트: dinghb/manila
    def _get_share_name(self, fsdev, location):
        try:
            out, __ = self._gpfs_execute('mmlsfileset', fsdev, '-J',
                                         location, '-L', '-Y')
        except exception.ProcessExecutionError:
            msg = (_('Given share path %(share_path)s does not exist at '
                     'mount point %(mount_point)s.')
                   % {'share_path': location, 'mount_point': fsdev})
            LOG.exception(msg)
            raise exception.ManageInvalidShare(reason=msg)

        lines = out.splitlines()
        try:
            validation_token = lines[0].split(':').index('filesetName')
            share_name = lines[1].split(':')[validation_token]
        except (IndexError, ValueError):
            msg = (_('Failed to check share at %s.') % location)
            LOG.exception(msg)
            raise exception.GPFSException(msg)

        return share_name
예제 #11
0
    def _manage_existing(self, share, hnas_share_id):
        """Manages a share that exists on backend.

        :param share: share that will be managed.
        :param hnas_share_id: HNAS ID of share that will be managed.
        :returns: Returns a dict with size of the share managed and a list of
            dicts containing its export locations.
        """
        self._ensure_share(share, hnas_share_id)

        share_size = self.hnas.get_share_quota(hnas_share_id)
        if share_size is None:
            msg = (_("The share %s trying to be managed does not have a "
                     "quota limit, please set it before manage.") %
                   share['id'])
            raise exception.ManageInvalidShare(reason=msg)

        export_list = self._get_export_locations(share['share_proto'],
                                                 hnas_share_id)

        return {'size': share_size, 'export_locations': export_list}
예제 #12
0
 def manage_existing(self, share, driver_options):
     try:
         # retrieve share path from export location, maprfs:// prefix and
         # metadata (-C -Z -N) should be casted away
         share_path = share['export_location'].split(
         )[0][len(self._maprfs_base_path):]
         info = self._maprfs_util.get_volume_info_by_path(
             share_path, check_if_exists=True)
         if not info:
             msg = _("Share %s not found") % share[
                 'export_location']
             LOG.error(msg)
             raise exception.ManageInvalidShare(reason=msg)
         size = math.ceil(float(info['quota']) / units.Ki)
         used = math.ceil(float(info['totalused']) / units.Ki)
         volume_name = info['volumename']
         should_rename = self.rename_volume
         rename_option = driver_options.get('rename')
         if rename_option:
             should_rename = strutils.bool_from_string(rename_option)
         if should_rename:
             self._maprfs_util.rename_volume(volume_name, share['name'])
         else:
             self.api.update_share_metadata(context.get_admin_context(),
                                            {'id': share['share_id']},
                                            {'_name': volume_name})
         location = self._get_share_export_locations(share, path=share_path)
         if size == 0:
             size = used
             msg = _LW(
                 'Share %s has no size quota. Total used value will be'
                 ' used as share size')
             LOG.warning(msg, share['name'])
         return {'size': size, 'export_locations': location}
     except (ValueError, KeyError, exception.ProcessExecutionError):
         msg = _('Failed to manage share.')
         LOG.exception(msg)
         raise exception.MapRFSException(msg=msg)
예제 #13
0
    def manage_server(self, context, share_server, identifier, driver_options):
        """Manage the share server and return compiled back end details.

        :param context: Current context.
        :param share_server: Share server model.
        :param identifier: A driver-specific share server identifier
        :param driver_options: Dictionary of driver options to assist managing
            the share server
        :return: Identifier and dictionary with back end details to be saved
            in the database.

        Example::

            'my_new_server_identifier',{'server_name': 'my_old_server'}

        """
        nas_server = self.client.get_nas_server(identifier)
        if not nas_server:
            message = ("Could not find the backend share server by server "
                       "name: %s, please make sure  the share server is "
                       "existing in the backend." % identifier)
            raise exception.ManageInvalidShare(reason=message)
        return identifier, driver_options
예제 #14
0
파일: driver.py 프로젝트: ponychou/manila
    def _manage_existing(self, share, hnas_share_id):
        """Manages a share that exists on backend.

        :param share: share that will be managed.
        :param hnas_share_id: HNAS ID of share that will be managed.
        :returns: Returns a dict with size of share managed
            and its export location.
        """
        self._ensure_share(share, hnas_share_id)

        share_size = self.hnas.get_share_quota(hnas_share_id)
        if share_size is None:
            msg = (_("The share %s trying to be managed does not have a "
                     "quota limit, please set it before manage.") %
                   share['id'])
            raise exception.ManageInvalidShare(reason=msg)

        if share['share_proto'].lower() == 'nfs':
            path = self.hnas_evs_ip + os.path.join(':/shares', hnas_share_id)
        else:
            path = r'\\%s\%s' % (self.hnas_evs_ip, hnas_share_id)

        return {'size': share_size, 'export_locations': [path]}
예제 #15
0
    def manage_existing(self, share, driver_options, share_server=None):
        """Manages a share that exists on backend.

        :param share: Share that will be managed.
        :param driver_options: Driver-specific options provided by admin.
        :param share_server: Share server name provided by admin in DHSS=True.
        :returns: Returns a dict with share size and export location.
        """
        export_locations = share['export_locations']
        if not export_locations:
            message = ("Failed to manage existing share: %s, missing "
                       "export locations." % share['id'])
            raise exception.ManageInvalidShare(reason=message)

        try:
            share_size = int(driver_options.get("size", 0))
        except (ValueError, TypeError):
            msg = _("The driver options' size to manage the share "
                    "%(share_id)s, should be an integer, in format "
                    "driver-options size=<SIZE>. Value specified: "
                    "%(size)s.") % {
                        'share_id': share['id'],
                        'size': driver_options.get("size")
                    }
            raise exception.ManageInvalidShare(reason=msg)

        if not share_size:
            msg = _("Share %(share_id)s has no specified size. "
                    "Using default value 1, set size in driver options if you "
                    "want.") % {
                        'share_id': share['id']
                    }
            LOG.warning(msg)
            share_size = 1

        share_id = unity_utils.get_share_backend_id(share)
        backend_share = self.client.get_share(share_id, share['share_proto'])
        if not backend_share:
            message = ("Could not find the share in backend, please make sure "
                       "the export location is right.")
            raise exception.ManageInvalidShare(reason=message)

        # Check the share server when in DHSS=true mode
        if share_server:
            backend_share_server = self._get_server_name(share_server)
            if not backend_share_server:
                message = ("Could not find the backend share server: %s, "
                           "please make sure that share server with the "
                           "specified name exists in the backend.",
                           share_server)
                raise exception.BadConfigurationException(message)
        LOG.info(
            "Share %(shr_path)s is being managed with ID "
            "%(shr_id)s.", {
                'shr_path': share['export_locations'][0]['path'],
                'shr_id': share['id']
            })
        # export_locations was not changed, return original value
        return {
            "size": share_size,
            'export_locations': {
                'path': share['export_locations'][0]['path']
            }
        }
예제 #16
0
    def _manage_container(self, share, vserver_client):
        """Bring existing volume under management as a share."""

        protocol_helper = self._get_helper(share)
        protocol_helper.set_client(vserver_client)

        volume_name = protocol_helper.get_share_name_for_share(share)
        if not volume_name:
            msg = _('Volume could not be determined from export location '
                    '%(export)s.')
            msg_args = {'export': share['export_location']}
            raise exception.ManageInvalidShare(reason=msg % msg_args)

        share_name = self._get_valid_share_name(share['id'])
        aggregate_name = share_utils.extract_host(share['host'], level='pool')

        # Get existing volume info
        volume = vserver_client.get_volume_to_manage(aggregate_name,
                                                     volume_name)
        if not volume:
            msg = _('Volume %(volume)s not found on aggregate %(aggr)s.')
            msg_args = {'volume': volume_name, 'aggr': aggregate_name}
            raise exception.ManageInvalidShare(reason=msg % msg_args)

        # Ensure volume is manageable
        self._validate_volume_for_manage(volume, vserver_client)

        # Validate extra specs
        extra_specs = share_types.get_extra_specs_from_share(share)
        try:
            self._check_extra_specs_validity(share, extra_specs)
            self._check_aggregate_extra_specs_validity(aggregate_name,
                                                       extra_specs)
        except exception.ManilaException as ex:
            raise exception.ManageExistingShareTypeMismatch(
                reason=six.text_type(ex))
        provisioning_options = self._get_provisioning_options(extra_specs)

        debug_args = {
            'share': share_name,
            'aggr': aggregate_name,
            'options': provisioning_options
        }
        LOG.debug('Managing share %(share)s on aggregate %(aggr)s with '
                  'provisioning options %(options)s', debug_args)

        # Rename & remount volume on new path
        vserver_client.unmount_volume(volume_name)
        vserver_client.set_volume_name(volume_name, share_name)
        vserver_client.mount_volume(share_name)

        # Modify volume to match extra specs
        vserver_client.manage_volume(aggregate_name, share_name,
                                     **provisioning_options)

        # Save original volume info to private storage
        original_data = {
            'original_name': volume['name'],
            'original_junction_path': volume['junction-path']
        }
        self.private_storage.update(share['id'], original_data)

        # When calculating the size, round up to the next GB.
        return int(math.ceil(float(volume['size']) / units.Gi))
예제 #17
0
    def manage_existing(self, share, driver_options):
        """Manage existing share to manila.

        Generic driver accepts only one driver_option 'volume_id'.
        If an administrator provides this option, then appropriate Cinder
        volume will be managed by Manila as well.

        :param share: share data
        :param driver_options: Empty dict or dict with 'volume_id' option.
        :return: dict with share size, example: {'size': 1}
        """
        helper = self._get_helper(share)
        share_server = self.service_instance_manager.get_common_server()
        server_details = share_server['backend_details']

        old_export_location = share['export_locations'][0]['path']
        mount_path = helper.get_share_path_by_export_location(
            share_server['backend_details'], old_export_location)
        LOG.debug("Manage: mount path = %s", mount_path)

        mounted = self._is_device_mounted(mount_path, server_details)
        LOG.debug("Manage: is share mounted = %s", mounted)

        if not mounted:
            msg = _("Provided share %s is not mounted.") % share['id']
            raise exception.ManageInvalidShare(reason=msg)

        def get_volume():
            if 'volume_id' in driver_options:
                try:
                    return self.volume_api.get(self.admin_context,
                                               driver_options['volume_id'])
                except exception.VolumeNotFound as e:
                    raise exception.ManageInvalidShare(reason=six.text_type(e))

            # NOTE(vponomaryov): Manila can only combine volume name by itself,
            # nowhere to get volume ID from. Return None since Cinder volume
            # names are not unique or fixed, hence, they can not be used for
            # sure.
            return None

        share_volume = get_volume()

        if share_volume:
            instance_volumes = self.compute_api.instance_volumes_list(
                self.admin_context, server_details['instance_id'])

            attached_volumes = [vol.id for vol in instance_volumes]
            LOG.debug('Manage: attached volumes = %s',
                      six.text_type(attached_volumes))

            if share_volume['id'] not in attached_volumes:
                msg = _("Provided volume %s is not attached "
                        "to service instance.") % share_volume['id']
                raise exception.ManageInvalidShare(reason=msg)

            linked_volume_name = self._get_volume_name(share['id'])
            if share_volume['name'] != linked_volume_name:
                LOG.debug('Manage: volume_id = %s' % share_volume['id'])
                self.volume_api.update(self.admin_context, share_volume['id'],
                                       {'name': linked_volume_name})

            self.private_storage.update(share['id'],
                                        {'volume_id': share_volume['id']})

            share_size = share_volume['size']
        else:
            share_size = self._get_mounted_share_size(
                mount_path, share_server['backend_details'])

        export_locations = helper.get_exports_for_share(
            server_details, old_export_location)
        return {'size': share_size, 'export_locations': export_locations}
예제 #18
0
    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}
예제 #19
0
    def manage_existing(self, share, driver_options):
        """Manage an existing ZFSSA share.

        This feature requires an option 'zfssa_name', which specifies the
        name of the share as appeared in ZFSSA.

        The driver automatically retrieves information from the ZFSSA backend
        and returns the correct share size and export location.
        """
        if 'zfssa_name' not in driver_options:
            msg = _('Name of the share in ZFSSA share has to be '
                    'specified in option zfssa_name.')
            LOG.error(msg)
            raise exception.ShareBackendException(msg=msg)
        name = driver_options['zfssa_name']
        try:
            details = self._get_share_details(name)
        except Exception:
            LOG.error('Cannot manage share %s', name)
            raise

        lcfg = self.configuration
        input_export_loc = share['export_locations'][0]['path']
        proto = share['share_proto']

        self._verify_share_to_manage(name, details)

        # Get and verify share size:
        size_byte = details['quota']
        size_gb = int(math.ceil(size_byte / float(units.Gi)))
        if size_byte % units.Gi != 0:
            # Round up the size:
            new_size_byte = size_gb * units.Gi
            free_space = self.zfssa.get_project_stats(lcfg.zfssa_pool,
                                                      lcfg.zfssa_project)

            diff_space = int(new_size_byte - size_byte)

            if diff_space > free_space:
                msg = (_('Quota and reservation of share %(name)s need to be '
                         'rounded up to %(size)d. But there is not enough '
                         'space in the backend.') % {'name': name,
                                                     'size': size_gb})
                LOG.error(msg)
                raise exception.ManageInvalidShare(reason=msg)
            size_byte = new_size_byte

        # Get and verify share export location, also update share properties.
        arg = {
            'host': lcfg.zfssa_data_ip,
            'mountpoint': input_export_loc,
            'name': share['id'],
        }
        manage_args = self.default_args.copy()
        manage_args.update(self.share_args)
        # The ZFSSA share name has to be updated, as Manila generates a new
        # share id for each share to be managed.
        manage_args.update({'name': share['id'],
                            'quota': size_byte,
                            'reservation': size_byte})
        if proto == 'NFS':
            export_loc = ("%(host)s:%(mountpoint)s/%(name)s" % arg)
            manage_args.update({'sharenfs': 'sec=sys',
                                'sharesmb': 'off'})
        elif proto == 'CIFS':
            export_loc = ("\\\\%(host)s\\%(name)s" % arg)
            manage_args.update({'sharesmb': 'on',
                                'sharenfs': 'off'})
        else:
            msg = _('Protocol %s is not supported.') % proto
            LOG.error(msg)
            raise exception.ManageInvalidShare(reason=msg)

        self.zfssa.modify_share(lcfg.zfssa_pool, lcfg.zfssa_project,
                                name, manage_args)
        return {'size': size_gb, 'export_locations': export_loc}