Blame cloudinit/config/cc_disk_setup.py

Packit Service a04d08
# Copyright (C) 2009-2010 Canonical Ltd.
Packit Service a04d08
# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
Packit Service a04d08
#
Packit Service a04d08
# Author: Ben Howard <ben.howard@canonical.com>
Packit Service a04d08
#
Packit Service a04d08
# This file is part of cloud-init. See LICENSE file for license information.
Packit Service a04d08
Packit Service a04d08
"""
Packit Service a04d08
Disk Setup
Packit Service a04d08
----------
Packit Service a04d08
**Summary:** configure partitions and filesystems
Packit Service a04d08
Packit Service a04d08
This module is able to configure simple partition tables and filesystems.
Packit Service a04d08
Packit Service a04d08
.. note::
Packit Service a04d08
    for more detail about configuration options for disk setup, see the disk
Packit Service a04d08
    setup example
Packit Service a04d08
Packit Service a04d08
For convenience, aliases can be specified for disks using the
Packit Service a04d08
``device_aliases`` config key, which takes a dictionary of alias: path
Packit Service a04d08
mappings. There are automatic aliases for ``swap`` and ``ephemeral<X>``, where
Packit Service a04d08
``swap`` will always refer to the active swap partition and ``ephemeral<X>``
Packit Service a04d08
will refer to the block device of the ephemeral image.
Packit Service a04d08
Packit Service a04d08
Disk partitioning is done using the ``disk_setup`` directive. This config
Packit Service a04d08
directive accepts a dictionary where each key is either a path to a block
Packit Service a04d08
device or an alias specified in ``device_aliases``, and each value is the
Packit Service a04d08
configuration options for the device. The ``table_type`` option specifies the
Packit Service a04d08
partition table type, either ``mbr`` or ``gpt``. The ``layout`` option
Packit Service a04d08
specifies how partitions on the device are to be arranged. If ``layout`` is set
Packit Service a04d08
to ``true``, a single partition using all the space on the device will be
Packit Service a04d08
created. If set to ``false``, no partitions will be created. Partitions can be
Packit Service a04d08
specified by providing a list to ``layout``, where each entry in the list is
Packit Service a04d08
either a size or a list containing a size and the numerical value for a
Packit Service a04d08
partition type. The size for partitions is specified in **percentage** of disk
Packit Service a04d08
space, not in bytes (e.g. a size of 33 would take up 1/3 of the disk space).
Packit Service a04d08
The ``overwrite`` option controls whether this module tries to be safe about
Packit Service a04d08
writing partition talbes or not. If ``overwrite: false`` is set, the device
Packit Service a04d08
will be checked for a partition table and for a file system and if either is
Packit Service a04d08
found, the operation will be skipped. If ``overwrite: true`` is set, no checks
Packit Service a04d08
will be performed.
Packit Service a04d08
Packit Service a04d08
.. note::
Packit Service a04d08
    Using ``overwrite: true`` is dangerous and can lead to data loss, so double
Packit Service a04d08
    check that the correct device has been specified if using this option.
Packit Service a04d08
Packit Service a04d08
File system configuration is done using the ``fs_setup`` directive. This config
Packit Service a04d08
directive accepts a list of filesystem configs. The device to create the
Packit Service a04d08
filesystem on may be specified either as a path or as an alias in the format
Packit Service a04d08
``<alias name>.<y>`` where ``<y>`` denotes the partition number on the device.
Packit Service a04d08
The partition can also be specified by setting ``partition`` to the desired
Packit Service a04d08
partition number. The ``partition`` option may also be set to ``auto``, in
Packit Service a04d08
which this module will search for the existance of a filesystem matching the
Packit Service a04d08
``label``, ``type`` and ``device`` of the ``fs_setup`` entry and will skip
Packit Service a04d08
creating the filesystem if one is found. The ``partition`` option may also be
Packit Service a04d08
set to ``any``, in which case any file system that matches ``type`` and
Packit Service a04d08
``device`` will cause this module to skip filesystem creation for the
Packit Service a04d08
``fs_setup`` entry, regardless of ``label`` matching or not. To write a
Packit Service a04d08
filesystem directly to a device, use ``partition: none``. A label can be
Packit Service a04d08
specified for the filesystem using ``label``, and the filesystem type can be
Packit Service a04d08
specified using ``filesystem``.
Packit Service a04d08
Packit Service a04d08
.. note::
Packit Service a04d08
    If specifying device using the ``<device name>.<partition number>`` format,
Packit Service a04d08
    the value of ``partition`` will be overwritten.
Packit Service a04d08
Packit Service a04d08
.. note::
Packit Service a04d08
    Using ``overwrite: true`` for filesystems is dangerous and can lead to data
Packit Service a04d08
    loss, so double check the entry in ``fs_setup``.
Packit Service a04d08
Packit Service a04d08
.. note::
Packit Service a04d08
    ``replace_fs`` is ignored unless ``partition`` is ``auto`` or ``any``.
Packit Service a04d08
Packit Service a04d08
**Internal name:** ``cc_disk_setup``
Packit Service a04d08
Packit Service a04d08
**Module frequency:** per instance
Packit Service a04d08
Packit Service a04d08
**Supported distros:** all
Packit Service a04d08
Packit Service a04d08
**Config keys**::
Packit Service a04d08
Packit Service a04d08
    device_aliases:
Packit Service a04d08
        <alias name>: <device path>
Packit Service a04d08
    disk_setup:
Packit Service a04d08
        <alias name/path>:
Packit Service a04d08
            table_type: <'mbr'/'gpt'>
Packit Service a04d08
            layout:
Packit Service a04d08
                - [33,82]
Packit Service a04d08
                - 66
Packit Service a04d08
            overwrite: <true/false>
Packit Service a04d08
    fs_setup:
Packit Service a04d08
        - label: <label>
Packit Service a04d08
          filesystem: <filesystem type>
Packit Service a04d08
          device: <device>
Packit Service a04d08
          partition: <"auto"/"any"/"none"/<partition number>>
Packit Service a04d08
          overwrite: <true/false>
Packit Service a04d08
          replace_fs: <filesystem type>
Packit Service a04d08
"""
Packit Service a04d08
Packit Service a04d08
from cloudinit.settings import PER_INSTANCE
Packit Service a04d08
from cloudinit import util
Packit Service 751c4a
from cloudinit import subp
Packit Service a04d08
import logging
Packit Service a04d08
import os
Packit Service a04d08
import shlex
Packit Service a04d08
Packit Service a04d08
frequency = PER_INSTANCE
Packit Service a04d08
Packit Service a04d08
# Define the commands to use
Packit Service 751c4a
UDEVADM_CMD = subp.which('udevadm')
Packit Service 751c4a
SFDISK_CMD = subp.which("sfdisk")
Packit Service 751c4a
SGDISK_CMD = subp.which("sgdisk")
Packit Service 751c4a
LSBLK_CMD = subp.which("lsblk")
Packit Service 751c4a
BLKID_CMD = subp.which("blkid")
Packit Service 751c4a
BLKDEV_CMD = subp.which("blockdev")
Packit Service 751c4a
WIPEFS_CMD = subp.which("wipefs")
Packit Service a04d08
Packit Service a04d08
LANG_C_ENV = {'LANG': 'C'}
Packit Service a04d08
Packit Service a04d08
LOG = logging.getLogger(__name__)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def handle(_name, cfg, cloud, log, _args):
Packit Service a04d08
    """
Packit Service a04d08
    See doc/examples/cloud-config-disk-setup.txt for documentation on the
Packit Service a04d08
    format.
Packit Service a04d08
    """
