Beispiel #1
0
    def test_delete_all_with_multiple_consumers(self):
        """Tests fix for LP #1781430 where alloc_obj.delete_all() when
        issued for a list of allocations returned by
        alloc_obj.get_by_resource_provider() where the resource provider
        had multiple consumers allocated against it, left the DB in an
        inconsistent state.
        """
        # Create a single resource provider and allocate resources for two
        # instances from it. Then grab all the provider's allocations with
        # alloc_obj.get_all_by_resource_provider() and attempt to delete
        # them all with alloc_obj.delete_all(). After which, another call
        # to alloc_obj.get_all_by_resource_provider() should return an
        # empty list.
        cn1 = self._create_provider('cn1')
        tb.add_inventory(cn1, 'VCPU', 8)

        c1_uuid = uuidsentinel.consumer1
        c2_uuid = uuidsentinel.consumer2

        for c_uuid in (c1_uuid, c2_uuid):
            self.allocate_from_provider(cn1, 'VCPU', 1, consumer_id=c_uuid)

        allocs = alloc_obj.get_all_by_resource_provider(self.ctx, cn1)
        self.assertEqual(2, len(allocs))

        alloc_obj.delete_all(self.ctx, allocs)

        allocs = alloc_obj.get_all_by_resource_provider(self.ctx, cn1)
        self.assertEqual(0, len(allocs))
Beispiel #2
0
    def test_create_list_and_delete_allocation(self):
        rp, _ = self._make_allocation(tb.DISK_INVENTORY, tb.DISK_ALLOCATION)

        allocations = alloc_obj.get_all_by_resource_provider(self.ctx, rp)

        self.assertEqual(1, len(allocations))

        self.assertEqual(tb.DISK_ALLOCATION['used'], allocations[0].used)

        alloc_obj.delete_all(self.ctx, allocations)

        allocations = alloc_obj.get_all_by_resource_provider(self.ctx, rp)

        self.assertEqual(0, len(allocations))
Beispiel #3
0
    def test_create_incomplete_consumers(self):
        """Test the online data migration that creates incomplete consumer
        records along with the incomplete consumer project/user records.
        """
        self._create_incomplete_allocations(self.ctx)
        # We do a "really online" online data migration for incomplete
        # consumers when calling alloc_obj.get_all_by_consumer_id() and
        # alloc_obj.get_all_by_resource_provider() and there are still
        # incomplete consumer records. So, to simulate a situation where the
        # operator has yet to run the nova-manage online_data_migration CLI
        # tool completely, we first call
        # consumer_obj.create_incomplete_consumers() with a batch size of 1.
        # This should mean there will be two allocation records still remaining
        # with a missing consumer record (since we create 3 total to begin
        # with). We then query the allocations table directly to grab that
        # consumer UUID in the allocations table that doesn't refer to a
        # consumer table record and call
        # alloc_obj.get_all_by_consumer_id() with that consumer UUID. This
        # should create the remaining missing consumer record "inline" in the
        # alloc_obj.get_all_by_consumer_id() method.
        # After that happens, there should still be a single allocation record
        # that is missing a relation to the consumers table. We call the
        # alloc_obj.get_all_by_resource_provider() method and verify that
        # method cleans up the remaining incomplete consumers relationship.
        res = consumer_obj.create_incomplete_consumers(self.ctx, 1)
        self.assertEqual((1, 1), res)

        # Grab the consumer UUID for the allocation record with a
        # still-incomplete consumer record.
        res = _get_allocs_with_no_consumer_relationship(self.ctx)
        self.assertEqual(2, len(res))
        still_missing = res[0][0]
        alloc_obj.get_all_by_consumer_id(self.ctx, still_missing)

        # There should still be a single missing consumer relationship. Let's
        # grab that and call alloc_obj.get_all_by_resource_provider()
        # which should clean that last one up for us.
        res = _get_allocs_with_no_consumer_relationship(self.ctx)
        self.assertEqual(1, len(res))
        still_missing = res[0][0]
        rp1 = rp_obj.ResourceProvider(self.ctx, id=1)
        alloc_obj.get_all_by_resource_provider(self.ctx, rp1)

        # get_all_by_resource_provider() should have auto-completed the still
        # missing consumer record and _check_incomplete_consumers() should
        # assert correctly that there are no more incomplete consumer records.
        self._check_incomplete_consumers(self.ctx)
        res = consumer_obj.create_incomplete_consumers(self.ctx, 10)
        self.assertEqual((0, 0), res)
Beispiel #4
0
 def test_get_all_by_resource_provider(self):
     rp, allocation = self._make_allocation(tb.DISK_INVENTORY,
                                            tb.DISK_ALLOCATION)
     allocations = alloc_obj.get_all_by_resource_provider(self.ctx, rp)
     self.assertEqual(1, len(allocations))
     self.assertEqual(rp.id, allocations[0].resource_provider.id)
     self.assertEqual(allocation.resource_provider.id,
                      allocations[0].resource_provider.id)
