Skip to content

Commit 874a726

Browse files
1049965823Dean Troyer
authored andcommitted
Microversion 2.79: Add delete_on_termination to volume-attach API
Added ``--disable-delete-on-termination`` and ``--enable-delete-on-termination`` options to the ``openstack server add volume`` command that enables users to mark whether to delete the attached volume when the server is destroyed. Depends-On: https://review.opendev.org/#/c/681267/ Part of blueprint support-delete-on-termination-in-server-attach-volume Change-Id: I6b5cd54b82a1135335a71b9768a1a2c2012f755b
1 parent c6a171f commit 874a726

5 files changed

Lines changed: 223 additions & 3 deletions

File tree

lower-constraints.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ python-mimeparse==1.6.0
100100
python-mistralclient==3.1.0
101101
python-muranoclient==0.8.2
102102
python-neutronclient==6.7.0
103-
python-novaclient==15.0.0
103+
python-novaclient==15.1.0
104104
python-octaviaclient==1.11.0
105105
python-rsdclient==1.0.1
106106
python-saharaclient==1.4.0

openstackclient/compute/v2/server.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,21 @@ def get_parser(self, prog_name):
446446
metavar='<device>',
447447
help=_('Server internal device name for volume'),
448448
)
449+
termination_group = parser.add_mutually_exclusive_group()
450+
termination_group.add_argument(
451+
'--enable-delete-on-termination',
452+
action='store_true',
453+
help=_("Specify if the attached volume should be deleted when "
454+
"the server is destroyed. (Supported with "
455+
"``--os-compute-api-version`` 2.79 or greater.)"),
456+
)
457+
termination_group.add_argument(
458+
'--disable-delete-on-termination',
459+
action='store_true',
460+
help=_("Specify if the attached volume should not be deleted "
461+
"when the server is destroyed. (Supported with "
462+
"``--os-compute-api-version`` 2.79 or greater.)"),
463+
)
449464
return parser
450465

451466
def take_action(self, parsed_args):
@@ -461,10 +476,34 @@ def take_action(self, parsed_args):
461476
parsed_args.volume,
462477
)
463478

479+
support_set_delete_on_termination = (compute_client.api_version >=
480+
api_versions.APIVersion('2.79'))
481+
482+
if not support_set_delete_on_termination:
483+
if parsed_args.enable_delete_on_termination:
484+
msg = _('--os-compute-api-version 2.79 or greater '
485+
'is required to support the '
486+
'--enable-delete-on-termination option.')
487+
raise exceptions.CommandError(msg)
488+
if parsed_args.disable_delete_on_termination:
489+
msg = _('--os-compute-api-version 2.79 or greater '
490+
'is required to support the '
491+
'--disable-delete-on-termination option.')
492+
raise exceptions.CommandError(msg)
493+
494+
kwargs = {
495+
"device": parsed_args.device
496+
}
497+
498+
if parsed_args.enable_delete_on_termination:
499+
kwargs['delete_on_termination'] = True
500+
if parsed_args.disable_delete_on_termination:
501+
kwargs['delete_on_termination'] = False
502+
464503
compute_client.volumes.create_server_volume(
465504
server.id,
466505
volume.id,
467-
parsed_args.device,
506+
**kwargs
468507
)
469508

470509

openstackclient/tests/unit/compute/v2/test_server.py

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ def setUp(self):
4343
self.servers_mock = self.app.client_manager.compute.servers
4444
self.servers_mock.reset_mock()
4545

46+
# Get a shortcut to the compute client volumeManager Mock
47+
self.servers_volumes_mock = self.app.client_manager.compute.volumes
48+
self.servers_volumes_mock.reset_mock()
49+
4650
# Get a shortcut to the compute client FlavorManager Mock
4751
self.flavors_mock = self.app.client_manager.compute.flavors
4852
self.flavors_mock.reset_mock()
@@ -457,6 +461,174 @@ def test_server_add_port_no_neutron(self):
457461
self.find_port.assert_not_called()
458462

459463

