Ejemplo n.º 1
0
    def create_share(self, share, share_server=None):
        """Create a share."""
        share_name = share['name']
        share_proto = share['share_proto']

        pool_name = share_utils.extract_host(share['host'], level='pool')

        if not pool_name:
            msg = _("Pool is not available in the share host field.")
            raise exception.InvalidHost(reason=msg)

        result = self.helper._find_all_pool_info()
        poolinfo = self.helper._find_pool_info(pool_name, result)
        if not poolinfo:
            msg = (_("Can not find pool info by pool name: %s") % pool_name)
            raise exception.InvalidHost(reason=msg)

        fs_id = None
        # We sleep here to ensure the newly created filesystem can be read.
        wait_interval = self._get_wait_interval()
        timeout = self._get_timeout()

        try:
            fs_id = self.allocate_container(share, poolinfo)
            fs = self.helper._get_fs_info_by_id(fs_id)
            end_time = time.time() + timeout

            while not (self.check_fs_status(fs['HEALTHSTATUS'],
                                            fs['RUNNINGSTATUS'])
                       or time.time() > end_time):
                time.sleep(wait_interval)
                fs = self.helper._get_fs_info_by_id(fs_id)

            if not self.check_fs_status(fs['HEALTHSTATUS'],
                                        fs['RUNNINGSTATUS']):
                raise exception.InvalidShare(
                    reason=(_('Invalid status of filesystem: %(health)s '
                              '%(running)s.')
                            % {'health': fs['HEALTHSTATUS'],
                               'running': fs['RUNNINGSTATUS']}))
        except Exception as err:
            if fs_id is not None:
                self.helper._delete_fs(fs_id)
            message = (_('Failed to create share %(name)s.'
                         'Reason: %(err)s.')
                       % {'name': share_name,
                          'err': err})
            raise exception.InvalidShare(reason=message)

        try:
            self.helper._create_share(share_name, fs_id, share_proto)
        except Exception as err:
            if fs_id is not None:
                self.helper._delete_fs(fs_id)
            raise exception.InvalidShare(
                reason=(_('Failed to create share %(name)s. Reason: %(err)s.')
                        % {'name': share_name, 'err': err}))

        location = self._get_location_path(share_name, share_proto)
        return location
Ejemplo n.º 2
0
    def create_share_from_snapshot(self, context, share, snapshot,
                                   share_server=None):
        """Create a share from a snapshot - clone a snapshot."""
        share_name = share['id']

        share_proto = share['share_proto'].upper()

        # Validate the share protocol
        if share_proto not in ('NFS', 'CIFS'):
            raise exception.InvalidShare(
                reason=(_('Invalid NAS protocol supplied: %s.')
                        % share_proto))

        # Get the pool name from share host field
        pool_name = share_utils.extract_host(share['host'], level='pool')
        if not pool_name:
            message = (_("Pool is not available in the share host %s.") %
                       share['host'])
            raise exception.InvalidHost(reason=message)

        self._share_server_validation(share_server)

        self._allocate_container_from_snapshot(
            share, snapshot, share_server, pool_name)

        if share_proto == 'NFS':
            self._create_nfs_share(share_name, share_server)
            location = ('%(nfs_if)s:/%(share_name)s'
                        % {'nfs_if': share_server['backend_details']['nfs_if'],
                           'share_name': share_name})
        elif share_proto == 'CIFS':
            location = self._create_cifs_share(share_name, share_server)

        return location
Ejemplo n.º 3
0
    def _get_pool_name_from_host(host):
        pool_name = share_utils.extract_host(host, level='pool')
        if not pool_name:
            message = (_("Pool is not available in the share host %s.") % host)
            raise exception.InvalidHost(reason=message)

        return pool_name
