コード例 #1
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)

        _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}
コード例 #2
0
 def _check_proto(cls, share):
     proto = share['share_proto'].upper()
     if proto not in cls.supported_protocols:
         msg = _("Share protocol %s is not supported.") % proto
         raise exception.ShareBackendException(msg=msg)
コード例 #3
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}
コード例 #4
0
    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)
コード例 #5
0
ファイル: driver.py プロジェクト: ponychou/manila
    def manage_existing(self, share, driver_options):
        """Manages a share that exists on backend.

        :param share: Share that will be managed.
        :param driver_options: Empty dict or dict with 'volume_id' option.
        :returns: Returns a dict with size of share managed
            and its export location.
        """
        hnas_share_id = self._get_hnas_share_id(share['id'])

        # Make sure returned value is the same as provided,
        # confirming it does not exist.
        if hnas_share_id != share['id']:
            msg = _("Share ID %s already exists, cannot manage.") % share['id']
            raise exception.HNASBackendException(msg=msg)

        self._check_protocol(share['id'], share['share_proto'])

        if share['share_proto'].lower() == 'nfs':
            # 10.0.0.1:/shares/example
            LOG.info(
                _LI("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(
                ':/shares/')

            if len(old_path_info) == 2:
                evs_ip = old_path_info[0]
                hnas_share_id = old_path_info[1]
            else:
                msg = _("Incorrect path. It should have the following format: "
                        "IP:/shares/share_id.")
                raise exception.ShareBackendException(msg=msg)
        else:  # then its CIFS
            # \\10.0.0.1\example
            old_path = share['export_locations'][0]['path'].split('\\')

            if len(old_path) == 4:
                evs_ip = old_path[2]
                hnas_share_id = old_path[3]
            else:
                msg = _("Incorrect path. It should have the following format: "
                        "\\\\IP\\share_id.")
                raise exception.ShareBackendException(msg=msg)

        if evs_ip != self.hnas_evs_ip:
            msg = _("The EVS IP %(evs)s is not "
                    "configured.") % {
                        'evs': evs_ip
                    }
            raise exception.ShareBackendException(msg=msg)

        if self.backend_name not in share['host']:
            msg = _("The backend passed in the host parameter (%(shr)s) is "
                    "not configured.") % {
                        'shr': share['host']
                    }
            raise exception.ShareBackendException(msg=msg)

        output = self._manage_existing(share, hnas_share_id)
        self.private_storage.update(share['id'], {'hnas_id': hnas_share_id})

        LOG.debug(
            "HNAS ID %(hnas_id)s has been saved to private storage for "
            "Share ID %(share_id)s", {
                'hnas_id': hnas_share_id,
                'share_id': 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']
                })

        return output
コード例 #6
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}
コード例 #7
0
 def check_for_setup_error(self):
     """Check the status of setup."""
     if self.api_executor is None:
         msg = _("Failed to instantiate API client to communicate with "
                 "QNAP storage systems.")
         raise exception.ShareBackendException(msg=msg)
コード例 #8
0
    def get_fpg_status(self, fpg):
        """Get capacity and capabilities for FPG."""

        try:
            result = self._client.getfpg(fpg)
        except Exception as e:
            msg = (_('Failed to get capacity for fpg %(fpg)s: %(e)s') % {
                'fpg': fpg,
                'e': six.text_type(e)
            })
            LOG.error(msg)
            raise exception.ShareBackendException(msg=msg)

        if result['total'] != 1:
            msg = (_('Failed to get capacity for fpg %s.') % fpg)
            LOG.error(msg)
            raise exception.ShareBackendException(msg=msg)

        member = result['members'][0]
        total_capacity_gb = float(member['capacityKiB']) / units.Mi
        free_capacity_gb = float(member['availCapacityKiB']) / units.Mi

        volumes = member['vvs']
        if isinstance(volumes, list):
            volume = volumes[0]  # Use first name from list
        else:
            volume = volumes  # There is just a name

        self._wsapi_login()
        try:
            volume_info = self._client.getVolume(volume)
            volume_set = self._client.getVolumeSet(fpg)
        finally:
            self._wsapi_logout()

        provisioning_type = volume_info['provisioningType']
        if provisioning_type not in (THIN, FULL, DEDUPE):
            msg = (_('Unexpected provisioning type for FPG %(fpg)s: '
                     '%(ptype)s.') % {
                         'fpg': fpg,
                         'ptype': provisioning_type
                     })
            LOG.error(msg)
            raise exception.ShareBackendException(msg=msg)

        dedupe = provisioning_type == DEDUPE
        thin_provisioning = provisioning_type in (THIN, DEDUPE)

        flash_cache_policy = volume_set.get('flashCachePolicy', DISABLED)
        hpe3par_flash_cache = flash_cache_policy == ENABLED

        status = {
            'total_capacity_gb': total_capacity_gb,
            'free_capacity_gb': free_capacity_gb,
            'thin_provisioning': thin_provisioning,
            'dedupe': dedupe,
            'hpe3par_flash_cache': hpe3par_flash_cache,
            'hp3par_flash_cache': hpe3par_flash_cache,
        }

        if thin_provisioning:
            status['provisioned_capacity_gb'] = self.get_provisioned_gb(fpg)

        return status
