summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/source/cli/nova.rst12
-rw-r--r--novaclient/__init__.py2
-rw-r--r--novaclient/tests/unit/v2/fakes.py116
-rw-r--r--novaclient/tests/unit/v2/test_shell.py88
-rw-r--r--novaclient/v2/shell.py13
-rw-r--r--releasenotes/notes/bp-handling-down-cell-728cdb1efd1ea75b.yaml9
6 files changed, 216 insertions, 24 deletions
diff --git a/doc/source/cli/nova.rst b/doc/source/cli/nova.rst
index f3bc8eab..64bdf2da 100644
--- a/doc/source/cli/nova.rst
+++ b/doc/source/cli/nova.rst
@@ -2195,6 +2195,10 @@ nova list
List servers.
+Note that from microversion 2.69, during partial infrastructure failures in the
+deployment, the output of this command may return partial results for the servers
+present in the failure domain.
+
**Optional arguments:**
``--reservation-id <reservation-id>``
@@ -3363,6 +3367,10 @@ nova service-list
Show a list of all running services. Filter by host & binary.
+Note that from microversion 2.69, during partial infrastructure failures in the
+deployment, the output of this command may return partial results for the
+services present in the failure domain.
+
**Optional arguments:**
``--host <hostname>``
@@ -3430,6 +3438,10 @@ nova show
Show details about the given server.
+Note that from microversion 2.69, during partial infrastructure failures in the
+deployment, the output of this command may return partial results for the server
+if it exists in the failure domain.
+
**Positional arguments:**
``<server>``
diff --git a/novaclient/__init__.py b/novaclient/__init__.py
index a4eef58c..a41a77af 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.68")
+API_MAX_VERSION = api_versions.APIVersion("2.69")
diff --git a/novaclient/tests/unit/v2/fakes.py b/novaclient/tests/unit/v2/fakes.py
index c6f34c34..0b72a677 100644
--- a/novaclient/tests/unit/v2/fakes.py
+++ b/novaclient/tests/unit/v2/fakes.py
@@ -392,14 +392,32 @@ class FakeSessionClient(base_client.SessionClient):
#
def get_servers(self, **kw):
- return (200, {}, {"servers": [
+ servers = {"servers": [
{'id': '1234', 'name': 'sample-server'},
{'id': '5678', 'name': 'sample-server2'},
{'id': '9014', 'name': 'help'}
- ]})
+ ]}
+ if self.api_version >= api_versions.APIVersion('2.69'):
+ # include "partial results" from non-responsive part of
+ # infrastructure.
+ servers['servers'].append(
+ {'id': '9015',
+ 'status': "UNKNOWN",
+ "links": [
+ {
+ "href": "http://fake/v2.1/",
+ "rel": "self"
+ },
+ {
+ "href": "http://fake",
+ "rel": "bookmark"
+ }
+ ]}
+ )
+ return (200, {}, servers)
def get_servers_detail(self, **kw):
- return (200, {}, {"servers": [
+ servers = {"servers": [
{
"id": '1234',
"name": "sample-server",
@@ -538,7 +556,29 @@ class FakeSessionClient(base_client.SessionClient):
"hostId": "9e107d9d372bb6826bd81d3542a419d6",
"status": "ACTIVE",
},
- ]})
+ ]}
+ if self.api_version >= api_versions.APIVersion('2.69'):
+ # include "partial results" from non-responsive part of
+ # infrastructure.
+ servers['servers'].append(
+ {
+ "id": "9015",
+ "status": "UNKNOWN",
+ "tenant_id": "6f70656e737461636b20342065766572",
+ "created": "2018-12-03T21:06:18Z",
+ "links": [
+ {
+ "href": "http://fake/v2.1/",
+ "rel": "self"
+ },
+ {
+ "href": "http://fake",
+ "rel": "bookmark"
+ }
+ ]
+ }
+ )
+ return (200, {}, servers)
def post_servers(self, body, **kw):
assert set(body.keys()) <= set(['server', 'os:scheduler_hints'])
@@ -599,6 +639,27 @@ class FakeSessionClient(base_client.SessionClient):
r = {'server': self.get_servers_detail()[2]['servers'][4]}
return (200, {}, r)
+ def get_servers_9015(self, **kw):
+ r = {'server': self.get_servers_detail()[2]['servers'][5]}
+ r['server']["OS-EXT-AZ:availability_zone"] = 'geneva'
+ r['server']["OS-EXT-STS:power_state"] = 0
+ flavor = {
+ "disk": 1,
+ "ephemeral": 0,
+ "original_name": "m1.tiny",
+ "ram": 512,
+ "swap": 0,
+ "vcpus": 1,
+ "extra_specs": {}
+ }
+ image = {
+ "id": "c99d7632-bd66-4be9-aed5-3dd14b223a76",
+ }
+ r['server']['image'] = image
+ r['server']['flavor'] = flavor
+ r['server']['user_id'] = "fake"
+ return (200, {}, r)
+
def delete_os_server_groups_12345(self, **kw):
return (202, {}, None)
@@ -1644,24 +1705,35 @@ class FakeSessionClient(base_client.SessionClient):
else:
service_id_1 = 1
service_id_2 = 2
- return (200, FAKE_RESPONSE_HEADERS,
- {'services': [{'binary': binary,
- 'host': host,
- 'zone': 'nova',
- 'status': 'enabled',
- 'state': 'up',
- 'updated_at': datetime.datetime(
- 2012, 10, 29, 13, 42, 2),
- 'id': service_id_1},
- {'binary': binary,
- 'host': host,
- 'zone': 'nova',
- 'status': 'disabled',
- 'state': 'down',
- 'updated_at': datetime.datetime(
- 2012, 9, 18, 8, 3, 38),
- 'id': service_id_2},
- ]})
+ services = {
+ 'services': [
+ {'binary': binary,
+ 'host': host,
+ 'zone': 'nova',
+ 'status': 'enabled',
+ 'state': 'up',
+ 'updated_at': datetime.datetime(
+ 2012, 10, 29, 13, 42, 2),
+ 'id': service_id_1},
+ {'binary': binary,
+ 'host': host,
+ 'zone': 'nova',
+ 'status': 'disabled',
+ 'state': 'down',
+ 'updated_at': datetime.datetime(
+ 2012, 9, 18, 8, 3, 38),
+ 'id': service_id_2},
+ ]
+ }
+ if self.api_version >= api_versions.APIVersion('2.69'):
+ services['services'].append(
+ {
+ "binary": "nova-compute",
+ "host": "host-down",
+ "status": "UNKNOWN"
+ }
+ )
+ return (200, FAKE_RESPONSE_HEADERS, services)
def put_os_services_enable(self, body, **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 fbf93910..eecd9315 100644
--- a/novaclient/tests/unit/v2/test_shell.py
+++ b/novaclient/tests/unit/v2/test_shell.py
@@ -2939,6 +2939,21 @@ class ShellTest(utils.TestCase):
self.run_command('service-list', api_version='2.53')
self.assert_called('GET', '/os-services')
+ def test_services_list_v269_with_down_cells(self):
+ """Tests nova service-list at the 2.69 microversion."""
+ stdout, _stderr = self.run_command('service-list', api_version='2.69')
+ self.assertEqual('''\
++--------------------------------------+--------------+-----------+------+----------+-------+---------------------+-----------------+-------------+
+| Id | Binary | Host | Zone | Status | State | Updated_at | Disabled Reason | Forced down |
++--------------------------------------+--------------+-----------+------+----------+-------+---------------------+-----------------+-------------+
+| 75e9eabc-ed3b-4f11-8bba-add1e7e7e2de | nova-compute | host1 | nova | enabled | up | 2012-10-29 13:42:02 | | |
+| 1f140183-c914-4ddf-8757-6df73028aa86 | nova-compute | host1 | nova | disabled | down | 2012-09-18 08:03:38 | | |
+| | nova-compute | host-down | | UNKNOWN | | | | |
++--------------------------------------+--------------+-----------+------+----------+-------+---------------------+-----------------+-------------+
+''', # noqa
+ stdout)
+ self.assert_called('GET', '/os-services')
+
def test_services_list_with_host(self):
self.run_command('service-list --host host1')
self.assert_called('GET', '/os-services?host=host1')
@@ -4021,6 +4036,15 @@ class ShellTest(utils.TestCase):
63, # There are no version-wrapped shell method changes for this.
65, # There are no version-wrapped shell method changes for this.
67, # There are no version-wrapped shell method changes for this.
+ 69, # NOTE(tssurya): 2.69 adds support for missing keys in the
+ # responses of `GET /servers``, ``GET /servers/detail``,
+ # ``GET /servers/{server_id}`` and ``GET /os-services`` when
+ # a cell is down to return minimal constructs. From 2.69 and
+ # upwards, if the response for ``GET /servers/detail`` does
+ # not have the 'flavor' key for those instances in the down
+ # cell, they will be handled on the client side by being
+ # skipped when forming the detailed lists for embedded
+ # flavor information.
])
versions_supported = set(range(0,
novaclient.API_MAX_VERSION.ver_minor + 1))
@@ -4098,6 +4122,70 @@ class ShellTest(utils.TestCase):
self.run_command('list --not-tags-any tag1,tag2', api_version='2.26')
self.assert_called('GET', '/servers/detail?not-tags-any=tag1%2Ctag2')
+ def test_list_detail_v269_with_down_cells(self):
+ """Tests nova list at the 2.69 microversion."""
+ stdout, _stderr = self.run_command('list', api_version='2.69')
+ self.assertIn('''\
++------+----------------+---------+------------+-------------+----------------------------------------------+
+| ID | Name | Status | Task State | Power State | Networks |
++------+----------------+---------+------------+-------------+----------------------------------------------+
+| 9015 | | UNKNOWN | N/A | N/A | |
+| 9014 | help | ACTIVE | N/A | N/A | |
+| 1234 | sample-server | BUILD | N/A | N/A | private=10.11.12.13; public=1.2.3.4, 5.6.7.8 |
+| 5678 | sample-server2 | ACTIVE | N/A | N/A | private=10.13.12.13; public=4.5.6.7, 5.6.9.8 |
+| 9012 | sample-server3 | ACTIVE | N/A | N/A | private=10.13.12.13; public=4.5.6.7, 5.6.9.8 |
+| 9013 | sample-server4 | ACTIVE | N/A | N/A | |
++------+----------------+---------+------------+-------------+----------------------------------------------+
+''', # noqa
+ stdout)
+ self.assert_called('GET', '/servers/detail')
+
+ def test_list_v269_with_down_cells(self):
+ stdout, _stderr = self.run_command(
+ 'list --minimal', api_version='2.69')
+ expected = '''\
++------+----------------+
+| ID | Name |
++------+----------------+
+| 9015 | |
+| 9014 | help |
+| 1234 | sample-server |
+| 5678 | sample-server2 |
++------+----------------+
+'''
+ self.assertEqual(expected, stdout)
+ self.assert_called('GET', '/servers')
+
+ def test_show_v269_with_down_cells(self):
+ stdout, _stderr = self.run_command('show 9015', api_version='2.69')
+ self.assertEqual('''\
++-----------------------------+---------------------------------------------------+
+| Property | Value |
++-----------------------------+---------------------------------------------------+
+| OS-EXT-AZ:availability_zone | geneva |
+| OS-EXT-STS:power_state | 0 |
+| created | 2018-12-03T21:06:18Z |
+| flavor:disk | 1 |
+| flavor:ephemeral | 0 |
+| flavor:extra_specs | {} |
+| flavor:original_name | m1.tiny |
+| flavor:ram | 512 |
+| flavor:swap | 0 |
+| flavor:vcpus | 1 |
+| id | 9015 |
+| image | CentOS 5.2 (c99d7632-bd66-4be9-aed5-3dd14b223a76) |
+| status | UNKNOWN |
+| tenant_id | 6f70656e737461636b20342065766572 |
+| user_id | fake |
++-----------------------------+---------------------------------------------------+
+''', # noqa
+ stdout)
+ FAKE_UUID_2 = 'c99d7632-bd66-4be9-aed5-3dd14b223a76'
+ self.assert_called('GET', '/servers?name=9015', pos=0)
+ self.assert_called('GET', '/servers?name=9015', pos=1)
+ self.assert_called('GET', '/servers/9015', pos=2)
+ self.assert_called('GET', '/v2/images/%s' % FAKE_UUID_2, pos=3)
+
class PollForStatusTestCase(utils.TestCase):
@mock.patch("novaclient.v2.shell.time")
diff --git a/novaclient/v2/shell.py b/novaclient/v2/shell.py
index a86c0d8e..0ff60156 100644
--- a/novaclient/v2/shell.py
+++ b/novaclient/v2/shell.py
@@ -1670,7 +1670,18 @@ def do_list(cs, args):
# For detailed lists, if we have embedded flavor information then replace
# the "flavor" attribute with more detailed information.
if detailed and have_embedded_flavor_info:
- _expand_dict_attr(servers, 'flavor')
+ if cs.api_version >= api_versions.APIVersion('2.69'):
+ # NOTE(tssurya): From 2.69, we will have the key 'flavor' missing
+ # in the server response during infrastructure failure situations.
+ # For those servers with partial constructs we just skip the
+ # process of expanding the flavor information.
+ servers_final = []
+ for server in servers:
+ if hasattr(server, 'flavor'):
+ servers_final.append(server)
+ _expand_dict_attr(servers_final, 'flavor')
+ else:
+ _expand_dict_attr(servers, 'flavor')
if servers:
cols, fmts = _get_list_table_columns_and_formatters(
diff --git a/releasenotes/notes/bp-handling-down-cell-728cdb1efd1ea75b.yaml b/releasenotes/notes/bp-handling-down-cell-728cdb1efd1ea75b.yaml
new file mode 100644
index 00000000..0403d80f
--- /dev/null
+++ b/releasenotes/notes/bp-handling-down-cell-728cdb1efd1ea75b.yaml
@@ -0,0 +1,9 @@
+---
+features:
+ - |
+ From microversion 2.69 the results of ``nova list``, ``nova show`` and
+ ``nova service-list`` may contain missing information in their outputs
+ when there are partial infrastructure failure periods in the deployment.
+ See `Handling Down Cells`_ for more information on the missing keys/info.
+
+ .. _Handling Down Cells: https://developer.openstack.org/api-guide/compute/down_cells.html