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
This commit is contained in:
He Jie Xu 2018-01-21 15:55:37 +08:00
parent 48d1ee1dd0
commit 6a818ebc19
6 changed files with 54 additions and 12 deletions

View File

@ -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
========

View File

@ -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.') %

View File

@ -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,
}

View File

@ -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)

View File

@ -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):

View File

@ -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.