Skip to content

Commit 06976f8

Browse files
Eric FriedBalazs Gibizer
authored andcommitted
Aggregate ops on ProviderTree
Adds the following methods on ProviderTree: in_aggregates: whether a specified provider is a member of *all* aggregates in a given list have_aggregates_changed: whether a new set of aggregates differs from those already registered for a provider update_aggregates: set the list of aggregates with which a provider is associated, returning whether this effected a change Change-Id: Ibb90d05d7827a2f78860182e24d62ad41c57e581
1 parent f029350 commit 06976f8

File tree

2 files changed

+134
-0
lines changed

2 files changed

+134
-0
lines changed

nova/compute/provider_tree.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ def __init__(self, name, uuid=None, generation=None, parent_uuid=None):
4949
self.inventory = {}
5050
# Set of trait names
5151
self.traits = set()
52+
# Set of aggregate UUIDs
53+
self.aggregates = set()
5254

5355
def get_provider_uuids(self):
5456
"""Returns a set of UUIDs of this provider and all its descendants."""
@@ -152,6 +154,31 @@ def has_traits(self, traits):
152154
"""
153155
return not bool(set(traits) - self.traits)
154156

157+
def have_aggregates_changed(self, new):
158+
"""Returns whether the provider's aggregates have changed."""
159+
return set(new) != self.aggregates
160+
161+
def update_aggregates(self, new, generation=None):
162+
"""Update the stored aggregates for the provider along with a resource
163+
provider generation to set the provider to. The method returns whether
164+
the aggregates have changed.
165+
"""
166+
self._update_generation(generation)
167+
if self.have_aggregates_changed(new):
168+
self.aggregates = set(new) # create a copy of the new aggregates
169+
return True
170+
return False
171+
172+
def in_aggregates(self, aggregates):
173+
"""Query whether the provider is a member of certain aggregates.
174+
175+
:param aggregates: Iterable of string aggregate UUIDs to look for.
176+
:return: True if this provider is a member of *all* of the specified
177+
aggregates; False if any of the specified aggregates are
178+
absent. Returns True if the aggregates parameter is empty.
179+
"""
180+
return not bool(set(aggregates) - self.aggregates)
181+
155182

156183
class ProviderTree(object):
157184

@@ -352,3 +379,59 @@ def update_traits(self, name_or_uuid, traits, generation=None):
352379
with self.lock:
353380
provider = self._find_with_lock(name_or_uuid)
354381
return provider.update_traits(traits, generation=generation)
382+
383+
def in_aggregates(self, name_or_uuid, aggregates):
384+
"""Given a name or UUID of a provider, query whether that provider is a
385+
member of *all* the specified aggregates.
386+
387+
:raises: ValueError if a provider with name_or_uuid was not found in
388+
the tree.
389+
:param name_or_uuid: Either name or UUID of the resource provider to
390+
query for aggregates.
391+
:param aggregates: Iterable of string aggregate UUIDs to search for.
392+
:return: True if this provider is associated with *all* of the
393+
specified aggregates; False if any of the specified aggregates
394+
are absent. Returns True if the aggregates parameter is
395+
empty, even if the provider has no aggregate associations.
396+
"""
397+
with self.lock:
398+
provider = self._find_with_lock(name_or_uuid)
399+
return provider.in_aggregates(aggregates)
400+
401+
def have_aggregates_changed(self, name_or_uuid, aggregates):
402+
"""Returns True if the specified aggregates list is different for the
403+
provider with the specified name or UUID.
404+
405+
:raises: ValueError if a provider with name_or_uuid was not found in
406+
the tree.
407+
:param name_or_uuid: Either name or UUID of the resource provider to
408+
query aggregates for.
409+
:param aggregates: Iterable of string aggregate UUIDs to compare
410+
against the provider's aggregates.
411+
"""
412+
with self.lock:
413+
provider = self._find_with_lock(name_or_uuid)
414+
return provider.have_aggregates_changed(aggregates)
415+
416+
def update_aggregates(self, name_or_uuid, aggregates, generation=None):
417+
"""Given a name or UUID of a provider and an iterable of string
418+
aggregate UUIDs, update the provider's aggregates and set the
419+
provider's generation.
420+
421+
:returns: True if the aggregates list has changed.
422+
423+
:note: The provider's generation is always set to the supplied
424+
generation, even if there were no changes to the aggregates.
425+
426+
:raises: ValueError if a provider with name_or_uuid was not found in
427+
the tree.
428+
:param name_or_uuid: Either name or UUID of the resource provider to
429+
update aggregates for.
430+
:param aggregates: Iterable of string aggregate UUIDs to set.
431+
:param generation: The resource provider generation to set. If None,
432+
the provider's generation is not changed.
433+
"""
434+
with self.lock:
435+
provider = self._find_with_lock(name_or_uuid)
436+
return provider.update_aggregates(aggregates,
437+
generation=generation)

