"image set" command should return None. But in one path,
it returns ({}, {}). This patch fixes this.
Change-Id: I3847e661cb7e89863921a3f0a859d9b1a8077ede
		
	
		
			
				
	
	
		
			727 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			727 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#   Copyright 2012-2013 OpenStack Foundation
 | 
						|
#
 | 
						|
#   Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
						|
#   not use this file except in compliance with the License. You may obtain
 | 
						|
#   a copy of the License at
 | 
						|
#
 | 
						|
#        http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
#
 | 
						|
#   Unless required by applicable law or agreed to in writing, software
 | 
						|
#   distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
						|
#   WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
						|
#   License for the specific language governing permissions and limitations
 | 
						|
#   under the License.
 | 
						|
#
 | 
						|
 | 
						|
"""Image V1 Action Implementations"""
 | 
						|
 | 
						|
import argparse
 | 
						|
import io
 | 
						|
import os
 | 
						|
import six
 | 
						|
import sys
 | 
						|
 | 
						|
if os.name == "nt":
 | 
						|
    import msvcrt
 | 
						|
else:
 | 
						|
    msvcrt = None
 | 
						|
 | 
						|
from glanceclient.common import utils as gc_utils
 | 
						|
from openstackclient.api import utils as api_utils
 | 
						|
from openstackclient.common import command
 | 
						|
from openstackclient.common import parseractions
 | 
						|
from openstackclient.common import utils
 | 
						|
from openstackclient.i18n import _  # noqa
 | 
						|
 | 
						|
 | 
						|
DEFAULT_CONTAINER_FORMAT = 'bare'
 | 
						|
DEFAULT_DISK_FORMAT = 'raw'
 | 
						|
 | 
						|
 | 
						|
def _format_visibility(data):
 | 
						|
    """Return a formatted visibility string
 | 
						|
 | 
						|
    :param data:
 | 
						|
        The server's visibility (is_public) status value: True, False
 | 
						|
    :rtype:
 | 
						|
        A string formatted to public/private
 | 
						|
    """
 | 
						|
 | 
						|
    if data:
 | 
						|
        return 'public'
 | 
						|
    else:
 | 
						|
        return 'private'
 | 
						|
 | 
						|
 | 
						|
