Esempio n. 1
0
 def _verify_rtstool(self):
     try:
         # This call doesn't need locking
         utils.execute('storage-rtstool', 'verify')
     except (OSError, putils.ProcessExecutionError):
         LOG.error(_LE('storage-rtstool is not installed correctly'))
         raise
Esempio n. 2
0
def _make_link(volume_path, backup_path, vol_id):
    """Create a hard link for the volume block device.

    The IBM TSM client performs an image backup on a block device.
    The name of the block device is the backup prefix plus the backup id

    :param volume_path: real device path name for volume
    :param backup_path: path name TSM will use as volume to backup
    :param vol_id: id of volume to backup (for reporting)

    :raises: InvalidBackup
    """

    try:
        utils.execute('ln',
                      volume_path,
                      backup_path,
                      run_as_root=True,
                      check_exit_code=True)
    except processutils.ProcessExecutionError as exc:
        err = (_('backup: %(vol_id)s failed to create device hardlink '
                 'from %(vpath)s to %(bpath)s.\n'
                 'stdout: %(out)s\n stderr: %(err)s') % {
                     'vol_id': vol_id,
                     'vpath': volume_path,
                     'bpath': backup_path,
                     'out': exc.stdout,
                     'err': exc.stderr
                 })
        LOG.error(err)
        raise exception.InvalidBackup(reason=err)
Esempio n. 3
0
def _make_link(volume_path, backup_path, vol_id):
    """Create a hard link for the volume block device.

    The IBM TSM client performs an image backup on a block device.
    The name of the block device is the backup prefix plus the backup id

    :param volume_path: real device path name for volume
    :param backup_path: path name TSM will use as volume to backup
    :param vol_id: id of volume to backup (for reporting)

    :raises: InvalidBackup
    """

    try:
        utils.execute('ln', volume_path, backup_path,
                      run_as_root=True,
                      check_exit_code=True)
    except processutils.ProcessExecutionError as exc:
        err = (_('backup: %(vol_id)s failed to create device hardlink '
                 'from %(vpath)s to %(bpath)s.\n'
                 'stdout: %(out)s\n stderr: %(err)s')
               % {'vol_id': vol_id,
                  'vpath': volume_path,
                  'bpath': backup_path,
                  'out': exc.stdout,
                  'err': exc.stderr})
        LOG.error(err)
        raise exception.InvalidBackup(reason=err)
Esempio n. 4
0
 def _verify_rtstool(self):
     try:
         # This call doesn't need locking
         utils.execute('storage-rtstool', 'verify')
     except (OSError, putils.ProcessExecutionError):
         LOG.error(_LE('storage-rtstool is not installed correctly'))
         raise
Esempio n. 5
0
    def update_config_file(self, name, tid, path, config_auth):

        conf_file = self.iet_conf
        vol_id = name.split(':')[1]

        # If config file does not exist, create a blank conf file and
        # add configuration for the volume on the new file.
        if not os.path.exists(conf_file):
            try:
                utils.execute("truncate", conf_file, "--size=0",
                              run_as_root=True)
            except putils.ProcessExecutionError:
                LOG.exception(_LE("Failed to create %(conf)s for volume "
                                  "id:%(vol_id)s"),
                              {'conf': conf_file, 'vol_id': vol_id})
                raise exception.ISCSITargetCreateFailed(volume_id=vol_id)

        try:
            volume_conf = """
                    Target %s
                        %s
                        Lun 0 Path=%s,Type=%s
            """ % (name, config_auth, path, self._iotype(path))

            with utils.temporary_chown(conf_file):
                with open(conf_file, 'a+') as f:
                    f.write(volume_conf)
        except Exception:
            LOG.exception(_LE("Failed to update %(conf)s for volume "
                              "id:%(vol_id)s"),
                          {'conf': conf_file, 'vol_id': vol_id})
            raise exception.ISCSITargetCreateFailed(volume_id=vol_id)
Esempio n. 6
0
 def _delete_logicalunit(self, tid, lun):
     utils.execute('ietadm',
                   '--op',
                   'delete',
                   '--tid=%s' % tid,
                   '--lun=%d' % lun,
                   run_as_root=True)
Esempio n. 7
0
 def _new_auth(self, tid, type, username, password):
     utils.execute('ietadm', '--op', 'new',
                   '--tid=%s' % tid,
                   '--user',
                   '--params=%s=%s,Password=%s' % (type,
                                                   username,
                                                   password),
                   run_as_root=True)
Esempio n. 8
0
 def _force_delete_target(self, tid, sid, cid):
     utils.execute('ietadm',
                   '--op',
                   'delete',
                   '--tid=%s' % tid,
                   '--sid=%s' % sid,
                   '--cid=%s' % cid,
                   run_as_root=True)
Esempio n. 9
0
 def _new_auth(self, tid, type, username, password):
     utils.execute('ietadm',
                   '--op',
                   'new',
                   '--tid=%s' % tid,
                   '--user',
                   '--params=%s=%s,Password=%s' %
                   (type, username, password),
                   run_as_root=True)
Esempio n. 10
0
    def _new_target(self, name, tid):
        """Create new scsi target using specified parameters.

        If the target already exists, ietadm returns
        'Invalid argument' and error code '234'.
        This should be ignored for ensure export case.
        """
        utils.execute('ietadm', '--op', 'new',
                      '--tid=%s' % tid,
                      '--params', 'Name=%s' % name,
                      run_as_root=True, check_exit_code=[0, 234])
Esempio n. 11
0
 def _limit_bps(self, rw, dev, bps):
     try:
         utils.execute('cgset',
                       '-r',
                       'blkio.throttle.%s_bps_device=%s %d' %
                       (rw, dev, bps),
                       self.cgroup,
                       run_as_root=True)
     except processutils.ProcessExecutionError:
         LOG.warning(
             _LW('Failed to setup blkio cgroup to throttle the '
                 'device \'%(device)s\'.'), {'device': dev})
