def do_image_delete(gc, args): """Delete specified image.""" image = gc.images.get(args.id) if image and image.status == "deleted": msg = "No image with an ID of '%s' exists." % image.id utils.exit(msg) gc.images.delete(args.id)
def main(): try: OpenStackImagesShell().main(map(encodeutils.safe_decode, sys.argv[1:])) except KeyboardInterrupt: utils.exit('... terminating glance client', exit_code=130) except Exception as e: utils.exit(utils.exception_to_str(e))
def do_image_list(gc, args): """List images you can access.""" filter_keys = ['visibility', 'member_status', 'owner', 'checksum', 'tag'] filter_items = [(key, getattr(args, key)) for key in filter_keys] if args.properties: filter_properties = [prop.split('=', 1) for prop in args.properties] if any(len(pair) != 2 for pair in filter_properties): utils.exit('Argument --property-filter expected properties in the' ' format KEY=VALUE') filter_items += filter_properties filters = dict([item for item in filter_items if item[1] is not None]) kwargs = {'filters': filters} if args.limit is not None: kwargs['limit'] = args.limit if args.page_size is not None: kwargs['page_size'] = args.page_size if args.sort_key: kwargs['sort_key'] = args.sort_key if args.sort_dir: kwargs['sort_dir'] = args.sort_dir if args.sort is not None: kwargs['sort'] = args.sort elif not args.sort_dir and not args.sort_key: kwargs['sort'] = 'name:asc' columns = ['ID', 'Name'] if args.verbose: columns += ['owner', 'status'] images = gc.images.list(**kwargs) utils.print_list(images, columns)
def do_image_create(gc, args): """Create a new image.""" schema = gc.schemas.get("image") _args = [(x[0].replace('-', '_'), x[1]) for x in vars(args).items()] fields = dict(filter(lambda x: x[1] is not None and (x[0] == 'property' or schema.is_core_property(x[0])), _args)) raw_properties = fields.pop('property', []) for datum in raw_properties: key, value = datum.split('=', 1) fields[key] = value file_name = fields.pop('file', None) if file_name is not None and os.access(file_name, os.R_OK) is False: utils.exit("File %s does not exist or user does not have read " "privileges to it" % file_name) image = gc.images.create(**fields) try: if utils.get_data_file(args) is not None: args.id = image['id'] args.size = None do_image_upload(gc, args) image = gc.images.get(args.id) finally: utils.print_image(image)
def do_md_tag_create_multiple(gc, args): """Create new metadata definitions tags inside a namespace.""" delim = args.delim or ',' tags = [] names_list = args.names.split(delim) for name in names_list: name = name.strip() if name: tags.append(name) if not tags: utils.exit('Please supply at least one tag name. For example: ' '--names Tag1') fields = {'tags': tags} new_tags = gc.metadefs_tag.create_multiple(args.namespace, **fields) columns = ['name'] column_settings = { "description": { "max_width": 50, "align": "l" } } utils.print_list(new_tags, columns, field_settings=column_settings)
def do_image_delete(gc, args): """Delete specified image.""" try: gc.images.delete(args.id) except exc.HTTPNotFound: msg = "No image with an ID of '%s' exists." % args.id utils.exit(msg)
def do_image_list(gc, args): """List images you can access.""" filter_keys = ["visibility", "member_status", "owner", "checksum", "tag"] filter_items = [(key, getattr(args, key)) for key in filter_keys] if args.properties: filter_properties = [prop.split("=", 1) for prop in args.properties] if any(len(pair) != 2 for pair in filter_properties): utils.exit("Argument --property-filter expected properties in the" " format KEY=VALUE") filter_items += filter_properties filters = dict([item for item in filter_items if item[1] is not None]) kwargs = {"filters": filters} if args.limit is not None: kwargs["limit"] = args.limit if args.page_size is not None: kwargs["page_size"] = args.page_size if args.sort_key: kwargs["sort_key"] = args.sort_key if args.sort_dir: kwargs["sort_dir"] = args.sort_dir if args.sort is not None: kwargs["sort"] = args.sort elif not args.sort_dir and not args.sort_key: kwargs["sort_key"] = "name" kwargs["sort_dir"] = "asc" columns = ["ID", "Name"] if args.verbose: columns += ["Disk_format", "Container_format", "Size", "Status", "Owner"] images = gc.images.list(**kwargs) utils.print_list(images, columns)
def do_md_tag_create(gc, args): """Add a new metadata definitions tag inside a namespace.""" name = args.name.strip() if name: new_tag = gc.metadefs_tag.create(args.namespace, name) _tag_show(new_tag) else: utils.exit("Please supply at least one non-blank tag name.")
def main(): try: argv = [encodeutils.safe_decode(a) for a in sys.argv[1:]] OpenStackImagesShell().main(argv) except KeyboardInterrupt: utils.exit('... terminating glance client', exit_code=130) except Exception as e: utils.exit(encodeutils.exception_to_unicode(e))
def do_location_update(gc, args): """Update metadata of an image's location.""" try: metadata = json.loads(args.metadata) except ValueError: utils.exit("Metadata is not a valid JSON object.") else: image = gc.images.update_location(args.id, args.url, metadata) utils.print_dict(image)
def do_md_object_property_show(gc, args): """Describe a specific metadata definitions property inside an object.""" obj = gc.metadefs_object.get(args.namespace, args.object) try: prop = obj["properties"][args.property] prop["name"] = args.property except KeyError: utils.exit("Property %s not found in object %s." % (args.property, args.object)) utils.print_dict(prop, int(args.max_column_width))
def do_md_tag_update(gc, args): """Rename a metadata definitions tag inside a namespace.""" name = args.name.strip() if name: fields = {"name": name} new_tag = gc.metadefs_tag.update(args.namespace, args.tag, **fields) _tag_show(new_tag) else: utils.exit("Please supply at least one non-blank tag name.")
def do_member_update(gc, args): """Update the status of a member for a given image.""" if not (args.image_id and args.member_id and args.member_status): utils.exit("Unable to update member. Specify image_id, member_id and" " member_status") else: member = gc.image_members.update(args.image_id, args.member_id, args.member_status) member = [member] columns = ["Image ID", "Member ID", "Status"] utils.print_list(member, columns)
def do_member_create(gc, args): """Create member for a given image.""" if not (args.image_id and args.member_id): utils.exit("Unable to create member. Specify image_id and member_id") else: member = gc.image_members.create(args.image_id, args.member_id) member = [member] columns = ["Image ID", "Member ID", "Status"] utils.print_list(member, columns)
def do_location_add(gc, args): """Add a location (and related metadata) to an image.""" try: metadata = json.loads(args.metadata) except ValueError: utils.exit("Metadata is not a valid JSON object.") else: image = gc.images.add_location(args.id, args.url, metadata) utils.print_dict(image)
def do_explain(gc, args): """Describe a specific model.""" try: schema = gc.schemas.get(args.model) except exc.SchemaNotFound: utils.exit('Unable to find requested model \'%s\'' % args.model) else: formatters = {'Attribute': lambda m: m.name} columns = ['Attribute', 'Description'] utils.print_list(schema.properties, columns, formatters)
def do_explain(gc, args): """Describe a specific model.""" try: schema = gc.schemas.get(args.model) except exc.HTTPNotFound: utils.exit("Unable to find requested model '%s'" % args.model) else: formatters = {"Attribute": lambda m: m.name} columns = ["Attribute", "Description"] utils.print_list(schema.properties, columns, formatters)
def do_image_tag_update(gc, args): """Update an image with the given tag.""" if not (args.image_id and args.tag_value): utils.exit("Unable to update tag. Specify image_id and tag_value") else: gc.image_tags.update(args.image_id, args.tag_value) image = gc.images.get(args.image_id) image = [image] columns = ["ID", "Tags"] utils.print_list(image, columns)
def main(): try: argv = [encodeutils.safe_decode(a) for a in sys.argv[1:]] OpenStackImagesShell().main(argv) except KeyboardInterrupt: utils.exit('... terminating glance client', exit_code=130) except Exception as e: if utils.debug_enabled(argv) is True: traceback.print_exc() utils.exit(encodeutils.exception_to_unicode(e))
def do_md_object_create(gc, args): """Create a new metadata definitions object inside a namespace.""" try: schema = json.loads(args.schema) except ValueError: utils.exit("Schema is not a valid JSON object.") else: fields = {"name": args.name} fields.update(schema) new_object = gc.metadefs_object.create(args.namespace, **fields) _object_show(new_object)
def do_md_property_create(gc, args): """Create a new metadata definitions property inside a namespace.""" try: schema = json.loads(args.schema) except ValueError: utils.exit("Schema is not a valid JSON object.") else: fields = {"name": args.name, "title": args.title} fields.update(schema) new_property = gc.metadefs_property.create(args.namespace, **fields) utils.print_dict(new_property)
def do_image_download(gc, args): """Download a specific image.""" body = gc.images.data(args.id) if args.progress: body = progressbar.VerboseIteratorWrapper(body, len(body)) if not (sys.stdout.isatty() and args.file is None): utils.save_image(body, args.file) else: msg = ('No redirection or local file specified for downloaded image ' 'data. Please specify a local file with --file to save ' 'downloaded image or redirect output to another source.') utils.exit(msg)
def do_location_update(gc, args): """Update metadata of an image's location.""" try: metadata = json.loads(args.metadata) if metadata == {}: print("WARNING -- The location's metadata will be updated to " "an empty JSON object.") except ValueError: utils.exit('Metadata is not a valid JSON object.') else: image = gc.images.update_location(args.id, args.url, metadata) utils.print_dict(image)
def do_md_namespace_import(gc, args): """Import a metadata definitions namespace from file or standard input.""" namespace_data = utils.get_data_file(args) if not namespace_data: utils.exit("No metadata definition namespace passed via stdin or " "--file argument.") try: namespace_json = json.load(namespace_data) except ValueError: utils.exit("Schema is not a valid JSON object.") else: namespace = gc.metadefs_namespace.create(**namespace_json) _namespace_show(namespace)
def do_task_create(gc, args): """Create a new task.""" if not (args.type and args.input): utils.exit("Unable to create task. Specify task type and input.") else: try: input = json.loads(args.input) except ValueError: utils.exit('Failed to parse the "input" parameter. Must be a ' "valid JSON object.") task_values = {"type": args.type, "input": input} task = gc.tasks.create(**task_values) ignore = ["self", "schema"] task = dict([item for item in task.iteritems() if item[0] not in ignore]) utils.print_dict(task)
def do_md_object_update(gc, args): """Update metadata definitions object inside a namespace.""" fields = {} if args.name: fields["name"] = args.name if args.schema: try: schema = json.loads(args.schema) except ValueError: utils.exit("Schema is not a valid JSON object.") else: fields.update(schema) new_object = gc.metadefs_object.update(args.namespace, args.object, **fields) _object_show(new_object)
def do_member_list(gc, args): """Describe sharing permissions by image or tenant.""" if args.image_id and args.tenant_id: utils.exit('Unable to filter members by both --image-id and' ' --tenant-id.') elif args.image_id: kwargs = {'image': args.image_id} elif args.tenant_id: kwargs = {'member': args.tenant_id} else: utils.exit('Unable to list all members. Specify --image-id or' ' --tenant-id') members = gc.image_members.list(**kwargs) columns = ['Image ID', 'Member ID', 'Can Share'] utils.print_list(members, columns)
def do_md_property_update(gc, args): """Update metadata definitions property inside a namespace.""" fields = {} if args.name: fields["name"] = args.name if args.title: fields["title"] = args.title if args.schema: try: schema = json.loads(args.schema) except ValueError: utils.exit("Schema is not a valid JSON object.") else: fields.update(schema) new_property = gc.metadefs_property.update(args.namespace, args.property, **fields) utils.print_dict(new_property)
def get_subcommand_parser(self, version): parser = self.get_base_parser() self.subcommands = {} subparsers = parser.add_subparsers(metavar='<subcommand>') try: submodule = utils.import_versioned_module(version, 'shell') except ImportError: print('"%s" is not a supported API version. Example ' 'values are "1" or "2".' % version) utils.exit() self._find_actions(subparsers, submodule) self._find_actions(subparsers, self) self._add_bash_completion_subparser(subparsers) return parser
def do_image_list(gc, args): """List images you can access.""" filter_keys = ['visibility', 'member_status', 'owner', 'checksum', 'tag'] filter_items = [(key, getattr(args, key)) for key in filter_keys] if args.properties: filter_properties = [prop.split('=', 1) for prop in args.properties] if False in (len(pair) == 2 for pair in filter_properties): utils.exit('Argument --property-filter expected properties in the' ' format KEY=VALUE') filter_items += filter_properties filters = dict([item for item in filter_items if item[1] is not None]) kwargs = {'filters': filters} if args.page_size is not None: kwargs['page_size'] = args.page_size images = gc.images.list(**kwargs) columns = ['ID', 'Name'] utils.print_list(images, columns)
def do_image_delete(gc, args): """Delete specified image.""" failure_flag = False for args_id in args.id: try: gc.images.delete(args_id) except exc.HTTPForbidden: msg = "You are not permitted to delete the image '%s'." % args_id utils.print_err(msg) failure_flag = True except exc.HTTPNotFound: msg = "No image with an ID of '%s' exists." % args_id utils.print_err(msg) failure_flag = True except exc.HTTPException as e: msg = "'%s': Unable to delete image '%s'" % (e, args_id) utils.print_err(msg) failure_flag = True if failure_flag: utils.exit()
def do_md_tag_create_multiple(gc, args): """Create new metadata definitions tags inside a namespace.""" delim = args.delim or ',' tags = [] names_list = args.names.split(delim) for name in names_list: name = name.strip() if name: tags.append(name) if not tags: utils.exit('Please supply at least one tag name. For example: ' '--names Tag1') fields = {'tags': tags} new_tags = gc.metadefs_tag.create_multiple(args.namespace, **fields) columns = ['name'] column_settings = {"description": {"max_width": 50, "align": "l"}} utils.print_list(new_tags, columns, field_settings=column_settings)
def do_image_list(gc, args): """List images you can access.""" filter_keys = [ 'name', 'status', 'container_format', 'disk_format', 'size_min', 'size_max', 'is_public' ] filter_items = [(key, getattr(args, key)) for key in filter_keys] filters = dict([item for item in filter_items if item[1] is not None]) if args.properties: property_filter_items = [p.split('=', 1) for p in args.properties] if any(len(pair) != 2 for pair in property_filter_items): utils.exit('Argument --property-filter requires properties in the' ' format KEY=VALUE') filters['properties'] = dict(property_filter_items) kwargs = {'filters': filters} if args.page_size is not None: kwargs['page_size'] = args.page_size kwargs['sort_key'] = args.sort_key kwargs['sort_dir'] = args.sort_dir kwargs['owner'] = args.owner if args.all_tenants is True: kwargs['is_public'] = None images = gc.images.list(**kwargs) if args.human_readable: def convert_size(image): image.size = utils.make_size_human_readable(image.size) return image images = (convert_size(image) for image in images) columns = [ 'ID', 'Name', 'Disk Format', 'Container Format', 'Size', 'Status' ] utils.print_list(images, columns)
def do_image_list(gc, args): """List images you can access.""" filter_keys = ['visibility', 'member_status', 'owner', 'checksum', 'tag'] filter_items = [(key, getattr(args, key)) for key in filter_keys] if args.properties: filter_properties = [prop.split('=', 1) for prop in args.properties] if False in (len(pair) == 2 for pair in filter_properties): utils.exit('Argument --property-filter expected properties in the' ' format KEY=VALUE') filter_items += filter_properties filters = dict([item for item in filter_items if item[1] is not None]) kwargs = {'filters': filters} if args.limit is not None: kwargs['limit'] = args.page_size if args.page_size is not None: kwargs['page_size'] = args.page_size images = gc.images.list(**kwargs) columns = ['ID', 'Name'] utils.print_list(images, columns)
def do_image_update(gc, args): """Update a specific image.""" # Filter out None values fields = dict(filter(lambda x: x[1] is not None, vars(args).items())) image_arg = fields.pop('image') image = utils.find_resource(gc.images, image_arg) if 'is_protected' in fields: fields['protected'] = fields.pop('is_protected') raw_properties = fields.pop('property') fields['properties'] = {} for datum in raw_properties: key, value = datum.split('=', 1) fields['properties'][key] = value # Filter out values we can't use UPDATE_PARAMS = glanceclient.v1.images.UPDATE_PARAMS fields = dict(filter(lambda x: x[0] in UPDATE_PARAMS, fields.items())) if image.status == 'queued': _set_data_field(fields, args) if args.progress: filesize = utils.get_file_size(fields['data']) fields['data'] = progressbar.VerboseFileWrapper( fields['data'], filesize ) elif _is_image_data_provided(args): # NOTE(kragniz): Exit with an error if the status is not queued # and image data was provided utils.exit('Unable to upload image data to an image which ' 'is %s.' % image.status) image = gc.images.update(image, purge_props=args.purge_props, **fields) _image_show(image, args.human_readable)
def do_image_create(gc, args): """Create a new image.""" schema = gc.schemas.get("image") _args = [(x[0].replace('-', '_'), x[1]) for x in vars(args).items()] fields = dict( filter( lambda x: x[1] is not None and (x[0] == 'property' or x[0] == 'cache_raw' or x[0] == 'wait' or schema.is_core_property(x[0])), _args)) raw_properties = fields.pop('property', []) cache_raw = fields.pop('cache_raw', False) cache_raw_wait = fields.pop('wait', None) if cache_raw is not False: raw_properties += ['cache_raw=True'] for datum in raw_properties: key, value = datum.split('=', 1) fields[key] = value file_name = fields.pop('file', None) if file_name is not None and os.access(file_name, os.R_OK) is False: utils.exit("File %s does not exist or user does not have read " "privileges to it" % file_name) image = gc.images.create(**fields) try: image_data = utils.get_data_file(args) if image_data is not None: args.id = image['id'] args.size = utils.get_file_size(image_data) do_image_upload(gc, args) # If cache_raw and wait options were chosen, wait until # image is cached. if cache_raw is not False and cache_raw_wait is not None: utils.wait_for_caching(cache_raw_wait, gc, args.id) image = gc.images.get(args.id) finally: utils.print_image(image)
def do_image_list(gc, args): """List images you can access.""" filter_keys = ['visibility', 'member_status', 'owner', 'checksum', 'tag'] filter_items = [(key, getattr(args, key)) for key in filter_keys] if args.properties: filter_properties = [prop.split('=', 1) for prop in args.properties] if any(len(pair) != 2 for pair in filter_properties): utils.exit('Argument --property-filter expected properties in the' ' format KEY=VALUE') filter_items += filter_properties filters = dict([item for item in filter_items if item[1] is not None]) kwargs = {'filters': filters} if args.limit is not None: kwargs['limit'] = args.limit if args.page_size is not None: kwargs['page_size'] = args.page_size if args.sort_key: kwargs['sort_key'] = args.sort_key if args.sort_dir: kwargs['sort_dir'] = args.sort_dir if args.sort is not None: kwargs['sort'] = args.sort elif not args.sort_dir and not args.sort_key: kwargs['sort_key'] = 'name' kwargs['sort_dir'] = 'asc' columns = ['ID', 'Name'] if args.verbose: columns += [ 'Disk_format', 'Container_format', 'Size', 'Status', 'Owner' ] images = gc.images.list(**kwargs) utils.print_list(images, columns)
def do_image_download(gc, args): """Download a specific image.""" try: body = gc.images.data(args.id) except (exc.HTTPForbidden, exc.HTTPException) as e: msg = "Unable to download image '%s'. (%s)" % (args.id, e) utils.exit(msg) if body is None: msg = ('Image %s has no data.' % args.id) utils.exit(msg) if args.progress: body = progressbar.VerboseIteratorWrapper(body, len(body)) if not (sys.stdout.isatty() and args.file is None): utils.save_image(body, args.file) else: msg = ('No redirection or local file specified for downloaded image ' 'data. Please specify a local file with --file to save ' 'downloaded image or redirect output to another source.') utils.exit(msg)
def main(self, argv): # Parse args once to find version #NOTE(flepied) Under Python3, parsed arguments are removed # from the list so make a copy for the first parsing base_argv = copy.deepcopy(argv) parser = self.get_base_parser() (options, args) = parser.parse_known_args(base_argv) try: # NOTE(flaper87): Try to get the version from the # image-url first. If no version was specified, fallback # to the api-image-version arg. If both of these fail then # fallback to the minimum supported one and let keystone # do the magic. endpoint = self._get_image_url(options) endpoint, url_version = utils.strip_version(endpoint) except ValueError: # NOTE(flaper87): ValueError is raised if no endpoint is povided url_version = None # build available subcommands based on version try: api_version = int(options.os_image_api_version or url_version or 1) except ValueError: print("Invalid API version parameter") utils.exit() if api_version == 2: self._cache_schemas(options) subcommand_parser = self.get_subcommand_parser(api_version) self.parser = subcommand_parser # Handle top-level --help/-h before attempting to parse # a command off the command line if options.help or not argv: self.do_help(options) return 0 # Parse args again and call whatever callback was selected args = subcommand_parser.parse_args(argv) # Short-circuit and deal with help command right away. if args.func == self.do_help: self.do_help(args) return 0 elif args.func == self.do_bash_completion: self.do_bash_completion(args) return 0 LOG = logging.getLogger('glanceclient') LOG.addHandler(logging.StreamHandler()) LOG.setLevel(logging.DEBUG if args.debug else logging.INFO) profile = osprofiler_profiler and options.profile if profile: osprofiler_profiler.init(options.profile) client = self._get_versioned_client(api_version, args, force_auth=False) try: args.func(client, args) except exc.Unauthorized: raise exc.CommandError("Invalid OpenStack Identity credentials.") except Exception: #NOTE(kragniz) Print any exceptions raised to stderr if the --debug # flag is set if args.debug: traceback.print_exc() raise finally: if profile: trace_id = osprofiler_profiler.get().get_base_id() print("Profiling trace ID: %s" % trace_id) print("To display trace use next command:\n" "osprofiler trace show --html %s " % trace_id)
def main(self, argv): # parse args initially with no help option and ignoring unknown init_args = self.parse_args(argv, initial=True) # attempt to load configuration config = self.load_config(init_args.config) # parse source and destination source_env, source_id_or_name = self.parse_specification( init_args.source) dest_env, dest_name = self.parse_specification(init_args.dest) # parse args again, this time with help enabled args = self.parse_args(argv, initial=False, source_env=source_env, dest_env=dest_env, config=config) # authenticate glance client for source and dest environments source_client, source_client_desc = self.authenticate_client( "source", source_env, args) dest_client, dest_client_desc = self.authenticate_client( "dest", dest_env, args) # find source image source_image = None try: source_image = source_client.images.get(source_id_or_name) except exc.HTTPNotFound: found = False for image in source_client.images.list(): if image.name == source_id_or_name: if found: utils.exit( "Multiple source images were found named %s, cannot continue." % source_id_or_name) else: source_image = source_client.images.get(image.id) found = True except exc.CommunicationError as ce: utils.exit( "Communication error while attempting to get source image: %s" % (ce)) except exc.HTTPInternalServerError as hise: utils.exit( "Internal server error while attempting to get source image: %s" % (hise)) if not source_image: utils.exit("Source image not found: %s" % source_id_or_name) # prepare destination image properties dest_image_properties = {} # copy essential properties (cannot upload without these) for key in ['disk_format', 'container_format']: dest_image_properties[key] = source_image[key] # copy extra properties according to user list for key in args.properties.split(','): k = key.strip() dest_image_properties[k] = source_image[k] # set or copy name if dest_name != "": dest_image_properties['name'] = dest_name else: dest_image_properties['name'] = source_image['name'] # inform user we are copying # TODO: only if verbose? print( "copying source image %s ('%s') from %s to destination image '%s' on %s" % (source_image.id, source_image.name, source_client_desc, dest_image_properties['name'], dest_client_desc), file=sys.stderr) # check for duplicates and plan strategy to deal with them delete_images = [] rename_images = [] image_names = {} if args.duplicate_name_strategy != "allow": # check for existing images by that name at destination for image in dest_client.images.list(): if args.duplicate_name_strategy in ["rename", "replace"]: image_names[image.name] = 1 if image.name == dest_image_properties['name']: if args.duplicate_name_strategy == "replace": rename_images.append(image.id) delete_images.append(image.id) elif args.duplicate_name_strategy == "rename": rename_images.append(image.id) elif args.duplicate_name_strategy == "none": utils.exit( "An image named '%s' is already present at " "destination. Please change to a unique name, " "use the '--duplicate-name-strategy=allow' " "option to allow creation of images with " "duplicate names, use the " "'--duplicate-name-strategy=replace' option " "to remove any other images with the " "destination name, or use the " "'--duplicate-name-strategy=rename' option " "to rename any existing images to make them " "unique." % dest_image_properties['name']) else: raise ValueError( "Unexpected value for '--duplicate-name-strategy': %s", args.duplicate_name_strategy) suffix = self.random_suffix() for image_id in rename_images: while "%s.%s" % (dest_image_properties['name'], suffix) in image_names: suffix = self.random_suffix() new_name = "%s.%s" % (dest_image_properties['name'], suffix) print("renaming existing image %s to '%s'" % (image_id, new_name), file=sys.stderr) try: dest_client.images.update(image_id, name=new_name) except exc.CommunicationError as ce: utils.exit( "Communication error while attempting to rename existing image: %s" % (ce)) except exc.HTTPInternalServerError as hise: utils.exit( "Internal server error while attempting to rename existing image: %s" % (hise)) except exc.HTTPException as he: utils.exit("HTTP error while attempting to rename: %s" % (he)) except Exception as e: utils.exit( "Failed to rename existing image (exception type %s): %s" % (type(e), e)) # create destination image print("creating image at destination: %s" % (dest_image_properties['name']), file=sys.stderr) try: dest_image = dest_client.images.create(**dest_image_properties) except exc.CommunicationError as ce: utils.exit( "Communication error while attempting to create image: %s" % (ce)) except exc.HTTPInternalServerError as hise: utils.exit( "Internal server error while attempting to create image: %s" % (hise)) except Exception as e: utils.exit( "Failed to create destination image (exception type %s): %s" % (type(e), e)) # copy data from source to destination failure_reason = "" print("copying data from source image %s to destination image %s" % (source_image.id, dest_image.id), file=sys.stderr) try: data = source_client.images.data(source_image.id) if data is not None: dest_client.images.upload(dest_image.id, data_to_upload_stream(data)) else: print("WARNING: source image %s contained no data" % (source_image.id), file=sys.stderr) except exc.CommunicationError as ce: failure_reason = "Communication error while attempting to transfer image: %s" % ( ce) except exc.HTTPInternalServerError as hise: failure_reason = "Internal server error while attempting to transfer image: %s" % ( hise) except Exception as ue: failure_reason = "Failed to transfer image (exception type %s): %s" % ( type(ue), ue) if failure_reason != "": try: dest_client.images.delete(dest_image.id) except exc.CommunicationError as ce: utils.exit( "%s. In addition, there was a communication error while attempting to delete image after upload failed: %s" % (failure_reason, ce)) except exc.HTTPInternalServerError as hise: utils.exit( "%s. In addition, there was an internal server error while attempting to delete image after upload failed: %s" % (failure_reason, hise)) except Exception as de: utils.exit( "%s. In addition, failed to delete image after upload failed (exception type %s): %s" % (failure_reason, type(de), de)) utils.exit(failure_reason) # successfully created image, now delete any images scheduled for deletion (because of duplicate_name_strategy=replace) for image_id in delete_images: print( "deleting existing image %s because it had a duplicate name" % (image_id), file=sys.stderr) try: dest_client.images.delete(image_id) except exc.CommunicationError as ce: utils.exit( "Communication error while attempting to delete image %s with duplicate name: %s" % (image_id, ce)) except exc.HTTPInternalServerError as hise: utils.exit( "Internal server error while attempting to delete image %s with duplicate name: %s" % (image_id, hise)) except exc.HTTPConflict as hc: utils.exit( "Conflict while attempting to delete image %s with duplicate name: %s" % (image_id, hc)) except Exception as e: utils.exit("Failed to delete image %s with duplicate " "name (exception type %s): %s" % (image_id, type(e), e)) # tell the user the id of their new image print(dest_image.id)
def do_member_delete(gc, args): """Delete image member.""" if not (args.image_id and args.member_id): utils.exit('Unable to delete member. Specify image_id and member_id') else: gc.image_members.delete(args.image_id, args.member_id)
def main(self, argv): # Parse args once to find version # NOTE(flepied) Under Python3, parsed arguments are removed # from the list so make a copy for the first parsing base_argv = copy.deepcopy(argv) parser = self.get_base_parser() (options, args) = parser.parse_known_args(base_argv) span_host = tomograph.getHost() span_name = ' '.join(sys.argv) tomograph.start("glanceclient-shell", span_name, span_host, 0) try: # NOTE(flaper87): Try to get the version from the # image-url first. If no version was specified, fallback # to the api-image-version arg. If both of these fail then # fallback to the minimum supported one and let keystone # do the magic. endpoint = self._get_image_url(options) endpoint, url_version = utils.strip_version(endpoint) except ValueError: # NOTE(flaper87): ValueError is raised if no endpoint is povided url_version = None # build available subcommands based on version try: api_version = int(options.os_image_api_version or url_version or 2) if api_version not in SUPPORTED_VERSIONS: raise ValueError except ValueError: msg = ("Invalid API version parameter. " "Supported values are %s" % SUPPORTED_VERSIONS) utils.exit(msg=msg) if api_version == 2: switch_version = self._cache_schemas(options) if switch_version: print('WARNING: The client is falling back to v1 because' ' the accessing to v2 failed. This behavior will' ' be removed in future versions') api_version = 1 try: subcommand_parser = self.get_subcommand_parser(api_version) except ImportError as e: if options.debug: traceback.print_exc() if not str(e): # Add a generic import error message if the raised ImportError # has none. raise ImportError('Unable to import module. Re-run ' 'with --debug for more info.') raise except Exception: if options.debug: traceback.print_exc() raise self.parser = subcommand_parser # Handle top-level --help/-h before attempting to parse # a command off the command line if options.help or not argv: self.do_help(options) return 0 # Parse args again and call whatever callback was selected args = subcommand_parser.parse_args(argv) # Short-circuit and deal with help command right away. if args.func == self.do_help: self.do_help(args) return 0 elif args.func == self.do_bash_completion: self.do_bash_completion(args) return 0 LOG = logging.getLogger('glanceclient') LOG.addHandler(logging.StreamHandler()) LOG.setLevel(logging.DEBUG if args.debug else logging.INFO) profile = osprofiler_profiler and options.profile if profile: osprofiler_profiler.init(options.profile) client = self._get_versioned_client(api_version, args, force_auth=False) try: # pdb.set_trace() args.func(client, args) except exc.Unauthorized: raise exc.CommandError("Invalid OpenStack Identity credentials.") except Exception: # NOTE(kragniz) Print any exceptions raised to stderr if the # --debug flag is set if args.debug: traceback.print_exc() raise finally: tomograph.stop(span_name) if profile: trace_id = osprofiler_profiler.get().get_base_id() print("Profiling trace ID: %s" % trace_id) print("To display trace use next command:\n" "osprofiler trace show --html %s " % trace_id)
def main(self, argv): def _get_subparser(api_version): try: return self.get_subcommand_parser(api_version, argv) except ImportError as e: if not str(e): # Add a generic import error message if the raised # ImportError has none. raise ImportError('Unable to import module. Re-run ' 'with --debug for more info.') raise # Parse args once to find version # NOTE(flepied) Under Python3, parsed arguments are removed # from the list so make a copy for the first parsing base_argv = copy.deepcopy(argv) parser = self.get_base_parser(argv) (options, args) = parser.parse_known_args(base_argv) try: # NOTE(flaper87): Try to get the version from the # image-url first. If no version was specified, fallback # to the api-image-version arg. If both of these fail then # fallback to the minimum supported one and let keystone # do the magic. endpoint = self._get_image_url(options) endpoint, url_version = utils.strip_version(endpoint) except ValueError: # NOTE(flaper87): ValueError is raised if no endpoint is provided url_version = None # build available subcommands based on version try: api_version = int(options.os_image_api_version or url_version or 2) if api_version not in SUPPORTED_VERSIONS: raise ValueError except ValueError: msg = ("Invalid API version parameter. " "Supported values are %s" % SUPPORTED_VERSIONS) utils.exit(msg=msg) # Handle top-level --help/-h before attempting to parse # a command off the command line if options.help or not argv: parser = _get_subparser(api_version) self.do_help(options, parser=parser) return 0 # NOTE(sigmavirus24): Above, args is defined as the left over # arguments from parser.parse_known_args(). This allows us to # skip any parameters to command-line flags that may have been passed # to glanceclient, e.g., --os-auth-token. self._fixup_subcommand(args, argv) # short-circuit and deal with help command right away. sub_parser = _get_subparser(api_version) args = sub_parser.parse_args(argv) if args.func == self.do_help: self.do_help(args, parser=sub_parser) return 0 elif args.func == self.do_bash_completion: self.do_bash_completion(args) return 0 if not options.os_image_api_version and api_version == 2: switch_version = True client = self._get_versioned_client('2', args) resp, body = client.http_client.get('/versions') for version in body['versions']: if version['id'].startswith('v2'): # NOTE(flaper87): We know v2 is enabled in the server, # which means we should be able to get the schemas and # move on. switch_version = self._cache_schemas(options, client) break if switch_version: print('WARNING: The client is falling back to v1 because' ' the accessing to v2 failed. This behavior will' ' be removed in future versions', file=sys.stderr) api_version = 1 sub_parser = _get_subparser(api_version) # Parse args again and call whatever callback was selected args = sub_parser.parse_args(argv) # NOTE(flaper87): Make sure we re-use the password input if we # have one. This may happen if the schemas were downloaded in # this same command. Password will be asked to download the # schemas and then for the operations below. if not args.os_password and options.os_password: args.os_password = options.os_password if args.debug: # Set up the root logger to debug so that the submodules can # print debug messages logging.basicConfig(level=logging.DEBUG) # for iso8601 < 0.1.11 logging.getLogger('iso8601').setLevel(logging.WARNING) LOG = logging.getLogger('glanceclient') LOG.addHandler(logging.StreamHandler()) LOG.setLevel(logging.DEBUG if args.debug else logging.INFO) profile = osprofiler_profiler and options.profile if profile: osprofiler_profiler.init(options.profile) client = self._get_versioned_client(api_version, args) try: args.func(client, args) except exc.Unauthorized: raise exc.CommandError("Invalid OpenStack Identity credentials.") finally: if profile: trace_id = osprofiler_profiler.get().get_base_id() print("Profiling trace ID: %s" % trace_id) print("To display trace use next command:\n" "osprofiler trace show --html %s " % trace_id)
def replate_images_from_region(args, other_endpoint, local_endpoint): # method to handle a single region token = get_fresh_token(args).service_catalog.catalog.get('token') token_id = token.get('id') token_tenant_id = token['tenant']['id'] remote_images = glanceclient(other_endpoint.get(ENDPOINT_TYPE), token_id).images.list() for remote_image in remote_images: if not image_for_me(remote_image): continue if remote_image.status != 'active': logging.warn("Ignoring the image %s (%s) as it is not in an active" " state yet" % (remote_image.name, remote_image.id)) global image_not_ready_state_count image_not_ready_state_count += 1 continue if image_exists(remote_image, local_endpoint, get_fresh_token_id(args)): logging.info("The image %s (%s) is already replicated locally" % (remote_image.name, remote_image.id)) continue logging.info("We need to replicate the image %s (%s) to the region" " %s" % (remote_image.name, remote_image.id, other_endpoint.get('region'))) # download the image try: body = glanceclient(other_endpoint.get(ENDPOINT_TYPE), token_id).images.data(remote_image.id) except (exc.HTTPForbidden, exc.HTTPException) as e: msg = "Unable to download image '%s'. (%s)" % (args.id, e) utils.exit(msg) temp = tempfile.NamedTemporaryFile() temp_file_name = temp.name temp.close() try: logging.info("The image %s is downloading to %s" % (remote_image.id, temp_file_name)) utils.save_image(body, temp_file_name) glance_cmd = ["glance", "--os-image-api-version", "1", "image-create", "--file", temp_file_name] # this code takes the properties on the source image, and uses them # for the target image for cli_param, glance_name in CREATE_ARGS.iteritems(): if glance_name in remote_image: value = remote_image[glance_name] if " " in str(value): value = "\"%s\"" % value glance_cmd.extend(["--%s" % cli_param, str(value)]) for xtra_prop in EXTRA_PROPS: if xtra_prop in remote_image and remote_image[xtra_prop]: value = remote_image[xtra_prop] if " " in str(value): value = "\"%s\"" % value glance_cmd.extend(["--property", "%s=%s" % (xtra_prop, value)]) call_glance_image_create(args, glance_cmd, local_endpoint.get('region'), token_tenant_id) finally: os.remove(temp_file_name) logging.info('Completed processing images for the region %s' % other_endpoint.get('region'))
def do_image_tag_delete(gc, args): """Delete the tag associated with the given image.""" if not (args.image_id and args.tag_value): utils.exit('Unable to delete tag. Specify image_id and tag_value') else: gc.image_tags.delete(args.image_id, args.tag_value)