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
|
# when client supported the max version, and bumped sequentially, otherwise
|
||||||
# the client may break due to server side new version may include some
|
# the client may break due to server side new version may include some
|
||||||
# backward incompatible change.
|
# 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}]})
|
"hosts": None}]})
|
||||||
|
|
||||||
def get_servers_1234_os_interface(self, **kw):
|
def get_servers_1234_os_interface(self, **kw):
|
||||||
return (200, {}, {
|
attachments = {
|
||||||
"interfaceAttachments": [
|
"interfaceAttachments": [
|
||||||
{"port_state": "ACTIVE",
|
{"port_state": "ACTIVE",
|
||||||
"net_id": "net-id-1",
|
"net_id": "net-id-1",
|
||||||
@ -2017,27 +2017,38 @@ class FakeSessionClient(base_client.SessionClient):
|
|||||||
"port_id": "port-id-1",
|
"port_id": "port-id-1",
|
||||||
"mac_address": "aa:bb:cc:dd:ee:ff",
|
"mac_address": "aa:bb:cc:dd:ee:ff",
|
||||||
"fixed_ips": [{"ip_address": "1.2.3.4"}],
|
"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):
|
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):
|
def delete_servers_1234_os_interface_port_id(self, **kw):
|
||||||
return (200, {}, None)
|
return (200, {}, None)
|
||||||
|
|
||||||
def post_servers_1234_os_volume_attachments(self, **kw):
|
def post_servers_1234_os_volume_attachments(self, **kw):
|
||||||
return (200, FAKE_RESPONSE_HEADERS, {
|
attachment = {"device": "/dev/vdb", "volumeId": 2}
|
||||||
"volumeAttachment":
|
if self.api_version >= api_versions.APIVersion('2.70'):
|
||||||
{"device": "/dev/vdb",
|
# Include the "tag" field in the response.
|
||||||
"volumeId": 2}})
|
attachment['tag'] = 'test-tag'
|
||||||
|
return (200, FAKE_RESPONSE_HEADERS, {"volumeAttachment": attachment})
|
||||||
|
|
||||||
def put_servers_1234_os_volume_attachments_Work(self, **kw):
|
def put_servers_1234_os_volume_attachments_Work(self, **kw):
|
||||||
return (200, FAKE_RESPONSE_HEADERS,
|
return (200, FAKE_RESPONSE_HEADERS,
|
||||||
{"volumeAttachment": {"volumeId": 2}})
|
{"volumeAttachment": {"volumeId": 2}})
|
||||||
|
|
||||||
def get_servers_1234_os_volume_attachments(self, **kw):
|
def get_servers_1234_os_volume_attachments(self, **kw):
|
||||||
return (200, FAKE_RESPONSE_HEADERS, {
|
attachments = {
|
||||||
"volumeAttachments": [
|
"volumeAttachments": [
|
||||||
{"display_name": "Work",
|
{"display_name": "Work",
|
||||||
"display_description": "volume for work",
|
"display_description": "volume for work",
|
||||||
@ -2047,7 +2058,14 @@ class FakeSessionClient(base_client.SessionClient):
|
|||||||
"attached": "2011-11-11T00:00:00Z",
|
"attached": "2011-11-11T00:00:00Z",
|
||||||
"size": 1024,
|
"size": 1024,
|
||||||
"attachments": [{"id": "3333", "links": ''}],
|
"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):
|
def get_servers_1234_os_volume_attachments_Work(self, **kw):
|
||||||
return (200, FAKE_RESPONSE_HEADERS, {
|
return (200, FAKE_RESPONSE_HEADERS, {
|
||||||
|
@ -3518,8 +3518,14 @@ class ShellTest(utils.TestCase):
|
|||||||
self.assert_called('GET', '/servers/1234/os-security-groups')
|
self.assert_called('GET', '/servers/1234/os-security-groups')
|
||||||
|
|
||||||
def test_interface_list(self):
|
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.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):
|
def test_interface_attach(self):
|
||||||
self.run_command('interface-attach --port-id port_id 1234')
|
self.run_command('interface-attach --port-id port_id 1234')
|
||||||
@ -3533,20 +3539,37 @@ class ShellTest(utils.TestCase):
|
|||||||
api_version='2.48')
|
api_version='2.48')
|
||||||
|
|
||||||
def test_interface_attach_with_tag(self):
|
def test_interface_attach_with_tag(self):
|
||||||
self.run_command(
|
out = self.run_command(
|
||||||
'interface-attach --port-id port_id --tag test_tag 1234',
|
'interface-attach --port-id port_id --tag test-tag 1234',
|
||||||
api_version='2.49')
|
api_version='2.49')[0]
|
||||||
self.assert_called('POST', '/servers/1234/os-interface',
|
self.assert_called('POST', '/servers/1234/os-interface',
|
||||||
{'interfaceAttachment': {'port_id': 'port_id',
|
{'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):
|
def test_interface_detach(self):
|
||||||
self.run_command('interface-detach 1234 port_id')
|
self.run_command('interface-detach 1234 port_id')
|
||||||
self.assert_called('DELETE', '/servers/1234/os-interface/port_id')
|
self.assert_called('DELETE', '/servers/1234/os-interface/port_id')
|
||||||
|
|
||||||
def test_volume_attachments(self):
|
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.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):
|
def test_volume_attach(self):
|
||||||
self.run_command('volume-attach sample-server Work /dev/vdb')
|
self.run_command('volume-attach sample-server Work /dev/vdb')
|
||||||
@ -3568,14 +3591,26 @@ class ShellTest(utils.TestCase):
|
|||||||
api_version='2.48')
|
api_version='2.48')
|
||||||
|
|
||||||
def test_volume_attach_with_tag(self):
|
def test_volume_attach_with_tag(self):
|
||||||
self.run_command(
|
out = self.run_command(
|
||||||
'volume-attach --tag test_tag sample-server Work /dev/vdb',
|
'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',
|
self.assert_called('POST', '/servers/1234/os-volume_attachments',
|
||||||
{'volumeAttachment':
|
{'volumeAttachment':
|
||||||
{'device': '/dev/vdb',
|
{'device': '/dev/vdb',
|
||||||
'volumeId': 'Work',
|
'volumeId': 'Work',
|
||||||
'tag': 'test_tag'}})
|
'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):
|
def test_volume_update(self):
|
||||||
self.run_command('volume-update sample-server Work Work')
|
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
|
# cell, they will be handled on the client side by being
|
||||||
# skipped when forming the detailed lists for embedded
|
# skipped when forming the detailed lists for embedded
|
||||||
# flavor information.
|
# flavor information.
|
||||||
|
70, # There are no version-wrapped shell method changes for this.
|
||||||
])
|
])
|
||||||
versions_supported = set(range(0,
|
versions_supported = set(range(0,
|
||||||
novaclient.API_MAX_VERSION.ver_minor + 1))
|
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."""
|
"""List all the volumes attached to a server."""
|
||||||
volumes = cs.volumes.get_server_volumes(_find_server(cs, args.server).id)
|
volumes = cs.volumes.get_server_volumes(_find_server(cs, args.server).id)
|
||||||
_translate_volume_attachments_keys(volumes)
|
_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')
|
@api_versions.wraps('2.0', '2.5')
|
||||||
@ -4497,9 +4501,11 @@ def do_evacuate(cs, args):
|
|||||||
utils.print_dict(res)
|
utils.print_dict(res)
|
||||||
|
|
||||||
|
|
||||||
def _print_interfaces(interfaces):
|
def _print_interfaces(interfaces, show_tag=False):
|
||||||
columns = ['Port State', 'Port ID', 'Net ID', 'IP addresses',
|
columns = ['Port State', 'Port ID', 'Net ID', 'IP addresses',
|
||||||
'MAC Addr']
|
'MAC Addr']
|
||||||
|
if show_tag:
|
||||||
|
columns.append('Tag')
|
||||||
|
|
||||||
class FormattedInterface(object):
|
class FormattedInterface(object):
|
||||||
def __init__(self, interface):
|
def __init__(self, interface):
|
||||||
@ -4519,7 +4525,9 @@ def do_interface_list(cs, args):
|
|||||||
|
|
||||||
res = server.interface_list()
|
res = server.interface_list()
|
||||||
if isinstance(res, 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.'))
|
@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