Ejemplo n.º 1
0
def create_resource_class(req):
    """POST to create a resource class.

    On success return a 201 response with an empty body and a location
    header pointing to the newly created resource class.
    """
    context = req.environ['placement.context']
    data = util.extract_json(req.body, POST_RC_SCHEMA_V1_2)

    try:
        rc = rp_obj.ResourceClass(context, name=data['name'])
        rc.create()
    except exception.ResourceClassExists:
        raise webob.exc.HTTPConflict(
            _('Conflicting resource class already exists: %(name)s') %
            {'name': data['name']})
    except exception.MaxDBRetriesExceeded:
        raise webob.exc.HTTPConflict(
            _('Max retries of DB transaction exceeded attempting '
              'to create resource class: %(name)s, please'
              'try again.') % {'name': data['name']})

    req.response.location = util.resource_class_url(req.environ, rc)
    req.response.status = 201
    req.response.content_type = None
    return req.response
Ejemplo n.º 2
0
def update_resource_class(req):
    """PUT to create or validate the existence of single resource class.

    On a successful create return 201. Return 204 if the class already
    exists. If the resource class is not a custom resource class, return
    a 400. 409 might be a better choice, but 400 aligns with previous code.
    """
    name = util.wsgi_path_item(req.environ, 'name')
    context = req.environ['placement.context']

    # Use JSON validation to validation resource class name.
    util.extract_json('{"name": "%s"}' % name, PUT_RC_SCHEMA_V1_2)

    status = 204
    try:
        rc = rp_obj.ResourceClass.get_by_name(context, name)
    except exception.NotFound:
        try:
            rc = rp_obj.ResourceClass(context, name=name)
            rc.create()
            status = 201
        # We will not see ResourceClassCannotUpdateStandard because
        # that was already caught when validating the {name}.
        except exception.ResourceClassExists:
            # Someone just now created the class, so stick with 204
            pass

    req.response.status = status
    req.response.content_type = None
    req.response.location = util.resource_class_url(req.environ, rc)
    return req.response
Ejemplo n.º 3
0
 def test_cannot_create_requires_name(self):
     rc = resource_provider.ResourceClass(self.context)
     exc = self.assertRaises(exception.ObjectActionError, rc.create)
     self.assertIn('name is required', str(exc))
Ejemplo n.º 4
0
 def test_cannot_create_with_id(self):
     rc = resource_provider.ResourceClass(self.context,
                                          id=1,
                                          name='CUSTOM_IRON_NFV')
     exc = self.assertRaises(exception.ObjectActionError, rc.create)
     self.assertIn('already created', str(exc))
Ejemplo n.º 5
0
 def setUp(self):
     super(TestPlacementURLs, self).setUp()
     self.resource_provider = rp_obj.ResourceProvider(
         name=uuidsentinel.rp_name, uuid=uuidsentinel.rp_uuid)
     self.resource_class = rp_obj.ResourceClass(
         name='CUSTOM_BAREMETAL_GOLD', id=1000)
