Exemple #1
0
def uefi_remove_old_loaders(grubcfg, target):
    """Removes the old UEFI loaders from efibootmgr."""
    efi_output = util.get_efibootmgr(target)
    current_uefi_boot = efi_output.get('current', None)
    old_efi_entries = {
        entry: info
        for entry, info in efi_output['entries'].items()
        if re.match(r'^.*File\(\\EFI.*$', info['path'])
    }
    old_efi_entries.pop(current_uefi_boot, None)
    remove_old_loaders = grubcfg.get('remove_old_uefi_loaders', True)
    if old_efi_entries:
        if remove_old_loaders:
            with util.ChrootableTarget(target) as in_chroot:
                for entry, info in old_efi_entries.items():
                    LOG.debug("removing old UEFI entry: %s" % info['name'])
                    in_chroot.subp(['efibootmgr', '-B', '-b', entry],
                                   capture=True)
        else:
            LOG.debug("Skipped removing %d old UEFI entrie%s.",
                      len(old_efi_entries),
                      '' if len(old_efi_entries) == 1 else 's')
            for info in old_efi_entries.values():
                LOG.debug(
                    "UEFI entry '%s' might no longer exist and "
                    "should be removed.", info['name'])
Exemple #2
0
def apt_command(args):
    """ Main entry point for curtin apt-config standalone command
        This does not read the global config as handled by curthooks, but
        instead one can specify a different "target" and a new cfg via --config
        """
    cfg = config.load_command_config(args, {})

    if args.target is not None:
        target = args.target
    else:
        state = util.load_command_environment()
        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)

    apt_cfg = cfg.get("apt")
    # if no apt config section is available, do nothing
    if apt_cfg is not None:
        LOG.debug("Handling apt to target %s with config %s", target, apt_cfg)
        try:
            with util.ChrootableTarget(target, sys_resolvconf=True):
                handle_apt(apt_cfg, target)
        except (RuntimeError, TypeError, ValueError, IOError):
            LOG.exception("Failed to configure apt features '%s'", apt_cfg)
            sys.exit(1)
    else:
        LOG.info("No apt config provided, skipping")

    sys.exit(0)
Exemple #3
0
def uefi_reorder_loaders(grubcfg, target):
    """Reorders the UEFI BootOrder to place BootCurrent first.

    The specifically doesn't try to do to much. The order in which grub places
    a new EFI loader is up to grub. This only moves the BootCurrent to the
    front of the BootOrder.
    """
    if grubcfg.get('reorder_uefi', True):
        efi_output = util.get_efibootmgr(target)
        currently_booted = efi_output.get('current', None)
        boot_order = efi_output.get('order', [])
        if currently_booted:
            if currently_booted in boot_order:
                boot_order.remove(currently_booted)
            boot_order = [currently_booted] + boot_order
            new_boot_order = ','.join(boot_order)
            LOG.debug(
                "Setting currently booted %s as the first "
                "UEFI loader.", currently_booted)
            LOG.debug("New UEFI boot order: %s", new_boot_order)
            with util.ChrootableTarget(target) as in_chroot:
                in_chroot.subp(['efibootmgr', '-o', new_boot_order])
    else:
        LOG.debug("Skipped reordering of UEFI boot methods.")
        LOG.debug("Currently booted UEFI loader might no longer boot.")
Exemple #4
0
 def test_chrootable_target_default_mounts_uefi(self, m_uefi):
     m_uefi.return_value = True
     in_chroot = util.ChrootableTarget("mytarget")
     default_mounts = [
         '/dev', '/proc', '/run', '/sys', '/sys/firmware/efi/efivars'
     ]
     self.assertEqual(sorted(default_mounts), sorted(in_chroot.mounts))
