Esempio n. 1
0
def luks_format_disk(disk_byid, passphrase):
    """
    Formats disk_byid using supplied passphrase for master key encryption.
    Simple run_command wrapper to execute 'cryptsetup luksFormat <dev> path'
    Care is taken to immediately remove our temporary key-file (in ram) even 
    in the event of an Exception.
    :param disk_byid: by-id type name without path as found in db Disks.name.
    :param passphrase: luks passphrase used to encrypt master key.
    :return: o, e, rc tuple as returned by cryptsetup luksFormat command.
    """
    disk_byid_withpath = get_device_path(disk_byid)
    # Create a temp file to pass our passphrase to our cryptsetup command.
    tfo, npath = mkstemp()
    # Pythons _candidate_tempdir_list() should ensure our npath temp file is
    # in memory (tmpfs). From https://docs.python.org/2/library/tempfile.html
    # we have "Creates a temporary file in the most secure manner possible."
    # Populate this file with our passphrase and use as cryptsetup keyfile.
    try:
        with open(npath, 'w') as passphrase_file_object:
            passphrase_file_object.write(passphrase)
        cmd = [CRYPTSETUP, 'luksFormat', disk_byid_withpath, npath]
        out, err, rc = run_command(cmd)
    except Exception as e:
        msg = ('Exception while running command(%s): %s' % (cmd, e.__str__()))
        raise Exception(msg)
    finally:
        passphrase_file_object.close()
        if os.path.exists(npath):
            try:
                os.remove(npath)
            except Exception as e:
                msg = ('Exception while removing temp file %s: %s' %
                       (npath, e.__str__()))
                raise Exception(msg)
    return out, err, rc
Esempio n. 2
0
def mount_share(share, mnt_pt):
    if (is_mounted(mnt_pt)):
        return
    mount_root(share.pool)
    pool_device = get_device_path(share.pool.disk_set.attached()
                                       .first().target_name)
    subvol_str = 'subvol=%s' % share.subvol_name
    create_tmp_dir(mnt_pt)
    toggle_path_rw(mnt_pt, rw=False)
    mnt_cmd = [MOUNT, '-t', 'btrfs', '-o', subvol_str, pool_device, mnt_pt]
    return run_command(mnt_cmd)
Esempio n. 3
0
def mount_snap(share, snap_name, snap_mnt=None):
    pool_device = get_device_path(share.pool.disk_set.attached()
                                       .first().target_name)
    share_path = ('%s%s' % (DEFAULT_MNT_DIR, share.name))
    rel_snap_path = ('.snapshots/%s/%s' % (share.name, snap_name))
    snap_path = ('%s%s/%s' %
                 (DEFAULT_MNT_DIR, share.pool.name, rel_snap_path))
    if (snap_mnt is None):
        snap_mnt = ('%s/.%s' % (share_path, snap_name))
    if (is_mounted(snap_mnt)):
        return
    mount_share(share, share_path)
    if (is_subvol(snap_path)):
        create_tmp_dir(snap_mnt)
        return run_command([MOUNT, '-o', 'subvol=%s' % rel_snap_path,
                            pool_device, snap_mnt])
Esempio n. 4
0
 def _refresh_pool_state():
     for p in Pool.objects.all():
         # If our pool has no disks, detached included, then delete it.
         # We leave pools with all detached members in place intentionally.
         if (p.disk_set.count() == 0):
             p.delete()
             continue
         # Log if no attached members are found, ie all devs are detached.
         if p.disk_set.attached().count() == 0:
             logger.error('Skipping Pool (%s) mount as there '
                          'are no attached devices. Moving on.' %
                          p.name)
             continue
         try:
             # Get and save what info we can prior to mount.
             first_attached_dev = p.disk_set.attached().first()
             is_root_pool = (p.role == 'root')
             # Observe any redirect role by using target_name.
             byid_disk_name, is_byid = get_dev_byid_name(
                 get_device_path(first_attached_dev.target_name))
             if is_byid:
                 pool_info = get_pool_info(first_attached_dev.target_name,
                                           is_root_pool)
                 pool_name = pool_info['label']
             else:
                 logger.error('Skipping pool ({}) mount as attached disk '
                              '({}) has no by-id name (no serial # ?)'.
                              format(p.name,
                                     first_attached_dev.target_name))
                 continue
             p.name = pool_name
             p.save()
             mount_root(p)
             p.raid = pool_raid('%s%s' % (settings.MNT_PT, p.name))['data']
             p.size = p.usage_bound()
             # Consider using mount_status() parse to update root pool db on
             # active (fstab initiated) compression setting.
             p.save()
         except Exception as e:
             logger.error('Exception while refreshing state for '
                          'Pool(%s). Moving on: %s' %
                          (p.name, e.__str__()))
             logger.exception(e)
