def _verify_if_non_public_share_type(self, context, share_type_id): try: share_type = share_types.get_share_type(context, share_type_id) if share_type['is_public']: msg = _("Type access modification is not applicable to " "public share type.") raise webob.exc.HTTPConflict(explanation=msg) except exception.ShareTypeNotFound as err: raise webob.exc.HTTPNotFound(explanation=six.text_type(err))
def show(self, req, id): """Return a single share type item.""" context = req.environ['manila.context'] try: share_type = share_types.get_share_type(context, id) except exception.NotFound: msg = _("Share type not found.") raise exc.HTTPNotFound(explanation=msg) share_type['id'] = six.text_type(share_type['id']) req.cache_db_share_type(share_type) return self._view_builder.show(req, share_type)
def _show_share_type_details(self, context, id): share_type = share_types.get_share_type(context, id) required_extra_specs = {} try: required_extra_specs = share_types.get_valid_required_extra_specs( share_type['extra_specs']) except exception.InvalidExtraSpec: LOG.exception('Share type %(share_type_id)s has invalid required' ' extra specs.', {'share_type_id': id}) share_type['required_extra_specs'] = required_extra_specs return share_type
def share_type_access(self, req, id): context = req.environ['manila.context'] try: share_type = share_types.get_share_type( context, id, expected_fields=['projects']) except exception.ShareTypeNotFound: explanation = _("Share type %s not found.") % id raise webob.exc.HTTPNotFound(explanation=explanation) if share_type['is_public']: expl = _("Access list not available for public share types.") raise webob.exc.HTTPNotFound(explanation=expl) return self._view_builder.share_type_access(req, share_type)
def index(self, req, type_id): context = req.environ['manila.context'] authorize(context) try: share_type = share_types.get_share_type( context, type_id, expected_fields=['projects']) except exception.ShareTypeNotFound: explanation = _("Share type %s not found.") % type_id raise webob.exc.HTTPNotFound(explanation=explanation) if share_type['is_public']: expl = _("Access list not available for public share types.") raise webob.exc.HTTPNotFound(explanation=expl) return _marshall_share_type_access(share_type)
def share_type_access(self, req, id): context = req.environ['manila.context'] try: share_type = share_types.get_share_type( context, id, expected_fields=['projects']) except exception.ShareTypeNotFound: explanation = _("Share type %s not found.") % id raise webob.exc.HTTPNotFound(explanation=explanation) if share_type['is_public']: expl = _("Access list not available for public share types.") raise webob.exc.HTTPNotFound(explanation=expl) # TODO(vponomaryov): move to views. rval = [] for project_id in share_type['projects']: rval.append( {'share_type_id': share_type['id'], 'project_id': project_id} ) return {'share_type_access': rval}
def _addProjectAccess(self, req, id, body): context = req.environ['manila.context'] authorize(context, action="addProjectAccess") self._check_body(body, 'addProjectAccess') project = body['addProjectAccess']['project'] try: share_type = share_types.get_share_type(context, id) if share_type['is_public']: msg = _("You cannot add project to public share_type.") raise webob.exc.HTTPForbidden(explanation=msg) except exception.ShareTypeNotFound as err: raise webob.exc.HTTPNotFound(explanation=six.text_type(err)) try: share_types.add_share_type_access(context, id, project) except exception.ShareTypeAccessExists as err: raise webob.exc.HTTPConflict(explanation=six.text_type(err)) return webob.Response(status_int=202)
def _delete(self, req, id): """Deletes an existing share type.""" context = req.environ['manila.context'] try: share_type = share_types.get_share_type(context, id) share_types.destroy(context, share_type['id']) notifier_info = dict(share_types=share_type) rpc.get_notifier('shareType').info( context, 'share_type.delete', notifier_info) except exception.ShareTypeInUse as err: notifier_err = dict(id=id, error_message=six.text_type(err)) self._notify_share_type_error(context, 'share_type.delete', notifier_err) msg = 'Target share type is still in use.' raise webob.exc.HTTPBadRequest(explanation=msg) except exception.NotFound as err: notifier_err = dict(id=id, error_message=six.text_type(err)) self._notify_share_type_error(context, 'share_type.delete', notifier_err) raise webob.exc.HTTPNotFound() return webob.Response(status_int=http_client.ACCEPTED)
def _create(self, req, body): """Creates a new share.""" context = req.environ['manila.context'] if not self.is_valid_body(body, 'share'): raise exc.HTTPUnprocessableEntity() share = body['share'] # NOTE(rushiagr): Manila API allows 'name' instead of 'display_name'. if share.get('name'): share['display_name'] = share.get('name') del share['name'] # NOTE(rushiagr): Manila API allows 'description' instead of # 'display_description'. if share.get('description'): share['display_description'] = share.get('description') del share['description'] size = share['size'] share_proto = share['share_proto'].upper() msg = (_LI("Create %(share_proto)s share of %(size)s GB") % {'share_proto': share_proto, 'size': size}) LOG.info(msg, context=context) availability_zone = share.get('availability_zone') if availability_zone: try: db.availability_zone_get(context, availability_zone) except exception.AvailabilityZoneNotFound as e: raise exc.HTTPNotFound(explanation=six.text_type(e)) kwargs = { 'availability_zone': availability_zone, 'metadata': share.get('metadata'), 'is_public': share.get('is_public', False), 'consistency_group_id': share.get('consistency_group_id') } snapshot_id = share.get('snapshot_id') if snapshot_id: snapshot = self.share_api.get_snapshot(context, snapshot_id) else: snapshot = None kwargs['snapshot'] = snapshot share_network_id = share.get('share_network_id') if snapshot: # Need to check that share_network_id from snapshot's # parents share equals to share_network_id from args. # If share_network_id is empty than update it with # share_network_id of parent share. parent_share = self.share_api.get(context, snapshot['share_id']) parent_share_net_id = parent_share['share_network_id'] if share_network_id: if share_network_id != parent_share_net_id: msg = "Share network ID should be the same as snapshot's" \ " parent share's or empty" raise exc.HTTPBadRequest(explanation=msg) elif parent_share_net_id: share_network_id = parent_share_net_id if share_network_id: try: self.share_api.get_share_network( context, share_network_id) except exception.ShareNetworkNotFound as e: raise exc.HTTPNotFound(explanation=six.text_type(e)) kwargs['share_network_id'] = share_network_id display_name = share.get('display_name') display_description = share.get('display_description') if 'share_type' in share and 'volume_type' in share: msg = 'Cannot specify both share_type and volume_type' raise exc.HTTPBadRequest(explanation=msg) req_share_type = share.get('share_type', share.get('volume_type')) if req_share_type: try: if not uuidutils.is_uuid_like(req_share_type): kwargs['share_type'] = \ share_types.get_share_type_by_name( context, req_share_type) else: kwargs['share_type'] = share_types.get_share_type( context, req_share_type) except exception.ShareTypeNotFound: msg = _("Share type not found.") raise exc.HTTPNotFound(explanation=msg) elif not snapshot: def_share_type = share_types.get_default_share_type() if def_share_type: kwargs['share_type'] = def_share_type new_share = self.share_api.create(context, share_proto, size, display_name, display_description, **kwargs) return self._view_builder.detail(req, dict(six.iteritems(new_share)))
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'] != 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']) 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(six.text_type(e)) 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': constants.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 _check_type(self, context, type_id): try: share_types.get_share_type(context, type_id) except exception.NotFound as ex: raise webob.exc.HTTPNotFound(explanation=ex.msg)
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 _create(self, req, body, check_create_share_from_snapshot_support=False, check_availability_zones_extra_spec=False): """Creates a new share.""" context = req.environ['manila.context'] if not self.is_valid_body(body, 'share'): raise exc.HTTPUnprocessableEntity() share = body['share'] share = common.validate_public_share_policy(context, share) # NOTE(rushiagr): Manila API allows 'name' instead of 'display_name'. if share.get('name'): share['display_name'] = share.get('name') del share['name'] # NOTE(rushiagr): Manila API allows 'description' instead of # 'display_description'. if share.get('description'): share['display_description'] = share.get('description') del share['description'] size = share['size'] share_proto = share['share_proto'].upper() msg = ("Create %(share_proto)s share of %(size)s GB" % {'share_proto': share_proto, 'size': size}) LOG.info(msg, context=context) availability_zone_id = None availability_zone = share.get('availability_zone') if availability_zone: try: availability_zone_id = db.availability_zone_get( context, availability_zone).id except exception.AvailabilityZoneNotFound as e: raise exc.HTTPNotFound(explanation=six.text_type(e)) share_group_id = share.get('share_group_id') if share_group_id: try: share_group = db.share_group_get(context, share_group_id) except exception.ShareGroupNotFound as e: raise exc.HTTPNotFound(explanation=six.text_type(e)) sg_az_id = share_group['availability_zone_id'] if availability_zone and availability_zone_id != sg_az_id: msg = _("Share cannot have AZ ('%(s_az)s') different than " "share group's one (%(sg_az)s).") % { 's_az': availability_zone_id, 'sg_az': sg_az_id} raise exception.InvalidInput(msg) availability_zone_id = sg_az_id kwargs = { 'availability_zone': availability_zone_id, 'metadata': share.get('metadata'), 'is_public': share.get('is_public', False), 'share_group_id': share_group_id, } snapshot_id = share.get('snapshot_id') if snapshot_id: snapshot = self.share_api.get_snapshot(context, snapshot_id) else: snapshot = None kwargs['snapshot_id'] = snapshot_id share_network_id = share.get('share_network_id') parent_share_type = {} if snapshot: # Need to check that share_network_id from snapshot's # parents share equals to share_network_id from args. # If share_network_id is empty then update it with # share_network_id of parent share. parent_share = self.share_api.get(context, snapshot['share_id']) parent_share_net_id = parent_share.instance['share_network_id'] parent_share_type = share_types.get_share_type( context, parent_share.instance['share_type_id']) if share_network_id: if share_network_id != parent_share_net_id: msg = ("Share network ID should be the same as snapshot's" " parent share's or empty") raise exc.HTTPBadRequest(explanation=msg) elif parent_share_net_id: share_network_id = parent_share_net_id # Verify that share can be created from a snapshot if (check_create_share_from_snapshot_support and not parent_share['create_share_from_snapshot_support']): msg = (_("A new share may not be created from snapshot '%s', " "because the snapshot's parent share does not have " "that capability.") % snapshot_id) LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg) if share_network_id: try: self.share_api.get_share_network( context, share_network_id) except exception.ShareNetworkNotFound as e: raise exc.HTTPNotFound(explanation=six.text_type(e)) kwargs['share_network_id'] = share_network_id display_name = share.get('display_name') display_description = share.get('display_description') if 'share_type' in share and 'volume_type' in share: msg = 'Cannot specify both share_type and volume_type' raise exc.HTTPBadRequest(explanation=msg) req_share_type = share.get('share_type', share.get('volume_type')) share_type = None if req_share_type: try: if not uuidutils.is_uuid_like(req_share_type): share_type = share_types.get_share_type_by_name( context, req_share_type) else: share_type = share_types.get_share_type( context, req_share_type) except exception.ShareTypeNotFound: msg = _("Share type not found.") raise exc.HTTPNotFound(explanation=msg) elif not snapshot: def_share_type = share_types.get_default_share_type() if def_share_type: share_type = def_share_type # Only use in create share feature. Create share from snapshot # and create share with share group features not # need this check. if (not share_network_id and not snapshot and not share_group_id and share_type and share_type.get('extra_specs') and (strutils.bool_from_string(share_type.get('extra_specs'). get('driver_handles_share_servers')))): msg = _('Share network must be set when the ' 'driver_handles_share_servers is true.') raise exc.HTTPBadRequest(explanation=msg) type_chosen = share_type or parent_share_type if type_chosen and check_availability_zones_extra_spec: type_azs = type_chosen.get( 'extra_specs', {}).get('availability_zones', '') type_azs = type_azs.split(',') if type_azs else [] kwargs['availability_zones'] = type_azs if (availability_zone and type_azs and availability_zone not in type_azs): msg = _("Share type %(type)s is not supported within the " "availability zone chosen %(az)s.") type_chosen = ( req_share_type or "%s (from source snapshot)" % ( parent_share_type.get('name') or parent_share_type.get('id')) ) payload = {'type': type_chosen, 'az': availability_zone} raise exc.HTTPBadRequest(explanation=msg % payload) if share_type: kwargs['share_type'] = share_type new_share = self.share_api.create(context, share_proto, size, display_name, display_description, **kwargs) return self._view_builder.detail(req, new_share)
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 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, name=None, description=None, share_type_ids=None, source_share_group_snapshot_id=None, share_network_id=None, share_group_type_id=None, availability_zone_id=None, availability_zone=None): """Create new share group.""" share_group_snapshot = None original_share_group = None # NOTE(gouthamr): share_server_id is inherited from the # parent share group if a share group snapshot is specified, # else, it will be set in the share manager. share_server_id = None if source_share_group_snapshot_id: share_group_snapshot = self.db.share_group_snapshot_get( context, source_share_group_snapshot_id) if share_group_snapshot['status'] != constants.STATUS_AVAILABLE: msg = (_("Share group snapshot status must be %s.") % constants.STATUS_AVAILABLE) raise exception.InvalidShareGroupSnapshot(reason=msg) original_share_group = self.db.share_group_get( context, share_group_snapshot['share_group_id']) share_type_ids = [ s['share_type_id'] for s in original_share_group['share_types'] ] share_network_id = original_share_group['share_network_id'] share_server_id = original_share_group['share_server_id'] availability_zone_id = original_share_group['availability_zone_id'] # 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) share_network = {} try: if share_network_id: share_network = 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 share_network: # Check if share network is active, otherwise raise a BadRequest api_common.check_share_network_is_active(share_network) if (driver_handles_share_servers and not (source_share_group_snapshot_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) try: share_group_type = self.db.share_group_type_get( context, share_group_type_id) except exception.ShareGroupTypeNotFound: msg = _("The specified share group type %s does not exist.") raise exception.InvalidInput(reason=msg % share_group_type_id) supported_share_types = set( [x['share_type_id'] for x in share_group_type['share_types']]) supported_share_type_objects = [ share_types.get_share_type(context, share_type_id) for share_type_id in supported_share_types ] if not set(share_type_ids or []) <= supported_share_types: msg = _("The specified share types must be a subset of the share " "types supported by the share group type.") raise exception.InvalidInput(reason=msg) # Grab share type AZs for scheduling share_types_of_new_group = (share_type_objects or supported_share_type_objects) stype_azs_of_new_group = [] stypes_unsupported_in_az = [] for stype in share_types_of_new_group: stype_azs = stype.get('extra_specs', {}).get('availability_zones', '') if stype_azs: stype_azs = stype_azs.split(',') stype_azs_of_new_group.extend(stype_azs) if availability_zone and availability_zone not in stype_azs: # If an AZ is requested, it must be supported by the AZs # configured in each of the share types requested stypes_unsupported_in_az.append( (stype['name'], stype['id'])) if stypes_unsupported_in_az: msg = _("Share group cannot be created since the following share " "types are not supported within the availability zone " "'%(az)s': (%(stypes)s)") payload = {'az': availability_zone, 'stypes': ''} for type_name, type_id in set(stypes_unsupported_in_az): if payload['stypes']: payload['stypes'] += ', ' type_name = '%s ' % (type_name or '') payload['stypes'] += type_name + '(ID: %s)' % type_id raise exception.InvalidInput(reason=msg % payload) try: reservations = QUOTAS.reserve(context, share_groups=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_groups' in overs: msg = ("Quota exceeded for '%(s_uid)s' user in '%(s_pid)s' " "project. (%(d_consumed)d of " "%(d_quota)d already consumed).") LOG.warning( msg, { 's_pid': context.project_id, 's_uid': context.user_id, 'd_consumed': _consumed('share_groups'), 'd_quota': quotas['share_groups'], }) raise exception.ShareGroupsLimitExceeded() options = { 'share_group_type_id': share_group_type_id, 'source_share_group_snapshot_id': source_share_group_snapshot_id, 'share_network_id': share_network_id, 'share_server_id': share_server_id, 'availability_zone_id': availability_zone_id, 'name': name, 'description': description, 'user_id': context.user_id, 'project_id': context.project_id, 'status': constants.STATUS_CREATING, 'share_types': share_type_ids or supported_share_types } if original_share_group: options['host'] = original_share_group['host'] share_group = {} try: share_group = self.db.share_group_create(context, options) if share_group_snapshot: members = self.db.share_group_snapshot_members_get_all( context, source_share_group_snapshot_id) for member in members: share_instance = self.db.share_instance_get( context, member['share_instance_id']) share_type = share_types.get_share_type( context, share_instance['share_type_id']) self.share_api.create( context, member['share_proto'], member['size'], None, None, share_group_id=share_group['id'], share_group_snapshot_member=member, share_type=share_type, availability_zone=availability_zone_id, share_network_id=share_network_id) except Exception: with excutils.save_and_reraise_exception(): if share_group: self.db.share_group_destroy(context.elevated(), share_group['id']) QUOTAS.rollback(context, reservations) try: QUOTAS.commit(context, reservations) except Exception: with excutils.save_and_reraise_exception(): QUOTAS.rollback(context, reservations) request_spec = {'share_group_id': share_group['id']} request_spec.update(options) request_spec['availability_zones'] = set(stype_azs_of_new_group) request_spec['share_types'] = share_type_objects request_spec['resource_type'] = share_group_type if share_group_snapshot and original_share_group: self.share_rpcapi.create_share_group(context, share_group, original_share_group['host']) else: self.scheduler_rpcapi.create_share_group( context, share_group_id=share_group['id'], request_spec=request_spec, filter_properties={}) return share_group