Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
 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")
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
 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")
Ejemplo n.º 6
0
    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)