コード例 #9
0
    def _create_share(self, project_id, share_id, protocol, extra_specs, fpg,
                      vfs, fstore, sharedir, readonly, size, comment):
        share_name = self.ensure_prefix(share_id, readonly=readonly)

        if not (sharedir or self.hpe3par_fstore_per_share):
            sharedir = share_name

        if fstore:
            use_existing_fstore = True
        else:
            use_existing_fstore = False
            if self.hpe3par_fstore_per_share:
                # Do not use -ro in the fstore name.
                fstore = self.ensure_prefix(share_id, readonly=False)
            else:
                fstore = self.ensure_prefix(project_id, protocol)

        createfshare_kwargs = self._build_createfshare_kwargs(
            protocol, fpg, fstore, readonly, sharedir, extra_specs, comment)

        if not use_existing_fstore:

            try:
                result = self._client.createfstore(vfs,
                                                   fstore,
                                                   fpg=fpg,
                                                   comment=comment)
                LOG.debug("createfstore result=%s", result)
            except Exception as e:
                msg = (_('Failed to create fstore %(fstore)s: %(e)s') % {
                    'fstore': fstore,
                    'e': six.text_type(e)
                })
                LOG.exception(msg)
                raise exception.ShareBackendException(msg)

            if size:
                self._update_capacity_quotas(fstore, size, 0, fpg, vfs)

        try:

            if readonly and protocol == 'nfs':
                # For NFS, RO is a 2nd 3PAR share pointing to same sharedir
                share_name = self.ensure_prefix(share_id, readonly=readonly)

            result = self._client.createfshare(protocol, vfs, share_name,
                                               **createfshare_kwargs)

            LOG.debug("createfshare result=%s", result)

        except Exception as e:
            msg = (_('Failed to create share %(share_name)s: %(e)s') % {
                'share_name': share_name,
                'e': six.text_type(e)
            })
            LOG.exception(msg)
            raise exception.ShareBackendException(msg)

        try:
            result = self._client.getfshare(protocol,
                                            share_name,
                                            fpg=fpg,
                                            vfs=vfs,
                                            fstore=fstore)
            LOG.debug("getfshare result=%s", result)

        except Exception as e:
            msg = (_('Failed to get fshare %(share_name)s after creating it: '
                     '%(e)s') % {
                         'share_name': share_name,
                         'e': six.text_type(e)
                     })
            LOG.exception(msg)
            raise exception.ShareBackendException(msg)

        if result['total'] != 1:
            msg = (_('Failed to get fshare %(share_name)s after creating it. '
                     'Expected to get 1 fshare.  Got %(total)s.') % {
                         'share_name': share_name,
                         'total': result['total']
                     })
            LOG.error(msg)
            raise exception.ShareBackendException(msg)
        return result['members'][0]
コード例 #10
0
def rados_command(rados_client,
                  prefix=None,
                  args=None,
                  json_obj=False,
                  target=None):
    """Safer wrapper for ceph_argparse.json_command

    Raises error exception instead of relying on caller to check return
    codes.

    Error exception can result from:
    * Timeout
    * Actual legitimate errors
    * Malformed JSON output

    return: If json_obj is True, return the decoded JSON object from ceph,
            or None if empty string returned.
            If json is False, return a decoded string (the data returned by
            ceph command)
    """

    target = target or ceph_default_target

    if args is None:
        args = {}

    argdict = args.copy()
    argdict['format'] = 'json'

    LOG.debug(
        "Invoking ceph_argparse.json_command - rados_client=%(cl)s, "
        "target=%(tg)s, prefix='%(pf)s', argdict=%(ad)s, "
        "timeout=%(to)s.", {
            "cl": rados_client,
            "tg": target,
            "pf": prefix,
            "ad": argdict,
            "to": RADOS_TIMEOUT
        })

    try:
        ret, outbuf, outs = json_command(rados_client,
                                         target=target,
                                         prefix=prefix,
                                         argdict=argdict,
                                         timeout=RADOS_TIMEOUT)
        if ret != 0:
            raise rados.Error(outs, ret)
        if not json_obj:
            result = outbuf.decode().strip()
        else:
            if outbuf:
                result = json.loads(outbuf.decode().strip())
            else:
                result = None
    except Exception as e:
        msg = _("json_command failed - prefix=%(pfx)s, argdict=%(ad)s - "
                "exception message: %(ex)s." % {
                    "pfx": prefix,
                    "ad": argdict,
                    "ex": e
                })
        raise exception.ShareBackendException(msg)

    return result
コード例 #11
0
ファイル: helper.py プロジェクト: gxwolddog/OpenStack_Driver
    def do_call(self,
                url,
                data=None,
                method=None,
                calltimeout=constants.SOCKET_TIMEOUT):
        """Send requests to server.

        Send HTTPS call, get response in JSON.
        Convert response into Python Object and return it.
        """
        if self.url:
            url = self.url + url
        if "xx/sessions" not in url:
            LOG.debug(
                'Request URL: %(url)s\n'
                'Call Method: %(method)s\n'
                'Request Data: %(data)s\n', {
                    'url': url,
                    'method': method,
                    'data': data
                })

        kwargs = {'timeout': calltimeout}
        if data:
            kwargs['data'] = data

        method = method or 'POST'
        if method in ('POST', 'PUT', 'GET', 'DELETE'):
            func = getattr(self.session, method.lower())
        else:
            msg = _("Request method %s is invalid.") % method
            LOG.error(msg)
            raise exception.ShareBackendException(msg=msg)

        try:
            res = func(url, **kwargs)
        except Exception as err:
            LOG.error(
                _LE('\nBad response from server: %(url)s.'
                    ' Error: %(err)s'), {
                        'url': url,
                        'err': err
                    })
            return {
                "error": {
                    "code": constants.ERROR_CONNECT_TO_SERVER,
                    "description": "Connect server error"
                }
            }

        try:
            res.raise_for_status()
        except requests.HTTPError as exc:
            return {
                "error": {
                    "code": exc.response.status_code,
                    "description": six.text_type(exc)
                }
            }

        result = res.json()
        LOG.debug('Response Data: %s', result)
        return result