Ejemplo n.º 4
0
    def _allocate_container(self, share, vserver_client):
        """Create new share on aggregate."""
        share_name = self._get_valid_share_name(share['id'])

        # Get Data ONTAP aggregate name as pool name.
        pool_name = share_utils.extract_host(share['host'], level='pool')
        if pool_name is None:
            msg = _("Pool is not available in the share host field.")
            raise exception.InvalidHost(reason=msg)

        extra_specs = share_types.get_extra_specs_from_share(share)
        self._check_extra_specs_validity(share, extra_specs)
        provisioning_options = self._get_provisioning_options(extra_specs)

        LOG.debug(
            'Creating share %(share)s on pool %(pool)s with '
            'provisioning options %(options)s', {
                'share': share_name,
                'pool': pool_name,
                'options': provisioning_options
            })

        LOG.debug('Creating share %(share)s on pool %(pool)s', {
            'share': share_name,
            'pool': pool_name
        })
        vserver_client.create_volume(pool_name, share_name, share['size'],
                                     **provisioning_options)
Ejemplo n.º 5
0
    def _get_pool_location_from_share_host(self, share_instance_host):
        # Return pool name, vfs, IPs for a pool from share instance host
        pool_name = share_utils.extract_host(share_instance_host, level='pool')
        if not pool_name:
            message = (_("Pool is not available in the share host %s.") %
                       share_instance_host)
            raise exception.InvalidHost(reason=message)

        if pool_name not in self.fpgs:
            message = (_("Pool location lookup failed. "
                         "Could not find pool %s") % pool_name)
            raise exception.InvalidHost(reason=message)

        vfs = list(self.fpgs[pool_name])[0]
        ips = self.fpgs[pool_name][vfs]

        return (pool_name, vfs, ips)
Ejemplo n.º 6
0
    def extend_share(self, share, new_size, share_server=None):
        # Get the pool name from share host field
        pool_name = share_utils.extract_host(share['host'], level='pool')
        if not pool_name:
            message = (_("Pool is not available in the share host %s.") %
                       share['host'])
            raise exception.InvalidHost(reason=message)

        share_name = share['id']

        self._get_context('FileSystem').extend(share_name, pool_name,
                                               new_size * units.Ki)
Ejemplo n.º 7
0
    def _get_share_pool_data(self, pool_name):
        if not pool_name:
            msg = _("Pool is not available in the share host.")
            raise exception.InvalidHost(reason=msg)

        if pool_name in self.pool_dict.keys():
            return self.pool_dict[pool_name]
        else:
            msg = _('Pool [%(pool_name)s] not set in conf.') % {
                'pool_name': pool_name}
            LOG.error(msg)
            raise exception.InfortrendNASException(err=msg)
Ejemplo n.º 8
0
    def create_share(self, context, share, share_server=None):
        """Create a share and export it based on protocol used."""
        share_name = share['id']
        size = share['size'] * units.Ki

        share_proto = share['share_proto']

        # Validate the share protocol
        if share_proto.upper() not in ('NFS', 'CIFS'):
            raise exception.InvalidShare(
                reason=(_('Invalid NAS protocol supplied: %s.')
                        % share_proto))

        # Get the pool name from share host field
        pool_name = share_utils.extract_host(share['host'], level='pool')
        if not pool_name:
            message = (_("Pool is not available in the share host %s.") %
                       share['host'])
            raise exception.InvalidHost(reason=message)

        # Validate share server
        self._share_server_validation(share_server)

        if share_proto == 'CIFS':
            vdm_name = self._get_share_server_name(share_server)
            server_name = vdm_name

            # Check if CIFS server exists.
            status, server = self._get_context('CIFSServer').get(server_name,
                                                                 vdm_name)
            if status != constants.STATUS_OK:
                message = (_("CIFS server %s not found.") % server_name)
                LOG.error(message)
                raise exception.EMCVnxXMLAPIError(err=message)

        self._allocate_container(share_name, size, share_server, pool_name)

        if share_proto == 'NFS':
            location = self._create_nfs_share(share_name, share_server)
        elif share_proto == 'CIFS':
            location = self._create_cifs_share(share_name, share_server)

        return [
            {'path': location}
        ]