Exemple #5
0
def in_target_main(args):
    if args.target is not None:
        target = args.target
    else:
        state = util.load_command_environment()
        target = state['target']

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

    daemons = args.allow_daemons
    if paths.target_path(args.target) == "/":
        sys.stderr.write("WARN: Target is /, daemons are allowed.\n")
        daemons = True
    cmd = args.command_args
    with util.ChrootableTarget(target, allow_daemons=daemons) as chroot:
        exit = 0
        if not args.interactive:
            try:
                chroot.subp(cmd, capture=args.capture)
            except util.ProcessExecutionError as e:
                exit = e.exit_code
        else:
            if chroot.target != "/":
                cmd = ["chroot", chroot.target] + args.command_args

            # in python 3.4 pty.spawn started returning a value.
            # There, it is the status from os.waitpid.  From testing (py3.6)
            # that seemse to be exit_code * 256.
            ret = pty.spawn(cmd)  # pylint: disable=E1111
            if ret is not None:
                exit = int(ret / 256)
        sys.exit(exit)
Exemple #6
0
def rpm_get_dist_id(target):
    """Use rpm command to extract the '%rhel' distro macro which returns
       the major os version id (6, 7, 8).  This works for centos or rhel
    """
    with util.ChrootableTarget(target) as in_chroot:
        dist, _ = in_chroot.subp(['rpm', '-E', '%rhel'], capture=True)
    return dist.rstrip()
Exemple #7
0
    def test_skip_rename_resolvconf_gone(self, m_rename):
        self.m_shutil.copy.side_effect = self.mycopy
        self.m_shutil.rmtree.side_effect = self.mydel
        with util.ChrootableTarget(self.target):
            tp = paths.target_path(self.target, path='/etc/resolv.conf')
            target_conf = util.load_file(tp)
            self.assertEqual(self.host_content, target_conf)

        self.assertEqual(0, m_rename.call_count)
Exemple #8
0
    def test_chrootable_target_renames_and_copies_resolvconf_if_symlink(self):
        target_rconf = os.path.join(self.target, 'etc/resolv.conf')
        os.symlink('../run/foobar/wark.conf', target_rconf)

        self.m_shutil.copy.side_effect = self.mycopy
        self.m_shutil.rmtree.side_effect = self.mydel
        with util.ChrootableTarget(self.target):
            target_conf = util.load_file(
                paths.target_path(self.target, path='/etc/resolv.conf'))
            self.assertEqual(self.host_content, target_conf)
Exemple #9
0
    def test_chrootable_target_renames_and_copies_resolvconf(self):
        content = "target_resolvconf"
        util.write_file(os.path.join(self.target, 'etc/resolv.conf'), content)

        self.m_shutil.copy.side_effect = self.mycopy
        self.m_shutil.rmtree.side_effect = self.mydel

        with util.ChrootableTarget(self.target):
            target_conf = util.load_file(
                paths.target_path(self.target, path='/etc/resolv.conf'))
            self.assertEqual(self.host_content, target_conf)
Exemple #10
0
    def test_chrootable_target_restores_resolvconf_on_copy_fail(self):
        content = "target_resolvconf"
        tconf = os.path.join(self.target, 'etc/resolv.conf')
        util.write_file(tconf, content)

        self.m_shutil.copy.side_effect = OSError('Failed to copy')
        self.m_shutil.rmtree.side_effect = self.mydel

        try:
            with util.ChrootableTarget(self.target):
                pass
        except OSError:
            pass

        target_conf = util.load_file(tconf)
        self.assertEqual(content, target_conf)
Exemple #11
0
def install_grub(devices, target, uefi=None, grubcfg=None):
    """Install grub to devices inside target chroot.

    :param: devices: List of block device paths to install grub upon.
    :param: target: A string specifying the path to the chroot mountpoint.
    :param: uefi: A boolean set to True if system is UEFI bootable otherwise
                  False.
    :param: grubcfg: An config dict with grub config options.
    """

    if not devices:
        raise ValueError("Invalid parameter 'devices': %s" % devices)

    if not target:
        raise ValueError("Invalid parameter 'target': %s" % target)

    LOG.debug("installing grub to target=%s devices=%s [replace_defaults=%s]",
              target, devices, grubcfg.get('replace_default'))
    update_nvram = config.value_as_boolean(grubcfg.get('update_nvram', True))
    distroinfo = distro.get_distroinfo(target=target)
    target_arch = distro.get_architecture(target=target)
    rhel_ver = (distro.rpm_get_dist_id(target)
                if distroinfo.family == distro.DISTROS.redhat else None)

    check_target_arch_machine(target, arch=target_arch, uefi=uefi)
    grub_name, grub_target = get_grub_package_name(target_arch, uefi, rhel_ver)
    grub_conf = get_grub_config_file(target, distroinfo.family)
    new_params = get_carryover_params(distroinfo)
    prepare_grub_dir(target, grub_conf)
    write_grub_config(target, grubcfg, grub_conf, new_params)
    grub_cmd = get_grub_install_command(uefi, distroinfo, target)
    if uefi:
        install_cmds, post_cmds = gen_uefi_install_commands(
            grub_name, grub_target, grub_cmd, update_nvram, distroinfo,
            devices, target)
    else:
        install_cmds, post_cmds = gen_install_commands(grub_name, grub_cmd,
                                                       distroinfo, devices,
                                                       rhel_ver)

    env = os.environ.copy()
    env['DEBIAN_FRONTEND'] = 'noninteractive'

    LOG.debug('Grub install cmds:\n%s', str(install_cmds + post_cmds))
    with util.ChrootableTarget(target) as in_chroot:
        for cmd in install_cmds + post_cmds:
            in_chroot.subp(cmd, env=env, capture=True)
