diff --git a/nova/api/openstack/placement/lib.py b/nova/api/openstack/placement/lib.py index ce16ecd24e..58c230db7b 100644 --- a/nova/api/openstack/placement/lib.py +++ b/nova/api/openstack/placement/lib.py @@ -37,3 +37,17 @@ class RequestGroup(object): self.required_traits = required_traits or set() self.forbidden_traits = forbidden_traits or set() self.member_of = member_of or [] + + def __str__(self): + ret = 'RequestGroup(use_same_provider=%s' % str(self.use_same_provider) + ret += ', resources={%s}' % ', '.join( + '%s:%d' % (rc, amount) + for rc, amount in sorted(list(self.resources.items()))) + ret += ', traits=[%s]' % ', '.join( + sorted(self.required_traits) + + ['!%s' % ft for ft in self.forbidden_traits]) + ret += ', aggregates=[%s]' % ', '.join( + sorted('[%s]' % ', '.join(agglist) + for agglist in sorted(self.member_of))) + ret += ')' + return ret diff --git a/nova/scheduler/client/report.py b/nova/scheduler/client/report.py index 2b4469eb9d..7f225af785 100644 --- a/nova/scheduler/client/report.py +++ b/nova/scheduler/client/report.py @@ -374,18 +374,13 @@ class SchedulerReportClient(object): version) args = { - 'resources': res, + 'resource_request': str(resources), 'status_code': resp.status_code, 'err_text': resp.text, } msg = ("Failed to retrieve allocation candidates from placement " - "API for filters %(resources)s, traits %(traits)s, " - "aggregates %(aggregates)s. Got " - "%(status_code)d: %(err_text)s.") - query_traits = [v for k, v in qs_params if k == 'required'] - query_aggs = [v for k, v in qs_params if k == 'member_of'] - args['traits'] = query_traits and query_traits[0] or '(none)' - args['aggregates'] = ','.join(query_aggs) or '(none)' + "API for filters: %(resource_request)s\n" + "Got %(status_code)d: %(err_text)s.") LOG.error(msg, args) return None, None, None diff --git a/nova/scheduler/utils.py b/nova/scheduler/utils.py index 6a635ffea2..4b16af76cf 100644 --- a/nova/scheduler/utils.py +++ b/nova/scheduler/utils.py @@ -57,6 +57,10 @@ class ResourceRequest(object): # { ident: RequestGroup } self._rg_by_id = {} + def __str__(self): + return ', '.join(sorted( + list(str(rg) for rg in list(self._rg_by_id.values())))) + def get_request_group(self, ident): if ident not in self._rg_by_id: rq_grp = placement_lib.RequestGroup(use_same_provider=bool(ident)) diff --git a/nova/tests/unit/scheduler/test_utils.py b/nova/tests/unit/scheduler/test_utils.py index 6b22aa810b..a9c321c5a9 100644 --- a/nova/tests/unit/scheduler/test_utils.py +++ b/nova/tests/unit/scheduler/test_utils.py @@ -290,6 +290,14 @@ class TestUtils(test.NoDBTestCase): self.assertEqual([('foo', 'bar'), ('baz',)], req.get_request_group(None).member_of) + # Test stringification + self.assertEqual( + 'RequestGroup(use_same_provider=False, ' + 'resources={DISK_GB:1, MEMORY_MB:1024, VCPU:1}, ' + 'traits=[], ' + 'aggregates=[[baz], [foo, bar]])', + str(req)) + def test_resources_from_request_spec_no_aggregates(self): flavor = objects.Flavor(vcpus=1, memory_mb=1024, root_gb=1, ephemeral_gb=0, @@ -481,8 +489,28 @@ class TestUtils(test.NoDBTestCase): 'DISK_GB': 5, } ) - self.assertResourceRequestsEqual( - expected, utils.ResourceRequest.from_extra_specs(extra_specs)) + rr = utils.ResourceRequest.from_extra_specs(extra_specs) + self.assertResourceRequestsEqual(expected, rr) + + # Test stringification + self.assertEqual( + 'RequestGroup(use_same_provider=False, ' + 'resources={MEMORY_MB:2048, VCPU:2}, ' + 'traits=[CUSTOM_MAGIC, HW_CPU_X86_AVX, !CUSTOM_BRONZE], ' + 'aggregates=[]), ' + 'RequestGroup(use_same_provider=True, ' + 'resources={DISK_GB:5}, ' + 'traits=[], ' + 'aggregates=[]), ' + 'RequestGroup(use_same_provider=True, ' + 'resources={IPV4_ADDRESS:1, SRIOV_NET_VF:1}, ' + 'traits=[CUSTOM_PHYSNET_NET1, !CUSTOM_PHYSNET_NET2], ' + 'aggregates=[]), ' + 'RequestGroup(use_same_provider=True, ' + 'resources={IPV4_ADDRESS:2, SRIOV_NET_VF:1}, ' + 'traits=[CUSTOM_PHYSNET_NET2, HW_NIC_ACCEL_SSL], ' + 'aggregates=[])', + str(rr)) def test_resource_request_from_extra_specs_append_request(self): extra_specs = {