Esempio n. 5
0
def get_pool_info(disk):
    """
    Extracts any pool information by running btrfs fi show <disk> and collates
    the results by 'Label', 'uuid', and a list of disk names. The disks names
    found are translated to the by-id type (/dev/disk/by-id)so that their
    counterparts in the db's Disk.name field can be found.
    N.B. devices without serial may have no by-id counterpart.
    Used by CommandView()._refresh_pool_state() and
    DiskDetailView()._btrfs_disk_import
    :param disk: by-id disk name without path
    :return: a dictionary with keys of 'disks', 'label', and 'uuid';
    disks keys a list of devices, while label and uuid keys are for strings.
    """
    dpath = get_device_path(disk)
    cmd = [BTRFS, 'fi', 'show', dpath]
    o, e, rc = run_command(cmd)
    pool_info = {
        'disks': [],
    }
    for l in o:
        if (re.match('Label', l) is not None):
            fields = l.split()
            pool_info['uuid'] = fields[3]
            label = fields[1].strip("'")
            if label == 'none':
                # fs has no label, set label = uuid.
                label = pool_info['uuid']
                run_command([BTRFS, 'fi', 'label', dpath, label])
            pool_info['label'] = label
        elif (re.match('\tdevid', l) is not None):
            # We have a line starting wth <tab>devid, extract the dev name.
            # Previously this would have been sda and used as is but we need
            # it's by-id references as that is the new format for Disks.name.
            # Original sda extraction:
            # pool_info['disks'].append(l.split()[-1].split('/')[-1])
            # Updated '/dev/sda' extraction to save on a split we no longer
            # need and use this 'now' name to get our by-id name with path
            # removed. This is required as that is how device names are stored
            # in the db Disk.name so that we can locate a drive and update it's
            # pool field reference.
            dev_byid, is_byid = get_dev_byid_name(l.split()[-1], True)
            pool_info['disks'].append(dev_byid)
    return pool_info
Esempio n. 6
0
def resize_pool(pool, dev_list_byid, add=True):
    """
    Acts on a given pool and list of device names by generating and then
    executing the appropriate:-
    "btrfs <device list> add(default)/delete root_mnt_pt(pool)"
    command, or returning None if a disk member sanity check fails ie if
    all the supplied devices are either not already a member of the pool
    (when adding) or are already members of the pool (when deleting).
    If any device in the supplied dev_list fails this test then no command is
    executed and None is returned.
    :param pool: btrfs pool name
    :param dev_list_byid: list of devices to add/delete in by-id (without
        path).
    :param add: when true (default) or not specified then attempt to add
        dev_list devices to pool, or when specified as True attempt to delete
        dev_list devices from pool.
    :return: Tuple of results from run_command(generated command) or None if
        the device member/pool sanity check fails.
    """
    dev_list_byid = [get_device_path(d) for d in dev_list_byid]
    root_mnt_pt = mount_root(pool)
    cur_dev = cur_devices(root_mnt_pt)
    resize_flag = 'add'
    if (not add):
        resize_flag = 'delete'
    resize_cmd = [
        BTRFS,
        'device',
        resize_flag,
    ]
    # Until we verify that all devices are or are not already members of the
    # given pools depending on if we are adding (default) or removing
    # (add=False) those devices we set our resize flag to false.
    resize = False
    for d in dev_list_byid:
        if (((resize_flag == 'add' and (d not in cur_dev))
             or (resize_flag == 'delete' and (d in cur_dev)))):
            resize = True  # Basic disk member of pool sanity check passed.
            resize_cmd.append(d)
    if (not resize):
        return None
    resize_cmd.append(root_mnt_pt)
    return run_command(resize_cmd)
