Beispiel #1
0
    def test_destroy_fail_with_inventory(self):
        """Test that we raise an exception when attempting to delete a resource
        class that is referenced in an inventory record.
        """
        rc = objects.ResourceClass(
            self.context,
            name='CUSTOM_IRON_NFV',
        )
        rc.create()
        rp = objects.ResourceProvider(
            self.context,
            name='my rp',
            uuid=uuidsentinel.rp,
        )
        rp.create()
        inv = objects.Inventory(
            resource_provider=rp,
            resource_class='CUSTOM_IRON_NFV',
            total=1,
        )
        inv.obj_set_defaults()
        inv_list = objects.InventoryList(objects=[inv])
        rp.set_inventory(inv_list)

        self.assertRaises(exception.ResourceClassInUse,
                          rc.destroy)

        rp.set_inventory(objects.InventoryList(objects=[]))
        rc.destroy()
        rc_list = objects.ResourceClassList.get_all(self.context)
        rc_ids = (r.id for r in rc_list)
        self.assertNotIn(rc.id, rc_ids)
Beispiel #2
0
    def test_find(self):
        rp = objects.ResourceProvider(uuid=uuids.rp_uuid)
        inv_list = objects.InventoryList(objects=[
            objects.Inventory(resource_provider=rp,
                              resource_class=fields.ResourceClass.VCPU,
                              total=24),
            objects.Inventory(resource_provider=rp,
                              resource_class=fields.ResourceClass.MEMORY_MB,
                              total=10240),
        ])

        found = inv_list.find(fields.ResourceClass.MEMORY_MB)
        self.assertIsNotNone(found)
        self.assertEqual(10240, found.total)

        found = inv_list.find(fields.ResourceClass.VCPU)
        self.assertIsNotNone(found)
        self.assertEqual(24, found.total)

        found = inv_list.find(fields.ResourceClass.DISK_GB)
        self.assertIsNone(found)

        # Try an integer resource class identifier...
        found = inv_list.find(
            fields.ResourceClass.index(fields.ResourceClass.VCPU))
        self.assertIsNotNone(found)
        self.assertEqual(24, found.total)
Beispiel #3
0
def set_inventories(req):
    """PUT to set all inventory for a resource provider.

    Create, update and delete inventory as required to reset all
    the inventory.

    If the resource generation is out of sync, return a 409.
    If an inventory to be deleted is in use, return a 409.
    If any inventory to be created or updated has settings which are
    invalid (for example reserved exceeds capacity), return a 400.

    On success return a 200 with an application/json body representing
    the inventories.
    """
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_provider = objects.ResourceProvider.get_by_uuid(context, uuid)

    data = _extract_inventories(req.body, PUT_INVENTORY_SCHEMA)
    if data['resource_provider_generation'] != resource_provider.generation:
        raise webob.exc.HTTPConflict(
            _('resource provider generation conflict'))

    inv_list = []
    for res_class, inventory_data in data['inventories'].items():
        inventory = _make_inventory_object(resource_provider, res_class,
                                           **inventory_data)
        inv_list.append(inventory)
    inventories = objects.InventoryList(objects=inv_list)

    try:
        resource_provider.set_inventory(inventories)
    except exception.ResourceClassNotFound as exc:
        raise webob.exc.HTTPBadRequest(
            _('Unknown resource class in inventory for resource provider '
              '%(rp_uuid)s: %(error)s') % {
                  'rp_uuid': resource_provider.uuid,
                  'error': exc
              })
    except exception.InventoryWithResourceClassNotFound as exc:
        raise webob.exc.HTTPConflict(
            _('Race condition detected when setting inventory. No inventory '
              'record with resource class for resource provider '
              '%(rp_uuid)s: %(error)s') % {
                  'rp_uuid': resource_provider.uuid,
                  'error': exc
              })
    except (exception.ConcurrentUpdateDetected, exception.InventoryInUse,
            db_exc.DBDuplicateEntry) as exc:
        raise webob.exc.HTTPConflict(
            _('update conflict: %(error)s') % {'error': exc})
    except exception.InvalidInventoryCapacity as exc:
        raise webob.exc.HTTPBadRequest(
            _('Unable to update inventory for resource provider '
              '%(rp_uuid)s: %(error)s') % {
                  'rp_uuid': resource_provider.uuid,
                  'error': exc
              })

    return _send_inventories(req.response, resource_provider, inventories)
    def test_update_inventory_violates_allocation(self, mock_log):
        # Compute nodes that are reconfigured have to be able to set
        # their inventory to something that violates allocations so
        # we need to make that possible.
        rp, allocation = self._make_allocation()
        disk_inv = objects.Inventory(resource_provider=rp,
                                     resource_class='DISK_GB',
                                     total=2048)
        disk_inv.obj_set_defaults()
        inv_list = objects.InventoryList(objects=[disk_inv])
        rp.set_inventory(inv_list)
        # attempt to set inventory to less than currently allocated
        # amounts
        new_total = 1
        disk_inv = objects.Inventory(
            resource_provider=rp,
            resource_class=fields.ResourceClass.DISK_GB,
            total=new_total)
        disk_inv.obj_set_defaults()
        rp.update_inventory(disk_inv)

        usages = objects.UsageList.get_all_by_resource_provider_uuid(
            self.context, rp.uuid)
        self.assertEqual(allocation.used, usages[0].usage)

        inv_list = objects.InventoryList.get_all_by_resource_provider_uuid(
            self.context, rp.uuid)
        self.assertEqual(new_total, inv_list[0].total)
        mock_log.warning.assert_called_once_with(mock.ANY, {
            'uuid': rp.uuid,
            'resource': 'DISK_GB'
        })