Esempio n. 12
0
def clear_volume(volume_size,
                 volume_path,
                 volume_clear=None,
                 volume_clear_size=None,
                 volume_clear_ionice=None,
                 throttle=None):
    """Unprovision old volumes to prevent data leaking between users."""
    if volume_clear is None:
        volume_clear = CONF.volume_clear

    if volume_clear_size is None:
        volume_clear_size = CONF.volume_clear_size

    if volume_clear_size == 0:
        volume_clear_size = volume_size

    if volume_clear_ionice is None:
        volume_clear_ionice = CONF.volume_clear_ionice

    LOG.info(_LI("Performing secure delete on volume: %s"), volume_path)

    # We pass sparse=False explicitly here so that zero blocks are not
    # skipped in order to clear the volume.
    if volume_clear == 'zero':
        return copy_volume('/dev/zero',
                           volume_path,
                           volume_clear_size,
                           CONF.volume_dd_blocksize,
                           sync=True,
                           execute=utils.execute,
                           ionice=volume_clear_ionice,
                           throttle=throttle,
                           sparse=False)
    elif volume_clear == 'shred':
        clear_cmd = ['shred', '-n3']
        if volume_clear_size:
            clear_cmd.append('-s%dMiB' % volume_clear_size)
    else:
        raise exception.InvalidConfigurationValue(option='volume_clear',
                                                  value=volume_clear)

    clear_cmd.append(volume_path)
    start_time = timeutils.utcnow()
    utils.execute(*clear_cmd, run_as_root=True)
    duration = timeutils.delta_seconds(start_time, timeutils.utcnow())

    # NOTE(jdg): use a default of 1, mostly for unit test, but in
    # some incredible event this is 0 (cirros image?) don't barf
    if duration < 1:
        duration = 1
    LOG.info(_LI('Elapsed time for clear volume: %.2f sec'), duration)
Esempio n. 13
0
    def _new_logicalunit(self, tid, lun, path):
        """Attach a new volume to scsi target as a logical unit.

        If a logical unit exists on the specified target lun,
        ietadm returns 'File exists' and error code '239'.
        This should be ignored for ensure export case.
        """

        utils.execute('ietadm', '--op', 'new',
                      '--tid=%s' % tid,
                      '--lun=%d' % lun,
                      '--params',
                      'Path=%s,Type=%s' % (path, self._iotype(path)),
                      run_as_root=True, check_exit_code=[0, 239])
Esempio n. 14
0
    def __init__(self, bps_limit, cgroup_name):
        self.bps_limit = bps_limit
        self.cgroup = cgroup_name
        self.srcdevs = {}
        self.dstdevs = {}

        try:
            utils.execute('cgcreate',
                          '-g',
                          'blkio:%s' % self.cgroup,
                          run_as_root=True)
        except processutils.ProcessExecutionError:
            LOG.error(_LE('Failed to create blkio cgroup \'%(name)s\'.'),
                      {'name': cgroup_name})
            raise
Esempio n. 15
0
    def _new_target(self, name, tid):
        """Create new scsi target using specified parameters.

        If the target already exists, ietadm returns
        'Invalid argument' and error code '234'.
        This should be ignored for ensure export case.
        """
        utils.execute('ietadm',
                      '--op',
                      'new',
                      '--tid=%s' % tid,
                      '--params',
                      'Name=%s' % name,
                      run_as_root=True,
                      check_exit_code=[0, 234])
Esempio n. 16
0
def check_for_odirect_support(src, dest, flag='oflag=direct'):

    # Check whether O_DIRECT is supported
    try:
        # iflag=direct and if=/dev/zero combination does not work
        # error: dd: failed to open '/dev/zero': Invalid argument
        if (src == '/dev/zero' and flag == 'iflag=direct'):
            return False
        else:
            utils.execute('dd', 'count=0', 'if=%s' % src,
                          'of=%s' % dest,
                          flag, run_as_root=True)
            return True
    except processutils.ProcessExecutionError:
        return False
Esempio n. 17
0
def _convert_image(prefix, source, dest, out_format, run_as_root=True):
    """Convert image to other format."""

    cmd = prefix + ('qemu-img', 'convert', '-O', out_format, source, dest)

    # Check whether O_DIRECT is supported and set '-t none' if it is
    # This is needed to ensure that all data hit the device before
    # it gets unmapped remotely from the host for some backends
    # Reference Bug: #1363016

    # NOTE(jdg): In the case of file devices qemu does the
    # flush properly and more efficiently than would be done
    # setting O_DIRECT, so check for that and skip the
    # setting for non BLK devs
    if (utils.is_blk_device(dest) and volume_utils.check_for_odirect_support(
            source, dest, 'oflag=direct')):
        cmd = prefix + ('qemu-img', 'convert', '-t', 'none', '-O', out_format,
                        source, dest)

    start_time = timeutils.utcnow()
    utils.execute(*cmd, run_as_root=run_as_root)
    duration = timeutils.delta_seconds(start_time, timeutils.utcnow())

    # NOTE(jdg): use a default of 1, mostly for unit test, but in
    # some incredible event this is 0 (cirros image?) don't barf
    if duration < 1:
        duration = 1
    try:
        image_size = qemu_img_info(source, run_as_root=True).virtual_size
    except ValueError as e:
        msg = _LI("The image was successfully converted, but image size "
                  "is unavailable. src %(src)s, dest %(dest)s. %(error)s")
        LOG.info(msg, {"src": source, "dest": dest, "error": e})
        return

    fsz_mb = image_size / units.Mi
    mbps = (fsz_mb / duration)
    msg = ("Image conversion details: src %(src)s, size %(sz).2f MB, "
           "duration %(duration).2f sec, destination %(dest)s")
    LOG.debug(msg, {
        "src": source,
        "sz": fsz_mb,
        "duration": duration,
        "dest": dest
    })

    msg = _LI("Converted %(sz).2f MB image at %(mbps).2f MB/s")
    LOG.info(msg, {"sz": fsz_mb, "mbps": mbps})
