Microversion 2.91: Support specifying destination host to unshelve

This patch adds ``host`` to novaclient api.
This can help administrators to specify a ``host``
to unshelve a shelve offloaded server from 2.91 microversion.

Depends-On: https://review.opendev.org/c/openstack/nova/+/831507
Implements: blueprint unshelve-to-host
Change-Id: I7efc8f0b0ef159e16cefee761bff5d7e90d0c427
This commit is contained in:
René Ribaud 2022-03-03 11:18:59 +01:00
parent 63d368168c
commit ee9b277c5f
6 changed files with 182 additions and 5 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.90")
API_MAX_VERSION = api_versions.APIVersion("2.91")

View File

@ -439,6 +439,17 @@ class V1(Base):
elif action == 'lock':
return None
elif action == 'unshelve':
if api_version >= api_versions.APIVersion("2.91"):
# In 2.91 and above, we allow body to be one of these:
# {'unshelve': None}
# {'unshelve': {'availability_zone': <string>}}
# {'unshelve': {'availability_zone': None}} (Unpin az)
# {'unshelve': {'host': <fqdn>}}
# {'unshelve': {'availability_zone': <string>, 'host': <fqdn>}}
# {'unshelve': {'availability_zone': None, 'host': <fqdn>}}
if body[action] is not None:
for key in body[action].keys():
key in ['availability_zone', 'host']
return None
elif action == 'rebuild':
body = body[action]

View File

@ -835,7 +835,7 @@ class FakeSessionClient(base_client.SessionClient):
if self.api_version < api_versions.APIVersion("2.77"):
assert body[action] is None
else:
# In 2.77 and above, we allow body to be one of these:
# In 2.77 to 2.91, we allow body to be one of these:
# {'unshelve': None}
# {'unshelve': {'availability_zone': 'foo-az'}}
if body[action] is not None:

View File

