Skip to content

Commit cd396b8

Browse files
1049965823mriedem
authored andcommitted
Microversion 2.79: Add delete_on_termination to volume-attach API
Support add 'delete_on_termination' field to the voume attach API to support configuring whether to delete the data volume when the server is destroyed. * Updating the ``nova volume-attachments`` command to show the ``delete_on_termination`` value if 2.79 or greater is used. * The '--delete-on-termination' option is added to the `nova volume-attach` CLI. Depends-On: https://review.opendev.org/#/c/673133/ Part of blueprint support-delete-on-termination-in-server-attach-volume Change-Id: I8dcf2fd21a2fd99ca4e05bd953fbbe026be3a619
1 parent aae95dc commit cd396b8

File tree

8 files changed

+144
-3
lines changed

8 files changed

+144
-3
lines changed

doc/source/cli/nova.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3849,7 +3849,8 @@ nova volume-attach
38493849

38503850
.. code-block:: console
38513851
3852-
usage: nova volume-attach [--tag <tag>] <server> <volume> [<device>]
3852+
usage: nova volume-attach [--delete-on-termination] [--tag <tag>]
3853+
<server> <volume> [<device>]
38533854
38543855
Attach a volume to a server.
38553856

@@ -3870,6 +3871,11 @@ Attach a volume to a server.
38703871
``--tag <tag>``
38713872
Tag for the attached volume. (Supported by API versions '2.49' - '2.latest')
38723873

3874+
``--delete-on-termination``
3875+
Specify if the attached volume sholud be deleted when the server is
3876+
destroyed. By default the attached volume is not deleted when the server is
3877+
destroyed. (Supported by API versions '2.79' - '2.latest')
3878+
38733879
.. _nova_volume-attachments:
38743880

38753881
nova volume-attachments

novaclient/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,4 @@
2525
# when client supported the max version, and bumped sequentially, otherwise
2626
# the client may break due to server side new version may include some
2727
# backward incompatible change.
28-
API_MAX_VERSION = api_versions.APIVersion("2.78")
28+
API_MAX_VERSION = api_versions.APIVersion("2.79")

novaclient/tests/unit/v2/fakes.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2115,6 +2115,11 @@ def post_servers_1234_os_volume_attachments(self, **kw):
21152115
if self.api_version >= api_versions.APIVersion('2.70'):
21162116
# Include the "tag" field in the response.
21172117
attachment['tag'] = 'test-tag'
2118+
2119+
if self.api_version >= api_versions.APIVersion('2.79'):
2120+
# Include the "delete_on_termination" field in the
2121+
# response.
2122+
attachment['delete_on_termination'] = True
21182123
return (200, FAKE_RESPONSE_HEADERS, {"volumeAttachment": attachment})
21192124

21202125
def put_servers_1234_os_volume_attachments_Work(self, **kw):
@@ -2139,6 +2144,12 @@ def get_servers_1234_os_volume_attachments(self, **kw):
21392144
# Include the "tag" field in each attachment.
21402145
for attachment in attachments['volumeAttachments']:
21412146
attachment['tag'] = 'test-tag'
2147+
2148+
if self.api_version >= api_versions.APIVersion('2.79'):
2149+
# Include the "delete_on_termination" field in each
2150+
# attachment.
2151+
for attachment in attachments['volumeAttachments']:
2152+
attachment['delete_on_termination'] = True
21422153
return (200, FAKE_RESPONSE_HEADERS, attachments)
21432154

21442155
def get_servers_1234_os_volume_attachments_Work(self, **kw):

novaclient/tests/unit/v2/test_shell.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3825,6 +3825,42 @@ def test_volume_attach_with_tag_v2_70(self):
38253825
'tag': 'test-tag'}})
38263826
self.assertIn('test-tag', out)
38273827

