summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.openstack.org>2019-02-28 23:29:49 +0000
committerGerrit Code Review <review@openstack.org>2019-02-28 23:29:49 +0000
commita966e2c3f0f6d698f82fbc5d0509e67f03e47243 (patch)
treea446c7426555fa68250591ea84bf2cfcd980b008
parent7e877c4fdb7843b674236204a9a3d31d07e6ad6f (diff)
parentde22cdd3c84e03ed76a261fa41c4ed2d829c8d65 (diff)
downloadpython-novaclient-a966e2c3f0f6d698f82fbc5d0509e67f03e47243.tar.gz
Merge "Add support for microversion 2.70 - expose device tags"
-rw-r--r--novaclient/__init__.py2
-rw-r--r--novaclient/tests/unit/v2/fakes.py38
-rw-r--r--novaclient/tests/unit/v2/test_shell.py52
-rw-r--r--novaclient/v2/shell.py14
-rw-r--r--releasenotes/notes/microversion_v2_70-09cbe0933b3a9335.yaml12
5 files changed, 96 insertions, 22 deletions
diff --git a/novaclient/__init__.py b/novaclient/__init__.py
index a41a77af..bb0e53d1 100644
--- a/novaclient/__init__.py
+++ b/novaclient/__init__.py
@@ -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")
diff --git a/novaclient/tests/unit/v2/fakes.py b/novaclient/tests/unit/v2/fakes.py
index a1e298e7..0f1857ff 100644
--- a/novaclient/tests/unit/v2/fakes.py
+++ b/novaclient/tests/unit/v2/fakes.py
@@ -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, {
diff --git a/novaclient/tests/unit/v2/test_shell.py b/novaclient/tests/unit/v2/test_shell.py
index eecd9315..778c74ac 100644
--- a/novaclient/tests/unit/v2/test_shell.py
+++ b/novaclient/tests/unit/v2/test_shell.py
@@ -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))
diff --git a/novaclient/v2/shell.py b/novaclient/v2/shell.py
index cb0b1c4a..4f65237d 100644
--- a/novaclient/v2/shell.py
+++ b/novaclient/v2/shell.py
@@ -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.'))
diff --git a/releasenotes/notes/microversion_v2_70-09cbe0933b3a9335.yaml b/releasenotes/notes/microversion_v2_70-09cbe0933b3a9335.yaml
new file mode 100644
index 00000000..93dee6e2
--- /dev/null
+++ b/releasenotes/notes/microversion_v2_70-09cbe0933b3a9335.yaml
@@ -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