Esempio n. 7
0
 def _refresh_pool_state():
     for p in Pool.objects.all():
         # If our pool has no disks, detached included, then delete it.
         # We leave pools with all detached members in place intentionally.
         if (p.disk_set.count() == 0):
             p.delete()
             continue
         # Log if no attached members are found, ie all devs are detached.
         if p.disk_set.attached().count() == 0:
             logger.error('Skipping Pool (%s) mount as there '
                          'are no attached devices. Moving on.' % p.name)
             continue
         try:
             # Get and save what info we can prior to mount.
             first_attached_dev = p.disk_set.attached().first()
             is_root_pool = (p.role == 'root')
             # Observe any redirect role by using target_name.
             byid_disk_name, is_byid = get_dev_byid_name(
                 get_device_path(first_attached_dev.target_name))
             if is_byid:
                 pool_info = get_pool_info(first_attached_dev.target_name,
                                           is_root_pool)
                 pool_name = pool_info['label']
             else:
                 logger.error(
                     'Skipping pool ({}) mount as attached disk '
                     '({}) has no by-id name (no serial # ?)'.format(
                         p.name, first_attached_dev.target_name))
                 continue
             p.name = pool_name
             p.save()
             mount_root(p)
             p.raid = pool_raid('%s%s' % (settings.MNT_PT, p.name))['data']
             p.size = p.usage_bound()
             # Consider using mount_status() parse to update root pool db on
             # active (fstab initiated) compression setting.
             p.save()
         except Exception as e:
             logger.error('Exception while refreshing state for '
                          'Pool(%s). Moving on: %s' % (p.name, e.__str__()))
             logger.exception(e)
Esempio n. 8
0
def rollback_snap(snap_name, sname, subvol_name, pool):
    """
    1. validate destination snapshot and umount the share
    2. remove the share
    3. move the snapshot to share location and mount it.
    """
    mnt_pt = ('%s%s' % (DEFAULT_MNT_DIR, sname))
    snap_fp = ('%s/%s/.snapshots/%s/%s' % (DEFAULT_MNT_DIR, pool.name, sname,
                                           snap_name))
    if (not is_subvol(snap_fp)):
        raise Exception('Snapshot(%s) does not exist. Rollback is not '
                        'possible' % snap_fp)
    mount_root(pool)
    if (is_share_mounted(sname)):
        umount_root(mnt_pt)
    remove_share(pool, subvol_name, '-1/-1')
    shutil.move(snap_fp, '%s/%s/%s' % (DEFAULT_MNT_DIR, pool.name, sname))
    create_tmp_dir(mnt_pt)
    subvol_str = 'subvol=%s' % sname
    dpath = get_device_path(pool.disk_set.attached().first().target_name)
    mnt_cmd = [MOUNT, '-t', 'btrfs', '-o', subvol_str, dpath, mnt_pt]
    run_command(mnt_cmd)