464+
class TestServerVolume(TestServer):
465+
466+
def setUp(self):
467+
super(TestServerVolume, self).setUp()
468+
469+
self.volume = volume_fakes.FakeVolume.create_one_volume()
470+
self.volumes_mock.get.return_value = self.volume
471+
472+
self.methods = {
473+
'create_server_volume': None,
474+
}
475+
476+
# Get the command object to test
477+
self.cmd = server.AddServerVolume(self.app, None)
478+
479+
def test_server_add_volume(self):
480+
servers = self.setup_servers_mock(count=1)
481+
arglist = [
482+
'--device', '/dev/sdb',
483+
servers[0].id,
484+
self.volume.id,
485+
]
486+
verifylist = [
487+
('server', servers[0].id),
488+
('volume', self.volume.id),
489+
('device', '/dev/sdb'),
490+
]
491+
492+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
493+
494+
result = self.cmd.take_action(parsed_args)
495+
496+
self.servers_volumes_mock.create_server_volume.assert_called_once_with(
497+
servers[0].id, self.volume.id, device='/dev/sdb')
498+
self.assertIsNone(result)
499+
500+
501+
class TestServerVolumeV279(TestServerVolume):
502+
503+
def test_server_add_volume_with_enable_delete_on_termination(self):
504+
self.app.client_manager.compute.api_version = api_versions.APIVersion(
505+
'2.79')
506+
507+
servers = self.setup_servers_mock(count=1)
508+
arglist = [
509+
'--enable-delete-on-termination',
510+
'--device', '/dev/sdb',
511+
servers[0].id,
512+
self.volume.id,
513+
]
514+
515+
verifylist = [
516+
('server', servers[0].id),
517+
('volume', self.volume.id),
518+
('device', '/dev/sdb'),
519+
('enable_delete_on_termination', True),
520+
]
521+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
522+
523+
result = self.cmd.take_action(parsed_args)
524+
525+
self.servers_volumes_mock.create_server_volume.assert_called_once_with(
526+
servers[0].id, self.volume.id,
527+
device='/dev/sdb', delete_on_termination=True)
528+
self.assertIsNone(result)
529+
530+
def test_server_add_volume_with_disable_delete_on_termination(self):
531+
self.app.client_manager.compute.api_version = api_versions.APIVersion(
532+
'2.79')
533+
534+
servers = self.setup_servers_mock(count=1)
535+
arglist = [
536+
'--disable-delete-on-termination',
537+
'--device', '/dev/sdb',
538+
servers[0].id,
539+
self.volume.id,
540+
]
541+
542+
verifylist = [
543+
('server', servers[0].id),
544+
('volume', self.volume.id),
545+
('device', '/dev/sdb'),
546+
('disable_delete_on_termination', True),
547+
]
548+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
549+
550+
result = self.cmd.take_action(parsed_args)
551+
552+
self.servers_volumes_mock.create_server_volume.assert_called_once_with(
553+
servers[0].id, self.volume.id,
554+
device='/dev/sdb', delete_on_termination=False)
555+
self.assertIsNone(result)
556+
557+
def test_server_add_volume_with_enable_delete_on_termination_pre_v279(
558+
self):
559+
self.app.client_manager.compute.api_version = api_versions.APIVersion(
560+
'2.78')
561+
562+
servers = self.setup_servers_mock(count=1)
563+
arglist = [
564+
servers[0].id,
565+
self.volume.id,
566+
'--enable-delete-on-termination',
567+
]
568+
verifylist = [
569+
('server', servers[0].id),
570+
('volume', self.volume.id),
571+
('enable_delete_on_termination', True),
572+
]
573+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
574+
575+
ex = self.assertRaises(exceptions.CommandError,
576+
self.cmd.take_action,
577+
parsed_args)
578+
self.assertIn('--os-compute-api-version 2.79 or greater is required',
579+
str(ex))
580+
581+
def test_server_add_volume_with_disable_delete_on_termination_pre_v279(
582+
self):
583+
self.app.client_manager.compute.api_version = api_versions.APIVersion(
584+
'2.78')
585+
586+
servers = self.setup_servers_mock(count=1)
587+
arglist = [
588+
servers[0].id,
589+
self.volume.id,
590+
'--disable-delete-on-termination',
591+
]
592+
verifylist = [
593+
('server', servers[0].id),
594+
('volume', self.volume.id),
595+
('disable_delete_on_termination', True),
596+
]
597+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
598+
599+
ex = self.assertRaises(exceptions.CommandError,
600+
self.cmd.take_action,
601+
parsed_args)
602+
self.assertIn('--os-compute-api-version 2.79 or greater is required',
603+
str(ex))
604+
605+
def test_server_add_volume_with_disable_and_enable_delete_on_termination(
606+
self):
607+
self.app.client_manager.compute.api_version = api_versions.APIVersion(
608+
'2.79')
609+
610+
servers = self.setup_servers_mock(count=1)
611+
arglist = [
612+
'--enable-delete-on-termination',
613+
'--disable-delete-on-termination',
614+
'--device', '/dev/sdb',
615+
servers[0].id,
616+
self.volume.id,
617+
]
618+
619+
verifylist = [
620+
('server', servers[0].id),
621+
('volume', self.volume.id),
622+
('device', '/dev/sdb'),
623+
('enable_delete_on_termination', True),
624+
('disable_delete_on_termination', True),
625+
]
626+
ex = self.assertRaises(utils.ParserException,
627+
self.check_parser,
628+
self.cmd, arglist, verifylist)
629+
self.assertIn('Argument parse failed', str(ex))
630+
631+
460632
class TestServerAddNetwork(TestServer):
461633

462634
def setUp(self):
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
features:
3+
- |
4+
Add ``--disable-delete-on-termination`` and
5+
``--enable-delete-on-termination`` options to the ``server add volume``
6+
command to indicate when to delete the attached volume when the server
7+
is deleted.
8+
Note that it requires ``--os-compute-api-version 2.79`` or greater.
9+
[Blueprint support-specifying-az-when-restore-shelved-server `<https://blueprints.launchpad.net/nova/+spec/support-delete-on-termination-in-server-attach-volume>`_]

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ oslo.i18n>=3.15.3 # Apache-2.0
1313
oslo.utils>=3.33.0 # Apache-2.0
1414
python-glanceclient>=2.8.0 # Apache-2.0
1515
python-keystoneclient>=3.17.0 # Apache-2.0
16-
python-novaclient>=15.0.0 # Apache-2.0
16+
python-novaclient>=15.1.0 # Apache-2.0
1717
python-cinderclient>=3.3.0 # Apache-2.0

0 commit comments

Comments
 (0)