Exemple #12
0
def netconfig_passthrough_available(target, feature='NETWORK_CONFIG_V2'):
    """
    Determine if curtin can pass v2 network config to in target cloud-init
    """
    LOG.debug('Checking in-target cloud-init for feature: %s', feature)
    with util.ChrootableTarget(target) as in_chroot:

        cloudinit = util.which('cloud-init', target=target)
        if not cloudinit:
            LOG.warning('Target does not have cloud-init installed')
            return False

        available = False
        try:
            out, _ = in_chroot.subp([cloudinit, 'features'], capture=True)
            available = feature in out.splitlines()
        except util.ProcessExecutionError:
            # we explicitly don't dump the exception as this triggers
            # vmtest failures when parsing the installation log file
            LOG.warning("Failed to probe cloudinit features")
            return False

        LOG.debug('cloud-init feature %s available? %s', feature, available)
        return available
Exemple #13
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)
Exemple #14
0
def centos_apply_network_config(netcfg, target=None):
    """ CentOS images execute built-in curthooks which only supports
        simple networking configuration.  This hook enables advanced
        network configuration via config passthrough to the target.
    """
    def cloud_init_repo(version):
        if not version:
            raise ValueError('Missing required version parameter')

        return CLOUD_INIT_YUM_REPO_TEMPLATE % version

    if netcfg:
        LOG.info('Removing embedded network configuration (if present)')
        ifcfgs = glob.glob(
            util.target_path(target, 'etc/sysconfig/network-scripts') +
            '/ifcfg-*')
        # remove ifcfg-* (except ifcfg-lo)
        for ifcfg in ifcfgs:
            if os.path.basename(ifcfg) != "ifcfg-lo":
                util.del_file(ifcfg)

        LOG.info(
            'Checking cloud-init in target [%s] for network '
            'configuration passthrough support.', target)
        passthrough = net.netconfig_passthrough_available(target)
        LOG.debug('passthrough available via in-target: %s', passthrough)

        # if in-target cloud-init is not updated, upgrade via cloud-init repo
        if not passthrough:
            cloud_init_yum_repo = (util.target_path(
                target, 'etc/yum.repos.d/curtin-cloud-init.repo'))
            # Inject cloud-init daily yum repo
            util.write_file(cloud_init_yum_repo,
                            content=cloud_init_repo(rpm_get_dist_id(target)))

            # we separate the installation of repository packages (epel,
            # cloud-init-el-release) as we need a new invocation of yum
            # to read the newly installed repo files.
            YUM_CMD = ['yum', '-y', '--noplugins', 'install']
            retries = [1] * 30
            with util.ChrootableTarget(target) as in_chroot:
                # ensure up-to-date ca-certificates to handle https mirror
                # connections
                in_chroot.subp(YUM_CMD + ['ca-certificates'],
                               capture=True,
                               log_captured=True,
                               retries=retries)
                in_chroot.subp(YUM_CMD + ['epel-release'],
                               capture=True,
                               log_captured=True,
                               retries=retries)
                in_chroot.subp(YUM_CMD + ['cloud-init-el-release'],
                               log_captured=True,
                               capture=True,
                               retries=retries)
                in_chroot.subp(YUM_CMD + ['cloud-init'],
                               capture=True,
                               log_captured=True,
                               retries=retries)

            # remove cloud-init el-stable bootstrap repo config as the
            # cloud-init-el-release package points to the correct repo
            util.del_file(cloud_init_yum_repo)

            # install bridge-utils if needed
            with util.ChrootableTarget(target) as in_chroot:
                try:
                    in_chroot.subp(['rpm', '-q', 'bridge-utils'],
                                   capture=False,
                                   rcs=[0])
                except util.ProcessExecutionError:
                    LOG.debug('Image missing bridge-utils package, installing')
                    in_chroot.subp(YUM_CMD + ['bridge-utils'],
                                   capture=True,
                                   log_captured=True,
                                   retries=retries)

    LOG.info('Passing network configuration through to target')
    net.render_netconfig_passthrough(target, netconfig={'network': netcfg})