Esempio n. 9
0
def add_pool(pool, disks):
    """
    Makes a btrfs pool (filesystem) of name 'pool' using the by-id disk names
    provided, then enables quotas for this pool.
    :param pool: name of pool to create.
    :param disks: list of by-id disk names without paths to make the pool from.
    :return o, err, rc from last command executed.
    """
    disks_fp = [get_device_path(d) for d in disks]
    draid = mraid = pool.raid
    if pool.raid == 'single':
        mraid = 'dup'
    cmd = [MKFS_BTRFS, '-f', '-d', draid, '-m', mraid, '-L', pool.name]
    cmd.extend(disks_fp)
    # Run the create pool command, any exceptions are logged and raised by
    # run_command as a CommandException.
    out, err, rc = run_command(cmd, log=True)
    # Note that given our cmd (mkfs.btrfs) is executed with the default
    # run_command flag of throw=True then program execution is stopped in the
    # event of rc != 0 so the following clause is redundant but offers an
    # additional level of isolation.
    # Only execute enable_quota on above btrfs command having an rc=0
    if rc == 0:
        # N.B. enable_quota wraps switch_quota() which doesn't enable logging
        # so log what we have on rc != 0.
        out2, err2, rc2 = enable_quota(pool)
        if rc2 != 0:
            e_msg = (
                'non-zero code (%d) returned by enable_quota() while '
                'enabling quota on a newly created pool : pool name = %s, '
                'output: %s, error: %s.' % (rc2, pool.name, out2, err2))
            logger.error(e_msg)
            return out2, err2, rc2
    else:
        logger.error('Unknown state in add_pool() - non-zero code (%d) '
                     'returned by %s with output: %s and error: %s.'
                     % (rc, cmd, out, err))
    return out, err, rc
Esempio n. 10
0
def device_scan(dev_byid_list=['all']):
    """
    When called with no parameters a 'btrfs device scan' is executed, ie a
    system wide scan of all /dev block devices to update their btrfs status.
    Otherwise the list of devices is iterated and a 'btrfs device scan dev'
    is executed for each item in the passed list. Detached device names and
    path names that don't exist are ignored.
    :param dev_byid_list: list of byid device names (without paths) to perform
    a 'btrfs device scan' on. If not supplied then a single element list
    ['all'] is substituted and this flags a system wide scan request.
    :return: (out, err, rc) of the first rc !=0 run or the last rc = 0 run.
    """
    out = err = ['']
    # default to successful return code unless we find otherwise.
    rc = 0
    if len(dev_byid_list) > 0:
        if dev_byid_list[0] == 'all':
            return run_command([BTRFS, 'device', 'scan'])
        for dev_byid in dev_byid_list:
            if re.match('detached-', dev_byid) is not None:
                # Skip detached devices as we know they don't exist.
                # Potential log point for early detached device discovery.
                continue
            dev_byid_withpath = get_device_path(dev_byid)
            if os.path.exists(dev_byid_withpath):  # only scan existing devices
                # using throw=False, to process the rc != 0 logic
                # afterwards. Without throw=False, when rc != 0, exception is
                # raised and the following if statement will never get
                # executed.
                out, err, rc = run_command(
                    [BTRFS, 'device', 'scan', dev_byid_withpath], throw=False)
                if rc != 0:
                    # Return on first non zero return code.
                    # Note that a drive specific device scan on a non btrfs
                    # device returns 'Invalid argument'!! and rc=1.
                    return out, err, rc
    return out, err, rc
Esempio n. 11
0
def luks_format_disk(disk_byid, passphrase):
    """
    Formats disk_byid using supplied passphrase for master key encryption.
    Simple run_command wrapper to execute 'cryptsetup luksFormat <dev> path'
    Care is taken to immediately remove our temporary key-file (in ram) even 
    in the event of an Exception.
    :param disk_byid: by-id type name without path as found in db Disks.name.
    :param passphrase: luks passphrase used to encrypt master key.
    :return: o, e, rc tuple as returned by cryptsetup luksFormat command.
    """
    disk_byid_withpath = get_device_path(disk_byid)
    # Create a temp file to pass our passphrase to our cryptsetup command.
    tfo, npath = mkstemp()
    # Pythons _candidate_tempdir_list() should ensure our npath temp file is
    # in memory (tmpfs). From https://docs.python.org/2/library/tempfile.html
    # we have "Creates a temporary file in the most secure manner possible."
    # Populate this file with our passphrase and use as cryptsetup keyfile.
    try:
        with open(npath, 'w') as passphrase_file_object:
            passphrase_file_object.write(passphrase)
        cmd = [CRYPTSETUP, 'luksFormat', disk_byid_withpath, npath]
        out, err, rc = run_command(cmd)
    except Exception as e:
        msg = ('Exception while running command(%s): %s' %
               (cmd, e.__str__()))
        raise Exception(msg)
    finally:
        passphrase_file_object.close()
        if os.path.exists(npath):
            try:
                os.remove(npath)
            except Exception as e:
                msg = ('Exception while removing temp file %s: %s' %
                       (npath, e.__str__()))
                raise Exception(msg)
    return out, err, rc