Beispiel #5
0
    def test_find(self):
        rp = objects.ResourceProvider(uuid=uuids.rp_uuid)
        inv_list = objects.InventoryList(objects=[
            objects.Inventory(resource_provider=rp,
                              resource_class=fields.ResourceClass.VCPU,
                              total=24),
            objects.Inventory(resource_provider=rp,
                              resource_class=fields.ResourceClass.MEMORY_MB,
                              total=10240),
        ])

        found = inv_list.find(fields.ResourceClass.MEMORY_MB)
        self.assertIsNotNone(found)
        self.assertEqual(10240, found.total)

        found = inv_list.find(fields.ResourceClass.VCPU)
        self.assertIsNotNone(found)
        self.assertEqual(24, found.total)

        found = inv_list.find(fields.ResourceClass.DISK_GB)
        self.assertIsNone(found)

        # Try an integer resource class identifier...
        self.assertRaises(ValueError, inv_list.find, VCPU_ID)

        # Use an invalid string...
        self.assertIsNone(inv_list.find('HOUSE'))
Beispiel #6
0
def delete_inventories(req):
    """DELETE all inventory for a resource provider.

    Delete inventory as required to reset all the inventory.
    If an inventory to be deleted is in use, return a 409 Conflict.
    On success return a 204 No content.
    Return 405 Method Not Allowed if the wanted microversion does not match.
    """
    microversion.raise_http_status_code_if_not_version(req, 405, (1, 5))
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_provider = objects.ResourceProvider.get_by_uuid(context, uuid)

    inventories = objects.InventoryList(objects=[])

    try:
        resource_provider.set_inventory(inventories)
    except exception.ConcurrentUpdateDetected:
        raise webob.exc.HTTPConflict(
            _('Unable to delete inventory for resource provider '
              '%(rp_uuid)s because the inventory was updated by '
              'another process. Please retry your request.') %
            {'rp_uuid': resource_provider.uuid})
    except exception.InventoryInUse:
        raise webob.exc.HTTPConflict(
            _('Unable to delete inventory for resource provider '
              '%(rp_uuid)s because the inventory is in use.') %
            {'rp_uuid': resource_provider.uuid})

    response = req.response
    response.status = 204
    response.content_type = None

    return response
    def test_find(self):
        rp = objects.ResourceProvider(uuid=uuids.rp_uuid)
        inv_list = objects.InventoryList(objects=[
            objects.Inventory(resource_provider=rp,
                              resource_class=fields.ResourceClass.VCPU,
                              total=24),
            objects.Inventory(resource_provider=rp,
                              resource_class=fields.ResourceClass.MEMORY_MB,
                              total=10240),
        ])

        found = inv_list.find(fields.ResourceClass.MEMORY_MB)
        self.assertIsNotNone(found)
        self.assertEqual(10240, found.total)

        found = inv_list.find(fields.ResourceClass.VCPU)
        self.assertIsNotNone(found)
        self.assertEqual(24, found.total)

        found = inv_list.find(fields.ResourceClass.DISK_GB)
        self.assertIsNone(found)

        # Try an integer resource class identifier...
        found = inv_list.find(
            fields.ResourceClass.index(fields.ResourceClass.VCPU))
        self.assertIsNotNone(found)
        self.assertEqual(24, found.total)

        # Use an invalid string...
        error = self.assertRaises(exception.NotFound, inv_list.find, 'HOUSE')
        self.assertIn('No such resource class', str(error))
    def test_set_inventory_unknown_resource_class(self):
        """Test attempting to set inventory to an unknown resource class raises
        an exception.
        """
        rp = objects.ResourceProvider(
            context=self.context,
            uuid=uuidsentinel.rp_uuid,
            name='compute-host',
        )
        rp.create()

        inv = objects.Inventory(
            resource_provider=rp,
            resource_class='UNKNOWN',
            total=1024,
            reserved=15,
            min_unit=10,
            max_unit=100,
            step_size=10,
            allocation_ratio=1.0,
        )

        inv_list = objects.InventoryList(objects=[inv])
        self.assertRaises(exception.ResourceClassNotFound, rp.set_inventory,
                          inv_list)
 def test_delete_inventory_with_allocation(self):
     rp, allocation = self._make_allocation()
     disk_inv = objects.Inventory(resource_provider=rp,
                                  resource_class='DISK_GB',
                                  total=2048)
     disk_inv.obj_set_defaults()
     inv_list = objects.InventoryList(objects=[disk_inv])
     rp.set_inventory(inv_list)
     error = self.assertRaises(exception.InventoryInUse,
                               rp.delete_inventory, 'DISK_GB')
     self.assertIn(
         "Inventory for 'DISK_GB' on resource provider '%s' in use" %
         rp.uuid, str(error))
 def _make_rp_and_inventory(self, **kwargs):
     # Create one resource provider and set some inventory
     rp_name = uuidsentinel.rp_name
     rp_uuid = uuidsentinel.rp_uuid
     rp = objects.ResourceProvider(
         self.context, name=rp_name, uuid=rp_uuid)
     rp.create()
     inv = objects.Inventory(resource_provider=rp,
                             total=1024, allocation_ratio=1,
                             reserved=0, **kwargs)
     inv.obj_set_defaults()
     rp.set_inventory(objects.InventoryList(objects=[inv]))
     return rp
    def test_get_all_one_allocation(self):
        db_rp, _ = self._make_allocation(rp_uuid=uuidsentinel.rp_uuid)
        inv = objects.Inventory(resource_provider=db_rp,
                                resource_class=fields.ResourceClass.DISK_GB,
                                total=1024)
        inv.obj_set_defaults()
        inv_list = objects.InventoryList(objects=[inv])
        db_rp.set_inventory(inv_list)

        usage_list = objects.UsageList.get_all_by_resource_provider_uuid(
            self.context, db_rp.uuid)
        self.assertEqual(1, len(usage_list))
        self.assertEqual(2, usage_list[0].usage)
        self.assertEqual(fields.ResourceClass.DISK_GB,
                         usage_list[0].resource_class)
    def test_set_inventory_over_capacity(self, mock_log):
        rp = objects.ResourceProvider(context=self.context,
                                      uuid=uuidsentinel.rp_uuid,
                                      name=uuidsentinel.rp_name)
        rp.create()

        disk_inv = objects.Inventory(
            resource_provider=rp,
            resource_class=fields.ResourceClass.DISK_GB,
            total=1024,
            reserved=15,
            min_unit=10,
            max_unit=100,
            step_size=10,
            allocation_ratio=1.0)
        vcpu_inv = objects.Inventory(resource_provider=rp,
                                     resource_class=fields.ResourceClass.VCPU,
                                     total=12,
                                     reserved=0,
                                     min_unit=1,
                                     max_unit=12,
                                     step_size=1,
                                     allocation_ratio=16.0)

        inv_list = objects.InventoryList(objects=[disk_inv, vcpu_inv])
        rp.set_inventory(inv_list)
        self.assertFalse(mock_log.warning.called)

        # Allocate something reasonable for the above inventory
        alloc = objects.Allocation(context=self.context,
                                   resource_provider=rp,
                                   consumer_id=uuidsentinel.consumer,
                                   resource_class='DISK_GB',
                                   used=512)
        alloc.create()

        # Update our inventory to over-subscribe us after the above allocation
        disk_inv.total = 400
        rp.set_inventory(inv_list)

        # We should succeed, but have logged a warning for going over on disk
        mock_log.warning.assert_called_once_with(mock.ANY, {
            'uuid': rp.uuid,
            'resource': 'DISK_GB'
        })
