def post(self, allocation): """Create a new allocation. :param allocation: an allocation within the request body. """ context = pecan.request.context cdict = context.to_policy_values() policy.authorize('baremetal:allocation:create', cdict, cdict) if allocation.node_uuid is not wtypes.Unset: msg = _("Cannot set node_uuid when creating an allocation") raise exception.Invalid(msg) if (allocation.name and not api_utils.is_valid_logical_name(allocation.name)): msg = _("Cannot create allocation with invalid name " "'%(name)s'") % { 'name': allocation.name } raise exception.Invalid(msg) if allocation.traits: for trait in allocation.traits: api_utils.validate_trait(trait) if allocation.candidate_nodes: # Convert nodes from names to UUIDs and check their validity try: converted = pecan.request.dbapi.check_node_list( allocation.candidate_nodes) except exception.NodeNotFound as exc: exc.code = http_client.BAD_REQUEST raise else: # Make sure we keep the ordering of candidate nodes. allocation.candidate_nodes = [ converted[ident] for ident in allocation.candidate_nodes ] all_dict = allocation.as_dict() # NOTE(yuriyz): UUID is mandatory for notifications payload if not all_dict.get('uuid'): all_dict['uuid'] = uuidutils.generate_uuid() new_allocation = objects.Allocation(context, **all_dict) topic = pecan.request.rpcapi.get_random_topic() notify.emit_start_notification(context, new_allocation, 'create') with notify.handle_error_notification(context, new_allocation, 'create'): new_allocation = pecan.request.rpcapi.create_allocation( context, new_allocation, topic) notify.emit_end_notification(context, new_allocation, 'create') # Set the HTTP Location Header pecan.response.location = link.build_url('allocations', new_allocation.uuid) return Allocation.convert_with_links(new_allocation)
def post(self, allocation): """Create a new allocation. :param allocation: an allocation within the request body. """ context = pecan.request.context cdict = context.to_policy_values() policy.authorize('baremetal:allocation:create', cdict, cdict) if allocation.node_uuid is not wtypes.Unset: msg = _("Cannot set node_uuid when creating an allocation") raise exception.Invalid(msg) if (allocation.name and not api_utils.is_valid_logical_name(allocation.name)): msg = _("Cannot create allocation with invalid name " "'%(name)s'") % {'name': allocation.name} raise exception.Invalid(msg) if allocation.traits: for trait in allocation.traits: api_utils.validate_trait(trait) if allocation.candidate_nodes: # Convert nodes from names to UUIDs and check their validity try: converted = pecan.request.dbapi.check_node_list( allocation.candidate_nodes) except exception.NodeNotFound as exc: exc.code = http_client.BAD_REQUEST raise else: # Make sure we keep the ordering of candidate nodes. allocation.candidate_nodes = [ converted[ident] for ident in allocation.candidate_nodes] all_dict = allocation.as_dict() # NOTE(yuriyz): UUID is mandatory for notifications payload if not all_dict.get('uuid'): all_dict['uuid'] = uuidutils.generate_uuid() new_allocation = objects.Allocation(context, **all_dict) topic = pecan.request.rpcapi.get_random_topic() notify.emit_start_notification(context, new_allocation, 'create') with notify.handle_error_notification(context, new_allocation, 'create'): new_allocation = pecan.request.rpcapi.create_allocation( context, new_allocation, topic) notify.emit_end_notification(context, new_allocation, 'create') # Set the HTTP Location Header pecan.response.location = link.build_url('allocations', new_allocation.uuid) return Allocation.convert_with_links(new_allocation)
def test_validate_trait(self): utils.validate_trait(os_traits.HW_CPU_X86_AVX2) utils.validate_trait("CUSTOM_1") utils.validate_trait("CUSTOM_TRAIT_GOLD") self.assertRaises(wsme.exc.ClientSideError, utils.validate_trait, "A" * 256) self.assertRaises(wsme.exc.ClientSideError, utils.validate_trait, "CuSTOM_1") self.assertRaises(wsme.exc.ClientSideError, utils.validate_trait, "") self.assertRaises(wsme.exc.ClientSideError, utils.validate_trait, "CUSTOM_bob") self.assertRaises(wsme.exc.ClientSideError, utils.validate_trait, "CUSTOM_1-BOB") self.assertRaises(wsme.exc.ClientSideError, utils.validate_trait, "aCUSTOM_1a") large = "CUSTOM_" + ("1" * 248) self.assertEqual(255, len(large)) utils.validate_trait(large) self.assertRaises(wsme.exc.ClientSideError, utils.validate_trait, large + "1") # Check custom error prefix. self.assertRaisesRegex(wsme.exc.ClientSideError, "spongebob", utils.validate_trait, "invalid", "spongebob")
def validate(value): if value is None: return # The name is mandatory, but the 'mandatory' attribute support in # wtypes.wsattr allows None. if value.name is None: err = _("Deploy template name cannot be None") raise exception.InvalidDeployTemplate(err=err) # The name must also be a valid trait. api_utils.validate_trait( value.name, error_prefix=_("Deploy template name must be a valid trait")) # There must be at least one step. if not value.steps: err = _("No deploy steps specified. A deploy template must have " "at least one deploy step.") raise exception.InvalidDeployTemplate(err=err) # TODO(mgoddard): Determine the consequences of allowing duplicate # steps. # * What if one step has zero priority and another non-zero? # * What if a step that is enabled by default is included in a # template? Do we override the default or add a second invocation? # Check for duplicate steps. Each interface/step combination can be # specified at most once. counter = collections.Counter( (step.interface, step.step) for step in value.steps) duplicates = {key for key, count in counter.items() if count > 1} if duplicates: duplicates = { "interface: %s, step: %s" % (interface, step) for interface, step in duplicates } err = _("Duplicate deploy steps. A deploy template cannot have " "multiple deploy steps with the same interface and step. " "Duplicates: %s") % "; ".join(duplicates) raise exception.InvalidDeployTemplate(err=err) return value
def test_validate_trait(self): utils.validate_trait(os_traits.HW_CPU_X86_AVX2) utils.validate_trait("CUSTOM_1") utils.validate_trait("CUSTOM_TRAIT_GOLD") self.assertRaises(wsme.exc.ClientSideError, utils.validate_trait, "A" * 256) self.assertRaises(wsme.exc.ClientSideError, utils.validate_trait, "CuSTOM_1") self.assertRaises(wsme.exc.ClientSideError, utils.validate_trait, "") self.assertRaises(wsme.exc.ClientSideError, utils.validate_trait, "CUSTOM_bob") self.assertRaises(wsme.exc.ClientSideError, utils.validate_trait, "CUSTOM_1-BOB") self.assertRaises(wsme.exc.ClientSideError, utils.validate_trait, "aCUSTOM_1a") large = "CUSTOM_" + ("1" * 248) self.assertEqual(255, len(large)) utils.validate_trait(large) self.assertRaises(wsme.exc.ClientSideError, utils.validate_trait, large + "1")
def post(self, allocation): """Create a new allocation. :param allocation: an allocation within the request body. """ context = api.request.context allocation = self._authorize_create_allocation(allocation) if (allocation.name and not api_utils.is_valid_logical_name(allocation.name)): msg = _("Cannot create allocation with invalid name " "'%(name)s'") % { 'name': allocation.name } raise exception.Invalid(msg) if allocation.traits: for trait in allocation.traits: api_utils.validate_trait(trait) node = None if allocation.node is not atypes.Unset: if api_utils.allow_allocation_backfill(): try: node = api_utils.get_rpc_node(allocation.node) except exception.NodeNotFound as exc: exc.code = http_client.BAD_REQUEST raise else: msg = _("Cannot set node when creating an allocation " "in this API version") raise exception.Invalid(msg) if not allocation.resource_class: if node: allocation.resource_class = node.resource_class else: msg = _("The resource_class field is mandatory when not " "backfilling") raise exception.Invalid(msg) if allocation.candidate_nodes: # Convert nodes from names to UUIDs and check their validity try: converted = api.request.dbapi.check_node_list( allocation.candidate_nodes) except exception.NodeNotFound as exc: exc.code = http_client.BAD_REQUEST raise else: # Make sure we keep the ordering of candidate nodes. allocation.candidate_nodes = [ converted[ident] for ident in allocation.candidate_nodes ] all_dict = allocation.as_dict() # NOTE(yuriyz): UUID is mandatory for notifications payload if not all_dict.get('uuid'): if node and node.instance_uuid: # When backfilling without UUID requested, assume that the # target instance_uuid is the desired UUID all_dict['uuid'] = node.instance_uuid else: all_dict['uuid'] = uuidutils.generate_uuid() new_allocation = objects.Allocation(context, **all_dict) if node: new_allocation.node_id = node.id topic = api.request.rpcapi.get_topic_for(node) else: topic = api.request.rpcapi.get_random_topic() notify.emit_start_notification(context, new_allocation, 'create') with notify.handle_error_notification(context, new_allocation, 'create'): new_allocation = api.request.rpcapi.create_allocation( context, new_allocation, topic) notify.emit_end_notification(context, new_allocation, 'create') # Set the HTTP Location Header api.response.location = link.build_url('allocations', new_allocation.uuid) return Allocation.convert_with_links(new_allocation)