Esempio n. 12
0
def establish_keyfile(dev_byid, keyfile_withpath, passphrase):
    """
    Ensures that the given keyfile_withpath exists and calls create_keyfile()
    if it doesn't. Then attempts to register the established keyfile with the
    dev_byid device via "cryptsetup luksAddKey dev keyfile passphrase". But
    only if the passphrase is found to not equal '', flag for skip luksAddKey.
    N.B. The passphrase is passed to the command via a secure temporary file.
    Care is taken to remove this file irrespective of outcome.
    An existing keyfile will not be altered or deleted but a freshly created
    keyfile will be removed if our 'cryptsetup luksAddKey' returns non zero.
    :param dev_byid: by-id type name without path as found in db Disks.name.
    :param keyfile_withpath: the intended keyfile with full path.
    :param passphrase: LUKS passphrase: any current key slot passphrase. If
    an empty passphrase is passed then 'cryptsetup luksAddKey' is skipped.
    :return: True if keyfile successfully registered. False or an Exception 
    is raised in all other instances.
    """
    fresh_keyfile = False  # Until we find otherwise.
    # First we establish if our keyfile exists, and if not we create it.
    if not os.path.isfile(keyfile_withpath):
        # attempt to create our keyfile:
        if not create_keyfile(keyfile_withpath):
            # msg = ('Failed to establish new or existing keyfile: %s: %s' %
            #        (keyfile_withpath, e.__str__()))
            # raise Exception(msg)
            return False
        fresh_keyfile = True
    # We are by now assured of an existing keyfile_withpath.
    # Only register this keyfile with our LUKS container if needed:
    if passphrase == '':
        # If an empty passphrase was passed then we interpret this as a flag
        # to indicate no requirement to 'cryptsetup luksAddKey' so we are now
        # done. Use case is the return to "auto unlock via keyfile" when that
        # keyfile has already been registered. UI will not ask for passphrase
        # as it is assumed that an existing keyfile is already registered.
        return True
    dev_byid_withpath = get_device_path(dev_byid)
    tfo, npath = mkstemp()
    # Pythons _candidate_tempdir_list() should ensure our npath temp file is
    # in memory (tmpfs). From https://docs.python.org/2/library/tempfile.html
    # we have "Creates a temporary file in the most secure manner possible."
    # Populate this file with our passphrase and use as cryptsetup keyfile.
    # We set rc in case our try fails earlier than our run_command.
    rc = 0
    cmd = [
        CRYPTSETUP, 'luksAddKey', dev_byid_withpath, keyfile_withpath,
        '--key-file', npath
    ]
    try:
        with open(npath, 'w') as passphrase_file_object:
            passphrase_file_object.write(passphrase)
        out, err, rc = run_command(cmd, throw=False)
        if rc != 0:  # our luksAddKey command failed.
            if fresh_keyfile:
                # a freshly created keyfile without successful luksAddKey is
                # meaningless so remove it.
                os.remove(keyfile_withpath)
            raise CommandException(('%s' % cmd), out, err, rc)
    except Exception as e:
        if rc == 1:
            msg = 'Wrong Parameters exception'
        elif rc == 2:
            msg = 'No Permission (Bad Passphrase) exception'
        elif rc == 3:
            msg = 'Out of Memory exception'
        elif rc == 4:
            msg = 'Wrong Device Specified exception'
        elif rc == 5:
            msg = "Device already exists or device is busy exception"
        else:
            msg = 'Exception'
        msg += ' while running command(%s): %s' % (cmd, e.__str__())
        raise Exception(msg)
    finally:
        passphrase_file_object.close()
        if os.path.exists(npath):
            try:
                os.remove(npath)
            except Exception as e:
                msg = ('Exception while removing temp file %s: %s' %
                       (npath, e.__str__()))
                raise Exception(msg)
    return True
