From 2a5fd148b90e2b6ce55ae4d5c454fffc89bf1b65 Mon Sep 17 00:00:00 2001 From: Eric Fried Date: Wed, 29 Nov 2017 11:14:54 -0600 Subject: [PATCH] ProviderTree.get_provider_uuids() As we start using nested resource providers in the resource tracker, and virt drivers, we're going to need to be able to e.g. diff provider trees and create or delete entries in placement accordingly. This change set implements get_provider_uuids() on ProviderTree, which returns a set of the UUIDs of all providers, optionally at and below the level of a provider specified by name or UUID. So you can say e.g.: uuids_to_delete = old.get_provider_uuids() - new.get_provider_uuids() or numa1_uuids = ptree.get_provider_uuids(name_or_uuid=numa_cell_1_uuid) Change-Id: I994442830588ee37eda409370a07152903b2e817 blueprint: nested-resource-providers --- nova/compute/provider_tree.py | 26 +++++++++++++++++++ nova/tests/unit/compute/test_provider_tree.py | 14 ++++++++++ 2 files changed, 40 insertions(+) diff --git a/nova/compute/provider_tree.py b/nova/compute/provider_tree.py index f2f1f29d9482..98abb1ede2b0 100644 --- a/nova/compute/provider_tree.py +++ b/nova/compute/provider_tree.py @@ -48,6 +48,13 @@ class _Provider(object): # dict of inventory records, keyed by resource class self.inventory = {} + def get_provider_uuids(self): + """Returns a set of UUIDs of this provider and all its descendants.""" + ret = set([self.uuid]) + for child in self.children.values(): + ret |= child.get_provider_uuids() + return ret + def find(self, search): if self.name == search or self.uuid == search: return self @@ -129,6 +136,25 @@ class ProviderTree(object): p = _Provider(cn.hypervisor_hostname, cn.uuid) self.roots.append(p) + def get_provider_uuids(self, name_or_uuid=None): + """Return a set of the UUIDs of all providers (in a subtree). + + :param name_or_uuid: Provider name or UUID representing the root of a + subtree for which to return UUIDs. If not + specified, the method returns all UUIDs in the + ProviderTree. + """ + if name_or_uuid is not None: + with self.lock: + return self._find_with_lock(name_or_uuid).get_provider_uuids() + + # If no name_or_uuid, get UUIDs for all providers recursively. + ret = set() + with self.lock: + for root in self.roots: + ret |= root.get_provider_uuids() + return ret + def remove(self, name_or_uuid): """Safely removes the provider identified by the supplied name_or_uuid parameter and all of its children from the tree. diff --git a/nova/tests/unit/compute/test_provider_tree.py b/nova/tests/unit/compute/test_provider_tree.py index 81535bf415e7..26c71d800143 100644 --- a/nova/tests/unit/compute/test_provider_tree.py +++ b/nova/tests/unit/compute/test_provider_tree.py @@ -34,6 +34,7 @@ class TestProviderTree(test.NoDBTestCase): def test_tree_ops(self): cn1 = self.compute_node1 + cn2 = self.compute_node2 cns = self.compute_nodes pt = provider_tree.ProviderTree(cns) @@ -50,6 +51,10 @@ class TestProviderTree(test.NoDBTestCase): self.assertFalse(pt.exists(uuids.non_existing_rp)) self.assertFalse(pt.exists('noexist')) + self.assertEqual(set([cn1.uuid]), + pt.get_provider_uuids(name_or_uuid=cn1.uuid)) + self.assertEqual(set([cn1.uuid, cn2.uuid]), pt.get_provider_uuids()) + numa_cell0_uuid = pt.new_child('numa_cell0', cn1.uuid) numa_cell1_uuid = pt.new_child('numa_cell1', cn1.uuid) @@ -63,6 +68,15 @@ class TestProviderTree(test.NoDBTestCase): 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 + self.assertEqual( + set([cn1.uuid, numa_cell0_uuid, pf1_cell0_uuid, numa_cell1_uuid]), + pt.get_provider_uuids(name_or_uuid=cn1.uuid)) + self.assertEqual( + set([cn1.uuid, cn2.uuid, numa_cell0_uuid, pf1_cell0_uuid, + numa_cell1_uuid]), + pt.get_provider_uuids()) + self.assertRaises( ValueError, pt.new_child,