Esempio n. 18
0
def qemu_img_info(path, run_as_root=True):
    """Return an object containing the parsed output from qemu-img info."""
    cmd = ('env', 'LC_ALL=C', 'qemu-img', 'info', path)
    if os.name == 'nt':
        cmd = cmd[2:]
    out, _err = utils.execute(*cmd, run_as_root=run_as_root)
    return imageutils.QemuImgInfo(out)
Esempio n. 19
0
    def _recreate_backing_lun(self, iqn, tid, name, path):
        LOG.warning(_LW('Attempting recreate of backing lun...'))

        # Since we think the most common case of this is a dev busy
        # (create vol from snapshot) we're going to add a sleep here
        # this will hopefully give things enough time to stabilize
        # how long should we wait??  I have no idea, let's go big
        # and error on the side of caution
        time.sleep(10)

        (out, err) = (None, None)
        try:
            (out, err) = utils.execute('tgtadm', '--lld', 'iscsi',
                                       '--op', 'new', '--mode',
                                       'logicalunit', '--tid',
                                       tid, '--lun', '1', '-b',
                                       path, run_as_root=True)
        except putils.ProcessExecutionError as e:
            LOG.error(_LE("Failed recovery attempt to create "
                          "iscsi backing lun for Volume "
                          "ID:%(vol_id)s: %(e)s"),
                      {'vol_id': name, 'e': e})
        finally:
            LOG.debug('StdOut from recreate backing lun: %s', out)
            LOG.debug('StdErr from recreate backing lun: %s', err)
Esempio n. 20
0
    def _do_backup(self, backup_path, vol_id, backup_mode):
        """Perform the actual backup operation.

       :param backup_path: volume path
       :param vol_id: volume id
       :param backup_mode: file mode of source volume; 'image' or 'file'
       :raises: InvalidBackup
        """

        backup_attrs = {'Total number of objects backed up': '1'}
        compr_flag = 'yes' if CONF.backup_tsm_compression else 'no'

        backup_cmd = ['dsmc', 'backup']
        if _image_mode(backup_mode):
            backup_cmd.append('image')
        backup_cmd.extend(['-quiet',
                           '-compression=%s' % compr_flag,
                           '-password=%s' % self.tsm_password,
                           backup_path])

        out, err = utils.execute(*backup_cmd,
                                 run_as_root=True,
                                 check_exit_code=False)

        success = _check_dsmc_output(out, backup_attrs, exact_match=False)
        if not success:
            err = (_('backup: %(vol_id)s failed to obtain backup '
                     'success notification from server.\n'
                     'stdout: %(out)s\n stderr: %(err)s')
                   % {'vol_id': vol_id,
                      'out': out,
                      'err': err})
            LOG.error(err)
            raise exception.InvalidBackup(reason=err)
Esempio n. 21
0
    def _do_iscsi_discovery(self, volume):
        # TODO(justinsb): Deprecate discovery and use stored info
        # NOTE(justinsb): Discovery won't work with CHAP-secured targets (?)
        LOG.warning(_LW("ISCSI provider_location not stored, using discovery"))

        volume_id = volume['id']

        try:
            # NOTE(griff) We're doing the split straight away which should be
            # safe since using '@' in hostname is considered invalid

            (out, _err) = utils.execute('iscsiadm', '-m', 'discovery',
                                        '-t', 'sendtargets', '-p',
                                        volume['host'].split('@')[0],
                                        run_as_root=True)
        except processutils.ProcessExecutionError as ex:
            LOG.error(_LE("ISCSI discovery attempt failed for:%s") %
                      volume['host'].split('@')[0])
            LOG.debug(("Error from iscsiadm -m discovery: %s") % ex.stderr)
            return None

        for target in out.splitlines():
            if (self.configuration.safe_get('iscsi_ip_address') in target
                    and volume_id in target):
                return target
        return None
Esempio n. 22
0
    def _execute(*args, **kwargs):
        """Locked execution to prevent racing issues.

        Racing issues are derived from a bug in RTSLib:
            https://github.com/agrover/rtslib-fb/issues/36
        """
        return utils.execute(*args, **kwargs)
Esempio n. 23
0
    def _execute(*args, **kwargs):
        """Locked execution to prevent racing issues.

        Racing issues are derived from a bug in RTSLib:
            https://github.com/agrover/rtslib-fb/issues/36
        """
        return utils.execute(*args, **kwargs)
Esempio n. 24
0
 def _do_tgt_update(self, name):
     (out, err) = utils.execute('tgt-admin',
                                '--update',
                                name,
                                run_as_root=True)
     LOG.debug("StdOut from tgt-admin --update: %s", out)
     LOG.debug("StdErr from tgt-admin --update: %s", err)
Esempio n. 25
0
def get_qemu_img_version():
    info = utils.execute('qemu-img', '--help', check_exit_code=False)[0]
    pattern = r"qemu-img version ([0-9\.]*)"
    version = re.match(pattern, info)
    if not version:
        LOG.warning(_LW("qemu-img is not installed."))
        return None
    return _get_version_from_string(version.groups()[0])
Esempio n. 26
0
    def _new_logicalunit(self, tid, lun, path):
        """Attach a new volume to scsi target as a logical unit.

        If a logical unit exists on the specified target lun,
        ietadm returns 'File exists' and error code '239'.
        This should be ignored for ensure export case.
        """

        utils.execute('ietadm',
                      '--op',
                      'new',
                      '--tid=%s' % tid,
                      '--lun=%d' % lun,
                      '--params',
                      'Path=%s,Type=%s' % (path, self._iotype(path)),
                      run_as_root=True,
                      check_exit_code=[0, 239])