Packit Service a04d08
    disk_setup = cfg.get("disk_setup")
Packit Service a04d08
    if isinstance(disk_setup, dict):
Packit Service a04d08
        update_disk_setup_devices(disk_setup, cloud.device_name_to_device)
Packit Service a04d08
        log.debug("Partitioning disks: %s", str(disk_setup))
Packit Service a04d08
        for disk, definition in disk_setup.items():
Packit Service a04d08
            if not isinstance(definition, dict):
Packit Service a04d08
                log.warning("Invalid disk definition for %s" % disk)
Packit Service a04d08
                continue
Packit Service a04d08
Packit Service a04d08
            try:
Packit Service a04d08
                log.debug("Creating new partition table/disk")
Packit Service a04d08
                util.log_time(logfunc=LOG.debug,
Packit Service a04d08
                              msg="Creating partition on %s" % disk,
Packit Service a04d08
                              func=mkpart, args=(disk, definition))
Packit Service a04d08
            except Exception as e:
Packit Service a04d08
                util.logexc(LOG, "Failed partitioning operation\n%s" % e)
Packit Service a04d08
Packit Service a04d08
    fs_setup = cfg.get("fs_setup")
Packit Service a04d08
    if isinstance(fs_setup, list):
Packit Service a04d08
        log.debug("setting up filesystems: %s", str(fs_setup))
Packit Service a04d08
        update_fs_setup_devices(fs_setup, cloud.device_name_to_device)
Packit Service a04d08
        for definition in fs_setup:
Packit Service a04d08
            if not isinstance(definition, dict):
Packit Service a04d08
                log.warning("Invalid file system definition: %s" % definition)
Packit Service a04d08
                continue
Packit Service a04d08
Packit Service a04d08
            try:
Packit Service a04d08
                log.debug("Creating new filesystem.")
Packit Service a04d08
                device = definition.get('device')
Packit Service a04d08
                util.log_time(logfunc=LOG.debug,
Packit Service a04d08
                              msg="Creating fs for %s" % device,
Packit Service a04d08
                              func=mkfs, args=(definition,))
Packit Service a04d08
            except Exception as e:
Packit Service a04d08
                util.logexc(LOG, "Failed during filesystem operation\n%s" % e)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def update_disk_setup_devices(disk_setup, tformer):
Packit Service a04d08
    # update 'disk_setup' dictionary anywhere were a device may occur
Packit Service a04d08
    # update it with the response from 'tformer'
Packit Service 751c4a
    for origname in list(disk_setup):
Packit Service a04d08
        transformed = tformer(origname)
Packit Service a04d08
        if transformed is None or transformed == origname:
Packit Service a04d08
            continue
Packit Service a04d08
        if transformed in disk_setup:
Packit Service a04d08
            LOG.info("Replacing %s in disk_setup for translation of %s",
Packit Service a04d08
                     origname, transformed)
Packit Service a04d08
            del disk_setup[transformed]
Packit Service a04d08
Packit Service a04d08
        disk_setup[transformed] = disk_setup[origname]
Packit Service a04d08
        disk_setup[transformed]['_origname'] = origname
Packit Service a04d08
        del disk_setup[origname]
Packit Service a04d08
        LOG.debug("updated disk_setup device entry '%s' to '%s'",
Packit Service a04d08
                  origname, transformed)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def update_fs_setup_devices(disk_setup, tformer):
Packit Service a04d08
    # update 'fs_setup' dictionary anywhere were a device may occur
Packit Service a04d08
    # update it with the response from 'tformer'
Packit Service a04d08
    for definition in disk_setup:
Packit Service a04d08
        if not isinstance(definition, dict):
Packit Service a04d08
            LOG.warning("entry in disk_setup not a dict: %s", definition)
Packit Service a04d08
            continue
Packit Service a04d08
Packit Service a04d08
        origname = definition.get('device')
Packit Service a04d08
Packit Service a04d08
        if origname is None:
Packit Service a04d08
            continue
Packit Service a04d08
Packit Service a04d08
        (dev, part) = util.expand_dotted_devname(origname)
Packit Service a04d08
Packit Service a04d08
        tformed = tformer(dev)
Packit Service a04d08
        if tformed is not None:
Packit Service a04d08
            dev = tformed
Packit Service a04d08
            LOG.debug("%s is mapped to disk=%s part=%s",
Packit Service a04d08
                      origname, tformed, part)
Packit Service a04d08
            definition['_origname'] = origname
Packit Service a04d08
            definition['device'] = tformed
Packit Service a04d08
Packit Service a04d08
        if part:
Packit Service a04d08
            # In origname with <dev>.N, N overrides 'partition' key.
Packit Service a04d08
            if 'partition' in definition:
Packit Service a04d08
                LOG.warning("Partition '%s' from dotted device name '%s' "
Packit Service a04d08
                            "overrides 'partition' key in %s", part, origname,
Packit Service a04d08
                            definition)
Packit Service a04d08
                definition['_partition'] = definition['partition']
Packit Service a04d08
            definition['partition'] = part
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def value_splitter(values, start=None):
Packit Service a04d08
    """
Packit Service a04d08
    Returns the key/value pairs of output sent as string
Packit Service a04d08
    like:  FOO='BAR' HOME='127.0.0.1'
Packit Service a04d08
    """
Packit Service a04d08
    _values = shlex.split(values)
Packit Service a04d08
    if start:
Packit Service a04d08
        _values = _values[start:]
Packit Service a04d08
Packit Service a04d08
    for key, value in [x.split('=') for x in _values]:
Packit Service a04d08
        yield key, value
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def enumerate_disk(device, nodeps=False):
Packit Service a04d08
    """
Packit Service a04d08
    Enumerate the elements of a child device.
Packit Service a04d08
Packit Service a04d08
    Parameters:
Packit Service a04d08
        device: the kernel device name
Packit Service a04d08
        nodeps <BOOL>: don't enumerate children devices
Packit Service a04d08
Packit Service a04d08
    Return a dict describing the disk:
Packit Service a04d08
        type: the entry type, i.e disk or part
Packit Service a04d08
        fstype: the filesystem type, if it exists
Packit Service a04d08
        label: file system label, if it exists
Packit Service a04d08
        name: the device name, i.e. sda
Packit Service a04d08
    """
Packit Service a04d08
Packit Service a04d08
    lsblk_cmd = [LSBLK_CMD, '--pairs', '--output', 'NAME,TYPE,FSTYPE,LABEL',
Packit Service a04d08
                 device]
Packit Service a04d08
Packit Service a04d08
    if nodeps:
Packit Service a04d08
        lsblk_cmd.append('--nodeps')
Packit Service a04d08
Packit Service a04d08
    info = None
Packit Service a04d08
    try:
Packit Service 751c4a
        info, _err = subp.subp(lsblk_cmd)
Packit Service a04d08
    except Exception as e:
Packit Service 751c4a
        raise Exception(
Packit Service 751c4a
            "Failed during disk check for %s\n%s" % (device, e)
Packit Service 751c4a
        ) from e
Packit Service a04d08
Packit Service a04d08
    parts = [x for x in (info.strip()).splitlines() if len(x.split()) > 0]
Packit Service a04d08
Packit Service a04d08
    for part in parts:
Packit Service a04d08
        d = {
Packit Service a04d08
            'name': None,
Packit Service a04d08
            'type': None,
Packit Service a04d08
            'fstype': None,
Packit Service a04d08
            'label': None,
Packit Service a04d08
        }
Packit Service a04d08
Packit Service a04d08
        for key, value in value_splitter(part):
Packit Service a04d08
            d[key.lower()] = value
Packit Service a04d08
Packit Service a04d08
        yield d
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def device_type(device):
Packit Service a04d08
    """
Packit Service a04d08
    Return the device type of the device by calling lsblk.
Packit Service a04d08
    """
Packit Service a04d08
Packit Service a04d08
    for d in enumerate_disk(device, nodeps=True):
Packit Service a04d08
        if "type" in d:
Packit Service a04d08
            return d["type"].lower()
Packit Service a04d08
    return None
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def is_device_valid(name, partition=False):
Packit Service a04d08
    """
Packit Service a04d08
    Check if the device is a valid device.
Packit Service a04d08
    """
Packit Service a04d08
    d_type = ""
Packit Service a04d08
    try:
Packit Service a04d08
        d_type = device_type(name)
Packit Service a04d08
    except Exception:
Packit Service a04d08
        LOG.warning("Query against device %s failed", name)
Packit Service a04d08
        return False
Packit Service a04d08
Packit Service a04d08
    if partition and d_type == 'part':
Packit Service a04d08
        return True
Packit Service a04d08
    elif not partition and d_type == 'disk':
Packit Service a04d08
        return True
Packit Service a04d08
    return False
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def check_fs(device):
Packit Service a04d08
    """
Packit Service a04d08
    Check if the device has a filesystem on it
Packit Service a04d08
Packit Service a04d08
    Output of blkid is generally something like:
Packit Service a04d08
    /dev/sda: LABEL="Backup500G" UUID="..." TYPE="ext4"
Packit Service a04d08
Packit Service a04d08
    Return values are device, label, type, uuid
Packit Service a04d08
    """
Packit Service a04d08
    out, label, fs_type, uuid = None, None, None, None
Packit Service a04d08
Packit Service a04d08
    blkid_cmd = [BLKID_CMD, '-c', '/dev/null', device]
Packit Service a04d08
    try:
Packit Service 751c4a
        out, _err = subp.subp(blkid_cmd, rcs=[0, 2])
Packit Service a04d08
    except Exception as e:
Packit Service 751c4a
        raise Exception(
Packit Service 751c4a
            "Failed during disk check for %s\n%s" % (device, e)
Packit Service 751c4a
        ) from e
Packit Service a04d08
Packit Service a04d08
    if out:
Packit Service a04d08
        if len(out.splitlines()) == 1:
Packit Service a04d08
            for key, value in value_splitter(out, start=1):
Packit Service a04d08
                if key.lower() == 'label':
Packit Service a04d08
                    label = value
Packit Service a04d08
                elif key.lower() == 'type':
Packit Service a04d08
                    fs_type = value
Packit Service a04d08
                elif key.lower() == 'uuid':
Packit Service a04d08
                    uuid = value
Packit Service a04d08
Packit Service a04d08
    return label, fs_type, uuid
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def is_filesystem(device):
Packit Service a04d08
    """
Packit Service a04d08
    Returns true if the device has a file system.
Packit Service a04d08
    """
Packit Service a04d08
    _, fs_type, _ = check_fs(device)
Packit Service a04d08
    return fs_type
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def find_device_node(device, fs_type=None, label=None, valid_targets=None,
Packit Service a04d08
                     label_match=True, replace_fs=None):
Packit Service a04d08
    """
Packit Service a04d08
    Find a device that is either matches the spec, or the first
Packit Service a04d08
Packit Service a04d08
    The return is value is (<device>, <bool>) where the device is the
Packit Service a04d08
    device to use and the bool is whether the device matches the
Packit Service a04d08
    fs_type and label.
Packit Service a04d08
Packit Service a04d08
    Note: This works with GPT partition tables!
Packit Service a04d08
    """
Packit Service a04d08
    # label of None is same as no label
Packit Service a04d08
    if label is None:
Packit Service a04d08
        label = ""
Packit Service a04d08
Packit Service a04d08
    if not valid_targets:
Packit Service a04d08
        valid_targets = ['disk', 'part']
Packit Service a04d08
Packit Service a04d08
    raw_device_used = False
Packit Service a04d08
    for d in enumerate_disk(device):
Packit Service a04d08
Packit Service a04d08
        if d['fstype'] == replace_fs and label_match is False:
Packit Service a04d08
            # We found a device where we want to replace the FS
Packit Service a04d08
            return ('/dev/%s' % d['name'], False)
Packit Service a04d08
Packit Service a04d08
        if (d['fstype'] == fs_type and
Packit Service a04d08
                ((label_match and d['label'] == label) or not label_match)):
Packit Service a04d08
            # If we find a matching device, we return that
Packit Service a04d08
            return ('/dev/%s' % d['name'], True)
Packit Service a04d08
Packit Service a04d08
        if d['type'] in valid_targets:
Packit Service a04d08
Packit Service a04d08
            if d['type'] != 'disk' or d['fstype']:
Packit Service a04d08
                raw_device_used = True
Packit Service a04d08
Packit Service a04d08
            if d['type'] == 'disk':
Packit Service a04d08
                # Skip the raw disk, its the default
Packit Service a04d08
                pass
Packit Service a04d08
Packit Service a04d08
            elif not d['fstype']:
Packit Service a04d08
                return ('/dev/%s' % d['name'], False)
Packit Service a04d08
Packit Service a04d08
    if not raw_device_used:
Packit Service a04d08
        return (device, False)
Packit Service a04d08
Packit Service a04d08
    LOG.warning("Failed to find device during available device search.")
Packit Service a04d08
    return (None, False)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def is_disk_used(device):
Packit Service a04d08
    """
Packit Service a04d08
    Check if the device is currently used. Returns true if the device
Packit Service a04d08
    has either a file system or a partition entry
Packit Service a04d08
    is no filesystem found on the disk.
Packit Service a04d08
    """
Packit Service a04d08
Packit Service a04d08
    # If the child count is higher 1, then there are child nodes
Packit Service a04d08
    # such as partition or device mapper nodes
Packit Service a04d08
    if len(list(enumerate_disk(device))) > 1:
Packit Service a04d08
        return True
Packit Service a04d08
Packit Service a04d08
    # If we see a file system, then its used
Packit Service a04d08
    _, check_fstype, _ = check_fs(device)
Packit Service a04d08
    if check_fstype:
Packit Service a04d08
        return True
Packit Service a04d08
Packit Service a04d08
    return False
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def get_dyn_func(*args):
Packit Service a04d08
    """
Packit Service a04d08
    Call the appropriate function.
Packit Service a04d08
Packit Service a04d08
    The first value is the template for function name
Packit Service a04d08
    The second value is the template replacement
Packit Service a04d08
    The remain values are passed to the function
Packit Service a04d08
Packit Service a04d08
    For example: get_dyn_func("foo_%s", 'bar', 1, 2, 3,)
Packit Service a04d08
        would call "foo_bar" with args of 1, 2, 3
Packit Service a04d08
    """
Packit Service a04d08
    if len(args) < 2:
Packit Service a04d08
        raise Exception("Unable to determine dynamic funcation name")
Packit Service a04d08
Packit Service a04d08
    func_name = (args[0] % args[1])
Packit Service a04d08
    func_args = args[2:]
Packit Service a04d08
Packit Service a04d08
    try:
Packit Service a04d08
        if func_args:
Packit Service a04d08
            return globals()[func_name](*func_args)
Packit Service a04d08
        else:
Packit Service a04d08
            return globals()[func_name]
Packit Service a04d08
Packit Service 751c4a
    except KeyError as e:
Packit Service 751c4a
        raise Exception("No such function %s to call!" % func_name) from e
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def get_hdd_size(device):
Packit Service a04d08
    try:
Packit Service 751c4a
        size_in_bytes, _ = subp.subp([BLKDEV_CMD, '--getsize64', device])
Packit Service 751c4a
        sector_size, _ = subp.subp([BLKDEV_CMD, '--getss', device])
Packit Service a04d08
    except Exception as e:
Packit Service 751c4a
        raise Exception("Failed to get %s size\n%s" % (device, e)) from e
Packit Service a04d08
Packit Service a04d08
    return int(size_in_bytes) / int(sector_size)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def check_partition_mbr_layout(device, layout):
Packit Service a04d08
    """
Packit Service a04d08
    Returns true if the partition layout matches the one on the disk
Packit Service a04d08
Packit Service a04d08
    Layout should be a list of values. At this time, this only
Packit Service a04d08
    verifies that the number of partitions and their labels is correct.
Packit Service a04d08
    """
Packit Service a04d08
Packit Service a04d08
    read_parttbl(device)
Packit Service a04d08
    prt_cmd = [SFDISK_CMD, "-l", device]
Packit Service a04d08
    try:
Packit Service 751c4a
        out, _err = subp.subp(prt_cmd, data="%s\n" % layout)
Packit Service a04d08
    except Exception as e:
Packit Service 751c4a
        raise Exception(
Packit Service 751c4a
            "Error running partition command on %s\n%s" % (device, e)
Packit Service 751c4a
        ) from e
Packit Service a04d08
Packit Service a04d08
    found_layout = []
Packit Service a04d08
    for line in out.splitlines():
Packit Service a04d08
        _line = line.split()
Packit Service a04d08
        if len(_line) == 0:
Packit Service a04d08
            continue
Packit Service a04d08
Packit Service a04d08
        if device in _line[0]:
Packit Service a04d08
            # We don't understand extended partitions yet
Packit Service a04d08
            if _line[-1].lower() in ['extended', 'empty']:
Packit Service a04d08
                continue
Packit Service a04d08
Packit Service a04d08
            # Find the partition types
Packit Service a04d08
            type_label = None
Packit Service a04d08
            for x in sorted(range(1, len(_line)), reverse=True):
Packit Service a04d08
                if _line[x].isdigit() and _line[x] != '/':
Packit Service a04d08
                    type_label = _line[x]
Packit Service a04d08
                    break
Packit Service a04d08
Packit Service a04d08
            found_layout.append(type_label)
Packit Service a04d08
    return found_layout
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def check_partition_gpt_layout(device, layout):
Packit Service a04d08
    prt_cmd = [SGDISK_CMD, '-p', device]
Packit Service a04d08
    try:
Packit Service 751c4a
        out, _err = subp.subp(prt_cmd, update_env=LANG_C_ENV)
Packit Service a04d08
    except Exception as e:
Packit Service 751c4a
        raise Exception(
Packit Service 751c4a
            "Error running partition command on %s\n%s" % (device, e)
Packit Service 751c4a
        ) from e
Packit Service a04d08
Packit Service a04d08
    out_lines = iter(out.splitlines())
Packit Service a04d08
    # Skip header.  Output looks like:
Packit Service a04d08
    # ***************************************************************
Packit Service a04d08
    # Found invalid GPT and valid MBR; converting MBR to GPT format
Packit Service a04d08
    # in memory.
Packit Service a04d08
    # ***************************************************************
Packit Service a04d08
    #
Packit Service a04d08
    # Disk /dev/vdb: 83886080 sectors, 40.0 GiB
Packit Service a04d08
    # Logical sector size: 512 bytes
Packit Service a04d08
    # Disk identifier (GUID): 8A7F11AD-3953-491B-8051-077E01C8E9A7
Packit Service a04d08
    # Partition table holds up to 128 entries
Packit Service a04d08
    # First usable sector is 34, last usable sector is 83886046