3828+
def test_volume_attachments_pre_v2_79(self):
3829+
out = self.run_command(
3830+
'volume-attachments 1234', api_version='2.78')[0]
3831+
self.assert_called('GET', '/servers/1234/os-volume_attachments')
3832+
self.assertNotIn('DELETE ON TERMINATION', out)
3833+
3834+
def test_volume_attachments_v2_79(self):
3835+
out = self.run_command(
3836+
'volume-attachments 1234', api_version='2.79')[0]
3837+
self.assert_called('GET', '/servers/1234/os-volume_attachments')
3838+
self.assertIn('DELETE ON TERMINATION', out)
3839+
3840+
def test_volume_attach_with_delete_on_termination_pre_v2_79(self):
3841+
self.assertRaises(
3842+
SystemExit, self.run_command,
3843+
'volume-attach --delete-on-termination sample-server '
3844+
'Work /dev/vdb', api_version='2.78')
3845+
3846+
def test_volume_attach_with_delete_on_termination_v2_79(self):
3847+
out = self.run_command(
3848+
'volume-attach --delete-on-termination sample-server '
3849+
'2 /dev/vdb', api_version='2.79')[0]
3850+
self.assert_called('POST', '/servers/1234/os-volume_attachments',
3851+
{'volumeAttachment':
3852+
{'device': '/dev/vdb',
3853+
'volumeId': '2',
3854+
'delete_on_termination': True}})
3855+
self.assertIn('delete_on_termination', out)
3856+
3857+
def test_volume_attach_without_delete_on_termination(self):
3858+
self.run_command('volume-attach sample-server Work',
3859+
api_version='2.79')
3860+
self.assert_called('POST', '/servers/1234/os-volume_attachments',
3861+
{'volumeAttachment':
3862+
{'volumeId': 'Work'}})
3863+
38283864
def test_volume_update(self):
38293865
self.run_command('volume-update sample-server Work Work')
38303866
self.assert_called('PUT', '/servers/1234/os-volume_attachments/Work',

novaclient/tests/unit/v2/test_volumes.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
# under the License.
1515

1616
import mock
17+
import six
1718

1819
from novaclient import api_versions
1920
from novaclient.tests.unit import utils
@@ -126,3 +127,33 @@ def test_delete_server_volume_with_warn(self, mock_warn):
126127
volume_id=None,
127128
attachment_id="Work")
128129
mock_warn.assert_called_once()
130+
131+
132+
class VolumesV279Test(VolumesV249Test):
133+
api_version = "2.79"
134+
135+
def test_create_server_volume_with_delete_on_termination(self):
136+
v = self.cs.volumes.create_server_volume(
137+
server_id=1234,
138+
volume_id='15e59938-07d5-11e1-90e3-e3dffe0c5983',
139+
device='/dev/vdb',
140+
tag='tag1',
141+
delete_on_termination=True
142+
)
143+
self.assert_request_id(v, fakes.FAKE_REQUEST_ID_LIST)
144+
self.cs.assert_called(
145+
'POST', '/servers/1234/os-volume_attachments',
146+
{'volumeAttachment': {
147+
'volumeId': '15e59938-07d5-11e1-90e3-e3dffe0c5983',
148+
'device': '/dev/vdb',
149+
'tag': 'tag1',
150+
'delete_on_termination': True}})
151+
self.assertIsInstance(v, volumes.Volume)
152+
153+
def test_create_server_volume_with_delete_on_termination_pre_v279(self):
154+
self.cs.api_version = api_versions.APIVersion('2.78')
155+
ex = self.assertRaises(
156+
TypeError, self.cs.volumes.create_server_volume, "1234",
157+
volume_id='15e59938-07d5-11e1-90e3-e3dffe0c5983',
158+
delete_on_termination=True)
159+
self.assertIn('delete_on_termination', six.text_type(ex))