class CreateImage(command.ShowOne):
 | 
						|
    """Create/upload an image"""
 | 
						|
 | 
						|
    def get_parser(self, prog_name):
 | 
						|
        parser = super(CreateImage, self).get_parser(prog_name)
 | 
						|
        parser.add_argument(
 | 
						|
            "name",
 | 
						|
            metavar="<image-name>",
 | 
						|
            help="New image name",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--id",
 | 
						|
            metavar="<id>",
 | 
						|
            help="Image ID to reserve",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--store",
 | 
						|
            metavar="<store>",
 | 
						|
            help="Upload image to this store",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--container-format",
 | 
						|
            default=DEFAULT_CONTAINER_FORMAT,
 | 
						|
            metavar="<container-format>",
 | 
						|
            help="Image container format "
 | 
						|
                 "(default: %s)" % DEFAULT_CONTAINER_FORMAT,
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--disk-format",
 | 
						|
            default=DEFAULT_DISK_FORMAT,
 | 
						|
            metavar="<disk-format>",
 | 
						|
            help="Image disk format "
 | 
						|
                 "(default: %s)" % DEFAULT_DISK_FORMAT,
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--size",
 | 
						|
            metavar="<size>",
 | 
						|
            help="Image size, in bytes (only used with --location and"
 | 
						|
                 " --copy-from)",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--min-disk",
 | 
						|
            metavar="<disk-gb>",
 | 
						|
            type=int,
 | 
						|
            help="Minimum disk size needed to boot image, in gigabytes",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--min-ram",
 | 
						|
            metavar="<ram-mb>",
 | 
						|
            type=int,
 | 
						|
            help="Minimum RAM size needed to boot image, in megabytes",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--location",
 | 
						|
            metavar="<image-url>",
 | 
						|
            help="Download image from an existing URL",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--copy-from",
 | 
						|
            metavar="<image-url>",
 | 
						|
            help="Copy image from the data store (similar to --location)",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--file",
 | 
						|
            metavar="<file>",
 | 
						|
            help="Upload image from local file",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--volume",
 | 
						|
            metavar="<volume>",
 | 
						|
            help="Create image from a volume",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--force",
 | 
						|
            dest='force',
 | 
						|
            action='store_true',
 | 
						|
            default=False,
 | 
						|
            help="Force image creation if volume is in use "
 | 
						|
                 "(only meaningful with --volume)",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--checksum",
 | 
						|
            metavar="<checksum>",
 | 
						|
            help="Image hash used for verification",
 | 
						|
        )
 | 
						|
        protected_group = parser.add_mutually_exclusive_group()
 | 
						|
        protected_group.add_argument(
 | 
						|
            "--protected",
 | 
						|
            action="store_true",
 | 
						|
            help="Prevent image from being deleted",
 | 
						|
        )
 | 
						|
        protected_group.add_argument(
 | 
						|
            "--unprotected",
 | 
						|
            action="store_true",
 | 
						|
            help="Allow image to be deleted (default)",
 | 
						|
        )
 | 
						|
        public_group = parser.add_mutually_exclusive_group()
 | 
						|
        public_group.add_argument(
 | 
						|
            "--public",
 | 
						|
            action="store_true",
 | 
						|
            help="Image is accessible to the public",
 | 
						|
        )
 | 
						|
        public_group.add_argument(
 | 
						|
            "--private",
 | 
						|
            action="store_true",
 | 
						|
            help="Image is inaccessible to the public (default)",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--property",
 | 
						|
            dest="properties",
 | 
						|
            metavar="<key=value>",
 | 
						|
            action=parseractions.KeyValueAction,
 | 
						|
            help="Set a property on this image "
 | 
						|
                 "(repeat option to set multiple properties)",
 | 
						|
        )
 | 
						|
        # NOTE(dtroyer): --owner is deprecated in Jan 2016 in an early
 | 
						|
        #                2.x release.  Do not remove before Jan 2017
 | 
						|
        #                and a 3.x release.
 | 
						|
        project_group = parser.add_mutually_exclusive_group()
 | 
						|
        project_group.add_argument(
 | 
						|
            "--project",
 | 
						|
            metavar="<project>",
 | 
						|
            help="Set an alternate project on this image (name or ID)",
 | 
						|
        )
 | 
						|
        project_group.add_argument(
 | 
						|
            "--owner",
 | 
						|
            metavar="<project>",
 | 
						|
            help=argparse.SUPPRESS,
 | 
						|
        )
 | 
						|
        return parser
 | 
						|
 | 
						|
    def take_action(self, parsed_args):
 | 
						|
        image_client = self.app.client_manager.image
 | 
						|
 | 
						|
        if getattr(parsed_args, 'owner', None) is not None:
 | 
						|
            self.log.warning(_(
 | 
						|
                'The --owner option is deprecated, '
 | 
						|
                'please use --project instead.'
 | 
						|
            ))
 | 
						|
 | 
						|
        # Build an attribute dict from the parsed args, only include
 | 
						|
        # attributes that were actually set on the command line
 | 
						|
        kwargs = {}
 | 
						|
        copy_attrs = ('name', 'id', 'store', 'container_format',
 | 
						|
                      'disk_format', 'owner', 'size', 'min_disk', 'min_ram',
 | 
						|
                      'location', 'copy_from', 'volume', 'force',
 | 
						|
                      'checksum', 'properties')
 | 
						|
        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
 | 
						|
 | 
						|
        # Special case project option back to API attribute name 'owner'
 | 
						|
        val = getattr(parsed_args, 'project', None)
 | 
						|
        if val:
 | 
						|
            kwargs['owner'] = val
 | 
						|
 | 
						|
        # Handle exclusive booleans with care
 | 
						|
        # Avoid including attributes in kwargs if an option is not
 | 
						|
        # present on the command line.  These exclusive booleans are not
 | 
						|
        # a single value for the pair of options because the default must be
 | 
						|
        # to do nothing when no options are present as opposed to always
 | 
						|
        # setting a default.
 | 
						|
        if parsed_args.protected:
 | 
						|
            kwargs['protected'] = True
 | 
						|
        if parsed_args.unprotected:
 | 
						|
            kwargs['protected'] = False
 | 
						|
        if parsed_args.public:
 | 
						|
            kwargs['is_public'] = True
 | 
						|
        if parsed_args.private:
 | 
						|
            kwargs['is_public'] = False
 | 
						|
 | 
						|
        info = {}
 | 
						|
 | 
						|
        if not parsed_args.location and not parsed_args.copy_from:
 | 
						|
            if parsed_args.volume:
 | 
						|
                volume_client = self.app.client_manager.volume
 | 
						|
                source_volume = utils.find_resource(
 | 
						|
                    volume_client.volumes,
 | 
						|
                    parsed_args.volume,
 | 
						|
                )
 | 
						|
                response, body = volume_client.volumes.upload_to_image(
 | 
						|
                    source_volume.id,
 | 
						|
                    parsed_args.force,
 | 
						|
                    parsed_args.name,
 | 
						|
                    parsed_args.container_format,
 | 
						|
                    parsed_args.disk_format,
 | 
						|
                )
 | 
						|
                info = body['os-volume_upload_image']
 | 
						|
            elif parsed_args.file:
 | 
						|
                # Send an open file handle to glanceclient so it will
 | 
						|
                # do a chunked transfer
 | 
						|
                kwargs["data"] = io.open(parsed_args.file, "rb")
 | 
						|
            else:
 | 
						|
                # Read file from stdin
 | 
						|
                if sys.stdin.isatty() is not True:
 | 
						|
                    if msvcrt:
 | 
						|
                        msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
 | 
						|
                    # Send an open file handle to glanceclient so it will
 | 
						|
                    # do a chunked transfer
 | 
						|
                    kwargs["data"] = sys.stdin
 | 
						|
 | 
						|
        if not parsed_args.volume:
 | 
						|
            # Wrap the call to catch exceptions in order to close files
 | 
						|
            try:
 | 
						|
                image = image_client.images.create(**kwargs)
 | 
						|
            finally:
 | 
						|
                # Clean up open files - make sure data isn't a string
 | 
						|
                if ('data' in kwargs and hasattr(kwargs['data'], 'close') and
 | 
						|
                        kwargs['data'] != sys.stdin):
 | 
						|
                    kwargs['data'].close()
 | 
						|
 | 
						|
            info.update(image._info)
 | 
						|
            info['properties'] = utils.format_dict(info.get('properties', {}))
 | 
						|
        return zip(*sorted(six.iteritems(info)))
 | 
						|
 | 
						|
 | 
						|