Beispiel #5
0
 def test_create_incomplete_consumers_multiple_allocs_per_consumer(self):
     """Tests that missing consumer records are created when listing
     allocations against a resource provider or running the online data
     migration routine when the consumers have multiple allocations on the
     same provider.
     """
     self._create_incomplete_allocations(self.ctx, num_of_consumer_allocs=2)
     # Run the online data migration to migrate one consumer. The batch size
     # needs to be large enough to hit more than one consumer for this test
     # where each consumer has two allocations.
     res = consumer_obj.create_incomplete_consumers(self.ctx, 2)
     self.assertEqual((2, 2), res)
     # Migrate the rest by listing allocations on the resource provider.
     rp1 = rp_obj.ResourceProvider(self.ctx, id=1)
     alloc_obj.get_all_by_resource_provider(self.ctx, rp1)
     self._check_incomplete_consumers(self.ctx)
     res = consumer_obj.create_incomplete_consumers(self.ctx, 10)
     self.assertEqual((0, 0), res)
Beispiel #6
0
    def test_get_all_by_resource_provider(self, mock_get_allocations_from_db):
        rp = rp_obj.ResourceProvider(self.context,
                                     id=_RESOURCE_PROVIDER_ID,
                                     uuid=uuids.resource_provider)
        allocations = alloc_obj.get_all_by_resource_provider(self.context, rp)

        self.assertEqual(1, len(allocations))
        mock_get_allocations_from_db.assert_called_once_with(
            self.context, rp.id)
        self.assertEqual(_ALLOCATION_DB['used'], allocations[0].used)
        self.assertEqual(_ALLOCATION_DB['created_at'],
                         allocations[0].created_at)
        self.assertEqual(_ALLOCATION_DB['updated_at'],
                         allocations[0].updated_at)
Beispiel #7
0
def list_for_resource_provider(req):
    """List allocations associated with a resource provider."""
    # TODO(cdent): On a shared resource provider (for example a
    # giant disk farm) this list could get very long. At the moment
    # we have no facility for limiting the output. Given that we are
    # using a dict of dicts for the output we are potentially limiting
    # ourselves in terms of sorting and filtering.
    context = req.environ['placement.context']
    context.can(policies.RP_ALLOC_LIST)
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]
    uuid = util.wsgi_path_item(req.environ, 'uuid')

    # confirm existence of resource provider so we get a reasonable
    # 404 instead of empty list
    try:
        rp = rp_obj.ResourceProvider.get_by_uuid(context, uuid)
    except exception.NotFound as exc:
        raise webob.exc.HTTPNotFound(
            "Resource provider '%(rp_uuid)s' not found: %(error)s" % {
                'rp_uuid': uuid,
                'error': exc
            })

    allocs = alloc_obj.get_all_by_resource_provider(context, rp)

    output = _serialize_allocations_for_resource_provider(
        allocs, rp, want_version)
    last_modified = _last_modified_from_allocations(allocs, want_version)
    allocations_json = jsonutils.dumps(output)

    response = req.response
    response.status = 200
    response.body = encodeutils.to_utf8(allocations_json)
    response.content_type = 'application/json'
    if want_version.matches((1, 15)):
        response.last_modified = last_modified
        response.cache_control = 'no-cache'
    return response