Esempio n. 13
0
def establish_keyfile(dev_byid, keyfile_withpath, passphrase):
    """
    Ensures that the given keyfile_withpath exists and calls create_keyfile()
    if it doesn't. Then attempts to register the established keyfile with the
    dev_byid device via "cryptsetup luksAddKey dev keyfile passphrase". But
    only if the passphrase is found to not equal '', flag for skip luksAddKey.
    N.B. The passphrase is passed to the command via a secure temporary file.
    Care is taken to remove this file irrespective of outcome.
    An existing keyfile will not be altered or deleted but a freshly created
    keyfile will be removed if our 'cryptsetup luksAddKey' returns non zero.
    :param dev_byid: by-id type name without path as found in db Disks.name.
    :param keyfile_withpath: the intended keyfile with full path.
    :param passphrase: LUKS passphrase: any current key slot passphrase. If
    an empty passphrase is passed then 'cryptsetup luksAddKey' is skipped.
    :return: True if keyfile successfully registered. False or an Exception 
    is raised in all other instances.
    """
    fresh_keyfile = False  # Until we find otherwise.
    # First we establish if our keyfile exists, and if not we create it.
    if not os.path.isfile(keyfile_withpath):
        # attempt to create our keyfile:
        if not create_keyfile(keyfile_withpath):
            # msg = ('Failed to establish new or existing keyfile: %s: %s' %
            #        (keyfile_withpath, e.__str__()))
            # raise Exception(msg)
            return False
        fresh_keyfile = True
    # We are by now assured of an existing keyfile_withpath.
    # Only register this keyfile with our LUKS container if needed:
    if passphrase == '':
        # If an empty passphrase was passed then we interpret this as a flag
        # to indicate no requirement to 'cryptsetup luksAddKey' so we are now
        # done. Use case is the return to "auto unlock via keyfile" when that
        # keyfile has already been registered. UI will not ask for passphrase
        # as it is assumed that an existing keyfile is already registered.
        return True
    dev_byid_withpath = get_device_path(dev_byid)
    tfo, npath = mkstemp()
    # Pythons _candidate_tempdir_list() should ensure our npath temp file is
    # in memory (tmpfs). From https://docs.python.org/2/library/tempfile.html
    # we have "Creates a temporary file in the most secure manner possible."
    # Populate this file with our passphrase and use as cryptsetup keyfile.
    # We set rc in case our try fails earlier than our run_command.
    rc = 0
    cmd = [CRYPTSETUP, 'luksAddKey', dev_byid_withpath, keyfile_withpath,
               '--key-file', npath]
    try:
        with open(npath, 'w') as passphrase_file_object:
            passphrase_file_object.write(passphrase)
        out, err, rc = run_command(cmd, throw=False)
        if rc != 0:  # our luksAddKey command failed.
            if fresh_keyfile:
                # a freshly created keyfile without successful luksAddKey is
                # meaningless so remove it.
                os.remove(keyfile_withpath)
            raise CommandException(('%s' % cmd), out, err, rc)
    except Exception as e:
        if rc == 1:
            msg = 'Wrong Parameters exception'
        elif rc == 2:
            msg = 'No Permission (Bad Passphrase) exception'
        elif rc == 3:
            msg = 'Out of Memory exception'
        elif rc == 4:
            msg = 'Wrong Device Specified exception'
        elif rc == 5:
            msg = "Device already exists or device is busy exception"
        else:
            msg = 'Exception'
        msg += ' while running command(%s): %s' % (cmd, e.__str__())
        raise Exception(msg)
    finally:
        passphrase_file_object.close()
        if os.path.exists(npath):
            try:
                os.remove(npath)
            except Exception as e:
                msg = ('Exception while removing temp file %s: %s' %
                       (npath, e.__str__()))
                raise Exception(msg)
    return True
