def container_running(): LOG.debug("Operation 'start': %s.", data["operation"]) try: state, info = self.api.operation_info(data["operation"]) except Exception as e: raise exception.ManilaException( _("Cannot get operation info: %s.") % e ) LOG.debug("Operation 'start' info: %s, %s.", state, info) if "status" in info["metadata"]: meta = info["metadata"] operation_failed = ( six.text_type(meta["status"]).lower() == "failure" and six.text_type(meta["err"]).lower() != "the container is already running" ) else: operation_failed = False if operation_failed: err_info = info["metadata"]["metadata"] raise exception.ManilaException( _("Cannot start container: %s.") % err_info ) result = self.api.container_running(name) LOG.debug("Check is container running: %s.", result) return result
def get_valid_required_extra_specs(extra_specs): """Returns required extra specs from dict. Returns None if extra specs are not valid, or if some required extras specs is missed. """ extra_specs = extra_specs or {} missed_extra_specs = set(get_required_extra_specs()) - set(extra_specs) if missed_extra_specs: specs = ",".join(missed_extra_specs) msg = _("Required extra specs '%s' not specified.") % specs raise exception.InvalidExtraSpec(reason=msg) required_extra_specs = {} for k in get_required_extra_specs(): value = extra_specs.get(k, '') if not is_valid_required_extra_spec(k, value): msg = _("Value of required extra_spec %s is not valid") % k raise exception.InvalidExtraSpec(reason=msg) required_extra_specs[k] = value return required_extra_specs
def wait_for_access_update(context, db, share_instance, migration_wait_access_rules_timeout): starttime = time.time() deadline = starttime + migration_wait_access_rules_timeout tries = 0 while True: instance = db.share_instance_get(context, share_instance['id']) if instance['access_rules_status'] == constants.STATUS_ACTIVE: break tries += 1 now = time.time() if instance['access_rules_status'] == constants.STATUS_ERROR: msg = _("Failed to update access rules" " on share instance %s") % share_instance['id'] raise exception.ShareMigrationFailed(reason=msg) elif now > deadline: msg = _("Timeout trying to update access rules" " on share instance %(share_id)s. Timeout " "was %(timeout)s seconds.") % { 'share_id': share_instance['id'], 'timeout': migration_wait_access_rules_timeout} raise exception.ShareMigrationFailed(reason=msg) else: time.sleep(tries ** 2)
def _allow_access(self, context, share, access, share_server=None): if access["access_type"] != CEPHX_ACCESS_TYPE: raise exception.InvalidShareAccess(reason=_("Only 'cephx' access type allowed.")) ceph_auth_id = access["access_to"] # We need to check here rather than the API or Manila Client to see # if the ceph_auth_id is the same as the one specified for Manila's # usage. This is due to the fact that the API and the Manila client # cannot read the contents of the Manila configuration file. If it # is the same, we need to error out. if ceph_auth_id == CONF.cephfs_auth_id: error_message = ( _("Ceph authentication ID %s must be different " "than the one the Manila service uses.") % ceph_auth_id ) raise exception.InvalidInput(message=error_message) # TODO(rraja): Log the Ceph point release version, once available, in # which the volume client can enable read-only access. if not getattr(self.volume_client, "version", None): if access["access_level"] == constants.ACCESS_LEVEL_RO: raise exception.InvalidShareAccessLevel(level=constants.ACCESS_LEVEL_RO) auth_result = self.volume_client.authorize(self._share_path(share), ceph_auth_id) else: readonly = access["access_level"] == constants.ACCESS_LEVEL_RO auth_result = self.volume_client.authorize( self._share_path(share), ceph_auth_id, readonly=readonly, tenant_id=share["project_id"] ) return auth_result["auth_key"]
def create(self, req, body): """Creates a new share group snapshot.""" context = req.environ['manila.context'] if not self.is_valid_body(body, 'share_group_snapshot'): msg = _("'share_group_snapshot' is missing from the request body.") raise exc.HTTPBadRequest(explanation=msg) share_group_snapshot = body.get('share_group_snapshot', {}) share_group_id = share_group_snapshot.get('share_group_id') if not share_group_id: msg = _("Must supply 'share_group_id' attribute.") raise exc.HTTPBadRequest(explanation=msg) if not uuidutils.is_uuid_like(share_group_id): msg = _("The 'share_group_id' attribute must be a uuid.") raise exc.HTTPBadRequest(explanation=six.text_type(msg)) kwargs = {"share_group_id": share_group_id} if 'name' in share_group_snapshot: kwargs['name'] = share_group_snapshot.get('name') if 'description' in share_group_snapshot: kwargs['description'] = share_group_snapshot.get('description') try: new_snapshot = self.share_group_api.create_share_group_snapshot( context, **kwargs) except exception.ShareGroupNotFound as e: raise exc.HTTPBadRequest(explanation=six.text_type(e)) except exception.InvalidShareGroup as e: raise exc.HTTPConflict(explanation=six.text_type(e)) return self._view_builder.detail(req, dict(new_snapshot.items()))
def _restart_gluster_vol(gluster_mgr): try: # TODO(csaba): '--mode=script' ensures that the Gluster CLI runs in # script mode. This seems unnecessary as the Gluster CLI is # expected to run in non-interactive mode when the stdin is not # a terminal, as is the case below. But on testing, found the # behaviour of Gluster-CLI to be the contrary. Need to investigate # this odd-behaviour of Gluster-CLI. gluster_mgr.gluster_call("volume", "stop", gluster_mgr.volume, "--mode=script") except exception.ProcessExecutionError as exc: msg = _("Error stopping gluster volume. " "Volume: %(volname)s, Error: %(error)s") % { "volname": gluster_mgr.volume, "error": exc.stderr, } LOG.error(msg) raise exception.GlusterfsException(msg) try: gluster_mgr.gluster_call("volume", "start", gluster_mgr.volume) except exception.ProcessExecutionError as exc: msg = _("Error starting gluster volume. " "Volume: %(volname)s, Error: %(error)s") % { "volname": gluster_mgr.volume, "error": exc.stderr, } LOG.error(msg) raise exception.GlusterfsException(msg)
def deny_access(self, context, share, access, share_server=None): """Deny access to a share that's using cert based auth. Remove the SSL CN (Common Name) that's allowed to access the server. """ if access['access_type'] != ACCESS_TYPE_CERT: raise exception.InvalidShareAccess(_("Only 'cert' access type " "allowed for access " "removal.")) exp_locn = share.get('export_location', None) gluster_addr = self.gluster_used_vols_dict.get(exp_locn) gargs, gkw = gluster_addr.make_gluster_args( 'volume', 'reset', gluster_addr.volume, AUTH_SSL_ALLOW) try: self._execute(*gargs, **gkw) except exception.ProcessExecutionError as exc: msg = (_("Error in gluster volume reset during deny access. " "Volume: %(volname)s, Option: %(option)s, " "Error: %(error)s"), {'volname': gluster_addr.volume, 'option': AUTH_SSL_ALLOW, 'error': exc.stderr}) LOG.error(msg) raise exception.GlusterfsException(msg) # TODO(deepakcs) Remove this once ssl options can be # set dynamically. self._restart_gluster_vol(gluster_addr)
def _check_boolean_extra_specs_validity(self, share, specs, keys_of_interest): # cDOT compression requires deduplication. dedup = specs.get('netapp:dedup', None) compression = specs.get('netapp:compression', None) if dedup is not None and compression is not None: if dedup.lower() == 'false' and compression.lower() == 'true': spec = {'netapp:dedup': dedup, 'netapp:compression': compression} type_id = share['share_type_id'] share_id = share['id'] args = {'type_id': type_id, 'share_id': share_id, 'spec': spec} msg = _('Invalid combination of extra_specs in share_type ' '%(type_id)s for share %(share_id)s: %(spec)s: ' 'deduplication must be enabled in order for ' 'compression to be enabled.') raise exception.Invalid(msg % args) """Check if the boolean_extra_specs have valid values.""" # Extra spec values must be (ignoring case) 'true' or 'false'. for key in keys_of_interest: value = specs.get(key) if value is not None and value.lower() not in ['true', 'false']: type_id = share['share_type_id'] share_id = share['id'] arg_map = {'value': value, 'key': key, 'type_id': type_id, 'share_id': share_id} msg = _('Invalid value "%(value)s" for extra_spec "%(key)s" ' 'in share_type %(type_id)s for share %(share_id)s.') raise exception.Invalid(msg % arg_map)
def unmanage(self, req, id): """Unmanage a share.""" context = req.environ['manila.context'] authorize(context) LOG.info(_LI("Unmanage share with id: %s"), id, context=context) try: share = self.share_api.get(context, id) if share.get('share_server_id'): msg = _("Operation 'unmanage' is not supported for shares " "that are created on top of share servers " "(created with share-networks).") raise exc.HTTPForbidden(explanation=msg) elif share['status'] in constants.TRANSITIONAL_STATUSES: msg = _("Share with transitional state can not be unmanaged. " "Share '%(s_id)s' is in '%(state)s' state.") % dict( state=share['status'], s_id=share['id']) raise exc.HTTPForbidden(explanation=msg) snapshots = self.share_api.db.share_snapshot_get_all_for_share( context, id) if snapshots: msg = _("Share '%(s_id)s' can not be unmanaged because it has " "'%(amount)s' dependent snapshot(s).") % { 's_id': id, 'amount': len(snapshots)} raise exc.HTTPForbidden(explanation=msg) self.share_api.unmanage(context, share) except exception.NotFound as e: raise exc.HTTPNotFound(explanation=six.text_type(e)) except (exception.InvalidShare, exception.PolicyNotAuthorized) as e: raise exc.HTTPForbidden(explanation=six.text_type(e)) return webob.Response(status_int=202)
def wrap(self, context, *args, **kwargs): server = kwargs.get('share_server') if not self.driver_handles_share_servers: if not server: server = self.service_instance_manager.get_common_server() kwargs['share_server'] = server else: raise exception.ManilaException( _("Share server handling is not available. " "But 'share_server' was provided. '%s'. " "Share network should not be used.") % server['id']) elif not server: raise exception.ManilaException( _("Share server handling is enabled. But 'share_server' " "is not provided. Make sure you used 'share_network'.")) if not server.get('backend_details'): raise exception.ManilaException( _("Share server '%s' does not have backend details.") % server['id']) if not self.service_instance_manager.ensure_service_instance( context, server['backend_details']): raise exception.ServiceInstanceUnavailable() return f(self, context, *args, **kwargs)
def limited(items, request, max_limit=CONF.osapi_max_limit): """Return a slice of items according to requested offset and limit. :param items: A sliceable entity :param request: ``wsgi.Request`` possibly containing 'offset' and 'limit' GET variables. 'offset' is where to start in the list, and 'limit' is the maximum number of items to return. If 'limit' is not specified, 0, or > max_limit, we default to max_limit. Negative values for either offset or limit will cause exc.HTTPBadRequest() exceptions to be raised. :kwarg max_limit: The maximum number of items to return from 'items' """ try: offset = int(request.GET.get('offset', 0)) except ValueError: msg = _('offset param must be an integer') raise webob.exc.HTTPBadRequest(explanation=msg) try: limit = int(request.GET.get('limit', max_limit)) except ValueError: msg = _('limit param must be an integer') raise webob.exc.HTTPBadRequest(explanation=msg) if limit < 0: msg = _('limit param must be positive') raise webob.exc.HTTPBadRequest(explanation=msg) if offset < 0: msg = _('offset param must be positive') raise webob.exc.HTTPBadRequest(explanation=msg) limit = min(max_limit, limit or max_limit) range_end = offset + limit return items[offset:range_end]
def _allocate_container(self, context, share, snapshot=None): """Creates cinder volume, associated to share by name.""" volume_snapshot = None if snapshot: volume_snapshot = self._get_volume_snapshot(context, snapshot['id']) volume = self.volume_api.create( context, share['size'], self.configuration.volume_name_template % share['id'], '', snapshot=volume_snapshot, volume_type=self.configuration.cinder_volume_type) self.private_storage.update( share['id'], {'volume_id': volume['id']}) msg_error = _('Failed to create volume') msg_timeout = ( _('Volume has not been created in %ss. Giving up') % self.configuration.max_time_to_create_volume ) return self._wait_for_available_volume( volume, self.configuration.max_time_to_create_volume, msg_error=msg_error, msg_timeout=msg_timeout )
def create_snapshot(self, context, snapshot, share_server=None): """Creates a snapshot.""" volume = self._get_volume(self.admin_context, snapshot['share_id']) volume_snapshot_name = (self.configuration. volume_snapshot_name_template % snapshot['id']) volume_snapshot = self.volume_api.create_snapshot_force( self.admin_context, volume['id'], volume_snapshot_name, '') t = time.time() while time.time() - t < self.configuration.max_time_to_create_volume: if volume_snapshot['status'] == const.STATUS_AVAILABLE: break if volume_snapshot['status'] == const.STATUS_ERROR: raise exception.ManilaException(_('Failed to create volume ' 'snapshot')) time.sleep(1) volume_snapshot = self.volume_api.get_snapshot( self.admin_context, volume_snapshot['id']) self.private_storage.update( snapshot['id'], {'volume_snapshot_id': volume_snapshot['id']}) else: raise exception.ManilaException( _('Volume snapshot have not been ' 'created in %ss. Giving up') % self.configuration.max_time_to_create_volume)
def _verify_denied_access(self, local_path, share, ip): try: cmd = ['exportfs'] outs = self._publish_access(*cmd) except exception.ProcessExecutionError: msg = _('Failed to verify denied access for ' 'share %s.') % share['name'] LOG.exception(msg) raise exception.GPFSException(msg) for stdout, stderr in outs: if stderr and stderr.strip(): msg = ('Log/ignore stderr during _validate_denied_access for ' 'share %(sharename)s. Return code OK. ' 'Stderr: %(stderr)s' % {'sharename': share['name'], 'stderr': stderr}) LOG.debug(msg) gpfs_ips = NFSHelper.get_host_list(stdout, local_path) if ip in gpfs_ips: msg = (_('Failed to deny access for share %(sharename)s. ' 'IP %(ip)s still has access.') % {'sharename': share['name'], 'ip': ip}) LOG.error(msg) raise exception.GPFSException(msg)
def do_attach(volume): if volume['status'] == 'in-use': attached_volumes = [vol.id for vol in self.compute_api.instance_volumes_list( self.admin_context, instance_id)] if volume['id'] in attached_volumes: return volume else: raise exception.ManilaException( _('Volume %s is already attached to another instance') % volume['id']) @retrying.retry(stop_max_attempt_number=3, wait_fixed=2000, retry_on_exception=lambda exc: True) def attach_volume(): self.compute_api.instance_volume_attach( self.admin_context, instance_id, volume['id']) attach_volume() t = time.time() while time.time() - t < self.configuration.max_time_to_attach: volume = self.volume_api.get(context, volume['id']) if volume['status'] == 'in-use': return volume elif volume['status'] != 'attaching': raise exception.ManilaException( _('Failed to attach volume %s') % volume['id']) time.sleep(1) else: raise exception.ManilaException( _('Volume have not been attached in %ss. Giving up') % self.configuration.max_time_to_attach)
def _delete_share(self, shareobj): """Remove container by removing GPFS fileset.""" sharename = shareobj['name'] fsdev = self._get_gpfs_device() # ignore error, when the fileset does not exist # it may happen, when the share creation failed, the share is in # 'error' state, and the fileset was never created # we want to ignore that error condition while deleting the fileset, # i.e. 'Fileset name share-xyz not found', with error code '2' # and mark the deletion successful ignore_exit_code = [ERR_FILE_NOT_FOUND] # unlink and delete the share's fileset try: self._gpfs_execute('mmunlinkfileset', fsdev, sharename, '-f', ignore_exit_code=ignore_exit_code) except exception.ProcessExecutionError as e: msg = (_('Failed unlink fileset for share %(sharename)s. ' 'Error: %(excmsg)s.') % {'sharename': sharename, 'excmsg': e}) LOG.error(msg) raise exception.GPFSException(msg) try: self._gpfs_execute('mmdelfileset', fsdev, sharename, '-f', ignore_exit_code=ignore_exit_code) except exception.ProcessExecutionError as e: msg = (_('Failed delete fileset for share %(sharename)s. ' 'Error: %(excmsg)s.') % {'sharename': sharename, 'excmsg': e}) LOG.error(msg) raise exception.GPFSException(msg)
def manage_existing(self, share, driver_options): old_export = share['export_location'].split(':') try: ces_ip = old_export[0] old_export_location = old_export[1] except IndexError: msg = _('Incorrect export path. Expected format: ' 'IP:/gpfs_mount_point_base/share_id.') LOG.exception(msg) raise exception.ShareBackendException(msg=msg) if ces_ip not in self.configuration.gpfs_nfs_server_list: msg = _('The CES IP %s is not present in the ' 'configuration option "gpfs_nfs_server_list".') % ces_ip raise exception.ShareBackendException(msg=msg) fsdev = self._get_gpfs_device() if not self._is_share_valid(fsdev, old_export_location): err_msg = _('Given share path %s does not have a valid ' 'share.') % old_export_location raise exception.ManageInvalidShare(reason=err_msg) share_name = self._get_share_name(fsdev, old_export_location) out = self._get_helper(share)._has_client_access(old_export_location) if out: err_msg = _('Clients have access to %s share currently. Evict any ' 'clients before trying again.') % share_name raise exception.ManageInvalidShare(reason=err_msg) share_size, new_export_location = self._manage_existing( fsdev, share, share_name) return {"size": share_size, "export_locations": new_export_location}
def main(): """Parse options and call the appropriate class/method.""" CONF.register_cli_opt(category_opt) script_name = sys.argv[0] if len(sys.argv) < 2: print(_("\nOpenStack manila version: %(version)s\n") % {"version": version.version_string()}) print(script_name + " category action [<args>]") print(_("Available categories:")) for category in CATEGORIES: print("\t%s" % category) sys.exit(2) try: log.register_options(CONF) CONF(sys.argv[1:], project="manila", version=version.version_string()) log.setup(CONF, "manila") except cfg.ConfigFilesNotFoundError: cfgfile = CONF.config_file[-1] if CONF.config_file else None if cfgfile and not os.access(cfgfile, os.R_OK): st = os.stat(cfgfile) print(_("Could not read %s. Re-running with sudo") % cfgfile) try: os.execvp("sudo", ["sudo", "-u", "#%s" % st.st_uid] + sys.argv) except Exception: print(_("sudo failed, continuing as if nothing happened")) print(_("Please re-run manila-manage as root.")) sys.exit(2) fn = CONF.category.action_fn fn_args = fetch_func_args(fn) fn(*fn_args)
def _add_security_service(self, req, id, data): """Associate share network with a given security service.""" context = req.environ['manila.context'] policy.check_policy(context, RESOURCE_NAME, 'add_security_service') share_network = db_api.share_network_get(context, id) if share_network['share_servers']: msg = _("Cannot add security services. Share network is used.") raise exc.HTTPForbidden(explanation=msg) security_service = db_api.security_service_get( context, data['security_service_id']) for attached_service in share_network['security_services']: if attached_service['type'] == security_service['type']: msg = _("Cannot add security service to share network. " "Security service with '%(ss_type)s' type already " "added to '%(sn_id)s' share network") % { 'ss_type': security_service['type'], 'sn_id': share_network['id']} raise exc.HTTPConflict(explanation=msg) try: share_network = db_api.share_network_add_security_service( context, id, data['security_service_id']) except KeyError: msg = "Malformed request body" raise exc.HTTPBadRequest(explanation=msg) except exception.NotFound as e: raise exc.HTTPNotFound(explanation=six.text_type(e)) except exception.ShareNetworkSecurityServiceAssociationError as e: raise exc.HTTPBadRequest(explanation=six.text_type(e)) return self._view_builder.build_share_network(share_network)
def _gluster_call(*args, **kwargs): logmsg = kwargs.pop('log', None) error_policy = kwargs.pop('error_policy', 'coerce') if (error_policy not in ('raw', 'coerce', 'suppress') and not isinstance(error_policy[0], int)): raise TypeError(_("undefined error_policy %s") % repr(error_policy)) try: return gluster_execf(*(('gluster',) + args), **kwargs) except exception.ProcessExecutionError as exc: if error_policy == 'raw': raise elif error_policy == 'coerce': pass elif (error_policy == 'suppress' or exc.exit_code in error_policy): return if logmsg: LOG.error(_LE("%s: GlusterFS instrumentation failed.") % logmsg) raise exception.GlusterfsException( _("GlusterFS management command '%(cmd)s' failed " "with details as follows:\n%(details)s.") % { 'cmd': ' '.join(args), 'details': exc})
def xml_response_check(self, xmlout, command, countpath=None): """Sanity check for GlusterFS XML response.""" commandstr = ' '.join(command) ret = {} for e in 'opRet', 'opErrno': ret[e] = int(volxml_get(xmlout, e)) if ret == {'opRet': -1, 'opErrno': 0}: raise exception.GlusterfsException(_( 'GlusterFS command %(command)s on volume %(volume)s failed' ) % {'volume': self.volume, 'command': command}) if list(six.itervalues(ret)) != [0, 0]: errdct = {'volume': self.volume, 'command': commandstr, 'opErrstr': volxml_get(xmlout, 'opErrstr', None)} errdct.update(ret) raise exception.InvalidShare(_( 'GlusterFS command %(command)s on volume %(volume)s got ' 'unexpected response: ' 'opRet=%(opRet)s, opErrno=%(opErrno)s, opErrstr=%(opErrstr)s' ) % errdct) if not countpath: return count = volxml_get(xmlout, countpath) if count != '1': raise exception.InvalidShare( _('GlusterFS command %(command)s on volume %(volume)s got ' 'ambiguous response: ' '%(count)s records') % { 'volume': self.volume, 'command': commandstr, 'count': count})
def shrink(self, context, share, new_size): policy.check_policy(context, 'share', 'shrink') status = six.text_type(share['status']).lower() valid_statuses = (constants.STATUS_AVAILABLE, constants.STATUS_SHRINKING_POSSIBLE_DATA_LOSS_ERROR) if status not in valid_statuses: msg_params = { 'valid_status': ", ".join(valid_statuses), 'share_id': share['id'], 'status': status, } msg = _("Share %(share_id)s status must in (%(valid_status)s) " "to shrink, but current status is: " "%(status)s.") % msg_params raise exception.InvalidShare(reason=msg) size_decrease = int(share['size']) - int(new_size) if size_decrease <= 0 or new_size <= 0: msg = (_("New size for shrink must be less " "than current size and greater than 0 (current: %(size)s," " new: %(new_size)s)") % {'new_size': new_size, 'size': share['size']}) raise exception.InvalidInput(reason=msg) self.update(context, share, {'status': constants.STATUS_SHRINKING}) self.share_rpcapi.shrink_share(context, share, new_size) LOG.info(_LI("Shrink share (id=%(id)s) request issued successfully." " New size: %(size)s") % {'id': share['id'], 'size': new_size})
def get_pool(self, share): """Get the pool name of the share.""" share_name = share['id'] status, filesystem = self._get_context('FileSystem').get(share_name) if status != constants.STATUS_OK: message = (_("File System %(name)s not found. " "Reason: %(err)s") % {'name': share_name, 'err': filesystem}) LOG.error(message) raise exception.EMCVnxXMLAPIError(err=message) pool_id = filesystem['pools_id'][0] # Get the real pools from the backend storage status, backend_pools = self._get_context('StoragePool').get_all() if status != constants.STATUS_OK: message = (_("Failed to get storage pool information. " "Reason: %s") % backend_pools) LOG.error(message) raise exception.EMCVnxXMLAPIError(err=message) for name, pool_info in backend_pools.items(): if pool_info['id'] == pool_id: return name available_pools = [item for item in backend_pools] message = (_("No matched pool name for share: %(share)s. " "Available pools: %(pools)s") % {'share': share_name, 'pools': available_pools}) raise exception.EMCVnxXMLAPIError(err=message)
def _cifs_deny_access(self, share, access, share_server): """Deny access to CIFS share.""" vdm_name = self._get_share_server_name(share_server) share_name = share['id'] if access['access_type'] != 'user': reason = _('Only user access type allowed for CIFS share') raise exception.InvalidShareAccess(reason=reason) user_name = access['access_to'] access_level = access['access_level'] if access_level == const.ACCESS_LEVEL_RW: cifs_access = constants.CIFS_ACL_FULLCONTROL else: cifs_access = constants.CIFS_ACL_READ # Check if CIFS server exists. server_name = vdm_name 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._get_context('CIFSShare').deny_share_access( vdm_name, share_name, user_name, server['domain'], access=cifs_access)
def _get_managed_storage_pools(self, pools): matched_pools = set() if pools: # Get the real pools from the backend storage status, backend_pools = self._get_context('StoragePool').get_all() if status != constants.STATUS_OK: message = (_("Failed to get storage pool information. " "Reason: %s") % backend_pools) LOG.error(message) raise exception.EMCVnxXMLAPIError(err=message) real_pools = set([item for item in backend_pools]) conf_pools = set([item.strip() for item in pools]) matched_pools, unmatched_pools = vnx_utils.do_match_any( real_pools, conf_pools) if not matched_pools: msg = (_("None of the specified storage pools to be managed " "exist. Please check your configuration " "emc_nas_pool_names in manila.conf. " "The available pools in the backend are %s.") % ",".join(real_pools)) raise exception.InvalidParameterValue(err=msg) LOG.info(_LI("Storage pools: %s will be managed."), ",".join(matched_pools)) else: LOG.debug("No storage pool is specified, so all pools " "in storage system will be managed.") return matched_pools
def extend_share(self, share, new_size, share_server): share_proto = share["share_proto"] share_name = share["name"] # The unit is in sectors. size = int(new_size) * units.Mi * 2 share_url_type = self.helper._get_share_url_type(share_proto) share = self.helper._get_share_by_name(share_name, share_url_type) if not share: err_msg = _("Can not get share ID by share %s.") % share_name LOG.error(err_msg) raise exception.InvalidShareAccess(reason=err_msg) fsid = share["FSID"] fs_info = self.helper._get_fs_info_by_id(fsid) current_size = int(fs_info["CAPACITY"]) / units.Mi / 2 if current_size > new_size: err_msg = _( "New size for extend must be equal or bigger than " "current size on array. (current: %(size)s, " "new: %(new_size)s)." ) % {"size": current_size, "new_size": new_size} LOG.error(err_msg) raise exception.InvalidInput(reason=err_msg) self.helper._change_share_size(fsid, size)
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'] # 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) 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 allow_access(self, ctx, share, access_type, access_to, access_level=None): """Allow access to share.""" if not share['host']: msg = _("Share host is None") raise exception.InvalidShare(reason=msg) if share['status'] != constants.STATUS_AVAILABLE: msg = _("Share status must be %s") % constants.STATUS_AVAILABLE raise exception.InvalidShare(reason=msg) policy.check_policy(ctx, 'share', 'allow_access') values = { 'share_id': share['id'], 'access_type': access_type, 'access_to': access_to, 'access_level': access_level, } for access in self.db.share_access_get_all_by_type_and_access( ctx, share['id'], access_type, access_to): if access['state'] != constants.STATUS_ERROR: raise exception.ShareAccessExists(access_type=access_type, access=access_to) if access_level not in constants.ACCESS_LEVELS + (None, ): msg = _("Invalid share access level: %s.") % access_level raise exception.InvalidShareAccess(reason=msg) access = self.db.share_access_create(ctx, values) self.share_rpcapi.allow_access(ctx, share, access) return access
def _validate_manage_parameters(self, context, body): if not (body and self.is_valid_body(body, 'share')): msg = _("Share entity not found in request body") raise exc.HTTPUnprocessableEntity(explanation=msg) required_parameters = ['export_path', 'service_host', 'protocol'] data = body['share'] for parameter in required_parameters: if parameter not in data: msg = _("Required parameter %s not found") % parameter raise exc.HTTPUnprocessableEntity(explanation=msg) if not data.get(parameter): msg = _("Required parameter %s is empty") % parameter raise exc.HTTPUnprocessableEntity(explanation=msg) if not share_utils.extract_host(data['service_host'], 'pool'): msg = _("service_host parameter should contain pool.") raise exc.HTTPBadRequest(explanation=msg) try: utils.validate_service_host( context, share_utils.extract_host(data['service_host'])) except exception.ServiceNotFound as e: raise exc.HTTPNotFound(explanation=six.text_type(e)) except exception.PolicyNotAuthorized as e: raise exc.HTTPForbidden(explanation=six.text_type(e)) except exception.ServiceIsDown as e: raise exc.HTTPBadRequest(explanation=six.text_type(e)) data['share_type_id'] = self._get_share_type_id( context, data.get('share_type')) return data
def delete(self, req, id): """Delete a share.""" context = req.environ['manila.context'] LOG.info(_LI("Delete share with id: %s"), id, context=context) try: share = self.share_api.get(context, id) # NOTE(ameade): If the share is in a consistency group, we require # it's id be specified as a param. if share.get('consistency_group_id'): consistency_group_id = req.params.get('consistency_group_id') if (share.get('consistency_group_id') and not consistency_group_id): msg = _("Must provide 'consistency_group_id' as a request " "parameter when deleting a share in a consistency " "group.") raise exc.HTTPBadRequest(explanation=msg) elif consistency_group_id != share.get('consistency_group_id'): msg = _("The specified 'consistency_group_id' does not " "match the consistency group id of the share.") raise exc.HTTPBadRequest(explanation=msg) self.share_api.delete(context, share) except exception.NotFound: raise exc.HTTPNotFound() except exception.InvalidShare as e: raise exc.HTTPForbidden(explanation=six.text_type(e)) return webob.Response(status_int=202)
class GPFSException(ManilaException): message = _("GPFS exception occurred.")
class ZFSonLinuxException(ManilaException): message = _("ZFSonLinux exception occurred: %(msg)s")
class MapRFSException(ManilaException): message = _("MapRFS exception occurred: %(msg)s")
class HDFSException(ManilaException): message = _("HDFS exception occurred!")
class SSHException(ManilaException): message = _("Exception in SSH protocol negotiation or logic.")
class InvalidSqliteDB(Invalid): message = _("Invalid Sqlite database.")
class GPFSGaneshaException(ManilaException): message = _("GPFS Ganesha exception occurred.")
class HPE3ParInvalid(Invalid): message = _("%(err)s")
class EMCVnxInvalidMoverID(ManilaException): message = _("Invalid mover or vdm %(id)s.")
class HPE3ParUnexpectedError(ManilaException): message = _("%(err)s")
class EMCVnxXMLAPIError(Invalid): message = _("%(err)s")
class EMCUnityError(ShareBackendException): message = _("%(err)s")
class VserverNotFound(NetAppException): message = _("Vserver %(vserver)s not found.")
class EMCVnxLockRequiredException(ManilaException): message = _("Unable to acquire lock(s).")
class SnapshotUnavailable(StorageResourceException): message = _("Snapshot %(name)s info not available.")
class VserverNotSpecified(NetAppException): message = _("Vserver not specified.")
class StorageResourceNotFound(StorageResourceException): message = _("Storage resource %(name)s not found.") code = 404
class NetAppException(ManilaException): message = _("Exception due to NetApp failure.")
class ServiceInstanceUnavailable(ServiceInstanceException): message = _("Service instance is not available.")
class SnapshotResourceNotFound(StorageResourceNotFound): message = _("Snapshot %(name)s not found.")
class BridgeDoesNotExist(ManilaException): message = _("Bridge %(bridge)s does not exist.")
class StorageResourceException(ManilaException): message = _("Storage resource exception.")
class ShareShrinkingPossibleDataLoss(ManilaException): message = _("Share %(share_id)s could not be shrunk due to " "possible data loss")
class ServiceInstanceException(ManilaException): message = _("Exception in service instance manager occurred.")
class ShareExtendingError(ManilaException): message = _("Share %(share_id)s could not be extended due to error " "in the driver: %(reason)s")
class InstanceNotFound(NotFound): message = _("Instance %(instance_id)s could not be found.")
class ShareGroupTypeCreateFailed(ManilaException): message = _("Cannot create share group type with " "name %(name)s and specs %(group_specs)s.")
class ShareShrinkingError(ManilaException): message = _("Share %(share_id)s could not be shrunk due to error " "in the driver: %(reason)s")
class ShareTypeCreateFailed(ManilaException): message = _("Cannot create share_type with " "name %(name)s and specs %(extra_specs)s.")
class ManageExistingShareTypeMismatch(ManilaException): message = _("Manage existing share failed due to share type mismatch: " "%(reason)s")