Ejemplo n.º 9
0
    def manage_existing(self, share, driver_options):
        """Manage existing share."""

        share_proto = share['share_proto']
        share_name = share['name']
        old_export_location = share['export_locations'][0]['path']
        pool_name = share_utils.extract_host(share['host'], level='pool')
        share_url_type = self.helper._get_share_url_type(share_proto)

        old_share_name = self.helper._get_share_name_by_export_location(
            old_export_location, share_proto)

        share = self.helper._get_share_by_name(old_share_name,
                                               share_url_type)
        if not share:
            err_msg = (_("Can not get share ID by share %s.")
                       % old_export_location)
            LOG.error(err_msg)
            raise exception.InvalidShare(reason=err_msg)

        fs_id = share['FSID']
        fs = self.helper._get_fs_info_by_id(fs_id)
        if not self.check_fs_status(fs['HEALTHSTATUS'],
                                    fs['RUNNINGSTATUS']):
            raise exception.InvalidShare(
                reason=(_('Invalid status of filesystem: %(health)s '
                          '%(running)s.')
                        % {'health': fs['HEALTHSTATUS'],
                           'running': fs['RUNNINGSTATUS']}))

        if pool_name and pool_name != fs['POOLNAME']:
            raise exception.InvalidHost(
                reason=(_('The current pool(%(fs_pool)s) of filesystem '
                          'does not match the input pool(%(host_pool)s).')
                        % {'fs_pool': fs['POOLNAME'],
                           'host_pool': pool_name}))

        self.helper._change_fs_name(fs_id, share_name)
        share_size = int(fs['CAPACITY']) / units.Mi / 2

        location = self._get_location_path(share_name, share_proto)
        return (share_size, [location])
Ejemplo n.º 10
0
    def test_resync_API_exception(self):

        replica, req = self._create_replica_get_req(
            replica_state=constants.REPLICA_STATE_OUT_OF_SYNC)
        self.mock_object(share_replicas.db, 'share_replica_get',
                         mock.Mock(return_value=replica))
        share_api_call = self.mock_object(
            share.API, 'update_share_replica',
            mock.Mock(side_effect=exception.InvalidHost(reason='')))

        body = {'resync': None}
        req.body = jsonutils.dumps(body).encode("utf-8")
        req.environ['manila.context'] = self.admin_context

        with mock.patch.object(policy, 'check_policy',
                               fakes.mock_fake_admin_check):
            resp = req.get_response(fakes.app())

        self.assertEqual(400, resp.status_int)
        share_api_call.assert_called_once_with(self.admin_context, replica)
Ejemplo n.º 11
0
    def migrate_share(self, context, share, host, force_host_copy):
        """Migrates share to a new host."""

        policy.check_policy(context, 'share', 'migrate')

        share_instance = share.instance

        # We only handle "available" share for now
        if share_instance['status'] != constants.STATUS_AVAILABLE:
            msg = _('Share instance %(instance_id)s status must be available, '
                    'but current status is: %(instance_status)s.') % {
                        'instance_id': share_instance['id'],
                        'instance_status': share_instance['status']
                    }
            LOG.error(msg)
            raise exception.InvalidShare(reason=msg)

        # Make sure share is not part of a migration
        if share['task_state'] in constants.BUSY_TASK_STATES:
            msg = _("Share %s is busy as part of an active "
                    "task.") % share['id']
            LOG.error(msg)
            raise exception.InvalidShare(reason=msg)

        # Make sure the destination host is different than the current one
        if host == share_instance['host']:
            msg = _('Destination host %(dest_host)s must be different '
                    'than the current host %(src_host)s.') % {
                        'dest_host': host,
                        'src_host': share_instance['host']
                    }
            LOG.error(msg)
            raise exception.InvalidHost(reason=msg)

        # We only handle shares without snapshots for now
        snaps = self.db.share_snapshot_get_all_for_share(context, share['id'])
        if snaps:
            msg = _("Share %s must not have snapshots.") % share['id']
            LOG.error(msg)
            raise exception.InvalidShare(reason=msg)

        # Make sure the host is in the list of available hosts
        utils.validate_service_host(context, share_utils.extract_host(host))

        # NOTE(ganso): there is the possibility of an error between here and
        # manager code, which will cause the share to be stuck in
        # MIGRATION_STARTING status. According to Liberty Midcycle discussion,
        # this kind of scenario should not be cleaned up, the administrator
        # should be issued to clear this status before a new migration request
        # is made
        self.update(
            context, share,
            {'task_state': constants.STATUS_TASK_STATE_MIGRATION_STARTING})

        share_type = {}
        share_type_id = share['share_type_id']
        if share_type_id:
            share_type = share_types.get_share_type(context, share_type_id)
        request_spec = {
            'share_properties': share,
            'share_instance_properties': share_instance.to_dict(),
            'share_type': share_type,
            'share_id': share['id']
        }

        try:
            self.scheduler_rpcapi.migrate_share_to_host(
                context, share['id'], host, force_host_copy, request_spec)
        except Exception:
            self.update(
                context, share,
                {'task_state': constants.STATUS_TASK_STATE_MIGRATION_ERROR})
            raise
