예제 #1
0
    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
예제 #2
0
    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
예제 #3
0
    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)
예제 #4
0
    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
예제 #5
0
    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})