def _get_encryption_key_id( self, key_manager, context: context.RequestContext, volume_type_id: str, snapshot: Optional[objects.Snapshot], source_volume: Optional[objects.Volume], image_metadata: Optional[dict[str, Any]]) -> Optional[str]: if volume_types.is_encrypted(context, volume_type_id): encryption_key_id = None if snapshot is not None: # creating from snapshot encryption_key_id = snapshot['encryption_key_id'] elif source_volume is not None: # cloning volume encryption_key_id = source_volume['encryption_key_id'] elif image_metadata is not None: # creating from image encryption_key_id = image_metadata.get( 'cinder_encryption_key_id') # NOTE(joel-coffman): References to the encryption key should *not* # be copied because the key is deleted when the volume is deleted. # Clone the existing key and associate a separate -- but # identical -- key with each volume. new_encryption_key_id: Optional[str] if encryption_key_id is not None: new_encryption_key_id = volume_utils.clone_encryption_key( context, key_manager, encryption_key_id) else: new_encryption_key_id = volume_utils.create_encryption_key( context, key_manager, volume_type_id) return new_encryption_key_id else: return None
def _get_encryption_key_id(self, key_manager, context, volume_type_id, snapshot, source_volume, image_metadata): encryption_key_id = None if volume_types.is_encrypted(context, volume_type_id): if snapshot is not None: # creating from snapshot encryption_key_id = snapshot['encryption_key_id'] elif source_volume is not None: # cloning volume encryption_key_id = source_volume['encryption_key_id'] elif image_metadata is not None: # creating from image encryption_key_id = image_metadata.get( 'cinder_encryption_key_id') # NOTE(joel-coffman): References to the encryption key should *not* # be copied because the key is deleted when the volume is deleted. # Clone the existing key and associate a separate -- but # identical -- key with each volume. if encryption_key_id is not None: encryption_key_id = volume_utils.clone_encryption_key( context, key_manager, encryption_key_id) else: encryption_key_id = volume_utils.create_encryption_key( context, key_manager, volume_type_id) return encryption_key_id
def _volume_upload_image(self, req, id, body): """Uploads the specified volume to image service.""" context = req.environ['cinder.context'] params = body['os-volume_upload_image'] req_version = req.api_version_request force = params.get('force', 'False') force = strutils.bool_from_string(force, strict=True) # Not found exception will be handled at the wsgi level volume = self.volume_api.get(context, id) context.authorize(policy.UPLOAD_IMAGE_POLICY) disk_format = params.get("disk_format", "raw") image_metadata = { "container_format": params.get("container_format", "bare"), "disk_format": disk_format, "name": params["image_name"] } if volume.encryption_key_id: # Clone volume encryption key: the current key cannot # be reused because it will be deleted when the volume is # deleted. encryption_key_id = volume_utils.clone_encryption_key( context, self._key_manager, volume.encryption_key_id) image_metadata['cinder_encryption_key_id'] = encryption_key_id image_metadata['cinder_encryption_key_deletion_policy'] = \ 'on_image_deletion' if req_version >= mv.get_api_version(mv.UPLOAD_IMAGE_PARAMS): image_metadata['visibility'] = params.get('visibility', 'private') image_metadata['protected'] = strutils.bool_from_string( params.get('protected', 'False'), strict=True) if image_metadata['visibility'] == 'public': context.authorize(policy.UPLOAD_PUBLIC_POLICY) try: response = self.volume_api.copy_volume_to_image( context, volume, image_metadata, force) except exception.InvalidVolume as error: raise webob.exc.HTTPBadRequest(explanation=error.msg) except ValueError as error: raise webob.exc.HTTPBadRequest(explanation=str(error)) except messaging.RemoteError as error: msg = "%(err_type)s: %(err_msg)s" % { 'err_type': error.exc_type, 'err_msg': error.value } raise webob.exc.HTTPBadRequest(explanation=msg) except Exception as error: raise webob.exc.HTTPBadRequest(explanation=str(error)) return {'os-volume_upload_image': response}
def _run_backup(self, context, backup, volume): # Save a copy of the encryption key ID in case the volume is deleted. if (volume.encryption_key_id is not None and backup.encryption_key_id is None): backup.encryption_key_id = volume_utils.clone_encryption_key( context, key_manager.API(CONF), volume.encryption_key_id) backup.save() backup_service = self.service(context) properties = volume_utils.brick_get_connector_properties() # NOTE(geguileo): Not all I/O disk operations properly do greenthread # context switching and may end up blocking the greenthread, so we go # with native threads proxy-wrapping the device file object. try: backup_device = self.volume_rpcapi.get_backup_device( context, backup, volume) attach_info = self._attach_device(context, backup_device.device_obj, properties, backup_device.is_snapshot) try: device_path = attach_info['device']['path'] if (isinstance(device_path, str) and not os.path.isdir(device_path)): if backup_device.secure_enabled: with open(device_path, 'rb') as device_file: updates = backup_service.backup( backup, tpool.Proxy(device_file)) else: with utils.temporary_chown(device_path): with open(device_path, 'rb') as device_file: updates = backup_service.backup( backup, tpool.Proxy(device_file)) # device_path is already file-like so no need to open it else: updates = backup_service.backup(backup, tpool.Proxy(device_path)) finally: self._detach_device(context, attach_info, backup_device.device_obj, properties, backup_device.is_snapshot, force=True, ignore_errors=True) finally: with backup.as_read_deleted(): backup.refresh() self._cleanup_temp_volumes_snapshots_when_backup_created( context, backup) return updates
def _run_restore(self, context, backup, volume): orig_key_id = volume.encryption_key_id backup_service = self.service(context) properties = volume_utils.brick_get_connector_properties() secure_enabled = (self.volume_rpcapi.secure_file_operations_enabled( context, volume)) attach_info = self._attach_device(context, volume, properties) # NOTE(geguileo): Not all I/O disk operations properly do greenthread # context switching and may end up blocking the greenthread, so we go # with native threads proxy-wrapping the device file object. try: device_path = attach_info['device']['path'] open_mode = 'rb+' if os.name == 'nt' else 'wb' if (isinstance(device_path, str) and not os.path.isdir(device_path)): if secure_enabled: with open(device_path, open_mode) as device_file: backup_service.restore(backup, volume.id, tpool.Proxy(device_file)) else: with utils.temporary_chown(device_path): with open(device_path, open_mode) as device_file: backup_service.restore(backup, volume.id, tpool.Proxy(device_file)) # device_path is already file-like so no need to open it else: backup_service.restore(backup, volume.id, tpool.Proxy(device_path)) except exception.BackupRestoreCancel: raise except Exception: LOG.exception( 'Restoring backup %(backup_id)s to volume ' '%(volume_id)s failed.', { 'backup_id': backup.id, 'volume_id': volume.id }) raise finally: self._detach_device(context, attach_info, volume, properties, force=True) # Regardless of whether the restore was successful, do some # housekeeping to ensure the restored volume's encryption key ID is # unique, and any previous key ID is deleted. Start by fetching fresh # info on the restored volume. restored_volume = objects.Volume.get_by_id(context, volume.id) restored_key_id = restored_volume.encryption_key_id if restored_key_id != orig_key_id: LOG.info( 'Updating encryption key ID for volume %(volume_id)s ' 'from backup %(backup_id)s.', { 'volume_id': volume.id, 'backup_id': backup.id }) key_mgr = key_manager.API(CONF) if orig_key_id is not None: LOG.debug('Deleting original volume encryption key ID.') volume_utils.delete_encryption_key(context, key_mgr, orig_key_id) if backup.encryption_key_id is None: # This backup predates the current code that stores the cloned # key ID in the backup database. Fortunately, the key ID # restored from the backup data _is_ a clone of the original # volume's key ID, so grab it. LOG.debug('Gleaning backup encryption key ID from metadata.') backup.encryption_key_id = restored_key_id backup.save() # Clone the key ID again to ensure every restored volume has # a unique key ID. The volume's key ID should not be the same # as the backup.encryption_key_id (the copy made when the backup # was first created). new_key_id = volume_utils.clone_encryption_key( context, key_mgr, backup.encryption_key_id) restored_volume.encryption_key_id = new_key_id restored_volume.save() else: LOG.debug( 'Encryption key ID for volume %(volume_id)s already ' 'matches encryption key ID in backup %(backup_id)s.', { 'volume_id': volume.id, 'backup_id': backup.id })