예제 #1
0
def main():
    state = util.load_command_environment()
    target = state['target']
    if target is None:
        print("Target was not provided in the environment.")
        sys.exit(1)
    fstab = state['fstab']
    if fstab is None:
        print("/etc/fstab output was not provided in the environment.")
        sys.exit(1)
    bootmac = get_boot_mac()
    if bootmac is None:
        print("Unable to determine boot interface.")
        sys.exit(1)
    devices = get_block_devices(target)
    if not devices:
        print("Unable to find block device for: %s" % target)
        sys.exit(1)

    write_fstab(target, fstab)

    update_grub_default(target, extra=get_extra_kernel_parameters())
    grub2_mkconfig(target)
    if util.is_uefi_bootable():
        uefi_part = get_uefi_partition()
        if uefi_part is None:
            print('Unable to determine UEFI parition.')
            sys.exit(1)
        install_efi(target, uefi_part['device_path'])
    else:
        for dev in devices:
            grub2_install(target, dev)

    set_autorelabel(target)
    write_network_config(target, bootmac)
예제 #2
0
def write_fstab(target, curtin_fstab):
    """Writes the new fstab, using the fstab provided
    from curtin."""
    fstab_path = os.path.join(target, 'etc', 'fstab')
    fstab_data = read_file(curtin_fstab)
    with open(fstab_path, 'w') as stream:
        stream.write(FSTAB_PREPEND)
        stream.write(fstab_data)
        if util.is_uefi_bootable():
            stream.write(FSTAB_UEFI)
예제 #3
0
def get_flash_kernel_pkgs(arch=None, uefi=None):
    if arch is None:
        arch = util.get_architecture()
    if uefi is None:
        uefi = util.is_uefi_bootable()
    if uefi:
        return None
    if not arch.startswith('arm'):
        return None

    try:
        fk_packages, _ = util.subp(['list-flash-kernel-packages'],
                                   capture=True)
        return fk_packages
    except util.ProcessExecutionError:
        # Ignore errors
        return None
예제 #4
0
def install_grub_main(args):
    state = util.load_command_environment()

    if args.target is not None:
        target = args.target
    else:
        target = state['target']

    if target is None:
        sys.stderr.write("Unable to find target.  "
                         "Use --target or set TARGET_MOUNT_POINT\n")
        sys.exit(2)

    cfg = config.load_command_config(args, state)
    stack_prefix = state.get('report_stack_prefix', '')
    uefi = util.is_uefi_bootable()
    grubcfg = cfg.get('grub')
    with events.ReportEventStack(
            name=stack_prefix,
            reporting_enabled=True,
            level="INFO",
            description="Installing grub to target devices"):
        install_grub(args.devices, target, uefi=uefi, grubcfg=grubcfg)
    sys.exit(0)
