Add microversion override for get and list
A continuation of previous patches adding support for node get and list calls to be able to overriden with an os_ironic_api_version keyword argument. Also adds a release note covering the prior patches in this series. Change-Id: I870540a23555e6ae37659452f727872d9d7882a3 Related-Bug: #1739440 Story: #2001870 Task: #14325
This commit is contained in:
parent
5448011fdf
commit
144ce25e42
@ -67,11 +67,13 @@ class Manager(object):
|
||||
|
||||
"""
|
||||
|
||||
def _get(self, resource_id, fields=None):
|
||||
def _get(self, resource_id, fields=None, os_ironic_api_version=None):
|
||||
"""Retrieve a resource.
|
||||
|
||||
:param resource_id: Identifier of the resource.
|
||||
:param fields: List of specific fields to be returned.
|
||||
:param os_ironic_api_version: String version (e.g. "1.35") to use for
|
||||
the request. If not specified, the client's default is used.
|
||||
:raises exc.ValidationError: For invalid resource_id arg value.
|
||||
"""
|
||||
|
||||
@ -85,19 +87,25 @@ class Manager(object):
|
||||
resource_id += ','.join(fields)
|
||||
|
||||
try:
|
||||
return self._list(self._path(resource_id))[0]
|
||||
return self._list(
|
||||
self._path(resource_id),
|
||||
os_ironic_api_version=os_ironic_api_version)[0]
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
def _get_as_dict(self, resource_id, fields=None):
|
||||
def _get_as_dict(self, resource_id, fields=None,
|
||||
os_ironic_api_version=None):
|
||||
"""Retrieve a resource as a dictionary
|
||||
|
||||
:param resource_id: Identifier of the resource.
|
||||
:param fields: List of specific fields to be returned.
|
||||
:param os_ironic_api_version: String version (e.g. "1.35") to use for
|
||||
the request. If not specified, the client's default is used.
|
||||
:returns: a dictionary representing the resource; may be empty
|
||||
"""
|
||||
|
||||
resource = self._get(resource_id, fields=fields)
|
||||
resource = self._get(resource_id, fields=fields,
|
||||
os_ironic_api_version=os_ironic_api_version)
|
||||
if resource:
|
||||
return resource.to_dict()
|
||||
else:
|
||||
@ -118,7 +126,7 @@ class Manager(object):
|
||||
return data
|
||||
|
||||
def _list_pagination(self, url, response_key=None, obj_class=None,
|
||||
limit=None):
|
||||
limit=None, os_ironic_api_version=None):
|
||||
"""Retrieve a list of items.
|
||||
|
||||
The Ironic API is configured to return a maximum number of
|
||||
@ -134,19 +142,24 @@ class Manager(object):
|
||||
:param obj_class: class for constructing the returned objects.
|
||||
:param limit: maximum number of items to return. If None returns
|
||||
everything.
|
||||
|
||||
:param os_ironic_api_version: String version (e.g. "1.35") to use for
|
||||
the request. If not specified, the client's default is used.
|
||||
"""
|
||||
if obj_class is None:
|
||||
obj_class = self.resource_class
|
||||
|
||||
if limit is not None:
|
||||
limit = int(limit)
|
||||
kwargs = {}
|
||||
if os_ironic_api_version is not None:
|
||||
kwargs['headers'] = {'X-OpenStack-Ironic-API-Version':
|
||||
os_ironic_api_version}
|
||||
|
||||
object_list = []
|
||||
object_count = 0
|
||||
limit_reached = False
|
||||
while url:
|
||||
resp, body = self.api.json_request('GET', url)
|
||||
resp, body = self.api.json_request('GET', url, **kwargs)
|
||||
data = self._format_body_data(body, response_key)
|
||||
for obj in data:
|
||||
object_list.append(obj_class(self, obj, loaded=True))
|
||||
@ -170,16 +183,26 @@ class Manager(object):
|
||||
|
||||
return object_list
|
||||
|
||||
def __list(self, url, response_key=None, body=None):
|
||||
resp, body = self.api.json_request('GET', url)
|
||||
def __list(self, url, response_key=None, body=None,
|
||||
os_ironic_api_version=None):
|
||||
kwargs = {}
|
||||
|
||||
if os_ironic_api_version is not None:
|
||||
kwargs['headers'] = {'X-OpenStack-Ironic-API-Version':
|
||||
os_ironic_api_version}
|
||||
|
||||
resp, body = self.api.json_request('GET', url, **kwargs)
|
||||
|
||||
data = self._format_body_data(body, response_key)
|
||||
return data
|
||||
|
||||
def _list(self, url, response_key=None, obj_class=None, body=None):
|
||||
def _list(self, url, response_key=None, obj_class=None, body=None,
|
||||
os_ironic_api_version=None):
|
||||
if obj_class is None:
|
||||
obj_class = self.resource_class
|
||||
|
||||
data = self.__list(url, response_key=response_key, body=body)
|
||||
data = self.__list(url, response_key=response_key, body=body,
|
||||
os_ironic_api_version=os_ironic_api_version)
|
||||
return [obj_class(self, res, loaded=True) for res in data if res]
|
||||
|
||||
def _list_primitives(self, url, response_key=None):
|
||||
|
@ -87,16 +87,16 @@ class TestableManager(base.CreateManager):
|
||||
return ('/v1/testableresources/%s' % id if id
|
||||
else '/v1/testableresources')
|
||||
|
||||
def get(self, testable_resource_id, fields=None):
|
||||
def get(self, testable_resource_id, fields=None, **kwargs):
|
||||
return self._get(resource_id=testable_resource_id,
|
||||
fields=fields)
|
||||
fields=fields, **kwargs)
|
||||
|
||||
def delete(self, testable_resource_id):
|
||||
return self._delete(resource_id=testable_resource_id)
|
||||
def delete(self, testable_resource_id, **kwargs):
|
||||
return self._delete(resource_id=testable_resource_id, **kwargs)
|
||||
|
||||
def update(self, testable_resource_id, patch):
|
||||
def update(self, testable_resource_id, patch, **kwargs):
|
||||
return self._update(resource_id=testable_resource_id,
|
||||
patch=patch)
|
||||
patch=patch, **kwargs)
|
||||
|
||||
|
||||
class ManagerTestCase(testtools.TestCase):
|
||||
@ -120,12 +120,13 @@ class ManagerTestCase(testtools.TestCase):
|
||||
self.manager.create,
|
||||
**INVALID_ATTRIBUTE_TESTABLE_RESOURCE)
|
||||
|
||||
def test__get(self):
|
||||
def test__get_microversion_override(self):
|
||||
resource_id = TESTABLE_RESOURCE['uuid']
|
||||
resource = self.manager._get(resource_id)
|
||||
resource = self.manager._get(resource_id,
|
||||
os_ironic_api_version='1.22')
|
||||
expect = [
|
||||
('GET', '/v1/testableresources/%s' % resource_id,
|
||||
{}, None),
|
||||
{'X-OpenStack-Ironic-API-Version': '1.22'}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(resource_id, resource.uuid)
|
||||
@ -147,12 +148,24 @@ class ManagerTestCase(testtools.TestCase):
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(TESTABLE_RESOURCE, resource)
|
||||
|
||||
def test__get_as_dict_microversion_override(self):
|
||||
resource_id = TESTABLE_RESOURCE['uuid']
|
||||
resource = self.manager._get_as_dict(resource_id,
|
||||
os_ironic_api_version='1.21')
|
||||
expect = [
|
||||
('GET', '/v1/testableresources/%s' % resource_id,
|
||||
{'X-OpenStack-Ironic-API-Version': '1.21'}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(TESTABLE_RESOURCE, resource)
|
||||
|
||||
@mock.patch.object(base.Manager, '_get', autospec=True)
|
||||
def test__get_as_dict_empty(self, mock_get):
|
||||
mock_get.return_value = None
|
||||
resource_id = TESTABLE_RESOURCE['uuid']
|
||||
resource = self.manager._get_as_dict(resource_id)
|
||||
mock_get.assert_called_once_with(mock.ANY, resource_id, fields=None)
|
||||
mock_get.assert_called_once_with(mock.ANY, resource_id, fields=None,
|
||||
os_ironic_api_version=None)
|
||||
self.assertEqual({}, resource)
|
||||
|
||||
def test_get(self):
|
||||
@ -165,6 +178,17 @@ class ManagerTestCase(testtools.TestCase):
|
||||
self.assertEqual(TESTABLE_RESOURCE['uuid'], resource.uuid)
|
||||
self.assertEqual(TESTABLE_RESOURCE['attribute1'], resource.attribute1)
|
||||
|
||||
def test_get_microversion_override(self):
|
||||
resource = self.manager.get(TESTABLE_RESOURCE['uuid'],
|
||||
os_ironic_api_version='1.10')
|
||||
expect = [
|
||||
('GET', '/v1/testableresources/%s' % TESTABLE_RESOURCE['uuid'],
|
||||
{'X-OpenStack-Ironic-API-Version': '1.10'}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(TESTABLE_RESOURCE['uuid'], resource.uuid)
|
||||
self.assertEqual(TESTABLE_RESOURCE['attribute1'], resource.attribute1)
|
||||
|
||||
def test_update(self):
|
||||
patch = {'op': 'replace',
|
||||
'value': NEW_ATTRIBUTE_VALUE,
|
||||
@ -180,6 +204,21 @@ class ManagerTestCase(testtools.TestCase):
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(NEW_ATTRIBUTE_VALUE, resource.attribute1)
|
||||
|
||||
def test_update_microversion_override(self):
|
||||
patch = {'op': 'replace',
|
||||
'value': NEW_ATTRIBUTE_VALUE,
|
||||
'path': '/attribute1'}
|
||||
resource = self.manager.update(
|
||||
testable_resource_id=TESTABLE_RESOURCE['uuid'],
|
||||
patch=patch, os_ironic_api_version='1.9'
|
||||
)
|
||||
expect = [
|
||||
('PATCH', '/v1/testableresources/%s' % TESTABLE_RESOURCE['uuid'],
|
||||
{'X-OpenStack-Ironic-API-Version': '1.9'}, patch),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(NEW_ATTRIBUTE_VALUE, resource.attribute1)
|
||||
|
||||
def test_delete(self):
|
||||
resource = self.manager.delete(
|
||||
testable_resource_id=TESTABLE_RESOURCE['uuid']
|
||||
|
@ -817,6 +817,16 @@ class NodeManagerTest(testtools.TestCase):
|
||||
self.assertEqual(2, len(nodes))
|
||||
self.assertEqual(nodes[0].extra, {})
|
||||
|
||||
def test_node_list_detail_microversion_override(self):
|
||||
nodes = self.mgr.list(detail=True, os_ironic_api_version='1.30')
|
||||
expect = [
|
||||
('GET', '/v1/nodes/detail',
|
||||
{'X-OpenStack-Ironic-API-Version': '1.30'}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(2, len(nodes))
|
||||
self.assertEqual(nodes[0].extra, {})
|
||||
|
||||
def test_node_list_fields(self):
|
||||
nodes = self.mgr.list(fields=['uuid', 'extra'])
|
||||
expect = [
|
||||
@ -898,6 +908,19 @@ class NodeManagerTest(testtools.TestCase):
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(NEW_DRIVER, node.driver)
|
||||
|
||||
def test_update_microversion_override(self):
|
||||
patch = {'op': 'replace',
|
||||
'value': NEW_DRIVER,
|
||||
'path': '/driver'}
|
||||
node = self.mgr.update(node_id=NODE1['uuid'], patch=patch,
|
||||
os_ironic_api_version='1.24')
|
||||
expect = [
|
||||
('PATCH', '/v1/nodes/%s' % NODE1['uuid'],
|
||||
{'X-OpenStack-Ironic-API-Version': '1.24'}, patch),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(NEW_DRIVER, node.driver)
|
||||
|
||||
def test_node_port_list_with_uuid(self):
|
||||
ports = self.mgr.list_ports(NODE1['uuid'])
|
||||
expect = [
|
||||
|
@ -58,7 +58,7 @@ class NodeManager(base.CreateManager):
|
||||
def list(self, associated=None, maintenance=None, marker=None, limit=None,
|
||||
detail=False, sort_key=None, sort_dir=None, fields=None,
|
||||
provision_state=None, driver=None, resource_class=None,
|
||||
chassis=None, fault=None):
|
||||
chassis=None, fault=None, os_ironic_api_version=None):
|
||||
"""Retrieve a list of nodes.
|
||||
|
||||
:param associated: Optional. Either a Boolean or a string
|
||||
@ -107,6 +107,8 @@ class NodeManager(base.CreateManager):
|
||||
|
||||
:param fault: Optional. String value to get only nodes with
|
||||
specified fault.
|
||||
:param os_ironic_api_version: String version (e.g. "1.35") to use for
|
||||
the request. If not specified, the client's default is used.
|
||||
|
||||
:returns: A list of nodes.
|
||||
|
||||
@ -142,10 +144,12 @@ class NodeManager(base.CreateManager):
|
||||
path += '?' + '&'.join(filters)
|
||||
|
||||
if limit is None:
|
||||
return self._list(self._path(path), "nodes")
|
||||
return self._list(self._path(path), "nodes",
|
||||
os_ironic_api_version=os_ironic_api_version)
|
||||
else:
|
||||
return self._list_pagination(self._path(path), "nodes",
|
||||
limit=limit)
|
||||
return self._list_pagination(
|
||||
self._path(path), "nodes", limit=limit,
|
||||
os_ironic_api_version=os_ironic_api_version)
|
||||
|
||||
def list_ports(self, node_id, marker=None, limit=None, sort_key=None,
|
||||
sort_dir=None, detail=False, fields=None):
|
||||
@ -314,8 +318,9 @@ class NodeManager(base.CreateManager):
|
||||
self._path(path), response_key="targets", limit=limit,
|
||||
obj_class=volume_target.VolumeTarget)
|
||||
|
||||
def get(self, node_id, fields=None):
|
||||
return self._get(resource_id=node_id, fields=fields)
|
||||
def get(self, node_id, fields=None, os_ironic_api_version=None):
|
||||
return self._get(resource_id=node_id, fields=fields,
|
||||
os_ironic_api_version=os_ironic_api_version)
|
||||
|
||||
def get_by_instance_uuid(self, instance_uuid, fields=None):
|
||||
path = '?instance_uuid=%s' % instance_uuid
|
||||
|
11
releasenotes/notes/version-overrides-4e9ba1266a238c6a.yaml
Normal file
11
releasenotes/notes/version-overrides-4e9ba1266a238c6a.yaml
Normal file
@ -0,0 +1,11 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Adds support for ``NodeManager.set_provision_state``,
|
||||
``NodeManager.update``, ``NodeManager.get``, and ``NodeManager.list``
|
||||
to accept an ``os_ironic_api_version`` keyword argument to override
|
||||
the API version for that specific call to the REST API.
|
||||
|
||||
When overridden, the API version is not preserved, and if an unsupported
|
||||
version is requested from the remote API, an ``UnsupportedVersion``
|
||||
exception is raised.
|
Loading…
Reference in New Issue
Block a user