class DeleteImage(command.Command):
 | 
						|
    """Delete image(s)"""
 | 
						|
 | 
						|
    def get_parser(self, prog_name):
 | 
						|
        parser = super(DeleteImage, self).get_parser(prog_name)
 | 
						|
        parser.add_argument(
 | 
						|
            "images",
 | 
						|
            metavar="<image>",
 | 
						|
            nargs="+",
 | 
						|
            help="Image(s) to delete (name or ID)",
 | 
						|
        )
 | 
						|
        return parser
 | 
						|
 | 
						|
    def take_action(self, parsed_args):
 | 
						|
        image_client = self.app.client_manager.image
 | 
						|
        for image in parsed_args.images:
 | 
						|
            image_obj = utils.find_resource(
 | 
						|
                image_client.images,
 | 
						|
                image,
 | 
						|
            )
 | 
						|
            image_client.images.delete(image_obj.id)
 | 
						|
 | 
						|
 | 
						|
class ListImage(command.Lister):
 | 
						|
    """List available images"""
 | 
						|
 | 
						|
    def get_parser(self, prog_name):
 | 
						|
        parser = super(ListImage, self).get_parser(prog_name)
 | 
						|
        public_group = parser.add_mutually_exclusive_group()
 | 
						|
        public_group.add_argument(
 | 
						|
            "--public",
 | 
						|
            dest="public",
 | 
						|
            action="store_true",
 | 
						|
            default=False,
 | 
						|
            help="List only public images",
 | 
						|
        )
 | 
						|
        public_group.add_argument(
 | 
						|
            "--private",
 | 
						|
            dest="private",
 | 
						|
            action="store_true",
 | 
						|
            default=False,
 | 
						|
            help="List only private images",
 | 
						|
        )
 | 
						|
        # Included for silent CLI compatibility with v2
 | 
						|
        public_group.add_argument(
 | 
						|
            "--shared",
 | 
						|
            dest="shared",
 | 
						|
            action="store_true",
 | 
						|
            default=False,
 | 
						|
            help=argparse.SUPPRESS,
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            '--property',
 | 
						|
            metavar='<key=value>',
 | 
						|
            action=parseractions.KeyValueAction,
 | 
						|
            help='Filter output based on property',
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            '--long',
 | 
						|
            action='store_true',
 | 
						|
            default=False,
 | 
						|
            help='List additional fields in output',
 | 
						|
        )
 | 
						|
 | 
						|
        # --page-size has never worked, leave here for silent compatibility
 | 
						|
        # We'll implement limit/marker differently later
 | 
						|
        parser.add_argument(
 | 
						|
            "--page-size",
 | 
						|
            metavar="<size>",
 | 
						|
            help=argparse.SUPPRESS,
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            '--sort',
 | 
						|
            metavar="<key>[:<direction>]",
 | 
						|
            help="Sort output by selected keys and directions(asc or desc) "
 | 
						|
                 "(default: asc), multiple keys and directions can be "
 | 
						|
                 "specified separated by comma",
 | 
						|
        )
 | 
						|
        return parser
 | 
						|
 | 
						|
    def take_action(self, parsed_args):
 | 
						|
        image_client = self.app.client_manager.image
 | 
						|
 | 
						|
        kwargs = {}
 | 
						|
        if parsed_args.public:
 | 
						|
            kwargs['public'] = True
 | 
						|
        if parsed_args.private:
 | 
						|
            kwargs['private'] = True
 | 
						|
        # Note: We specifically need to do that below to get the 'status'
 | 
						|
        #       column.
 | 
						|
        #
 | 
						|
        # Always set kwargs['detailed'] to True, and then filter the columns
 | 
						|
        # according to whether the --long option is specified or not.
 | 
						|
        kwargs['detailed'] = True
 | 
						|
 | 
						|
        if parsed_args.long:
 | 
						|
            columns = (
 | 
						|
                'ID',
 | 
						|
                'Name',
 | 
						|
                'Disk Format',
 | 
						|
                'Container Format',
 | 
						|
                'Size',
 | 
						|
                'Status',
 | 
						|
                'is_public',
 | 
						|
                'protected',
 | 
						|
                'owner',
 | 
						|
                'properties',
 | 
						|
            )
 | 
						|
            column_headers = (
 | 
						|
                'ID',
 | 
						|
                'Name',
 | 
						|
                'Disk Format',
 | 
						|
                'Container Format',
 | 
						|
                'Size',
 | 
						|
                'Status',
 | 
						|
                'Visibility',
 | 
						|
                'Protected',
 | 
						|
                'Project',
 | 
						|
                'Properties',
 | 
						|
            )
 | 
						|
        else:
 | 
						|
            columns = ("ID", "Name", "Status")
 | 
						|
            column_headers = columns
 | 
						|
 | 
						|
        # List of image data received
 | 
						|
        data = []
 | 
						|
        # No pages received yet, so start the page marker at None.
 | 
						|
        marker = None
 | 
						|
        while True:
 | 
						|
            page = image_client.api.image_list(marker=marker, **kwargs)
 | 
						|
            if not page:
 | 
						|
                break
 | 
						|
            data.extend(page)
 | 
						|
            # Set the marker to the id of the last item we received
 | 
						|
            marker = page[-1]['id']
 | 
						|
 | 
						|
        if parsed_args.property:
 | 
						|
            # NOTE(dtroyer): coerce to a list to subscript it in py3
 | 
						|
            attr, value = list(parsed_args.property.items())[0]
 | 
						|
            api_utils.simple_filter(
 | 
						|
                data,
 | 
						|
                attr=attr,
 | 
						|
                value=value,
 | 
						|
                property_field='properties',
 | 
						|
            )
 | 
						|
 | 
						|
        data = utils.sort_items(data, parsed_args.sort)
 | 
						|
 | 
						|
        return (
 | 
						|
            column_headers,
 | 
						|
            (utils.get_dict_properties(
 | 
						|
                s,
 | 
						|
                columns,
 | 
						|
                formatters={
 | 
						|
                    'is_public': _format_visibility,
 | 
						|
                    'properties': utils.format_dict,
 | 
						|
                },
 | 
						|
            ) for s in data)
 | 
						|
        )
 | 
						|
 | 
						|
 | 
						|
