Esempio n. 1
0
 def _connection_context(self, volume):
     use_multipath = self.configuration.use_multipath_for_image_xfer
     enforce_multipath = self.configuration.enforce_multipath_for_image_xfer
     connector = volume_utils.brick_get_connector_properties(
         use_multipath, enforce_multipath)
     connection = self.initialize_connection(volume, connector)
     try:
         yield connection
     finally:
         self.terminate_connection(volume, connector)
Esempio n. 2
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.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
Esempio n. 3
0
 def attach(self):
     connector_dict = volume_utils.brick_get_connector_properties(
         self.backend.configuration.use_multipath_for_image_xfer,
         self.backend.configuration.enforce_multipath_for_image_xfer)
     conn = self.connect(connector_dict)
     try:
         conn.attach()
     except Exception:
         self.disconnect(conn)
         raise
     return conn
Esempio n. 4
0
    def init_cinder_hosts(self, **kwargs):
        """Initialize server-storage connection."""
        targets = kwargs.pop(
            'targets', {'info': {}, 'list': [], 'iqns': {}, 'target_map': {}})
        connector = volume_utils.brick_get_connector_properties(
            multipath=self.conf.use_multipath_for_image_xfer,
            enforce_multipath=self.conf.enforce_multipath_for_image_xfer)
        target_ports = self.storage_info['controller_ports']

        if target_ports:
            if (self.find_targets_from_storage(
                    targets, connector, target_ports) and
                    self.conf.hitachi_group_create):
                self.create_mapping_targets(targets, connector)

            utils.require_target_existed(targets)
Esempio n. 5
0
    def _copy_vdisk_data(self, src_vdisk_name, src_vdisk_id, dest_vdisk_name,
                         dest_vdisk_id):
        """Copy data from src vdisk to dest vdisk.

        To be able to copy data between vdisks, we must ensure that both
        vdisks have been mapped to host. If vdisk has not been mapped,
        it must be mapped firstly. When data copy completed, vdisk
        should be restored to previous mapped or non-mapped status.
        """

        LOG.debug('enter: _copy_vdisk_data: %(src)s -> %(dest)s.', {
            'src': src_vdisk_name,
            'dest': dest_vdisk_name
        })

        connector = volume_utils.brick_get_connector_properties()
        (src_map, src_lun_id) = self._is_vdisk_map(src_vdisk_name, connector)
        (dest_map, dest_lun_id) = self._is_vdisk_map(dest_vdisk_name,
                                                     connector)

        src_map_device = None
        src_properties = None
        dest_map_device = None
        dest_properties = None

        try:
            if not src_map:
                src_lun_id = self._map_vdisk_to_host(src_vdisk_name, connector)
            if not dest_map:
                dest_lun_id = self._map_vdisk_to_host(dest_vdisk_name,
                                                      connector)
            src_properties = self._get_vdisk_map_properties(
                connector, src_lun_id, src_vdisk_name, src_vdisk_id,
                self._get_vdisk_params(None))
            src_map_device = self._scan_device(src_properties)

            dest_properties = self._get_vdisk_map_properties(
                connector, dest_lun_id, dest_vdisk_name, dest_vdisk_id,
                self._get_vdisk_params(None))
            dest_map_device = self._scan_device(dest_properties)

            src_vdisk_attr = self._get_vdisk_attributes(src_vdisk_name)

            # vdisk capacity is bytes, translate into MB
            size_in_mb = int(src_vdisk_attr['capacity']) / units.Mi
            volume_utils.copy_volume(src_map_device['path'],
                                     dest_map_device['path'], size_in_mb,
                                     self.configuration.volume_dd_blocksize)
        except Exception:
            with excutils.save_and_reraise_exception():
                LOG.error('Failed to copy %(src)s to %(dest)s.', {
                    'src': src_vdisk_name,
                    'dest': dest_vdisk_name
                })
        finally:
            if not dest_map:
                self._unmap_vdisk_from_host(dest_vdisk_name, connector)
                self._remove_device(dest_properties, dest_map_device)
            if not src_map:
                self._unmap_vdisk_from_host(src_vdisk_name, connector)
                self._remove_device(src_properties, src_map_device)

        LOG.debug('leave: _copy_vdisk_data: %(src)s -> %(dest)s.', {
            'src': src_vdisk_name,
            'dest': dest_vdisk_name
        })
Esempio n. 6
0
    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
                })