Beispiel #13
0
def set_inventories(req):
    """PUT to set all inventory for a resource provider.

    Create, update and delete inventory as required to reset all
    the inventory.

    If the resource generation is out of sync, return a 409.
    If an inventory to be deleted is in use, return a 409.
    If an inventory to be updated would set capacity to exceed existing
    use, return a 409.
    If any inventory to be created or updated has settings which are
    invalid (for example reserved exceeds capacity), return a 400.

    On success return a 200 with an application/json body representing
    the inventories.
    """
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_provider = objects.ResourceProvider.get_by_uuid(context, uuid)

    data = _extract_inventories(req.body, PUT_INVENTORY_SCHEMA)
    if data['resource_provider_generation'] != resource_provider.generation:
        raise webob.exc.HTTPConflict('resource provider generation conflict',
                                     json_formatter=util.json_error_formatter)

    inv_list = []
    for inventory_data in data['inventories']:
        inventory = _make_inventory_object(resource_provider, **inventory_data)
        inv_list.append(inventory)
    inventories = objects.InventoryList(objects=inv_list)

    try:
        resource_provider.set_inventory(inventories)
    except (exception.ConcurrentUpdateDetected, exception.InventoryInUse,
            exception.InvalidInventoryNewCapacityExceeded,
            db_exc.DBDuplicateEntry) as exc:
        raise webob.exc.HTTPConflict('update conflict: %s' % exc,
                                     json_formatter=util.json_error_formatter)
    except exception.InvalidInventoryCapacity as exc:
        raise webob.exc.HTTPBadRequest(
            'Unable to update inventory for resource provider %s: %s' %
            (resource_provider.uuid, exc),
            json_formatter=util.json_error_formatter)

    return _send_inventories(req.response, resource_provider, inventories)
    def test_get_all_multiple_inv(self):
        db_rp = objects.ResourceProvider(self.context,
                                         name=uuidsentinel.rp_no_inv,
                                         uuid=uuidsentinel.rp_no_inv)
        db_rp.create()
        disk_inv = objects.Inventory(
            resource_provider=db_rp,
            resource_class=fields.ResourceClass.DISK_GB, total=1024)
        disk_inv.obj_set_defaults()
        vcpu_inv = objects.Inventory(
            resource_provider=db_rp,
            resource_class=fields.ResourceClass.VCPU, total=24)
        vcpu_inv.obj_set_defaults()
        inv_list = objects.InventoryList(objects=[disk_inv, vcpu_inv])
        db_rp.set_inventory(inv_list)

        usage_list = objects.UsageList.get_all_by_resource_provider_uuid(
            self.context, db_rp.uuid)
        self.assertEqual(2, len(usage_list))
 def test_update_inventory_violates_allocation(self):
     rp, allocation = self._make_allocation()
     disk_inv = objects.Inventory(resource_provider=rp,
                                  resource_class='DISK_GB',
                                  total=2048)
     disk_inv.obj_set_defaults()
     inv_list = objects.InventoryList(objects=[disk_inv])
     rp.set_inventory(inv_list)
     # attempt to set inventory to less than currently allocated
     # amounts
     disk_inv = objects.Inventory(
         resource_provider=rp,
         resource_class=fields.ResourceClass.DISK_GB, total=1)
     disk_inv.obj_set_defaults()
     error = self.assertRaises(
         exception.InvalidInventoryNewCapacityExceeded,
         rp.update_inventory, disk_inv)
     self.assertIn("Invalid inventory for '%s'"
                   % fields.ResourceClass.DISK_GB, str(error))
     self.assertIn("on resource provider '%s'." % rp.uuid, str(error))
