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 = vol_utils.clone_encryption_key( context, key_manager, encryption_key_id) else: encryption_key_id = vol_utils.create_encryption_key( context, key_manager, volume_type_id) return encryption_key_id
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 = vol_utils.clone_encryption_key( context, key_manager, encryption_key_id) else: encryption_key_id = vol_utils.create_encryption_key( context, key_manager, volume_type_id) return encryption_key_id
def _save_vol_base_meta(self, container, volume_id): """Save base volume metadata to container. This will fetch all fields from the db Volume object for volume_id and save them in the provided container dictionary. """ type_tag = self.TYPE_TAG_VOL_BASE_META LOG.debug("Getting metadata type '%s'", type_tag) meta = self.db.volume_get(self.context, volume_id) if meta: container[type_tag] = {} for key, value in meta: # Exclude fields that are "not JSON serializable" if not self._is_serializable(value): LOG.info( "Unable to serialize field '%s' - excluding " "from backup", key) continue # Copy the encryption key UUID for backup if key is 'encryption_key_id' and value is not None: value = vol_utils.clone_encryption_key( self.context, self._key_manager, value) LOG.debug("Copying encryption key UUID for backup.") container[type_tag][key] = value LOG.debug("Completed fetching metadata type '%s'", type_tag) else: LOG.debug("No metadata type '%s' available", type_tag)
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.get_backup_driver(context) properties = 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, six.string_types) 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: backup = objects.Backup.get_by_id(context, backup.id) 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.get_backup_driver(context) properties = 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, six.string_types) 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)) 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})