Merge "Move Inventory and InventoryList to own file"

This commit is contained in:
Zuul 2019-03-15 07:48:43 +00:00 committed by Gerrit Code Review
commit 2a21fbdae9
13 changed files with 325 additions and 274 deletions

View File

@ -24,6 +24,7 @@ from placement import errors
from placement import exception
from placement.i18n import _
from placement import microversion
from placement.objects import inventory as inv_obj
from placement.objects import resource_provider as rp_obj
from placement.policies import inventory as policies
from placement.schemas import inventory as schema
@ -82,7 +83,7 @@ def make_inventory_object(resource_provider, resource_class, **data):
# 0) for non-negative integers. It's not clear if that is
# duplication or decoupling so leaving it as this for now.
try:
inventory = rp_obj.Inventory(
inventory = inv_obj.Inventory(
resource_provider=resource_provider,
resource_class=resource_class, **data)
except (ValueError, TypeError) as exc:
@ -165,8 +166,8 @@ def _validate_inventory_capacity(version, inventories):
else:
op = operator.lt
exc_class = exception.InvalidInventoryCapacityReservedCanBeTotal
if isinstance(inventories, rp_obj.Inventory):
inventories = rp_obj.InventoryList(objects=[inventories])
if isinstance(inventories, inv_obj.Inventory):
inventories = inv_obj.InventoryList(objects=[inventories])
for inventory in inventories:
if op(inventory.capacity, 0):
raise exc_class(
@ -271,7 +272,7 @@ def get_inventories(req):
_("No resource provider with uuid %(uuid)s found : %(error)s") %
{'uuid': uuid, 'error': exc})
inv_list = rp_obj.InventoryList.get_all_by_resource_provider(context, rp)
inv_list = inv_obj.InventoryList.get_all_by_resource_provider(context, rp)
return _send_inventories(req, rp, inv_list)
@ -295,7 +296,7 @@ def get_inventory(req):
_("No resource provider with uuid %(uuid)s found : %(error)s") %
{'uuid': uuid, 'error': exc})
inv_list = rp_obj.InventoryList.get_all_by_resource_provider(context, rp)
inv_list = inv_obj.InventoryList.get_all_by_resource_provider(context, rp)
inventory = inv_list.find(resource_class)
if not inventory:
@ -339,7 +340,7 @@ def set_inventories(req):
inventory = make_inventory_object(
resource_provider, res_class, **inventory_data)
inv_list.append(inventory)
inventories = rp_obj.InventoryList(objects=inv_list)
inventories = inv_obj.InventoryList(objects=inv_list)
try:
_validate_inventory_capacity(
@ -390,7 +391,7 @@ def delete_inventories(req):
resource_provider = rp_obj.ResourceProvider.get_by_uuid(
context, uuid)
inventories = rp_obj.InventoryList(objects=[])
inventories = inv_obj.InventoryList(objects=[])
try:
resource_provider.set_inventory(inventories)

View File

@ -30,6 +30,7 @@ from placement.handlers import allocation
from placement.handlers import inventory
from placement.i18n import _
from placement import microversion
from placement.objects import inventory as inv_obj
from placement.objects import reshaper
from placement.objects import resource_provider as rp_obj
from placement.policies import reshaper as policies
@ -78,10 +79,10 @@ def reshape(req):
for res_class, raw_inventory in inventory_data['inventories'].items():
inv_data = copy.copy(inventory.INVENTORY_DEFAULTS)
inv_data.update(raw_inventory)
inv_obj = inventory.make_inventory_object(
inv_object = inventory.make_inventory_object(
resource_provider, res_class, **inv_data)
inv_list.append(inv_obj)
inventory_by_rp[resource_provider] = rp_obj.InventoryList(
inv_list.append(inv_object)
inventory_by_rp[resource_provider] = inv_obj.InventoryList(
objects=inv_list)
# Make the consumer objects associated with the allocations.

View File

@ -0,0 +1,107 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import six
import sqlalchemy as sa
from placement.db.sqlalchemy import models
from placement import db_api
from placement.objects import common as common_obj
from placement import resource_class_cache as rc_cache
_INV_TBL = models.Inventory.__table__
class Inventory(object):
# kwargs included because some constructors pass resource_class_id
# but it is not used.
def __init__(self, id=None, resource_provider=None, resource_class=None,
total=None, reserved=0, min_unit=1, max_unit=1, step_size=1,
allocation_ratio=1.0, updated_at=None, created_at=None,
**kwargs):
self.id = id
self.resource_provider = resource_provider
self.resource_class = resource_class
self.total = total
self.reserved = reserved
self.min_unit = min_unit
self.max_unit = max_unit
self.step_size = step_size
self.allocation_ratio = allocation_ratio
self.updated_at = updated_at
self.created_at = created_at
@property
def capacity(self):
"""Inventory capacity, adjusted by allocation_ratio."""
return int((self.total - self.reserved) * self.allocation_ratio)
class InventoryList(common_obj.ObjectList):
ITEM_CLS = Inventory
def find(self, res_class):
"""Return the inventory record from the list of Inventory records that
matches the supplied resource class, or None.
:param res_class: An integer or string representing a resource
class. If the value is a string, the method first
looks up the resource class identifier from the
string.
"""
if not isinstance(res_class, six.string_types):
raise ValueError
for inv_rec in self.objects:
if inv_rec.resource_class == res_class:
return inv_rec
@classmethod
def get_all_by_resource_provider(cls, context, rp):
db_inv = _get_inventory_by_provider_id(context, rp.id)
# Build up a list of Inventory objects, setting the Inventory object
# fields to the same-named database record field we got from
# _get_inventory_by_provider_id(). We already have the ResourceProvider
# object so we just pass that object to the Inventory object
# constructor as-is
objs = [
Inventory(
resource_provider=rp,
resource_class=rc_cache.RC_CACHE.string_from_id(
rec['resource_class_id']),
**rec)
for rec in db_inv
]
inv_list = cls(objects=objs)
return inv_list
@db_api.placement_context_manager.reader
def _get_inventory_by_provider_id(ctx, rp_id):
inv = sa.alias(_INV_TBL, name="i")
cols = [
inv.c.resource_class_id,
inv.c.total,
inv.c.reserved,
inv.c.min_unit,
inv.c.max_unit,
inv.c.step_size,
inv.c.allocation_ratio,
inv.c.updated_at,
inv.c.created_at,
]
sel = sa.select(cols)
sel = sel.where(inv.c.resource_provider_id == rp_id)
return [dict(r) for r in ctx.session.execute(sel)]

View File

@ -13,7 +13,7 @@ from oslo_log import log as logging
from placement import db_api
from placement.objects import allocation as alloc_obj
from placement.objects import resource_provider as rp_obj
from placement.objects import inventory as inv_obj
LOG = logging.getLogger(__name__)
@ -84,7 +84,7 @@ def reshape(ctx, inventories, allocations):
# with the original inventory list.
inv_by_rc = {
inv.resource_class: inv for inv in
rp_obj.InventoryList.get_all_by_resource_provider(ctx, rp)}
inv_obj.InventoryList.get_all_by_resource_provider(ctx, rp)}
# Now add each inventory in the new inventory list. If an inventory for
# that resource class existed in the original inventory list, it is
# overwritten.
@ -92,7 +92,7 @@ def reshape(ctx, inventories, allocations):
inv_by_rc[inv.resource_class] = inv
# Set the interim inventory structure.
rp.set_inventory(
rp_obj.InventoryList(objects=list(inv_by_rc.values())))
inv_obj.InventoryList(objects=list(inv_by_rc.values())))
# NOTE(jaypipes): The above inventory replacements will have
# incremented the resource provider generations, so we need to look in

View File

@ -35,6 +35,7 @@ from placement import db_api
from placement import exception
from placement.i18n import _
from placement.objects import common as common_obj
from placement.objects import inventory as inv_obj
from placement.objects import rp_candidates
from placement.objects import trait as trait_obj
from placement import resource_class_cache as rc_cache
@ -197,7 +198,7 @@ def _add_inventory(context, rp, inventory):
cannot be found in the DB.
"""
rc_id = rc_cache.RC_CACHE.id_from_string(inventory.resource_class)
inv_list = InventoryList(objects=[inventory])
inv_list = inv_obj.InventoryList(objects=[inventory])
_add_inventory_to_provider(
context, rp, inv_list, set([rc_id]))
rp.increment_generation()
@ -211,7 +212,7 @@ def _update_inventory(context, rp, inventory):
cannot be found in the DB.
"""
rc_id = rc_cache.RC_CACHE.id_from_string(inventory.resource_class)
inv_list = InventoryList(objects=[inventory])
inv_list = inv_obj.InventoryList(objects=[inventory])
exceeded = _update_inventory_for_provider(
context, rp, inv_list, set([rc_id]))
rp.increment_generation()
@ -1485,91 +1486,6 @@ class ResourceProviderList(common_obj.ObjectList):
return cls._set_objects(context, resource_providers)
class Inventory(object):
# kwargs included because some constructors pass resource_class_id
# but it is not used.
def __init__(self, id=None, resource_provider=None, resource_class=None,
total=None, reserved=0, min_unit=1, max_unit=1, step_size=1,
allocation_ratio=1.0, updated_at=None, created_at=None,
**kwargs):
self.id = id
self.resource_provider = resource_provider
self.resource_class = resource_class
self.total = total
self.reserved = reserved
self.min_unit = min_unit
self.max_unit = max_unit
self.step_size = step_size
self.allocation_ratio = allocation_ratio
self.updated_at = updated_at
self.created_at = created_at
@property
def capacity(self):
"""Inventory capacity, adjusted by allocation_ratio."""
return int((self.total - self.reserved) * self.allocation_ratio)
@db_api.placement_context_manager.reader
def _get_inventory_by_provider_id(ctx, rp_id):
inv = sa.alias(_INV_TBL, name="i")
cols = [
inv.c.resource_class_id,
inv.c.total,
inv.c.reserved,
inv.c.min_unit,
inv.c.max_unit,
inv.c.step_size,
inv.c.allocation_ratio,
inv.c.updated_at,
inv.c.created_at,
]
sel = sa.select(cols)
sel = sel.where(inv.c.resource_provider_id == rp_id)
return [dict(r) for r in ctx.session.execute(sel)]
class InventoryList(common_obj.ObjectList):
ITEM_CLS = Inventory
def find(self, res_class):
"""Return the inventory record from the list of Inventory records that
matches the supplied resource class, or None.
:param res_class: An integer or string representing a resource
class. If the value is a string, the method first
looks up the resource class identifier from the
string.
"""
if not isinstance(res_class, six.string_types):
raise ValueError
for inv_rec in self.objects:
if inv_rec.resource_class == res_class:
return inv_rec
@classmethod
def get_all_by_resource_provider(cls, context, rp):
db_inv = _get_inventory_by_provider_id(context, rp.id)
# Build up a list of Inventory objects, setting the Inventory object
# fields to the same-named database record field we got from
# _get_inventory_by_provider_id(). We already have the ResourceProvider
# object so we just pass that object to the Inventory object
# constructor as-is
objs = [
Inventory(
resource_provider=rp,
resource_class=rc_cache.RC_CACHE.string_from_id(
rec['resource_class_id']),
**rec)
for rec in db_inv
]
inv_list = cls(objects=objs)
return inv_list
@db_api.placement_context_manager.reader
def get_provider_ids_having_any_trait(ctx, traits):
"""Returns a set of resource provider internal IDs that have ANY of the

View File

@ -17,7 +17,7 @@ from oslo_utils.fixture import uuidsentinel
from placement import exception
from placement.objects import allocation as alloc_obj
from placement.objects import consumer as consumer_obj
from placement.objects import resource_provider as rp_obj
from placement.objects import inventory as inv_obj
from placement.objects import usage as usage_obj
from placement.tests.functional.db import test_base as tb
@ -138,14 +138,14 @@ class TestAllocationListCreateDelete(tb.PlacementDbBaseTestCase):
# Now the allocations will still fail because max_unit 1
self.assertRaises(exception.InvalidAllocationConstraintsViolated,
alloc_obj.replace_all, self.ctx, allocation_list)
inv1 = rp_obj.Inventory(resource_provider=rp1,
resource_class=rp1_class,
total=1024, max_unit=max_unit)
rp1.set_inventory(rp_obj.InventoryList(objects=[inv1]))
inv2 = rp_obj.Inventory(resource_provider=rp2,
resource_class=rp2_class,
total=255, reserved=2, max_unit=max_unit)
rp2.set_inventory(rp_obj.InventoryList(objects=[inv2]))
inv1 = inv_obj.Inventory(resource_provider=rp1,
resource_class=rp1_class,
total=1024, max_unit=max_unit)
rp1.set_inventory(inv_obj.InventoryList(objects=[inv1]))
inv2 = inv_obj.Inventory(resource_provider=rp2,
resource_class=rp2_class,
total=255, reserved=2, max_unit=max_unit)
rp2.set_inventory(inv_obj.InventoryList(objects=[inv2]))
# Now we can finally allocate.
alloc_obj.replace_all(self.ctx, allocation_list)

View File

@ -20,6 +20,7 @@ from oslo_utils import uuidutils
from placement import exception
from placement.objects import allocation as alloc_obj
from placement.objects import consumer as consumer_obj
from placement.objects import inventory as inv_obj
from placement.objects import project as project_obj
from placement.objects import resource_provider as rp_obj
from placement.objects import trait as trait_obj
@ -58,8 +59,8 @@ def create_provider(context, name, *aggs, **kwargs):
def add_inventory(rp, rc, total, **kwargs):
kwargs.setdefault('max_unit', total)
inv = rp_obj.Inventory(rp._context, resource_provider=rp,
resource_class=rc, total=total, **kwargs)
inv = inv_obj.Inventory(rp._context, resource_provider=rp,
resource_class=rc, total=total, **kwargs)
rp.add_inventory(inv)
return inv
@ -141,8 +142,8 @@ class PlacementDbBaseTestCase(base.TestCase):
def _make_allocation(self, inv_dict, alloc_dict):
alloc_dict = copy.copy(alloc_dict)
rp = self._create_provider('allocation_resource_provider')
disk_inv = rp_obj.Inventory(resource_provider=rp, **inv_dict)
inv_list = rp_obj.InventoryList(objects=[disk_inv])
disk_inv = inv_obj.Inventory(resource_provider=rp, **inv_dict)
inv_list = inv_obj.InventoryList(objects=[disk_inv])
rp.set_inventory(inv_list)
consumer_id = alloc_dict.pop('consumer_id')
consumer = ensure_consumer(

View File

@ -14,6 +14,7 @@ from oslo_utils.fixture import uuidsentinel as uuids
from placement import exception
from placement.objects import allocation as alloc_obj
from placement.objects import consumer as consumer_obj
from placement.objects import inventory as inv_obj
from placement.objects import reshaper
from placement.objects import resource_provider as rp_obj
from placement.tests.functional.db import test_base as tb
@ -103,31 +104,31 @@ class ReshapeTestCase(tb.PlacementDbBaseTestCase):
# storage provider.
after_inventories = {
# cn1 keeps the RAM only
cn1: rp_obj.InventoryList(objects=[
rp_obj.Inventory(
cn1: inv_obj.InventoryList(objects=[
inv_obj.Inventory(
resource_provider=cn1,
resource_class='MEMORY_MB', total=32768, reserved=0,
max_unit=32768, min_unit=1, step_size=1,
allocation_ratio=1.0),
]),
# each NUMA node gets half of the CPUs
cn1_numa0: rp_obj.InventoryList(objects=[
rp_obj.Inventory(
cn1_numa0: inv_obj.InventoryList(objects=[
inv_obj.Inventory(
resource_provider=cn1_numa0,
resource_class='VCPU', total=8, reserved=0,
max_unit=8, min_unit=1, step_size=1,
allocation_ratio=1.0),
]),
cn1_numa1: rp_obj.InventoryList(objects=[
rp_obj.Inventory(
cn1_numa1: inv_obj.InventoryList(objects=[
inv_obj.Inventory(
resource_provider=cn1_numa1,
resource_class='VCPU', total=8, reserved=0,
max_unit=8, min_unit=1, step_size=1,
allocation_ratio=1.0),
]),
# The sharing provider gets a bunch of disk
ss: rp_obj.InventoryList(objects=[
rp_obj.Inventory(
ss: inv_obj.InventoryList(objects=[
inv_obj.Inventory(
resource_provider=ss,
resource_class='DISK_GB', total=100000, reserved=0,
max_unit=1000, min_unit=1, step_size=1,
@ -172,24 +173,24 @@ class ReshapeTestCase(tb.PlacementDbBaseTestCase):
# providers in the AFTER scenario
# The root compute node should only have MEMORY_MB, nothing else
cn1_inv = rp_obj.InventoryList.get_all_by_resource_provider(
cn1_inv = inv_obj.InventoryList.get_all_by_resource_provider(
self.ctx, cn1)
self.assertEqual(1, len(cn1_inv))
self.assertEqual('MEMORY_MB', cn1_inv[0].resource_class)
self.assertEqual(32768, cn1_inv[0].total)
# Each NUMA node should only have half the original VCPU, nothing else
numa0_inv = rp_obj.InventoryList.get_all_by_resource_provider(
numa0_inv = inv_obj.InventoryList.get_all_by_resource_provider(
self.ctx, cn1_numa0)
self.assertEqual(1, len(numa0_inv))
self.assertEqual('VCPU', numa0_inv[0].resource_class)
self.assertEqual(8, numa0_inv[0].total)
numa1_inv = rp_obj.InventoryList.get_all_by_resource_provider(
numa1_inv = inv_obj.InventoryList.get_all_by_resource_provider(
self.ctx, cn1_numa1)
self.assertEqual(1, len(numa1_inv))
self.assertEqual('VCPU', numa1_inv[0].resource_class)
self.assertEqual(8, numa1_inv[0].total)
# The sharing storage provider should only have DISK_GB, nothing else
ss_inv = rp_obj.InventoryList.get_all_by_resource_provider(
ss_inv = inv_obj.InventoryList.get_all_by_resource_provider(
self.ctx, ss)
self.assertEqual(1, len(ss_inv))
self.assertEqual('DISK_GB', ss_inv[0].resource_class)
@ -279,31 +280,31 @@ class ReshapeTestCase(tb.PlacementDbBaseTestCase):
# storage provider.
after_inventories = {
# cn1 keeps the RAM only
cn1: rp_obj.InventoryList(objects=[
rp_obj.Inventory(
cn1: inv_obj.InventoryList(objects=[
inv_obj.Inventory(
resource_provider=cn1,
resource_class='MEMORY_MB', total=32768, reserved=0,
max_unit=32768, min_unit=1, step_size=1,
allocation_ratio=1.0),
]),
# each NUMA node gets half of the CPUs
cn1_numa0: rp_obj.InventoryList(objects=[
rp_obj.Inventory(
cn1_numa0: inv_obj.InventoryList(objects=[
inv_obj.Inventory(
resource_provider=cn1_numa0,
resource_class='VCPU', total=8, reserved=0,
max_unit=8, min_unit=1, step_size=1,
allocation_ratio=1.0),
]),
cn1_numa1: rp_obj.InventoryList(objects=[
rp_obj.Inventory(
cn1_numa1: inv_obj.InventoryList(objects=[
inv_obj.Inventory(
resource_provider=cn1_numa1,
resource_class='VCPU', total=8, reserved=0,
max_unit=8, min_unit=1, step_size=1,
allocation_ratio=1.0),
]),
# The sharing provider gets a bunch of disk
ss: rp_obj.InventoryList(objects=[
rp_obj.Inventory(
ss: inv_obj.InventoryList(objects=[
inv_obj.Inventory(
resource_provider=ss,
resource_class='DISK_GB', total=100000, reserved=0,
max_unit=1000, min_unit=1, step_size=1,
@ -337,8 +338,8 @@ class ReshapeTestCase(tb.PlacementDbBaseTestCase):
# generation was validated and the actual call to reshape()
ss_threadB = rp_obj.ResourceProvider.get_by_uuid(self.ctx, ss.uuid)
# Reduce the amount of storage to 2000, from 100000.
new_ss_inv = rp_obj.InventoryList(objects=[
rp_obj.Inventory(
new_ss_inv = inv_obj.InventoryList(objects=[
inv_obj.Inventory(
resource_provider=ss_threadB, resource_class='DISK_GB',
total=2000, reserved=0, max_unit=1000, min_unit=1, step_size=1,
allocation_ratio=1.0)])

View File

@ -17,6 +17,7 @@ from oslo_utils.fixture import uuidsentinel
import placement
from placement import exception
from placement.objects import inventory as inv_obj
from placement.objects import resource_class as rc_obj
from placement.objects import resource_provider as rp_obj
from placement.tests.functional.db import test_base as tb
@ -221,18 +222,18 @@ class ResourceClassTestCase(tb.PlacementDbBaseTestCase):
uuid=uuidsentinel.rp,
)
rp.create()
inv = rp_obj.Inventory(
inv = inv_obj.Inventory(
resource_provider=rp,
resource_class='CUSTOM_IRON_NFV',
total=1,
)
inv_list = rp_obj.InventoryList(objects=[inv])
inv_list = inv_obj.InventoryList(objects=[inv])
rp.set_inventory(inv_list)
self.assertRaises(exception.ResourceClassInUse,
rc.destroy)
rp.set_inventory(rp_obj.InventoryList(objects=[]))
rp.set_inventory(inv_obj.InventoryList(objects=[]))
rc.destroy()
rc_list = rc_obj.get_all(self.ctx)
rc_ids = (r.id for r in rc_list)

View File

@ -21,6 +21,7 @@ from placement.db.sqlalchemy import models
from placement import exception
from placement.objects import allocation as alloc_obj
from placement.objects import consumer as consumer_obj
from placement.objects import inventory as inv_obj
from placement.objects import resource_provider as rp_obj
from placement.objects import trait as trait_obj
from placement.objects import usage as usage_obj
@ -523,11 +524,11 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
tb.add_inventory(resource_provider,
tb.DISK_INVENTORY['resource_class'],
tb.DISK_INVENTORY['total'])
inventories = rp_obj.InventoryList.get_all_by_resource_provider(
inventories = inv_obj.InventoryList.get_all_by_resource_provider(
self.ctx, resource_provider)
self.assertEqual(1, len(inventories))
resource_provider.destroy()
inventories = rp_obj.InventoryList.get_all_by_resource_provider(
inventories = inv_obj.InventoryList.get_all_by_resource_provider(
self.ctx, resource_provider)
self.assertEqual(0, len(inventories))
@ -576,7 +577,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
tb.add_inventory(rp, 'VCPU', 12)
self.allocate_from_provider(rp, 'VCPU', 1)
inv = rp_obj.Inventory(
inv = inv_obj.Inventory(
resource_provider=rp,
resource_class='MEMORY_MB',
total=1024,
@ -587,7 +588,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
allocation_ratio=1.0,
)
inv_list = rp_obj.InventoryList(objects=[inv])
inv_list = inv_obj.InventoryList(objects=[inv])
self.assertRaises(exception.InventoryInUse,
rp.set_inventory,
inv_list)
@ -611,7 +612,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
# Update our inventory to over-subscribe us after the above allocation
disk_inv.total = 400
rp.set_inventory(rp_obj.InventoryList(objects=[disk_inv, vcpu_inv]))
rp.set_inventory(inv_obj.InventoryList(objects=[disk_inv, vcpu_inv]))
# We should succeed, but have logged a warning for going over on disk
mock_log.warning.assert_called_once_with(
@ -634,7 +635,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
self.assertEqual(saved_generation + 2, rp.generation)
saved_generation = rp.generation
new_inv_list = rp_obj.InventoryList.get_all_by_resource_provider(
new_inv_list = inv_obj.InventoryList.get_all_by_resource_provider(
self.ctx, rp)
self.assertEqual(2, len(new_inv_list))
resource_classes = [inv.resource_class for inv in new_inv_list]
@ -642,14 +643,14 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
self.assertIn(orc.DISK_GB, resource_classes)
# reset list to just disk_inv
inv_list = rp_obj.InventoryList(objects=[disk_inv])
inv_list = inv_obj.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 = rp_obj.InventoryList.get_all_by_resource_provider(
new_inv_list = inv_obj.InventoryList.get_all_by_resource_provider(
self.ctx, rp)
self.assertEqual(1, len(new_inv_list))
resource_classes = [inv.resource_class for inv in new_inv_list]
@ -658,7 +659,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
self.assertEqual(1024, new_inv_list[0].total)
# update existing disk inv to new settings
disk_inv = rp_obj.Inventory(
disk_inv = inv_obj.Inventory(
resource_provider=rp,
resource_class=orc.DISK_GB,
total=2048,
@ -673,7 +674,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
self.assertEqual(saved_generation + 1, rp.generation)
saved_generation = rp.generation
new_inv_list = rp_obj.InventoryList.get_all_by_resource_provider(
new_inv_list = inv_obj.InventoryList.get_all_by_resource_provider(
self.ctx, rp)
self.assertEqual(1, len(new_inv_list))
self.assertEqual(2048, new_inv_list[0].total)
@ -685,7 +686,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
self.assertEqual(saved_generation + 1, rp.generation)
saved_generation = rp.generation
new_inv_list = rp_obj.InventoryList.get_all_by_resource_provider(
new_inv_list = inv_obj.InventoryList.get_all_by_resource_provider(
self.ctx, rp)
result = new_inv_list.find(orc.DISK_GB)
self.assertIsNone(result)
@ -693,13 +694,13 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
orc.DISK_GB)
# check inventory list is empty
inv_list = rp_obj.InventoryList.get_all_by_resource_provider(
inv_list = inv_obj.InventoryList.get_all_by_resource_provider(
self.ctx, rp)
self.assertEqual(0, len(inv_list))
# add some inventory
rp.add_inventory(vcpu_inv)
inv_list = rp_obj.InventoryList.get_all_by_resource_provider(
inv_list = inv_obj.InventoryList.get_all_by_resource_provider(
self.ctx, rp)
self.assertEqual(1, len(inv_list))
@ -738,9 +739,9 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
def test_update_inventory_not_found(self):
rp = self._create_provider(uuidsentinel.rp_name)
disk_inv = rp_obj.Inventory(resource_provider=rp,
resource_class='DISK_GB',
total=2048)
disk_inv = inv_obj.Inventory(resource_provider=rp,
resource_class='DISK_GB',
total=2048)
error = self.assertRaises(exception.NotFound, rp.update_inventory,
disk_inv)
self.assertIn('No inventory of class DISK_GB found',
@ -756,7 +757,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
# attempt to set inventory to less than currently allocated
# amounts
new_total = 1
disk_inv = rp_obj.Inventory(
disk_inv = inv_obj.Inventory(
resource_provider=rp,
resource_class=orc.DISK_GB, total=new_total)
rp.update_inventory(disk_inv)
@ -765,7 +766,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
self.ctx, rp.uuid)
self.assertEqual(allocation.used, usages[0].usage)
inv_list = rp_obj.InventoryList.get_all_by_resource_provider(
inv_list = inv_obj.InventoryList.get_all_by_resource_provider(
self.ctx, rp)
self.assertEqual(new_total, inv_list[0].total)
mock_log.warning.assert_called_once_with(
@ -792,7 +793,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
# Get inventories for the first resource provider and validate
# the inventory records have a matching resource provider
got_inv = rp_obj.InventoryList.get_all_by_resource_provider(
got_inv = inv_obj.InventoryList.get_all_by_resource_provider(
self.ctx, rp1)
for inv in got_inv:
self.assertEqual(rp1.id, inv.resource_provider.id)

View File

@ -13,7 +13,7 @@
import os_resource_classes as orc
from oslo_utils.fixture import uuidsentinel
from placement.objects import resource_provider as rp_obj
from placement.objects import inventory as inv_obj
from placement.objects import usage as usage_obj
from placement.tests.functional.db import test_base as tb
@ -31,10 +31,10 @@ class UsageListTestCase(tb.PlacementDbBaseTestCase):
def test_get_all_one_allocation(self):
db_rp, _ = self._make_allocation(tb.DISK_INVENTORY,
tb.DISK_ALLOCATION)
inv = rp_obj.Inventory(resource_provider=db_rp,
resource_class=orc.DISK_GB,
total=1024)
inv_list = rp_obj.InventoryList(objects=[inv])
inv = inv_obj.Inventory(resource_provider=db_rp,
resource_class=orc.DISK_GB,
total=1024)
inv_list = inv_obj.InventoryList(objects=[inv])
db_rp.set_inventory(inv_list)
usages = usage_obj.get_all_by_resource_provider_uuid(

View File

@ -0,0 +1,134 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
import os_resource_classes as orc
from oslo_utils.fixture import uuidsentinel as uuids
from oslo_utils import timeutils
from placement.objects import inventory
from placement.objects import resource_provider
from placement.tests.unit.objects import base
_RESOURCE_CLASS_NAME = 'DISK_GB'
_RESOURCE_CLASS_ID = 2
_RESOURCE_PROVIDER_ID = 1
_RESOURCE_PROVIDER_UUID = uuids.resource_provider
VCPU_ID = orc.STANDARDS.index(
orc.VCPU)
_INVENTORY_ID = 2
_INVENTORY_DB = {
'id': _INVENTORY_ID,
'resource_provider_id': _RESOURCE_PROVIDER_ID,
'resource_class_id': _RESOURCE_CLASS_ID,
'total': 16,
'reserved': 2,
'min_unit': 1,
'max_unit': 8,
'step_size': 1,
'allocation_ratio': 1.0,
'updated_at': None,
'created_at': timeutils.utcnow(with_timezone=True),
}
class TestInventoryNoDB(base.TestCase):
@mock.patch('placement.resource_class_cache.ensure_rc_cache',
side_effect=base.fake_ensure_cache)
@mock.patch('placement.objects.inventory._get_inventory_by_provider_id')
def test_get_all_by_resource_provider(self, mock_get, mock_ensure_cache):
mock_ensure_cache(self.context)
expected = [dict(_INVENTORY_DB,
resource_provider_id=_RESOURCE_PROVIDER_ID),
dict(_INVENTORY_DB,
id=_INVENTORY_DB['id'] + 1,
resource_provider_id=_RESOURCE_PROVIDER_ID)]
mock_get.return_value = expected
rp = resource_provider.ResourceProvider(self.context,
id=_RESOURCE_PROVIDER_ID,
uuid=_RESOURCE_PROVIDER_UUID)
objs = inventory.InventoryList.get_all_by_resource_provider(
self.context, rp)
self.assertEqual(2, len(objs))
self.assertEqual(_INVENTORY_DB['id'], objs[0].id)
self.assertEqual(_INVENTORY_DB['id'] + 1, objs[1].id)
self.assertEqual(_RESOURCE_PROVIDER_ID, objs[0].resource_provider.id)
def test_set_defaults(self):
rp = resource_provider.ResourceProvider(self.context,
id=_RESOURCE_PROVIDER_ID,
uuid=_RESOURCE_PROVIDER_UUID)
kwargs = dict(resource_provider=rp,
resource_class=_RESOURCE_CLASS_NAME,
total=16)
inv = inventory.Inventory(self.context, **kwargs)
self.assertEqual(0, inv.reserved)
self.assertEqual(1, inv.min_unit)
self.assertEqual(1, inv.max_unit)
self.assertEqual(1, inv.step_size)
self.assertEqual(1.0, inv.allocation_ratio)
def test_capacity(self):
rp = resource_provider.ResourceProvider(self.context,
id=_RESOURCE_PROVIDER_ID,
uuid=_RESOURCE_PROVIDER_UUID)
kwargs = dict(resource_provider=rp,
resource_class=_RESOURCE_CLASS_NAME,
total=16,
reserved=16)
inv = inventory.Inventory(self.context, **kwargs)
self.assertEqual(0, inv.capacity)
inv.reserved = 15
self.assertEqual(1, inv.capacity)
inv.allocation_ratio = 2.0
self.assertEqual(2, inv.capacity)
class TestInventoryList(base.TestCase):
def test_find(self):
rp = resource_provider.ResourceProvider(
self.context, uuid=uuids.rp_uuid)
inv_list = inventory.InventoryList(
objects=[
inventory.Inventory(
resource_provider=rp,
resource_class=orc.VCPU,
total=24),
inventory.Inventory(
resource_provider=rp,
resource_class=orc.MEMORY_MB,
total=10240),
])
found = inv_list.find(orc.MEMORY_MB)
self.assertIsNotNone(found)
self.assertEqual(10240, found.total)
found = inv_list.find(orc.VCPU)
self.assertIsNotNone(found)
self.assertEqual(24, found.total)
found = inv_list.find(orc.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'))

View File

@ -10,8 +10,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import mock
import os_resource_classes as orc
from oslo_utils.fixture import uuidsentinel as uuids
from oslo_utils import timeutils
import six
@ -21,12 +19,7 @@ from placement.objects import resource_provider
from placement.tests.unit.objects import base
_RESOURCE_CLASS_NAME = 'DISK_GB'
_RESOURCE_CLASS_ID = 2
IPV4_ADDRESS_ID = orc.STANDARDS.index(
orc.IPV4_ADDRESS)
VCPU_ID = orc.STANDARDS.index(
orc.VCPU)
_RESOURCE_PROVIDER_ID = 1
_RESOURCE_PROVIDER_UUID = uuids.resource_provider
@ -55,20 +48,6 @@ _RESOURCE_PROVIDER_DB2 = {
}
_INVENTORY_ID = 2
_INVENTORY_DB = {
'id': _INVENTORY_ID,
'resource_provider_id': _RESOURCE_PROVIDER_ID,
'resource_class_id': _RESOURCE_CLASS_ID,
'total': 16,
'reserved': 2,
'min_unit': 1,
'max_unit': 8,
'step_size': 1,
'allocation_ratio': 1.0,
'updated_at': None,
'created_at': timeutils.utcnow(with_timezone=True),
}
_ALLOCATION_ID = 2
_ALLOCATION_DB = {
'id': _ALLOCATION_ID,
@ -119,94 +98,3 @@ class TestResourceProviderNoDB(base.TestCase):
obj = resource_provider.ResourceProvider(context=self.context)
self.assertRaises(exception.ObjectActionError,
obj.create)
class TestInventoryNoDB(base.TestCase):
@mock.patch('placement.resource_class_cache.ensure_rc_cache',
side_effect=base.fake_ensure_cache)
@mock.patch('placement.objects.resource_provider.'
'_get_inventory_by_provider_id')
def test_get_all_by_resource_provider(self, mock_get, mock_ensure_cache):
mock_ensure_cache(self.context)
expected = [dict(_INVENTORY_DB,
resource_provider_id=_RESOURCE_PROVIDER_ID),
dict(_INVENTORY_DB,
id=_INVENTORY_DB['id'] + 1,
resource_provider_id=_RESOURCE_PROVIDER_ID)]
mock_get.return_value = expected
rp = resource_provider.ResourceProvider(self.context,
id=_RESOURCE_PROVIDER_ID,
uuid=_RESOURCE_PROVIDER_UUID)
objs = resource_provider.InventoryList.get_all_by_resource_provider(
self.context, rp)
self.assertEqual(2, len(objs))
self.assertEqual(_INVENTORY_DB['id'], objs[0].id)
self.assertEqual(_INVENTORY_DB['id'] + 1, objs[1].id)
self.assertEqual(_RESOURCE_PROVIDER_ID, objs[0].resource_provider.id)
def test_set_defaults(self):
rp = resource_provider.ResourceProvider(self.context,
id=_RESOURCE_PROVIDER_ID,
uuid=_RESOURCE_PROVIDER_UUID)
kwargs = dict(resource_provider=rp,
resource_class=_RESOURCE_CLASS_NAME,
total=16)
inv = resource_provider.Inventory(self.context, **kwargs)
self.assertEqual(0, inv.reserved)
self.assertEqual(1, inv.min_unit)
self.assertEqual(1, inv.max_unit)
self.assertEqual(1, inv.step_size)
self.assertEqual(1.0, inv.allocation_ratio)
def test_capacity(self):
rp = resource_provider.ResourceProvider(self.context,
id=_RESOURCE_PROVIDER_ID,
uuid=_RESOURCE_PROVIDER_UUID)
kwargs = dict(resource_provider=rp,
resource_class=_RESOURCE_CLASS_NAME,
total=16,
reserved=16)
inv = resource_provider.Inventory(self.context, **kwargs)
self.assertEqual(0, inv.capacity)
inv.reserved = 15
self.assertEqual(1, inv.capacity)
inv.allocation_ratio = 2.0
self.assertEqual(2, inv.capacity)
class TestInventoryList(base.TestCase):
def test_find(self):
rp = resource_provider.ResourceProvider(
self.context, uuid=uuids.rp_uuid)
inv_list = resource_provider.InventoryList(
objects=[
resource_provider.Inventory(
resource_provider=rp,
resource_class=orc.VCPU,
total=24),
resource_provider.Inventory(
resource_provider=rp,
resource_class=orc.MEMORY_MB,
total=10240),
])
found = inv_list.find(orc.MEMORY_MB)
self.assertIsNotNone(found)
self.assertEqual(10240, found.total)
found = inv_list.find(orc.VCPU)
self.assertIsNotNone(found)
self.assertEqual(24, found.total)
found = inv_list.find(orc.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'))