@ -1851,6 +1851,23 @@ class ServersV277Test(ServersV274Test):
api_version = "2.77"
def test_unshelve(self):
s = self.cs.servers.get(1234)
# Test going through the Server object.
ret = s.unshelve()
self.assert_request_id(ret, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called(
'POST',
'/servers/1234/action',
{'unshelve': None})
# Test going through the ServerManager directly.
ret = self.cs.servers.unshelve(s)
self.assert_request_id(ret, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called(
'POST',
'/servers/1234/action',
{'unshelve': None})
def test_unshelve_with_az(self):
s = self.cs.servers.get(1234)
# Test going through the Server object.
@ -1883,7 +1900,7 @@ class ServersV277Test(ServersV274Test):
str(ex))
class ServersV278Test(ServersV273Test):
class ServersV278Test(ServersV277Test):
api_version = "2.78"
@ -1992,3 +2009,82 @@ class ServersV290Test(ServersV278Test):
s.update,
hostname='new-hostname')
self.assertIn('hostname', str(ex))
class ServersV291Test(ServersV290Test):
api_version = "2.91"
def test_unshelve_with_host(self):
s = self.cs.servers.get(1234)
# Test going through the Server object.
ret = s.unshelve(host='server1')
self.assert_request_id(ret, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called(
'POST',
'/servers/1234/action',
{'unshelve': {'host': 'server1'}})
# Test going through the ServerManager directly.
ret = self.cs.servers.unshelve(s, host='server1')
self.assert_request_id(ret, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called(
'POST',
'/servers/1234/action',
{'unshelve': {'host': 'server1'}})
def test_unshelve_server_with_az_and_host(self):
s = self.cs.servers.get(1234)
# Test going through the Server object.
ret = s.unshelve(host='server1', availability_zone='foo-az')
self.assert_request_id(ret, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called(
'POST',
'/servers/1234/action',
{'unshelve': {'host': 'server1',
'availability_zone': 'foo-az'}})
# Test going through the ServerManager directly.
ret = self.cs.servers.unshelve(
s, host='server1', availability_zone='foo-az')
self.assert_request_id(ret, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called(
'POST',
'/servers/1234/action',
{'unshelve': {'host': 'server1',
'availability_zone': 'foo-az'}})
def test_unshelve_unpin_az(self):
s = self.cs.servers.get(1234)
# Test going through the Server object.
ret = s.unshelve(availability_zone=None)
self.assert_request_id(ret, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called(
'POST',
'/servers/1234/action',
{'unshelve': {'availability_zone': None}})
# Test going through the ServerManager directly.
ret = self.cs.servers.unshelve(s, availability_zone=None)
self.assert_request_id(ret, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called(
'POST',
'/servers/1234/action',
{'unshelve': {'availability_zone': None}})
def test_unshelve_server_with_host_and_unpin(self):
s = self.cs.servers.get(1234)
# Test going through the Server object.
ret = s.unshelve(availability_zone=None, host='server1')
self.assert_request_id(ret, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called(
'POST',
'/servers/1234/action',
{'unshelve': {'host': 'server1',
'availability_zone': None}})
# Test going through the ServerManager directly.
ret = self.cs.servers.unshelve(
s, availability_zone=None, host='server1')
self.assert_request_id(ret, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called(
'POST',
'/servers/1234/action',
{'unshelve': {'host': 'server1',
'availability_zone': None}})

View File

@ -314,7 +314,7 @@ class Server(base.Resource):
"""
return self.manager.unshelve(self)
@api_versions.wraps("2.77")
@api_versions.wraps("2.77", "2.90")
def unshelve(self, availability_zone=None):
"""
Unshelve -- Unshelve the server.
@ -326,6 +326,37 @@ class Server(base.Resource):
return self.manager.unshelve(self,
availability_zone=availability_zone)
@api_versions.wraps("2.91")
def unshelve(self, availability_zone=object(), host=None):
"""
Unshelve -- Unshelve the server.
:param availability_zone: If specified the instance will be unshelved
to the availability_zone.
If None is passed the instance defined
availability_zone is unpin and the instance
will be scheduled to any availability_zone
(free scheduling).
If not specified the instance will be
unshelved to either its defined
availability_zone or any
availability_zone (free scheduling).
:param host: The specified host
(Optional)
:returns: An instance of novaclient.base.TupleWithMeta
"""
if (
availability_zone is None or isinstance(availability_zone, str)
) and host:
return self.manager.unshelve(
self, availability_zone=availability_zone, host=host)
if availability_zone is None or isinstance(availability_zone, str):
return self.manager.unshelve(
self, availability_zone=availability_zone)
if host:
return self.manager.unshelve(self, host=host)
return self.manager.unshelve(self)
def diagnostics(self):
"""Diagnostics -- Retrieve server diagnostics."""
return self.manager.diagnostics(self)
@ -1266,7 +1297,7 @@ class ServerManager(base.BootingManagerWithFind):
"""
return self._action('unshelve', server, None)
@api_versions.wraps("2.77")
@api_versions.wraps("2.77", "2.90")
def unshelve(self, server, availability_zone=None):
"""
Unshelve the server.
@ -1281,6 +1312,36 @@ class ServerManager(base.BootingManagerWithFind):
info = {'availability_zone': availability_zone}
return self._action('unshelve', server, info)
@api_versions.wraps("2.91")
def unshelve(self, server, availability_zone=object(), host=None):
"""
Unshelve the server.
:param availability_zone: If specified the instance will be unshelved
to the availability_zone.
If None is passed the instance defined
availability_zone is unpin and the instance
will be scheduled to any availability_zone
(free scheduling).
If not specified the instance will be
unshelved to either its defined
availability_zone or any
availability_zone (free scheduling).
:param host: The specified host
(Optional)
:returns: An instance of novaclient.base.TupleWithMeta
"""
info = None
if availability_zone is None or isinstance(availability_zone, str):
info = {'availability_zone': availability_zone}
if host:
if info:
info['host'] = host
else:
info = {'host': host}
return self._action('unshelve', server, info)
def ips(self, server):
"""
Return IP Addresses associated with the server.

View File

@ -0,0 +1,9 @@
---
features:
- |
Support has been added for `microversion 2.91`_. This microversion
allows specifying a destination host to unshelve a shelve
offloaded server. And availability zone can be set to None to unpin
the availability zone of a server.
.. _microversion 2.91: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#microversion-2-91