def update(self, req, id, body): """Update specified share network.""" context = req.environ['manila.context'] policy.check_policy(context, RESOURCE_NAME, 'update') if not body or RESOURCE_NAME not in body: raise exc.HTTPUnprocessableEntity() try: share_network = db_api.share_network_get(context, id) except exception.ShareNetworkNotFound as e: msg = "%s" % e raise exc.HTTPNotFound(explanation=msg) if share_network['share_servers']: msg = _("Cannot update share network %s." " It is used by share servers") % share_network['id'] raise exc.HTTPForbidden(explanation=msg) update_values = body[RESOURCE_NAME] try: share_network = db_api.share_network_update(context, id, update_values) except db_exception.DBError: msg = "Could not save supplied data due to database error" raise exc.HTTPBadRequest(explanation=msg) return self._view_builder.build_share_network(share_network)
def update(self, req, id, body): """Update specified share network.""" context = req.environ["manila.context"] policy.check_policy(context, RESOURCE_NAME, "update") if not body or RESOURCE_NAME not in body: raise exc.HTTPUnprocessableEntity() try: share_network = db_api.share_network_get(context, id) except exception.ShareNetworkNotFound as e: msg = "%s" % e raise exc.HTTPNotFound(explanation=msg) if share_network["status"] == constants.STATUS_ACTIVE: msg = "Network %s is in use" % id raise exc.HTTPBadRequest(explanation=msg) update_values = body[RESOURCE_NAME] try: share_network = db_api.share_network_update(context, id, update_values) except exception.DBError: msg = "Could not save supplied data due to database error" raise exc.HTTPBadRequest(explanation=msg) return self._view_builder.build_share_network(share_network)
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 update(self, req, id, body): """Update specified share network.""" context = req.environ['manila.context'] policy.check_policy(context, RESOURCE_NAME, 'update') if not body or RESOURCE_NAME not in body: raise exc.HTTPUnprocessableEntity() try: share_network = db_api.share_network_get(context, id) except exception.ShareNetworkNotFound as e: raise exc.HTTPNotFound(explanation=six.text_type(e)) update_values = body[RESOURCE_NAME] self._verify_no_mutually_exclusive_data(share_network, update_values) if share_network['share_servers']: for value in update_values: if value not in ['name', 'description']: msg = _("Cannot update share network %s. It is used by " "share servers. Only 'name' and 'description' " "fields are available for update")\ % share_network['id'] raise exc.HTTPForbidden(explanation=msg) try: share_network = db_api.share_network_update(context, id, update_values) except db_exception.DBError: msg = "Could not save supplied data due to database error" raise exc.HTTPBadRequest(explanation=msg) return self._view_builder.build_share_network(share_network)
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 _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 delete(self, req, id): """Delete specified share network.""" context = req.environ['manila.context'] policy.check_policy(context, RESOURCE_NAME, 'delete') try: share_network = db_api.share_network_get(context, id) except exception.ShareNetworkNotFound as e: msg = "%s" % e raise exc.HTTPNotFound(explanation=msg) if share_network['share_servers']: msg = _("Cannot delete share network %s. " "There are share servers using it") % id raise exc.HTTPForbidden(explanation=msg) db_api.share_network_delete(context, id) try: reservations = QUOTAS.reserve( context, project_id=share_network['project_id'], share_networks=-1) except Exception: msg = _("Failed to update usages deleting share-network.") LOG.exception(msg) else: QUOTAS.commit(context, reservations, project_id=share_network['project_id']) return webob.Response(status_int=202)
def index(self, req): """Returns a list of share servers.""" context = req.environ["manila.context"] policy.check_policy(context, RESOURCE_NAME, "index") search_opts = {} search_opts.update(req.GET) share_servers = db_api.share_server_get_all(context) for s in share_servers: s.project_id = s.share_network["project_id"] if s.share_network["name"]: s.share_network_name = s.share_network["name"] else: s.share_network_name = s.share_network_id if search_opts: for k, v in six.iteritems(search_opts): share_servers = [ s for s in share_servers if ( hasattr(s, k) and s[k] == v or k == "share_network" and v in [s.share_network["name"], s.share_network["id"]] ) ] return self._view_builder.build_share_servers(share_servers)
def get_all(self, context, search_opts=None): policy.check_policy(context, 'share', 'get_all') if search_opts is None: search_opts = {} if 'share_server_id' in search_opts: # NOTE(vponomaryov): this is project_id independent policy.check_policy(context, 'share', 'list_by_share_server_id') shares = self.db.share_get_all_by_share_server( context, search_opts.pop('share_server_id')) elif (context.is_admin and 'all_tenants' in search_opts): shares = self.db.share_get_all(context) else: shares = self.db.share_get_all_by_project(context, context.project_id) # NOTE(vponomaryov): we do not need 'all_tenants' opt anymore search_opts.pop('all_tenants', None) if search_opts: LOG.debug("Searching for shares by: %s" % str(search_opts)) results = [] for s in shares: # values in search_opts can be only strings if all(s.get(k, None) == v for k, v in search_opts.items()): results.append(s) shares = results return shares
def delete(self, req, id): """Delete specified share network.""" context = req.environ['manila.context'] policy.check_policy(context, RESOURCE_NAME, 'delete') try: share_network = db_api.share_network_get(context, id) except exception.ShareNetworkNotFound as e: raise exc.HTTPNotFound(explanation=six.text_type(e)) shares = db_api.share_get_all_by_share_network(context, id) if shares: msg = _("Can not delete share network %(id)s, it has " "%(len)s share(s).") % {'id': id, 'len': len(shares)} LOG.error(msg) raise exc.HTTPConflict(explanation=msg) for share_server in share_network['share_servers']: self.share_rpcapi.delete_share_server(context, share_server) db_api.share_network_delete(context, id) try: reservations = QUOTAS.reserve( context, project_id=share_network['project_id'], share_networks=-1) except Exception: LOG.exception(_LE("Failed to update usages deleting " "share-network.")) else: QUOTAS.commit(context, reservations, project_id=share_network['project_id']) return webob.Response(status_int=202)
def delete_instance(self, context, share_instance, force=False): policy.check_policy(context, 'share', 'delete') statuses = (constants.STATUS_AVAILABLE, constants.STATUS_ERROR, constants.STATUS_INACTIVE) if not (force or share_instance['status'] in statuses): msg = _("Share instance status must be one of %(statuses)s") % { "statuses": statuses} raise exception.InvalidShareInstance(reason=msg) share_instance = self.db.share_instance_update( context, share_instance['id'], {'status': constants.STATUS_DELETING, 'terminated_at': timeutils.utcnow()} ) self.share_rpcapi.delete_share_instance(context, share_instance) # NOTE(u_glide): 'updated_at' timestamp is used to track last usage of # share server. This is required for automatic share servers cleanup # because we should track somehow period of time when share server # doesn't have shares (unused). We do this update only on share # deletion because share server with shares cannot be deleted, so no # need to do this update on share creation or any other share operation if share_instance['share_server_id']: self.db.share_server_update( context, share_instance['share_server_id'], {'updated_at': timeutils.utcnow()})
def deny_access(self, ctx, share, access): """Deny access to share.""" policy.check_policy(ctx, 'share', 'deny_access') # First check state of the target share share = self.db.share_get(ctx, share['id']) if not (share.instances and share.instance['host']): msg = _("Share doesn't have any instances") 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) # Then check state of the access rule if (access['state'] == constants.STATUS_ERROR and not self.db.share_instance_access_get_all(ctx, access['id'])): self.db.share_access_delete(ctx, access["id"]) elif access['state'] in [constants.STATUS_ACTIVE, constants.STATUS_ERROR]: for share_instance in share.instances: try: self.deny_access_to_instance(ctx, share_instance, access) except exception.NotFound: LOG.warn(_LW("Access rule %(access_id)s not found " "for instance %(instance_id)s.") % { 'access_id': access['id'], 'instance_id': share_instance['id']}) else: msg = _("Access policy should be %(active)s or in %(error)s " "state") % {"active": constants.STATUS_ACTIVE, "error": constants.STATUS_ERROR} raise exception.InvalidShareAccess(reason=msg)
def update(self, req, id, body): """Update a security service.""" context = req.environ['manila.context'] if not body or 'security_service' not in body: raise exc.HTTPUnprocessableEntity() security_service_data = body['security_service'] valid_update_keys = ( 'description', 'name' ) try: security_service = db.security_service_get(context, id) policy.check_policy(context, RESOURCE_NAME, 'update', security_service) except exception.NotFound: raise exc.HTTPNotFound() if self._share_servers_dependent_on_sn_exist(context, id): for item in security_service_data: if item not in valid_update_keys: msg = _("Cannot update security service %s. It is " "attached to share network with share server " "associated. Only 'name' and 'description' " "fields are available for update.") % id raise exc.HTTPForbidden(explanation=msg) policy.check_policy(context, RESOURCE_NAME, 'update', security_service) security_service = db.security_service_update( context, id, security_service_data) return self._view_builder.detail(req, security_service)
def get_all_snapshots(self, context, search_opts=None): policy.check_policy(context, 'share', 'get_all_snapshots') search_opts = search_opts or {} if (context.is_admin and 'all_tenants' in search_opts): # Need to remove all_tenants to pass the filtering below. del search_opts['all_tenants'] snapshots = self.db.share_snapshot_get_all(context) else: snapshots = self.db.share_snapshot_get_all_by_project( context, context.project_id) if search_opts: LOG.debug("Searching by: %s" % str(search_opts)) results = [] not_found = object() for snapshot in snapshots: for opt, value in search_opts.iteritems(): if snapshot.get(opt, not_found) != value: break else: results.append(snapshot) snapshots = results return snapshots
def update(self, req, id, body): """Update a security service.""" context = req.environ['manila.context'] if not body or 'security_service' not in body: raise exc.HTTPUnprocessableEntity() security_service_data = body['security_service'] valid_update_keys = ( 'description', 'name' ) try: security_service = db.security_service_get(context, id) policy.check_policy(context, RESOURCE_NAME, 'show', security_service) except exception.NotFound: raise exc.HTTPNotFound() if security_service['status'].lower() in ['new', 'inactive']: update_dict = security_service_data else: update_dict = dict([(key, security_service_data[key]) for key in valid_update_keys if key in security_service_data]) policy.check_policy(context, RESOURCE_NAME, 'update', security_service) security_service = db.security_service_update(context, id, update_dict) return self._view_builder.detail(req, security_service)
def access_get_all(self, context, share): """Returns all access rules for share.""" policy.check_policy(context, 'share', 'access_get_all') rules = self.db.share_access_get_all_for_share(context, share['id']) return [{'id': rule.id, 'access_type': rule.access_type, 'access_to': rule.access_to, 'state': rule.state} for rule in rules]
def allow_access_to_instance(self, context, share_instance, access): policy.check_policy(context, 'share', 'allow_access') if not share_instance['host']: msg = _("Invalid share instance host: %s") % share_instance['host'] raise exception.InvalidShareInstance(reason=msg) self.share_rpcapi.allow_access(context, share_instance, access)
def index(self, req): """Returns the list of share types.""" context = req.environ['manila.context'] policy.check_policy(context, RESOURCE_NAME, 'index') limited_types = self._get_share_types(req) req.cache_db_share_types(limited_types) return self._view_builder.index(req, limited_types)
def unmanage(self, context, share): policy.check_policy(context, 'share', 'unmanage') update_data = {'status': constants.STATUS_UNMANAGING, 'terminated_at': timeutils.utcnow()} share_ref = self.db.share_update(context, share['id'], update_data) self.share_rpcapi.unmanage_share(context, share_ref)
def _pools(self, req, action='index'): context = req.environ['manila.context'] policy.check_policy(context, POOLS_RESOURCES_NAME, action) search_opts = {} search_opts.update(req.GET) pools = self.scheduler_api.get_pools(context, filters=search_opts) detail = (action == 'detail') return self._view_builder.pools(pools, detail=detail)
def wrapper(self, req, *args, **kwargs): action = action_name or f.__name__ context = req.environ['manila.context'] try: policy.check_policy(context, self.resource_name, action) except exception.PolicyNotAuthorized: raise webob.exc.HTTPForbidden() return f(self, req, *args, **kwargs)
def _verify_snapshot(self, context, snapshot_id): try: snapshot = db_api.share_snapshot_get(context, snapshot_id) share = db_api.share_get(context, snapshot['share_id']) if not share['is_public']: policy.check_policy(context, 'share', 'get', share) except exception.NotFound: msg = _("Snapshot '%s' not found.") % snapshot_id raise exc.HTTPNotFound(explanation=msg) return snapshot
def details(self, req, id): """Return details for requested share server.""" context = req.environ['manila.context'] policy.check_policy(context, RESOURCE_NAME, 'details') try: db_api.share_server_get(context, id) except exception.ShareServerNotFound as e: raise exc.HTTPNotFound(explanation=six.text_type(e)) details = db_api.share_server_backend_details_get(context, id) return self._view_builder.build_share_server_details(details)
def delete(self, req, id): """Delete specified share network.""" context = req.environ['manila.context'] policy.check_policy(context, RESOURCE_NAME, 'delete') try: share_network = db_api.share_network_get(context, id) except exception.ShareNetworkNotFound as e: raise exc.HTTPNotFound(explanation=six.text_type(e)) share_instances = ( db_api.share_instances_get_all_by_share_network(context, id) ) if share_instances: msg = _("Can not delete share network %(id)s, it has " "%(len)s share(s).") % {'id': id, 'len': len(share_instances)} LOG.error(msg) raise exc.HTTPConflict(explanation=msg) # NOTE(ameade): Do not allow deletion of share network used by share # group sg_count = db_api.count_share_groups_in_share_network(context, id) if sg_count: msg = _("Can not delete share network %(id)s, it has %(len)s " "share group(s).") % {'id': id, 'len': sg_count} LOG.error(msg) raise exc.HTTPConflict(explanation=msg) # NOTE(silvacarlose): Do not allow the deletion of any share server # if one of them has the flag is_auto_deletable = False if not self._all_share_servers_are_auto_deletable(share_network): msg = _("The service cannot determine if there are any " "non-managed shares on the share network %(id)s, so it " "cannot be deleted. Please contact the cloud " "administrator to rectify.") % {'id': id} LOG.error(msg) raise exc.HTTPConflict(explanation=msg) for share_server in share_network['share_servers']: self.share_rpcapi.delete_share_server(context, share_server) db_api.share_network_delete(context, id) try: reservations = QUOTAS.reserve( context, project_id=share_network['project_id'], share_networks=-1, user_id=share_network['user_id']) except Exception: LOG.exception("Failed to update usages deleting " "share-network.") else: QUOTAS.commit(context, reservations, project_id=share_network['project_id'], user_id=share_network['user_id']) return webob.Response(status_int=http_client.ACCEPTED)
def show(self, req, id): """Return data about the given security service.""" context = req.environ['manila.context'] try: security_service = db.security_service_get(context, id) policy.check_policy(context, RESOURCE_NAME, 'show', security_service) except exception.NotFound: raise exc.HTTPNotFound() return self._view_builder.detail(req, security_service)
def show(self, req, id): """Return data about the requested network info.""" context = req.environ['manila.context'] policy.check_policy(context, RESOURCE_NAME, 'show') try: share_network = db_api.share_network_get(context, id) except exception.ShareNetworkNotFound as e: raise exc.HTTPNotFound(explanation=six.text_type(e)) return self._view_builder.build_share_network(share_network)
def _get_security_services(self, req, is_detail): """Returns a transformed list of security services. The list gets transformed through view builder. """ context = req.environ['manila.context'] search_opts = {} search_opts.update(req.GET) # NOTE(vponomaryov): remove 'status' from search opts # since it was removed from security service model. search_opts.pop('status', None) if 'share_network_id' in search_opts: share_nw = db.share_network_get(context, search_opts['share_network_id']) security_services = share_nw['security_services'] del search_opts['share_network_id'] else: if 'all_tenants' in search_opts and context.is_admin: policy.check_policy(context, RESOURCE_NAME, 'get_all_security_services') security_services = db.security_service_get_all(context) else: security_services = db.security_service_get_all_by_project( context, context.project_id) search_opts.pop('all_tenants', None) common.remove_invalid_options( context, search_opts, self._get_security_services_search_options()) if search_opts: results = [] not_found = object() for ss in security_services: if all(ss.get(opt, not_found) == value for opt, value in search_opts.items()): results.append(ss) security_services = results limited_list = common.limited(security_services, req) if is_detail: security_services = self._view_builder.detail_list( req, limited_list) for ss in security_services['security_services']: share_networks = db.share_network_get_all_by_security_service( context, ss['id']) ss['share_networks'] = [sn['id'] for sn in share_networks] else: security_services = self._view_builder.summary_list( req, limited_list) return security_services
def show(self, req, id): """Return data about the requested network info.""" context = req.environ["manila.context"] policy.check_policy(context, RESOURCE_NAME, "show") try: share_network = db_api.share_network_get(context, id) except exception.ShareNetworkNotFound as e: msg = "%s" % e raise exc.HTTPNotFound(explanation=msg) return self._view_builder.build_share_network(share_network)
def delete_share_server(self, context, server): """Delete share server.""" policy.check_policy(context, 'share_server', 'delete', server) shares = self.db.share_get_all_by_share_server(context, server['id']) if shares: raise exception.ShareServerInUse(share_server_id=server['id']) # NOTE(vponomaryov): There is no share_server status update here, # it is intentional. # Status will be changed in manila.share.manager after verification # for race condition between share creation on server # and server deletion. self.share_rpcapi.delete_share_server(context, server)
def extend(self, context, share, new_size): policy.check_policy(context, 'share', 'extend') if share['status'] != constants.STATUS_AVAILABLE: msg_params = { 'valid_status': constants.STATUS_AVAILABLE, 'share_id': share['id'], 'status': share['status'], } msg = _("Share %(share_id)s status must be '%(valid_status)s' " "to extend, but current status is: " "%(status)s.") % msg_params raise exception.InvalidShare(reason=msg) self._check_is_share_busy(share) size_increase = int(new_size) - share['size'] if size_increase <= 0: msg = (_("New size for extend must be greater " "than current size. (current: %(size)s, " "extended: %(new_size)s).") % {'new_size': new_size, 'size': share['size']}) raise exception.InvalidInput(reason=msg) try: reservations = QUOTAS.reserve(context, project_id=share['project_id'], gigabytes=size_increase) except exception.OverQuota as exc: usages = exc.kwargs['usages'] quotas = exc.kwargs['quotas'] def _consumed(name): return usages[name]['reserved'] + usages[name]['in_use'] msg = _LE("Quota exceeded for %(s_pid)s, tried to extend share " "by %(s_size)sG, (%(d_consumed)dG of %(d_quota)dG " "already consumed).") LOG.error(msg, {'s_pid': context.project_id, 's_size': size_increase, 'd_consumed': _consumed('gigabytes'), 'd_quota': quotas['gigabytes']}) raise exception.ShareSizeExceedsAvailableQuota( requested=size_increase, consumed=_consumed('gigabytes'), quota=quotas['gigabytes']) self.update(context, share, {'status': constants.STATUS_EXTENDING}) self.share_rpcapi.extend_share(context, share, new_size, reservations) LOG.info(_LI("Extend share request issued successfully."), resource=share)
def create(self, req, body): """Creates a new share network.""" context = req.environ['manila.context'] policy.check_policy(context, RESOURCE_NAME, 'create') if not body or RESOURCE_NAME not in body: raise exc.HTTPUnprocessableEntity() share_network_values = body[RESOURCE_NAME] share_network_subnet_values = copy.deepcopy(share_network_values) share_network_values['project_id'] = context.project_id share_network_values['user_id'] = context.user_id if 'nova_net_id' in share_network_values: msg = _("nova networking is not supported starting in Ocata.") raise exc.HTTPBadRequest(explanation=msg) share_network_values.pop('availability_zone', None) share_network_values.pop('neutron_net_id', None) share_network_values.pop('neutron_subnet_id', None) if req.api_version_request >= api_version.APIVersionRequest("2.51"): if 'availability_zone' in share_network_subnet_values: try: az = db_api.availability_zone_get( context, share_network_subnet_values['availability_zone']) share_network_subnet_values['availability_zone_id'] = ( az['id']) share_network_subnet_values.pop('availability_zone') except exception.AvailabilityZoneNotFound: msg = (_("The provided availability zone %s does not " "exist.") % share_network_subnet_values['availability_zone']) raise exc.HTTPBadRequest(explanation=msg) common.check_net_id_and_subnet_id(share_network_subnet_values) try: reservations = QUOTAS.reserve(context, share_networks=1) except exception.OverQuota as e: overs = e.kwargs['overs'] usages = e.kwargs['usages'] quotas = e.kwargs['quotas'] def _consumed(name): return (usages[name]['reserved'] + usages[name]['in_use']) if 'share_networks' in overs: LOG.warning( "Quota exceeded for %(s_pid)s, " "tried to create " "share-network (%(d_consumed)d of %(d_quota)d " "already consumed).", { 's_pid': context.project_id, 'd_consumed': _consumed('share_networks'), 'd_quota': quotas['share_networks'] }) raise exception.ShareNetworksLimitExceeded( allowed=quotas['share_networks']) else: # Tries to create the new share network try: share_network = db_api.share_network_create( context, share_network_values) except db_exception.DBError as e: LOG.exception(e) msg = "Could not create share network." raise exc.HTTPInternalServerError(explanation=msg) share_network_subnet_values['share_network_id'] = ( share_network['id']) share_network_subnet_values.pop('id', None) # Try to create the share network subnet. If it fails, the service # must rollback the share network creation. try: db_api.share_network_subnet_create( context, share_network_subnet_values) except db_exception.DBError: db_api.share_network_delete(context, share_network['id']) msg = _('Could not create share network.') raise exc.HTTPInternalServerError(explanation=msg) QUOTAS.commit(context, reservations) share_network = db_api.share_network_get(context, share_network['id']) return self._view_builder.build_share_network(req, share_network)
def create(self, context, share_proto, size, name, description, snapshot=None, availability_zone=None, metadata=None, share_network_id=None, share_type=None, is_public=False, consistency_group_id=None, cgsnapshot_member=None): """Create new share.""" policy.check_policy(context, 'share', 'create') self._check_metadata_properties(context, metadata) if snapshot is not None: if snapshot['status'] != constants.STATUS_AVAILABLE: msg = _("status must be '%s'") % constants.STATUS_AVAILABLE raise exception.InvalidShareSnapshot(reason=msg) if not size: size = snapshot['size'] snapshot_id = snapshot['id'] else: snapshot_id = None def as_int(s): try: return int(s) except (ValueError, TypeError): return s # tolerate size as stringified int size = as_int(size) if not isinstance(size, int) or size <= 0: msg = (_("Share size '%s' must be an integer and greater than 0") % size) raise exception.InvalidInput(reason=msg) if snapshot and size < snapshot['size']: msg = (_("Share size '%s' must be equal or greater " "than snapshot size") % size) raise exception.InvalidInput(reason=msg) if snapshot is None: share_type_id = share_type['id'] if share_type else None else: source_share = self.db.share_get(context, snapshot['share_id']) availability_zone = source_share['availability_zone'] if share_type is None: share_type_id = source_share['share_type_id'] else: share_type_id = share_type['id'] if share_type_id != source_share['share_type_id']: msg = _("Invalid share type specified: the requested " "share type must match the type of the source " "share. If a share type is not specified when " "requesting a new share from a snapshot, the " "share type of the source share will be applied " "to the new share.") raise exception.InvalidInput(reason=msg) supported_share_protocols = (proto.upper() for proto in CONF.enabled_share_protocols) if not (share_proto and share_proto.upper() in supported_share_protocols): msg = (_("Invalid share protocol provided: %(provided)s. " "It is either disabled or unsupported. Available " "protocols: %(supported)s") % dict(provided=share_proto, supported=CONF.enabled_share_protocols)) raise exception.InvalidInput(reason=msg) try: reservations = QUOTAS.reserve(context, shares=1, gigabytes=size) except exception.OverQuota as e: overs = e.kwargs['overs'] usages = e.kwargs['usages'] quotas = e.kwargs['quotas'] def _consumed(name): return (usages[name]['reserved'] + usages[name]['in_use']) if 'gigabytes' in overs: LOG.warning( _LW("Quota exceeded for %(s_pid)s, " "tried to create " "%(s_size)sG share (%(d_consumed)dG of " "%(d_quota)dG already consumed)."), { 's_pid': context.project_id, 's_size': size, 'd_consumed': _consumed('gigabytes'), 'd_quota': quotas['gigabytes'] }) raise exception.ShareSizeExceedsAvailableQuota() elif 'shares' in overs: LOG.warning( _LW("Quota exceeded for %(s_pid)s, " "tried to create " "share (%(d_consumed)d shares " "already consumed)."), { 's_pid': context.project_id, 'd_consumed': _consumed('shares') }) raise exception.ShareLimitExceeded(allowed=quotas['shares']) try: is_public = strutils.bool_from_string(is_public, strict=True) snapshot_support = strutils.bool_from_string( share_type.get('extra_specs', {}).get('snapshot_support', True) if share_type else True, strict=True) except ValueError as e: raise exception.InvalidParameterValue(six.text_type(e)) consistency_group = None if consistency_group_id: try: consistency_group = self.db.consistency_group_get( context, consistency_group_id) except exception.NotFound as e: raise exception.InvalidParameterValue(six.text_type(e)) if (not cgsnapshot_member and not (consistency_group['status'] == constants.STATUS_AVAILABLE)): params = { 'avail': constants.STATUS_AVAILABLE, 'cg_status': consistency_group['status'], } msg = _("Consistency group status must be %(avail)s, got" "%(cg_status)s.") % params raise exception.InvalidConsistencyGroup(message=msg) if share_type_id: cg_st_ids = [ st['share_type_id'] for st in consistency_group.get('share_types', []) ] if share_type_id not in cg_st_ids: params = { 'type': share_type_id, 'cg': consistency_group_id } msg = _("The specified share type (%(type)s) is not " "supported by the specified consistency group " "(%(cg)s).") % params raise exception.InvalidParameterValue(msg) if (not consistency_group.get('share_network_id') == share_network_id): params = {'net': share_network_id, 'cg': consistency_group_id} msg = _("The specified share network (%(net)s) is not " "supported by the specified consistency group " "(%(cg)s).") % params raise exception.InvalidParameterValue(msg) options = { 'size': size, 'user_id': context.user_id, 'project_id': context.project_id, 'snapshot_id': snapshot_id, 'snapshot_support': snapshot_support, 'metadata': metadata, 'display_name': name, 'display_description': description, 'share_proto': share_proto, 'share_type_id': share_type_id, 'is_public': is_public, 'consistency_group_id': consistency_group_id, } if cgsnapshot_member: options['source_cgsnapshot_member_id'] = cgsnapshot_member['id'] try: share = self.db.share_create(context, options, create_share_instance=False) QUOTAS.commit(context, reservations) except Exception: with excutils.save_and_reraise_exception(): try: self.db.share_delete(context, share['id']) finally: QUOTAS.rollback(context, reservations) host = None if snapshot and not CONF.use_scheduler_creating_share_from_snapshot: # Shares from snapshots with restriction - source host only. # It is common situation for different types of backends. host = snapshot['share']['host'] self.create_instance(context, share, share_network_id=share_network_id, host=host, availability_zone=availability_zone, consistency_group=consistency_group, cgsnapshot_member=cgsnapshot_member) return share
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'] } raise exception.InvalidShare(reason=msg) self._check_is_share_busy(share) # 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'] } 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'] 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 create(self, context, share_proto, size, name, description, snapshot=None, availability_zone=None, metadata=None, share_network_id=None, volume_type=None): """Create new share.""" policy.check_policy(context, 'share', 'create') self._check_metadata_properties(context, metadata) if snapshot is not None: if snapshot['status'] != 'available': msg = _('status must be available') raise exception.InvalidShareSnapshot(reason=msg) if not size: size = snapshot['size'] snapshot_id = snapshot['id'] else: snapshot_id = None def as_int(s): try: return int(s) except (ValueError, TypeError): return s # tolerate size as stringified int size = as_int(size) if not isinstance(size, int) or size <= 0: msg = (_("Share size '%s' must be an integer and greater than 0") % size) raise exception.InvalidInput(reason=msg) if snapshot and size < snapshot['size']: msg = (_("Share size '%s' must be equal or greater " "than snapshot size") % size) raise exception.InvalidInput(reason=msg) if snapshot and volume_type: source_share = self.db.share_get(context, snapshot['share_id']) if volume_type['id'] != source_share['volume_type_id']: msg = _("Invalid volume_type provided (requested type " "must match source snapshot, or be omitted). " "You should omit the argument.") raise exception.InvalidInput(reason=msg) # TODO(rushiagr): Find a suitable place to keep all the allowed # share types so that it becomes easier to add one if share_proto.lower() not in ['nfs', 'cifs', 'glusterfs']: msg = (_("Invalid share type provided: %s") % share_proto) raise exception.InvalidInput(reason=msg) try: reservations = QUOTAS.reserve(context, shares=1, gigabytes=size) except exception.OverQuota as e: overs = e.kwargs['overs'] usages = e.kwargs['usages'] quotas = e.kwargs['quotas'] def _consumed(name): return (usages[name]['reserved'] + usages[name]['in_use']) if 'gigabytes' in overs: LOG.warn( _LW("Quota exceeded for %(s_pid)s, tried to create " "%(s_size)sG share (%(d_consumed)dG of " "%(d_quota)dG already consumed)"), { 's_pid': context.project_id, 's_size': size, 'd_consumed': _consumed('gigabytes'), 'd_quota': quotas['gigabytes'] }) raise exception.ShareSizeExceedsAvailableQuota() elif 'shares' in overs: LOG.warn( _LW("Quota exceeded for %(s_pid)s, tried to create " "share (%(d_consumed)d shares " "already consumed)"), { 's_pid': context.project_id, 'd_consumed': _consumed('shares') }) raise exception.ShareLimitExceeded(allowed=quotas['shares']) if availability_zone is None: availability_zone = CONF.storage_availability_zone options = { 'size': size, 'user_id': context.user_id, 'project_id': context.project_id, 'snapshot_id': snapshot_id, 'share_network_id': share_network_id, 'availability_zone': availability_zone, 'metadata': metadata, 'status': "creating", 'scheduled_at': timeutils.utcnow(), 'display_name': name, 'display_description': description, 'share_proto': share_proto, 'volume_type_id': volume_type['id'] if volume_type else None } try: share = self.db.share_create(context, options) QUOTAS.commit(context, reservations) except Exception: with excutils.save_and_reraise_exception(): try: self.db.share_delete(context, share['id']) finally: QUOTAS.rollback(context, reservations) request_spec = { 'share_properties': options, 'share_proto': share_proto, 'share_id': share['id'], 'snapshot_id': snapshot_id, 'volume_type': volume_type, } filter_properties = {} if (snapshot and not CONF.use_scheduler_creating_share_from_snapshot): # Shares from snapshots with restriction - source host only. # It is common situation for different types of backends. host = snapshot['share']['host'] share = self.db.share_update(context, share['id'], {'host': host}) self.share_rpcapi.create_share( context, share, host, request_spec=request_spec, filter_properties=filter_properties, snapshot_id=snapshot_id, ) else: # Shares from scratch and from snapshots when source host is not # the only allowed, it is possible, for example, in multibackend # installation with Generic drivers only. self.scheduler_rpcapi.create_share( context, CONF.share_topic, share['id'], snapshot_id, request_spec=request_spec, filter_properties=filter_properties, ) return share
def get(self, context, share_id): rv = self.db.share_get(context, share_id) if not rv['is_public']: policy.check_policy(context, 'share', 'get', rv) return rv
def index(self, req): """Returns a summary list of security services.""" policy.check_policy(req.environ['manila.context'], RESOURCE_NAME, 'index') return self._get_security_services(req, is_detail=False)
def _get_share_networks(self, req, is_detail=True): """Returns a list of share networks.""" context = req.environ['manila.context'] search_opts = {} search_opts.update(req.GET) if ('all_tenants' in search_opts or ('project_id' in search_opts and search_opts['project_id'] != context.project_id)): policy.check_policy(context, RESOURCE_NAME, 'get_all_share_networks') if 'security_service_id' in search_opts: networks = db_api.share_network_get_all_by_security_service( context, search_opts['security_service_id']) elif ('project_id' in search_opts and search_opts['project_id'] != context.project_id): networks = db_api.share_network_get_all_by_project( context, search_opts['project_id']) elif 'all_tenants' in search_opts: networks = db_api.share_network_get_all(context) else: networks = db_api.share_network_get_all_by_project( context, context.project_id) date_parsing_error_msg = '''%s is not in yyyy-mm-dd format.''' if 'created_since' in search_opts: try: created_since = timeutils.parse_strtime( search_opts['created_since'], fmt="%Y-%m-%d") except ValueError: msg = date_parsing_error_msg % search_opts['created_since'] raise exc.HTTPBadRequest(explanation=msg) networks = [ network for network in networks if network['created_at'] >= created_since ] if 'created_before' in search_opts: try: created_before = timeutils.parse_strtime( search_opts['created_before'], fmt="%Y-%m-%d") except ValueError: msg = date_parsing_error_msg % search_opts['created_before'] raise exc.HTTPBadRequest(explanation=msg) networks = [ network for network in networks if network['created_at'] <= created_before ] opts_to_remove = [ 'all_tenants', 'created_since', 'created_before', 'limit', 'offset', 'security_service_id', ] for opt in opts_to_remove: search_opts.pop(opt, None) if search_opts: for key, value in search_opts.items(): if key in ['ip_version', 'segmentation_id']: value = int(value) networks = [ network for network in networks if network[key] == value ] limited_list = common.limited(networks, req) return self._view_builder.build_share_networks(limited_list, is_detail)
def access_get(self, context, access_id): """Returns access rule with the id.""" policy.check_policy(context, 'share', 'access_get') rule = self.db.share_access_get(context, access_id) return rule
def get(self, context, cg_id): policy.check_policy(context, 'consistency_group', 'get') return self.db.consistency_group_get(context, cg_id)
def create_instance(self, context, share, share_network_id=None, host=None, availability_zone=None, consistency_group=None, cgsnapshot_member=None): policy.check_policy(context, 'share', 'create') availability_zone_id = None if availability_zone: availability_zone_id = self.db.availability_zone_get( context, availability_zone).id # TODO(u_glide): Add here validation that provided share network # doesn't conflict with provided availability_zone when Neutron # will have AZ support. share_instance = self.db.share_instance_create( context, share['id'], { 'share_network_id': share_network_id, 'status': constants.STATUS_CREATING, 'scheduled_at': timeutils.utcnow(), 'host': host if host else '', 'availability_zone_id': availability_zone_id, }) if cgsnapshot_member: host = cgsnapshot_member['share']['host'] share = self.db.share_instance_update(context, share_instance['id'], {'host': host}) # NOTE(ameade): Do not cast to driver if creating from cgsnapshot return share_dict = share.to_dict() share_dict.update( {'metadata': self.db.share_metadata_get(context, share['id'])}) share_type = None if share['share_type_id']: share_type = self.db.share_type_get(context, share['share_type_id']) request_spec = { 'share_properties': share_dict, 'share_instance_properties': share_instance.to_dict(), 'share_proto': share['share_proto'], 'share_id': share['id'], 'snapshot_id': share['snapshot_id'], 'share_type': share_type, 'consistency_group': consistency_group, } if host: self.share_rpcapi.create_share_instance( context, share_instance, host, request_spec=request_spec, filter_properties={}, snapshot_id=share['snapshot_id'], ) else: # Create share instance from scratch or from snapshot could happen # on hosts other than the source host. self.scheduler_rpcapi.create_share_instance( context, request_spec=request_spec, filter_properties={}) return share_instance
def get_all_cgsnapshot_members(self, context, cgsnapshot_id): policy.check_policy(context, 'consistency_group', 'get_cgsnapshot') members = self.db.cgsnapshot_members_get_all(context, cgsnapshot_id) return members
def delete(self, req, id): """Delete specified share network.""" context = req.environ['manila.context'] policy.check_policy(context, RESOURCE_NAME, 'delete') try: share_network = db_api.share_network_get(context, id) except exception.ShareNetworkNotFound as e: raise exc.HTTPNotFound(explanation=e.msg) share_instances = (db_api.share_instances_get_all_by_share_network( context, id)) if share_instances: msg = _("Can not delete share network %(id)s, it has " "%(len)s share(s).") % { 'id': id, 'len': len(share_instances) } LOG.error(msg) raise exc.HTTPConflict(explanation=msg) # NOTE(ameade): Do not allow deletion of share network used by share # group sg_count = db_api.count_share_groups_in_share_network(context, id) if sg_count: msg = _("Can not delete share network %(id)s, it has %(len)s " "share group(s).") % { 'id': id, 'len': sg_count } LOG.error(msg) raise exc.HTTPConflict(explanation=msg) # NOTE(silvacarlose): Do not allow the deletion of share networks # if it still contains two or more subnets if self._share_network_contains_subnets(share_network): msg = _("The share network %(id)s has more than one subnet " "attached. Please remove the subnets untill you have one " "or no subnets remaining.") % { 'id': id } LOG.error(msg) raise exc.HTTPConflict(explanation=msg) for subnet in share_network['share_network_subnets']: if not self._all_share_servers_are_auto_deletable(subnet): msg = _("The service cannot determine if there are any " "non-managed shares on the share network subnet " "%(id)s, so it cannot be deleted. Please contact the " "cloud administrator to rectify.") % { 'id': subnet['id'] } LOG.error(msg) raise exc.HTTPConflict(explanation=msg) for subnet in share_network['share_network_subnets']: for share_server in subnet['share_servers']: self.share_rpcapi.delete_share_server(context, share_server) db_api.share_network_delete(context, id) try: reservations = QUOTAS.reserve( context, project_id=share_network['project_id'], share_networks=-1, user_id=share_network['user_id']) except Exception: LOG.exception("Failed to update usages deleting " "share-network.") else: QUOTAS.commit(context, reservations, project_id=share_network['project_id'], user_id=share_network['user_id']) return webob.Response(status_int=http_client.ACCEPTED)
def create_snapshot(self, context, share, name, description, force=False): policy.check_policy(context, 'share', 'create_snapshot', share) if ((not force) and (share['status'] != "available")): msg = _("must be available") raise exception.InvalidShare(reason=msg) size = share['size'] try: reservations = QUOTAS.reserve(context, snapshots=1, gigabytes=size) except exception.OverQuota as e: overs = e.kwargs['overs'] usages = e.kwargs['usages'] quotas = e.kwargs['quotas'] def _consumed(name): return (usages[name]['reserved'] + usages[name]['in_use']) if 'gigabytes' in overs: msg = _LW("Quota exceeded for %(s_pid)s, tried to create " "%(s_size)sG snapshot (%(d_consumed)dG of " "%(d_quota)dG already consumed)") LOG.warn( msg, { 's_pid': context.project_id, 's_size': size, 'd_consumed': _consumed('gigabytes'), 'd_quota': quotas['gigabytes'] }) raise exception.ShareSizeExceedsAvailableQuota() elif 'snapshots' in overs: msg = _LW("Quota exceeded for %(s_pid)s, tried to create " "snapshot (%(d_consumed)d snapshots " "already consumed)") LOG.warn( msg, { 's_pid': context.project_id, 'd_consumed': _consumed('snapshots') }) raise exception.SnapshotLimitExceeded( allowed=quotas['snapshots']) options = { 'share_id': share['id'], 'size': share['size'], 'user_id': context.user_id, 'project_id': context.project_id, 'status': "creating", 'progress': '0%', 'share_size': share['size'], 'display_name': name, 'display_description': description, 'share_proto': share['share_proto'], 'export_location': share['export_location'] } try: snapshot = self.db.share_snapshot_create(context, options) QUOTAS.commit(context, reservations) except Exception: with excutils.save_and_reraise_exception(): try: self.db.snapshot_delete(context, share['id']) finally: QUOTAS.rollback(context, reservations) self.share_rpcapi.create_snapshot(context, share, snapshot) return snapshot
def get_snapshot(self, context, snapshot_id): policy.check_policy(context, 'share', 'get_snapshot') rv = self.db.share_snapshot_get(context, snapshot_id) return dict(six.iteritems(rv))
def get(self, context, share_id): rv = self.db.share_get(context, share_id) policy.check_policy(context, 'share', 'get', rv) return rv
def get_all(self, context, search_opts=None, sort_key='created_at', sort_dir='desc'): policy.check_policy(context, 'share', 'get_all') if search_opts is None: search_opts = {} LOG.debug("Searching for shares by: %s", six.text_type(search_opts)) # Prepare filters filters = {} if 'metadata' in search_opts: filters['metadata'] = search_opts.pop('metadata') if not isinstance(filters['metadata'], dict): msg = _("Wrong metadata filter provided: " "%s.") % six.text_type(filters['metadata']) raise exception.InvalidInput(reason=msg) if 'extra_specs' in search_opts: # Verify policy for extra-specs access extensions.extension_authorizer('share', 'types_extra_specs')(context) filters['extra_specs'] = search_opts.pop('extra_specs') if not isinstance(filters['extra_specs'], dict): msg = _("Wrong extra specs filter provided: " "%s.") % six.text_type(filters['extra_specs']) raise exception.InvalidInput(reason=msg) if not (isinstance(sort_key, six.string_types) and sort_key): msg = _("Wrong sort_key filter provided: " "'%s'.") % six.text_type(sort_key) raise exception.InvalidInput(reason=msg) if not (isinstance(sort_dir, six.string_types) and sort_dir): msg = _("Wrong sort_dir filter provided: " "'%s'.") % six.text_type(sort_dir) raise exception.InvalidInput(reason=msg) # Get filtered list of shares if 'share_server_id' in search_opts: # NOTE(vponomaryov): this is project_id independent policy.check_policy(context, 'share', 'list_by_share_server_id') shares = self.db.share_get_all_by_share_server( context, search_opts.pop('share_server_id'), filters=filters, sort_key=sort_key, sort_dir=sort_dir) elif (context.is_admin and 'all_tenants' in search_opts): shares = self.db.share_get_all(context, filters=filters, sort_key=sort_key, sort_dir=sort_dir) else: shares = self.db.share_get_all_by_project( context, project_id=context.project_id, filters=filters, sort_key=sort_key, sort_dir=sort_dir) # NOTE(vponomaryov): we do not need 'all_tenants' opt anymore search_opts.pop('all_tenants', None) if search_opts: results = [] for s in shares: # values in search_opts can be only strings if all(s.get(k, None) == v for k, v in search_opts.items()): results.append(s) shares = results return shares
def create(self, context, name=None, description=None, share_type_ids=None, source_cgsnapshot_id=None, share_network_id=None): """Create new consistency group.""" policy.check_policy(context, 'consistency_group', 'create') cgsnapshot = None original_cg = None if source_cgsnapshot_id: cgsnapshot = self.db.cgsnapshot_get(context, source_cgsnapshot_id) if cgsnapshot['status'] != constants.STATUS_AVAILABLE: msg = (_("Consistency group snapshot status must be %s") % constants.STATUS_AVAILABLE) raise exception.InvalidCGSnapshot(reason=msg) original_cg = self.db.consistency_group_get( context, cgsnapshot['consistency_group_id']) share_type_ids = [ s['share_type_id'] for s in original_cg['share_types'] ] # Get share_type_objects share_type_objects = [] driver_handles_share_servers = None for share_type_id in (share_type_ids or []): try: share_type_object = share_types.get_share_type( context, share_type_id) except exception.ShareTypeNotFound: msg = _("Share type with id %s could not be found") raise exception.InvalidInput(msg % share_type_id) share_type_objects.append(share_type_object) extra_specs = share_type_object.get('extra_specs') if extra_specs: share_type_handle_ss = strutils.bool_from_string( extra_specs.get( constants.ExtraSpecs.DRIVER_HANDLES_SHARE_SERVERS)) if driver_handles_share_servers is None: driver_handles_share_servers = share_type_handle_ss elif not driver_handles_share_servers == share_type_handle_ss: # NOTE(ameade): if the share types have conflicting values # for driver_handles_share_servers then raise bad request msg = _("The specified share_types cannot have " "conflicting values for the " "driver_handles_share_servers extra spec.") raise exception.InvalidInput(reason=msg) if (not share_type_handle_ss) and share_network_id: msg = _("When using a share types with the " "driver_handles_share_servers extra spec as " "False, a share_network_id must not be provided.") raise exception.InvalidInput(reason=msg) try: if share_network_id: self.db.share_network_get(context, share_network_id) except exception.ShareNetworkNotFound: msg = _("The specified share network does not exist.") raise exception.InvalidInput(reason=msg) if (driver_handles_share_servers and not (source_cgsnapshot_id or share_network_id)): msg = _("When using a share type with the " "driver_handles_share_servers extra spec as" "True, a share_network_id must be provided.") raise exception.InvalidInput(reason=msg) options = { 'source_cgsnapshot_id': source_cgsnapshot_id, 'share_network_id': share_network_id, 'name': name, 'description': description, 'user_id': context.user_id, 'project_id': context.project_id, 'status': constants.STATUS_CREATING, 'share_types': share_type_ids } if original_cg: options['host'] = original_cg['host'] cg = self.db.consistency_group_create(context, options) try: if cgsnapshot: members = self.db.cgsnapshot_members_get_all( context, source_cgsnapshot_id) for member in members: share_type = share_types.get_share_type( context, member['share_type_id']) member['share'] = self.db.share_instance_get( context, member['share_instance_id'], with_share_data=True) self.share_api.create(context, member['share_proto'], member['size'], None, None, consistency_group_id=cg['id'], cgsnapshot_member=member, share_type=share_type, share_network_id=share_network_id) except Exception: with excutils.save_and_reraise_exception(): self.db.consistency_group_destroy(context.elevated(), cg['id']) request_spec = {'consistency_group_id': cg['id']} request_spec.update(options) request_spec['share_types'] = share_type_objects if cgsnapshot and original_cg: self.share_rpcapi.create_consistency_group(context, cg, original_cg['host']) else: self.scheduler_rpcapi.create_consistency_group( context, cg_id=cg['id'], request_spec=request_spec, filter_properties={}) return cg
def update(self, req, id, body): """Update specified share network.""" context = req.environ['manila.context'] policy.check_policy(context, RESOURCE_NAME, 'update') if not body or RESOURCE_NAME not in body: raise exc.HTTPUnprocessableEntity() try: share_network = db_api.share_network_get(context, id) except exception.ShareNetworkNotFound as e: raise exc.HTTPNotFound(explanation=e.msg) update_values = body[RESOURCE_NAME] if 'nova_net_id' in update_values: msg = _("nova networking is not supported starting in Ocata.") raise exc.HTTPBadRequest(explanation=msg) if self._share_network_subnets_contain_share_servers(share_network): for value in update_values: if value not in ['name', 'description']: msg = (_("Cannot update share network %s. It is used by " "share servers. Only 'name' and 'description' " "fields are available for update") % share_network['id']) raise exc.HTTPForbidden(explanation=msg) try: if ('neutron_net_id' in update_values or 'neutron_subnet_id' in update_values): subnet = db_api.share_network_subnet_get_default_subnet( context, id) if not subnet: msg = _("The share network %(id)s does not have a " "'default' subnet that serves all availability " "zones, so subnet details " "('neutron_net_id', 'neutron_subnet_id') cannot " "be updated.") % { 'id': id } raise exc.HTTPBadRequest(explanation=msg) # NOTE(silvacarlose): If the default share network subnet have # the fields neutron_net_id and neutron_subnet_id set as None, # we need to make sure that in the update request the user is # passing both parameter since a share network subnet must # have both fields filled or empty. subnet_neutron_net_and_subnet_id_are_empty = ( subnet['neutron_net_id'] is None and subnet['neutron_subnet_id'] is None) update_values_without_neutron_net_or_subnet = ( update_values.get('neutron_net_id') is None or update_values.get('neutron_subnet_id') is None) if (subnet_neutron_net_and_subnet_id_are_empty and update_values_without_neutron_net_or_subnet): msg = _("To update the share network %(id)s you need to " "specify both 'neutron_net_id' and " "'neutron_subnet_id'.") % { 'id': id } raise webob.exc.HTTPBadRequest(explanation=msg) db_api.share_network_subnet_update(context, subnet['id'], update_values) share_network = db_api.share_network_update( context, id, update_values) except db_exception.DBError: msg = "Could not save supplied data due to database error" raise exc.HTTPBadRequest(explanation=msg) return self._view_builder.build_share_network(req, share_network)
def get_cgsnapshot(self, context, snapshot_id): policy.check_policy(context, 'consistency_group', 'get_cgsnapshot') return self.db.cgsnapshot_get(context, snapshot_id)
def detail(self, req): """Returns a detailed list of share networks.""" policy.check_policy(req.environ['manila.context'], RESOURCE_NAME, 'detail') return self._get_share_networks(req)
def create_cgsnapshot(self, context, name=None, description=None, consistency_group_id=None): """Create new cgsnapshot.""" policy.check_policy(context, 'consistency_group', 'create_cgsnapshot') options = { 'consistency_group_id': consistency_group_id, 'name': name, 'description': description, 'user_id': context.user_id, 'project_id': context.project_id, 'status': constants.STATUS_CREATING, } cg = self.db.consistency_group_get(context, consistency_group_id) # Check status of CG, must be active if not cg['status'] == constants.STATUS_AVAILABLE: msg = (_("Consistency group status must be %s") % constants.STATUS_AVAILABLE) raise exception.InvalidConsistencyGroup(reason=msg) # Create members for every share in the CG shares = self.db.share_get_all_by_consistency_group_id( context, consistency_group_id) # Check status of all shares, they must be active in order to snap # the CG for s in shares: if not s['status'] == constants.STATUS_AVAILABLE: msg = (_("Share %(s)s in consistency group must have status " "of %(status)s in order to create a CG snapshot") % { "s": s['id'], "status": constants.STATUS_AVAILABLE }) raise exception.InvalidConsistencyGroup(reason=msg) snap = self.db.cgsnapshot_create(context, options) try: members = [] for s in shares: member_options = { 'cgsnapshot_id': snap['id'], 'user_id': context.user_id, 'project_id': context.project_id, 'status': constants.STATUS_CREATING, 'size': s['size'], 'share_proto': s['share_proto'], 'share_type_id': s['share_type_id'], 'share_id': s['id'], 'share_instance_id': s.instance['id'] } member = self.db.cgsnapshot_member_create( context, member_options) members.append(member) # Cast to share manager self.share_rpcapi.create_cgsnapshot(context, snap, cg['host']) except Exception: with excutils.save_and_reraise_exception(): # This will delete the snapshot and all of it's members self.db.cgsnapshot_destroy(context, snap['id']) return snap
def index(self, req): """Returns a summary list of share networks.""" policy.check_policy(req.environ['manila.context'], RESOURCE_NAME, 'index') return self._get_share_networks(req, is_detail=False)
def create(self, context, share_proto, size, name, description, snapshot=None, availability_zone=None, metadata=None, share_network_id=None, share_type=None, is_public=False): """Create new share.""" policy.check_policy(context, 'share', 'create') self._check_metadata_properties(context, metadata) if snapshot is not None: if snapshot['status'] != 'available': msg = _("status must be 'available'") raise exception.InvalidShareSnapshot(reason=msg) if not size: size = snapshot['size'] snapshot_id = snapshot['id'] else: snapshot_id = None def as_int(s): try: return int(s) except (ValueError, TypeError): return s # tolerate size as stringified int size = as_int(size) if not isinstance(size, int) or size <= 0: msg = (_("Share size '%s' must be an integer and greater than 0") % size) raise exception.InvalidInput(reason=msg) if snapshot and size < snapshot['size']: msg = (_("Share size '%s' must be equal or greater " "than snapshot size") % size) raise exception.InvalidInput(reason=msg) if snapshot is None: share_type_id = share_type['id'] if share_type else None else: source_share = self.db.share_get(context, snapshot['share_id']) if share_type is None: share_type_id = source_share['share_type_id'] if share_type_id is not None: share_type = share_types.get_share_type( context, share_type_id) else: share_type_id = share_type['id'] if share_type_id != source_share['share_type_id']: msg = _("Invalid share type specified: the requested " "share type must match the type of the source " "share. If a share type is not specified when " "requesting a new share from a snapshot, the " "share type of the source share will be applied " "to the new share.") raise exception.InvalidInput(reason=msg) supported_share_protocols = (proto.upper() for proto in CONF.enabled_share_protocols) if not (share_proto and share_proto.upper() in supported_share_protocols): msg = (_("Invalid share protocol provided: %(provided)s. " "It is either disabled or unsupported. Available " "protocols: %(supported)s") % dict(provided=share_proto, supported=CONF.enabled_share_protocols)) raise exception.InvalidInput(reason=msg) try: reservations = QUOTAS.reserve(context, shares=1, gigabytes=size) except exception.OverQuota as e: overs = e.kwargs['overs'] usages = e.kwargs['usages'] quotas = e.kwargs['quotas'] def _consumed(name): return (usages[name]['reserved'] + usages[name]['in_use']) if 'gigabytes' in overs: LOG.warn( _LW("Quota exceeded for %(s_pid)s, tried to create " "%(s_size)sG share (%(d_consumed)dG of " "%(d_quota)dG already consumed)"), { 's_pid': context.project_id, 's_size': size, 'd_consumed': _consumed('gigabytes'), 'd_quota': quotas['gigabytes'] }) raise exception.ShareSizeExceedsAvailableQuota() elif 'shares' in overs: LOG.warn( _LW("Quota exceeded for %(s_pid)s, tried to create " "share (%(d_consumed)d shares " "already consumed)"), { 's_pid': context.project_id, 'd_consumed': _consumed('shares') }) raise exception.ShareLimitExceeded(allowed=quotas['shares']) if availability_zone is None: availability_zone = CONF.storage_availability_zone try: is_public = strutils.bool_from_string(is_public, strict=True) except ValueError as e: raise exception.InvalidParameterValue(e.message) options = { 'size': size, 'user_id': context.user_id, 'project_id': context.project_id, 'snapshot_id': snapshot_id, 'share_network_id': share_network_id, 'availability_zone': availability_zone, 'metadata': metadata, 'status': "creating", 'scheduled_at': timeutils.utcnow(), 'display_name': name, 'display_description': description, 'share_proto': share_proto, 'share_type_id': share_type_id, 'is_public': is_public, } try: share = self.db.share_create(context, options) QUOTAS.commit(context, reservations) except Exception: with excutils.save_and_reraise_exception(): try: self.db.share_delete(context, share['id']) finally: QUOTAS.rollback(context, reservations) request_spec = { 'share_properties': options, 'share_proto': share_proto, 'share_id': share['id'], 'snapshot_id': snapshot_id, 'share_type': share_type, } filter_properties = {} if (snapshot and not CONF.use_scheduler_creating_share_from_snapshot): # Shares from snapshots with restriction - source host only. # It is common situation for different types of backends. host = snapshot['share']['host'] share = self.db.share_update(context, share['id'], {'host': host}) self.share_rpcapi.create_share( context, share, host, request_spec=request_spec, filter_properties=filter_properties, snapshot_id=snapshot_id, ) else: # Shares from scratch and from snapshots when source host is not # the only allowed, it is possible, for example, in multibackend # installation with Generic drivers only. self.scheduler_rpcapi.create_share( context, CONF.share_topic, share['id'], snapshot_id, request_spec=request_spec, filter_properties=filter_properties, ) return share
def detail(self, req): """Returns a detailed list of security services.""" policy.check_policy(req.environ['manila.context'], RESOURCE_NAME, 'detail') return self._get_security_services(req, is_detail=True)