nova/nova/tests/unit/compute/test_provider_tree.py
LuyaoZhong f45368e02f Add resources dict into _Provider
Add resources dict into _Provider, which is similar to inventory,
and _Provider.resources will contain some resource details but not
resource amount in inventory, which will be Resource object set
keyed by resource class. We can populate this from update provider
tree.

Change-Id: If37aaff1e3652692fd0750e98612f3b040019042
Partially-Implements: blueprint virtual-persistent-memory
Co-Authored-By: He Jie Xu <hejie.xu@intel.com>
2019-09-13 08:50:35 +00:00

729 lines
28 KiB
Python

# 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.
from oslo_utils.fixture import uuidsentinel as uuids
from nova.compute import provider_tree
from nova import objects
from nova import test
class TestProviderTree(test.NoDBTestCase):
def setUp(self):
super(TestProviderTree, self).setUp()
self.compute_node1 = objects.ComputeNode(
uuid=uuids.cn1,
hypervisor_hostname='compute-node-1',
)
self.compute_node2 = objects.ComputeNode(
uuid=uuids.cn2,
hypervisor_hostname='compute-node-2',
)
self.compute_nodes = objects.ComputeNodeList(
objects=[self.compute_node1, self.compute_node2],
)
def _pt_with_cns(self):
pt = provider_tree.ProviderTree()
for cn in self.compute_nodes:
pt.new_root(cn.hypervisor_hostname, cn.uuid, generation=0)
return pt
def test_tree_ops(self):
cn1 = self.compute_node1
cn2 = self.compute_node2
pt = self._pt_with_cns()
self.assertRaises(
ValueError,
pt.new_root,
cn1.hypervisor_hostname,
cn1.uuid,
)
self.assertTrue(pt.exists(cn1.uuid))
self.assertTrue(pt.exists(cn1.hypervisor_hostname))
self.assertFalse(pt.exists(uuids.non_existing_rp))
self.assertFalse(pt.exists('noexist'))
self.assertEqual([cn1.uuid],
pt.get_provider_uuids(name_or_uuid=cn1.uuid))
# Same with ..._in_tree
self.assertEqual([cn1.uuid], pt.get_provider_uuids_in_tree(cn1.uuid))
self.assertEqual(set([cn1.uuid, cn2.uuid]),
set(pt.get_provider_uuids()))
numa_cell0_uuid = pt.new_child('numa_cell0', cn1.uuid)
numa_cell1_uuid = pt.new_child('numa_cell1', cn1.hypervisor_hostname)
self.assertEqual(cn1.uuid, pt.data(numa_cell1_uuid).parent_uuid)
self.assertTrue(pt.exists(numa_cell0_uuid))
self.assertTrue(pt.exists('numa_cell0'))
self.assertTrue(pt.exists(numa_cell1_uuid))
self.assertTrue(pt.exists('numa_cell1'))
pf1_cell0_uuid = pt.new_child('pf1_cell0', numa_cell0_uuid)
self.assertTrue(pt.exists(pf1_cell0_uuid))
self.assertTrue(pt.exists('pf1_cell0'))
# Now we've got a 3-level tree under cn1 - check provider UUIDs again
all_cn1 = [cn1.uuid, numa_cell0_uuid, pf1_cell0_uuid, numa_cell1_uuid]
self.assertEqual(
set(all_cn1),
set(pt.get_provider_uuids(name_or_uuid=cn1.uuid)))
# Same with ..._in_tree if we're asking for the root
self.assertEqual(
set(all_cn1),
set(pt.get_provider_uuids_in_tree(cn1.uuid)))
# Asking for a subtree.
self.assertEqual(
[numa_cell0_uuid, pf1_cell0_uuid],
pt.get_provider_uuids(name_or_uuid=numa_cell0_uuid))
# With ..._in_tree, get the whole tree no matter which we specify.
for node in all_cn1:
self.assertEqual(set(all_cn1), set(pt.get_provider_uuids_in_tree(
node)))
# With no provider specified, get everything
self.assertEqual(
set([cn1.uuid, cn2.uuid, numa_cell0_uuid, pf1_cell0_uuid,
numa_cell1_uuid]),
set(pt.get_provider_uuids()))
self.assertRaises(
ValueError,
pt.new_child,
'pf1_cell0',
uuids.non_existing_rp,
)
# Fail attempting to add a child that already exists in the tree
# Existing provider is a child; search by name
self.assertRaises(ValueError, pt.new_child, 'numa_cell0', cn1.uuid)
# Existing provider is a root; search by UUID
self.assertRaises(ValueError, pt.new_child, cn1.uuid, cn2.uuid)
# Test data().
# Root, by UUID
cn1_snap = pt.data(cn1.uuid)
# Fields were faithfully copied
self.assertEqual(cn1.uuid, cn1_snap.uuid)
self.assertEqual(cn1.hypervisor_hostname, cn1_snap.name)
self.assertIsNone(cn1_snap.parent_uuid)
self.assertEqual({}, cn1_snap.inventory)
self.assertEqual(set(), cn1_snap.traits)
self.assertEqual(set(), cn1_snap.aggregates)
# Validate read-only-ness
self.assertRaises(AttributeError, setattr, cn1_snap, 'name', 'foo')
cn3 = objects.ComputeNode(
uuid=uuids.cn3,
hypervisor_hostname='compute-node-3',
)
self.assertFalse(pt.exists(cn3.uuid))
self.assertFalse(pt.exists(cn3.hypervisor_hostname))
pt.new_root(cn3.hypervisor_hostname, cn3.uuid)
self.assertTrue(pt.exists(cn3.uuid))
self.assertTrue(pt.exists(cn3.hypervisor_hostname))
self.assertRaises(
ValueError,
pt.new_root,
cn3.hypervisor_hostname,
cn3.uuid,
)
self.assertRaises(
ValueError,
pt.remove,
uuids.non_existing_rp,
)
pt.remove(numa_cell1_uuid)
self.assertFalse(pt.exists(numa_cell1_uuid))
self.assertTrue(pt.exists(pf1_cell0_uuid))
self.assertTrue(pt.exists(numa_cell0_uuid))
self.assertTrue(pt.exists(uuids.cn1))
# Now remove the root and check that children no longer exist
pt.remove(uuids.cn1)
self.assertFalse(pt.exists(pf1_cell0_uuid))
self.assertFalse(pt.exists(numa_cell0_uuid))
self.assertFalse(pt.exists(uuids.cn1))
def test_populate_from_iterable_empty(self):
pt = provider_tree.ProviderTree()
# Empty list is a no-op
pt.populate_from_iterable([])
self.assertEqual([], pt.get_provider_uuids())
def test_populate_from_iterable_error_orphan_cycle(self):
pt = provider_tree.ProviderTree()
# Error trying to populate with an orphan
grandchild1_1 = {
'uuid': uuids.grandchild1_1,
'name': 'grandchild1_1',
'generation': 11,
'parent_provider_uuid': uuids.child1,
}
self.assertRaises(ValueError,
pt.populate_from_iterable, [grandchild1_1])
# Create a cycle so there are no orphans, but no path to a root
cycle = {
'uuid': uuids.child1,
'name': 'child1',
'generation': 1,
# There's a country song about this
'parent_provider_uuid': uuids.grandchild1_1,
}
self.assertRaises(ValueError,
pt.populate_from_iterable, [grandchild1_1, cycle])
def test_populate_from_iterable_complex(self):
# root
# +-> child1
# | +-> grandchild1_2
# | +-> ggc1_2_1
# | +-> ggc1_2_2
# | +-> ggc1_2_3
# +-> child2
# another_root
pt = provider_tree.ProviderTree()
plist = [
{
'uuid': uuids.root,
'name': 'root',
'generation': 0,
},
{
'uuid': uuids.child1,
'name': 'child1',
'generation': 1,
'parent_provider_uuid': uuids.root,
},
{
'uuid': uuids.child2,
'name': 'child2',
'generation': 2,
'parent_provider_uuid': uuids.root,
},
{
'uuid': uuids.grandchild1_2,
'name': 'grandchild1_2',
'generation': 12,
'parent_provider_uuid': uuids.child1,
},
{
'uuid': uuids.ggc1_2_1,
'name': 'ggc1_2_1',
'generation': 121,
'parent_provider_uuid': uuids.grandchild1_2,
},
{
'uuid': uuids.ggc1_2_2,
'name': 'ggc1_2_2',
'generation': 122,
'parent_provider_uuid': uuids.grandchild1_2,
},
{
'uuid': uuids.ggc1_2_3,
'name': 'ggc1_2_3',
'generation': 123,
'parent_provider_uuid': uuids.grandchild1_2,
},
{
'uuid': uuids.another_root,
'name': 'another_root',
'generation': 911,
},
]
pt.populate_from_iterable(plist)
def validate_root(expected_uuids):
# Make sure we have all and only the expected providers
self.assertEqual(expected_uuids, set(pt.get_provider_uuids()))
# Now make sure they're in the right hierarchy. Cheat: get the
# actual _Provider to make it easier to walk the tree (ProviderData
# doesn't include children).
root = pt._find_with_lock(uuids.root)
self.assertEqual(uuids.root, root.uuid)
self.assertEqual('root', root.name)
self.assertEqual(0, root.generation)
self.assertIsNone(root.parent_uuid)
self.assertEqual(2, len(list(root.children)))
for child in root.children.values():
self.assertTrue(child.name.startswith('child'))
if child.name == 'child1':
if uuids.grandchild1_1 in expected_uuids:
self.assertEqual(2, len(list(child.children)))
else:
self.assertEqual(1, len(list(child.children)))
for grandchild in child.children.values():
self.assertTrue(grandchild.name.startswith(
'grandchild1_'))
if grandchild.name == 'grandchild1_1':
self.assertEqual(0, len(list(grandchild.children)))
if grandchild.name == 'grandchild1_2':
self.assertEqual(3, len(list(grandchild.children)))
for ggc in grandchild.children.values():
self.assertTrue(ggc.name.startswith('ggc1_2_'))
another_root = pt._find_with_lock(uuids.another_root)
self.assertEqual(uuids.another_root, another_root.uuid)
self.assertEqual('another_root', another_root.name)
self.assertEqual(911, another_root.generation)
self.assertIsNone(another_root.parent_uuid)
self.assertEqual(0, len(list(another_root.children)))
if uuids.new_root in expected_uuids:
new_root = pt._find_with_lock(uuids.new_root)
self.assertEqual(uuids.new_root, new_root.uuid)
self.assertEqual('new_root', new_root.name)
self.assertEqual(42, new_root.generation)
self.assertIsNone(new_root.parent_uuid)
self.assertEqual(0, len(list(new_root.children)))
expected_uuids = set([
uuids.root, uuids.child1, uuids.child2, uuids.grandchild1_2,
uuids.ggc1_2_1, uuids.ggc1_2_2, uuids.ggc1_2_3,
uuids.another_root])
validate_root(expected_uuids)
# Merge an orphan - still an error
orphan = {
'uuid': uuids.orphan,
'name': 'orphan',
'generation': 86,
'parent_provider_uuid': uuids.mystery,
}
self.assertRaises(ValueError, pt.populate_from_iterable, [orphan])
# And the tree didn't change
validate_root(expected_uuids)
# Merge a list with a new grandchild and a new root
plist = [
{
'uuid': uuids.grandchild1_1,
'name': 'grandchild1_1',
'generation': 11,
'parent_provider_uuid': uuids.child1,
},
{
'uuid': uuids.new_root,
'name': 'new_root',
'generation': 42,
},
]
pt.populate_from_iterable(plist)
expected_uuids |= set([uuids.grandchild1_1, uuids.new_root])
validate_root(expected_uuids)
# Merge an empty list - still a no-op
pt.populate_from_iterable([])
validate_root(expected_uuids)
# Since we have a complex tree, test the ordering of get_provider_uuids
# We can't predict the order of siblings, or where nephews will appear
# relative to their uncles, but we can guarantee that any given child
# always comes after its parent (and by extension, its ancestors too).
puuids = pt.get_provider_uuids()
for desc in (uuids.child1, uuids.child2):
self.assertGreater(puuids.index(desc), puuids.index(uuids.root))
for desc in (uuids.grandchild1_1, uuids.grandchild1_2):
self.assertGreater(puuids.index(desc), puuids.index(uuids.child1))
for desc in (uuids.ggc1_2_1, uuids.ggc1_2_2, uuids.ggc1_2_3):
self.assertGreater(
puuids.index(desc), puuids.index(uuids.grandchild1_2))
def test_populate_from_iterable_with_root_update(self):
# Ensure we can update hierarchies, including adding children, in a
# tree that's already populated. This tests the case where a given
# provider exists both in the tree and in the input. We must replace
# that provider *before* we inject its descendants; otherwise the
# descendants will be lost. Note that this test case is not 100%
# reliable, as we can't predict the order over which hashed values are
# iterated.
pt = provider_tree.ProviderTree()
# Let's create a root
plist = [
{
'uuid': uuids.root,
'name': 'root',
'generation': 0,
},
]
pt.populate_from_iterable(plist)
expected_uuids = [uuids.root]
self.assertEqual(expected_uuids, pt.get_provider_uuids())
# Let's add a child updating the name and generation for the root.
# root
# +-> child1
plist = [
{
'uuid': uuids.root,
'name': 'root_with_new_name',
'generation': 1,
},
{
'uuid': uuids.child1,
'name': 'child1',
'generation': 1,
'parent_provider_uuid': uuids.root,
},
]
pt.populate_from_iterable(plist)
expected_uuids = [uuids.root, uuids.child1]
self.assertEqual(expected_uuids, pt.get_provider_uuids())
def test_populate_from_iterable_disown_grandchild(self):
# Start with:
# root
# +-> child
# | +-> grandchild
# Then send in [child] and grandchild should disappear.
child = {
'uuid': uuids.child,
'name': 'child',
'generation': 1,
'parent_provider_uuid': uuids.root,
}
pt = provider_tree.ProviderTree()
plist = [
{
'uuid': uuids.root,
'name': 'root',
'generation': 0,
},
child,
{
'uuid': uuids.grandchild,
'name': 'grandchild',
'generation': 2,
'parent_provider_uuid': uuids.child,
},
]
pt.populate_from_iterable(plist)
self.assertEqual([uuids.root, uuids.child, uuids.grandchild],
pt.get_provider_uuids())
self.assertTrue(pt.exists(uuids.grandchild))
pt.populate_from_iterable([child])
self.assertEqual([uuids.root, uuids.child], pt.get_provider_uuids())
self.assertFalse(pt.exists(uuids.grandchild))
def test_has_inventory_changed_no_existing_rp(self):
pt = self._pt_with_cns()
self.assertRaises(
ValueError,
pt.has_inventory_changed,
uuids.non_existing_rp,
{}
)
def test_update_inventory_no_existing_rp(self):
pt = self._pt_with_cns()
self.assertRaises(
ValueError,
pt.update_inventory,
uuids.non_existing_rp,
{},
)
def test_has_inventory_changed(self):
cn = self.compute_node1
pt = self._pt_with_cns()
rp_gen = 1
cn_inv = {
'VCPU': {
'total': 8,
'min_unit': 1,
'max_unit': 8,
'step_size': 1,
'allocation_ratio': 16.0,
},
'MEMORY_MB': {
'total': 1024,
'reserved': 512,
'min_unit': 64,
'max_unit': 1024,
'step_size': 64,
'allocation_ratio': 1.5,
},
'DISK_GB': {
'total': 1000,
'reserved': 100,
'min_unit': 10,
'max_unit': 1000,
'step_size': 10,
'allocation_ratio': 1.0,
},
}
self.assertTrue(pt.has_inventory_changed(cn.uuid, cn_inv))
self.assertTrue(pt.update_inventory(cn.uuid, cn_inv,
generation=rp_gen))
# Updating with the same inventory info should return False
self.assertFalse(pt.has_inventory_changed(cn.uuid, cn_inv))
self.assertFalse(pt.update_inventory(cn.uuid, cn_inv,
generation=rp_gen))
# A data-grab's inventory should be "equal" to the original
cndata = pt.data(cn.uuid)
self.assertFalse(pt.has_inventory_changed(cn.uuid, cndata.inventory))
cn_inv['VCPU']['total'] = 6
self.assertTrue(pt.has_inventory_changed(cn.uuid, cn_inv))
self.assertTrue(pt.update_inventory(cn.uuid, cn_inv,
generation=rp_gen))
# The data() result was not affected; now the tree's copy is different
self.assertTrue(pt.has_inventory_changed(cn.uuid, cndata.inventory))
self.assertFalse(pt.has_inventory_changed(cn.uuid, cn_inv))
self.assertFalse(pt.update_inventory(cn.uuid, cn_inv,
generation=rp_gen))
# Deleting a key in the new record should NOT result in changes being
# recorded...
del cn_inv['VCPU']['allocation_ratio']
self.assertFalse(pt.has_inventory_changed(cn.uuid, cn_inv))
self.assertFalse(pt.update_inventory(cn.uuid, cn_inv,
generation=rp_gen))
del cn_inv['MEMORY_MB']
self.assertTrue(pt.has_inventory_changed(cn.uuid, cn_inv))
self.assertTrue(pt.update_inventory(cn.uuid, cn_inv,
generation=rp_gen))
# ...but *adding* a key in the new record *should* result in changes
# being recorded
cn_inv['VCPU']['reserved'] = 0
self.assertTrue(pt.has_inventory_changed(cn.uuid, cn_inv))
self.assertTrue(pt.update_inventory(cn.uuid, cn_inv,
generation=rp_gen))
def test_have_traits_changed_no_existing_rp(self):
pt = self._pt_with_cns()
self.assertRaises(
ValueError, pt.have_traits_changed, uuids.non_existing_rp, [])
def test_update_traits_no_existing_rp(self):
pt = self._pt_with_cns()
self.assertRaises(
ValueError, pt.update_traits, uuids.non_existing_rp, [])
def test_have_traits_changed(self):
cn = self.compute_node1
pt = self._pt_with_cns()
rp_gen = 1
traits = [
"HW_GPU_API_DIRECT3D_V7_0",
"HW_NIC_OFFLOAD_SG",
"HW_CPU_X86_AVX",
]
self.assertTrue(pt.have_traits_changed(cn.uuid, traits))
# A data-grab's traits are the same
cnsnap = pt.data(cn.uuid)
self.assertFalse(pt.have_traits_changed(cn.uuid, cnsnap.traits))
self.assertTrue(pt.has_traits(cn.uuid, []))
self.assertFalse(pt.has_traits(cn.uuid, traits))
self.assertFalse(pt.has_traits(cn.uuid, traits[:1]))
self.assertTrue(pt.update_traits(cn.uuid, traits, generation=rp_gen))
self.assertTrue(pt.has_traits(cn.uuid, traits))
self.assertTrue(pt.has_traits(cn.uuid, traits[:1]))
# Updating with the same traits info should return False
self.assertFalse(pt.have_traits_changed(cn.uuid, traits))
# But the generation should get updated
rp_gen = 2
self.assertFalse(pt.update_traits(cn.uuid, traits, generation=rp_gen))
self.assertFalse(pt.have_traits_changed(cn.uuid, traits))
self.assertEqual(rp_gen, pt.data(cn.uuid).generation)
self.assertTrue(pt.has_traits(cn.uuid, traits))
self.assertTrue(pt.has_traits(cn.uuid, traits[:1]))
# Make a change to the traits list
traits.append("HW_GPU_RESOLUTION_W800H600")
self.assertTrue(pt.have_traits_changed(cn.uuid, traits))
# The previously-taken data now differs
self.assertTrue(pt.have_traits_changed(cn.uuid, cnsnap.traits))
self.assertFalse(pt.has_traits(cn.uuid, traits[-1:]))
# Don't update the generation
self.assertTrue(pt.update_traits(cn.uuid, traits))
self.assertEqual(rp_gen, pt.data(cn.uuid).generation)
self.assertTrue(pt.has_traits(cn.uuid, traits[-1:]))
def test_add_remove_traits(self):
cn = self.compute_node1
pt = self._pt_with_cns()
self.assertEqual(set([]), pt.data(cn.uuid).traits)
# Test adding with no trait provided for a bogus provider
pt.add_traits('bogus-uuid')
self.assertEqual(
set([]),
pt.data(cn.uuid).traits
)
# Add a couple of traits
pt.add_traits(cn.uuid, "HW_GPU_API_DIRECT3D_V7_0", "HW_NIC_OFFLOAD_SG")
self.assertEqual(
set(["HW_GPU_API_DIRECT3D_V7_0", "HW_NIC_OFFLOAD_SG"]),
pt.data(cn.uuid).traits)
# set() behavior: add a trait that's already there, and one that's not.
# The unrelated one is unaffected.
pt.add_traits(cn.uuid, "HW_GPU_API_DIRECT3D_V7_0", "HW_CPU_X86_AVX")
self.assertEqual(
set(["HW_GPU_API_DIRECT3D_V7_0", "HW_NIC_OFFLOAD_SG",
"HW_CPU_X86_AVX"]),
pt.data(cn.uuid).traits)
# Test removing with no trait provided for a bogus provider
pt.remove_traits('bogus-uuid')
self.assertEqual(
set(["HW_GPU_API_DIRECT3D_V7_0", "HW_NIC_OFFLOAD_SG",
"HW_CPU_X86_AVX"]),
pt.data(cn.uuid).traits)
# Now remove a trait
pt.remove_traits(cn.uuid, "HW_NIC_OFFLOAD_SG")
self.assertEqual(
set(["HW_GPU_API_DIRECT3D_V7_0", "HW_CPU_X86_AVX"]),
pt.data(cn.uuid).traits)
# set() behavior: remove a trait that's there, and one that's not.
# The unrelated one is unaffected.
pt.remove_traits(cn.uuid,
"HW_NIC_OFFLOAD_SG", "HW_GPU_API_DIRECT3D_V7_0")
self.assertEqual(set(["HW_CPU_X86_AVX"]), pt.data(cn.uuid).traits)
# Remove the last trait, and an unrelated one
pt.remove_traits(cn.uuid, "CUSTOM_FOO", "HW_CPU_X86_AVX")
self.assertEqual(set([]), pt.data(cn.uuid).traits)
def test_have_aggregates_changed_no_existing_rp(self):
pt = self._pt_with_cns()
self.assertRaises(
ValueError, pt.have_aggregates_changed, uuids.non_existing_rp, [])
def test_update_aggregates_no_existing_rp(self):
pt = self._pt_with_cns()
self.assertRaises(
ValueError, pt.update_aggregates, uuids.non_existing_rp, [])
def test_have_aggregates_changed(self):
cn = self.compute_node1
pt = self._pt_with_cns()
rp_gen = 1
aggregates = [
uuids.agg1,
uuids.agg2,
]
self.assertTrue(pt.have_aggregates_changed(cn.uuid, aggregates))
self.assertTrue(pt.in_aggregates(cn.uuid, []))
self.assertFalse(pt.in_aggregates(cn.uuid, aggregates))
self.assertFalse(pt.in_aggregates(cn.uuid, aggregates[:1]))
self.assertTrue(pt.update_aggregates(cn.uuid, aggregates,
generation=rp_gen))
self.assertTrue(pt.in_aggregates(cn.uuid, aggregates))
self.assertTrue(pt.in_aggregates(cn.uuid, aggregates[:1]))
# data() gets the same aggregates
cnsnap = pt.data(cn.uuid)
self.assertFalse(
pt.have_aggregates_changed(cn.uuid, cnsnap.aggregates))
# Updating with the same aggregates info should return False
self.assertFalse(pt.have_aggregates_changed(cn.uuid, aggregates))
# But the generation should get updated
rp_gen = 2
self.assertFalse(pt.update_aggregates(cn.uuid, aggregates,
generation=rp_gen))
self.assertFalse(pt.have_aggregates_changed(cn.uuid, aggregates))
self.assertEqual(rp_gen, pt.data(cn.uuid).generation)
self.assertTrue(pt.in_aggregates(cn.uuid, aggregates))
self.assertTrue(pt.in_aggregates(cn.uuid, aggregates[:1]))
# Make a change to the aggregates list
aggregates.append(uuids.agg3)
self.assertTrue(pt.have_aggregates_changed(cn.uuid, aggregates))
self.assertFalse(pt.in_aggregates(cn.uuid, aggregates[-1:]))
# Don't update the generation
self.assertTrue(pt.update_aggregates(cn.uuid, aggregates))
self.assertEqual(rp_gen, pt.data(cn.uuid).generation)
self.assertTrue(pt.in_aggregates(cn.uuid, aggregates[-1:]))
# Previously-taken data now differs
self.assertTrue(pt.have_aggregates_changed(cn.uuid, cnsnap.aggregates))
def test_add_remove_aggregates(self):
cn = self.compute_node1
pt = self._pt_with_cns()
self.assertEqual(set([]), pt.data(cn.uuid).aggregates)
# Add a couple of aggregates
pt.add_aggregates(cn.uuid, uuids.agg1, uuids.agg2)
self.assertEqual(
set([uuids.agg1, uuids.agg2]),
pt.data(cn.uuid).aggregates)
# set() behavior: add an aggregate that's already there, and one that's
# not. The unrelated one is unaffected.
pt.add_aggregates(cn.uuid, uuids.agg1, uuids.agg3)
self.assertEqual(set([uuids.agg1, uuids.agg2, uuids.agg3]),
pt.data(cn.uuid).aggregates)
# Now remove an aggregate
pt.remove_aggregates(cn.uuid, uuids.agg2)
self.assertEqual(set([uuids.agg1, uuids.agg3]),
pt.data(cn.uuid).aggregates)
# set() behavior: remove an aggregate that's there, and one that's not.
# The unrelated one is unaffected.
pt.remove_aggregates(cn.uuid, uuids.agg2, uuids.agg3)
self.assertEqual(set([uuids.agg1]), pt.data(cn.uuid).aggregates)
# Remove the last aggregate, and an unrelated one
pt.remove_aggregates(cn.uuid, uuids.agg4, uuids.agg1)
self.assertEqual(set([]), pt.data(cn.uuid).aggregates)
def test_update_resources_no_existing_rp(self):
pt = self._pt_with_cns()
self.assertRaises(
ValueError,
pt.update_resources,
uuids.non_existing_rp,
{},
)
def test_update_resources(self):
cn = self.compute_node1
pt = self._pt_with_cns()
cn_resources = {
"CUSTOM_RESOURCE_0": {
objects.Resource(provider_uuid=cn.uuid,
resource_class="CUSTOM_RESOURCE_0",
identifier="bar")},
"CUSTOM_RESOURCE_1": {
objects.Resource(provider_uuid=cn.uuid,
resource_class="CUSTOM_RESOURCE_1",
identifier="foo_1"),
objects.Resource(provider_uuid=cn.uuid,
resource_class="CUSTOM_RESOURCE_1",
identifier="foo_2")}}
# resources changed
self.assertTrue(pt.update_resources(cn.uuid, cn_resources))
# resources not changed
self.assertFalse(pt.update_resources(cn.uuid, cn_resources))