Ejemplo n.º 6
0
    def test_local_with_shared_custom_resource(self):
        """Create some resource providers that can satisfy the request for
        resources with local VCPU and MEMORY_MB but rely on a shared resource
        provider to satisfy a custom resource requirement and verify that the
        allocation requests returned by AllocationCandidates have the custom
        resource served up by the shared custom resource provider and
        VCPU/MEMORY_MB by the compute node providers
        """
        # The aggregate that will be associated to everything...
        agg_uuid = uuids.agg

        # Create two compute node providers with VCPU, RAM and NO local
        # CUSTOM_MAGIC resources, associated with the aggregate.
        for name in ('cn1', 'cn2'):
            cn = self._create_provider(name, agg_uuid)
            _add_inventory(cn,
                           fields.ResourceClass.VCPU,
                           24,
                           allocation_ratio=16.0)
            _add_inventory(cn,
                           fields.ResourceClass.MEMORY_MB,
                           1024,
                           min_unit=64,
                           allocation_ratio=1.5)

        # Create a custom resource called MAGIC
        magic_rc = rp_obj.ResourceClass(
            self.ctx,
            name='CUSTOM_MAGIC',
        )
        magic_rc.create()

        # Create the shared provider that serves CUSTOM_MAGIC, associated with
        # the same aggregate
        magic_p = self._create_provider('shared custom resource provider',
                                        agg_uuid)
        _add_inventory(magic_p,
                       magic_rc.name,
                       2048,
                       reserved=1024,
                       min_unit=10)

        # Mark the magic provider as having inventory shared among any provider
        # associated via aggregate
        _set_traits(magic_p, "MISC_SHARES_VIA_AGGREGATE")

        # The resources we will request
        requested_resources = {
            fields.ResourceClass.VCPU: 1,
            fields.ResourceClass.MEMORY_MB: 64,
            magic_rc.name: 512,
        }

        alloc_cands = self._get_allocation_candidates(
            resources=requested_resources)

        # Verify the allocation requests that are returned. There should be 2
        # allocation requests, one for each compute node, containing 3
        # resources in each allocation request, one each for VCPU, RAM, and
        # MAGIC. The amounts of the requests should correspond to the requested
        # resource amounts in the filter:resources dict passed to
        # AllocationCandidates.get_by_filters(). The providers for VCPU and
        # MEMORY_MB should be the compute nodes while the provider for the
        # MAGIC should be the shared custom resource provider.
        expected = [
            [('cn1', fields.ResourceClass.VCPU, 1),
             ('cn1', fields.ResourceClass.MEMORY_MB, 64),
             ('shared custom resource provider', magic_rc.name, 512)],
            [('cn2', fields.ResourceClass.VCPU, 1),
             ('cn2', fields.ResourceClass.MEMORY_MB, 64),
             ('shared custom resource provider', magic_rc.name, 512)],
        ]
        self._validate_allocation_requests(expected, alloc_cands)
