diff options
| author | sunyajing <yajing.sun@easystack.cn> | 2016-05-28 11:01:22 +0800 |
|---|---|---|
| committer | sunyajing <yajing.sun@easystack.cn> | 2016-05-28 16:38:22 +0800 |
| commit | 3e11661074e1a7e051e0ebff5800f8f1aac85153 (patch) | |
| tree | 8714135039224e6e1cc338cbd75dd038e8022655 /openstackclient | |
| parent | 9da02d14eadc39da6f97b3df095af8b0c452a5b4 (diff) | |
| download | python-openstackclient-3e11661074e1a7e051e0ebff5800f8f1aac85153.tar.gz | |
Add "image unset" command
This patch add a command that supports
unsetting image tags and properties
Change-Id: I6f2cf45a61ff89da6664f3a34ae49fdd85d8c986
Closes-Bug:#1582968
Diffstat (limited to 'openstackclient')
| -rw-r--r-- | openstackclient/image/v2/image.py | 89 | ||||
| -rw-r--r-- | openstackclient/tests/image/v2/fakes.py | 2 | ||||
| -rw-r--r-- | openstackclient/tests/image/v2/test_image.py | 93 |
3 files changed, 182 insertions, 2 deletions
diff --git a/openstackclient/image/v2/image.py b/openstackclient/image/v2/image.py index a9c0f1fd..a81f092c 100644 --- a/openstackclient/image/v2/image.py +++ b/openstackclient/image/v2/image.py @@ -805,8 +805,8 @@ class SetImage(command.Command): # Checks if anything that requires getting the image if not (kwargs or parsed_args.deactivate or parsed_args.activate): - self.log.warning(_("No arguments specified")) - return {}, {} + msg = _("No arguments specified") + raise exceptions.CommandError(msg) image = utils.find_resource( image_client.images, parsed_args.image) @@ -856,3 +856,88 @@ class ShowImage(command.ShowOne): info = _format_image(image) return zip(*sorted(six.iteritems(info))) + + +class UnsetImage(command.Command): + """Unset image tags and properties""" + + def get_parser(self, prog_name): + parser = super(UnsetImage, self).get_parser(prog_name) + parser.add_argument( + "image", + metavar="<image>", + help=_("Image to modify (name or ID)"), + ) + parser.add_argument( + "--tag", + dest="tags", + metavar="<tag>", + default=[], + action='append', + help=_("Unset a tag on this image " + "(repeat option to set multiple tags)"), + ) + parser.add_argument( + "--property", + dest="properties", + metavar="<property_key>", + default=[], + action='append', + help=_("Unset a property on this image " + "(repeat option to set multiple properties)"), + ) + return parser + + def take_action(self, parsed_args): + image_client = self.app.client_manager.image + image = utils.find_resource( + image_client.images, + parsed_args.image, + ) + + if not (parsed_args.tags or parsed_args.properties): + msg = _("No arguments specified") + raise exceptions.CommandError(msg) + + kwargs = {} + tagret = 0 + propret = 0 + if parsed_args.tags: + for k in parsed_args.tags: + try: + image_client.image_tags.delete(image.id, k) + except Exception: + self.log.error(_("tag unset failed," + " '%s' is a nonexistent tag ") % k) + tagret += 1 + + if parsed_args.properties: + for k in parsed_args.properties: + try: + assert(k in image.keys()) + except AssertionError: + self.log.error(_("property unset failed," + " '%s' is a nonexistent property ") % k) + propret += 1 + image_client.images.update( + image.id, + parsed_args.properties, + **kwargs) + + tagtotal = len(parsed_args.tags) + proptotal = len(parsed_args.properties) + if (tagret > 0 and propret > 0): + msg = (_("Failed to unset %(tagret)s of %(tagtotal)s tags," + "Failed to unset %(propret)s of %(proptotal)s properties.") + % {'tagret': tagret, 'tagtotal': tagtotal, + 'propret': propret, 'proptotal': proptotal}) + raise exceptions.CommandError(msg) + elif tagret > 0: + msg = (_("Failed to unset %(target)s of %(tagtotal)s tags.") + % {'tagret': tagret, 'tagtotal': tagtotal}) + raise exceptions.CommandError(msg) + elif propret > 0: + msg = (_("Failed to unset %(propret)s of %(proptotal)s" + " properties.") + % {'propret': propret, 'proptotal': proptotal}) + raise exceptions.CommandError(msg) diff --git a/openstackclient/tests/image/v2/fakes.py b/openstackclient/tests/image/v2/fakes.py index a662a585..24aaec51 100644 --- a/openstackclient/tests/image/v2/fakes.py +++ b/openstackclient/tests/image/v2/fakes.py @@ -157,6 +157,8 @@ class FakeImagev2Client(object): self.images.resource_class = fakes.FakeResource(None, {}) self.image_members = mock.Mock() self.image_members.resource_class = fakes.FakeResource(None, {}) + self.image_tags = mock.Mock() + self.image_tags.resource_class = fakes.FakeResource(None, {}) self.auth_token = kwargs['token'] self.management_url = kwargs['endpoint'] diff --git a/openstackclient/tests/image/v2/test_image.py b/openstackclient/tests/image/v2/test_image.py index beebdef9..ca20d83d 100644 --- a/openstackclient/tests/image/v2/test_image.py +++ b/openstackclient/tests/image/v2/test_image.py @@ -37,6 +37,8 @@ class TestImage(image_fakes.TestImagev2): self.images_mock.reset_mock() self.image_members_mock = self.app.client_manager.image.image_members self.image_members_mock.reset_mock() + self.image_tags_mock = self.app.client_manager.image.image_tags + self.image_tags_mock.reset_mock() # Get shortcut to the Mocks in identity client self.project_mock = self.app.client_manager.identity.projects @@ -1184,3 +1186,94 @@ class TestImageShow(TestImage): self.assertEqual(image_fakes.IMAGE_columns, columns) self.assertEqual(image_fakes.IMAGE_SHOW_data, data) + + +class TestImageUnset(TestImage): + + attrs = {} + attrs['tags'] = ['test'] + attrs['prop'] = 'test' + image = image_fakes.FakeImage.create_one_image(attrs) + + def setUp(self): + super(TestImageUnset, self).setUp() + + # Set up the schema + self.model = warlock.model_factory( + image_fakes.IMAGE_schema, + schemas.SchemaBasedModel, + ) + + self.images_mock.get.return_value = self.image + self.image_tags_mock.delete.return_value = self.image + + # Get the command object to test + self.cmd = image.UnsetImage(self.app, None) + + def test_image_unset_tag_option(self): + + arglist = [ + '--tag', 'test', + self.image.id, + ] + + verifylist = [ + ('tags', ['test']), + ('image', self.image.id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + result = self.cmd.take_action(parsed_args) + + self.image_tags_mock.delete.assert_called_with( + self.image.id, 'test' + ) + self.assertIsNone(result) + + def test_image_unset_property_option(self): + + arglist = [ + '--property', 'prop', + self.image.id, + ] + + verifylist = [ + ('properties', ['prop']), + ('image', self.image.id) + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + result = self.cmd.take_action(parsed_args) + + kwargs = {} + self.images_mock.update.assert_called_with( + self.image.id, + parsed_args.properties, + **kwargs) + + self.assertIsNone(result) + + def test_image_unset_mixed_option(self): + + arglist = [ + '--tag', 'test', + '--property', 'prop', + self.image.id, + ] + + verifylist = [ + ('tags', ['test']), + ('properties', ['prop']), + ('image', self.image.id) + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + result = self.cmd.take_action(parsed_args) + + kwargs = {} + self.images_mock.update.assert_called_with( + self.image.id, + parsed_args.properties, + **kwargs) + + self.image_tags_mock.delete.assert_called_with( + self.image.id, 'test' + ) + self.assertIsNone(result) |
