diff options
| author | Zuul <zuul@review.opendev.org> | 2021-01-15 04:09:58 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2021-01-15 04:09:58 +0000 |
| commit | 3864ceea269a606c47dc8a26691d044c28fd3c87 (patch) | |
| tree | b0d2cc549186d792f496d7b6be22f4b3c3054c29 /openstackclient | |
| parent | 1febc8cd0335c6f9ffada9a3b24589b55b76f1af (diff) | |
| parent | ca7f23d0d1876dc53ef4d5ecbf2c5f367aafe13e (diff) | |
| download | python-openstackclient-3864ceea269a606c47dc8a26691d044c28fd3c87.tar.gz | |
Merge "compute: Add 'server volume update' command"
Diffstat (limited to 'openstackclient')
| -rw-r--r-- | openstackclient/compute/v2/server.py | 16 | ||||
| -rw-r--r-- | openstackclient/compute/v2/server_volume.py | 67 | ||||
| -rw-r--r-- | openstackclient/tests/unit/compute/v2/test_server_volume.py | 120 |
3 files changed, 195 insertions, 8 deletions
diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index 59fc4b7d..1b601efe 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -513,27 +513,27 @@ class AddServerVolume(command.Command): '--tag', metavar='<tag>', help=_( - "Tag for the attached volume. " - "(Supported by API versions '2.49' - '2.latest')" + 'Tag for the attached volume ' + '(supported by --os-compute-api-version 2.49 or above)' ), ) + # TODO(stephenfin): These should be called 'delete-on-termination' and + # 'preserve-on-termination' termination_group = parser.add_mutually_exclusive_group() termination_group.add_argument( '--enable-delete-on-termination', action='store_true', help=_( - "Specify if the attached volume should be deleted when the " - "server is destroyed. " - "(Supported by API versions '2.79' - '2.latest')" + 'Delete the volume when the server is destroyed ' + '(supported by --os-compute-api-version 2.79 or above)' ), ) termination_group.add_argument( '--disable-delete-on-termination', action='store_true', help=_( - "Specify if the attached volume should not be deleted when " - "the server is destroyed. " - "(Supported by API versions '2.79' - '2.latest')" + 'Do not delete the volume when the server is destroyed ' + '(supported by --os-compute-api-version 2.79 or above)' ), ) return parser diff --git a/openstackclient/compute/v2/server_volume.py b/openstackclient/compute/v2/server_volume.py index 8a931ae5..b53c92fe 100644 --- a/openstackclient/compute/v2/server_volume.py +++ b/openstackclient/compute/v2/server_volume.py @@ -16,6 +16,7 @@ from novaclient import api_versions from osc_lib.command import command +from osc_lib import exceptions from osc_lib import utils from openstackclient.i18n import _ @@ -71,3 +72,69 @@ class ListServerVolume(command.Lister): ) for s in volumes ), ) + + +class UpdateServerVolume(command.Command): + """Update a volume attachment on the server.""" + + def get_parser(self, prog_name): + parser = super(UpdateServerVolume, self).get_parser(prog_name) + parser.add_argument( + 'server', + help=_('Server to update volume for (name or ID)'), + ) + parser.add_argument( + 'volume', + help=_('Volume (ID)'), + ) + termination_group = parser.add_mutually_exclusive_group() + termination_group.add_argument( + '--delete-on-termination', + action='store_true', + dest='delete_on_termination', + default=None, + help=_( + 'Delete the volume when the server is destroyed ' + '(supported by --os-compute-api-version 2.85 or above)' + ), + ) + termination_group.add_argument( + '--preserve-on-termination', + action='store_false', + dest='delete_on_termination', + help=_( + 'Preserve the volume when the server is destroyed ' + '(supported by --os-compute-api-version 2.85 or above)' + ), + ) + return parser + + def take_action(self, parsed_args): + + compute_client = self.app.client_manager.compute + + if parsed_args.delete_on_termination is not None: + if compute_client.api_version < api_versions.APIVersion('2.85'): + msg = _( + '--os-compute-api-version 2.85 or greater is required to ' + 'support the --(no-)delete-on-termination option' + ) + raise exceptions.CommandError(msg) + + server = utils.find_resource( + compute_client.servers, + parsed_args.server, + ) + + # NOTE(stephenfin): This may look silly, and that's because it is. + # This API was originally used only for the swapping volumes, which + # is an internal operation that should only be done by + # orchestration software rather than a human. We're not going to + # expose that, but we are going to expose the ability to change the + # delete on termination behavior. + compute_client.volumes.update_server_volume( + server.id, + parsed_args.volume, + parsed_args.volume, + delete_on_termination=parsed_args.delete_on_termination, + ) diff --git a/openstackclient/tests/unit/compute/v2/test_server_volume.py b/openstackclient/tests/unit/compute/v2/test_server_volume.py index d09c2874..4d4916b7 100644 --- a/openstackclient/tests/unit/compute/v2/test_server_volume.py +++ b/openstackclient/tests/unit/compute/v2/test_server_volume.py @@ -12,6 +12,7 @@ # from novaclient import api_versions +from osc_lib import exceptions from openstackclient.compute.v2 import server_volume from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes @@ -165,3 +166,122 @@ class TestServerVolumeList(TestServerVolume): ) self.servers_volumes_mock.get_server_volumes.assert_called_once_with( self.server.id) + + +class TestServerVolumeUpdate(TestServerVolume): + + def setUp(self): + super().setUp() + + self.server = compute_fakes.FakeServer.create_one_server() + self.servers_mock.get.return_value = self.server + + # Get the command object to test + self.cmd = server_volume.UpdateServerVolume(self.app, None) + + def test_server_volume_update(self): + + arglist = [ + self.server.id, + 'foo', + ] + verifylist = [ + ('server', self.server.id), + ('volume', 'foo'), + ('delete_on_termination', None), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + + # This is a no-op + self.servers_volumes_mock.update_server_volume.assert_not_called() + self.assertIsNone(result) + + def test_server_volume_update_with_delete_on_termination(self): + self.app.client_manager.compute.api_version = \ + api_versions.APIVersion('2.85') + + arglist = [ + self.server.id, + 'foo', + '--delete-on-termination', + ] + verifylist = [ + ('server', self.server.id), + ('volume', 'foo'), + ('delete_on_termination', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + + self.servers_volumes_mock.update_server_volume.assert_called_once_with( + self.server.id, 'foo', 'foo', + delete_on_termination=True) + self.assertIsNone(result) + + def test_server_volume_update_with_preserve_on_termination(self): + self.app.client_manager.compute.api_version = \ + api_versions.APIVersion('2.85') + + arglist = [ + self.server.id, + 'foo', + '--preserve-on-termination', + ] + verifylist = [ + ('server', self.server.id), + ('volume', 'foo'), + ('delete_on_termination', False), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + + self.servers_volumes_mock.update_server_volume.assert_called_once_with( + self.server.id, 'foo', 'foo', + delete_on_termination=False) + self.assertIsNone(result) + + def test_server_volume_update_with_delete_on_termination_pre_v285(self): + self.app.client_manager.compute.api_version = \ + api_versions.APIVersion('2.84') + + arglist = [ + self.server.id, + 'foo', + '--delete-on-termination', + ] + verifylist = [ + ('server', self.server.id), + ('volume', 'foo'), + ('delete_on_termination', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.assertRaises( + exceptions.CommandError, + self.cmd.take_action, + parsed_args) + + def test_server_volume_update_with_preserve_on_termination_pre_v285(self): + self.app.client_manager.compute.api_version = \ + api_versions.APIVersion('2.84') + + arglist = [ + self.server.id, + 'foo', + '--preserve-on-termination', + ] + verifylist = [ + ('server', self.server.id), + ('volume', 'foo'), + ('delete_on_termination', False), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.assertRaises( + exceptions.CommandError, + self.cmd.take_action, + parsed_args) |