Esempio n. 14
0
def mount_root(pool):
    """
    Mounts a given pool at the default mount root (usually /mnt2/) using the
    pool.name as the final path entry. Ie pool.name = test-pool will be mounted
    at /mnt2/test-pool. Any mount options held in pool.mnt_options will be
    added to the mount command via the -o option as will a compress =
    pool.compression entry.
    N.B. Initially the mount target is defined by /dev/disk/by-label/pool.name,
    if this fails then an attempt to mount by each member of
    /dev/disk/by-id/pool.disk_set.all() but only if there are any members.
    If this second method also fails then an exception is raised, currently all
    but the last failed mount by device name is logged. If no disk members were
    reported by pool.disk_set.count() a separate Exception is raised.
    :param pool: pool object
    :return: either the relevant mount point or an Exception which either
    indicates 'no disks in pool' or 'Unknown Reason'
    """
    root_pool_mnt = DEFAULT_MNT_DIR + pool.name
    if pool.is_mounted:
        return root_pool_mnt
    # Creates a directory to act as the mount point.
    create_tmp_dir(root_pool_mnt)
    toggle_path_rw(root_pool_mnt, rw=False)
    mnt_device = '/dev/disk/by-label/%s' % pool.name
    mnt_cmd = [MOUNT, mnt_device, root_pool_mnt, ]
    mnt_options = ''
    if (pool.mnt_options is not None):
        mnt_options = pool.mnt_options
    if (pool.compression is not None):
        if (re.search('compress', mnt_options) is None):
            mnt_options = ('%s,compress=%s' % (mnt_options, pool.compression))
    # Prior to a mount by label attempt we call btrfs device scan on all
    # members of our pool. This call ensures btrfs has up-to-date info on
    # the relevant devices and avoids the potential overkill of a system wide
    # call such as is performed in the rockstor-bootstrap service on boot.
    # Disk.target_name ensures we observe any redirect roles.
    device_scan([dev.target_name for dev in pool.disk_set.attached()])
    if (os.path.exists(mnt_device)):
        if (len(mnt_options) > 0):
            mnt_cmd.extend(['-o', mnt_options])
        run_command(mnt_cmd)
        return root_pool_mnt
    # If we cannot mount by-label, let's try mounting by device; one by one
    # until we get our first success. All devices known to our pool object
    # have already been scanned prior to our mount by label attempt above.
    if (pool.disk_set.count() < 1):
        raise Exception('Cannot mount Pool(%s) as it has no disks in it.'
                        % pool.name)
    last_device = pool.disk_set.attached().last()
    logger.info('Mount by label (%s) failed.' % mnt_device)
    for device in pool.disk_set.attached():
        mnt_device = get_device_path(device.target_name)
        logger.info('Attempting mount by device (%s).' % mnt_device)
        if (os.path.exists(mnt_device)):
            mnt_cmd = [MOUNT, mnt_device, root_pool_mnt, ]
            if (len(mnt_options) > 0):
                mnt_cmd.extend(['-o', mnt_options])
            try:
                run_command(mnt_cmd)
                return root_pool_mnt
            except Exception as e:
                if (device.name == last_device.name):
                    # exhausted mounting using all devices in the pool
                    raise e
                logger.error('Error mounting: %s. '
                             'Will try using another device.' % mnt_cmd)
                logger.exception(e)
        else:
            logger.error('Device (%s) was not found' % mnt_device)
    raise Exception('Failed to mount Pool(%s) due to an unknown reason. '
                    'Command used %s' % (pool.name, mnt_cmd))
Esempio n. 15
0
def btrfs_uuid(disk):
    """return uuid of a btrfs filesystem"""
    o, e, rc = run_command(
        [BTRFS, 'filesystem', 'show', get_device_path(disk)])
    return o[0].split()[3]