Beispiel #16
0
    def start_fixture(self):
        super(SharedStorageFixture, self).start_fixture()
        self.context = context.get_admin_context()

        # These UUIDs are staticly defined here because the JSONPath querying
        # needed in the allocation-candidates.yaml gabbits cannot refer to an
        # ENVIRON variable because the $ sign is a token in the JSONPath
        # parser.
        os.environ['CN1_UUID'] = 'c1c1c1c1-2894-4df1-aa6b-c61fa72ed22d'
        os.environ['CN2_UUID'] = 'c2c2c2c2-beef-49a0-98a0-b998b88debfd'
        os.environ['SS_UUID'] = 'dddddddd-61a6-472e-b8c1-74796e803066'
        os.environ['AGG_UUID'] = 'aaaaaaaa-04b3-458c-9a9f-361aad56f41c'

        cn1_uuid = os.environ['CN1_UUID']
        cn2_uuid = os.environ['CN2_UUID']
        ss_uuid = os.environ['SS_UUID']
        agg_uuid = os.environ['AGG_UUID']

        cn1 = objects.ResourceProvider(self.context, name='cn1', uuid=cn1_uuid)
        cn1.create()

        cn2 = objects.ResourceProvider(self.context, name='cn2', uuid=cn2_uuid)
        cn2.create()

        ss = objects.ResourceProvider(self.context, name='ss', uuid=ss_uuid)
        ss.create()

        # Populate compute node inventory for VCPU and RAM
        for cn in (cn1, cn2):
            vcpu_inv = objects.Inventory(self.context,
                                         resource_provider=cn,
                                         resource_class='VCPU',
                                         total=24,
                                         reserved=0,
                                         max_unit=24,
                                         min_unit=1,
                                         step_size=1,
                                         allocation_ratio=16.0)
            vcpu_inv.obj_set_defaults()
            ram_inv = objects.Inventory(self.context,
                                        resource_provider=cn,
                                        resource_class='MEMORY_MB',
                                        total=128 * 1024,
                                        reserved=0,
                                        max_unit=128 * 1024,
                                        min_unit=256,
                                        step_size=256,
                                        allocation_ratio=1.5)
            ram_inv.obj_set_defaults()
            inv_list = objects.InventoryList(objects=[vcpu_inv, ram_inv])
            cn.set_inventory(inv_list)

        # Populate shared storage provider with DISK_GB inventory
        disk_inv = objects.Inventory(self.context,
                                     resource_provider=ss,
                                     resource_class='DISK_GB',
                                     total=2000,
                                     reserved=100,
                                     max_unit=2000,
                                     min_unit=10,
                                     step_size=10,
                                     allocation_ratio=1.0)
        disk_inv.obj_set_defaults()
        inv_list = objects.InventoryList(objects=[disk_inv])
        ss.set_inventory(inv_list)

        # Mark the shared storage pool as having inventory shared among any
        # provider associated via aggregate
        t = objects.Trait.get_by_name(
            self.context,
            "MISC_SHARES_VIA_AGGREGATE",
        )
        ss.set_traits(objects.TraitList(objects=[t]))

        # Now associate the shared storage pool and both compute nodes with the
        # same aggregate
        cn1.set_aggregates([agg_uuid])
        cn2.set_aggregates([agg_uuid])
        ss.set_aggregates([agg_uuid])
    def test_allocation_list_create(self):
        consumer_uuid = uuidsentinel.consumer

        # Create two resource providers
        rp1_name = uuidsentinel.rp1_name
        rp1_uuid = uuidsentinel.rp1_uuid
        rp1_class = fields.ResourceClass.DISK_GB
        rp1_used = 6

        rp2_name = uuidsentinel.rp2_name
        rp2_uuid = uuidsentinel.rp2_uuid
        rp2_class = fields.ResourceClass.IPV4_ADDRESS
        rp2_used = 2

        rp1 = objects.ResourceProvider(
            self.context, name=rp1_name, uuid=rp1_uuid)
        rp1.create()
        rp2 = objects.ResourceProvider(
            self.context, name=rp2_name, uuid=rp2_uuid)
        rp2.create()

        # Two allocations, one for each resource provider.
        allocation_1 = objects.Allocation(resource_provider=rp1,
                                          consumer_id=consumer_uuid,
                                          resource_class=rp1_class,
                                          used=rp1_used)
        allocation_2 = objects.Allocation(resource_provider=rp2,
                                          consumer_id=consumer_uuid,
                                          resource_class=rp2_class,
                                          used=rp2_used)
        allocation_list = objects.AllocationList(
            self.context, objects=[allocation_1, allocation_2])

        # There's no inventory, we have a failure.
        self.assertRaises(exception.InvalidInventory,
                          allocation_list.create_all)

        # Add inventory for one of the two resource providers. This should also
        # fail, since rp2 has no inventory.
        inv = objects.Inventory(resource_provider=rp1,
                                resource_class=rp1_class,
                                total=1024)
        inv.obj_set_defaults()
        inv_list = objects.InventoryList(objects=[inv])
        rp1.set_inventory(inv_list)
        self.assertRaises(exception.InvalidInventory,
                          allocation_list.create_all)

        # Add inventory for the second resource provider
        inv = objects.Inventory(resource_provider=rp2,
                                resource_class=rp2_class,
                                total=255, reserved=2)
        inv.obj_set_defaults()
        inv_list = objects.InventoryList(objects=[inv])
        rp2.set_inventory(inv_list)

        # Now the allocations will work.
        allocation_list.create_all()

        # Check that those allocations changed usage on each
        # resource provider.
        rp1_usage = objects.UsageList.get_all_by_resource_provider_uuid(
            self.context, rp1_uuid)
        rp2_usage = objects.UsageList.get_all_by_resource_provider_uuid(
            self.context, rp2_uuid)
        self.assertEqual(rp1_used, rp1_usage[0].usage)
        self.assertEqual(rp2_used, rp2_usage[0].usage)

        # redo one allocation
        # TODO(cdent): This does not currently behave as expected
        # because a new allocataion is created, adding to the total
        # used, not replacing.
        rp1_used += 1
        allocation_1 = objects.Allocation(resource_provider=rp1,
                                          consumer_id=consumer_uuid,
                                          resource_class=rp1_class,
                                          used=rp1_used)
        allocation_list = objects.AllocationList(
            self.context, objects=[allocation_1])
        allocation_list.create_all()

        rp1_usage = objects.UsageList.get_all_by_resource_provider_uuid(
            self.context, rp1_uuid)
        self.assertEqual(rp1_used, rp1_usage[0].usage)

        # delete the allocations for the consumer
        # NOTE(cdent): The database uses 'consumer_id' for the
        # column, presumably because some ids might not be uuids, at
        # some point in the future.
        consumer_allocations = objects.AllocationList.get_all_by_consumer_id(
            self.context, consumer_uuid)
        consumer_allocations.delete_all()

        rp1_usage = objects.UsageList.get_all_by_resource_provider_uuid(
            self.context, rp1_uuid)
        rp2_usage = objects.UsageList.get_all_by_resource_provider_uuid(
            self.context, rp2_uuid)
        self.assertEqual(0, rp1_usage[0].usage)
        self.assertEqual(0, rp2_usage[0].usage)
    def test_provider_modify_inventory(self):
        rp = objects.ResourceProvider(context=self.context,
                                      uuid=uuidsentinel.rp_uuid,
                                      name=uuidsentinel.rp_name)
        rp.create()
        saved_generation = rp.generation

        disk_inv = objects.Inventory(
                resource_provider=rp,
                resource_class=fields.ResourceClass.DISK_GB,
                total=1024,
                reserved=15,
                min_unit=10,
                max_unit=100,
                step_size=10,
                allocation_ratio=1.0)

        vcpu_inv = objects.Inventory(
                resource_provider=rp,
                resource_class=fields.ResourceClass.VCPU,
                total=12,
                reserved=0,
                min_unit=1,
                max_unit=12,
                step_size=1,
                allocation_ratio=16.0)

        # set to new list
        inv_list = objects.InventoryList(objects=[disk_inv, vcpu_inv])
        rp.set_inventory(inv_list)

        # generation has bumped
        self.assertEqual(saved_generation + 1, rp.generation)
        saved_generation = rp.generation

        new_inv_list = objects.InventoryList.get_all_by_resource_provider_uuid(
                self.context, uuidsentinel.rp_uuid)
        self.assertEqual(2, len(new_inv_list))
        resource_classes = [inv.resource_class for inv in new_inv_list]
        self.assertIn(fields.ResourceClass.VCPU, resource_classes)
        self.assertIn(fields.ResourceClass.DISK_GB, resource_classes)

        # reset list to just disk_inv
        inv_list = objects.InventoryList(objects=[disk_inv])
        rp.set_inventory(inv_list)

        # generation has bumped
        self.assertEqual(saved_generation + 1, rp.generation)
        saved_generation = rp.generation

        new_inv_list = objects.InventoryList.get_all_by_resource_provider_uuid(
                self.context, uuidsentinel.rp_uuid)
        self.assertEqual(1, len(new_inv_list))
        resource_classes = [inv.resource_class for inv in new_inv_list]
        self.assertNotIn(fields.ResourceClass.VCPU, resource_classes)
        self.assertIn(fields.ResourceClass.DISK_GB, resource_classes)
        self.assertEqual(1024, new_inv_list[0].total)

        # update existing disk inv to new settings
        disk_inv = objects.Inventory(
                resource_provider=rp,
                resource_class=fields.ResourceClass.DISK_GB,
                total=2048,
                reserved=15,
                min_unit=10,
                max_unit=100,
                step_size=10,
                allocation_ratio=1.0)
        rp.update_inventory(disk_inv)

        # generation has bumped
        self.assertEqual(saved_generation + 1, rp.generation)
        saved_generation = rp.generation

        new_inv_list = objects.InventoryList.get_all_by_resource_provider_uuid(
                self.context, uuidsentinel.rp_uuid)
        self.assertEqual(1, len(new_inv_list))
        self.assertEqual(2048, new_inv_list[0].total)

        # fail when inventory bad
        disk_inv = objects.Inventory(
                resource_provider=rp,
                resource_class=fields.ResourceClass.DISK_GB,
                total=2048,
                reserved=2048)
        disk_inv.obj_set_defaults()
        error = self.assertRaises(exception.InvalidInventoryCapacity,
                                  rp.update_inventory, disk_inv)
        self.assertIn("Invalid inventory for '%s'"
                      % fields.ResourceClass.DISK_GB, str(error))
        self.assertIn("on resource provider '%s'." % rp.uuid, str(error))

        # generation has not bumped
        self.assertEqual(saved_generation, rp.generation)

        # delete inventory
        rp.delete_inventory(fields.ResourceClass.DISK_GB)

        # generation has bumped
        self.assertEqual(saved_generation + 1, rp.generation)
        saved_generation = rp.generation

        new_inv_list = objects.InventoryList.get_all_by_resource_provider_uuid(
                self.context, uuidsentinel.rp_uuid)
        result = new_inv_list.find(fields.ResourceClass.DISK_GB)
        self.assertIsNone(result)
        self.assertRaises(exception.NotFound, rp.delete_inventory,
                          fields.ResourceClass.DISK_GB)

        # check inventory list is empty
        inv_list = objects.InventoryList.get_all_by_resource_provider_uuid(
                self.context, uuidsentinel.rp_uuid)
        self.assertEqual(0, len(inv_list))

        # add some inventory
        rp.add_inventory(vcpu_inv)
        inv_list = objects.InventoryList.get_all_by_resource_provider_uuid(
                self.context, uuidsentinel.rp_uuid)
        self.assertEqual(1, len(inv_list))

        # generation has bumped
        self.assertEqual(saved_generation + 1, rp.generation)
        saved_generation = rp.generation

        # add same inventory again
        self.assertRaises(db_exc.DBDuplicateEntry,
                          rp.add_inventory, vcpu_inv)

        # generation has not bumped
        self.assertEqual(saved_generation, rp.generation)

        # fail when generation wrong
        rp.generation = rp.generation - 1
        self.assertRaises(exception.ConcurrentUpdateDetected,
                          rp.set_inventory, inv_list)
    def test_allocation_checking(self):
        """Test that allocation check logic works with 2 resource classes on
        one provider.

        If this fails, we get a KeyError at create_all()
        """

        consumer_uuid = uuidsentinel.consumer
        consumer_uuid2 = uuidsentinel.consumer2

        # Create one resource provider with 2 classes
        rp1_name = uuidsentinel.rp1_name
        rp1_uuid = uuidsentinel.rp1_uuid
        rp1_class = fields.ResourceClass.DISK_GB
        rp1_used = 6

        rp2_class = fields.ResourceClass.IPV4_ADDRESS
        rp2_used = 2

        rp1 = objects.ResourceProvider(self.context,
                                       name=rp1_name,
                                       uuid=rp1_uuid)
        rp1.create()

        inv = objects.Inventory(resource_provider=rp1,
                                resource_class=rp1_class,
                                total=1024)
        inv.obj_set_defaults()

        inv2 = objects.Inventory(resource_provider=rp1,
                                 resource_class=rp2_class,
                                 total=255,
                                 reserved=2)
        inv2.obj_set_defaults()
        inv_list = objects.InventoryList(objects=[inv, inv2])
        rp1.set_inventory(inv_list)

        # create the allocations for a first consumer
        allocation_1 = objects.Allocation(resource_provider=rp1,
                                          consumer_id=consumer_uuid,
                                          resource_class=rp1_class,
                                          used=rp1_used)
        allocation_2 = objects.Allocation(resource_provider=rp1,
                                          consumer_id=consumer_uuid,
                                          resource_class=rp2_class,
                                          used=rp2_used)
        allocation_list = objects.AllocationList(
            self.context, objects=[allocation_1, allocation_2])
        allocation_list.create_all()

        # create the allocations for a second consumer, until we have
        # allocations for more than one consumer in the db, then we
        # won't actually be doing real allocation math, which triggers
        # the sql monster.
        allocation_1 = objects.Allocation(resource_provider=rp1,
                                          consumer_id=consumer_uuid2,
                                          resource_class=rp1_class,
                                          used=rp1_used)
        allocation_2 = objects.Allocation(resource_provider=rp1,
                                          consumer_id=consumer_uuid2,
                                          resource_class=rp2_class,
                                          used=rp2_used)
        allocation_list = objects.AllocationList(
            self.context, objects=[allocation_1, allocation_2])
        # If we are joining wrong, this will be a KeyError
        allocation_list.create_all()