nova/tests/unit/compute/test_provider_tree.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,3 +247,54 @@ def test_have_traits_changed(self):
247247
self.assertTrue(pt.update_traits(cn.uuid, traits))
248248
self.assertEqual(rp_gen, pt._find_with_lock(cn.uuid).generation)
249249
self.assertTrue(pt.has_traits(cn.uuid, traits[-1:]))
250+
251+
def test_have_aggregates_changed_no_existing_rp(self):
252+
cns = self.compute_nodes
253+
pt = provider_tree.ProviderTree(cns)
254+
self.assertRaises(
255+
ValueError, pt.have_aggregates_changed, uuids.non_existing_rp, [])
256+
257+
def test_update_aggregates_no_existing_rp(self):
258+
cns = self.compute_nodes
259+
pt = provider_tree.ProviderTree(cns)
260+
self.assertRaises(
261+
ValueError, pt.update_aggregates, uuids.non_existing_rp, [])
262+
263+
def test_have_aggregates_changed(self):
264+
cn = self.compute_node1
265+
cns = self.compute_nodes
266+
pt = provider_tree.ProviderTree(cns)
267+
rp_gen = 1
268+
269+
aggregates = [
270+
uuids.agg1,
271+
uuids.agg2,
272+
]
273+
self.assertTrue(pt.have_aggregates_changed(cn.uuid, aggregates))
274+
self.assertTrue(pt.in_aggregates(cn.uuid, []))
275+
self.assertFalse(pt.in_aggregates(cn.uuid, aggregates))
276+
self.assertFalse(pt.in_aggregates(cn.uuid, aggregates[:1]))
277+
self.assertTrue(pt.update_aggregates(cn.uuid, aggregates,
278+
generation=rp_gen))
279+
self.assertTrue(pt.in_aggregates(cn.uuid, aggregates))
280+
self.assertTrue(pt.in_aggregates(cn.uuid, aggregates[:1]))
281+
282+
# Updating with the same aggregates info should return False
283+
self.assertFalse(pt.have_aggregates_changed(cn.uuid, aggregates))
284+
# But the generation should get updated
285+
rp_gen = 2
286+
self.assertFalse(pt.update_aggregates(cn.uuid, aggregates,
287+
generation=rp_gen))
288+
self.assertFalse(pt.have_aggregates_changed(cn.uuid, aggregates))
289+
self.assertEqual(rp_gen, pt._find_with_lock(cn.uuid).generation)
290+
self.assertTrue(pt.in_aggregates(cn.uuid, aggregates))
291+
self.assertTrue(pt.in_aggregates(cn.uuid, aggregates[:1]))
292+
293+
# Make a change to the aggregates list
294+
aggregates.append(uuids.agg3)
295+
self.assertTrue(pt.have_aggregates_changed(cn.uuid, aggregates))
296+
self.assertFalse(pt.in_aggregates(cn.uuid, aggregates[-1:]))
297+
# Don't update the generation
298+
self.assertTrue(pt.update_aggregates(cn.uuid, aggregates))
299+
self.assertEqual(rp_gen, pt._find_with_lock(cn.uuid).generation)
300+
self.assertTrue(pt.in_aggregates(cn.uuid, aggregates[-1:]))

0 commit comments

Comments
 (0)