Add support for microversion 2.70 - expose device tags
This adds support for microversion 2.70 which exposes the 'tag' field in the following APIs: * GET /servers/{server_id}/os-volume_attachments * GET /servers/{server_id}/os-volume_attachments/{volume_id} * POST /servers/{server_id}/os-volume_attachments * GET /servers/{server_id}/os-interface * GET /servers/{server_id}/os-interface/{port_id} * POST /servers/{server_id}/os-interface Which corresponds to showing the tag in the output of the following commands: * nova volume-attachments * nova volume-attach * nova interface-list * nova interface-attach Depends-On: https://review.openstack.org/631948/ Part of blueprint expose-virtual-device-tags-in-rest-api Change-Id: I5e9d7e0219605503a56d2cf745b95c6e05d01101
This commit is contained in:
parent
d64677701c
commit
de22cdd3c8
@ -25,4 +25,4 @@ API_MIN_VERSION = api_versions.APIVersion("2.1")
|
||||
# when client supported the max version, and bumped sequentially, otherwise
|
||||
# the client may break due to server side new version may include some
|
||||
# backward incompatible change.
|
||||
API_MAX_VERSION = api_versions.APIVersion("2.69")
|
||||
API_MAX_VERSION = api_versions.APIVersion("2.70")
|
||||
|
@ -2004,7 +2004,7 @@ class FakeSessionClient(base_client.SessionClient):
|
||||
"hosts": None}]})
|
||||
|
||||
def get_servers_1234_os_interface(self, **kw):
|
||||
return (200, {}, {
|
||||
attachments = {
|
||||
"interfaceAttachments": [
|
||||
{"port_state": "ACTIVE",
|
||||
"net_id": "net-id-1",
|
||||
@ -2017,27 +2017,38 @@ class FakeSessionClient(base_client.SessionClient):
|
||||
"port_id": "port-id-1",
|
||||
"mac_address": "aa:bb:cc:dd:ee:ff",
|
||||
"fixed_ips": [{"ip_address": "1.2.3.4"}],
|
||||
}]
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
if self.api_version >= api_versions.APIVersion('2.70'):
|
||||
# Include the "tag" field in each attachment.
|
||||
for attachment in attachments['interfaceAttachments']:
|
||||
attachment['tag'] = 'test-tag'
|
||||
return (200, {}, attachments)
|
||||
|
||||
def post_servers_1234_os_interface(self, **kw):
|
||||
return (200, {}, {'interfaceAttachment': {}})
|
||||
attachment = {}
|
||||
if self.api_version >= api_versions.APIVersion('2.70'):
|
||||
# Include the "tag" field in the response.
|
||||
attachment['tag'] = 'test-tag'
|
||||
return (200, {}, {'interfaceAttachment': attachment})
|
||||
|
||||
def delete_servers_1234_os_interface_port_id(self, **kw):
|
||||
return (200, {}, None)
|
||||
|
||||
def post_servers_1234_os_volume_attachments(self, **kw):
|
||||
return (200, FAKE_RESPONSE_HEADERS, {
|
||||
"volumeAttachment":
|
||||
{"device": "/dev/vdb",
|
||||
"volumeId": 2}})
|
||||
attachment = {"device": "/dev/vdb", "volumeId": 2}
|
||||
if self.api_version >= api_versions.APIVersion('2.70'):
|
||||
# Include the "tag" field in the response.
|
||||
attachment['tag'] = 'test-tag'
|
||||
return (200, FAKE_RESPONSE_HEADERS, {"volumeAttachment": attachment})
|
||||
|
||||
def put_servers_1234_os_volume_attachments_Work(self, **kw):
|
||||
return (200, FAKE_RESPONSE_HEADERS,
|
||||
{"volumeAttachment": {"volumeId": 2}})
|
||||
|
||||
def get_servers_1234_os_volume_attachments(self, **kw):
|
||||
return (200, FAKE_RESPONSE_HEADERS, {
|
||||
attachments = {
|
||||
"volumeAttachments": [
|
||||
{"display_name": "Work",
|
||||
"display_description": "volume for work",
|
||||
@ -2047,7 +2058,14 @@ class FakeSessionClient(base_client.SessionClient):
|
||||
"attached": "2011-11-11T00:00:00Z",
|
||||
"size": 1024,
|
||||
"attachments": [{"id": "3333", "links": ''}],
|
||||
"metadata": {}}]})
|
||||
"metadata": {}}
|
||||
]
|
||||
}
|
||||
if self.api_version >= api_versions.APIVersion('2.70'):
|
||||
# Include the "tag" field in each attachment.
|
||||
for attachment in attachments['volumeAttachments']:
|
||||
attachment['tag'] = 'test-tag'
|
||||
return (200, FAKE_RESPONSE_HEADERS, attachments)
|
||||
|
||||
def get_servers_1234_os_volume_attachments_Work(self, **kw):
|
||||
return (200, FAKE_RESPONSE_HEADERS, {
|
||||
|
@ -3518,8 +3518,14 @@ class ShellTest(utils.TestCase):
|
||||
self.assert_called('GET', '/servers/1234/os-security-groups')
|
||||
|
||||
def test_interface_list(self):
|
||||
self.run_command('interface-list 1234')
|
||||
out = self.run_command('interface-list 1234')[0]
|
||||
self.assert_called('GET', '/servers/1234/os-interface')
|
||||
self.assertNotIn('Tag', out)
|
||||
|
||||
def test_interface_list_v2_70(self):
|
||||
out = self.run_command('interface-list 1234', api_version='2.70')[0]
|
||||
self.assert_called('GET', '/servers/1234/os-interface')
|
||||
self.assertIn('test-tag', out)
|
||||
|
||||
def test_interface_attach(self):
|
||||
self.run_command('interface-attach --port-id port_id 1234')
|
||||
@ -3533,20 +3539,37 @@ class ShellTest(utils.TestCase):
|
||||
api_version='2.48')
|
||||
|
||||
def test_interface_attach_with_tag(self):
|
||||
self.run_command(
|
||||
'interface-attach --port-id port_id --tag test_tag 1234',
|
||||
api_version='2.49')
|
||||
out = self.run_command(
|
||||
'interface-attach --port-id port_id --tag test-tag 1234',
|
||||
api_version='2.49')[0]
|
||||
self.assert_called('POST', '/servers/1234/os-interface',
|
||||
{'interfaceAttachment': {'port_id': 'port_id',
|
||||
'tag': 'test_tag'}})
|
||||
'tag': 'test-tag'}})
|
||||
self.assertNotIn('test-tag', out)
|
||||
|
||||
def test_interface_attach_v2_70(self):
|
||||
out = self.run_command(
|
||||
'interface-attach --port-id port_id --tag test-tag 1234',
|
||||
api_version='2.70')[0]
|
||||
self.assert_called('POST', '/servers/1234/os-interface',
|
||||
{'interfaceAttachment': {'port_id': 'port_id',
|
||||
'tag': 'test-tag'}})
|
||||
self.assertIn('test-tag', out)
|
||||
|
||||
def test_interface_detach(self):
|
||||
self.run_command('interface-detach 1234 port_id')
|
||||
self.assert_called('DELETE', '/servers/1234/os-interface/port_id')
|
||||
|
||||
def test_volume_attachments(self):
|
||||
self.run_command('volume-attachments 1234')
|
||||
out = self.run_command('volume-attachments 1234')[0]
|
||||
self.assert_called('GET', '/servers/1234/os-volume_attachments')
|
||||
self.assertNotIn('test-tag', out)
|
||||
|
||||
def test_volume_attachments_v2_70(self):
|
||||
out = self.run_command(
|
||||
'volume-attachments 1234', api_version='2.70')[0]
|
||||
self.assert_called('GET', '/servers/1234/os-volume_attachments')
|
||||
self.assertIn('test-tag', out)
|
||||
|
||||
def test_volume_attach(self):
|
||||
self.run_command('volume-attach sample-server Work /dev/vdb')
|
||||
@ -3568,14 +3591,26 @@ class ShellTest(utils.TestCase):
|
||||
api_version='2.48')
|
||||
|
||||
def test_volume_attach_with_tag(self):
|
||||
self.run_command(
|
||||
out = self.run_command(
|
||||
'volume-attach --tag test_tag sample-server Work /dev/vdb',
|
||||
api_version='2.49')
|
||||
api_version='2.49')[0]
|
||||
self.assert_called('POST', '/servers/1234/os-volume_attachments',
|
||||
{'volumeAttachment':
|
||||
{'device': '/dev/vdb',
|
||||
'volumeId': 'Work',
|
||||
'tag': 'test_tag'}})
|
||||
self.assertNotIn('test-tag', out)
|
||||
|
||||
def test_volume_attach_with_tag_v2_70(self):
|
||||
out = self.run_command(
|
||||
'volume-attach --tag test-tag sample-server Work /dev/vdb',
|
||||
api_version='2.70')[0]
|
||||
self.assert_called('POST', '/servers/1234/os-volume_attachments',
|
||||
{'volumeAttachment':
|
||||
{'device': '/dev/vdb',
|
||||
'volumeId': 'Work',
|
||||
'tag': 'test-tag'}})
|
||||
self.assertIn('test-tag', out)
|
||||
|
||||
def test_volume_update(self):
|
||||
self.run_command('volume-update sample-server Work Work')
|
||||
@ -4045,6 +4080,7 @@ class ShellTest(utils.TestCase):
|
||||
# cell, they will be handled on the client side by being
|
||||
# skipped when forming the detailed lists for embedded
|
||||
# flavor information.
|
||||
70, # There are no version-wrapped shell method changes for this.
|
||||
])
|
||||
versions_supported = set(range(0,
|
||||
novaclient.API_MAX_VERSION.ver_minor + 1))
|
||||
|
@ -2617,7 +2617,11 @@ def do_volume_attachments(cs, args):
|
||||
"""List all the volumes attached to a server."""
|
||||
volumes = cs.volumes.get_server_volumes(_find_server(cs, args.server).id)
|
||||
_translate_volume_attachments_keys(volumes)
|
||||
utils.print_list(volumes, ['ID', 'DEVICE', 'SERVER ID', 'VOLUME ID'])
|
||||
# Microversion >= 2.70 returns the tag value.
|
||||
fields = ['ID', 'DEVICE', 'SERVER ID', 'VOLUME ID']
|
||||
if cs.api_version >= api_versions.APIVersion('2.70'):
|
||||
fields.append('TAG')
|
||||
utils.print_list(volumes, fields)
|
||||
|
||||
|
||||
@api_versions.wraps('2.0', '2.5')
|
||||
@ -4497,9 +4501,11 @@ def do_evacuate(cs, args):
|
||||
utils.print_dict(res)
|
||||
|
||||
|
||||
def _print_interfaces(interfaces):
|
||||
def _print_interfaces(interfaces, show_tag=False):
|
||||
columns = ['Port State', 'Port ID', 'Net ID', 'IP addresses',
|
||||
'MAC Addr']
|
||||
if show_tag:
|
||||
columns.append('Tag')
|
||||
|
||||
class FormattedInterface(object):
|
||||
def __init__(self, interface):
|
||||
@ -4519,7 +4525,9 @@ def do_interface_list(cs, args):
|
||||
|
||||
res = server.interface_list()
|
||||
if isinstance(res, list):
|
||||
_print_interfaces(res)
|
||||
# The "tag" field is in the response starting with microversion 2.70.
|
||||
show_tag = cs.api_version >= api_versions.APIVersion('2.70')
|
||||
_print_interfaces(res, show_tag=show_tag)
|
||||
|
||||
|
||||
@utils.arg('server', metavar='<server>', help=_('Name or ID of server.'))
|
||||
|
12
releasenotes/notes/microversion_v2_70-09cbe0933b3a9335.yaml
Normal file
12
releasenotes/notes/microversion_v2_70-09cbe0933b3a9335.yaml
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Added support for `microversion 2.70`_ which outputs the `Tag` field in
|
||||
the following commands:
|
||||
|
||||
* ``nova interface-list``
|
||||
* ``nova interface-attach``
|
||||
* ``nova volume-attachments``
|
||||
* ``nova volume-attach``
|
||||
|
||||
.. _microversion 2.70: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id63
|
Loading…
Reference in New Issue
Block a user