Packit Service a04d08
    # Partitions will be aligned on 2048-sector boundaries
Packit Service a04d08
    # Total free space is 83476413 sectors (39.8 GiB)
Packit Service a04d08
    #
Packit Service a04d08
    # Number Start (sector) End (sector) Size       Code  Name
Packit Service a04d08
    # 1      2048           206847       100.0 MiB  0700  Microsoft basic data
Packit Service a04d08
    for line in out_lines:
Packit Service a04d08
        if line.strip().startswith('Number'):
Packit Service a04d08
            break
Packit Service a04d08
Packit Service a04d08
    codes = [line.strip().split()[5] for line in out_lines]
Packit Service a04d08
    cleaned = []
Packit Service a04d08
Packit Service a04d08
    # user would expect a code '83' to be Linux, but sgdisk outputs 8300.
Packit Service a04d08
    for code in codes:
Packit Service a04d08
        if len(code) == 4 and code.endswith("00"):
Packit Service a04d08
            code = code[0:2]
Packit Service a04d08
        cleaned.append(code)
Packit Service a04d08
    return cleaned
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def check_partition_layout(table_type, device, layout):
Packit Service a04d08
    """
Packit Service a04d08
    See if the partition lay out matches.
Packit Service a04d08
Packit Service a04d08
    This is future a future proofing function. In order
Packit Service a04d08
    to add support for other disk layout schemes, add a
Packit Service a04d08
    function called check_partition_%s_layout
Packit Service a04d08
    """
Packit Service a04d08
    found_layout = get_dyn_func(
Packit Service a04d08
        "check_partition_%s_layout", table_type, device, layout)
Packit Service a04d08
Packit Service a04d08
    LOG.debug("called check_partition_%s_layout(%s, %s), returned: %s",
Packit Service a04d08
              table_type, device, layout, found_layout)
Packit Service a04d08
    if isinstance(layout, bool):
Packit Service a04d08
        # if we are using auto partitioning, or "True" be happy
Packit Service a04d08
        # if a single partition exists.
Packit Service a04d08
        if layout and len(found_layout) >= 1:
Packit Service a04d08
            return True
Packit Service a04d08
        return False
Packit Service a04d08
Packit Service a04d08
    elif len(found_layout) == len(layout):
Packit Service a04d08
        # This just makes sure that the number of requested
Packit Service a04d08
        # partitions and the type labels are right
Packit Service a04d08
        layout_types = [str(x[1]) if isinstance(x, (tuple, list)) else None
Packit Service a04d08
                        for x in layout]
Packit Service a04d08
        LOG.debug("Layout types=%s. Found types=%s",
Packit Service a04d08
                  layout_types, found_layout)
Packit Service a04d08
        for itype, ftype in zip(layout_types, found_layout):
Packit Service a04d08
            if itype is not None and str(ftype) != str(itype):
Packit Service a04d08
                return False
Packit Service a04d08
        return True
Packit Service a04d08
Packit Service a04d08
    return False
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def get_partition_mbr_layout(size, layout):
Packit Service a04d08
    """
Packit Service a04d08
    Calculate the layout of the partition table. Partition sizes
Packit Service a04d08
    are defined as percentage values or a tuple of percentage and
Packit Service a04d08
    partition type.
Packit Service a04d08
Packit Service a04d08
    For example:
Packit Service a04d08
        [ 33, [66: 82] ]
Packit Service a04d08
Packit Service a04d08
    Defines the first partition to be a size of 1/3 the disk,
Packit Service a04d08
    while the remaining 2/3's will be of type Linux Swap.
Packit Service a04d08
    """
Packit Service a04d08
Packit Service a04d08
    if not isinstance(layout, list) and isinstance(layout, bool):
Packit Service a04d08
        # Create a single partition
Packit Service a04d08
        return "0,"
Packit Service a04d08
Packit Service a04d08
    if ((len(layout) == 0 and isinstance(layout, list)) or
Packit Service a04d08
            not isinstance(layout, list)):
Packit Service a04d08
        raise Exception("Partition layout is invalid")
Packit Service a04d08
Packit Service a04d08
    last_part_num = len(layout)
Packit Service a04d08
    if last_part_num > 4:
Packit Service a04d08
        raise Exception("Only simply partitioning is allowed.")
Packit Service a04d08
Packit Service a04d08
    part_definition = []
Packit Service a04d08
    part_num = 0
Packit Service a04d08
    for part in layout:
Packit Service a04d08
        part_type = 83  # Default to Linux
Packit Service a04d08
        percent = part
Packit Service a04d08
        part_num += 1
Packit Service a04d08
Packit Service a04d08
        if isinstance(part, list):
Packit Service a04d08
            if len(part) != 2:
Packit Service a04d08
                raise Exception("Partition was incorrectly defined: %s" % part)
Packit Service a04d08
            percent, part_type = part
Packit Service a04d08
Packit Service a04d08
        part_size = int(float(size) * (float(percent) / 100))
Packit Service a04d08
Packit Service a04d08
        if part_num == last_part_num:
Packit Service a04d08
            part_definition.append(",,%s" % part_type)
Packit Service a04d08
        else:
Packit Service a04d08
            part_definition.append(",%s,%s" % (part_size, part_type))
Packit Service a04d08
Packit Service a04d08
    sfdisk_definition = "\n".join(part_definition)
Packit Service a04d08
    if len(part_definition) > 4:
Packit Service a04d08
        raise Exception("Calculated partition definition is too big\n%s" %
Packit Service a04d08
                        sfdisk_definition)
Packit Service a04d08
Packit Service a04d08
    return sfdisk_definition
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def get_partition_gpt_layout(size, layout):
Packit Service a04d08
    if isinstance(layout, bool):
Packit Service a04d08
        return [(None, [0, 0])]
Packit Service a04d08
Packit Service a04d08
    partition_specs = []
Packit Service a04d08
    for partition in layout:
Packit Service a04d08
        if isinstance(partition, list):
Packit Service a04d08
            if len(partition) != 2:
Packit Service a04d08
                raise Exception(
Packit Service a04d08
                    "Partition was incorrectly defined: %s" % partition)
Packit Service a04d08
            percent, partition_type = partition
Packit Service a04d08
        else:
Packit Service a04d08
            percent = partition
Packit Service a04d08
            partition_type = None
Packit Service a04d08
Packit Service a04d08
        part_size = int(float(size) * (float(percent) / 100))
Packit Service a04d08
        partition_specs.append((partition_type, [0, '+{}'.format(part_size)]))
Packit Service a04d08
Packit Service a04d08
    # The last partition should use up all remaining space
Packit Service a04d08
    partition_specs[-1][-1][-1] = 0