コード例 #12
0
ファイル: generic.py プロジェクト: ddiss/manila
 def create_export(self, server, share_name, recreate=False):
     """Create share at samba server."""
     create_cmd = [
         'sudo',
         'net',
         'conf',
         'addshare',
         share_name,
         self.configuration.share_mount_path,
         'writeable=y',
         'guest_ok=y',
     ]
     try:
         self._ssh_exec(server, [
             'sudo',
             'net',
             'conf',
             'showshare',
             share_name,
         ])
     except exception.ProcessExecutionError as parent_e:
         # Share does not exist, create it
         try:
             self._ssh_exec(server, create_cmd)
         except Exception:
             # If we get here, then it will be useful
             # to log parent exception too.
             with excutils.save_and_reraise_exception():
                 LOG.error(parent_e)
     else:
         # Share exists
         if recreate:
             self._ssh_exec(server, [
                 'sudo',
                 'net',
                 'conf',
                 'delshare',
                 share_name,
             ])
             self._ssh_exec(server, create_cmd)
         else:
             msg = _('Share section %s already defined.') % share_name
             raise exception.ShareBackendException(msg=msg)
     parameters = {
         'browseable': 'yes',
         '\"create mask\"': '0755',
         '\"hosts deny\"': '0.0.0.0/0',  # deny all by default
         '\"hosts allow\"': '127.0.0.1',
         '\"read only\"': 'no',
     }
     set_of_commands = [
         ':',
     ]  # : is just placeholder
     for param, value in parameters.items():
         # These are combined in one list to run in one process
         # instead of big chain of one action calls.
         set_of_commands.extend([
             '&&', 'sudo', 'net', 'conf', 'setparm', share_name, param,
             value
         ])
     self._ssh_exec(server, set_of_commands)
     return '//%s/%s' % (server['public_address'], share_name)
コード例 #13
0
 def handle_keyerror(cmd, out):
     msg = (_('Could not find key in output of command %(cmd)s: %(out)s.')
            % {'out': out, 'cmd': cmd})
     raise exception.ShareBackendException(msg=msg)
コード例 #14
0
    def create_share(self, project_id, share_id, share_proto, extra_specs,
                     fpg, vfs,
                     fstore=None, sharedir=None, readonly=False, size=None,
                     comment=OPEN_STACK_MANILA):
        """Create the share and return its path.

        This method can create a share when called by the driver or when
        called locally from create_share_from_snapshot().  The optional
        parameters allow re-use.

        :param project_id: The tenant ID.
        :param share_id: The share-id with or without osf- prefix.
        :param share_proto: The protocol (to map to smb or nfs)
        :param extra_specs: The share type extra-specs
        :param fpg: The file provisioning group
        :param vfs:  The virtual file system
        :param fstore:  (optional) The file store.  When provided, an existing
        file store is used.  Otherwise one is created.
        :param sharedir: (optional) Share directory.
        :param readonly: (optional) Create share as read-only.
        :param size: (optional) Size limit for file store if creating one.
        :return: share path string
        """

        protocol = self.ensure_supported_protocol(share_proto)
        share_name = self.ensure_prefix(share_id)

        if not (sharedir or self.hp3par_fstore_per_share):
            sharedir = share_name

        if fstore:
            use_existing_fstore = True
        else:
            use_existing_fstore = False
            if self.hp3par_fstore_per_share:
                fstore = share_name
            else:
                fstore = self.ensure_prefix(project_id, protocol)

        createfshare_kwargs = self._build_createfshare_kwargs(protocol,
                                                              fpg,
                                                              fstore,
                                                              readonly,
                                                              sharedir,
                                                              extra_specs,
                                                              comment)

        if not use_existing_fstore:

            try:
                result = self._client.createfstore(
                    vfs, fstore, fpg=fpg,
                    comment=comment)
                LOG.debug("createfstore result=%s", result)
            except Exception as e:
                msg = (_('Failed to create fstore %(fstore)s: %(e)s') %
                       {'fstore': fstore, 'e': six.text_type(e)})
                LOG.exception(msg)
                raise exception.ShareBackendException(msg)

            if size:
                if self.hp3par_fstore_per_share:
                    hcapacity = six.text_type(size * units.Ki)
                    scapacity = hcapacity
                else:
                    hard_size_mb = size * units.Ki
                    soft_size_mb = hard_size_mb
                    result = self._client.getfsquota(
                        fpg=fpg, vfs=vfs, fstore=fstore)
                    LOG.debug("getfsquota result=%s", result)
                    quotas = result['members']
                    if len(quotas) == 1:
                        hard_size_mb += int(quotas[0].get('hardBlock', '0'))
                        soft_size_mb += int(quotas[0].get('softBlock', '0'))
                    hcapacity = six.text_type(hard_size_mb)
                    scapacity = six.text_type(soft_size_mb)

                try:
                    result = self._client.setfsquota(
                        vfs, fpg=fpg, fstore=fstore,
                        scapacity=scapacity, hcapacity=hcapacity)
                    LOG.debug("setfsquota result=%s", result)
                except Exception as e:
                    msg = (_('Failed to setfsquota on %(fstore)s: %(e)s') %
                           {'fstore': fstore, 'e': six.text_type(e)})
                    LOG.exception(msg)
                    raise exception.ShareBackendException(msg)

        try:

            result = self._client.createfshare(protocol,
                                               vfs,
                                               share_name,
                                               **createfshare_kwargs)

            LOG.debug("createfshare result=%s", result)

        except Exception as e:
            msg = (_('Failed to create share %(share_name)s: %(e)s') %
                   {'share_name': share_name, 'e': six.text_type(e)})
            LOG.exception(msg)
            raise exception.ShareBackendException(msg)

        try:
            result = self._client.getfshare(
                protocol, share_name,
                fpg=fpg, vfs=vfs, fstore=fstore)
            LOG.debug("getfshare result=%s", result)

        except Exception as e:
            msg = (_('Failed to get fshare %(share_name)s after creating it: '
                     '%(e)s') % {'share_name': share_name,
                                 'e': six.text_type(e)})
            LOG.exception(msg)
            raise exception.ShareBackendException(msg)

        if result['total'] != 1:
            msg = (_('Failed to get fshare %(share_name)s after creating it. '
                     'Expected to get 1 fshare.  Got %(total)s.') %
                   {'share_name': share_name, 'total': result['total']})
            LOG.error(msg)
            raise exception.ShareBackendException(msg)

        if protocol == 'nfs':
            return result['members'][0]['sharePath']
        else:
            return result['members'][0]['shareName']