novaclient/v2/shell.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2633,6 +2633,13 @@ def _translate_volume_attachments_keys(collection):
26332633
default=None,
26342634
help=_('Tag for the attached volume.'),
26352635
start_version="2.49")
2636+
@utils.arg(
2637+
'--delete-on-termination',
2638+
action='store_true',
2639+
default=False,
2640+
help=_('Specify if the attached volume should be deleted '
2641+
'when the server is destroyed.'),
2642+
start_version="2.79")
26362643
def do_volume_attach(cs, args):
26372644
"""Attach a volume to a server."""
26382645
if args.device == 'auto':
@@ -2642,6 +2649,9 @@ def do_volume_attach(cs, args):
26422649
if 'tag' in args and args.tag:
26432650
update_kwargs['tag'] = args.tag
26442651

2652+
if 'delete_on_termination' in args and args.delete_on_termination:
2653+
update_kwargs['delete_on_termination'] = args.delete_on_termination
2654+
26452655
volume = cs.volumes.create_server_volume(_find_server(cs, args.server).id,
26462656
args.volume,
26472657
args.device,
@@ -2699,6 +2709,9 @@ def do_volume_attachments(cs, args):
26992709
fields = ['ID', 'DEVICE', 'SERVER ID', 'VOLUME ID']
27002710
if cs.api_version >= api_versions.APIVersion('2.70'):
27012711
fields.append('TAG')
2712+
# Microversion >= 2.79 returns the delete_on_termination value.
2713+
if cs.api_version >= api_versions.APIVersion('2.79'):
2714+
fields.append('DELETE ON TERMINATION')
27022715
utils.print_list(volumes, fields)
27032716

27042717

novaclient/v2/volumes.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def create_server_volume(self, server_id, volume_id, device=None):
5555
return self._create("/servers/%s/os-volume_attachments" % server_id,
5656
body, "volumeAttachment")
5757

58-
@api_versions.wraps("2.49")
58+
@api_versions.wraps("2.49", "2.78")
5959
def create_server_volume(self, server_id, volume_id, device=None,
6060
tag=None):
6161
"""
@@ -75,6 +75,34 @@ def create_server_volume(self, server_id, volume_id, device=None,
7575
return self._create("/servers/%s/os-volume_attachments" % server_id,
7676
body, "volumeAttachment")
7777

78+
@api_versions.wraps("2.79")
79+
def create_server_volume(self, server_id, volume_id, device=None,
80+
tag=None, delete_on_termination=False):
81+
"""
82+
Attach a volume identified by the volume ID to the given server ID
83+
84+
:param server_id: The ID of the server.
85+
:param volume_id: The ID of the volume to attach.
86+
:param device: The device name (optional).
87+
:param tag: The tag (optional).
88+
:param delete_on_termination: Marked whether to delete the attached
89+
volume when the server is deleted
90+
(optional).
91+
:rtype: :class:`Volume`
92+
"""
93+
# TODO(mriedem): Move this body construction into a private common
94+
# helper method for all versions of create_server_volume to use.
95+
body = {'volumeAttachment': {'volumeId': volume_id}}
96+
if device is not None:
97+
body['volumeAttachment']['device'] = device
98+
if tag is not None:
99+
body['volumeAttachment']['tag'] = tag
100+
if delete_on_termination:
101+
body['volumeAttachment']['delete_on_termination'] = (
102+
delete_on_termination)
103+
return self._create("/servers/%s/os-volume_attachments" % server_id,
104+
body, "volumeAttachment")
105+
78106
def update_server_volume(self, server_id, src_volid, dest_volid):
79107
"""
80108
Swaps the existing volume attachment to point to a new volume.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
features:
3+
- |
4+
Added support for `microversion 2.79`_ which includes the following
5+
changes:
6+
7+
- The ``--delete-on-termination`` option is added to the
8+
``nova volume-attach`` CLI.
9+
- A ``DELETE ON TERMINATION`` column is added to the
10+
``nova volume-attachments`` table.
11+
- New kwarg called ``delete_on_termination`` added to the python API
12+
binding:
13+
14+
- ``novaclient.v2.volumes.VolumeManager.create_server_volume()``
15+
16+
.. _microversion 2.79: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id71

0 commit comments

Comments
 (0)