예제 #5
0
def curthooks(args):
    state = util.load_command_environment()

    if args.target is not None:
        target = args.target
    else:
        target = state['target']

    if target is None:
        sys.stderr.write("Unable to find target.  "
                         "Use --target or set TARGET_MOUNT_POINT\n")
        sys.exit(2)

    cfg = config.load_command_config(args, state)
    stack_prefix = state.get('report_stack_prefix', '')

    # if curtin-hooks hook exists in target we can defer to the in-target hooks
    if util.run_hook_if_exists(target, 'curtin-hooks'):
        # For vmtests to force execute centos_apply_network_config, uncomment
        # the value in examples/tests/centos_defaults.yaml
        if cfg.get('_ammend_centos_curthooks'):
            if cfg.get('cloudconfig'):
                handle_cloudconfig(cfg['cloudconfig'],
                                   base_dir=util.target_path(
                                       target, 'etc/cloud/cloud.cfg.d'))

            if target_is_centos(target) or target_is_rhel(target):
                LOG.info('Detected RHEL/CentOS image, running extra hooks')
                with events.ReportEventStack(
                        name=stack_prefix,
                        reporting_enabled=True,
                        level="INFO",
                        description="Configuring CentOS for first boot"):
                    centos_apply_network_config(cfg.get('network', {}), target)
        sys.exit(0)

    if target_is_ubuntu_core(target):
        LOG.info('Detected Ubuntu-Core image, running hooks')
        with events.ReportEventStack(
                name=stack_prefix,
                reporting_enabled=True,
                level="INFO",
                description="Configuring Ubuntu-Core for first boot"):
            ubuntu_core_curthooks(cfg, target)
        sys.exit(0)

    with events.ReportEventStack(
            name=stack_prefix + '/writing-config',
            reporting_enabled=True,
            level="INFO",
            description="configuring apt configuring apt"):
        do_apt_config(cfg, target)
        disable_overlayroot(cfg, target)

    # LP: #1742560 prevent zfs-dkms from being installed (Xenial)
    if util.lsb_release(target=target)['codename'] == 'xenial':
        util.apt_update(target=target)
        with util.ChrootableTarget(target) as in_chroot:
            in_chroot.subp(['apt-mark', 'hold', 'zfs-dkms'])

    # packages may be needed prior to installing kernel
    with events.ReportEventStack(name=stack_prefix +
                                 '/installing-missing-packages',
                                 reporting_enabled=True,
                                 level="INFO",
                                 description="installing missing packages"):
        install_missing_packages(cfg, target)

    # If a /etc/iscsi/nodes/... file was created by block_meta then it
    # needs to be copied onto the target system
    nodes_location = os.path.join(os.path.split(state['fstab'])[0], "nodes")
    if os.path.exists(nodes_location):
        copy_iscsi_conf(nodes_location, target)
        # do we need to reconfigure open-iscsi?

    # If a mdadm.conf file was created by block_meta than it needs to be copied
    # onto the target system
    mdadm_location = os.path.join(
        os.path.split(state['fstab'])[0], "mdadm.conf")
    if os.path.exists(mdadm_location):
        copy_mdadm_conf(mdadm_location, target)
        # as per https://bugs.launchpad.net/ubuntu/+source/mdadm/+bug/964052
        # reconfigure mdadm
        util.subp(['dpkg-reconfigure', '--frontend=noninteractive', 'mdadm'],
                  data=None,
                  target=target)

    with events.ReportEventStack(name=stack_prefix + '/installing-kernel',
                                 reporting_enabled=True,
                                 level="INFO",
                                 description="installing kernel"):
        setup_zipl(cfg, target)
        install_kernel(cfg, target)
        run_zipl(cfg, target)
        restore_dist_interfaces(cfg, target)

    with events.ReportEventStack(name=stack_prefix + '/setting-up-swap',
                                 reporting_enabled=True,
                                 level="INFO",
                                 description="setting up swap"):
        add_swap(cfg, target, state.get('fstab'))

    with events.ReportEventStack(name=stack_prefix +
                                 '/apply-networking-config',
                                 reporting_enabled=True,
                                 level="INFO",
                                 description="apply networking config"):
        apply_networking(target, state)

    with events.ReportEventStack(name=stack_prefix + '/writing-etc-fstab',
                                 reporting_enabled=True,
                                 level="INFO",
                                 description="writing etc/fstab"):
        copy_fstab(state.get('fstab'), target)

    with events.ReportEventStack(name=stack_prefix + '/configuring-multipath',
                                 reporting_enabled=True,
                                 level="INFO",
                                 description="configuring multipath"):
        detect_and_handle_multipath(cfg, target)

    with events.ReportEventStack(
            name=stack_prefix + '/system-upgrade',
            reporting_enabled=True,
            level="INFO",
            description="updating packages on target system"):
        system_upgrade(cfg, target)

    with events.ReportEventStack(
            name=stack_prefix + '/pollinate-user-agent',
            reporting_enabled=True,
            level="INFO",
            description="configuring pollinate user-agent on target system"):
        handle_pollinate_user_agent(cfg, target)

    # If a crypttab file was created by block_meta than it needs to be copied
    # onto the target system, and update_initramfs() needs to be run, so that
    # the cryptsetup hooks are properly configured on the installed system and
    # it will be able to open encrypted volumes at boot.
    crypttab_location = os.path.join(
        os.path.split(state['fstab'])[0], "crypttab")
    if os.path.exists(crypttab_location):
        copy_crypttab(crypttab_location, target)
        update_initramfs(target)

    # If udev dname rules were created, copy them to target
    udev_rules_d = os.path.join(state['scratch'], "rules.d")
    if os.path.isdir(udev_rules_d):
        copy_dname_rules(udev_rules_d, target)

    # As a rule, ARMv7 systems don't use grub. This may change some
    # day, but for now, assume no. They do require the initramfs
    # to be updated, and this also triggers boot loader setup via
    # flash-kernel.
    machine = platform.machine()
    if (machine.startswith('armv7') or machine.startswith('s390x')
            or machine.startswith('aarch64') and not util.is_uefi_bootable()):
        update_initramfs(target)
    else:
        setup_grub(cfg, target)

    sys.exit(0)
