Allocation candidates parameter: required (v1.17)
New parameter to 'allocation candidate list': --required TRAIT [--required ...] New output field of 'allocation candidate list': traits Change-Id: Ie70497981ff4295b3ccd6b495b21bbb919d92c47 Partially-Implements: blueprint placement-osc-plugin-rocky
This commit is contained in:
parent
9f4e7eb9e8
commit
5883b82f69
|
@ -17,7 +17,6 @@ from osc_placement import version
|
|||
|
||||
|
||||
BASE_URL = '/allocation_candidates'
|
||||
FIELDS = ('#', 'allocation', 'resource provider', 'inventory used/capacity')
|
||||
|
||||
|
||||
class ListAllocationCandidate(command.Lister, version.CheckerMixin):
|
||||
|
@ -76,6 +75,16 @@ class ListAllocationCandidate(command.Lister, version.CheckerMixin):
|
|||
'This option requires at least '
|
||||
'``--os-placement-api-version 1.16``.'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--required',
|
||||
metavar='<required>',
|
||||
action='append',
|
||||
default=[],
|
||||
help='A required trait. May be repeated. Allocation candidates '
|
||||
'must collectively contain all of the required traits. '
|
||||
'This option requires at least '
|
||||
'``--os-placement-api-version 1.17``.'
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
|
@ -93,13 +102,22 @@ class ListAllocationCandidate(command.Lister, version.CheckerMixin):
|
|||
# Fail if --limit but not high enough microversion.
|
||||
self.check_version(version.ge('1.16'))
|
||||
params['limit'] = int(parsed_args.limit)
|
||||
if 'required' in parsed_args and parsed_args.required:
|
||||
# Fail if --required but not high enough microversion.
|
||||
self.check_version(version.ge('1.17'))
|
||||
params['required'] = ','.join(parsed_args.required)
|
||||
resp = http.request('GET', BASE_URL, params=params).json()
|
||||
|
||||
rps = {}
|
||||
rp_resources = {}
|
||||
include_traits = self.compare_version(version.ge('1.17'))
|
||||
if include_traits:
|
||||
rp_traits = {}
|
||||
for rp_uuid, resources in resp['provider_summaries'].items():
|
||||
rps[rp_uuid] = ','.join(
|
||||
rp_resources[rp_uuid] = ','.join(
|
||||
'%s=%s/%s' % (rc, value['used'], value['capacity'])
|
||||
for rc, value in resources['resources'].items())
|
||||
if include_traits:
|
||||
rp_traits[rp_uuid] = ','.join(resources['traits'])
|
||||
|
||||
rows = []
|
||||
if self.compare_version(version.ge('1.12')):
|
||||
|
@ -108,7 +126,11 @@ class ListAllocationCandidate(command.Lister, version.CheckerMixin):
|
|||
req = ','.join(
|
||||
'%s=%s' % (rc, value)
|
||||
for rc, value in resources['resources'].items())
|
||||
rows.append([i + 1, req, rp, rps[rp]])
|
||||
if include_traits:
|
||||
row = [i + 1, req, rp, rp_resources[rp], rp_traits[rp]]
|
||||
else:
|
||||
row = [i + 1, req, rp, rp_resources[rp]]
|
||||
rows.append(row)
|
||||
else:
|
||||
for i, allocation_req in enumerate(resp['allocation_requests']):
|
||||
for allocation in allocation_req['allocations']:
|
||||
|
@ -116,6 +138,11 @@ class ListAllocationCandidate(command.Lister, version.CheckerMixin):
|
|||
req = ','.join(
|
||||
'%s=%s' % (rc, value)
|
||||
for rc, value in allocation['resources'].items())
|
||||
rows.append([i + 1, req, rp, rps[rp]])
|
||||
rows.append([i + 1, req, rp, rp_resources[rp]])
|
||||
|
||||
return FIELDS, rows
|
||||
fields = ('#', 'allocation', 'resource provider',
|
||||
'inventory used/capacity')
|
||||
if include_traits:
|
||||
fields += ('traits',)
|
||||
|
||||
return fields, rows
|
||||
|
|
|
@ -258,9 +258,11 @@ class BaseTestCase(base.BaseTestCase):
|
|||
cmd = 'resource provider trait delete %s ' % uuid
|
||||
self.openstack(cmd)
|
||||
|
||||
def allocation_candidate_list(self, resources, limit=None):
|
||||
def allocation_candidate_list(self, resources, required=None, limit=None):
|
||||
cmd = 'allocation candidate list ' + ' '.join(
|
||||
'--resource %s' % resource for resource in resources)
|
||||
if required is not None:
|
||||
cmd += ''.join([' --required %s' % t for t in required])
|
||||
if limit is not None:
|
||||
cmd += ' --limit %d' % limit
|
||||
return self.openstack(cmd, use_json=True)
|
||||
|
|
|
@ -118,3 +118,30 @@ class TestAllocationCandidate116(base.BaseTestCase):
|
|||
resources=('MEMORY_MB=1024', 'DISK_GB=80'),
|
||||
limit=1)
|
||||
self.assertEqual(len(set([row['#'] for row in limited])), 1)
|
||||
|
||||
|
||||
class TestAllocationCandidate117(base.BaseTestCase):
|
||||
VERSION = '1.17'
|
||||
|
||||
def test_show_required_trait(self):
|
||||
rp1 = self.resource_provider_create()
|
||||
rp2 = self.resource_provider_create()
|
||||
self.resource_inventory_set(
|
||||
rp1['uuid'], 'MEMORY_MB=8192', 'DISK_GB=512')
|
||||
self.resource_inventory_set(
|
||||
rp2['uuid'], 'MEMORY_MB=8192', 'DISK_GB=512')
|
||||
self.resource_provider_trait_set(
|
||||
rp1['uuid'], 'STORAGE_DISK_SSD', 'HW_NIC_SRIOV')
|
||||
self.resource_provider_trait_set(
|
||||
rp2['uuid'], 'STORAGE_DISK_HDD', 'HW_NIC_SRIOV')
|
||||
|
||||
rps = self.allocation_candidate_list(
|
||||
resources=('MEMORY_MB=1024', 'DISK_GB=80'),
|
||||
required=('STORAGE_DISK_SSD',))
|
||||
|
||||
candidate_dict = {rp['resource provider']: rp for rp in rps}
|
||||
self.assertIn(rp1['uuid'], candidate_dict)
|
||||
self.assertNotIn(rp2['uuid'], candidate_dict)
|
||||
self.assertEqual(
|
||||
set(candidate_dict[rp1['uuid']]['traits'].split(',')),
|
||||
set(['STORAGE_DISK_SSD', 'HW_NIC_SRIOV']))
|
||||
|
|
|
@ -31,7 +31,8 @@ SUPPORTED_VERSIONS = [
|
|||
'1.13', # unused
|
||||
'1.14',
|
||||
'1.15', # unused
|
||||
'1.16'
|
||||
'1.16',
|
||||
'1.17'
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Support is added for the `1.17`_ placement API microversion by adding
|
||||
the ``--required`` option to the ``openstack allocation candidate list``
|
||||
command.
|
||||
|
||||
.. _1.17: https://docs.openstack.org/nova/latest/user/placement.html#add-required-parameter-to-the-allocation-candidates-maximum-in-queens
|
Loading…
Reference in New Issue