コード例 #15
0
def _assert_result(result, format_str, *args):
    if _error_code(result) != 0:
        args += (result, )
        msg = (format_str + '\nresult: %s.') % args
        LOG.error(msg)
        raise exception.ShareBackendException(msg=msg)
コード例 #16
0
    def delete_snapshot(self, orig_project_id, orig_share_id, orig_proto,
                        snapshot_id, fpg, vfs):
        """Deletes a snapshot of a share."""

        snapshot_tag = self.ensure_prefix(snapshot_id)

        snapshot = self._find_fsnap(orig_project_id, orig_share_id, orig_proto,
                                    snapshot_tag, fpg, vfs)

        if not snapshot:
            return

        fstore = snapshot.get('fstoreName')

        for protocol in ('nfs', 'smb'):
            try:
                shares = self._client.getfshare(protocol,
                                                fpg=fpg,
                                                vfs=vfs,
                                                fstore=fstore)
            except Exception as e:
                msg = (_('Unexpected exception while getting share list. '
                         'Cannot delete snapshot without checking for '
                         'dependent shares first: %s') % six.text_type(e))
                LOG.exception(msg)
                raise exception.ShareBackendException(msg)

            for share in shares['members']:
                if protocol == 'nfs':
                    path = share['sharePath'][1:].split('/')
                    dot_snapshot_index = 3
                else:
                    if share['shareDir']:
                        path = share['shareDir'].split('/')
                    else:
                        path = None
                    dot_snapshot_index = 0

                snapshot_index = dot_snapshot_index + 1
                if path and len(path) > snapshot_index:
                    if (path[dot_snapshot_index] == '.snapshot'
                            and path[snapshot_index].endswith(snapshot_tag)):
                        msg = (_('Cannot delete snapshot because it has a '
                                 'dependent share.'))
                        raise exception.Invalid(msg)

        snapname = snapshot['snapName']
        try:
            result = self._client.removefsnap(vfs,
                                              fstore,
                                              snapname=snapname,
                                              fpg=fpg)

            LOG.debug("removefsnap result=%s", result)

        except Exception as e:
            msg = (_('Failed to delete snapshot for FPG/VFS/fstore/snapshot '
                     '%(fpg)s/%(vfs)s/%(fstore)s/%(snapname)s: %(e)s') % {
                         'fpg': fpg,
                         'vfs': vfs,
                         'fstore': fstore,
                         'snapname': snapname,
                         'e': six.text_type(e)
                     })
            LOG.exception(msg)
            raise exception.ShareBackendException(msg)

        # Try to reclaim the space
        try:
            self._client.startfsnapclean(fpg, reclaimStrategy='maxspeed')
        except Exception as e:
            # Remove already happened so only log this.
            msg = (_('Unexpected exception calling startfsnapclean for FPG '
                     '%(fpg)s: %(e)s') % {
                         'fpg': fpg,
                         'e': six.text_type(e)
                     })
            LOG.exception(msg)
