def _copy_volume_with_file(src, dest, size_in_m):
    src_handle = src
    if isinstance(src, six.string_types):
        src_handle = _open_volume_with_path(src, 'rb')

    dest_handle = dest
    if isinstance(dest, six.string_types):
        dest_handle = _open_volume_with_path(dest, 'wb')

    if not src_handle:
        raise exception.DeviceUnavailable(
            _("Failed to copy volume, source device unavailable."))

    if not dest_handle:
        raise exception.DeviceUnavailable(
            _("Failed to copy volume, destination device unavailable."))

    start_time = timeutils.utcnow()

    _transfer_data(src_handle, dest_handle, size_in_m * units.Mi, units.Mi * 4)

    duration = max(1, timeutils.delta_seconds(start_time, timeutils.utcnow()))

    if isinstance(src, six.string_types):
        src_handle.close()
    if isinstance(dest, six.string_types):
        dest_handle.close()

    mbps = (size_in_m / duration)
    LOG.info(_LI("Volume copy completed (%(size_in_m).2f MB at "
                 "%(mbps).2f MB/s)."),
             {'size_in_m': size_in_m, 'mbps': mbps})
Esempio n. 2
0
    def _attach_volume(self, context, volume, properties, remote=False):
        """Attach the volume."""
        if remote:
            rpcapi = volume_rpcapi.VolumeAPI()
            conn = rpcapi.initialize_connection(context, volume, properties)
        else:
            conn = self.initialize_connection(volume, properties)

        # Use Brick's code to do attach/detach
        use_multipath = self.configuration.use_multipath_for_image_xfer
        device_scan_attempts = self.configuration.num_volume_device_scan_tries
        protocol = conn['driver_volume_type']
        connector = utils.brick_get_connector(
            protocol,
            use_multipath=use_multipath,
            device_scan_attempts=device_scan_attempts)
        device = connector.connect_volume(conn['data'])
        host_device = device['path']

        if not connector.check_valid_device(host_device):
            raise exception.DeviceUnavailable(path=host_device,
                                              reason=(_("Unable to access "
                                                        "the backend storage "
                                                        "via the path "
                                                        "%(path)s.") % {
                                                            'path': host_device
                                                        }))
        return {'conn': conn, 'device': device, 'connector': connector}
Esempio n. 3
0
    def attach(self):
        device = self.connector.connect_volume(self.conn_info['data'])
        self.device_attached(device)
        try:
            unavailable = not self.connector.check_valid_device(self.path)
        except Exception:
            unavailable = True
            LOG.exception('Could not validate device %s', self.path)

        if unavailable:
            raise cinder_exception.DeviceUnavailable(
                path=self.path,
                attach_info=self._ovo.connection_information,
                reason=('Unable to access the backend storage via path '
                        '%s.') % self.path)
        if self._volume:
            self.volume.local_attach = self
Esempio n. 4
0
    def attach(self):
        device = self.connector.connect_volume(self.conn_info['data'])
        self.device_attached(device)
        try:
            if self.connector.check_valid_device(self.path):
                error_msg = None
            else:
                error_msg = ('Unable to access the backend storage via path '
                             '%s.' % self.path)
        except Exception:
            error_msg = ('Could not validate device %s. There may be missing '
                         'packages on your host.' % self.path)
            LOG.exception(error_msg)

        if error_msg:
            self.detach(force=True, ignore_errors=True)
            raise cinder_exception.DeviceUnavailable(
                path=self.path, attach_info=self._ovo.connection_information,
                reason=error_msg)
        if self._volume:
            self.volume.local_attach = self
Esempio n. 5
0
    def _connect_device(self, conn):
        # Use Brick's code to do attach/detach
        use_multipath = self.configuration.use_multipath_for_image_xfer
        device_scan_attempts = self.configuration.num_volume_device_scan_tries
        protocol = conn['driver_volume_type']
        connector = utils.brick_get_connector(
            protocol,
            use_multipath=use_multipath,
            device_scan_attempts=device_scan_attempts,
            conn=conn)
        device = connector.connect_volume(conn['data'])
        attach_info = {'conn': conn, 'device': device['path'], 'connector': connector}

        if conn['data']['encrypted']:
            symlink_dev = '/dev/rbd-volume-%s' % conn['data']['volume_id']
            utils.execute('ln', '--symbolic', '--force',
                          device['path'], symlink_dev, run_as_root=True)
            
            attach_info = {'conn': conn, 'device': {'path': symlink_dev}, 'connector': connector}

        if not conn['data']['encrypted']:
            host_device = device['path']
            unavailable = True
            try:
                # Secure network file systems will NOT run as root.
                root_access = not self.secure_file_operations_enabled()
                unavailable = not connector.check_valid_device(host_device,
                                                               root_access)
            except Exception:
                LOG.exception(_LE('Could not validate device %s'), host_device)
    
            if unavailable and conn['encrypted']:
                raise exception.DeviceUnavailable(path=host_device,
                                                  attach_info=attach_info,
                                                  reason=(_("Unable to access "
                                                            "the backend storage "
                                                            "via the path "
                                                            "%(path)s.") %
                                                          {'path': host_device}))
        return attach_info
