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