コード例 #17
0
ファイル: generic.py プロジェクト: dinghb/manila
        def _mount_device_with_lock():
            mount_path = self._get_mount_path(share)
            device_path = volume['mountpoint']
            log_data = {
                'dev': device_path,
                'path': mount_path,
                'server': server_details['instance_id'],
            }
            try:
                if not self._is_device_mounted(mount_path, server_details,
                                               volume):
                    LOG.debug(
                        "Mounting '%(dev)s' to path '%(path)s' on "
                        "server '%(server)s'.", log_data)
                    mount_cmd = (
                        'sudo',
                        'mkdir',
                        '-p',
                        mount_path,
                        '&&',
                        'sudo',
                        'mount',
                        device_path,
                        mount_path,
                        '&&',
                        'sudo',
                        'chmod',
                        '777',
                        mount_path,
                        '&&',
                        'sudo',
                        'umount',
                        mount_path,
                        # NOTE(vponomaryov): 'tune2fs' is required to make
                        # filesystem of share created from snapshot have
                        # unique ID, in case of LVM volumes, by default,
                        # it will have the same UUID as source volume one.
                        # 'tune2fs' command can be executed only when device
                        # is not mounted and also, in current case, it takes
                        # effect only after it was mounted. Closes #1645751
                        '&&',
                        'sudo',
                        'tune2fs',
                        '-U',
                        'random',
                        device_path,
                        '&&',
                        'sudo',
                        'mount',
                        device_path,
                        mount_path,
                    )
                    self._ssh_exec(server_details, mount_cmd)

                    # Add mount permanently
                    self._sync_mount_temp_and_perm_files(server_details)
                else:
                    LOG.warning(
                        _LW("Mount point '%(path)s' already exists on "
                            "server '%(server)s'."), log_data)
            except exception.ProcessExecutionError as e:
                raise exception.ShareBackendException(msg=six.text_type(e))
コード例 #18
0
    def _change_access(self,
                       plus_or_minus,
                       project_id,
                       share_id,
                       share_proto,
                       access_type,
                       access_to,
                       access_level,
                       fpg,
                       vfs,
                       extra_specs=None):
        """Allow or deny access to a share.

        Plus_or_minus character indicates add to allow list (+) or remove from
        allow list (-).
        """

        readonly = access_level == 'ro'
        protocol = self.ensure_supported_protocol(share_proto)

        try:
            self._validate_access_type(protocol, access_type)
        except Exception:
            if plus_or_minus == DENY:
                # Catch invalid rules for deny. Allow them to be deleted.
                return
            else:
                raise

        fshare = self._find_fshare(project_id,
                                   share_id,
                                   protocol,
                                   fpg,
                                   vfs,
                                   readonly=readonly)
        if not fshare:
            # Change access might apply to the share with the name that
            # does not match the access_level prefix.
            other_fshare = self._find_fshare(project_id,
                                             share_id,
                                             protocol,
                                             fpg,
                                             vfs,
                                             readonly=not readonly)
            if other_fshare:

                if plus_or_minus == DENY:
                    # Try to deny rule from 'other' share for SMB or legacy.
                    fshare = other_fshare

                elif self._is_share_from_snapshot(other_fshare):
                    # Found a share-from-snapshot from before
                    # "-ro" was added to the name. Use it.
                    fshare = other_fshare

                elif protocol == 'nfs':
                    # We don't have the RO|RW share we need, but the
                    # opposite one already exists. It is OK to create
                    # the one we need for ALLOW with NFS (not from snapshot).
                    fstore = other_fshare.get('fstoreName')
                    sharedir = other_fshare.get('shareDir')
                    comment = other_fshare.get('comment')

                    fshare = self._create_share(project_id,
                                                share_id,
                                                protocol,
                                                extra_specs,
                                                fpg,
                                                vfs,
                                                fstore=fstore,
                                                sharedir=sharedir,
                                                readonly=readonly,
                                                size=None,
                                                comment=comment)
                else:
                    # SMB only has one share for RO and RW. Try to use it.
                    fshare = other_fshare

            if not fshare:
                msg = _('Failed to change (%(change)s) access '
                        'to FPG/share %(fpg)s/%(share)s '
                        'for %(type)s %(to)s %(level)s): '
                        'Share does not exist on 3PAR.')
                msg_data = {
                    'change': plus_or_minus,
                    'fpg': fpg,
                    'share': share_id,
                    'type': access_type,
                    'to': access_to,
                    'level': access_level,
                }

                if plus_or_minus == DENY:
                    LOG.warning(msg, msg_data)
                    return
                else:
                    raise exception.HPE3ParInvalid(err=msg % msg_data)

        try:
            self._validate_access_level(protocol, access_type, access_level,
                                        fshare)
        except exception.InvalidShareAccess as e:
            if plus_or_minus == DENY:
                # Allow invalid access rules to be deleted.
                msg = _('Ignoring deny invalid access rule '
                        'for FPG/share %(fpg)s/%(share)s '
                        'for %(type)s %(to)s %(level)s): %(e)s')
                msg_data = {
                    'change': plus_or_minus,
                    'fpg': fpg,
                    'share': share_id,
                    'type': access_type,
                    'to': access_to,
                    'level': access_level,
                    'e': six.text_type(e),
                }
                LOG.info(msg, msg_data)
                return
            else:
                raise

        share_name = fshare.get('shareName')
        setfshare_kwargs = {
            'fpg': fpg,
            'fstore': fshare.get('fstoreName'),
            'comment': fshare.get('comment'),
        }

        if protocol == 'nfs':
            access_change = '%s%s' % (plus_or_minus, access_to)
            setfshare_kwargs['clientip'] = access_change

        elif protocol == 'smb':

            if access_type == 'ip':
                access_change = '%s%s' % (plus_or_minus, access_to)
                setfshare_kwargs['allowip'] = access_change

            else:
                access_str = 'read' if readonly else 'fullcontrol'
                perm = '%s%s:%s' % (plus_or_minus, access_to, access_str)
                setfshare_kwargs['allowperm'] = perm

        try:
            result = self._client.setfshare(protocol, vfs, share_name,
                                            **setfshare_kwargs)

            result = self.ignore_benign_access_results(plus_or_minus,
                                                       access_type, access_to,
                                                       result)

        except Exception as e:
            result = six.text_type(e)

        LOG.debug("setfshare result=%s", result)
        if result:
            msg = (_('Failed to change (%(change)s) access to FPG/share '
                     '%(fpg)s/%(share)s for %(type)s %(to)s %(level)s: '
                     '%(error)s') % {
                         'change': plus_or_minus,
                         'fpg': fpg,
                         'share': share_id,
                         'type': access_type,
                         'to': access_to,
                         'level': access_level,
                         'error': result
                     })
            raise exception.ShareBackendException(msg=msg)
