Skip to content

Commit

Permalink
Merge "Aggregate ops on ProviderTree"
Browse files Browse the repository at this point in the history
  • Loading branch information
Zuul authored and openstack-gerrit committed Dec 16, 2017
2 parents 1058a45 + 06976f8 commit 4da48a7
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 0 deletions.
83 changes: 83 additions & 0 deletions nova/compute/provider_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ def __init__(self, name, uuid=None, generation=None, parent_uuid=None):
self.inventory = {}
# Set of trait names
self.traits = set()
# Set of aggregate UUIDs
self.aggregates = set()

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

def have_aggregates_changed(self, new):
"""Returns whether the provider's aggregates have changed."""
return set(new) != self.aggregates

def update_aggregates(self, new, generation=None):
"""Update the stored aggregates for the provider along with a resource
provider generation to set the provider to. The method returns whether
the aggregates have changed.
"""
self._update_generation(generation)
if self.have_aggregates_changed(new):
self.aggregates = set(new) # create a copy of the new aggregates
return True
return False

def in_aggregates(self, aggregates):
"""Query whether the provider is a member of certain aggregates.
:param aggregates: Iterable of string aggregate UUIDs to look for.
:return: True if this provider is a member of *all* of the specified
aggregates; False if any of the specified aggregates are
absent. Returns True if the aggregates parameter is empty.
"""
return not bool(set(aggregates) - self.aggregates)


class ProviderTree(object):

Expand Down Expand Up @@ -352,3 +379,59 @@ def update_traits(self, name_or_uuid, traits, generation=None):
with self.lock:
provider = self._find_with_lock(name_or_uuid)
return provider.update_traits(traits, generation=generation)

def in_aggregates(self, name_or_uuid, aggregates):
"""Given a name or UUID of a provider, query whether that provider is a
member of *all* the specified aggregates.
:raises: ValueError if a provider with name_or_uuid was not found in
the tree.
:param name_or_uuid: Either name or UUID of the resource provider to
query for aggregates.
:param aggregates: Iterable of string aggregate UUIDs to search for.
:return: True if this provider is associated with *all* of the
specified aggregates; False if any of the specified aggregates
are absent. Returns True if the aggregates parameter is
empty, even if the provider has no aggregate associations.
"""
with self.lock:
provider = self._find_with_lock(name_or_uuid)
return provider.in_aggregates(aggregates)

def have_aggregates_changed(self, name_or_uuid, aggregates):
"""Returns True if the specified aggregates list is different for the
provider with the specified name or UUID.
:raises: ValueError if a provider with name_or_uuid was not found in
the tree.
:param name_or_uuid: Either name or UUID of the resource provider to
query aggregates for.
:param aggregates: Iterable of string aggregate UUIDs to compare
against the provider's aggregates.
"""
with self.lock:
provider = self._find_with_lock(name_or_uuid)
return provider.have_aggregates_changed(aggregates)

def update_aggregates(self, name_or_uuid, aggregates, generation=None):
"""Given a name or UUID of a provider and an iterable of string
aggregate UUIDs, update the provider's aggregates and set the
provider's generation.
:returns: True if the aggregates list has changed.
:note: The provider's generation is always set to the supplied
generation, even if there were no changes to the aggregates.
:raises: ValueError if a provider with name_or_uuid was not found in
the tree.
:param name_or_uuid: Either name or UUID of the resource provider to
update aggregates for.
:param aggregates: Iterable of string aggregate UUIDs to set.
:param generation: The resource provider generation to set. If None,
the provider's generation is not changed.
"""
with self.lock:
provider = self._find_with_lock(name_or_uuid)
return provider.update_aggregates(aggregates,
generation=generation)
51 changes: 51 additions & 0 deletions nova/tests/unit/compute/test_provider_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,3 +247,54 @@ def test_have_traits_changed(self):
self.assertTrue(pt.update_traits(cn.uuid, traits))
self.assertEqual(rp_gen, pt._find_with_lock(cn.uuid).generation)
self.assertTrue(pt.has_traits(cn.uuid, traits[-1:]))

def test_have_aggregates_changed_no_existing_rp(self):
cns = self.compute_nodes
pt = provider_tree.ProviderTree(cns)
self.assertRaises(
ValueError, pt.have_aggregates_changed, uuids.non_existing_rp, [])

def test_update_aggregates_no_existing_rp(self):
cns = self.compute_nodes
pt = provider_tree.ProviderTree(cns)
self.assertRaises(
ValueError, pt.update_aggregates, uuids.non_existing_rp, [])

def test_have_aggregates_changed(self):
cn = self.compute_node1
cns = self.compute_nodes
pt = provider_tree.ProviderTree(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]))

# 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._find_with_lock(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._find_with_lock(cn.uuid).generation)
self.assertTrue(pt.in_aggregates(cn.uuid, aggregates[-1:]))

0 comments on commit 4da48a7

Please sign in to comment.