Esempio n. 27
0
def clear_volume(volume_size, volume_path, volume_clear=None,
                 volume_clear_size=None, volume_clear_ionice=None,
                 throttle=None):
    """Unprovision old volumes to prevent data leaking between users."""
    if volume_clear is None:
        volume_clear = CONF.volume_clear

    if volume_clear_size is None:
        volume_clear_size = CONF.volume_clear_size

    if volume_clear_size == 0:
        volume_clear_size = volume_size

    if volume_clear_ionice is None:
        volume_clear_ionice = CONF.volume_clear_ionice

    LOG.info(_LI("Performing secure delete on volume: %s"), volume_path)

    # We pass sparse=False explicitly here so that zero blocks are not
    # skipped in order to clear the volume.
    if volume_clear == 'zero':
        return copy_volume('/dev/zero', volume_path, volume_clear_size,
                           CONF.volume_dd_blocksize,
                           sync=True, execute=utils.execute,
                           ionice=volume_clear_ionice,
                           throttle=throttle, sparse=False)
    elif volume_clear == 'shred':
        clear_cmd = ['shred', '-n3']
        if volume_clear_size:
            clear_cmd.append('-s%dMiB' % volume_clear_size)
    else:
        raise exception.InvalidConfigurationValue(
            option='volume_clear',
            value=volume_clear)

    clear_cmd.append(volume_path)
    start_time = timeutils.utcnow()
    utils.execute(*clear_cmd, run_as_root=True)
    duration = timeutils.delta_seconds(start_time, timeutils.utcnow())

    # NOTE(jdg): use a default of 1, mostly for unit test, but in
    # some incredible event this is 0 (cirros image?) don't barf
    if duration < 1:
        duration = 1
    LOG.info(_LI('Elapsed time for clear volume: %.2f sec'), duration)
Esempio n. 28
0
def check_for_odirect_support(src, dest, flag='oflag=direct'):

    # Check whether O_DIRECT is supported
    try:
        # iflag=direct and if=/dev/zero combination does not work
        # error: dd: failed to open '/dev/zero': Invalid argument
        if (src == '/dev/zero' and flag == 'iflag=direct'):
            return False
        else:
            utils.execute('dd',
                          'count=0',
                          'if=%s' % src,
                          'of=%s' % dest,
                          flag,
                          run_as_root=True)
            return True
    except processutils.ProcessExecutionError:
        return False
Esempio n. 29
0
    def delete(self, backup):
        """Delete the given backup from TSM server.

        :param backup: backup information for volume
        :raises: InvalidBackup
        """

        delete_attrs = {'Total number of objects deleted': '1'}
        delete_path, backup_mode = _get_backup_metadata(backup, 'restore')

        LOG.debug('Delete started for backup: %(backup)s, mode: %(mode)s.',
                  {'backup': backup.id,
                   'mode': backup_mode})

        try:
            out, err = utils.execute('dsmc',
                                     'delete',
                                     'backup',
                                     '-quiet',
                                     '-noprompt',
                                     '-objtype=%s' % backup_mode,
                                     '-password=%s' % self.tsm_password,
                                     delete_path,
                                     run_as_root=True,
                                     check_exit_code=False)

        except processutils.ProcessExecutionError as exc:
            err = (_('delete: %(vol_id)s failed to run dsmc with '
                     'stdout: %(out)s\n stderr: %(err)s')
                   % {'vol_id': backup.volume_id,
                      'out': exc.stdout,
                      'err': exc.stderr})
            LOG.error(err)
            raise exception.InvalidBackup(reason=err)
        except exception.Error as exc:
            err = (_('delete: %(vol_id)s failed to run dsmc '
                     'due to invalid arguments with '
                     'stdout: %(out)s\n stderr: %(err)s')
                   % {'vol_id': backup.volume_id,
                      'out': exc.stdout,
                      'err': exc.stderr})
            LOG.error(err)
            raise exception.InvalidBackup(reason=err)

        success = _check_dsmc_output(out, delete_attrs)
        if not success:
            # log error if tsm cannot delete the backup object
            # but do not raise exception so that storage backup
            # object can be removed.
            LOG.error(_LE('delete: %(vol_id)s failed with '
                          'stdout: %(out)s\n stderr: %(err)s'),
                      {'vol_id': backup.volume_id,
                       'out': out,
                       'err': err})

        LOG.debug('Delete %s finished.', backup['id'])
Esempio n. 30
0
    def _get_target(self, iqn):
        (out, err) = utils.execute('tgt-admin', '--show', run_as_root=True)
        lines = out.split('\n')
        for line in lines:
            if iqn in line:
                parsed = line.split()
                tid = parsed[1]
                return tid[:-1]

        return None
Esempio n. 31
0
    def _get_target(self, iqn):
        (out, err) = utils.execute('tgt-admin', '--show', run_as_root=True)
        lines = out.split('\n')
        for line in lines:
            if iqn in line:
                parsed = line.split()
                tid = parsed[1]
                return tid[:-1]

        return None
Esempio n. 32
0
def _cleanup_device_hardlink(hardlink_path, volume_path, volume_id):
    """Remove the hardlink for the volume block device.

    :param hardlink_path: hardlink to the volume block device
    :param volume_path: real path of the backup/restore device
    :param volume_id: Volume id for backup or as restore target
    """

    try:
        utils.execute('rm', '-f', hardlink_path, run_as_root=True)
    except processutils.ProcessExecutionError as exc:
        LOG.error(
            _LE('backup: %(vol_id)s failed to remove backup hardlink '
                'from %(vpath)s to %(bpath)s.\n'
                'stdout: %(out)s\n stderr: %(err)s.'), {
                    'vol_id': volume_id,
                    'vpath': volume_path,
                    'bpath': hardlink_path,
                    'out': exc.stdout,
                    'err': exc.stderr
                })