コード例 #19
0
ファイル: api.py プロジェクト: gkklovetm/manila
    def create_share(self, share, pool_name, create_share_name, share_proto):
        """Create share."""
        LOG.debug('create_share_name: %s', create_share_name)

        params = {
            'wiz_func': 'share_create',
            'action': 'add_share',
            'vol_name': create_share_name,
            'vol_size': six.text_type(share['size']) + 'GB',
            'threshold': '80',
            'dedup': 'off',
            'compression': '1',
            'thin_pro': '0',
            'cache': '0',
            'cifs_enable': '0' if share_proto == 'NFS' else '1',
            'nfs_enable': '0' if share_proto == 'CIFS' else '1',
            'afp_enable': '0',
            'ftp_enable': '0',
            'encryption': '0',
            'hidden': '0',
            'oplocks': '1',
            'sync': 'always',
            'userrw0': 'admin',
            'userrd_len': '0',
            'userrw_len': '1',
            'userno_len': '0',
            'access_r': 'setup_users',
            'path_type': 'auto',
            'recycle_bin': '1',
            'recycle_bin_administrators_only': '0',
            'pool_name': pool_name,
            'sid': self.sid,
        }
        sanitized_params = self._sanitize_params(params)

        sanitized_params = urllib.parse.urlencode(sanitized_params)
        url = ('/cgi-bin/wizReq.cgi?%s' % sanitized_params)

        res_details = self._execute_and_get_response_details(self.ip, url)
        root = ET.fromstring(res_details['data'])

        if root.find('authPassed').text == '0':
            raise exception.ShareBackendException(msg=MSG_SESSION_EXPIRED)
        if root.find('ES_RET_CODE').text < '0':
            msg = _("Fail to create share %s on NAS.") % create_share_name
            LOG.error(msg)
            raise exception.ShareBackendException(msg=msg)

        vol_list = root.find('func').find('ownContent').find('volumeList')
        vol_info_tree = vol_list.findall('volume')
        for vol in vol_info_tree:
            LOG.debug(
                'Iterating vol name: %(name)s, index: %(id)s', {
                    'name': vol.find('volumeLabel').text,
                    'id': vol.find('volumeValue').text
                })
            if (create_share_name == vol.find('volumeLabel').text):
                LOG.debug('volumeLabel:%s', vol.find('volumeLabel').text)
                return vol.find('volumeValue').text

        return res_details['data']
コード例 #20
0
    def do_setup(self):

        if self.no_client():
            msg = _('You must install hpe3parclient before using the 3PAR '
                    'driver.')
            LOG.error(msg)
            raise exception.HPE3ParInvalidClient(message=msg)

        self.client_version = hpe3parclient.version_tuple
        if self.client_version < MIN_CLIENT_VERSION:
            msg = (
                _('Invalid hpe3parclient version found (%(found)s). '
                  'Version %(minimum)s or greater required.') %
                {
                    'found': '.'.join(map(six.text_type, self.client_version)),
                    'minimum': '.'.join(map(six.text_type, MIN_CLIENT_VERSION))
                })
            LOG.error(msg)
            raise exception.HPE3ParInvalidClient(message=msg)

        try:
            self._client = file_client.HPE3ParFilePersonaClient(
                self.hpe3par_api_url)
        except Exception as e:
            msg = (_('Failed to connect to HPE 3PAR File Persona Client: %s') %
                   six.text_type(e))
            LOG.exception(msg)
            raise exception.ShareBackendException(message=msg)

        try:
            ssh_kwargs = {}
            if self.hpe3par_san_ssh_port:
                ssh_kwargs['port'] = self.hpe3par_san_ssh_port
            if self.ssh_conn_timeout:
                ssh_kwargs['conn_timeout'] = self.ssh_conn_timeout
            if self.hpe3par_san_private_key:
                ssh_kwargs['privatekey'] = self.hpe3par_san_private_key

            self._client.setSSHOptions(self.hpe3par_san_ip,
                                       self.hpe3par_san_login,
                                       self.hpe3par_san_password, **ssh_kwargs)

        except Exception as e:
            msg = (_('Failed to set SSH options for HPE 3PAR File Persona '
                     'Client: %s') % six.text_type(e))
            LOG.exception(msg)
            raise exception.ShareBackendException(message=msg)

        LOG.info(
            _LI("HPE3ParMediator %(version)s, "
                "hpe3parclient %(client_version)s"), {
                    "version": self.VERSION,
                    "client_version": hpe3parclient.get_version_string()
                })

        try:
            wsapi_version = self._client.getWsApiVersion()['build']
            LOG.info(_LI("3PAR WSAPI %s"), wsapi_version)
        except Exception as e:
            msg = (_('Failed to get 3PAR WSAPI version: %s') %
                   six.text_type(e))
            LOG.exception(msg)
            raise exception.ShareBackendException(message=msg)

        if self.hpe3par_debug:
            self._client.debug_rest(True)  # Includes SSH debug (setSSH above)
