From 6a818ebc1987d728958e26e131f6b46f462c04ac Mon Sep 17 00:00:00 2001 From: He Jie Xu Date: Sun, 21 Jan 2018 15:55:37 +0800 Subject: [PATCH] placement: enable required traits from the flavor extra specs This patch enables the flavor extra spec 'required:[traits]'. The admin can specifiy a set of traits that a flavor required. To enable this, the placement 1.17 is required, it added trait support in the `GET /allocation_candidates` API. So bump the minimal placement version requirement to 1.17 and update the check in cmd `nova-status`. Implement blueprint request-traits-in-nova Change-Id: Ia51ace951e9a0402f873ce9751a8cd3c0283db08 --- doc/source/cli/nova-status.rst | 2 +- nova/cmd/status.py | 2 +- nova/scheduler/client/report.py | 11 ++++--- nova/tests/unit/cmd/test_status.py | 6 ++-- .../unit/scheduler/client/test_report.py | 31 +++++++++++++++++-- ...quest-traits-in-nova-ffcb00f76229b6e9.yaml | 14 +++++++++ 6 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 releasenotes/notes/request-traits-in-nova-ffcb00f76229b6e9.yaml diff --git a/doc/source/cli/nova-status.rst b/doc/source/cli/nova-status.rst index 5d25e502ba8f..cd145f6ab8d3 100644 --- a/doc/source/cli/nova-status.rst +++ b/doc/source/cli/nova-status.rst @@ -103,7 +103,7 @@ Upgrade **17.0.0 (Queens)** - * Checks for the Placement API are modified to require version 1.14. + * Checks for the Placement API are modified to require version 1.17. See Also ======== diff --git a/nova/cmd/status.py b/nova/cmd/status.py index 60b54634620d..218c8f53f9ac 100644 --- a/nova/cmd/status.py +++ b/nova/cmd/status.py @@ -201,7 +201,7 @@ class UpgradeCommands(object): # provider support. # NOTE: If you bump this version, remember to update the history # section in the nova-status man page (doc/source/cli/nova-status). - needs_version = pkg_resources.parse_version("1.14") + needs_version = pkg_resources.parse_version("1.17") if max_version < needs_version: msg = (_('Placement API version %(needed)s needed, ' 'you have %(current)s.') % diff --git a/nova/scheduler/client/report.py b/nova/scheduler/client/report.py index a993eb28a3cf..901fab3c0c1d 100644 --- a/nova/scheduler/client/report.py +++ b/nova/scheduler/client/report.py @@ -327,16 +327,19 @@ class SchedulerReportClient(object): # existing behavior. Once the GET /allocation_candidates API is # prepped to accept the whole shebang, we'll join up all the resources # and traits in the query string (via a new method on ResourceRequest). - resources = resources.get_request_group(None).resources + res = resources.get_request_group(None).resources + required_traits = resources.get_request_group(None).required_traits resource_query = ",".join( sorted("%s:%s" % (rc, amount) - for (rc, amount) in resources.items())) + for (rc, amount) in res.items())) qs_params = { 'resources': resource_query, } + if required_traits: + qs_params['required'] = ",".join(required_traits) - version = '1.12' + version = '1.17' url = "/allocation_candidates?%s" % parse.urlencode(qs_params) resp = self.get(url, version=version) if resp.status_code == 200: @@ -347,7 +350,7 @@ class SchedulerReportClient(object): msg = ("Failed to retrieve allocation candidates from placement API " "for filters %(resources)s. Got %(status_code)d: %(err_text)s.") args = { - 'resources': resources, + 'resources': res, 'status_code': resp.status_code, 'err_text': resp.text, } diff --git a/nova/tests/unit/cmd/test_status.py b/nova/tests/unit/cmd/test_status.py index d8c7064dc1ee..a8d31728c4cd 100644 --- a/nova/tests/unit/cmd/test_status.py +++ b/nova/tests/unit/cmd/test_status.py @@ -210,7 +210,7 @@ class TestPlacementCheck(test.NoDBTestCase): "versions": [ { "min_version": "1.0", - "max_version": "1.14", + "max_version": "1.17", "id": "v1.0" } ] @@ -230,7 +230,7 @@ class TestPlacementCheck(test.NoDBTestCase): "versions": [ { "min_version": "1.0", - "max_version": "1.14", + "max_version": "1.17", "id": "v1.0" } ] @@ -251,7 +251,7 @@ class TestPlacementCheck(test.NoDBTestCase): } res = self.cmd._check_placement() self.assertEqual(status.UpgradeCheckCode.FAILURE, res.code) - self.assertIn('Placement API version 1.14 needed, you have 0.9', + self.assertIn('Placement API version 1.17 needed, you have 0.9', res.details) diff --git a/nova/tests/unit/scheduler/client/test_report.py b/nova/tests/unit/scheduler/client/test_report.py index 50b641d80157..70badbeefdc1 100644 --- a/nova/tests/unit/scheduler/client/test_report.py +++ b/nova/tests/unit/scheduler/client/test_report.py @@ -1417,12 +1417,37 @@ class TestProviderOperations(SchedulerReportClientTestCase): self.client.get_allocation_candidates(resources) expected_url = '/allocation_candidates?%s' % parse.urlencode( - {'resources': 'MEMORY_MB:1024,VCPU:1'}) + {'resources': 'MEMORY_MB:1024,VCPU:1', + 'required': 'CUSTOM_TRAIT1'}) self.ks_adap_mock.get.assert_called_once_with( - expected_url, raise_exc=False, microversion='1.12') + expected_url, raise_exc=False, microversion='1.17') self.assertEqual(mock.sentinel.alloc_reqs, alloc_reqs) self.assertEqual(mock.sentinel.p_sums, p_sums) + def test_get_allocation_candidates_with_no_trait(self): + resp_mock = mock.Mock(status_code=200) + json_data = { + 'allocation_requests': mock.sentinel.alloc_reqs, + 'provider_summaries': mock.sentinel.p_sums, + } + resources = scheduler_utils.ResourceRequest.from_extra_specs({ + 'resources:VCPU': '1', + 'resources:MEMORY_MB': '1024', + 'resources1:DISK_GB': '30', + }) + + resp_mock.json.return_value = json_data + self.ks_adap_mock.get.return_value = resp_mock + + alloc_reqs, p_sums, allocation_request_version = \ + self.client.get_allocation_candidates(resources) + + expected_url = '/allocation_candidates?%s' % parse.urlencode( + {'resources': 'MEMORY_MB:1024,VCPU:1'}) + self.ks_adap_mock.get.assert_called_once_with( + expected_url, raise_exc=False, microversion='1.17') + self.assertEqual(mock.sentinel.alloc_reqs, alloc_reqs) + def test_get_allocation_candidates_not_found(self): # Ensure _get_resource_provider() just returns None when the placement # API doesn't find a resource provider matching a UUID @@ -1436,7 +1461,7 @@ class TestProviderOperations(SchedulerReportClientTestCase): expected_url = '/allocation_candidates?resources=MEMORY_MB%3A1024' self.ks_adap_mock.get.assert_called_once_with( - expected_url, raise_exc=False, microversion='1.12') + expected_url, raise_exc=False, microversion='1.17') self.assertIsNone(res[0]) def test_get_resource_provider_found(self): diff --git a/releasenotes/notes/request-traits-in-nova-ffcb00f76229b6e9.yaml b/releasenotes/notes/request-traits-in-nova-ffcb00f76229b6e9.yaml new file mode 100644 index 000000000000..a35e2745e686 --- /dev/null +++ b/releasenotes/notes/request-traits-in-nova-ffcb00f76229b6e9.yaml @@ -0,0 +1,14 @@ +--- +features: + - | + Add traits support to the Nova. The new flavor extra spec is added to + support specifying the required traits. The syntax of extra spec is + as below: + + - trait:HW_CPU_X86_AVX2=required + - trait:STORAGE_DISK_SSD=required + + The scheduler will pass traits to the GET /allocation_candidates endpoint + in the Placement API to filter out resource providers with each of the + required traits. Currently the only valid value is required. For any other + value will be considered as invalid.