Ejemplo n.º 12
0
    def check_retype_change_opts(self, opts, poolinfo, fs):
        change_opts = {
            "partitionid": None,
            "cacheid": None,
            "dedupe&compression": None,
        }

        # SmartPartition
        old_partition_id = fs['SMARTPARTITIONID']
        old_partition_name = None
        new_partition_id = None
        new_partition_name = None
        if strutils.bool_from_string(opts['huawei_smartpartition']):
            if not opts['partitionname']:
                raise exception.InvalidInput(
                    reason=_('Partition name is None, please set '
                             'huawei_smartpartition:partitionname in key.'))
            new_partition_name = opts['partitionname']
            new_partition_id = self.helper._get_partition_id_by_name(
                new_partition_name)
            if new_partition_id is None:
                raise exception.InvalidInput(
                    reason=(_("Can't find partition name on the array, "
                              "partition name is: %(name)s.")
                            % {"name": new_partition_name}))

        if old_partition_id != new_partition_id:
            if old_partition_id:
                partition_info = self.helper.get_partition_info_by_id(
                    old_partition_id)
                old_partition_name = partition_info['NAME']
            change_opts["partitionid"] = ([old_partition_id,
                                           old_partition_name],
                                          [new_partition_id,
                                           new_partition_name])

        # SmartCache
        old_cache_id = fs['SMARTCACHEID']
        old_cache_name = None
        new_cache_id = None
        new_cache_name = None
        if strutils.bool_from_string(opts['huawei_smartcache']):
            if not opts['cachename']:
                raise exception.InvalidInput(
                    reason=_('Cache name is None, please set '
                             'huawei_smartcache:cachename in key.'))
            new_cache_name = opts['cachename']
            new_cache_id = self.helper._get_cache_id_by_name(
                new_cache_name)
            if new_cache_id is None:
                raise exception.InvalidInput(
                    reason=(_("Can't find cache name on the array, "
                              "cache name is: %(name)s.")
                            % {"name": new_cache_name}))

        if old_cache_id != new_cache_id:
            if old_cache_id:
                cache_info = self.helper.get_cache_info_by_id(
                    old_cache_id)
                old_cache_name = cache_info['NAME']
            change_opts["cacheid"] = ([old_cache_id, old_cache_name],
                                      [new_cache_id, new_cache_name])

        # SmartDedupe&SmartCompression
        smartx_opts = constants.OPTS_CAPABILITIES
        if opts is not None:
            smart = smartx.SmartX()
            smartx_opts = smart.get_smartx_extra_specs_opts(opts)

        old_compression = fs['COMPRESSION']
        new_compression = smartx_opts['compression']
        old_dedupe = fs['DEDUP']
        new_dedupe = smartx_opts['dedupe']

        if fs['ALLOCTYPE'] == constants.ALLOC_TYPE_THIN_FLAG:
            fs['ALLOCTYPE'] = constants.ALLOC_TYPE_THIN
        else:
            fs['ALLOCTYPE'] = constants.ALLOC_TYPE_THICK

        if strutils.bool_from_string(opts['thin_provisioning']):
            opts['thin_provisioning'] = constants.ALLOC_TYPE_THIN
        else:
            opts['thin_provisioning'] = constants.ALLOC_TYPE_THICK

        if (fs['ALLOCTYPE'] != poolinfo['type']
                or fs['ALLOCTYPE'] != opts['thin_provisioning']):
            msg = (_("Manage existing share fs type and pool type "
                     "or fs type and new_share_type mismatch. "
                     "fs type is: %(fs_type)s, pool type is: "
                     "%(pool_type)s, new_share_type is: "
                     "%(new_share_type)s")
                   % {"fs_type": fs['ALLOCTYPE'],
                      "pool_type": poolinfo['type'],
                      "new_share_type": opts['thin_provisioning']})
            raise exception.InvalidHost(reason=msg)
        else:
            if fs['ALLOCTYPE'] == constants.ALLOC_TYPE_THICK:
                if new_compression or new_dedupe:
                    raise exception.InvalidInput(
                        reason=_("Dedupe or compression cannot be set for "
                                 "thick filesystem."))
            else:
                if (old_dedupe != new_dedupe
                        or old_compression != new_compression):
                    change_opts["dedupe&compression"] = ([old_dedupe,
                                                          old_compression],
                                                         [new_dedupe,
                                                          new_compression])
        return change_opts
