Merge "compute: Add 'server volume update' command"
This commit is contained in:
commit
3864ceea26
@ -71,7 +71,7 @@ python-cinderclient==3.3.0
|
||||
python-dateutil==2.5.3
|
||||
python-keystoneclient==3.22.0
|
||||
python-mimeparse==1.6.0
|
||||
python-novaclient==15.1.0
|
||||
python-novaclient==17.0.0
|
||||
python-subunit==1.0.0
|
||||
pytz==2013.6
|
||||
PyYAML==3.13
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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)
|
||||
|
@ -3,3 +3,6 @@ features:
|
||||
- |
|
||||
Add ``server volume list`` command, to list the volumes attached to an
|
||||
instance.
|
||||
- |
|
||||
Add ``server volume update`` command, to update the volumes attached to
|
||||
an instance.
|
||||
|
@ -9,6 +9,6 @@ openstacksdk>=0.52.0 # Apache-2.0
|
||||
osc-lib>=2.3.0 # Apache-2.0
|
||||
oslo.i18n>=3.15.3 # Apache-2.0
|
||||
python-keystoneclient>=3.22.0 # Apache-2.0
|
||||
python-novaclient>=15.1.0 # Apache-2.0
|
||||
python-novaclient>=17.0.0 # Apache-2.0
|
||||
python-cinderclient>=3.3.0 # Apache-2.0
|
||||
stevedore>=2.0.1 # Apache-2.0
|
||||
|
@ -154,6 +154,7 @@ openstack.compute.v2 =
|
||||
server_image_create = openstackclient.compute.v2.server_image:CreateServerImage
|
||||
|
||||
server_volume_list = openstackclient.compute.v2.server_volume:ListServerVolume
|
||||
server_volume_update = openstackclient.compute.v2.server_volume:UpdateServerVolume
|
||||
|
||||
usage_list = openstackclient.compute.v2.usage:ListUsage
|
||||
usage_show = openstackclient.compute.v2.usage:ShowUsage
|
||||
|
Loading…
Reference in New Issue
Block a user