Ejemplo n.º 7
0
    def test_get_provider_ids_matching_all(self):
        # These RPs are named based on whether we expect them to be 'incl'uded
        # or 'excl'uded in the result.

        # No inventory records.  This one should never show up in a result.
        self._create_provider('no_inventory')

        # Inventory of adequate CPU and memory, no allocations against it.
        excl_big_cm_noalloc = self._create_provider('big_cm_noalloc')
        _add_inventory(excl_big_cm_noalloc, fields.ResourceClass.VCPU, 15)
        _add_inventory(excl_big_cm_noalloc, fields.ResourceClass.MEMORY_MB,
                       4096, max_unit=2048)

        # Adequate inventory, no allocations against it.
        incl_biginv_noalloc = self._create_provider('biginv_noalloc')
        _add_inventory(incl_biginv_noalloc, fields.ResourceClass.VCPU, 15)
        _add_inventory(incl_biginv_noalloc, fields.ResourceClass.MEMORY_MB,
                       4096, max_unit=2048)
        _add_inventory(incl_biginv_noalloc, fields.ResourceClass.DISK_GB, 2000)

        # No allocations, but inventory unusable.  Try to hit all the possible
        # reasons for exclusion.
        # VCPU min_unit too high
        excl_badinv_min_unit = self._create_provider('badinv_min_unit')
        _add_inventory(excl_badinv_min_unit, fields.ResourceClass.VCPU, 12,
                       min_unit=6)
        _add_inventory(excl_badinv_min_unit, fields.ResourceClass.MEMORY_MB,
                       4096, max_unit=2048)
        _add_inventory(excl_badinv_min_unit, fields.ResourceClass.DISK_GB,
                       2000)
        # MEMORY_MB max_unit too low
        excl_badinv_max_unit = self._create_provider('badinv_max_unit')
        _add_inventory(excl_badinv_max_unit, fields.ResourceClass.VCPU, 15)
        _add_inventory(excl_badinv_max_unit, fields.ResourceClass.MEMORY_MB,
                       4096, max_unit=512)
        _add_inventory(excl_badinv_max_unit, fields.ResourceClass.DISK_GB,
                       2000)
        # DISK_GB unsuitable step_size
        excl_badinv_step_size = self._create_provider('badinv_step_size')
        _add_inventory(excl_badinv_step_size, fields.ResourceClass.VCPU, 15)
        _add_inventory(excl_badinv_step_size, fields.ResourceClass.MEMORY_MB,
                       4096, max_unit=2048)
        _add_inventory(excl_badinv_step_size, fields.ResourceClass.DISK_GB,
                       2000, step_size=7)
        # Not enough total VCPU
        excl_badinv_total = self._create_provider('badinv_total')
        _add_inventory(excl_badinv_total, fields.ResourceClass.VCPU, 4)
        _add_inventory(excl_badinv_total, fields.ResourceClass.MEMORY_MB,
                       4096, max_unit=2048)
        _add_inventory(excl_badinv_total, fields.ResourceClass.DISK_GB, 2000)
        # Too much reserved MEMORY_MB
        excl_badinv_reserved = self._create_provider('badinv_reserved')
        _add_inventory(excl_badinv_reserved, fields.ResourceClass.VCPU, 15)
        _add_inventory(excl_badinv_reserved, fields.ResourceClass.MEMORY_MB,
                       4096, max_unit=2048, reserved=3500)
        _add_inventory(excl_badinv_reserved, fields.ResourceClass.DISK_GB,
                       2000)
        # DISK_GB allocation ratio blows it up
        excl_badinv_alloc_ratio = self._create_provider('badinv_alloc_ratio')
        _add_inventory(excl_badinv_alloc_ratio, fields.ResourceClass.VCPU, 15)
        _add_inventory(excl_badinv_alloc_ratio, fields.ResourceClass.MEMORY_MB,
                       4096, max_unit=2048)
        _add_inventory(excl_badinv_alloc_ratio, fields.ResourceClass.DISK_GB,
                       2000, allocation_ratio=0.5)

        # Inventory consumed in one RC, but available in the others
        excl_1invunavail = self._create_provider('1invunavail')
        _add_inventory(excl_1invunavail, fields.ResourceClass.VCPU, 10)
        _allocate_from_provider(excl_1invunavail, fields.ResourceClass.VCPU, 7)
        _add_inventory(excl_1invunavail, fields.ResourceClass.MEMORY_MB, 4096)
        _allocate_from_provider(excl_1invunavail,
                                fields.ResourceClass.MEMORY_MB, 1024)
        _add_inventory(excl_1invunavail, fields.ResourceClass.DISK_GB, 2000)
        _allocate_from_provider(excl_1invunavail,
                                fields.ResourceClass.DISK_GB, 400)

        # Inventory all consumed
        excl_allused = self._create_provider('allused')
        _add_inventory(excl_allused, fields.ResourceClass.VCPU, 10)
        _allocate_from_provider(excl_allused, fields.ResourceClass.VCPU, 7)
        _add_inventory(excl_allused, fields.ResourceClass.MEMORY_MB, 4000)
        _allocate_from_provider(excl_allused,
                                fields.ResourceClass.MEMORY_MB, 1500)
        _allocate_from_provider(excl_allused,
                                fields.ResourceClass.MEMORY_MB, 2000)
        _add_inventory(excl_allused, fields.ResourceClass.DISK_GB, 1500)
        _allocate_from_provider(excl_allused, fields.ResourceClass.DISK_GB, 1)

        # Inventory available in requested classes, but unavailable in others
        incl_extra_full = self._create_provider('extra_full')
        _add_inventory(incl_extra_full, fields.ResourceClass.VCPU, 20)
        _allocate_from_provider(incl_extra_full, fields.ResourceClass.VCPU, 15)
        _add_inventory(incl_extra_full, fields.ResourceClass.MEMORY_MB, 4096)
        _allocate_from_provider(incl_extra_full,
                                fields.ResourceClass.MEMORY_MB, 1024)
        _add_inventory(incl_extra_full, fields.ResourceClass.DISK_GB, 2000)
        _allocate_from_provider(incl_extra_full, fields.ResourceClass.DISK_GB,
                                400)
        _add_inventory(incl_extra_full, fields.ResourceClass.PCI_DEVICE, 4)
        _allocate_from_provider(incl_extra_full,
                                fields.ResourceClass.PCI_DEVICE, 1)
        _allocate_from_provider(incl_extra_full,
                                fields.ResourceClass.PCI_DEVICE, 3)

        # Inventory available in a unrequested classes, not in requested ones
        excl_extra_avail = self._create_provider('extra_avail')
        # Incompatible step size
        _add_inventory(excl_extra_avail, fields.ResourceClass.VCPU, 10,
                       step_size=3)
        # Not enough left after reserved + used
        _add_inventory(excl_extra_avail, fields.ResourceClass.MEMORY_MB, 4096,
                       max_unit=2048, reserved=2048)
        _allocate_from_provider(excl_extra_avail,
                                fields.ResourceClass.MEMORY_MB, 1040)
        # Allocation ratio math
        _add_inventory(excl_extra_avail, fields.ResourceClass.DISK_GB, 2000,
                       allocation_ratio=0.5)
        _add_inventory(excl_extra_avail, fields.ResourceClass.IPV4_ADDRESS, 48)
        custom_special = rp_obj.ResourceClass(self.ctx, name='CUSTOM_SPECIAL')
        custom_special.create()
        _add_inventory(excl_extra_avail, 'CUSTOM_SPECIAL', 100)
        _allocate_from_provider(excl_extra_avail, 'CUSTOM_SPECIAL', 99)

        resources = {
            fields.ResourceClass.STANDARD.index(fields.ResourceClass.VCPU): 5,
            fields.ResourceClass.STANDARD.index(
                fields.ResourceClass.MEMORY_MB): 1024,
            fields.ResourceClass.STANDARD.index(
                fields.ResourceClass.DISK_GB): 1500
        }

        # Run it!
        res = rp_obj._get_provider_ids_matching_all(self.ctx, resources, {})

        # We should get all the incl_* RPs
        expected = [incl_biginv_noalloc, incl_extra_full]

        self.assertEqual(set(rp.id for rp in expected), set(res))

        # Now request that the providers must have a set of required traits and
        # that this results in no results returned, since we haven't yet
        # associated any traits with the providers
        avx2_t = rp_obj.Trait.get_by_name(self.ctx, os_traits.HW_CPU_X86_AVX2)
        # _get_provider_ids_matching_all()'s required_traits argument is a map,
        # keyed by trait name, of the trait internal ID
        req_traits = {os_traits.HW_CPU_X86_AVX2: avx2_t.id}
        res = rp_obj._get_provider_ids_matching_all(self.ctx, resources,
                                                    req_traits)

        self.assertEqual([], res)

        # OK, now add the trait to one of the providers and verify that
        # provider now shows up in our results
        incl_biginv_noalloc.set_traits([avx2_t])
        res = rp_obj._get_provider_ids_matching_all(self.ctx, resources,
                                                    req_traits)

        self.assertEqual([incl_biginv_noalloc.id], res)
    def test_get_provider_ids_matching_all(self):
        # These RPs are named based on whether we expect them to be 'incl'uded
        # or 'excl'uded in the result.

        # No inventory records.  This one should never show up in a result.
        self._create_provider('no_inventory')

        # Inventory of adequate CPU and memory, no allocations against it.
        excl_big_cm_noalloc = self._create_provider('big_cm_noalloc')
        _add_inventory(excl_big_cm_noalloc, fields.ResourceClass.VCPU, 15)
        _add_inventory(excl_big_cm_noalloc, fields.ResourceClass.MEMORY_MB,
                       4096, max_unit=2048)

        # Adequate inventory, no allocations against it.
        incl_biginv_noalloc = self._create_provider('biginv_noalloc')
        _add_inventory(incl_biginv_noalloc, fields.ResourceClass.VCPU, 15)
        _add_inventory(incl_biginv_noalloc, fields.ResourceClass.MEMORY_MB,
                       4096, max_unit=2048)
        _add_inventory(incl_biginv_noalloc, fields.ResourceClass.DISK_GB, 2000)

        # No allocations, but inventory unusable.  Try to hit all the possible
        # reasons for exclusion.
        # VCPU min_unit too high
        excl_badinv_min_unit = self._create_provider('badinv_min_unit')
        _add_inventory(excl_badinv_min_unit, fields.ResourceClass.VCPU, 12,
                       min_unit=6)
        _add_inventory(excl_badinv_min_unit, fields.ResourceClass.MEMORY_MB,
                       4096, max_unit=2048)
        _add_inventory(excl_badinv_min_unit, fields.ResourceClass.DISK_GB,
                       2000)
        # MEMORY_MB max_unit too low
        excl_badinv_max_unit = self._create_provider('badinv_max_unit')
        _add_inventory(excl_badinv_max_unit, fields.ResourceClass.VCPU, 15)
        _add_inventory(excl_badinv_max_unit, fields.ResourceClass.MEMORY_MB,
                       4096, max_unit=512)
        _add_inventory(excl_badinv_max_unit, fields.ResourceClass.DISK_GB,
                       2000)
        # DISK_GB unsuitable step_size
        excl_badinv_step_size = self._create_provider('badinv_step_size')
        _add_inventory(excl_badinv_step_size, fields.ResourceClass.VCPU, 15)
        _add_inventory(excl_badinv_step_size, fields.ResourceClass.MEMORY_MB,
                       4096, max_unit=2048)
        _add_inventory(excl_badinv_step_size, fields.ResourceClass.DISK_GB,
                       2000, step_size=7)
        # Not enough total VCPU
        excl_badinv_total = self._create_provider('badinv_total')
        _add_inventory(excl_badinv_total, fields.ResourceClass.VCPU, 4)
        _add_inventory(excl_badinv_total, fields.ResourceClass.MEMORY_MB,
                       4096, max_unit=2048)
        _add_inventory(excl_badinv_total, fields.ResourceClass.DISK_GB, 2000)
        # Too much reserved MEMORY_MB
        excl_badinv_reserved = self._create_provider('badinv_reserved')
        _add_inventory(excl_badinv_reserved, fields.ResourceClass.VCPU, 15)
        _add_inventory(excl_badinv_reserved, fields.ResourceClass.MEMORY_MB,
                       4096, max_unit=2048, reserved=3500)
        _add_inventory(excl_badinv_reserved, fields.ResourceClass.DISK_GB,
                       2000)
        # DISK_GB allocation ratio blows it up
        excl_badinv_alloc_ratio = self._create_provider('badinv_alloc_ratio')
        _add_inventory(excl_badinv_alloc_ratio, fields.ResourceClass.VCPU, 15)
        _add_inventory(excl_badinv_alloc_ratio, fields.ResourceClass.MEMORY_MB,
                       4096, max_unit=2048)
        _add_inventory(excl_badinv_alloc_ratio, fields.ResourceClass.DISK_GB,
                       2000, allocation_ratio=0.5)

        # Inventory consumed in one RC, but available in the others
        excl_1invunavail = self._create_provider('1invunavail')
        _add_inventory(excl_1invunavail, fields.ResourceClass.VCPU, 10)
        _allocate_from_provider(excl_1invunavail, fields.ResourceClass.VCPU, 7)
        _add_inventory(excl_1invunavail, fields.ResourceClass.MEMORY_MB, 4096)
        _allocate_from_provider(excl_1invunavail,
                                fields.ResourceClass.MEMORY_MB, 1024)
        _add_inventory(excl_1invunavail, fields.ResourceClass.DISK_GB, 2000)
        _allocate_from_provider(excl_1invunavail,
                                fields.ResourceClass.DISK_GB, 400)

        # Inventory all consumed
        excl_allused = self._create_provider('allused')
        _add_inventory(excl_allused, fields.ResourceClass.VCPU, 10)
        _allocate_from_provider(excl_allused, fields.ResourceClass.VCPU, 7)
        _add_inventory(excl_allused, fields.ResourceClass.MEMORY_MB, 4000)
        _allocate_from_provider(excl_allused,
                                fields.ResourceClass.MEMORY_MB, 1500)
        _allocate_from_provider(excl_allused,
                                fields.ResourceClass.MEMORY_MB, 2000)
        _add_inventory(excl_allused, fields.ResourceClass.DISK_GB, 1500)
        _allocate_from_provider(excl_allused, fields.ResourceClass.DISK_GB, 1)

        # Inventory available in requested classes, but unavailable in others
        incl_extra_full = self._create_provider('extra_full')
        _add_inventory(incl_extra_full, fields.ResourceClass.VCPU, 20)
        _allocate_from_provider(incl_extra_full, fields.ResourceClass.VCPU, 15)
        _add_inventory(incl_extra_full, fields.ResourceClass.MEMORY_MB, 4096)
        _allocate_from_provider(incl_extra_full,
                                fields.ResourceClass.MEMORY_MB, 1024)
        _add_inventory(incl_extra_full, fields.ResourceClass.DISK_GB, 2000)
        _allocate_from_provider(incl_extra_full, fields.ResourceClass.DISK_GB,
                                400)
        _add_inventory(incl_extra_full, fields.ResourceClass.PCI_DEVICE, 4)
        _allocate_from_provider(incl_extra_full,
                                fields.ResourceClass.PCI_DEVICE, 1)
        _allocate_from_provider(incl_extra_full,
                                fields.ResourceClass.PCI_DEVICE, 3)

        # Inventory available in a unrequested classes, not in requested ones
        excl_extra_avail = self._create_provider('extra_avail')
        # Incompatible step size
        _add_inventory(excl_extra_avail, fields.ResourceClass.VCPU, 10,
                       step_size=3)
        # Not enough left after reserved + used
        _add_inventory(excl_extra_avail, fields.ResourceClass.MEMORY_MB, 4096,
                       max_unit=2048, reserved=2048)
        _allocate_from_provider(excl_extra_avail,
                                fields.ResourceClass.MEMORY_MB, 1040)
        # Allocation ratio math
        _add_inventory(excl_extra_avail, fields.ResourceClass.DISK_GB, 2000,
                       allocation_ratio=0.5)
        _add_inventory(excl_extra_avail, fields.ResourceClass.IPV4_ADDRESS, 48)
        custom_special = rp_obj.ResourceClass(self.ctx, name='CUSTOM_SPECIAL')
        custom_special.create()
        _add_inventory(excl_extra_avail, 'CUSTOM_SPECIAL', 100)
        _allocate_from_provider(excl_extra_avail, 'CUSTOM_SPECIAL', 99)

        resources = {
            fields.ResourceClass.STANDARD.index(fields.ResourceClass.VCPU): 5,
            fields.ResourceClass.STANDARD.index(
                fields.ResourceClass.MEMORY_MB): 1024,
            fields.ResourceClass.STANDARD.index(
                fields.ResourceClass.DISK_GB): 1500
        }

        # Run it!
        res = rp_obj._get_provider_ids_matching_all(self.ctx, resources)

        # We should get all the incl_* RPs
        expected = [incl_biginv_noalloc, incl_extra_full]

        self.assertEqual(set(rp.id for rp in expected), set(res))