コード例 #21
0
    def _create_api_executor(self):
        """Create API executor by NAS model."""
        """LOG.debug('CONF.qnap_nas_login=%(conf)s',
                  {'conf': CONF.qnap_nas_login})
        LOG.debug('self.configuration.qnap_nas_login=%(conf)s',
                  {'conf': self.configuration.qnap_nas_login})"""
        self.api_executor = api.QnapAPIExecutor(
            username=self.configuration.qnap_nas_login,
            password=self.configuration.qnap_nas_password,
            management_url=self.configuration.qnap_management_url)

        display_model_name, internal_model_name, fw_version = (
            self.api_executor.get_basic_info(
                self.configuration.qnap_management_url))

        pattern = re.compile(r"^([A-Z]+)-?[A-Z]{0,2}(\d+)\d{2}(U|[a-z]*)")
        matches = pattern.match(display_model_name)

        if not matches:
            return None
        model_type = matches.group(1)

        ts_model_types = ("TS", "SS", "IS", "TVS", "TBS")
        tes_model_types = ("TES", "TDS")
        es_model_types = ("ES", )

        if model_type in ts_model_types:
            if (fw_version.startswith("4.2") or fw_version.startswith("4.3")):
                LOG.debug('Create TS API Executor')
                # modify the pool name to pool index
                self.configuration.qnap_poolname = (self._get_ts_model_pool_id(
                    self.configuration.qnap_poolname))

                return api.QnapAPIExecutorTS(
                    username=self.configuration.qnap_nas_login,
                    password=self.configuration.qnap_nas_password,
                    management_url=self.configuration.qnap_management_url)
        elif model_type in tes_model_types:
            if 'TS' in internal_model_name:
                if (fw_version.startswith("4.2")
                        or fw_version.startswith("4.3")):
                    LOG.debug('Create TS API Executor')
                    # modify the pool name to pool index
                    self.configuration.qnap_poolname = (
                        self._get_ts_model_pool_id(
                            self.configuration.qnap_poolname))
                    return api.QnapAPIExecutorTS(
                        username=self.configuration.qnap_nas_login,
                        password=self.configuration.qnap_nas_password,
                        management_url=self.configuration.qnap_management_url)
            elif "1.1.2" <= fw_version <= "2.1.9999":
                LOG.debug('Create ES API Executor')
                return api.QnapAPIExecutor(
                    username=self.configuration.qnap_nas_login,
                    password=self.configuration.qnap_nas_password,
                    management_url=self.configuration.qnap_management_url)
        elif model_type in es_model_types:
            if "1.1.2" <= fw_version <= "2.1.9999":
                LOG.debug('Create ES API Executor')
                return api.QnapAPIExecutor(
                    username=self.configuration.qnap_nas_login,
                    password=self.configuration.qnap_nas_password,
                    management_url=self.configuration.qnap_management_url)

        msg = _('QNAP Storage model is not supported by this driver.')
        raise exception.ShareBackendException(msg=msg)
コード例 #22
0
    def send_api(self, method, params=None, request_type='post'):
        if params is not None:
            params = json.dumps(params)
        url = ('http://%(hostname)s:%(port)s/%(rest)s/%(method)s' % {
            'hostname': self._hostname,
            'port': self._port,
            'rest': 'rest',
            'method': method
        })
        # header is not needed when the driver login the backend
        if method == 'security/token':
            # token won't be return to the token_pool
            if request_type == 'delete':
                header = {'X-Auth-Token': self._token_pool.pop(0)}
            else:
                header = None
        else:
            if len(self._token_pool) == 0:
                self.logins()
            token = self._token_pool.pop(0)
            header = {'X-Auth-Token': token}
            self._token_pool.append(token)

        if request_type == 'post':

            req = requests.post(url, data=params, headers=header)
        elif request_type == 'get':
            req = requests.get(url, data=params, headers=header)
        elif request_type == 'put':
            req = requests.put(url, data=params, headers=header)
        elif request_type == 'delete':
            req = requests.delete(url, data=params, headers=header)
        else:
            msg = 'Unsupported request_type: %s' % request_type
            raise exception.ShareBackendException(msg)

        if req.status_code != 200:
            msg = 'Error code: %(code)s , API: %(api)s , Message: %(msg)s'\
                  % {'code': req.status_code, 'api': req.url, 'msg': req.text}
            LOG.error(msg)
            raise exception.NetworkException(msg)
        try:
            response = req.json()
            code = response.get('code')
            if code == 0:
                if request_type == 'get':
                    data = response.get('data')

                else:
                    if method == 'security/token':
                        data = response.get('data')
                    else:
                        data = response.get('message')
                        data = str(data).lower()
                        if hasattr(data, 'success'):
                            return
            elif code == 301:
                msg = 'Token is out time'
                LOG.error(msg)
                raise exception.NetworkException(msg)
            else:
                message = response.get('message')  # response['message']
                msg = ('The RestAPI exception output:'
                       'Message:%s, Code:%s' % (message, code))
                LOG.error(msg)
                raise exception.ShareBackendException(msg)

        except ValueError:
            raise exception.ShareBackendException(msg)
            data = None

        req.close()

        return data