예제 #6
0
def setup_grub(cfg, target):
    # target is the path to the mounted filesystem

    # FIXME: these methods need moving to curtin.block
    # and using them from there rather than commands.block_meta
    from curtin.commands.block_meta import (extract_storage_ordered_dict,
                                            get_path_to_storage_volume)

    grubcfg = cfg.get('grub', {})

    # copy legacy top level name
    if 'grub_install_devices' in cfg and 'install_devices' not in grubcfg:
        grubcfg['install_devices'] = cfg['grub_install_devices']

    LOG.debug("setup grub on target %s", target)
    # if there is storage config, look for devices tagged with 'grub_device'
    storage_cfg_odict = None
    try:
        storage_cfg_odict = extract_storage_ordered_dict(cfg)
    except ValueError:
        pass

    if storage_cfg_odict:
        storage_grub_devices = []
        for item_id, item in storage_cfg_odict.items():
            if not item.get('grub_device'):
                continue
            LOG.debug("checking: %s", item)
            storage_grub_devices.append(
                get_path_to_storage_volume(item_id, storage_cfg_odict))
        if len(storage_grub_devices) > 0:
            grubcfg['install_devices'] = storage_grub_devices

    LOG.debug("install_devices: %s", grubcfg.get('install_devices'))
    if 'install_devices' in grubcfg:
        instdevs = grubcfg.get('install_devices')
        if isinstance(instdevs, str):
            instdevs = [instdevs]
        if instdevs is None:
            LOG.debug("grub installation disabled by config")
    else:
        # If there were no install_devices found then we try to do the right
        # thing.  That right thing is basically installing on all block
        # devices that are mounted.  On powerpc, though it means finding PrEP
        # partitions.
        devs = block.get_devices_for_mp(target)
        blockdevs = set()
        for maybepart in devs:
            try:
                (blockdev, part) = block.get_blockdev_for_partition(maybepart)
                blockdevs.add(blockdev)
            except ValueError:
                # if there is no syspath for this device such as a lvm
                # or raid device, then a ValueError is raised here.
                LOG.debug("failed to find block device for %s", maybepart)

        if platform.machine().startswith("ppc64"):
            # assume we want partitions that are 4100 (PReP). The snippet here
            # just prints the partition number partitions of that type.
            shnip = textwrap.dedent("""
                export LANG=C;
                for d in "$@"; do
                    sgdisk "$d" --print |
                        awk '$6 == prep { print d $1 }' "d=$d" prep=4100
                done
                """)
            try:
                out, err = util.subp(['sh', '-c', shnip, '--'] +
                                     list(blockdevs),
                                     capture=True)
                instdevs = str(out).splitlines()
                if not instdevs:
                    LOG.warn("No power grub target partitions found!")
                    instdevs = None
            except util.ProcessExecutionError as e:
                LOG.warn("Failed to find power grub partitions: %s", e)
                instdevs = None
        else:
            instdevs = list(blockdevs)

    # UEFI requires grub-efi-{arch}. If a signed version of that package
    # exists then it will be installed.
    if util.is_uefi_bootable():
        arch = util.get_architecture()
        pkgs = ['grub-efi-%s' % arch]

        # Architecture might support a signed UEFI loader
        uefi_pkg_signed = 'grub-efi-%s-signed' % arch
        if util.has_pkg_available(uefi_pkg_signed):
            pkgs.append(uefi_pkg_signed)

        # AMD64 has shim-signed for SecureBoot support
        if arch == "amd64":
            pkgs.append("shim-signed")

        # Install the UEFI packages needed for the architecture
        util.install_packages(pkgs, target=target)

    env = os.environ.copy()

    replace_default = grubcfg.get('replace_linux_default', True)
    if str(replace_default).lower() in ("0", "false"):
        env['REPLACE_GRUB_LINUX_DEFAULT'] = "0"
    else:
        env['REPLACE_GRUB_LINUX_DEFAULT'] = "1"

    if instdevs:
        instdevs = [block.get_dev_name_entry(i)[1] for i in instdevs]
    else:
        instdevs = ["none"]

    if util.is_uefi_bootable() and grubcfg.get('update_nvram', True):
        uefi_remove_old_loaders(grubcfg, target)

    LOG.debug("installing grub to %s [replace_default=%s]", instdevs,
              replace_default)
    with util.ChrootableTarget(target):
        args = ['install-grub']
        if util.is_uefi_bootable():
            args.append("--uefi")
            if grubcfg.get('update_nvram', True):
                LOG.debug("GRUB UEFI enabling NVRAM updates")
                args.append("--update-nvram")
            else:
                LOG.debug("NOT enabling UEFI nvram updates")
                LOG.debug("Target system may not boot")
        args.append(target)

        # capture stdout and stderr joined.
        join_stdout_err = ['sh', '-c', 'exec "$0" "$@" 2>&1']
        out, _err = util.subp(join_stdout_err + args + instdevs,
                              env=env,
                              capture=True)
        LOG.debug("%s\n%s\n", args, out)

    if util.is_uefi_bootable() and grubcfg.get('update_nvram', True):
        uefi_reorder_loaders(grubcfg, target)
예제 #7
0
REQUIRED_KERNEL_MODULES = [
    # kmod name
]

if lsb_release()['codename'] == "precise":
    REQUIRED_IMPORTS.append(('import oauth.oauth', 'python-oauth', None), )
else:
    REQUIRED_IMPORTS.append(
        ('import oauthlib.oauth1', 'python-oauthlib', 'python3-oauthlib'), )

# zfs is > trusty only
if not lsb_release()['codename'] in ["precise", "trusty"]:
    REQUIRED_EXECUTABLES.append(('zfs', 'zfsutils-linux'))
    REQUIRED_KERNEL_MODULES.append('zfs')

if not is_uefi_bootable() and 'arm' in get_architecture():
    REQUIRED_EXECUTABLES.append(('flash-kernel', 'flash-kernel'))


class MissingDeps(Exception):
    def __init__(self, message, deps):
        self.message = message
        if isinstance(deps, str) or deps is None:
            deps = [deps]
        self.deps = [d for d in deps if d is not None]
        self.fatal = None in deps

    def __str__(self):
        if self.fatal:
            if not len(self.deps):
                return self.message + " Unresolvable."