Beispiel #20
0
    def test_provider_set_inventory(self):
        rp = objects.ResourceProvider(context=self.context,
                                      uuid=uuidsentinel.rp_uuid,
                                      name=uuidsentinel.rp_name)
        rp.create()
        saved_generation = rp.generation

        disk_inv = objects.Inventory(
            resource_provider=rp,
            resource_class=fields.ResourceClass.DISK_GB,
            total=1024,
            reserved=15,
            min_unit=10,
            max_unit=100,
            step_size=10,
            allocation_ratio=1.0)

        vcpu_inv = objects.Inventory(resource_provider=rp,
                                     resource_class=fields.ResourceClass.VCPU,
                                     total=12,
                                     reserved=0,
                                     min_unit=1,
                                     max_unit=12,
                                     step_size=1,
                                     allocation_ratio=16.0)

        # set to new list
        inv_list = objects.InventoryList(objects=[disk_inv, vcpu_inv])
        rp.set_inventory(inv_list)

        # generation has bumped
        self.assertEqual(saved_generation + 1, rp.generation)
        saved_generation = rp.generation

        new_inv_list = objects.InventoryList.get_all_by_resource_provider_uuid(
            self.context, uuidsentinel.rp_uuid)
        self.assertEqual(2, len(new_inv_list))
        resource_classes = [inv.resource_class for inv in new_inv_list]
        self.assertIn(fields.ResourceClass.VCPU, resource_classes)
        self.assertIn(fields.ResourceClass.DISK_GB, resource_classes)

        # reset list to just disk_inv
        inv_list = objects.InventoryList(objects=[disk_inv])
        rp.set_inventory(inv_list)

        # generation has bumped
        self.assertEqual(saved_generation + 1, rp.generation)
        saved_generation = rp.generation

        new_inv_list = objects.InventoryList.get_all_by_resource_provider_uuid(
            self.context, uuidsentinel.rp_uuid)
        self.assertEqual(1, len(new_inv_list))
        resource_classes = [inv.resource_class for inv in new_inv_list]
        self.assertNotIn(fields.ResourceClass.VCPU, resource_classes)
        self.assertIn(fields.ResourceClass.DISK_GB, resource_classes)
        self.assertEqual(1024, new_inv_list[0].total)

        # update existing disk inv to new settings
        disk_inv = objects.Inventory(
            resource_provider=rp,
            resource_class=fields.ResourceClass.DISK_GB,
            total=2048,
            reserved=15,
            min_unit=10,
            max_unit=100,
            step_size=10,
            allocation_ratio=1.0)
        inv_list = objects.InventoryList(objects=[disk_inv])
        rp.set_inventory(inv_list)

        # generation has bumped
        self.assertEqual(saved_generation + 1, rp.generation)
        saved_generation = rp.generation

        new_inv_list = objects.InventoryList.get_all_by_resource_provider_uuid(
            self.context, uuidsentinel.rp_uuid)
        self.assertEqual(1, len(new_inv_list))
        self.assertEqual(2048, new_inv_list[0].total)

        # fail when generation wrong
        rp.generation = rp.generation - 1
        self.assertRaises(exception.ConcurrentUpdateDetected, rp.set_inventory,
                          inv_list)
    def start_fixture(self):
        super(SharedStorageFixture, self).start_fixture()
        self.context = context.get_admin_context()

        cn1_uuid = uuidutils.generate_uuid()
        cn2_uuid = uuidutils.generate_uuid()
        ss_uuid = uuidutils.generate_uuid()
        agg_uuid = uuidutils.generate_uuid()
        os.environ['CN1_UUID'] = cn1_uuid
        os.environ['CN2_UUID'] = cn2_uuid
        os.environ['SS_UUID'] = ss_uuid
        os.environ['AGG_UUID'] = agg_uuid

        cn1 = objects.ResourceProvider(self.context, name='cn1', uuid=cn1_uuid)
        cn1.create()

        cn2 = objects.ResourceProvider(self.context, name='cn2', uuid=cn2_uuid)
        cn2.create()

        ss = objects.ResourceProvider(self.context, name='ss', uuid=ss_uuid)
        ss.create()

        # Populate compute node inventory for VCPU and RAM
        for cn in (cn1, cn2):
            vcpu_inv = objects.Inventory(self.context,
                                         resource_provider=cn,
                                         resource_class='VCPU',
                                         total=24,
                                         reserved=0,
                                         max_unit=24,
                                         min_unit=1,
                                         step_size=1,
                                         allocation_ratio=16.0)
            vcpu_inv.obj_set_defaults()
            ram_inv = objects.Inventory(self.context,
                                        resource_provider=cn,
                                        resource_class='MEMORY_MB',
                                        total=128 * 1024,
                                        reserved=0,
                                        max_unit=128 * 1024,
                                        min_unit=256,
                                        step_size=256,
                                        allocation_ratio=1.5)
            ram_inv.obj_set_defaults()
            inv_list = objects.InventoryList(objects=[vcpu_inv, ram_inv])
            cn.set_inventory(inv_list)

        # Populate shared storage provider with DISK_GB inventory
        disk_inv = objects.Inventory(self.context,
                                     resource_provider=ss,
                                     resource_class='DISK_GB',
                                     total=2000,
                                     reserved=100,
                                     max_unit=2000,
                                     min_unit=10,
                                     step_size=10,
                                     allocation_ratio=1.0)
        disk_inv.obj_set_defaults()
        inv_list = objects.InventoryList(objects=[disk_inv])
        ss.set_inventory(inv_list)

        # Mark the shared storage pool as having inventory shared among any
        # provider associated via aggregate
        t = objects.Trait.get_by_name(
            self.context,
            "MISC_SHARES_VIA_AGGREGATE",
        )
        ss.set_traits(objects.TraitList(objects=[t]))

        # Now associate the shared storage pool and both compute nodes with the
        # same aggregate
        cn1.set_aggregates([agg_uuid])
        cn2.set_aggregates([agg_uuid])
        ss.set_aggregates([agg_uuid])