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)
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)
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
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)
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)
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)
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."