def take_action(self, parsed_args): identity_client = self.app.client_manager.identity image_client = self.app.client_manager.image for deadopt in self.deadopts: if getattr(parsed_args, deadopt.replace('-', '_'), None): raise exceptions.CommandError( _("ERROR: --%s was given, which is an Image v1 option" " that is no longer supported in Image v2") % deadopt) # Build an attribute dict from the parsed args, only include # attributes that were actually set on the command line kwargs = {} copy_attrs = ('name', 'id', 'container_format', 'disk_format', 'min_disk', 'min_ram', 'tags', '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 # properties should get flattened into the general kwargs if getattr(parsed_args, 'properties', None): for k, v in six.iteritems(parsed_args.properties): kwargs[k] = str(v) # 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['visibility'] = 'public' if parsed_args.private: kwargs['visibility'] = 'private' if parsed_args.community: kwargs['visibility'] = 'community' if parsed_args.shared: kwargs['visibility'] = 'shared' # Handle deprecated --owner option project_arg = parsed_args.project if parsed_args.owner: project_arg = parsed_args.owner LOG.warning( _('The --owner option is deprecated, ' 'please use --project instead.')) if project_arg: kwargs['owner'] = common.find_project( identity_client, project_arg, parsed_args.project_domain, ).id # open the file first to ensure any failures are handled before the # image is created fp = gc_utils.get_data_file(parsed_args) info = {} if fp is not None and parsed_args.volume: raise exceptions.CommandError( _("Uploading data and using " "container are not allowed at " "the same time")) if fp is None and parsed_args.file: LOG.warning(_("Failed to get an image file.")) return {}, {} if parsed_args.owner: kwargs['owner'] = common.find_project( identity_client, parsed_args.owner, parsed_args.project_domain, ).id # sign an image using a given local private key file if parsed_args.sign_key_path or parsed_args.sign_cert_id: if not parsed_args.file: msg = (_("signing an image requires the --file option, " "passing files via stdin when signing is not " "supported.")) raise exceptions.CommandError(msg) if (len(parsed_args.sign_key_path) < 1 or len(parsed_args.sign_cert_id) < 1): msg = (_("'sign-key-path' and 'sign-cert-id' must both be " "specified when attempting to sign an image.")) raise exceptions.CommandError(msg) else: sign_key_path = parsed_args.sign_key_path sign_cert_id = parsed_args.sign_cert_id signer = image_signer.ImageSigner() try: pw = utils.get_password( self.app.stdin, prompt=("Please enter private key password, leave " "empty if none: "), confirm=False) if not pw or len(pw) < 1: pw = None signer.load_private_key(sign_key_path, password=pw) except Exception: msg = (_("Error during sign operation: private key could " "not be loaded.")) raise exceptions.CommandError(msg) signature = signer.generate_signature(fp) signature_b64 = b64encode(signature) kwargs['img_signature'] = signature_b64 kwargs['img_signature_certificate_uuid'] = sign_cert_id kwargs['img_signature_hash_method'] = signer.hash_method if signer.padding_method: kwargs['img_signature_key_type'] = signer.padding_method # If a volume is specified. 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'] try: info['volume_type'] = info['volume_type']['name'] except TypeError: info['volume_type'] = None else: image = image_client.images.create(**kwargs) if fp is not None: with fp: try: image_client.images.upload(image.id, fp) except Exception: # If the upload fails for some reason attempt to remove the # dangling queued image made by the create() call above but # only if the user did not specify an id which indicates # the Image already exists and should be left alone. try: if 'id' not in kwargs: image_client.images.delete(image.id) except Exception: pass # we don't care about this one raise # now, throw the upload exception again # update the image after the data has been uploaded image = image_client.images.get(image.id) if not info: info = _format_image(image) return zip(*sorted(six.iteritems(info)))
def take_action(self, parsed_args): identity_client = self.app.client_manager.identity image_client = self.app.client_manager.image for deadopt in self.deadopts: if getattr(parsed_args, deadopt.replace('-', '_'), None): raise exceptions.CommandError( _("ERROR: --%s was given, which is an Image v1 option" " that is no longer supported in Image v2") % deadopt) # Build an attribute dict from the parsed args, only include # attributes that were actually set on the command line kwargs = {} copy_attrs = ('name', 'id', 'container_format', 'disk_format', 'min_disk', 'min_ram', 'tags', '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 # properties should get flattened into the general kwargs if getattr(parsed_args, 'properties', None): for k, v in parsed_args.properties.items(): kwargs[k] = str(v) # 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['is_protected'] = True if parsed_args.unprotected: kwargs['is_protected'] = False if parsed_args.public: kwargs['visibility'] = 'public' if parsed_args.private: kwargs['visibility'] = 'private' if parsed_args.community: kwargs['visibility'] = 'community' if parsed_args.shared: kwargs['visibility'] = 'shared' if parsed_args.project: kwargs['owner_id'] = common.find_project( identity_client, parsed_args.project, parsed_args.project_domain, ).id if parsed_args.use_import: kwargs['use_import'] = True # open the file first to ensure any failures are handled before the # image is created. Get the file name (if it is file, and not stdin) # for easier further handling. (fp, fname) = get_data_file(parsed_args) info = {} if fp is not None and parsed_args.volume: raise exceptions.CommandError(_("Uploading data and using " "container are not allowed at " "the same time")) if fp is None and parsed_args.file: LOG.warning(_("Failed to get an image file.")) return {}, {} elif fname: kwargs['filename'] = fname elif fp: kwargs['validate_checksum'] = False kwargs['data'] = fp # sign an image using a given local private key file if parsed_args.sign_key_path or parsed_args.sign_cert_id: if not parsed_args.file: msg = (_("signing an image requires the --file option, " "passing files via stdin when signing is not " "supported.")) raise exceptions.CommandError(msg) if (len(parsed_args.sign_key_path) < 1 or len(parsed_args.sign_cert_id) < 1): msg = (_("'sign-key-path' and 'sign-cert-id' must both be " "specified when attempting to sign an image.")) raise exceptions.CommandError(msg) else: sign_key_path = parsed_args.sign_key_path sign_cert_id = parsed_args.sign_cert_id signer = image_signer.ImageSigner() try: pw = utils.get_password( self.app.stdin, prompt=("Please enter private key password, leave " "empty if none: "), confirm=False) if not pw or len(pw) < 1: pw = None else: # load_private_key() requires the password to be # passed as bytes pw = pw.encode() signer.load_private_key( sign_key_path, password=pw) except Exception: msg = (_("Error during sign operation: private key " "could not be loaded.")) raise exceptions.CommandError(msg) signature = signer.generate_signature(fp) signature_b64 = b64encode(signature) kwargs['img_signature'] = signature_b64 kwargs['img_signature_certificate_uuid'] = sign_cert_id kwargs['img_signature_hash_method'] = signer.hash_method if signer.padding_method: kwargs['img_signature_key_type'] = \ signer.padding_method # If a volume is specified. 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'] try: info['volume_type'] = info['volume_type']['name'] except TypeError: info['volume_type'] = None else: image = image_client.create_image(**kwargs) if not info: info = _format_image(image) return zip(*sorted(info.items()))