Beispiel #8
0
    def test_multi_provider_allocation(self):
        """Tests that an allocation that includes more than one resource
        provider can be created, listed and deleted properly.

        Bug #1707669 highlighted a situation that arose when attempting to
        remove part of an allocation for a source host during a resize
        operation where the exiting allocation was not being properly
        deleted.
        """
        cn_source = self._create_provider('cn_source')
        cn_dest = self._create_provider('cn_dest')

        # Add same inventory to both source and destination host
        for cn in (cn_source, cn_dest):
            tb.add_inventory(cn, orc.VCPU, 24,
                             allocation_ratio=16.0)
            tb.add_inventory(cn, orc.MEMORY_MB, 1024,
                             min_unit=64,
                             max_unit=1024,
                             step_size=64,
                             allocation_ratio=1.5)

        # Create a consumer representing the instance
        inst_consumer = consumer_obj.Consumer(
            self.ctx, uuid=uuidsentinel.instance, user=self.user_obj,
            project=self.project_obj)
        inst_consumer.create()

        # Now create an allocation that represents a move operation where the
        # scheduler has selected cn_dest as the target host and created a
        # "doubled-up" allocation for the duration of the move operation
        alloc_list = [
            alloc_obj.Allocation(
                consumer=inst_consumer,
                resource_provider=cn_source,
                resource_class=orc.VCPU,
                used=1),
            alloc_obj.Allocation(
                consumer=inst_consumer,
                resource_provider=cn_source,
                resource_class=orc.MEMORY_MB,
                used=256),
            alloc_obj.Allocation(
                consumer=inst_consumer,
                resource_provider=cn_dest,
                resource_class=orc.VCPU,
                used=1),
            alloc_obj.Allocation(
                consumer=inst_consumer,
                resource_provider=cn_dest,
                resource_class=orc.MEMORY_MB,
                used=256),
        ]
        alloc_obj.replace_all(self.ctx, alloc_list)

        src_allocs = alloc_obj.get_all_by_resource_provider(
            self.ctx, cn_source)

        self.assertEqual(2, len(src_allocs))

        dest_allocs = alloc_obj.get_all_by_resource_provider(self.ctx, cn_dest)

        self.assertEqual(2, len(dest_allocs))

        consumer_allocs = alloc_obj.get_all_by_consumer_id(
            self.ctx, uuidsentinel.instance)

        self.assertEqual(4, len(consumer_allocs))

        # Validate that when we create an allocation for a consumer that we
        # delete any existing allocation and replace it with what the new.
        # Here, we're emulating the step that occurs on confirm_resize() where
        # the source host pulls the existing allocation for the instance and
        # removes any resources that refer to itself and saves the allocation
        # back to placement
        new_alloc_list = [
            alloc_obj.Allocation(
                consumer=inst_consumer,
                resource_provider=cn_dest,
                resource_class=orc.VCPU,
                used=1),
            alloc_obj.Allocation(
                consumer=inst_consumer,
                resource_provider=cn_dest,
                resource_class=orc.MEMORY_MB,
                used=256),
        ]
        alloc_obj.replace_all(self.ctx, new_alloc_list)

        src_allocs = alloc_obj.get_all_by_resource_provider(
            self.ctx, cn_source)

        self.assertEqual(0, len(src_allocs))

        dest_allocs = alloc_obj.get_all_by_resource_provider(
            self.ctx, cn_dest)

        self.assertEqual(2, len(dest_allocs))

        consumer_allocs = alloc_obj.get_all_by_consumer_id(
            self.ctx, uuidsentinel.instance)

        self.assertEqual(2, len(consumer_allocs))
Beispiel #9
0
    def test_create_exceeding_capacity_allocation(self):
        """Tests on a list of allocations which contains an invalid allocation
        exceeds resource provider's capacity.

        Expect InvalidAllocationCapacityExceeded to be raised and all
        allocations in the list should not be applied.

        """
        empty_rp = self._create_provider('empty_rp')
        full_rp = self._create_provider('full_rp')

        for rp in (empty_rp, full_rp):
            tb.add_inventory(rp, orc.VCPU, 24,
                             allocation_ratio=16.0)
            tb.add_inventory(rp, orc.MEMORY_MB, 1024,
                             min_unit=64,
                             max_unit=1024,
                             step_size=64)

        # Create a consumer representing the instance
        inst_consumer = consumer_obj.Consumer(
            self.ctx, uuid=uuidsentinel.instance, user=self.user_obj,
            project=self.project_obj)
        inst_consumer.create()

        # First create a allocation to consume full_rp's resource.
        alloc_list = [
            alloc_obj.Allocation(
                consumer=inst_consumer,
                resource_provider=full_rp,
                resource_class=orc.VCPU,
                used=12),
            alloc_obj.Allocation(
                consumer=inst_consumer,
                resource_provider=full_rp,
                resource_class=orc.MEMORY_MB,
                used=1024)
        ]
        alloc_obj.replace_all(self.ctx, alloc_list)

        # Create a consumer representing the second instance
        inst2_consumer = consumer_obj.Consumer(
            self.ctx, uuid=uuidsentinel.instance2, user=self.user_obj,
            project=self.project_obj)
        inst2_consumer.create()

        # Create an allocation list consisting of valid requests and an invalid
        # request exceeding the memory full_rp can provide.
        alloc_list = [
            alloc_obj.Allocation(
                consumer=inst2_consumer,
                resource_provider=empty_rp,
                resource_class=orc.VCPU,
                used=12),
            alloc_obj.Allocation(
                consumer=inst2_consumer,
                resource_provider=empty_rp,
                resource_class=orc.MEMORY_MB,
                used=512),
            alloc_obj.Allocation(
                consumer=inst2_consumer,
                resource_provider=full_rp,
                resource_class=orc.VCPU,
                used=12),
            alloc_obj.Allocation(
                consumer=inst2_consumer,
                resource_provider=full_rp,
                resource_class=orc.MEMORY_MB,
                used=512),
        ]

        self.assertRaises(exception.InvalidAllocationCapacityExceeded,
                          alloc_obj.replace_all, self.ctx, alloc_list)

        # Make sure that allocations of both empty_rp and full_rp remain
        # unchanged.
        allocations = alloc_obj.get_all_by_resource_provider(self.ctx, full_rp)
        self.assertEqual(2, len(allocations))

        allocations = alloc_obj.get_all_by_resource_provider(
            self.ctx, empty_rp)
        self.assertEqual(0, len(allocations))