Esempio n. 33
0
    def update_config_file(self, name, tid, path, config_auth):

        conf_file = self.iet_conf
        vol_id = name.split(':')[1]

        # If config file does not exist, create a blank conf file and
        # add configuration for the volume on the new file.
        if not os.path.exists(conf_file):
            try:
                utils.execute("truncate",
                              conf_file,
                              "--size=0",
                              run_as_root=True)
            except putils.ProcessExecutionError:
                LOG.exception(
                    _LE("Failed to create %(conf)s for volume "
                        "id:%(vol_id)s"), {
                            'conf': conf_file,
                            'vol_id': vol_id
                        })
                raise exception.ISCSITargetCreateFailed(volume_id=vol_id)

        try:
            volume_conf = """
                    Target %s
                        %s
                        Lun 0 Path=%s,Type=%s
            """ % (name, config_auth, path, self._iotype(path))

            with utils.temporary_chown(conf_file):
                with open(conf_file, 'a+') as f:
                    f.write(volume_conf)
        except Exception:
            LOG.exception(
                _LE("Failed to update %(conf)s for volume "
                    "id:%(vol_id)s"), {
                        'conf': conf_file,
                        'vol_id': vol_id
                    })
            raise exception.ISCSITargetCreateFailed(volume_id=vol_id)
Esempio n. 34
0
def _cleanup_device_hardlink(hardlink_path, volume_path, volume_id):
    """Remove the hardlink for the volume block device.

    :param hardlink_path: hardlink to the volume block device
    :param volume_path: real path of the backup/restore device
    :param volume_id: Volume id for backup or as restore target
    """

    try:
        utils.execute('rm',
                      '-f',
                      hardlink_path,
                      run_as_root=True)
    except processutils.ProcessExecutionError as exc:
        LOG.error(_LE('backup: %(vol_id)s failed to remove backup hardlink '
                      'from %(vpath)s to %(bpath)s.\n'
                      'stdout: %(out)s\n stderr: %(err)s.'),
                  {'vol_id': volume_id,
                   'vpath': volume_path,
                   'bpath': hardlink_path,
                   'out': exc.stdout,
                   'err': exc.stderr})
Esempio n. 35
0
    def _get_target(self, iqn):
        # We can use target=iqn here, but iscsictl has no --brief mode, and
        # this way we save on a lot of unnecessary parsing
        (out, err) = utils.execute('iscsictl',
                                   '-c',
                                   'target=ALL',
                                   run_as_root=True)
        lines = out.split('\n')
        for line in lines:
            if iqn in line:
                parsed = line.split()
                tid = parsed[2]
                return tid[3:].rstrip(',')

        return None
Esempio n. 36
0
    def _verify_backing_lun(self, iqn, tid):
        backing_lun = True
        capture = False
        target_info = []

        (out, err) = utils.execute('tgt-admin', '--show', run_as_root=True)
        lines = out.split('\n')

        for line in lines:
            if iqn in line and "Target %s" % tid in line:
                capture = True
            if capture:
                target_info.append(line)
            if iqn not in line and 'Target ' in line:
                capture = False

        if '        LUN: 1' not in target_info:
            backing_lun = False

        return backing_lun
Esempio n. 37
0
    def _verify_backing_lun(self, iqn, tid):
        backing_lun = True
        capture = False
        target_info = []

        (out, err) = utils.execute('tgt-admin', '--show', run_as_root=True)
        lines = out.split('\n')

        for line in lines:
            if iqn in line and "Target %s" % tid in line:
                capture = True
            if capture:
                target_info.append(line)
            if iqn not in line and 'Target ' in line:
                capture = False

        if '        LUN: 1' not in target_info:
            backing_lun = False

        return backing_lun
Esempio n. 38
0
    def _do_restore(self, backup_path, restore_path, vol_id, backup_mode):
        """Perform the actual restore operation.

        :param backup_path: the path the backup was created from, this
        identifies the backup to tsm
        :param restore_path: volume path to restore into
        :param vol_id: volume id
        :param backup_mode: mode used to create the backup ('image' or 'file')
        :raises: InvalidBackup
        """

        restore_attrs = {'Total number of objects restored': '1'}
        restore_cmd = ['dsmc', 'restore']
        if _image_mode(backup_mode):
            restore_cmd.append('image')
            restore_cmd.append('-noprompt')  # suppress prompt
        else:
            restore_cmd.append('-replace=yes')  # suppress prompt

        restore_cmd.extend(
            ['-quiet',
             '-password=%s' % self.tsm_password, backup_path])

        if restore_path != backup_path:
            restore_cmd.append(restore_path)

        out, err = utils.execute(*restore_cmd,
                                 run_as_root=True,
                                 check_exit_code=False)

        success = _check_dsmc_output(out, restore_attrs)
        if not success:
            err = (_('restore: %(vol_id)s failed.\n'
                     'stdout: %(out)s\n stderr: %(err)s.') % {
                         'vol_id': vol_id,
                         'out': out,
                         'err': err
                     })
            LOG.error(err)
            raise exception.InvalidBackup(reason=err)
Esempio n. 39
0
    def _do_restore(self, backup_path, restore_path, vol_id, backup_mode):
        """Perform the actual restore operation.

        :param backup_path: the path the backup was created from, this
        identifies the backup to tsm
        :param restore_path: volume path to restore into
        :param vol_id: volume id
        :param backup_mode: mode used to create the backup ('image' or 'file')
        :raises: InvalidBackup
        """

        restore_attrs = {'Total number of objects restored': '1'}
        restore_cmd = ['dsmc', 'restore']
        if _image_mode(backup_mode):
            restore_cmd.append('image')
            restore_cmd.append('-noprompt')  # suppress prompt
        else:
            restore_cmd.append('-replace=yes')  # suppress prompt

        restore_cmd.extend(['-quiet',
                            '-password=%s' % self.tsm_password,
                            backup_path])

        if restore_path != backup_path:
            restore_cmd.append(restore_path)

        out, err = utils.execute(*restore_cmd,
                                 run_as_root=True,
                                 check_exit_code=False)

        success = _check_dsmc_output(out, restore_attrs)
        if not success:
            err = (_('restore: %(vol_id)s failed.\n'
                     'stdout: %(out)s\n stderr: %(err)s.')
                   % {'vol_id': vol_id,
                      'out': out,
                      'err': err})
            LOG.error(err)
            raise exception.InvalidBackup(reason=err)