コード例 #23
0
    def create_share_from_snapshot(self,
                                   context,
                                   share,
                                   snapshot,
                                   share_server=None,
                                   parent_share=None):
        """Create a share from a snapshot."""
        LOG.debug(
            'Entering create_share_from_snapshot. The source '
            'snapshot=%(snap)s. The created share=%(share)s', {
                'snap': snapshot['id'],
                'share': share['id']
            })

        snapshot_id = (snapshot.get('provider_location') or
                       self.private_storage.get(snapshot['id'], 'snapshot_id'))
        if not snapshot_id:
            LOG.warning('Snapshot %s does not exist', snapshot['id'])
            raise exception.SnapshotResourceNotFound(name=snapshot['id'])
        LOG.debug('snapshot_id: %s', snapshot_id)

        create_share_name = self._gen_random_name("share")
        # if sharename exist, need to change another
        created_share = self.api_executor.get_share_info(
            self.configuration.qnap_poolname, vol_label=create_share_name)

        if created_share is not None:
            msg = _("Failed to create an unused share name.")
            raise exception.ShareBackendException(msg=msg)

        self.api_executor.clone_snapshot(snapshot_id, create_share_name,
                                         share['size'])

        create_volID = ""
        created_share = self.api_executor.get_share_info(
            self.configuration.qnap_poolname, vol_label=create_share_name)
        if created_share is not None:
            create_volID = created_share.find('vol_no').text
            LOG.debug('create_volID: %s', create_volID)
        else:
            msg = _("Failed to clone a snapshot in time.")
            raise exception.ShareBackendException(msg=msg)

        thin_provision = self.private_storage.get(
            snapshot['share_instance_id'], 'thin_provision')
        compression = self.private_storage.get(snapshot['share_instance_id'],
                                               'compression')
        deduplication = self.private_storage.get(snapshot['share_instance_id'],
                                                 'deduplication')
        ssd_cache = self.private_storage.get(snapshot['share_instance_id'],
                                             'ssd_cache')
        LOG.debug(
            'thin_provision: %(thin_provision)s '
            'compression: %(compression)s '
            'deduplication: %(deduplication)s '
            'ssd_cache: %(ssd_cache)s', {
                'thin_provision': thin_provision,
                'compression': compression,
                'deduplication': deduplication,
                'ssd_cache': ssd_cache
            })

        # Use private_storage to record volume ID and Name created in the NAS.
        _metadata = {
            'volID': create_volID,
            'volName': create_share_name,
            'thin_provision': thin_provision,
            'compression': compression,
            'deduplication': deduplication,
            'ssd_cache': ssd_cache
        }
        self.private_storage.update(share['id'], _metadata)

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

        return self._get_location_path(create_share_name, share['share_proto'],
                                       self.configuration.qnap_share_ip,
                                       create_volID)
コード例 #24
0
ファイル: qnap.py プロジェクト: dinghb/manila
    def create_share_from_snapshot(self,
                                   context,
                                   share,
                                   snapshot,
                                   share_server=None):
        """Create a share from a snapshot."""
        LOG.debug(
            'Entering create_share_from_snapshot. The source '
            'snapshot=%(snap)s. The created share=%(share)s', {
                'snap': snapshot['id'],
                'share': share['id']
            })

        snapshot_id = (snapshot.get('provider_location') or
                       self.private_storage.get(snapshot['id'], 'snapshot_id'))
        if not snapshot_id:
            LOG.warning(_LW('Snapshot %s does not exist'), snapshot['id'])
            raise exception.SnapshotResourceNotFound(name=snapshot['id'])
        LOG.debug('snapshot_id: %s', snapshot_id)

        create_share_name = self._gen_random_name("share")
        # if sharename exist, need to change another
        created_share = self.api_executor.get_share_info(
            self.configuration.qnap_poolname, vol_label=create_share_name)

        if created_share is not None:
            msg = _("Failed to create an unused share name.")
            raise exception.ShareBackendException(msg=msg)

        self.api_executor.clone_snapshot(snapshot_id, create_share_name)

        create_volID = ""
        created_share = self.api_executor.get_share_info(
            self.configuration.qnap_poolname, vol_label=create_share_name)
        if created_share.find('vol_no') is not None:
            create_volID = created_share.find('vol_no').text
        else:
            msg = _("Failed to clone a snapshot in time.")
            raise exception.ShareBackendException(msg=msg)

        snap_share = self.share_api.get(context,
                                        snapshot['share_instance']['share_id'])
        LOG.debug('snap_share[size]: %s', snap_share['size'])

        if (share['size'] > snap_share['size']):
            share_dict = {
                'sharename': create_share_name,
                'old_sharename': create_share_name,
                'new_size': share['size']
            }
            self.api_executor.edit_share(share_dict)

        # Use private_storage to record volume ID and Name created in the NAS.
        _metadata = {
            'volID': create_volID,
            'volName': create_share_name,
        }
        self.private_storage.update(share['id'], _metadata)

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

        return self._get_location_path(create_share_name, share['share_proto'],
                                       self.configuration.qnap_share_ip)