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:
@@ -103,7 +103,7 @@ Upgrade
|
|||||||
|
|
||||||
**17.0.0 (Queens)**
|
**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
|
See Also
|
||||||
========
|
========
|
||||||
|
@@ -201,7 +201,7 @@ class UpgradeCommands(object):
|
|||||||
# provider support.
|
# provider support.
|
||||||
# NOTE: If you bump this version, remember to update the history
|
# NOTE: If you bump this version, remember to update the history
|
||||||
# section in the nova-status man page (doc/source/cli/nova-status).
|
# 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:
|
if max_version < needs_version:
|
||||||
msg = (_('Placement API version %(needed)s needed, '
|
msg = (_('Placement API version %(needed)s needed, '
|
||||||
'you have %(current)s.') %
|
'you have %(current)s.') %
|
||||||
|
@@ -327,16 +327,19 @@ class SchedulerReportClient(object):
|
|||||||
# existing behavior. Once the GET /allocation_candidates API is
|
# existing behavior. Once the GET /allocation_candidates API is
|
||||||
# prepped to accept the whole shebang, we'll join up all the resources
|
# 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).
|
# 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(
|
resource_query = ",".join(
|
||||||
sorted("%s:%s" % (rc, amount)
|
sorted("%s:%s" % (rc, amount)
|
||||||
for (rc, amount) in resources.items()))
|
for (rc, amount) in res.items()))
|
||||||
qs_params = {
|
qs_params = {
|
||||||
'resources': resource_query,
|
'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)
|
url = "/allocation_candidates?%s" % parse.urlencode(qs_params)
|
||||||
resp = self.get(url, version=version)
|
resp = self.get(url, version=version)
|
||||||
if resp.status_code == 200:
|
if resp.status_code == 200:
|
||||||
@@ -347,7 +350,7 @@ class SchedulerReportClient(object):
|
|||||||
msg = ("Failed to retrieve allocation candidates from placement API "
|
msg = ("Failed to retrieve allocation candidates from placement API "
|
||||||
"for filters %(resources)s. Got %(status_code)d: %(err_text)s.")
|
"for filters %(resources)s. Got %(status_code)d: %(err_text)s.")
|
||||||
args = {
|
args = {
|
||||||
'resources': resources,
|
'resources': res,
|
||||||
'status_code': resp.status_code,
|
'status_code': resp.status_code,
|
||||||
'err_text': resp.text,
|
'err_text': resp.text,
|
||||||
}
|
}
|
||||||
|
@@ -210,7 +210,7 @@ class TestPlacementCheck(test.NoDBTestCase):
|
|||||||
"versions": [
|
"versions": [
|
||||||
{
|
{
|
||||||
"min_version": "1.0",
|
"min_version": "1.0",
|
||||||
"max_version": "1.14",
|
"max_version": "1.17",
|
||||||
"id": "v1.0"
|
"id": "v1.0"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -230,7 +230,7 @@ class TestPlacementCheck(test.NoDBTestCase):
|
|||||||
"versions": [
|
"versions": [
|
||||||
{
|
{
|
||||||
"min_version": "1.0",
|
"min_version": "1.0",
|
||||||
"max_version": "1.14",
|
"max_version": "1.17",
|
||||||
"id": "v1.0"
|
"id": "v1.0"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -251,7 +251,7 @@ class TestPlacementCheck(test.NoDBTestCase):
|
|||||||
}
|
}
|
||||||
res = self.cmd._check_placement()
|
res = self.cmd._check_placement()
|
||||||
self.assertEqual(status.UpgradeCheckCode.FAILURE, res.code)
|
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)
|
res.details)
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1417,12 +1417,37 @@ class TestProviderOperations(SchedulerReportClientTestCase):
|
|||||||
self.client.get_allocation_candidates(resources)
|
self.client.get_allocation_candidates(resources)
|
||||||
|
|
||||||
expected_url = '/allocation_candidates?%s' % parse.urlencode(
|
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(
|
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.alloc_reqs, alloc_reqs)
|
||||||
self.assertEqual(mock.sentinel.p_sums, p_sums)
|
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):
|
def test_get_allocation_candidates_not_found(self):
|
||||||
# Ensure _get_resource_provider() just returns None when the placement
|
# Ensure _get_resource_provider() just returns None when the placement
|
||||||
# API doesn't find a resource provider matching a UUID
|
# 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'
|
expected_url = '/allocation_candidates?resources=MEMORY_MB%3A1024'
|
||||||
self.ks_adap_mock.get.assert_called_once_with(
|
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])
|
self.assertIsNone(res[0])
|
||||||
|
|
||||||
def test_get_resource_provider_found(self):
|
def test_get_resource_provider_found(self):
|
||||||
|
@@ -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.
|
Reference in New Issue
Block a user