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:
Matt Riedemann 2019-02-13 18:29:39 -05:00
parent d64677701c
commit de22cdd3c8
5 changed files with 96 additions and 22 deletions

View File

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

View File

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

View File

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

View File

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

View 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