Esempio n. 40
0
    def _recreate_backing_lun(self, iqn, tid, name, path):
        LOG.warning(_LW('Attempting recreate of backing lun...'))

        # Since we think the most common case of this is a dev busy
        # (create vol from snapshot) we're going to add a sleep here
        # this will hopefully give things enough time to stabilize
        # how long should we wait??  I have no idea, let's go big
        # and error on the side of caution
        time.sleep(10)

        (out, err) = (None, None)
        try:
            (out, err) = utils.execute('tgtadm',
                                       '--lld',
                                       'iscsi',
                                       '--op',
                                       'new',
                                       '--mode',
                                       'logicalunit',
                                       '--tid',
                                       tid,
                                       '--lun',
                                       '1',
                                       '-b',
                                       path,
                                       run_as_root=True)
        except putils.ProcessExecutionError as e:
            LOG.error(
                _LE("Failed recovery attempt to create "
                    "iscsi backing lun for Volume "
                    "ID:%(vol_id)s: %(e)s"), {
                        'vol_id': name,
                        'e': e
                    })
        finally:
            LOG.debug('StdOut from recreate backing lun: %s', out)
            LOG.debug('StdErr from recreate backing lun: %s', err)
Esempio n. 41
0
    def _do_backup(self, backup_path, vol_id, backup_mode):
        """Perform the actual backup operation.

       :param backup_path: volume path
       :param vol_id: volume id
       :param backup_mode: file mode of source volume; 'image' or 'file'
       :raises: InvalidBackup
        """

        backup_attrs = {'Total number of objects backed up': '1'}
        compr_flag = 'yes' if CONF.backup_tsm_compression else 'no'

        backup_cmd = ['dsmc', 'backup']
        if _image_mode(backup_mode):
            backup_cmd.append('image')
        backup_cmd.extend([
            '-quiet',
            '-compression=%s' % compr_flag,
            '-password=%s' % self.tsm_password, backup_path
        ])

        out, err = utils.execute(*backup_cmd,
                                 run_as_root=True,
                                 check_exit_code=False)

        success = _check_dsmc_output(out, backup_attrs, exact_match=False)
        if not success:
            err = (_('backup: %(vol_id)s failed to obtain backup '
                     'success notification from server.\n'
                     'stdout: %(out)s\n stderr: %(err)s') % {
                         'vol_id': vol_id,
                         'out': out,
                         'err': err
                     })
            LOG.error(err)
            raise exception.InvalidBackup(reason=err)
Esempio n. 42
0
    def create_iscsi_target(self, name, tid, lun, path,
                            chap_auth=None, **kwargs):

        (out, err) = utils.execute('iscsictl',
                                   '-c',
                                   'target=ALL',
                                   run_as_root=True)
        LOG.debug("Targets prior to update: %s", out)
        volumes_dir = self._get_volumes_dir()
        fileutils.ensure_tree(volumes_dir)

        vol_id = name.split(':')[1]

        cfg_port = kwargs.get('portals_port')
        cfg_ips = kwargs.get('portals_ips')

        portals = ','.join(map(lambda ip: self._get_portal(ip, cfg_port),
                               cfg_ips))

        if chap_auth is None:
            volume_conf = self.TARGET_FMT % (name, path, portals)
        else:
            volume_conf = self.TARGET_FMT_WITH_CHAP % (name,
                                                       path, portals,
                                                       '"%s":"%s"' % chap_auth)
        LOG.debug('Creating iscsi_target for: %s', vol_id)
        volume_path = os.path.join(volumes_dir, vol_id)

        if os.path.exists(volume_path):
            LOG.warning(_LW('Persistence file already exists for volume, '
                            'found file at: %s'), volume_path)
        utils.robust_file_write(volumes_dir, vol_id, volume_conf)
        LOG.debug('Created volume path %(vp)s,\n'
                  'content: %(vc)s',
                  {'vp': volume_path, 'vc': volume_conf})

        old_persist_file = None
        old_name = kwargs.get('old_name', None)
        if old_name:
            LOG.debug('Detected old persistence file for volume '
                      '%{vol}s at %{old_name}s',
                      {'vol': vol_id, 'old_name': old_name})
            old_persist_file = os.path.join(volumes_dir, old_name)

        try:
            # With the persistent tgts we create them
            # by creating the entry in the persist file
            # and then doing an update to get the target
            # created.
            (out, err) = utils.execute('iscsictl', '-S', 'target=%s' % name,
                                       '-f', volume_path,
                                       '-x', self.config,
                                       run_as_root=True)
        except putils.ProcessExecutionError as e:
            LOG.error(_LE("Failed to create iscsi target for volume "
                          "id:%(vol_id)s: %(e)s"),
                      {'vol_id': vol_id, 'e': e})

            # Don't forget to remove the persistent file we created
            os.unlink(volume_path)
            raise exception.ISCSITargetCreateFailed(volume_id=vol_id)
        finally:
            LOG.debug("StdOut from iscsictl -S: %s", out)
            LOG.debug("StdErr from iscsictl -S: %s", err)

        # Grab targets list for debug
        (out, err) = utils.execute('iscsictl',
                                   '-c',
                                   'target=ALL',
                                   run_as_root=True)
        LOG.debug("Targets after update: %s", out)

        iqn = '%s%s' % (self.iscsi_target_prefix, vol_id)
        tid = self._get_target(iqn)
        if tid is None:
            LOG.error(_LE("Failed to create iscsi target for volume "
                          "id:%(vol_id)s. Please verify your configuration "
                          "in %(volumes_dir)s'"), {
                      'vol_id': vol_id,
                      'volumes_dir': volumes_dir, })
            raise exception.NotFound()

        if old_persist_file is not None and os.path.exists(old_persist_file):
            os.unlink(old_persist_file)

        return tid
Esempio n. 43
0
def coalesce_vhd(vhd_path):
    utils.execute('vhd-util', 'coalesce', '-n', vhd_path)
Esempio n. 44
0
def get_vhd_size(vhd_path):
    out, _err = utils.execute('vhd-util', 'query', '-n', vhd_path, '-v')
    return int(out)
