Microversion 2.85: Change volume-update CLI
This commit add a new CLI ``nova volume-update [--[no-]delete-on-termination] <server> <src_volume> <dest_volume>`` to update 'delete_on_termination' for an attached volume, that the user can decide whether to delete attached volumes when destroying the server. Depends-On: https://review.opendev.org/#/c/711194/ Change-Id: I1fc64fb6e6611c92c6b72265e1bf4b32e9c45f0a Blueprint: destroy-instance-with-datavolume
This commit is contained in:
parent
ea092b2988
commit
4d6c70d25d
@ -558,10 +558,12 @@ nova usage
|
|||||||
Detach a volume from a server.
|
Detach a volume from a server.
|
||||||
|
|
||||||
``volume-update``
|
``volume-update``
|
||||||
Update the attachment on the server. Migrates
|
Update the attachment on the server. Migrates the data from an
|
||||||
the data from an attached volume to the
|
attached volume to the specified available volume and swaps out
|
||||||
specified available volume and swaps out the
|
the active attachment to the new volume.
|
||||||
active attachment to the new volume.
|
Since microversion 2.85, support for updating the
|
||||||
|
``delete_on_termination`` delete flag, which allows changing the
|
||||||
|
behavior of volume deletion on instance deletion.
|
||||||
|
|
||||||
``x509-create-cert``
|
``x509-create-cert``
|
||||||
**DEPRECATED** Create x509 cert for a user in
|
**DEPRECATED** Create x509 cert for a user in
|
||||||
@ -3896,7 +3898,7 @@ Attach a volume to a server.
|
|||||||
Tag for the attached volume. (Supported by API versions '2.49' - '2.latest')
|
Tag for the attached volume. (Supported by API versions '2.49' - '2.latest')
|
||||||
|
|
||||||
``--delete-on-termination``
|
``--delete-on-termination``
|
||||||
Specify if the attached volume sholud be deleted when the server is
|
Specify if the attached volume should be deleted when the server is
|
||||||
destroyed. By default the attached volume is not deleted when the server is
|
destroyed. By default the attached volume is not deleted when the server is
|
||||||
destroyed. (Supported by API versions '2.79' - '2.latest')
|
destroyed. (Supported by API versions '2.79' - '2.latest')
|
||||||
|
|
||||||
@ -3942,7 +3944,8 @@ nova volume-update
|
|||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
usage: nova volume-update <server> <src_volid> <dest_volid>
|
usage: nova volume-update [--[no-]delete-on-termination]
|
||||||
|
<server> <src_volume> <dest_volume>
|
||||||
|
|
||||||
Update the attachment on the server. Migrates the data from an attached volume
|
Update the attachment on the server. Migrates the data from an attached volume
|
||||||
to the specified available volume and swaps out the active attachment to the
|
to the specified available volume and swaps out the active attachment to the
|
||||||
@ -3953,12 +3956,22 @@ new volume.
|
|||||||
``<server>``
|
``<server>``
|
||||||
Name or ID of server.
|
Name or ID of server.
|
||||||
|
|
||||||
``<src_volid>``
|
``<src_volume>``
|
||||||
ID of the source (original) volume.
|
ID of the source (original) volume.
|
||||||
|
|
||||||
``<dest_volid>``
|
``<dest_volume>``
|
||||||
ID of the destination volume.
|
ID of the destination volume.
|
||||||
|
|
||||||
|
**Optional arguments:**
|
||||||
|
|
||||||
|
``--delete-on-termination``
|
||||||
|
Specify that the volume should be deleted when the server is destroyed.
|
||||||
|
(Supported by API versions '2.85' - '2.latest')
|
||||||
|
|
||||||
|
``--no-delete-on-termination``
|
||||||
|
Specify that the attached volume should not be deleted when
|
||||||
|
the server is destroyed. (Supported by API versions '2.85' - '2.latest')
|
||||||
|
|
||||||
.. _nova_bash-completion:
|
.. _nova_bash-completion:
|
||||||
|
|
||||||
nova bash-completion
|
nova bash-completion
|
||||||
|
@ -25,4 +25,4 @@ API_MIN_VERSION = api_versions.APIVersion("2.1")
|
|||||||
# when client supported the max version, and bumped sequentially, otherwise
|
# when client supported the max version, and bumped sequentially, otherwise
|
||||||
# the client may break due to server side new version may include some
|
# the client may break due to server side new version may include some
|
||||||
# backward incompatible change.
|
# backward incompatible change.
|
||||||
API_MAX_VERSION = api_versions.APIVersion("2.84")
|
API_MAX_VERSION = api_versions.APIVersion("2.85")
|
||||||
|
@ -3992,11 +3992,43 @@ class ShellTest(utils.TestCase):
|
|||||||
{'volumeAttachment':
|
{'volumeAttachment':
|
||||||
{'volumeId': 'Work'}})
|
{'volumeId': 'Work'}})
|
||||||
|
|
||||||
def test_volume_update(self):
|
def test_volume_update_pre_v285(self):
|
||||||
self.run_command('volume-update sample-server Work Work')
|
"""Before microversion 2.85, we should keep the original behavior"""
|
||||||
|
self.run_command('volume-update sample-server Work Work',
|
||||||
|
api_version='2.84')
|
||||||
self.assert_called('PUT', '/servers/1234/os-volume_attachments/Work',
|
self.assert_called('PUT', '/servers/1234/os-volume_attachments/Work',
|
||||||
{'volumeAttachment': {'volumeId': 'Work'}})
|
{'volumeAttachment': {'volumeId': 'Work'}})
|
||||||
|
|
||||||
|
def test_volume_update_swap_v285(self):
|
||||||
|
"""Microversion 2.85, we should also keep the original behavior."""
|
||||||
|
self.run_command('volume-update sample-server Work Work',
|
||||||
|
api_version='2.85')
|
||||||
|
self.assert_called('PUT', '/servers/1234/os-volume_attachments/Work',
|
||||||
|
{'volumeAttachment': {'volumeId': 'Work'}})
|
||||||
|
|
||||||
|
def test_volume_update_v285(self):
|
||||||
|
self.run_command('volume-update sample-server --delete-on-termination '
|
||||||
|
'Work Work', api_version='2.85')
|
||||||
|
body = {'volumeAttachment':
|
||||||
|
{'volumeId': 'Work', 'delete_on_termination': True}}
|
||||||
|
self.assert_called('PUT', '/servers/1234/os-volume_attachments/Work',
|
||||||
|
body)
|
||||||
|
|
||||||
|
self.run_command('volume-update sample-server '
|
||||||
|
'--no-delete-on-termination '
|
||||||
|
'Work Work', api_version='2.85')
|
||||||
|
body = {'volumeAttachment':
|
||||||
|
{'volumeId': 'Work', 'delete_on_termination': False}}
|
||||||
|
self.assert_called('PUT', '/servers/1234/os-volume_attachments/Work',
|
||||||
|
body)
|
||||||
|
|
||||||
|
def test_volume_update_v285_conflicting(self):
|
||||||
|
self.assertRaises(
|
||||||
|
SystemExit, self.run_command,
|
||||||
|
'volume-update sample-server --delete-on-termination '
|
||||||
|
'--no-delete-on-termination Work Work',
|
||||||
|
api_version='2.85')
|
||||||
|
|
||||||
def test_volume_detach(self):
|
def test_volume_detach(self):
|
||||||
self.run_command('volume-detach sample-server Work')
|
self.run_command('volume-detach sample-server Work')
|
||||||
self.assert_called('DELETE',
|
self.assert_called('DELETE',
|
||||||
|
@ -156,3 +156,26 @@ class VolumesV279Test(VolumesV249Test):
|
|||||||
volume_id='15e59938-07d5-11e1-90e3-e3dffe0c5983',
|
volume_id='15e59938-07d5-11e1-90e3-e3dffe0c5983',
|
||||||
delete_on_termination=True)
|
delete_on_termination=True)
|
||||||
self.assertIn('delete_on_termination', str(ex))
|
self.assertIn('delete_on_termination', str(ex))
|
||||||
|
|
||||||
|
|
||||||
|
class VolumesV285Test(VolumesV279Test):
|
||||||
|
api_version = "2.85"
|
||||||
|
|
||||||
|
def test_volume_update_server_volume(self):
|
||||||
|
v = self.cs.volumes.update_server_volume(
|
||||||
|
server_id=1234,
|
||||||
|
src_volid='Work',
|
||||||
|
dest_volid='Work',
|
||||||
|
delete_on_termination=True
|
||||||
|
)
|
||||||
|
self.assert_request_id(v, fakes.FAKE_REQUEST_ID_LIST)
|
||||||
|
self.cs.assert_called('PUT',
|
||||||
|
'/servers/1234/os-volume_attachments/Work')
|
||||||
|
self.assertIsInstance(v, volumes.Volume)
|
||||||
|
|
||||||
|
def test_volume_update_server_volume_pre_v285(self):
|
||||||
|
self.cs.api_version = api_versions.APIVersion('2.84')
|
||||||
|
ex = self.assertRaises(
|
||||||
|
TypeError, self.cs.volumes.update_server_volume, "1234",
|
||||||
|
'Work', 'Work', delete_on_termination=True)
|
||||||
|
self.assertIn('delete_on_termination', str(ex))
|
||||||
|
@ -2730,22 +2730,44 @@ def do_volume_attach(cs, args):
|
|||||||
help=_('Name or ID of server.'))
|
help=_('Name or ID of server.'))
|
||||||
@utils.arg(
|
@utils.arg(
|
||||||
'src_volume',
|
'src_volume',
|
||||||
metavar='<src_volid>',
|
metavar='<src_volume>',
|
||||||
help=_('ID of the source (original) volume.'))
|
help=_('ID of the source (original) volume.'))
|
||||||
@utils.arg(
|
@utils.arg(
|
||||||
'dest_volume',
|
'dest_volume',
|
||||||
metavar='<dest_volid>',
|
metavar='<dest_volume>',
|
||||||
help=_('ID of the destination volume.'))
|
help=_('ID of the destination volume.'))
|
||||||
|
@utils.arg(
|
||||||
|
'--delete-on-termination',
|
||||||
|
default=None,
|
||||||
|
group='delete_on_termination',
|
||||||
|
action='store_true',
|
||||||
|
help=_('Specify that the volume should be deleted '
|
||||||
|
'when the server is destroyed.'),
|
||||||
|
start_version='2.85')
|
||||||
|
@utils.arg(
|
||||||
|
'--no-delete-on-termination',
|
||||||
|
group='delete_on_termination',
|
||||||
|
action='store_false',
|
||||||
|
help=_('Specify that the volume should not be deleted '
|
||||||
|
'when the server is destroyed.'),
|
||||||
|
start_version='2.85')
|
||||||
def do_volume_update(cs, args):
|
def do_volume_update(cs, args):
|
||||||
"""Update the attachment on the server.
|
"""Update the attachment on the server.
|
||||||
|
|
||||||
Migrates the data from an attached volume to the
|
If dest_volume is the same as the src_volume then the command migrates
|
||||||
specified available volume and swaps out the active
|
the data from the attached volume to the specified available volume
|
||||||
attachment to the new volume.
|
and swaps out the active attachment to the new volume. Otherwise it
|
||||||
|
only updates the parameters of the existing attachment.
|
||||||
"""
|
"""
|
||||||
|
kwargs = dict()
|
||||||
|
if (cs.api_version >= api_versions.APIVersion('2.85') and
|
||||||
|
args.delete_on_termination is not None):
|
||||||
|
kwargs['delete_on_termination'] = args.delete_on_termination
|
||||||
|
|
||||||
cs.volumes.update_server_volume(_find_server(cs, args.server).id,
|
cs.volumes.update_server_volume(_find_server(cs, args.server).id,
|
||||||
args.src_volume,
|
args.src_volume,
|
||||||
args.dest_volume)
|
args.dest_volume,
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
|
||||||
@utils.arg(
|
@utils.arg(
|
||||||
|
@ -103,6 +103,7 @@ class VolumeManager(base.Manager):
|
|||||||
return self._create("/servers/%s/os-volume_attachments" % server_id,
|
return self._create("/servers/%s/os-volume_attachments" % server_id,
|
||||||
body, "volumeAttachment")
|
body, "volumeAttachment")
|
||||||
|
|
||||||
|
@api_versions.wraps("2.0", "2.84")
|
||||||
def update_server_volume(self, server_id, src_volid, dest_volid):
|
def update_server_volume(self, server_id, src_volid, dest_volid):
|
||||||
"""
|
"""
|
||||||
Swaps the existing volume attachment to point to a new volume.
|
Swaps the existing volume attachment to point to a new volume.
|
||||||
@ -124,6 +125,35 @@ class VolumeManager(base.Manager):
|
|||||||
(server_id, src_volid,),
|
(server_id, src_volid,),
|
||||||
body, "volumeAttachment")
|
body, "volumeAttachment")
|
||||||
|
|
||||||
|
@api_versions.wraps("2.85")
|
||||||
|
def update_server_volume(self, server_id, src_volid, dest_volid,
|
||||||
|
delete_on_termination=None):
|
||||||
|
"""
|
||||||
|
Swaps the existing volume attachment to point to a new volume.
|
||||||
|
|
||||||
|
Takes a server, a source (attached) volume and a destination volume and
|
||||||
|
performs a hypervisor assisted data migration from src to dest volume,
|
||||||
|
detaches the original (source) volume and attaches the new destination
|
||||||
|
volume. Note that not all backing hypervisor drivers support this
|
||||||
|
operation and it may be disabled via policy.
|
||||||
|
|
||||||
|
|
||||||
|
:param server_id: The ID of the server
|
||||||
|
:param source_volume: The ID of the src volume
|
||||||
|
:param dest_volume: The ID of the destination volume
|
||||||
|
:param delete_on_termination: Marked whether to delete the attached
|
||||||
|
volume when the server is deleted
|
||||||
|
(optional).
|
||||||
|
:rtype: :class:`Volume`
|
||||||
|
"""
|
||||||
|
body = {'volumeAttachment': {'volumeId': dest_volid}}
|
||||||
|
if delete_on_termination is not None:
|
||||||
|
body['volumeAttachment']['delete_on_termination'] = (
|
||||||
|
delete_on_termination)
|
||||||
|
return self._update("/servers/%s/os-volume_attachments/%s" %
|
||||||
|
(server_id, src_volid),
|
||||||
|
body, "volumeAttachment")
|
||||||
|
|
||||||
def get_server_volume(self, server_id, volume_id=None, attachment_id=None):
|
def get_server_volume(self, server_id, volume_id=None, attachment_id=None):
|
||||||
"""
|
"""
|
||||||
Get the volume identified by the volume ID, that is attached to
|
Get the volume identified by the volume ID, that is attached to
|
||||||
|
16
releasenotes/notes/microversion-v2_85-230931f88c4f1d52.yaml
Normal file
16
releasenotes/notes/microversion-v2_85-230931f88c4f1d52.yaml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Support is added for compute API `microversion 2.85`_. This adds the
|
||||||
|
ability to update an attached volume with a ``delete_on_termination``,
|
||||||
|
which specify if the attached volume should be deleted when the server
|
||||||
|
is destroyed.
|
||||||
|
|
||||||
|
- The ``--delete-on-termination`` and ``--no-delete-on-termination``
|
||||||
|
options are added to the ``nova volume-update`` CLI.
|
||||||
|
- New kwarg called ``delete_on_termination`` added to the python API
|
||||||
|
binding:
|
||||||
|
|
||||||
|
- ``novaclient.v2.volumes.VolumeManager.update_server_volume()``
|
||||||
|
|
||||||
|
.. _microversion 2.85: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id78
|
Loading…
Reference in New Issue
Block a user