Exemple #1
0
 def test_trait_create_duplicated_trait(self):
     trait = trait_obj.Trait(self.ctx)
     trait.name = 'CUSTOM_TRAIT_A'
     trait.create()
     tmp_trait = trait_obj.Trait.get_by_name(self.ctx, 'CUSTOM_TRAIT_A')
     self.assertEqual('CUSTOM_TRAIT_A', tmp_trait.name)
     duplicated_trait = trait_obj.Trait(self.ctx)
     duplicated_trait.name = 'CUSTOM_TRAIT_A'
     self.assertRaises(exception.TraitExists, duplicated_trait.create)
Exemple #2
0
def put_trait(req):
    context = req.environ['placement.context']
    context.can(policies.TRAITS_UPDATE)
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]
    name = util.wsgi_path_item(req.environ, 'name')

    try:
        jsonschema.validate(name, schema.CUSTOM_TRAIT)
    except jsonschema.ValidationError:
        raise webob.exc.HTTPBadRequest(
            'The trait is invalid. A valid trait must be no longer than '
            '255 characters, start with the prefix "CUSTOM_" and use '
            'following characters: "A"-"Z", "0"-"9" and "_"')

    trait = trait_obj.Trait(context)
    trait.name = name

    try:
        trait.create()
        req.response.status = 201
    except exception.TraitExists:
        # Get the trait that already exists to get last-modified time.
        if want_version.matches((1, 15)):
            trait = trait_obj.Trait.get_by_name(context, name)
        req.response.status = 204

    req.response.content_type = None
    req.response.location = util.trait_url(req.environ, trait)
    if want_version.matches((1, 15)):
        req.response.last_modified = trait.created_at
        req.response.cache_control = 'no-cache'
    return req.response
Exemple #3
0
 def test_trait_destroy(self):
     t = trait_obj.Trait(self.ctx)
     t.name = 'CUSTOM_TRAIT_A'
     t.create()
     t = trait_obj.Trait.get_by_name(self.ctx, 'CUSTOM_TRAIT_A')
     self.assertEqual(t.name, 'CUSTOM_TRAIT_A')
     t.destroy()
     self.assertRaises(exception.TraitNotFound, trait_obj.Trait.get_by_name,
                       self.ctx, 'CUSTOM_TRAIT_A')
Exemple #4
0
    def test_traits_get_all(self):
        trait_names = ['CUSTOM_TRAIT_A', 'CUSTOM_TRAIT_B', 'CUSTOM_TRAIT_C']
        for name in trait_names:
            t = trait_obj.Trait(self.ctx)
            t.name = name
            t.create()

        self._assert_traits_in(trait_names,
                               trait_obj.get_all(self.ctx))
Exemple #5
0
    def test_traits_get_all_with_prefix_filter(self):
        trait_names = ['CUSTOM_TRAIT_A', 'CUSTOM_TRAIT_B', 'CUSTOM_TRAIT_C']
        for name in trait_names:
            t = trait_obj.Trait(self.ctx)
            t.name = name
            t.create()

        traits = trait_obj.get_all(self.ctx, filters={'prefix': 'CUSTOM'})
        self._assert_traits(
            ['CUSTOM_TRAIT_A', 'CUSTOM_TRAIT_B', 'CUSTOM_TRAIT_C'],
            traits)
Exemple #6
0
def set_traits(rp, *traits):
    tlist = []
    for tname in traits:
        try:
            trait = trait_obj.Trait.get_by_name(rp._context, tname)
        except exception.TraitNotFound:
            trait = trait_obj.Trait(rp._context, name=tname)
            trait.create()
        tlist.append(trait)
    rp.set_traits(tlist)
    return tlist
Exemple #7
0
    def test_traits_get_all_with_associated_false(self):
        rp1 = self._create_provider('fake_resource_provider1')
        rp2 = self._create_provider('fake_resource_provider2')
        trait_names = ['CUSTOM_TRAIT_A', 'CUSTOM_TRAIT_B', 'CUSTOM_TRAIT_C']
        for name in trait_names:
            t = trait_obj.Trait(self.ctx)
            t.name = name
            t.create()

        associated_traits = trait_obj.get_all(
            self.ctx,
            filters={'name_in': ['CUSTOM_TRAIT_A', 'CUSTOM_TRAIT_B']})
        rp1.set_traits(associated_traits)
        rp2.set_traits(associated_traits)
        self._assert_traits_in(
            ['CUSTOM_TRAIT_C'],
            trait_obj.get_all(self.ctx, filters={'associated': False}))