Esempio n. 6
0
    def _attach_volume(self, context, volume, properties, remote=False):
        """Attach the volume."""
        if remote:
            # Call remote manager's initialize_connection which includes
            # driver's create_export and initialize_connection
            rpcapi = volume_rpcapi.VolumeAPI()
            conn = rpcapi.initialize_connection(context, volume, properties)
        else:
            # Call local driver's create_export and initialize_connection.
            # NOTE(avishay) This is copied from the manager's code - need to
            # clean this up in the future.
            model_update = None
            try:
                LOG.debug(_("Volume %s: creating export"), volume['id'])
                model_update = self.create_export(context, volume)
                if model_update:
                    volume = self.db.volume_update(context, volume['id'],
                                                   model_update)
            except exception.CinderException as ex:
                if model_update:
                    LOG.exception(
                        _("Failed updating model of volume "
                          "%(volume_id)s with driver provided model "
                          "%(model)s") % {
                              'volume_id': volume['id'],
                              'model': model_update
                          })
                    raise exception.ExportFailure(reason=ex)

            try:
                conn = self.initialize_connection(volume, properties)
            except Exception as err:
                try:
                    err_msg = (_('Unable to fetch connection information from '
                                 'backend: %(err)s') % {
                                     'err': err
                                 })
                    LOG.error(err_msg)
                    LOG.debug("Cleaning up failed connect initialization.")
                    self.remove_export(context, volume)
                except Exception as ex:
                    ex_msg = (_('Error encountered during cleanup '
                                'of a failed attach: %(ex)s') % {
                                    'ex': ex
                                })
                    LOG.error(err_msg)
                    raise exception.VolumeBackendAPIException(data=ex_msg)
                raise exception.VolumeBackendAPIException(data=err_msg)

        # Use Brick's code to do attach/detach
        use_multipath = self.configuration.use_multipath_for_image_xfer
        device_scan_attempts = self.configuration.num_volume_device_scan_tries
        protocol = conn['driver_volume_type']
        connector = utils.brick_get_connector(
            protocol,
            use_multipath=use_multipath,
            device_scan_attempts=device_scan_attempts,
            conn=conn)
        device = connector.connect_volume(conn['data'])
        host_device = device['path']

        if not connector.check_valid_device(host_device):
            raise exception.DeviceUnavailable(path=host_device,
                                              reason=(_("Unable to access "
                                                        "the backend storage "
                                                        "via the path "
                                                        "%(path)s.") % {
                                                            'path': host_device
                                                        }))
        return {'conn': conn, 'device': device, 'connector': connector}
Esempio n. 7
0
    def _attach_volume(self, context, volume, connector):
        """Attach the volume."""
        iser_properties = None
        host_device = None
        init_conn = self.initialize_connection(volume, connector)
        iser_properties = init_conn['data']

        # code "inspired by" nova/virt/libvirt/volume.py
        try:
            self._run_iscsiadm(iser_properties, ())
        except processutils.ProcessExecutionError as exc:
            # iscsiadm returns 21 for "No records found" after version 2.0-871
            if exc.exit_code in [21, 255]:
                self._run_iscsiadm(iser_properties, ('--op', 'new'))
            else:
                raise

        if iser_properties.get('auth_method'):
            self._iscsiadm_update(iser_properties,
                                  "node.session.auth.authmethod",
                                  iser_properties['auth_method'])
            self._iscsiadm_update(iser_properties,
                                  "node.session.auth.username",
                                  iser_properties['auth_username'])
            self._iscsiadm_update(iser_properties,
                                  "node.session.auth.password",
                                  iser_properties['auth_password'])

        host_device = (
            "/dev/disk/by-path/ip-%s-iser-%s-lun-%s" %
            (iser_properties['target_portal'], iser_properties['target_iqn'],
             iser_properties.get('target_lun', 0)))

        out = self._run_iscsiadm_bare(["-m", "session"],
                                      run_as_root=True,
                                      check_exit_code=[0, 1, 21])[0] or ""

        portals = [{
            'portal': p.split(" ")[2],
            'iqn': p.split(" ")[3]
        } for p in out.splitlines() if p.startswith("iser:")]

        stripped_portal = iser_properties['target_portal'].split(",")[0]
        length_iqn = [
            s for s in portals if stripped_portal == s['portal'].split(",")[0]
            and s['iqn'] == iser_properties['target_iqn']
        ]
        if len(portals) == 0 or len(length_iqn) == 0:
            try:
                self._run_iscsiadm(iser_properties, ("--login", ),
                                   check_exit_code=[0, 255])
            except processutils.ProcessExecutionError as err:
                if err.exit_code in [15]:
                    self._iscsiadm_update(iser_properties, "node.startup",
                                          "automatic")
                    return iser_properties, host_device
                else:
                    raise

            self._iscsiadm_update(iser_properties, "node.startup", "automatic")

            tries = 0
            while not os.path.exists(host_device):
                if tries >= self.configuration.num_iser_scan_tries:
                    raise exception.CinderException(
                        _("iSER device "
                          "not found "
                          "at %s") % (host_device))

                LOG.warn(
                    _("ISER volume not yet found at: %(host_device)s. "
                      "Will rescan & retry.  Try number: %(tries)s.") % {
                          'host_device': host_device,
                          'tries': tries
                      })

                # The rescan isn't documented as being necessary(?),
                # but it helps
                self._run_iscsiadm(iser_properties, ("--rescan", ))

                tries = tries + 1
                if not os.path.exists(host_device):
                    time.sleep(tries**2)

            if tries != 0:
                LOG.debug(
                    _("Found iSER node %(host_device)s "
                      "(after %(tries)s rescans).") % {
                          'host_device': host_device,
                          'tries': tries
                      })

        if not self._check_valid_device(host_device):
            raise exception.DeviceUnavailable(path=host_device,
                                              reason=(_("Unable to access "
                                                        "the backend storage "
                                                        "via the path "
                                                        "%(path)s.") % {
                                                            'path': host_device
                                                        }))
        return iser_properties, host_device