refactor: RequestGroup.is_empty() and .strip_zeros()

This makes an is_empty() method on RequestGroup which answers whether
the group has any resources, traits, or aggregates; and a strip_zeros()
method which removes any resources whose amount is zero.

These are used to refactor ResourceRequest.strip_zeros().
_clean_empties() becomes not worth keeping in its own method, so it's
rolled into ResourceRequest.strip_zeros(), its only consumer. At the
same time, the worthless (at least now that we're py3-only)
ResourceRequest.resource_groups() generator is removed and inlined in
the couple of places it was used.

In addition to simply making the code more cohesive, a later patch will
make use of RequestGroup.is_empty() to forbid no-op groups coming from
ports, accelerators, etc.

Change-Id: I6a83b0eb0f1c352f197f2ef8fab124decd537270
This commit is contained in:
Eric Fried 2019-12-02 18:19:57 -06:00
parent 54195a1bd9
commit 683ffb097c
3 changed files with 22 additions and 20 deletions

View File

@ -1153,3 +1153,15 @@ class RequestGroup(base.NovaObject):
LOG.warning(
"Only (%(tvals)s) traits are supported. Received '%(val)s'.",
{"tvals": ', '.join(trait_vals), "val": trait_type})
def is_empty(self):
return not any((
self.resources,
self.required_traits, self.forbidden_traits,
self.aggregates, self.forbidden_aggregates))
def strip_zeros(self):
"""Remove any resources whose amount is zero."""
for rclass in list(self.resources):
if self.resources[rclass] == 0:
self.resources.pop(rclass)

View File

@ -338,10 +338,6 @@ class ResourceRequest(object):
return
self._group_policy = policy
def resource_groups(self):
for rg in self._rg_by_id.values():
yield rg.resources
def get_num_of_suffixed_groups(self):
return len([ident for ident in self._rg_by_id.keys()
if ident is not None])
@ -355,25 +351,19 @@ class ResourceRequest(object):
:return: A dict of the form {resource_class: amount}
"""
ret = collections.defaultdict(lambda: 0)
for resource_dict in self.resource_groups():
for resource_class, amount in resource_dict.items():
for rg in self._rg_by_id.values():
for resource_class, amount in rg.resources.items():
ret[resource_class] += amount
return dict(ret)
def _clean_empties(self):
"""Get rid of any empty RequestGroup instances."""
for ident, rg in list(self._rg_by_id.items()):
if not any((rg.resources, rg.required_traits,
rg.forbidden_traits)):
self._rg_by_id.pop(ident)
def strip_zeros(self):
"""Remove any resources whose amounts are zero."""
for resource_dict in self.resource_groups():
for rclass in list(resource_dict):
if resource_dict[rclass] == 0:
resource_dict.pop(rclass)
self._clean_empties()
for rg in self._rg_by_id.values():
rg.strip_zeros()
# Get rid of any empty RequestGroup instances.
for ident, rg in list(self._rg_by_id.items()):
if rg.is_empty():
self._rg_by_id.pop(ident)
def to_querystring(self):
"""Produce a querystring of the form expected by

View File

@ -698,14 +698,14 @@ class TestUtils(TestUtilsBase):
self.context, reqspec, self.mock_host_manager)
self.assertEqual({'MEMORY_MB': 1024, 'DISK_GB': 15, 'VCPU': 1},
req.get_request_group(None).resources)
self.assertEqual(1, len(list(req.resource_groups())))
self.assertEqual(1, len(list(req._rg_by_id)))
reqspec = objects.RequestSpec(flavor=flavor, requested_resources=[])
req = utils.resources_from_request_spec(
self.context, reqspec, self.mock_host_manager)
self.assertEqual({'MEMORY_MB': 1024, 'DISK_GB': 15, 'VCPU': 1},
req.get_request_group(None).resources)
self.assertEqual(1, len(list(req.resource_groups())))
self.assertEqual(1, len(list(req._rg_by_id)))
@ddt.data(
# Test single hint that we are checking for.