Exemple #8
0
def put_trait(req):
    context = req.environ['placement.context']
    context.can(policies.TRAITS_UPDATE)
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]
    name = util.wsgi_path_item(req.environ, 'name')

    try:
        jsonschema.validate(name, schema.CUSTOM_TRAIT)
    except jsonschema.ValidationError:
        raise webob.exc.HTTPBadRequest(
            'The trait is invalid. A valid trait must be no longer than '
            '255 characters, start with the prefix "CUSTOM_" and use '
            'following characters: "A"-"Z", "0"-"9" and "_"')

    status = 204
    try:
        trait = trait_obj.Trait.get_by_name(context, name)
    except exception.TraitNotFound:
        try:
            trait = trait_obj.Trait(context, name=name)
            trait.create()
            status = 201
        except exception.TraitExists:
            # Something just created the trait
            pass

    req.response.status = status
    req.response.content_type = None
    req.response.location = util.trait_url(req.environ, trait)
    if want_version.matches((1, 15)):
        # If the TraitExists exception was hit above, created_at is None
        # so fall back to now for the last modified header.
        last_modified = (trait.created_at
                         or timeutils.utcnow(with_timezone=True))
        req.response.last_modified = last_modified
        req.response.cache_control = 'no-cache'
    return req.response
def _build_provider_summaries(context, usages, prov_traits):
    """Given a list of dicts of usage information and a map of providers to
    their associated string traits, returns a dict, keyed by resource provider
    ID, of ProviderSummary objects.

    :param context: placement.context.RequestContext object
    :param usages: A list of dicts with the following format:

        {
            'resource_provider_id': <internal resource provider ID>,
            'resource_provider_uuid': <UUID>,
            'resource_class_id': <internal resource class ID>,
            'total': integer,
            'reserved': integer,
            'allocation_ratio': float,
        }
    :param prov_traits: A dict, keyed by internal resource provider ID, of
                        string trait names associated with that provider
    """
    # Before we go creating provider summary objects, first grab all the
    # provider information (including root, parent and UUID information) for
    # all providers involved in our operation
    rp_ids = set(usage['resource_provider_id'] for usage in usages)
    provider_ids = rp_obj.provider_ids_from_rp_ids(context, rp_ids)

    # Build up a dict, keyed by internal resource provider ID, of
    # ProviderSummary objects containing one or more ProviderSummaryResource
    # objects representing the resources the provider has inventory for.
    summaries = {}
    for usage in usages:
        rp_id = usage['resource_provider_id']
        summary = summaries.get(rp_id)
        if not summary:
            pids = provider_ids[rp_id]
            summary = ProviderSummary(
                resource_provider=rp_obj.ResourceProvider(
                    context, id=pids.id, uuid=pids.uuid,
                    root_provider_uuid=pids.root_uuid,
                    parent_provider_uuid=pids.parent_uuid),
                resources=[],
            )
            summaries[rp_id] = summary

        traits = prov_traits[rp_id]
        summary.traits = [trait_obj.Trait(context, name=tname)
                          for tname in traits]

        rc_id = usage['resource_class_id']
        if rc_id is None:
            # NOTE(tetsuro): This provider doesn't have any inventory itself.
            # But we include this provider in summaries since another
            # provider in the same tree will be in the "allocation_request".
            # Let's skip the following and leave "ProviderSummary.resources"
            # field empty.
            continue
        # NOTE(jaypipes): usage['used'] may be None due to the LEFT JOIN of
        # the usages subquery, so we coerce NULL values to 0 here. It may
        # also be a Decimal, as that's the type that mysql tends to return
        # when func.sum is used in a query. We need an int, otherwise later
        # JSON serialization will not work.
        used = int(usage['used'] or 0)
        allocation_ratio = usage['allocation_ratio']
        cap = int((usage['total'] - usage['reserved']) * allocation_ratio)
        rc_name = rc_cache.RC_CACHE.string_from_id(rc_id)
        rpsr = ProviderSummaryResource(
            resource_class=rc_name,
            capacity=cap,
            used=used,
            max_unit=usage['max_unit'],
        )
        summary.resources.append(rpsr)
    return summaries