Packit Service a04d08
    return partition_specs
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def purge_disk_ptable(device):
Packit Service a04d08
    # wipe the first and last megabyte of a disk (or file)
Packit Service a04d08
    # gpt stores partition table both at front and at end.
Packit Service a04d08
    null = '\0'
Packit Service a04d08
    start_len = 1024 * 1024
Packit Service a04d08
    end_len = 1024 * 1024
Packit Service a04d08
    with open(device, "rb+") as fp:
Packit Service a04d08
        fp.write(null * (start_len))
Packit Service a04d08
        fp.seek(-end_len, os.SEEK_END)
Packit Service a04d08
        fp.write(null * end_len)
Packit Service a04d08
        fp.flush()
Packit Service a04d08
Packit Service a04d08
    read_parttbl(device)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def purge_disk(device):
Packit Service a04d08
    """
Packit Service a04d08
    Remove parition table entries
Packit Service a04d08
    """
Packit Service a04d08
Packit Service a04d08
    # wipe any file systems first
Packit Service a04d08
    for d in enumerate_disk(device):
Packit Service a04d08
        if d['type'] not in ["disk", "crypt"]:
Packit Service a04d08
            wipefs_cmd = [WIPEFS_CMD, "--all", "/dev/%s" % d['name']]
Packit Service a04d08
            try:
Packit Service a04d08
                LOG.info("Purging filesystem on /dev/%s", d['name'])
Packit Service 751c4a
                subp.subp(wipefs_cmd)
Packit Service 751c4a
            except Exception as e:
Packit Service 751c4a
                raise Exception(
Packit Service 751c4a
                    "Failed FS purge of /dev/%s" % d['name']
Packit Service 751c4a
                ) from e
Packit Service a04d08
Packit Service a04d08
    purge_disk_ptable(device)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def get_partition_layout(table_type, size, layout):
Packit Service a04d08
    """
Packit Service a04d08
    Call the appropriate function for creating the table
Packit Service a04d08
    definition. Returns the table definition
Packit Service a04d08
Packit Service a04d08
    This is a future proofing function. To add support for
Packit Service a04d08
    other layouts, simply add a "get_partition_%s_layout"
Packit Service a04d08
    function.
Packit Service a04d08
    """
Packit Service a04d08
    return get_dyn_func("get_partition_%s_layout", table_type, size, layout)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def read_parttbl(device):
Packit Service a04d08
    """
Packit Service a04d08
    Use partprobe instead of 'udevadm'. Partprobe is the only
Packit Service a04d08
    reliable way to probe the partition table.
Packit Service a04d08
    """
Packit Service a04d08
    blkdev_cmd = [BLKDEV_CMD, '--rereadpt', device]
Packit Service a04d08
    util.udevadm_settle()
Packit Service a04d08
    try:
Packit Service 751c4a
        subp.subp(blkdev_cmd)
Packit Service a04d08
    except Exception as e:
Packit Service a04d08
        util.logexc(LOG, "Failed reading the partition table %s" % e)
Packit Service a04d08
Packit Service a04d08
    util.udevadm_settle()
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def exec_mkpart_mbr(device, layout):
Packit Service a04d08
    """
Packit Service a04d08
    Break out of mbr partition to allow for future partition
Packit Service a04d08
    types, i.e. gpt
Packit Service a04d08
    """
Packit Service a04d08
    # Create the partitions
Packit Service a04d08
    prt_cmd = [SFDISK_CMD, "--Linux", "--unit=S", "--force", device]
Packit Service a04d08
    try:
Packit Service 751c4a
        subp.subp(prt_cmd, data="%s\n" % layout)
Packit Service a04d08
    except Exception as e:
Packit Service 751c4a
        raise Exception(
Packit Service 751c4a
            "Failed to partition device %s\n%s" % (device, e)
Packit Service 751c4a
        ) from e
Packit Service a04d08
Packit Service a04d08
    read_parttbl(device)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def exec_mkpart_gpt(device, layout):
Packit Service a04d08
    try:
Packit Service 751c4a
        subp.subp([SGDISK_CMD, '-Z', device])
Packit Service a04d08
        for index, (partition_type, (start, end)) in enumerate(layout):
Packit Service a04d08
            index += 1
Packit Service 751c4a
            subp.subp([SGDISK_CMD,
Packit Service a04d08
                       '-n', '{}:{}:{}'.format(index, start, end), device])
Packit Service a04d08
            if partition_type is not None:
Packit Service a04d08
                # convert to a 4 char (or more) string right padded with 0
Packit Service a04d08
                # 82 -> 8200.  'Linux' -> 'Linux'
Packit Service a04d08
                pinput = str(partition_type).ljust(4, "0")
Packit Service 751c4a
                subp.subp(
Packit Service a04d08
                    [SGDISK_CMD, '-t', '{}:{}'.format(index, pinput), device])
Packit Service a04d08
    except Exception:
Packit Service a04d08
        LOG.warning("Failed to partition device %s", device)
Packit Service a04d08
        raise
Packit Service a04d08
Packit Service a04d08
    read_parttbl(device)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def exec_mkpart(table_type, device, layout):
Packit Service a04d08
    """
Packit Service a04d08
    Fetches the function for creating the table type.
Packit Service a04d08
    This allows to dynamically find which function to call.
Packit Service a04d08
Packit Service a04d08
    Paramaters:
Packit Service a04d08
        table_type: type of partition table to use
Packit Service a04d08
        device: the device to work on
Packit Service a04d08
        layout: layout definition specific to partition table
Packit Service a04d08
    """
Packit Service a04d08
    return get_dyn_func("exec_mkpart_%s", table_type, device, layout)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def assert_and_settle_device(device):
Packit Service a04d08
    """Assert that device exists and settle so it is fully recognized."""
Packit Service a04d08
    if not os.path.exists(device):
Packit Service a04d08
        util.udevadm_settle()
Packit Service a04d08
        if not os.path.exists(device):
Packit Service a04d08
            raise RuntimeError("Device %s did not exist and was not created "
Packit Service a04d08
                               "with a udevadm settle." % device)
Packit Service a04d08
Packit Service a04d08
    # Whether or not the device existed above, it is possible that udev
Packit Service a04d08
    # events that would populate udev database (for reading by lsdname) have
Packit Service a04d08
    # not yet finished. So settle again.