Ejemplo n.º 13
0
    def manage_existing(self, share, driver_options):
        """Manage existing share."""

        share_proto = share['share_proto']
        share_name = share['name']
        old_export_location = share['export_locations'][0]['path']
        pool_name = share_utils.extract_host(share['host'], level='pool')
        share_url_type = self.helper._get_share_url_type(share_proto)
        old_share_name = self.helper._get_share_name_by_export_location(
            old_export_location, share_proto)

        share_storage = self.helper._get_share_by_name(old_share_name,
                                                       share_url_type)
        if not share_storage:
            err_msg = (_("Can not get share ID by share %s.")
                       % old_export_location)
            LOG.error(err_msg)
            raise exception.InvalidShare(reason=err_msg)

        fs_id = share_storage['FSID']
        fs = self.helper._get_fs_info_by_id(fs_id)
        if not self.check_fs_status(fs['HEALTHSTATUS'],
                                    fs['RUNNINGSTATUS']):
            raise exception.InvalidShare(
                reason=(_('Invalid status of filesystem: %(health)s '
                          '%(running)s.')
                        % {'health': fs['HEALTHSTATUS'],
                           'running': fs['RUNNINGSTATUS']}))

        if pool_name and pool_name != fs['POOLNAME']:
            raise exception.InvalidHost(
                reason=(_('The current pool(%(fs_pool)s) of filesystem '
                          'does not match the input pool(%(host_pool)s).')
                        % {'fs_pool': fs['POOLNAME'],
                           'host_pool': pool_name}))

        result = self.helper._find_all_pool_info()
        poolinfo = self.helper._find_pool_info(pool_name, result)

        opts = huawei_utils.get_share_extra_specs_params(
            share['share_type_id'])
        specs = share_types.get_share_type_extra_specs(share['share_type_id'])
        if ('capabilities:thin_provisioning' not in specs.keys()
                and 'thin_provisioning' not in specs.keys()):
            if fs['ALLOCTYPE'] == constants.ALLOC_TYPE_THIN_FLAG:
                opts['thin_provisioning'] = constants.THIN_PROVISIONING
            else:
                opts['thin_provisioning'] = constants.THICK_PROVISIONING

        change_opts = self.check_retype_change_opts(opts, poolinfo, fs)
        LOG.info(_LI('Retyping share (%(share)s), changed options are : '
                     '(%(change_opts)s).'),
                 {'share': old_share_name, 'change_opts': change_opts})
        try:
            self.retype_share(change_opts, fs_id)
        except Exception as err:
            message = (_("Retype share error. Share: %(share)s. "
                         "Reason: %(reason)s.")
                       % {'share': old_share_name,
                          'reason': err})
            raise exception.InvalidShare(reason=message)

        share_size = int(fs['CAPACITY']) / units.Mi / 2
        self.helper._change_fs_name(fs_id, share_name)
        location = self._get_location_path(share_name, share_proto)
        return (share_size, [location])