Exemple #10
0
 def test_trait_destroy_with_standard_trait(self):
     t = trait_obj.Trait(self.ctx)
     t.id = 1
     t.name = 'HW_CPU_X86_AVX'
     self.assertRaises(exception.TraitCannotDeleteStandard, t.destroy)
Exemple #11
0
 def test_trait_get(self):
     t = trait_obj.Trait(self.ctx)
     t.name = 'CUSTOM_TRAIT_A'
     t.create()
     t = trait_obj.Trait.get_by_name(self.ctx, 'CUSTOM_TRAIT_A')
     self.assertEqual(t.name, 'CUSTOM_TRAIT_A')
Exemple #12
0
 def test_trait_create_without_name_set(self):
     t = trait_obj.Trait(self.ctx)
     self.assertRaises(exception.ObjectActionError, t.create)
Exemple #13
0
 def test_trait_create_with_id_set(self):
     t = trait_obj.Trait(self.ctx)
     t.name = 'CUSTOM_TRAIT_A'
     t.id = 1
     self.assertRaises(exception.ObjectActionError, t.create)
Exemple #14
0
 def test_trait_create(self):
     t = trait_obj.Trait(self.ctx)
     t.name = 'CUSTOM_TRAIT_A'
     t.create()
     self.assertIsNotNone(t.id)
     self.assertEqual(t.name, 'CUSTOM_TRAIT_A')
Exemple #15
0
def _build_provider_summaries(context, usages, prov_traits):
    """Given a list of dicts of usage information and a map of providers to
    their associated string traits, returns a dict, keyed by resource provider
    UUID, of ProviderSummary objects.

    :param context: placement.context.RequestContext object
    :param usages: A list of dicts with the following format:

        {
            "resource_provider_uuid": <UUID>,
            "resource_class_name": <resource class name>,
            "total": integer,
            "reserved": integer,
            "allocation_ratio": float,
            "used": integer,
        }
    :param prov_traits: A dict, keyed by resource provider UUID, of
                        string trait names associated with that provider
    """
    # Before we go creating provider summary objects, first grab all the
    # provider information (including root, parent and UUID information) for
    # all providers involved in our operation
    rp_uuids = list(set(usage["resource_provider_uuid"] for usage in usages))
    provider_dict = res_ctx.provider_uuids_from_rp_uuids(context, rp_uuids)
    provider_uuids = list(provider_dict.keys())

    # Build up a dict, keyed by resource provider UUID, of ProviderSummary
    # objects containing one or more ProviderSummaryResource objects
    # representing the resources the provider has inventory for.
    summaries = {}
    for usage in usages:
        rp_uuid = usage["resource_provider_uuid"]
        summary = summaries.get(rp_uuid)
        if not summary:
            puuids = provider_dict[rp_uuid]
            summary = ProviderSummary(
                    resource_provider=rp_obj.ResourceProvider(
                        context, uuid=puuids.uuid,
                        root_provider_uuid=puuids.root_uuid,
                        parent_provider_uuid=puuids.parent_uuid),
                resources=[],
            )
            summaries[rp_uuid] = summary

        traits = prov_traits[rp_uuid]
        summary.traits = [trait_obj.Trait(context, name=tname)
                          for tname in traits]

        rc_name = usage['resource_class_name']
        if rc_name is None:
            # NOTE(tetsuro): This provider doesn't have any inventory itself.
            # But we include this provider in summaries since another
            # provider in the same tree will be in the "allocation_request".
            # Let's skip the following and leave "ProviderSummary.resources"
            # field empty.
            continue
        used = int(usage["used"] or 0)
        allocation_ratio = usage["allocation_ratio"]
        cap = int((usage["total"] - usage["reserved"]) * allocation_ratio)
        rpsr = ProviderSummaryResource(
            resource_class=rc_name,
            capacity=cap,
            used=used,
            max_unit=usage["max_unit"],
        )
        summary.resources.append(rpsr)
    return summaries