diff --git a/openstackclient/image/v2/image.py b/openstackclient/image/v2/image.py index 0b2becb85a..3dd9833849 100644 --- a/openstackclient/image/v2/image.py +++ b/openstackclient/image/v2/image.py @@ -250,3 +250,140 @@ class ShowImage(show.ShowOne): info = {} info.update(image) return zip(*sorted(six.iteritems(info))) + + +class SetImage(show.ShowOne): + """Set image properties""" + + log = logging.getLogger(__name__ + ".SetImage") + + def get_parser(self, prog_name): + parser = super(SetImage, self).get_parser(prog_name) + parser.add_argument( + "image", + metavar="", + help="Image to modify (name or ID)" + ) + parser.add_argument( + "--name", + metavar="", + help="New image name" + ) + parser.add_argument( + "--architecture", + metavar="", + help="Operating system Architecture" + ) + parser.add_argument( + "--protected", + dest="protected", + action="store_true", + help="Prevent image from being deleted" + ) + parser.add_argument( + "--instance-uuid", + metavar="", + help="ID of instance used to create this image" + ) + parser.add_argument( + "--min-disk", + type=int, + metavar="", + help="Minimum disk size needed to boot image, in gigabytes" + ) + visibility_choices = ["public", "private"] + parser.add_argument( + "--visibility", + metavar="", + choices=visibility_choices, + help="Scope of image accessibility. Valid values: %s" + % visibility_choices + ) + help_msg = ("ID of image in Glance that should be used as the kernel" + " when booting an AMI-style image") + parser.add_argument( + "--kernel-id", + metavar="", + help=help_msg + ) + parser.add_argument( + "--os-version", + metavar="", + help="Operating system version as specified by the distributor" + ) + disk_choices = ["None", "ami", "ari", "aki", "vhd", "vmdk", "raw", + "qcow2", "vdi", "iso"] + help_msg = ("Format of the disk. Valid values: %s" % disk_choices) + parser.add_argument( + "--disk-format", + metavar="", + choices=disk_choices, + help=help_msg + ) + parser.add_argument( + "--os-distro", + metavar="", + help="Common name of operating system distribution" + ) + parser.add_argument( + "--owner", + metavar="", + help="New Owner of the image" + ) + msg = ("ID of image stored in Glance that should be used as the " + "ramdisk when booting an AMI-style image") + parser.add_argument( + "--ramdisk-id", + metavar="", + help=msg + ) + parser.add_argument( + "--min-ram", + type=int, + metavar="", + help="Amount of RAM (in MB) required to boot image" + ) + container_choices = ["None", "ami", "ari", "aki", "bare", "ovf", "ova"] + help_msg = ("Format of the container. Valid values: %s" + % container_choices) + parser.add_argument( + "--container-format", + metavar="", + choices=container_choices, + help=help_msg + ) + return parser + + def take_action(self, parsed_args): + self.log.debug("take_action(%s)", parsed_args) + image_client = self.app.client_manager.image + + kwargs = {} + copy_attrs = ('architecture', 'container_format', 'disk_format', + 'file', 'kernel_id', 'locations', 'name', + 'min_disk', 'min_ram', 'name', 'os_distro', 'os_version', + 'owner', 'prefix', 'progress', 'ramdisk_id', + 'visibility') + for attr in copy_attrs: + if attr in parsed_args: + val = getattr(parsed_args, attr, None) + if val: + # Only include a value in kwargs for attributes that are + # actually present on the command line + kwargs[attr] = val + if parsed_args.protected: + kwargs['protected'] = True + else: + kwargs['protected'] = False + + if not kwargs: + self.log.warning("No arguments specified") + return {}, {} + + image = utils.find_resource( + image_client.images, parsed_args.image) + + image = image_client.images.update(image.id, **kwargs) + info = {} + info.update(image) + return zip(*sorted(six.iteritems(info))) diff --git a/openstackclient/tests/image/v2/test_image.py b/openstackclient/tests/image/v2/test_image.py index 73b5d39a4a..7cfaf08315 100644 --- a/openstackclient/tests/image/v2/test_image.py +++ b/openstackclient/tests/image/v2/test_image.py @@ -331,3 +331,53 @@ class TestImageShow(TestImage): self.assertEqual(image_fakes.IMAGE_columns, columns) self.assertEqual(image_fakes.IMAGE_data, data) + + +class TestImageSet(TestImage): + + def setUp(self): + super(TestImageSet, self).setUp() + # Set up the schema + self.model = warlock.model_factory( + image_fakes.IMAGE_schema, + schemas.SchemaBasedModel, + ) + + self.images_mock.get.return_value = self.model(**image_fakes.IMAGE) + self.images_mock.update.return_value = self.model(**image_fakes.IMAGE) + # Get the command object to test + self.cmd = image.SetImage(self.app, None) + + def test_image_set_options(self): + arglist = [ + '--name', 'new-name', + '--owner', 'new-owner', + '--min-disk', '2', + '--min-ram', '4', + image_fakes.image_id, + ] + verifylist = [ + ('name', 'new-name'), + ('owner', 'new-owner'), + ('min_disk', 2), + ('min_ram', 4), + ('image', image_fakes.image_id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + kwargs = { + 'name': 'new-name', + 'owner': 'new-owner', + 'min_disk': 2, + 'min_ram': 4, + 'protected': False + } + # ImageManager.update(image, **kwargs) + self.images_mock.update.assert_called_with( + image_fakes.image_id, **kwargs) + + self.assertEqual(image_fakes.IMAGE_columns, columns) + self.assertEqual(image_fakes.IMAGE_data, data) diff --git a/setup.cfg b/setup.cfg index e2d7288488..9abc216044 100644 --- a/setup.cfg +++ b/setup.cfg @@ -313,6 +313,7 @@ openstack.image.v2 = image_list = openstackclient.image.v2.image:ListImage image_save = openstackclient.image.v2.image:SaveImage image_show = openstackclient.image.v2.image:ShowImage + image_set = openstackclient.image.v2.image:SetImage openstack.network.v2 = network_create = openstackclient.network.v2.network:CreateNetwork