Exemple #15
0
def update_initramfs(target=None, all_kernels=False):
    cmd = ['update-initramfs', '-u']
    if all_kernels:
        cmd.extend(['-k', 'all'])
    with util.ChrootableTarget(target) as in_chroot:
        in_chroot.subp(cmd)
Exemple #16
0
 def test_chrootable_target_custom_mounts(self):
     my_mounts = ['/foo', '/bar', '/wark']
     in_chroot = util.ChrootableTarget("mytarget", mounts=my_mounts)
     self.assertEqual(sorted(my_mounts), sorted(in_chroot.mounts))
Exemple #17
0
def run_zipl(cfg, target):
    if platform.machine() != 's390x':
        return
    with util.ChrootableTarget(target) as in_chroot:
        in_chroot.subp(['zipl'])
Exemple #18
0
def add_apt_sources(srcdict,
                    target=None,
                    template_params=None,
                    aa_repo_match=None):
    """
    add entries in /etc/apt/sources.list.d for each abbreviated
    sources.list entry in 'srcdict'.  When rendering template, also
    include the values in dictionary searchList
    """
    if template_params is None:
        template_params = {}

    if aa_repo_match is None:
        raise ValueError('did not get a valid repo matcher')

    if not isinstance(srcdict, dict):
        raise TypeError('unknown apt format: %s' % (srcdict))

    for filename in srcdict:
        ent = srcdict[filename]
        if 'filename' not in ent:
            ent['filename'] = filename

        add_apt_key(ent['filename'], ent, target)

        if 'source' not in ent:
            continue
        source = ent['source']
        if source == 'proposed':
            source = APT_SOURCES_PROPOSED
        source = util.render_string(source, template_params)

        if not ent['filename'].startswith("/"):
            ent['filename'] = os.path.join("/etc/apt/sources.list.d/",
                                           ent['filename'])
        if not ent['filename'].endswith(".list"):
            ent['filename'] += ".list"

        if aa_repo_match(source):
            with util.ChrootableTarget(target,
                                       sys_resolvconf=True) as in_chroot:
                try:
                    in_chroot.subp(["add-apt-repository", source],
                                   retries=(1, 2, 5, 10))
                except util.ProcessExecutionError:
                    LOG.exception("add-apt-repository failed.")
                    raise
            continue

        sourcefn = paths.target_path(target, ent['filename'])
        try:
            contents = "%s\n" % (source)
            util.write_file(sourcefn, contents, omode="a")
        except IOError as detail:
            LOG.exception("failed write to file %s: %s", sourcefn, detail)
            raise

    distro.apt_update(target=target,
                      force=True,
                      comment="apt-source changed config")

    return
Exemple #19
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)
Exemple #20
0
 def test_chrootable_target_default_mounts(self):
     in_chroot = util.ChrootableTarget("mytarget")
     default_mounts = ['/dev', '/proc', '/run', '/sys']
     self.assertEqual(sorted(default_mounts), sorted(in_chroot.mounts))
Exemple #21
0
 def test_chrootable_target_no_mounts(self):
     my_mounts = []
     in_chroot = util.ChrootableTarget("mytarget", mounts=my_mounts)
     self.assertEqual(sorted(my_mounts), sorted(in_chroot.mounts))