Skip to content

Commit a5039e7

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "volume: Add more missing 'volume backup *' options"
2 parents 3f3d882 + 7f66dfe commit a5039e7

5 files changed

Lines changed: 251 additions & 5 deletions

File tree

openstackclient/tests/unit/volume/v2/fakes.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from unittest import mock
1818
import uuid
1919

20+
from cinderclient import api_versions
2021
from osc_lib.cli import format_columns
2122

2223
from openstackclient.tests.unit import fakes
@@ -292,6 +293,8 @@ class FakeVolumeClient(object):
292293
def __init__(self, **kwargs):
293294
self.auth_token = kwargs['token']
294295
self.management_url = kwargs['endpoint']
296+
self.api_version = api_versions.APIVersion('2.0')
297+
295298
self.availability_zones = mock.Mock()
296299
self.availability_zones.resource_class = fakes.FakeResource(None, {})
297300
self.backups = mock.Mock()

openstackclient/tests/unit/volume/v2/test_volume_backup.py

Lines changed: 156 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,9 @@ def test_backup_restore(self):
490490

491491
class TestBackupSet(TestBackup):
492492

493-
backup = volume_fakes.FakeBackup.create_one_backup()
493+
backup = volume_fakes.FakeBackup.create_one_backup(
494+
attrs={'metadata': {'wow': 'cool'}},
495+
)
494496

495497
def setUp(self):
496498
super(TestBackupSet, self).setUp()
@@ -627,6 +629,159 @@ def test_backup_set_state_failed(self):
627629
self.backups_mock.reset_state.assert_called_with(
628630
self.backup.id, 'error')
629631

632+
def test_backup_set_no_property(self):
633+
self.app.client_manager.volume.api_version = \
634+
api_versions.APIVersion('3.43')
635+
636+
arglist = [
637+
'--no-property',
638+
self.backup.id,
639+
]
640+
verifylist = [
641+
('no_property', True),
642+
('backup', self.backup.id),
643+
]
644+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
645+
646+
result = self.cmd.take_action(parsed_args)
647+
648+
# Set expected values
649+
kwargs = {
650+
'metadata': {},
651+
}
652+
self.backups_mock.update.assert_called_once_with(
653+
self.backup.id,
654+
**kwargs
655+
)
656+
self.assertIsNone(result)
657+
658+
def test_backup_set_no_property_pre_v343(self):
659+
self.app.client_manager.volume.api_version = \
660+
api_versions.APIVersion('3.42')
661+
662+
arglist = [
663+
'--no-property',
664+
self.backup.id,
665+
]
666+
verifylist = [
667+
('no_property', True),
668+
('backup', self.backup.id),
669+
]
670+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
671+
672+
exc = self.assertRaises(
673+
exceptions.CommandError,
674+
self.cmd.take_action,
675+
parsed_args)
676+
self.assertIn("--os-volume-api-version 3.43 or greater", str(exc))
677+
678+
def test_backup_set_property(self):
679+
self.app.client_manager.volume.api_version = \
680+
api_versions.APIVersion('3.43')
681+
682+
arglist = [
683+
'--property', 'foo=bar',
684+
self.backup.id,
685+
]
686+
verifylist = [
687+
('properties', {'foo': 'bar'}),
688+
('backup', self.backup.id),
689+
]
690+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
691+
692+
result = self.cmd.take_action(parsed_args)
693+
694+
# Set expected values
695+
kwargs = {
696+
'metadata': {'wow': 'cool', 'foo': 'bar'},
697+
}
698+
self.backups_mock.update.assert_called_once_with(
699+
self.backup.id,
700+
**kwargs
701+
)
702+
self.assertIsNone(result)
703+
704+
def test_backup_set_property_pre_v343(self):
705+
self.app.client_manager.volume.api_version = \
706+
api_versions.APIVersion('3.42')
707+
708+
arglist = [
709+
'--property', 'foo=bar',
710+
self.backup.id,
711+
]
712+
verifylist = [
713+
('properties', {'foo': 'bar'}),
714+
('backup', self.backup.id),
715+
]
716+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
717+
718+
exc = self.assertRaises(
719+
exceptions.CommandError,
720+
self.cmd.take_action,
721+
parsed_args)
722+
self.assertIn("--os-volume-api-version 3.43 or greater", str(exc))
723+
724+
725+
class TestBackupUnset(TestBackup):
726+
727+
backup = volume_fakes.FakeBackup.create_one_backup(
728+
attrs={'metadata': {'foo': 'bar'}},
729+
)
730+
731+
def setUp(self):
732+
super().setUp()
733+
734+
self.backups_mock.get.return_value = self.backup
735+
736+
# Get the command object to test
737+
self.cmd = volume_backup.UnsetVolumeBackup(self.app, None)
738+
739+
def test_backup_unset_property(self):
740+
self.app.client_manager.volume.api_version = \
741+
api_versions.APIVersion('3.43')
742+
743+
arglist = [
744+
'--property', 'foo',
745+
self.backup.id,
746+
]
747+
verifylist = [
748+
('properties', ['foo']),
749+
('backup', self.backup.id),
750+
]
751+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
752+
753+
result = self.cmd.take_action(parsed_args)
754+
755+
# Set expected values
756+
kwargs = {
757+
'metadata': {},
758+
}
759+
self.backups_mock.update.assert_called_once_with(
760+
self.backup.id,
761+
**kwargs
762+
)
763+
self.assertIsNone(result)
764+
765+
def test_backup_unset_property_pre_v343(self):
766+
self.app.client_manager.volume.api_version = \
767+
api_versions.APIVersion('3.42')
768+
769+
arglist = [
770+
'--property', 'foo',
771+
self.backup.id,
772+
]
773+
verifylist = [
774+
('properties', ['foo']),
775+
('backup', self.backup.id),
776+
]
777+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
778+
779+
exc = self.assertRaises(
780+
exceptions.CommandError,
781+
self.cmd.take_action,
782+
parsed_args)
783+
self.assertIn("--os-volume-api-version 3.43 or greater", str(exc))
784+
630785

