diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index 33545a74e8..59fc4b7d44 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -4131,25 +4131,54 @@ class UnshelveServer(command.Command): 'SHELVED_OFFLOADED server (supported by ' '--os-compute-api-version 2.77 or above)'), ) + parser.add_argument( + '--wait', + action='store_true', + default=False, + help=_('Wait for unshelve operation to complete'), + ) return parser def take_action(self, parsed_args): + + def _show_progress(progress): + if progress: + self.app.stdout.write('\rProgress: %s' % progress) + self.app.stdout.flush() + compute_client = self.app.client_manager.compute - support_az = compute_client.api_version >= api_versions.APIVersion( - '2.77') - if not support_az and parsed_args.availability_zone: - msg = _("--os-compute-api-version 2.77 or greater is required " - "to support the '--availability-zone' option.") - raise exceptions.CommandError(msg) + kwargs = {} + + if parsed_args.availability_zone: + if compute_client.api_version < api_versions.APIVersion('2.77'): + msg = _( + '--os-compute-api-version 2.77 or greater is required ' + 'to support the --availability-zone option' + ) + raise exceptions.CommandError(msg) + + kwargs['availability_zone'] = parsed_args.availability_zone for server in parsed_args.server: - if support_az: - utils.find_resource( - compute_client.servers, - server - ).unshelve(availability_zone=parsed_args.availability_zone) - else: - utils.find_resource( - compute_client.servers, - server, - ).unshelve() + server_obj = utils.find_resource( + compute_client.servers, + server, + ) + + if server_obj.status.lower() not in ( + 'shelved', 'shelved_offloaded', + ): + continue + + server_obj.unshelve(**kwargs) + + if parsed_args.wait: + if not utils.wait_for_status( + compute_client.servers.get, server_obj.id, + success_status=('active', 'shutoff'), + callback=_show_progress, + ): + LOG.error(_('Error unshelving server %s'), server_obj.id) + self.app.stdout.write( + _('Error unshelving server: %s\n') % server_obj.id) + raise SystemExit diff --git a/openstackclient/tests/unit/compute/v2/test_server.py b/openstackclient/tests/unit/compute/v2/test_server.py index 9ad6d15508..2c0cadfc88 100644 --- a/openstackclient/tests/unit/compute/v2/test_server.py +++ b/openstackclient/tests/unit/compute/v2/test_server.py @@ -6969,6 +6969,9 @@ class TestServerUnshelve(TestServer): self.methods = { 'unshelve': None, } + self.attrs = { + 'status': 'SHELVED', + } def test_unshelve_one_server(self): self.run_method_with_servers('unshelve', 1) @@ -6976,8 +6979,34 @@ class TestServerUnshelve(TestServer): def test_unshelve_multi_servers(self): self.run_method_with_servers('unshelve', 3) - def test_unshelve_server_with_specified_az(self): - server = compute_fakes.FakeServer.create_one_server() + def test_unshelve_with_specified_az(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 = [ + '--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_az_pre_v277(self): + self.app.client_manager.compute.api_version = \ + api_versions.APIVersion('2.76') + + server = compute_fakes.FakeServer.create_one_server( + attrs=self.attrs, methods=self.methods) arglist = [ server.id, '--availability-zone', "foo-az", @@ -6987,44 +7016,37 @@ class TestServerUnshelve(TestServer): ('server', [server.id]) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) - ex = self.assertRaises(exceptions.CommandError, - self.cmd.take_action, - parsed_args) + ex = self.assertRaises( + exceptions.CommandError, + self.cmd.take_action, + parsed_args) self.assertIn( '--os-compute-api-version 2.77 or greater is required', 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( + attrs=self.attrs, methods=self.methods) + self.servers_mock.get.return_value = server -class TestServerUnshelveV277(TestServerUnshelve): - - def setUp(self): - super(TestServerUnshelveV277, self).setUp() - - self.server = compute_fakes.FakeServer.create_one_server( - methods=self.methods) - - # This is the return value for utils.find_resource() - self.servers_mock.get.return_value = self.server - - # Get the command object to test - self.cmd = server.UnshelveServer(self.app, None) - - def test_specified_az_to_unshelve_with_v277(self): - self.app.client_manager.compute.api_version = api_versions.APIVersion( - '2.77') - - arglist = [ - '--availability-zone', "foo-az", - self.server.id, - ] + arglist = ['--wait', server.name] verifylist = [ - ('availability_zone', "foo-az"), - ('server', [self.server.id]) + ('server', [server.name]), + ('wait', True), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - self.servers_mock.get.assert_called_with(self.server.id) - self.server.unshelve.assert_called_with(availability_zone="foo-az") + result = self.cmd.take_action(parsed_args) + self.assertIsNone(result) + + self.servers_mock.get.assert_called_once_with(server.name) + server.unshelve.assert_called_once_with() + mock_wait_for_status.assert_called_once_with( + self.servers_mock.get, + server.id, + callback=mock.ANY, + success_status=('active', 'shutoff'), + ) class TestServerGeneral(TestServer): diff --git a/releasenotes/notes/add-shelve-offload-wait-d0a5c8ba92586f72.yaml b/releasenotes/notes/add-shelve-offload-wait-d0a5c8ba92586f72.yaml index ddd3293191..750abd6af1 100644 --- a/releasenotes/notes/add-shelve-offload-wait-d0a5c8ba92586f72.yaml +++ b/releasenotes/notes/add-shelve-offload-wait-d0a5c8ba92586f72.yaml @@ -6,3 +6,5 @@ features: server in environments where automatic offloading is not configured, while ``--wait`` allows users to wait for the shelve and/or shelve offload operations to complete. + - | + Add support ``--wait`` option for ``server shelve``.