Packit Service a04d08
    util.udevadm_settle()
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def mkpart(device, definition):
Packit Service a04d08
    """
Packit Service a04d08
    Creates the partition table.
Packit Service a04d08
Packit Service a04d08
    Parameters:
Packit Service a04d08
        definition: dictionary describing how to create the partition.
Packit Service a04d08
Packit Service a04d08
            The following are supported values in the dict:
Packit Service a04d08
                overwrite: Should the partition table be created regardless
Packit Service a04d08
                            of any pre-exisiting data?
Packit Service a04d08
                layout: the layout of the partition table
Packit Service a04d08
                table_type: Which partition table to use, defaults to MBR
Packit Service a04d08
                device: the device to work on.
Packit Service a04d08
    """
Packit Service a04d08
    # ensure that we get a real device rather than a symbolic link
Packit Service a04d08
    assert_and_settle_device(device)
Packit Service a04d08
    device = os.path.realpath(device)
Packit Service a04d08
Packit Service a04d08
    LOG.debug("Checking values for %s definition", device)
Packit Service a04d08
    overwrite = definition.get('overwrite', False)
Packit Service a04d08
    layout = definition.get('layout', False)
Packit Service a04d08
    table_type = definition.get('table_type', 'mbr')
Packit Service a04d08
Packit Service a04d08
    # Check if the default device is a partition or not
Packit Service a04d08
    LOG.debug("Checking against default devices")
Packit Service a04d08
Packit Service a04d08
    if (isinstance(layout, bool) and not layout) or not layout:
Packit Service a04d08
        LOG.debug("Device is not to be partitioned, skipping")
Packit Service a04d08
        return  # Device is not to be partitioned
Packit Service a04d08
Packit Service a04d08
    # This prevents you from overwriting the device
Packit Service a04d08
    LOG.debug("Checking if device %s is a valid device", device)
Packit Service a04d08
    if not is_device_valid(device):
Packit Service a04d08
        raise Exception(
Packit Service a04d08
            'Device {device} is not a disk device!'.format(device=device))
Packit Service a04d08
Packit Service a04d08
    # Remove the partition table entries
Packit Service a04d08
    if isinstance(layout, str) and layout.lower() == "remove":
Packit Service a04d08
        LOG.debug("Instructed to remove partition table entries")
Packit Service a04d08
        purge_disk(device)
Packit Service a04d08
        return
Packit Service a04d08
Packit Service a04d08
    LOG.debug("Checking if device layout matches")
Packit Service a04d08
    if check_partition_layout(table_type, device, layout):
Packit Service a04d08
        LOG.debug("Device partitioning layout matches")
Packit Service a04d08
        return True
Packit Service a04d08
Packit Service a04d08
    LOG.debug("Checking if device is safe to partition")
Packit Service a04d08
    if not overwrite and (is_disk_used(device) or is_filesystem(device)):
Packit Service a04d08
        LOG.debug("Skipping partitioning on configured device %s", device)
Packit Service a04d08
        return
Packit Service a04d08
Packit Service a04d08
    LOG.debug("Checking for device size of %s", device)
Packit Service a04d08
    device_size = get_hdd_size(device)
Packit Service a04d08
Packit Service a04d08
    LOG.debug("Calculating partition layout")
Packit Service a04d08
    part_definition = get_partition_layout(table_type, device_size, layout)
Packit Service a04d08
    LOG.debug("   Layout is: %s", part_definition)
Packit Service a04d08
Packit Service a04d08
    LOG.debug("Creating partition table on %s", device)
Packit Service a04d08
    exec_mkpart(table_type, device, part_definition)
Packit Service a04d08
Packit Service a04d08
    LOG.debug("Partition table created for %s", device)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def lookup_force_flag(fs):
Packit Service a04d08
    """
Packit Service a04d08
    A force flag might be -F or -F, this look it up
Packit Service a04d08
    """
Packit Service a04d08
    flags = {
Packit Service a04d08
        'ext': '-F',
Packit Service a04d08
        'btrfs': '-f',
Packit Service a04d08
        'xfs': '-f',
Packit Service a04d08
        'reiserfs': '-f',
Packit Service 751c4a
        'swap': '-f',
Packit Service a04d08
    }
Packit Service a04d08
Packit Service a04d08
    if 'ext' in fs.lower():
Packit Service a04d08
        fs = 'ext'
Packit Service a04d08
Packit Service a04d08
    if fs.lower() in flags:
Packit Service a04d08
        return flags[fs]
Packit Service a04d08
Packit Service a04d08
    LOG.warning("Force flag for %s is unknown.", fs)
Packit Service a04d08
    return ''
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def mkfs(fs_cfg):
Packit Service a04d08
    """
Packit Service a04d08
    Create a file system on the device.
Packit Service a04d08
Packit Service a04d08
        label: defines the label to use on the device
Packit Service a04d08
        fs_cfg: defines how the filesystem is to look
Packit Service a04d08
            The following values are required generally:
Packit Service a04d08
                device: which device or cloud defined default_device
Packit Service a04d08
                filesystem: which file system type
Packit Service a04d08
                overwrite: indiscriminately create the file system
Packit Service a04d08
                partition: when device does not define a partition,
Packit Service a04d08
                            setting this to a number will mean
Packit Service a04d08
                            device + partition. When set to 'auto', the
Packit Service a04d08
                            first free device or the first device which
Packit Service a04d08
                            matches both label and type will be used.
Packit Service a04d08
Packit Service a04d08
                            'any' means the first filesystem that matches
Packit Service a04d08
                            on the device.
Packit Service a04d08
Packit Service a04d08
            When 'cmd' is provided then no other parameter is required.
Packit Service a04d08
    """
Packit Service a04d08
    label = fs_cfg.get('label')
Packit Service a04d08
    device = fs_cfg.get('device')
Packit Service a04d08
    partition = str(fs_cfg.get('partition', 'any'))
Packit Service a04d08
    fs_type = fs_cfg.get('filesystem')
Packit Service a04d08
    fs_cmd = fs_cfg.get('cmd', [])
Packit Service a04d08
    fs_opts = fs_cfg.get('extra_opts', [])
Packit Service a04d08
    fs_replace = fs_cfg.get('replace_fs', False)
Packit Service a04d08
    overwrite = fs_cfg.get('overwrite', False)
Packit Service a04d08
Packit Service a04d08
    # ensure that we get a real device rather than a symbolic link
Packit Service a04d08
    assert_and_settle_device(device)
Packit Service a04d08
    device = os.path.realpath(device)
Packit Service a04d08
Packit Service a04d08
    # This allows you to define the default ephemeral or swap
Packit Service a04d08
    LOG.debug("Checking %s against default devices", device)
Packit Service a04d08
Packit Service a04d08
    if not partition or partition.isdigit():
Packit Service a04d08
        # Handle manual definition of partition
Packit Service a04d08
        if partition.isdigit():
Packit Service a04d08
            device = "%s%s" % (device, partition)