class SaveImage(command.Command):
 | 
						|
    """Save an image locally"""
 | 
						|
 | 
						|
    def get_parser(self, prog_name):
 | 
						|
        parser = super(SaveImage, self).get_parser(prog_name)
 | 
						|
        parser.add_argument(
 | 
						|
            "--file",
 | 
						|
            metavar="<filename>",
 | 
						|
            help="Downloaded image save filename (default: stdout)",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "image",
 | 
						|
            metavar="<image>",
 | 
						|
            help="Image to save (name or ID)",
 | 
						|
        )
 | 
						|
        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,
 | 
						|
        )
 | 
						|
        data = image_client.images.data(image)
 | 
						|
 | 
						|
        gc_utils.save_image(data, parsed_args.file)
 | 
						|
 | 
						|
 | 
						|
class SetImage(command.Command):
 | 
						|
    """Set image properties"""
 | 
						|
 | 
						|
    def get_parser(self, prog_name):
 | 
						|
        parser = super(SetImage, self).get_parser(prog_name)
 | 
						|
        parser.add_argument(
 | 
						|
            "image",
 | 
						|
            metavar="<image>",
 | 
						|
            help="Image to modify (name or ID)",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--name",
 | 
						|
            metavar="<name>",
 | 
						|
            help="New image name",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--min-disk",
 | 
						|
            metavar="<disk-gb>",
 | 
						|
            type=int,
 | 
						|
            help="Minimum disk size needed to boot image, in gigabytes",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--min-ram",
 | 
						|
            metavar="<disk-ram>",
 | 
						|
            type=int,
 | 
						|
            help="Minimum RAM size needed to boot image, in megabytes",
 | 
						|
        )
 | 
						|
        container_choices = ["ami", "ari", "aki", "bare", "ovf"]
 | 
						|
        parser.add_argument(
 | 
						|
            "--container-format",
 | 
						|
            metavar="<container-format>",
 | 
						|
            help=("Container format of image. Acceptable formats: %s" %
 | 
						|
                  container_choices),
 | 
						|
            choices=container_choices
 | 
						|
        )
 | 
						|
        disk_choices = ["ami", "ari", "aki", "vhd", "vmdk", "raw", "qcow2",
 | 
						|
                        "vdi", "iso"]
 | 
						|
        parser.add_argument(
 | 
						|
            "--disk-format",
 | 
						|
            metavar="<disk-format>",
 | 
						|
            help="Disk format of image. Acceptable formats: %s" % disk_choices,
 | 
						|
            choices=disk_choices
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--size",
 | 
						|
            metavar="<size>",
 | 
						|
            type=int,
 | 
						|
            help="Size of image data (in bytes)"
 | 
						|
        )
 | 
						|
        protected_group = parser.add_mutually_exclusive_group()
 | 
						|
        protected_group.add_argument(
 | 
						|
            "--protected",
 | 
						|
            action="store_true",
 | 
						|
            help="Prevent image from being deleted",
 | 
						|
        )
 | 
						|
        protected_group.add_argument(
 | 
						|
            "--unprotected",
 | 
						|
            action="store_true",
 | 
						|
            help="Allow image to be deleted (default)",
 | 
						|
        )
 | 
						|
        public_group = parser.add_mutually_exclusive_group()
 | 
						|
        public_group.add_argument(
 | 
						|
            "--public",
 | 
						|
            action="store_true",
 | 
						|
            help="Image is accessible to the public",
 | 
						|
        )
 | 
						|
        public_group.add_argument(
 | 
						|
            "--private",
 | 
						|
            action="store_true",
 | 
						|
            help="Image is inaccessible to the public (default)",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--property",
 | 
						|
            dest="properties",
 | 
						|
            metavar="<key=value>",
 | 
						|
            action=parseractions.KeyValueAction,
 | 
						|
            help="Set a property on this image "
 | 
						|
                 "(repeat option to set multiple properties)",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--store",
 | 
						|
            metavar="<store>",
 | 
						|
            help="Upload image to this store",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--location",
 | 
						|
            metavar="<image-url>",
 | 
						|
            help="Download image from an existing URL",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--copy-from",
 | 
						|
            metavar="<image-url>",
 | 
						|
            help="Copy image from the data store (similar to --location)",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--file",
 | 
						|
            metavar="<file>",
 | 
						|
            help="Upload image from local file",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--volume",
 | 
						|
            metavar="<volume>",
 | 
						|
            help="Create image from a volume",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--force",
 | 
						|
            dest='force',
 | 
						|
            action='store_true',
 | 
						|
            default=False,
 | 
						|
            help="Force image change if volume is in use "
 | 
						|
            "(only meaningful with --volume)",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--stdin",
 | 
						|
            dest='stdin',
 | 
						|
            action='store_true',
 | 
						|
            default=False,
 | 
						|
            help="Read image data from standard input",
 | 
						|
        )
 | 
						|
        parser.add_argument(
 | 
						|
            "--checksum",
 | 
						|
            metavar="<checksum>",
 | 
						|
            help="Image hash used for verification",
 | 
						|
        )
 | 
						|
        # NOTE(dtroyer): --owner is deprecated in Jan 2016 in an early
 | 
						|
        #                2.x release.  Do not remove before Jan 2017
 | 
						|
        #                and a 3.x release.
 | 
						|
        project_group = parser.add_mutually_exclusive_group()
 | 
						|
        project_group.add_argument(
 | 
						|
            "--project",
 | 
						|
            metavar="<project>",
 | 
						|
            help="Set an alternate project on this image (name or ID)",
 | 
						|
        )
 | 
						|
        project_group.add_argument(
 | 
						|
            "--owner",
 | 
						|
            metavar="<project>",
 | 
						|
            help=argparse.SUPPRESS,
 | 
						|
        )
 | 
						|
        return parser
 | 
						|
 | 
						|
    def take_action(self, parsed_args):
 | 
						|
        image_client = self.app.client_manager.image
 | 
						|
 | 
						|
        if getattr(parsed_args, 'owner', None) is not None:
 | 
						|
            self.log.warning(_(
 | 
						|
                'The --owner option is deprecated, '
 | 
						|
                'please use --project instead.'
 | 
						|
            ))
 | 
						|
 | 
						|
        kwargs = {}
 | 
						|
        copy_attrs = ('name', 'owner', 'min_disk', 'min_ram', 'properties',
 | 
						|
                      'container_format', 'disk_format', 'size', 'store',
 | 
						|
                      'location', 'copy_from', 'volume', 'force', 'checksum')
 | 
						|
        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
 | 
						|
 | 
						|
        # Special case project option back to API attribute name 'owner'
 | 
						|
        val = getattr(parsed_args, 'project', None)
 | 
						|
        if val:
 | 
						|
            kwargs['owner'] = val
 | 
						|
 | 
						|
        # Handle exclusive booleans with care
 | 
						|
        # Avoid including attributes in kwargs if an option is not
 | 
						|
        # present on the command line.  These exclusive booleans are not
 | 
						|
        # a single value for the pair of options because the default must be
 | 
						|
        # to do nothing when no options are present as opposed to always
 | 
						|
        # setting a default.
 | 
						|
        if parsed_args.protected:
 | 
						|
            kwargs['protected'] = True
 | 
						|
        if parsed_args.unprotected:
 | 
						|
            kwargs['protected'] = False
 | 
						|
        if parsed_args.public:
 | 
						|
            kwargs['is_public'] = True
 | 
						|
        if parsed_args.private:
 | 
						|
            kwargs['is_public'] = False
 | 
						|
 | 
						|
        # Wrap the call to catch exceptions in order to close files
 | 
						|
        try:
 | 
						|
            image = utils.find_resource(
 | 
						|
                image_client.images,
 | 
						|
                parsed_args.image,
 | 
						|
            )
 | 
						|
 | 
						|
            if not parsed_args.location and not parsed_args.copy_from:
 | 
						|
                if parsed_args.volume:
 | 
						|
                    volume_client = self.app.client_manager.volume
 | 
						|
                    source_volume = utils.find_resource(
 | 
						|
                        volume_client.volumes,
 | 
						|
                        parsed_args.volume,
 | 
						|
                    )
 | 
						|
                    volume_client.volumes.upload_to_image(
 | 
						|
                        source_volume.id,
 | 
						|
                        parsed_args.force,
 | 
						|
                        parsed_args.image,
 | 
						|
                        (parsed_args.container_format
 | 
						|
                         if parsed_args.container_format
 | 
						|
                         else image.container_format),
 | 
						|
                        (parsed_args.disk_format
 | 
						|
                         if parsed_args.disk_format
 | 
						|
                         else image.disk_format),
 | 
						|
                    )
 | 
						|
                elif parsed_args.file:
 | 
						|
                    # Send an open file handle to glanceclient so it will
 | 
						|
                    # do a chunked transfer
 | 
						|
                    kwargs["data"] = io.open(parsed_args.file, "rb")
 | 
						|
                else:
 | 
						|
                    # Read file from stdin
 | 
						|
                    if sys.stdin.isatty() is not True:
 | 
						|
                        if parsed_args.stdin:
 | 
						|
                            if msvcrt:
 | 
						|
                                msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
 | 
						|
                            # Send an open file handle to glanceclient so it
 | 
						|
                            # will do a chunked transfer
 | 
						|
                            kwargs["data"] = sys.stdin
 | 
						|
                        else:
 | 
						|
                            self.log.warning('Use --stdin to enable read image'
 | 
						|
                                             ' data from standard input')
 | 
						|
 | 
						|
            if image.properties and parsed_args.properties:
 | 
						|
                image.properties.update(kwargs['properties'])
 | 
						|
                kwargs['properties'] = image.properties
 | 
						|
 | 
						|
            if not kwargs:
 | 
						|
                self.log.warning('no arguments specified')
 | 
						|
                return
 | 
						|
 | 
						|
            image = image_client.images.update(image.id, **kwargs)
 | 
						|
        finally:
 | 
						|
            # Clean up open files - make sure data isn't a string
 | 
						|
            if ('data' in kwargs and hasattr(kwargs['data'], 'close') and
 | 
						|
                    kwargs['data'] != sys.stdin):
 | 
						|
                kwargs['data'].close()
 | 
						|
 | 
						|
 | 
						|
class ShowImage(command.ShowOne):
 | 
						|
    """Display image details"""
 | 
						|
 | 
						|
    def get_parser(self, prog_name):
 | 
						|
        parser = super(ShowImage, self).get_parser(prog_name)
 | 
						|
        parser.add_argument(
 | 
						|
            "image",
 | 
						|
            metavar="<image>",
 | 
						|
            help="Image to display (name or ID)",
 | 
						|
        )
 | 
						|
        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,
 | 
						|
        )
 | 
						|
 | 
						|
        info = {}
 | 
						|
        info.update(image._info)
 | 
						|
        info['properties'] = utils.format_dict(info.get('properties', {}))
 | 
						|
        return zip(*sorted(six.iteritems(info)))
 |