Esempio n. 45
0
def resize_vhd(vhd_path, size, journal):
    utils.execute('vhd-util', 'resize', '-n', vhd_path, '-s', '%d' % size,
                  '-j', journal)
Esempio n. 46
0
def set_vhd_parent(vhd_path, parentpath):
    utils.execute('vhd-util', 'modify', '-n', vhd_path, '-p', parentpath)
Esempio n. 47
0
def extract_targz(archive_name, target):
    utils.execute('tar', '-xzf', archive_name, '-C', target)
Esempio n. 48
0
    def remove_iscsi_target(self, tid, lun, vol_id, vol_name, **kwargs):
        LOG.info(_LI('Removing iscsi_target for Volume ID: %s'), vol_id)
        vol_uuid_file = vol_name
        volume_path = os.path.join(self.volumes_dir, vol_uuid_file)
        if not os.path.exists(volume_path):
            LOG.warning(_LW('Volume path %s does not exist, '
                            'nothing to remove.'), volume_path)
            return

        if os.path.isfile(volume_path):
            iqn = '%s%s' % (self.iscsi_target_prefix,
                            vol_uuid_file)
        else:
            raise exception.ISCSITargetRemoveFailed(volume_id=vol_id)
        try:
            # NOTE(vish): --force is a workaround for bug:
            #             https://bugs.launchpad.net/storage/+bug/1159948
            utils.execute('tgt-admin',
                          '--force',
                          '--delete',
                          iqn,
                          run_as_root=True)
        except putils.ProcessExecutionError as e:
            non_fatal_errors = ("can't find the target",
                                "access control rule does not exist")

            if any(error in e.stderr for error in non_fatal_errors):
                LOG.warning(_LW("Failed target removal because target or "
                                "ACL's couldn't be found for iqn: %s."), iqn)
            else:
                LOG.error(_LE("Failed to remove iscsi target for Volume "
                              "ID: %(vol_id)s: %(e)s"),
                          {'vol_id': vol_id, 'e': e})
                raise exception.ISCSITargetRemoveFailed(volume_id=vol_id)
        # NOTE(jdg): There's a bug in some versions of tgt that
        # will sometimes fail silently when using the force flag
        #    https://bugs.launchpad.net/ubuntu/+source/tgt/+bug/1305343
        # For now work-around by checking if the target was deleted,
        # if it wasn't, try again without the force.

        # This will NOT do any good for the case of mutliple sessions
        # which the force was aded for but it will however address
        # the cases pointed out in bug:
        #    https://bugs.launchpad.net/storage/+bug/1304122
        if self._get_target(iqn):
            try:
                LOG.warning(_LW('Silent failure of target removal '
                                'detected, retry....'))
                utils.execute('tgt-admin',
                              '--delete',
                              iqn,
                              run_as_root=True)
            except putils.ProcessExecutionError as e:
                LOG.error(_LE("Failed to remove iscsi target for Volume "
                              "ID: %(vol_id)s: %(e)s"),
                          {'vol_id': vol_id, 'e': e})
                raise exception.ISCSITargetRemoveFailed(volume_id=vol_id)

        # NOTE(jdg): This *should* be there still but incase
        # it's not we don't care, so just ignore it if was
        # somehow deleted between entry of this method
        # and here
        if os.path.exists(volume_path):
            os.unlink(volume_path)
        else:
            LOG.debug('Volume path %s not found at end, '
                      'of remove_iscsi_target.', volume_path)
Esempio n. 49
0
    def remove_iscsi_target(self, tid, lun, vol_id, vol_name, **kwargs):
        LOG.info(_LI('Removing iscsi_target for: %s'), vol_id)
        vol_uuid_file = vol_name
        volume_path = os.path.join(self._get_volumes_dir(), vol_uuid_file)
        if not os.path.exists(volume_path):
            LOG.warning(_LW('Volume path %s does not exist, '
                            'nothing to remove.'), volume_path)
            return

        if os.path.isfile(volume_path):
            iqn = '%s%s' % (self.iscsi_target_prefix,
                            vol_uuid_file)
        else:
            raise exception.ISCSITargetRemoveFailed(volume_id=vol_id)

        target_exists = False
        try:
            (out, err) = utils.execute('iscsictl',
                                       '-c',
                                       'target=%s' % iqn,
                                       run_as_root=True)
            LOG.debug("StdOut from iscsictl -c: %s", out)
            LOG.debug("StdErr from iscsictl -c: %s", err)
        except putils.ProcessExecutionError as e:
            if "NOT found" in e.stdout:
                LOG.info(_LI("No iscsi target present for volume "
                             "id:%(vol_id)s: %(e)s"),
                         {'vol_id': vol_id, 'e': e})
                return
            else:
                raise exception.ISCSITargetRemoveFailed(volume_id=vol_id)
        else:
            target_exists = True

        try:
            utils.execute('iscsictl',
                          '-s',
                          'target=%s' % iqn,
                          run_as_root=True)
        except putils.ProcessExecutionError as e:
            # There exists a race condition where multiple calls to
            # remove_iscsi_target come in simultaneously. If we can poll
            # for a target successfully but it is gone before we can remove
            # it, fail silently
            if "is not found" in e.stderr and target_exists:
                LOG.info(_LI("No iscsi target present for volume "
                             "id:%(vol_id)s: %(e)s"),
                         {'vol_id': vol_id, 'e': e})
                return
            else:
                LOG.error(_LE("Failed to remove iscsi target for volume "
                              "id:%(vol_id)s: %(e)s"),
                          {'vol_id': vol_id, 'e': e})
                raise exception.ISCSITargetRemoveFailed(volume_id=vol_id)

        # Carried over from tgt
        # NOTE(jdg): This *should* be there still but incase
        # it's not we don't care, so just ignore it if was
        # somehow deleted between entry of this method
        # and here
        if os.path.exists(volume_path):
            os.unlink(volume_path)
        else:
            LOG.debug('Volume path %s not found at end, '
                      'of remove_iscsi_target.', volume_path)
