Microversion 2.91: Support specifying destination host to unshelve
This patch adds a new parameter ``--host`` to ``openstack server unshelve`` command. This can help administrators to specify an ``host`` to unshelve a shelve offloaded server. And add new parameter ``--no-availability-zone`` to unpin a server availability These parameters are available in the 2.91 microversion. Depends-On: https://review.opendev.org/c/openstack/python-novaclient/+/831651 Implements: blueprint unshelve-to-host Change-Id: I7986adc7563f63bcd4b3caf5eb7bc4329b4e1eca
This commit is contained in:
parent
27b2496e03
commit
6e0699c1cf
@ -4564,13 +4564,30 @@ class UnshelveServer(command.Command):
|
||||
nargs='+',
|
||||
help=_('Server(s) to unshelve (name or ID)'),
|
||||
)
|
||||
parser.add_argument(
|
||||
group = parser.add_mutually_exclusive_group()
|
||||
group.add_argument(
|
||||
'--availability-zone',
|
||||
default=None,
|
||||
help=_('Name of the availability zone in which to unshelve a '
|
||||
'SHELVED_OFFLOADED server (supported by '
|
||||
'--os-compute-api-version 2.77 or above)'),
|
||||
)
|
||||
group.add_argument(
|
||||
'--no-availability-zone',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_('Unpin the availability zone of a SHELVED_OFFLOADED '
|
||||
'server. Server will be unshelved on a host without '
|
||||
'availability zone constraint (supported by '
|
||||
'--os-compute-api-version 2.91 or above)'),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--host',
|
||||
default=None,
|
||||
help=_('Name of the destination host in which to unshelve a '
|
||||
'SHELVED_OFFLOADED server (supported by '
|
||||
'--os-compute-api-version 2.91 or above)'),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--wait',
|
||||
action='store_true',
|
||||
@ -4599,6 +4616,26 @@ class UnshelveServer(command.Command):
|
||||
|
||||
kwargs['availability_zone'] = parsed_args.availability_zone
|
||||
|
||||
if parsed_args.host:
|
||||
if compute_client.api_version < api_versions.APIVersion('2.91'):
|
||||
msg = _(
|
||||
'--os-compute-api-version 2.91 or greater is required '
|
||||
'to support the --host option'
|
||||
)
|
||||
raise exceptions.CommandError(msg)
|
||||
|
||||
kwargs['host'] = parsed_args.host
|
||||
|
||||
if parsed_args.no_availability_zone:
|
||||
if compute_client.api_version < api_versions.APIVersion('2.91'):
|
||||
msg = _(
|
||||
'--os-compute-api-version 2.91 or greater is required '
|
||||
'to support the --no-availability-zone option'
|
||||
)
|
||||
raise exceptions.CommandError(msg)
|
||||
|
||||
kwargs['availability_zone'] = None
|
||||
|
||||
for server in parsed_args.server:
|
||||
server_obj = utils.find_resource(
|
||||
compute_client.servers,
|
||||
|
@ -161,6 +161,10 @@ class TestServer(compute_fakes.TestComputev2):
|
||||
return volumes
|
||||
|
||||
def run_method_with_servers(self, method_name, server_count):
|
||||
# Starting with v2.91, the nova api needs to be call with a sentinel
|
||||
# as availability_zone=None will unpin the server az.
|
||||
_sentinel = object()
|
||||
|
||||
servers = self.setup_servers_mock(server_count)
|
||||
|
||||
arglist = []
|
||||
@ -183,7 +187,11 @@ class TestServer(compute_fakes.TestComputev2):
|
||||
method.assert_called_with(reason=None)
|
||||
elif method_name == 'unshelve':
|
||||
version = self.app.client_manager.compute.api_version
|
||||
if version >= api_versions.APIVersion('2.77'):
|
||||
if version >= api_versions.APIVersion('2.91'):
|
||||
method.assert_called_with(availability_zone=_sentinel,
|
||||
host=None)
|
||||
elif (version >= api_versions.APIVersion('2.77') and
|
||||
version < api_versions.APIVersion('2.91')):
|
||||
method.assert_called_with(availability_zone=None)
|
||||
else:
|
||||
method.assert_called_with()
|
||||
@ -8204,7 +8212,23 @@ class TestServerUnshelve(TestServer):
|
||||
def test_unshelve_multi_servers(self):
|
||||
self.run_method_with_servers('unshelve', 3)
|
||||
|
||||
def test_unshelve_with_specified_az(self):
|
||||
def test_unshelve_v277(self):
|
||||
self.app.client_manager.compute.api_version = \
|
||||
api_versions.APIVersion('2.77')
|
||||
|
||||
server = compute_fakes.FakeServer.create_one_server(
|
||||
attrs=self.attrs, methods=self.methods)
|
||||
self.servers_mock.get.return_value = server
|
||||
arglist = [server.id]
|
||||
verifylist = [('server', [server.id])]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.servers_mock.get.assert_called_with(server.id)
|
||||
server.unshelve.assert_called_with()
|
||||
|
||||
def test_unshelve_with_specified_az_v277(self):
|
||||
self.app.client_manager.compute.api_version = \
|
||||
api_versions.APIVersion('2.77')
|
||||
|
||||
@ -8248,6 +8272,157 @@ class TestServerUnshelve(TestServer):
|
||||
self.assertIn(
|
||||
'--os-compute-api-version 2.77 or greater is required', str(ex))
|
||||
|
||||
def test_unshelve_v291(self):
|
||||
self.app.client_manager.compute.api_version = (
|
||||
api_versions.APIVersion('2.91'))
|
||||
|
||||
server = compute_fakes.FakeServer.create_one_server(
|
||||
attrs=self.attrs, methods=self.methods)
|
||||
self.servers_mock.get.return_value = server
|
||||
arglist = [server.id]
|
||||
verifylist = [('server', [server.id])]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.servers_mock.get.assert_called_with(server.id)
|
||||
server.unshelve.assert_called_with()
|
||||
|
||||
def test_unshelve_with_specified_az_v291(self):
|
||||
self.app.client_manager.compute.api_version = (
|
||||
api_versions.APIVersion('2.91'))
|
||||
|
||||
server = compute_fakes.FakeServer.create_one_server(
|
||||
attrs=self.attrs, methods=self.methods)
|
||||
self.servers_mock.get.return_value = server
|
||||
arglist = [
|
||||
'--availability-zone', "foo-az",
|
||||
server.id,
|
||||
]
|
||||
verifylist = [
|
||||
('availability_zone', "foo-az"),
|
||||
('server', [server.id])
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.servers_mock.get.assert_called_with(server.id)
|
||||
server.unshelve.assert_called_with(availability_zone="foo-az")
|
||||
|
||||
def test_unshelve_with_specified_host_v291(self):
|
||||
self.app.client_manager.compute.api_version = (
|
||||
api_versions.APIVersion('2.91'))
|
||||
|
||||
server = compute_fakes.FakeServer.create_one_server(
|
||||
attrs=self.attrs, methods=self.methods)
|
||||
self.servers_mock.get.return_value = server
|
||||
arglist = [
|
||||
'--host', "server1",
|
||||
server.id,
|
||||
]
|
||||
verifylist = [
|
||||
('host', "server1"),
|
||||
('server', [server.id])
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.servers_mock.get.assert_called_with(server.id)
|
||||
server.unshelve.assert_called_with(host="server1")
|
||||
|
||||
def test_unshelve_with_unpin_az_v291(self):
|
||||
self.app.client_manager.compute.api_version = (
|
||||
api_versions.APIVersion('2.91'))
|
||||
|
||||
server = compute_fakes.FakeServer.create_one_server(
|
||||
attrs=self.attrs, methods=self.methods)
|
||||
self.servers_mock.get.return_value = server
|
||||
arglist = ['--no-availability-zone', server.id]
|
||||
verifylist = [
|
||||
('no_availability_zone', True),
|
||||
('server', [server.id])
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.servers_mock.get.assert_called_with(server.id)
|
||||
server.unshelve.assert_called_with(availability_zone=None)
|
||||
|
||||
def test_unshelve_with_specified_az_and_host_v291(self):
|
||||
self.app.client_manager.compute.api_version = (
|
||||
api_versions.APIVersion('2.91'))
|
||||
|
||||
server = compute_fakes.FakeServer.create_one_server(
|
||||
attrs=self.attrs, methods=self.methods)
|
||||
self.servers_mock.get.return_value = server
|
||||
arglist = [
|
||||
'--host', "server1",
|
||||
'--availability-zone', "foo-az",
|
||||
server.id,
|
||||
]
|
||||
verifylist = [
|
||||
('host', "server1"),
|
||||
('availability_zone', "foo-az"),
|
||||
('server', [server.id])
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.servers_mock.get.assert_called_with(server.id)
|
||||
|
||||
def test_unshelve_with_unpin_az_and_host_v291(self):
|
||||
self.app.client_manager.compute.api_version = (
|
||||
api_versions.APIVersion('2.91'))
|
||||
|
||||
server = compute_fakes.FakeServer.create_one_server(
|
||||
attrs=self.attrs, methods=self.methods)
|
||||
self.servers_mock.get.return_value = server
|
||||
arglist = [
|
||||
'--host', "server1",
|
||||
'--no-availability-zone',
|
||||
server.id,
|
||||
]
|
||||
verifylist = [
|
||||
('host', "server1"),
|
||||
('no_availability_zone', True),
|
||||
('server', [server.id])
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.servers_mock.get.assert_called_with(server.id)
|
||||
|
||||
def test_unshelve_fails_with_unpin_az_and_az_v291(self):
|
||||
self.app.client_manager.compute.api_version = (
|
||||
api_versions.APIVersion('2.91'))
|
||||
|
||||
server = compute_fakes.FakeServer.create_one_server(
|
||||
attrs=self.attrs, methods=self.methods)
|
||||
self.servers_mock.get.return_value = server
|
||||
arglist = [
|
||||
'--availability-zone', "foo-az",
|
||||
'--no-availability-zone',
|
||||
server.id,
|
||||
]
|
||||
verifylist = [
|
||||
('availability_zone', "foo-az"),
|
||||
('no_availability_zone', True),
|
||||
('server', [server.id])
|
||||
]
|
||||
|
||||
ex = self.assertRaises(utils.ParserException,
|
||||
self.check_parser,
|
||||
self.cmd, arglist, verifylist)
|
||||
self.assertIn('argument --no-availability-zone: not allowed '
|
||||
'with argument --availability-zone', str(ex))
|
||||
|
||||
@mock.patch.object(common_utils, 'wait_for_status', return_value=True)
|
||||
def test_unshelve_with_wait(self, mock_wait_for_status):
|
||||
server = compute_fakes.FakeServer.create_one_server(
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
features:
|
||||
- Add ``--host`` and ``--no-availability-zone`` options to the
|
||||
``server unshelve`` command to enable administrators to specify a
|
||||
destination host or unset the availability zone during a server
|
||||
unshelve, respectively. Both options require the server to be
|
||||
shelved offload and ``--os-compute-api-version 2.91`` or greater.
|
Loading…
x
Reference in New Issue
Block a user