631786
class TestBackupShow(TestBackup):
632787

openstackclient/volume/v2/volume_backup.py

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
"""Volume v2 Backup action implementations"""
1616

17+
import copy
1718
import functools
1819
import logging
1920

@@ -405,11 +406,21 @@ def get_parser(self, prog_name):
405406
'exercise caution when using)'
406407
),
407408
)
409+
parser.add_argument(
410+
'--no-property',
411+
action='store_true',
412+
help=_(
413+
'Remove all properties from this backup '
414+
'(specify both --no-property and --property to remove the '
415+
'current properties before setting new properties)'
416+
),
417+
)
408418
parser.add_argument(
409419
'--property',
410420
metavar='<key=value>',
411421
action=parseractions.KeyValueAction,
412422
dest='properties',
423+
default={},
413424
help=_(
414425
'Set a property on this backup '
415426
'(repeat option to set multiple values) '
@@ -454,6 +465,14 @@ def take_action(self, parsed_args):
454465

455466
kwargs['description'] = parsed_args.description
456467

468+
if parsed_args.no_property:
469+
if volume_client.api_version < api_versions.APIVersion('3.43'):
470+
msg = _(
471+
'--os-volume-api-version 3.43 or greater is required to '
472+
'support the --no-property option'
473+
)
474+
raise exceptions.CommandError(msg)
475+
457476
if parsed_args.properties:
458477
if volume_client.api_version < api_versions.APIVersion('3.43'):
459478
msg = _(
@@ -462,20 +481,84 @@ def take_action(self, parsed_args):
462481
)
463482
raise exceptions.CommandError(msg)
464483

465-
kwargs['metadata'] = parsed_args.properties
484+
if volume_client.api_version >= api_versions.APIVersion('3.43'):
485+
metadata = copy.deepcopy(backup.metadata)
486+
487+
if parsed_args.no_property:
488+
metadata = {}
489+
490+
metadata.update(parsed_args.properties)
491+
kwargs['metadata'] = metadata
466492

467493
if kwargs:
468494
try:
469495
volume_client.backups.update(backup.id, **kwargs)
470496
except Exception as e:
471-
LOG.error("Failed to update backup name or description: %s", e)
497+
LOG.error("Failed to update backup: %s", e)
472498
result += 1
473499

474500
if result > 0:
475501
msg = _("One or more of the set operations failed")
476502
raise exceptions.CommandError(msg)
477503

478504

505+
class UnsetVolumeBackup(command.Command):
506+
"""Unset volume backup properties.
507+
508+
This command requires ``--os-volume-api-version`` 3.43 or greater.
509+
"""
510+
511+
def get_parser(self, prog_name):
512+
parser = super().get_parser(prog_name)
513+
parser.add_argument(
514+
'backup',
515+
metavar='<backup>',
516+
help=_('Backup to modify (name or ID)')
517+
)
518+
parser.add_argument(
519+
'--property',
520+
metavar='<key>',
521+
action='append',
522+
dest='properties',
523+
help=_(
524+
'Property to remove from this backup '
525+
'(repeat option to unset multiple values) '
526+
),
527+
)
528+
return parser
529+
530+
def take_action(self, parsed_args):
531+
volume_client = self.app.client_manager.volume
532+
533+
if volume_client.api_version < api_versions.APIVersion('3.43'):
534+
msg = _(
535+
'--os-volume-api-version 3.43 or greater is required to '
536+
'support the --property option'
537+
)
538+
raise exceptions.CommandError(msg)
539+
540+
backup = utils.find_resource(
541+
volume_client.backups, parsed_args.backup)
542+
metadata = copy.deepcopy(backup.metadata)
543+
544+
for key in parsed_args.properties:
545+
if key not in metadata:
546+
# ignore invalid properties but continue
547+
LOG.warning(
548+
"'%s' is not a valid property for backup '%s'",
549+
key, parsed_args.backup,
550+
)
551+
continue
552+
553+
del metadata[key]
554+
555+
kwargs = {
556+
'metadata': metadata,
557+
}
558+
559+
volume_client.backups.update(backup.id, **kwargs)
560+
561+
479562
class ShowVolumeBackup(command.ShowOne):
480563
_description = _("Display volume backup details")
481564

releasenotes/notes/add-missing-volume-backup-opts-b9246aded87427ce.yaml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ features:
66
non-incremental backup, set a metadata property on the created backup, and
77
set an availability zone on the created backup, respectively.
88
- |
9-
Add ``--property`` option the ``volume backup set`` command to set a
10-
metadata property on an existing backup.
9+
Add ``--property`` and ``--no-property`` options to the
10+
``volume backup set`` command to set a metadata property or remove all
11+
metadata properties from an existing backup.
12+
- |
13+
Add new ``volume backup unset`` command to allow unsetting of properties
14+
from an existing volume backup.
1115
fixes:
1216
- |
1317
The ``--name`` and ``--description`` options of the ``volume backup set``

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,7 @@ openstack.volume.v3 =
715715
volume_backup_list = openstackclient.volume.v2.volume_backup:ListVolumeBackup
716716
volume_backup_restore = openstackclient.volume.v2.volume_backup:RestoreVolumeBackup
717717
volume_backup_set = openstackclient.volume.v2.volume_backup:SetVolumeBackup
718+
volume_backup_unset = openstackclient.volume.v2.volume_backup:UnsetVolumeBackup
718719
volume_backup_show = openstackclient.volume.v2.volume_backup:ShowVolumeBackup
719720

720721
volume_backup_record_export = openstackclient.volume.v2.backup_record:ExportBackupRecord

0 commit comments

Comments
 (0)