Esempio n. 50
0
 def _delete_target(self, tid):
     utils.execute('ietadm', '--op', 'delete',
                   '--tid=%s' % tid,
                   run_as_root=True)
Esempio n. 51
0
    def create_iscsi_target(self, name, tid, lun, path,
                            chap_auth=None, **kwargs):

        # Note(jdg) tid and lun aren't used by TgtAdm but remain for
        # compatibility

        # NOTE(jdg): Remove this when we get to the bottom of bug: #1398078
        # for now, since we intermittently hit target already exists we're
        # adding some debug info to try and pinpoint what's going on
        (out, err) = utils.execute('tgtadm',
                                   '--lld',
                                   'iscsi',
                                   '--op',
                                   'show',
                                   '--mode',
                                   'target',
                                   run_as_root=True)
        LOG.debug("Targets prior to update: %s", out)
        fileutils.ensure_tree(self.volumes_dir)

        vol_id = name.split(':')[1]
        write_cache = self.configuration.get('iscsi_write_cache', 'on')
        driver = self.iscsi_protocol
        chap_str = ''

        if chap_auth is not None:
            chap_str = 'incominguser %s %s' % chap_auth

        target_flags = self.configuration.get('iscsi_target_flags', '')
        if target_flags:
            target_flags = 'bsoflags ' + target_flags

        volume_conf = self.VOLUME_CONF % {
            'name': name, 'path': path, 'driver': driver,
            'chap_auth': chap_str, 'target_flags': target_flags,
            'write_cache': write_cache}

        LOG.debug('Creating iscsi_target for Volume ID: %s', vol_id)
        volumes_dir = self.volumes_dir
        volume_path = os.path.join(volumes_dir, vol_id)

        if os.path.exists(volume_path):
            LOG.warning(_LW('Persistence file already exists for volume, '
                            'found file at: %s'), volume_path)
        utils.robust_file_write(volumes_dir, vol_id, volume_conf)
        LOG.debug(('Created volume path %(vp)s,\n'
                   'content: %(vc)s'),
                  {'vp': volume_path, 'vc': volume_conf})

        old_persist_file = None
        old_name = kwargs.get('old_name', None)
        if old_name is not None:
            LOG.debug('Detected old persistence file for volume '
                      '%{vol}s at %{old_name}s',
                      {'vol': vol_id, 'old_name': old_name})
            old_persist_file = os.path.join(volumes_dir, old_name)

        try:
            # With the persistent tgts we create them
            # by creating the entry in the persist file
            # and then doing an update to get the target
            # created.

            self._do_tgt_update(name)
        except putils.ProcessExecutionError as e:
            if "target already exists" in e.stderr:
                # Adding the additional Warning message below for a clear
                # ER marker (Ref bug: #1398078).
                LOG.warning(_LW('Could not create target because '
                                'it already exists for volume: %s'), vol_id)
                LOG.debug('Exception was: %s', e)

            else:
                LOG.error(_LE("Failed to create iscsi target for Volume "
                              "ID: %(vol_id)s: %(e)s"),
                          {'vol_id': vol_id, 'e': e})

            # Don't forget to remove the persistent file we created
            os.unlink(volume_path)
            raise exception.ISCSITargetCreateFailed(volume_id=vol_id)

        # Grab targets list for debug
        # Consider adding a check for lun 0 and 1 for tgtadm
        # before considering this as valid
        (out, err) = utils.execute('tgtadm',
                                   '--lld',
                                   'iscsi',
                                   '--op',
                                   'show',
                                   '--mode',
                                   'target',
                                   run_as_root=True)
        LOG.debug("Targets after update: %s", out)

        iqn = '%s%s' % (self.iscsi_target_prefix, vol_id)
        tid = self._get_target(iqn)
        if tid is None:
            LOG.error(_LE("Failed to create iscsi target for Volume "
                          "ID: %(vol_id)s. Please ensure your tgtd config "
                          "file contains 'include %(volumes_dir)s/*'"), {
                      'vol_id': vol_id,
                      'volumes_dir': volumes_dir, })
            raise exception.NotFound()

        # NOTE(jdg): Sometimes we have some issues with the backing lun
        # not being created, believe this is due to a device busy
        # or something related, so we're going to add some code
        # here that verifies the backing lun (lun 1) was created
        # and we'll try and recreate it if it's not there
        if not self._verify_backing_lun(iqn, tid):
            try:
                self._recreate_backing_lun(iqn, tid, name, path)
            except putils.ProcessExecutionError:
                os.unlink(volume_path)
                raise exception.ISCSITargetCreateFailed(volume_id=vol_id)

            # Finally check once more and if no go, fail and punt
            if not self._verify_backing_lun(iqn, tid):
                os.unlink(volume_path)
                raise exception.ISCSITargetCreateFailed(volume_id=vol_id)

        if old_persist_file is not None and os.path.exists(old_persist_file):
            os.unlink(old_persist_file)

        return tid
Esempio n. 52
0
 def _force_delete_target(self, tid, sid, cid):
     utils.execute('ietadm', '--op', 'delete',
                   '--tid=%s' % tid,
                   '--sid=%s' % sid,
                   '--cid=%s' % cid,
                   run_as_root=True)
Esempio n. 53
0
 def scst_execute(self, *args):
     return utils.execute('scstadmin', *args, run_as_root=True)
Esempio n. 54
0
 def _do_tgt_update(self, name):
     (out, err) = utils.execute('tgt-admin', '--update', name,
                                run_as_root=True)
     LOG.debug("StdOut from tgt-admin --update: %s", out)
     LOG.debug("StdErr from tgt-admin --update: %s", err)
Esempio n. 55
0
 def show_target(self, tid, iqn=None):
     utils.execute('ietadm', '--op', 'show',
                   '--tid=%s' % tid,
                   run_as_root=True)
Esempio n. 56
0
 def _delete_logicalunit(self, tid, lun):
     utils.execute('ietadm', '--op', 'delete',
                   '--tid=%s' % tid,
                   '--lun=%d' % lun,
                   run_as_root=True)