Packit Service a04d08
            LOG.debug("Manual request of partition %s for %s",
Packit Service a04d08
                      partition, device)
Packit Service a04d08
Packit Service a04d08
        # Check to see if the fs already exists
Packit Service a04d08
        LOG.debug("Checking device %s", device)
Packit Service a04d08
        check_label, check_fstype, _ = check_fs(device)
Packit Service a04d08
        LOG.debug("Device '%s' has check_label='%s' check_fstype=%s",
Packit Service a04d08
                  device, check_label, check_fstype)
Packit Service a04d08
Packit Service a04d08
        if check_label == label and check_fstype == fs_type:
Packit Service a04d08
            LOG.debug("Existing file system found at %s", device)
Packit Service a04d08
Packit Service a04d08
            if not overwrite:
Packit Service a04d08
                LOG.debug("Device %s has required file system", device)
Packit Service a04d08
                return
Packit Service a04d08
            else:
Packit Service a04d08
                LOG.warning("Destroying filesystem on %s", device)
Packit Service a04d08
Packit Service a04d08
        else:
Packit Service a04d08
            LOG.debug("Device %s is cleared for formating", device)
Packit Service a04d08
Packit Service a04d08
    elif partition and str(partition).lower() in ('auto', 'any'):
Packit Service a04d08
        # For auto devices, we match if the filesystem does exist
Packit Service a04d08
        odevice = device
Packit Service a04d08
        LOG.debug("Identifying device to create %s filesytem on", label)
Packit Service a04d08
Packit Service a04d08
        # any mean pick the first match on the device with matching fs_type
Packit Service a04d08
        label_match = True
Packit Service a04d08
        if partition.lower() == 'any':
Packit Service a04d08
            label_match = False
Packit Service a04d08
Packit Service a04d08
        device, reuse = find_device_node(device, fs_type=fs_type, label=label,
Packit Service a04d08
                                         label_match=label_match,
Packit Service a04d08
                                         replace_fs=fs_replace)
Packit Service a04d08
        LOG.debug("Automatic device for %s identified as %s", odevice, device)
Packit Service a04d08
Packit Service a04d08
        if reuse:
Packit Service a04d08
            LOG.debug("Found filesystem match, skipping formating.")
Packit Service a04d08
            return
Packit Service a04d08
Packit Service a04d08
        if not reuse and fs_replace and device:
Packit Service a04d08
            LOG.debug("Replacing file system on %s as instructed.", device)
Packit Service a04d08
Packit Service a04d08
        if not device:
Packit Service a04d08
            LOG.debug("No device aviable that matches request. "
Packit Service a04d08
                      "Skipping fs creation for %s", fs_cfg)
Packit Service a04d08
            return
Packit Service a04d08
    elif not partition or str(partition).lower() == 'none':
Packit Service a04d08
        LOG.debug("Using the raw device to place filesystem %s on", label)
Packit Service a04d08
Packit Service a04d08
    else:
Packit Service a04d08
        LOG.debug("Error in device identification handling.")
Packit Service a04d08
        return
Packit Service a04d08
Packit Service a04d08
    LOG.debug("File system type '%s' with label '%s' will be created on %s",
Packit Service a04d08
              fs_type, label, device)
Packit Service a04d08
Packit Service a04d08
    # Make sure the device is defined
Packit Service a04d08
    if not device:
Packit Service a04d08
        LOG.warning("Device is not known: %s", device)
Packit Service a04d08
        return
Packit Service a04d08
Packit Service a04d08
    # Check that we can create the FS
Packit Service a04d08
    if not (fs_type or fs_cmd):
Packit Service a04d08
        raise Exception(
Packit Service a04d08
            "No way to create filesystem '{label}'. fs_type or fs_cmd "
Packit Service a04d08
            "must be set.".format(label=label))
Packit Service a04d08
Packit Service a04d08
    # Create the commands
Packit Service a04d08
    shell = False
Packit Service a04d08
    if fs_cmd:
Packit Service a04d08
        fs_cmd = fs_cfg['cmd'] % {
Packit Service a04d08
            'label': label,
Packit Service a04d08
            'filesystem': fs_type,
Packit Service a04d08
            'device': device,
Packit Service a04d08
        }
Packit Service a04d08
        shell = True
Packit Service a04d08
Packit Service a04d08
        if overwrite:
Packit Service a04d08
            LOG.warning(
Packit Service a04d08
                "fs_setup:overwrite ignored because cmd was specified: %s",
Packit Service a04d08
                fs_cmd)
Packit Service a04d08
        if fs_opts:
Packit Service a04d08
            LOG.warning(
Packit Service a04d08
                "fs_setup:extra_opts ignored because cmd was specified: %s",
Packit Service a04d08
                fs_cmd)
Packit Service a04d08
    else:
Packit Service a04d08
        # Find the mkfs command
Packit Service 751c4a
        mkfs_cmd = subp.which("mkfs.%s" % fs_type)
Packit Service a04d08
        if not mkfs_cmd:
Packit Service 751c4a
            mkfs_cmd = subp.which("mk%s" % fs_type)
Packit Service a04d08
Packit Service a04d08
        if not mkfs_cmd:
Packit Service a04d08
            LOG.warning("Cannot create fstype '%s'.  No mkfs.%s command",
Packit Service a04d08
                        fs_type, fs_type)
Packit Service a04d08
            return
Packit Service a04d08
Packit Service a04d08
        fs_cmd = [mkfs_cmd, device]
Packit Service a04d08
Packit Service a04d08
        if label:
Packit Service a04d08
            fs_cmd.extend(["-L", label])
Packit Service a04d08
Packit Service a04d08
        # File systems that support the -F flag
Packit Service a04d08
        if overwrite or device_type(device) == "disk":
Packit Service 751c4a
            force_flag = lookup_force_flag(fs_type)
Packit Service 751c4a
            if force_flag:
Packit Service 751c4a
                fs_cmd.append(force_flag)
Packit Service a04d08
Packit Service a04d08
        # Add the extends FS options
Packit Service a04d08
        if fs_opts:
Packit Service a04d08
            fs_cmd.extend(fs_opts)
Packit Service a04d08
Packit Service a04d08
    LOG.debug("Creating file system %s on %s", label, device)
Packit Service a04d08
    LOG.debug("     Using cmd: %s", str(fs_cmd))
Packit Service a04d08
    try:
Packit Service 751c4a
        subp.subp(fs_cmd, shell=shell)
Packit Service a04d08
    except Exception as e:
Packit Service 751c4a
        raise Exception("Failed to exec of '%s':\n%s" % (fs_cmd, e)) from e
Packit Service a04d08
Packit Service a04d08
# vi: ts=4 expandtab