Merge "Microversion 2.91: Support specifying destination host to unshelve"
This commit is contained in:
		| @@ -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. | ||||
		Reference in New Issue
	
	Block a user
	 Zuul
					Zuul