diff --git a/.gitignore b/.gitignore index aeaefa1..e50125c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ build/ .direnv/ .envrc +ass diff --git a/overlay.d/05core/etc/security/pwquality.conf.d/20-disable-dict.conf b/overlay.d/05core/etc/security/pwquality.conf.d/20-disable-dict.conf new file mode 100644 index 0000000..e946311 --- /dev/null +++ b/overlay.d/05core/etc/security/pwquality.conf.d/20-disable-dict.conf @@ -0,0 +1,3 @@ +# We don't ship cracklib dicts, so don't try to use them to validate +# password changes. +dictcheck = 0 diff --git a/overlay.d/05core/etc/sudoers.d/coreos-sudo-group b/overlay.d/05core/etc/sudoers.d/coreos-sudo-group new file mode 100644 index 0000000..2b3669d --- /dev/null +++ b/overlay.d/05core/etc/sudoers.d/coreos-sudo-group @@ -0,0 +1,2 @@ +# https://github.com/openshift/os/issues/96 +%sudo ALL=(ALL) NOPASSWD: ALL diff --git a/overlay.d/05core/statoverride b/overlay.d/05core/statoverride new file mode 100644 index 0000000..a726b7f --- /dev/null +++ b/overlay.d/05core/statoverride @@ -0,0 +1,7 @@ +# Config file for overriding permission bits on overlay files/dirs +# Format: = + +# sudo prefers its config files to be mode 440, and some security scanners +# complain if /etc/sudoers.d files are world-readable. +# https://bugzilla.redhat.com/show_bug.cgi?id=1981979 +=288 /etc/sudoers.d/coreos-sudo-group diff --git a/overlay.d/05core/usr/lib/NetworkManager/conf.d/20-client-id-from-mac.conf b/overlay.d/05core/usr/lib/NetworkManager/conf.d/20-client-id-from-mac.conf new file mode 100644 index 0000000..320ea4a --- /dev/null +++ b/overlay.d/05core/usr/lib/NetworkManager/conf.d/20-client-id-from-mac.conf @@ -0,0 +1,2 @@ +[connection] +ipv4.dhcp-client-id=mac diff --git a/overlay.d/05core/usr/lib/coreos/generator-lib.sh b/overlay.d/05core/usr/lib/coreos/generator-lib.sh new file mode 100644 index 0000000..dd19ad8 --- /dev/null +++ b/overlay.d/05core/usr/lib/coreos/generator-lib.sh @@ -0,0 +1,30 @@ +# File intended to be sourced by shell script generators shipped with CoreOS systems + +# Generators don't have logging right now +# https://github.com/systemd/systemd/issues/15638 +exec 1>/dev/kmsg; exec 2>&1 + +UNIT_DIR="${1:-/tmp}" + +have_karg() { + local arg="$1" + local cmdline=( $( "$initdir/etc/sysctl.d/10-dont-ratelimit-kmsg.conf" +} diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/01-secex.ign b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/01-secex.ign new file mode 100644 index 0000000..215c179 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/01-secex.ign @@ -0,0 +1,70 @@ +{ + "ignition": { + "version": "3.2.0" + }, + "storage": { + "disks": [ + { + "device": "${BOOTDEV}", + "partitions": [ + { + "label": "boot", + "number": 3 + }, + { + "label": "root", + "number": 4, + "resize": true, + "sizeMiB": 0 + }, + { + "number": 5, + "shouldExist": false, + "wipePartitionEntry": true + }, + { + "number": 6, + "shouldExist": false, + "wipePartitionEntry": true + } + ] + } + ], + "luks": [ + { + "device": "/dev/disk/by-partlabel/boot", + "label": "crypt_bootfs", + "name": "boot", + "options": [ + "--integrity", + "hmac-sha256" + ], + "wipeVolume": true + }, + { + "device": "/dev/disk/by-partlabel/root", + "label": "crypt_rootfs", + "name": "root", + "options": [ + "--integrity", + "hmac-sha256" + ], + "wipeVolume": true + } + ], + "filesystems": [ + { + "device": "/dev/mapper/boot", + "format": "ext4", + "label": "boot", + "wipeFilesystem": true + }, + { + "device": "/dev/mapper/root", + "format": "xfs", + "label": "root", + "wipeFilesystem": true + } + ] + } +} diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/80-coreos-boot-disk.rules b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/80-coreos-boot-disk.rules new file mode 100644 index 0000000..e56ee5b --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/80-coreos-boot-disk.rules @@ -0,0 +1,10 @@ +# CoreOS-specific symlink for boot disk + +ACTION!="add|change", GOTO="stable_boot_end" +SUBSYSTEM!="block", GOTO="stable_boot_end" + +ENV{DEVTYPE}=="disk" \ + , PROGRAM=="coreos-disk-contains-fs $name boot" \ + , SYMLINK+="disk/by-id/coreos-boot-disk" + +LABEL="stable_boot_end" diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-boot-edit.service b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-boot-edit.service new file mode 100644 index 0000000..bc2d9ec --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-boot-edit.service @@ -0,0 +1,32 @@ +# This unit will run late in the initrd process after Ignition is completed +# successfully and temporarily mount /boot read-write to make edits +# (e.g. removing firstboot networking configuration files if necessary). + +[Unit] +Description=CoreOS Boot Edit +ConditionPathExists=/usr/lib/initrd-release +OnFailure=emergency.target +OnFailureJobMode=isolate + +# Since we are mounting /boot, require the device first. This isn't strictly +# necessary since we run late, but on principle let's make clear the dependency. +Requires=dev-disk-by\x2dlabel-boot.device +After=dev-disk-by\x2dlabel-boot.device +# Start after Ignition has finished +After=ignition-files.service +# As above, this isn't strictly necessary, but on principle. +After=coreos-multipath-wait.target +# Finish before systemd starts tearing down services +Before=initrd.target +# initrd-parse-etc.service starts initrd-cleanup.service which will race +# with us completing before we get nuked. Need to get to the bottom of it, +# but for now we need this. +Before=initrd-parse-etc.service + +[Service] +Type=oneshot +ExecStart=/usr/sbin/coreos-boot-edit +RemainAfterExit=yes +# MountFlags=slave is so the umount of /boot is guaranteed to happen. +# /boot will only be mounted for the lifetime of the unit. +MountFlags=slave diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-boot-edit.sh b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-boot-edit.sh new file mode 100755 index 0000000..cf2e9c3 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-boot-edit.sh @@ -0,0 +1,45 @@ +#!/bin/bash +set -euo pipefail + +# For a description of how this is used, see `coreos-boot-edit.service`. + +cmdline=( $(/dev/kmsg; exec 2>&1 + +UNIT_DIR="${1:-/tmp}" + +cmdline=( $( "${UNIT_DIR}/coreos-ignition-setup-user.service.d/diskful.conf" <&2 + exit 1 + fi +else + /usr/bin/rdcore kargs --boot-device /dev/disk/by-label/boot --create-if-changed /run/coreos-kargs-reboot "$@" +fi diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-post-ignition-checks.service b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-post-ignition-checks.service new file mode 100644 index 0000000..e370822 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-post-ignition-checks.service @@ -0,0 +1,17 @@ +# This unit will run late in the initrd process after the Ignition files +# stage has completed successfully so that we may validate ignition changes + +[Unit] +Description=CoreOS Post Ignition Checks +ConditionPathExists=/usr/lib/initrd-release +OnFailure=emergency.target +OnFailureJobMode=isolate + +# Start after Ignition has finished creating files and before ignition umount +After=ignition-files.service +Before=ignition-complete.target + +[Service] +Type=oneshot +ExecStart=/usr/sbin/coreos-post-ignition-checks +RemainAfterExit=yes diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-post-ignition-checks.sh b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-post-ignition-checks.sh new file mode 100755 index 0000000..12a4926 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-post-ignition-checks.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# See coreos-post-ignition-checks.service for more information about this script +set -euo pipefail + +# Verify that GRUB password directives are only used when GRUB is being used +arch=$(uname -p) +# Butane sugar will tell ignition to mount /boot to /sysroot/boot. We can simply check if +# the file exists to see whether the check needs to be performed. +# It is possible that the user creates a config, which will mount /boot at a different path +# but that case is not officially supported. +if [ -f /sysroot/boot/grub2/user.cfg ]; then + # s390x does not use GRUB, ppcle64 uses petitboot with a GRUB config parser which does not support passwords + # So in both these cases, GRUB password is not supported + if grep -q password_pbkdf2 /sysroot/boot/grub2/user.cfg && [[ "$arch" =~ ^(s390x|ppc64le)$ ]]; then + echo "Ignition config provisioned a GRUB password, which is not supported on $arch" + exit 1 + fi +fi diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-teardown-initramfs.service b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-teardown-initramfs.service new file mode 100644 index 0000000..060530e --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-teardown-initramfs.service @@ -0,0 +1,38 @@ +# Clean up the initramfs networking on first boot +# so the real network is being brought up +# https://github.com/coreos/fedora-coreos-tracker/issues/394#issuecomment-599721763 + +[Unit] +Description=CoreOS Tear Down Initramfs +DefaultDependencies=false + +# We want to run the teardown after all other Ignition stages +# have run because some platforms (like Packet) do remote status +# reporting for each Ignition stage. Since we are tearing down +# the networking using an ExecStop we need to make sure we run +# the ExecStop *after* any other ignition*.service unit's ExecStop. +# The only other one right now is ignition-mount that has an ExecStop +# for doing an unmount. Since the ordering for ExecStop is the +# opposite of ExecStart we need to use `Before=ignition-mount.service`. +# https://github.com/coreos/fedora-coreos-tracker/issues/440 +Before=ignition-mount.service +Before=ignition-complete.target + +# Make sure ExecStop= runs before we switch root +Conflicts=initrd-switch-root.target umount.target +Before=initrd-switch-root.target + +OnFailure=emergency.target +OnFailureJobMode=isolate + +# If we are already heading towards emergency.target +# then don't try to stop this unit because it will fail +# when trying to access files in /sysroot/etc/. The failure +# is mostly harmless but having the extra error messages +# leads us away from the original problem. +IgnoreOnIsolate=true + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStop=/usr/sbin/coreos-teardown-initramfs diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-teardown-initramfs.sh b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-teardown-initramfs.sh new file mode 100755 index 0000000..bfc9320 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-teardown-initramfs.sh @@ -0,0 +1,240 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh + +set -euo pipefail + +# Load dracut libraries. Using getargbool() and getargs() from +# dracut-lib and ip_to_var() from net-lib +load_dracut_libs() { + # dracut is not friendly to set -eu + set +euo pipefail + type getargbool &>/dev/null || . /lib/dracut-lib.sh + type ip_to_var &>/dev/null || . /lib/net-lib.sh + set -euo pipefail +} + +dracut_func() { + # dracut is not friendly to set -eu + set +euo pipefail + "$@"; local rc=$? + set -euo pipefail + return $rc +} + +# Get the BOOTIF and rd.bootif kernel arguments from +# the kernel command line. +get_bootif_kargs() { + bootif_kargs="" + bootif_karg=$(dracut_func getarg BOOTIF) + if [ ! -z "$bootif_karg" ]; then + bootif_kargs+="BOOTIF=${bootif_karg}" + fi + rdbootif_karg=$(dracut_func getarg rd.bootif) + if [ ! -z "$rdbootif_karg" ]; then + bootif_kargs+=" rd.bootif=${rdbootif_karg}" + fi + echo $bootif_kargs +} + +# Determine if the generated NM connection profiles match the default +# that would be given to us if the user had provided no additional +# configuration. i.e. did the user give us any network configuration +# other than the default? We determine this by comparing the generated +# output of nm-initrd-generator with a new run of nm-initrd-generator. +# If it matches then it was the default, if not then the user provided +# something extra. +are_default_NM_configs() { + # pick up our CoreOS default networking kargs from the afterburn dropin + DEFAULT_KARGS_FILE=/usr/lib/systemd/system/afterburn-network-kargs.service.d/50-afterburn-network-kargs-default.conf + source <(grep -o 'AFTERBURN_NETWORK_KARGS_DEFAULT=.*' $DEFAULT_KARGS_FILE) + # Also pick up BOOTIF/rd.bootif kargs and apply them here. + # See https://github.com/coreos/fedora-coreos-tracker/issues/1048 + BOOTIF_KARGS=$(get_bootif_kargs) + # Make two dirs for storing files to use in the comparison + mkdir -p /run/coreos-teardown-initramfs/connections-compare-{1,2} + # Make another that's just a throwaway for the initrd-data-dir + mkdir -p /run/coreos-teardown-initramfs/initrd-data-dir + # Copy over the previously generated connection(s) profiles + cp /run/NetworkManager/system-connections/* \ + /run/coreos-teardown-initramfs/connections-compare-1/ + # Do a new run with the default input + /usr/libexec/nm-initrd-generator \ + -c /run/coreos-teardown-initramfs/connections-compare-2 \ + -i /run/coreos-teardown-initramfs/initrd-data-dir \ + -- $AFTERBURN_NETWORK_KARGS_DEFAULT $BOOTIF_KARGS + # remove unique identifiers from the files (so our diff can work) + sed -i '/^uuid=/d' /run/coreos-teardown-initramfs/connections-compare-{1,2}/* + # currently the output will differ based on whether rd.neednet=1 + # was part of the kargs. Let's ignore the single difference (wait-device-timeout) + sed -i '/^wait-device-timeout=/d' /run/coreos-teardown-initramfs/connections-compare-{1,2}/* + if diff -r -q /run/coreos-teardown-initramfs/connections-compare-{1,2}/; then + rc=0 # They are the default configs + else + rc=1 # They are not the defaults, user must have added configuration + fi + rm -rf /run/coreos-teardown-initramfs + return $rc +} + +# Propagate initramfs networking if desired. The policy here is: +# +# - If a networking configuration was provided before this point +# (most likely via Ignition) and exists in the real root then +# we do nothing and don't propagate any initramfs networking. +# - If a user did not provide any networking configuration +# then we'll propagate the initramfs networking configuration +# into the real root, but only if it's different than the NM +# defaults (trying dhcp/dhcp6 on everything). If it's just the +# defaults then we want to avoid a slight behavior diff between +# propagating configs and just booting with no configuration. See +# https://github.com/coreos/fedora-coreos-tracker/issues/696 +# +# See https://github.com/coreos/fedora-coreos-tracker/issues/394#issuecomment-599721173 +propagate_initramfs_networking() { + # Check for any real root config in the two locations where a user could have + # provided network configuration. On FCOS we only support keyfiles, but on RHCOS + # we support keyfiles and ifcfg. We also need to ignore readme-ifcfg-rh.txt + # which is a cosmetic file added in + # https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/commit/96d7362 + if [ -n "$(ls -A /sysroot/etc/NetworkManager/system-connections/)" -o \ + -n "$(ls -A -I readme-ifcfg-rh.txt /sysroot/etc/sysconfig/network-scripts/)" ]; then + echo "info: networking config is defined in the real root" + realrootconfig=1 + else + echo "info: no networking config is defined in the real root" + realrootconfig=0 + fi + + # Did the user tell us to force initramfs networking config + # propagation even if real root networking config exists? + # Hopefully we only need this in rare circumstances. + # https://github.com/coreos/fedora-coreos-tracker/issues/853 + forcepropagate=0 + if dracut_func getargbool 0 'coreos.force_persist_ip'; then + forcepropagate=1 + echo "info: coreos.force_persist_ip detected: will force network config propagation" + fi + + if [ $realrootconfig == 1 -a $forcepropagate == 0 ]; then + echo "info: will not attempt to propagate initramfs networking" + fi + + if [ $realrootconfig == 0 -o $forcepropagate == 1 ]; then + if [ -n "$(ls -A /run/NetworkManager/system-connections/)" ]; then + if are_default_NM_configs; then + echo "info: skipping propagation of default networking configs" + else + echo "info: propagating initramfs networking config to the real root" + cp -v /run/NetworkManager/system-connections/* /sysroot/etc/NetworkManager/system-connections/ + coreos-relabel /etc/NetworkManager/system-connections/ + fi + else + echo "info: no initramfs networking information to propagate" + fi + fi +} + +# Propagate the ip= karg hostname if desired. The policy here is: +# +# - IF a hostname was detected in ip= kargs by NetworkManager +# - AND no hostname was set via Ignition (realroot `/etc/hostname`) +# - THEN we make the hostname detected by NM apply permanently +# by writing it into `/etc/hostname` +# +propagate_initramfs_hostname() { + if [ -e '/sysroot/etc/hostname' ]; then + echo "info: hostname is defined in the real root" + echo "info: will not attempt to propagate initramfs hostname" + return 0 + fi + + # If any hostname was provided NetworkManager will write it out to + # /run/NetworkManager/initrd/hostname. See + # https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/481 + if [ -s /run/NetworkManager/initrd/hostname ]; then + hostname=$( /sysroot/etc/hostname + coreos-relabel /etc/hostname + else + echo "info: no initramfs hostname information to propagate" + fi +} + +down_interface() { + echo "info: taking down network device: $1" + # On recommendation from the NM team let's try to delete the device + # first and if that doesn't work then set it to down and flush any + # associated addresses. Deleting virtual devices (bonds, teams, bridges, + # ip-tunnels, etc) will clean up any associated kernel resources. A real + # device can't be deleted so that will fail and we'll fallback to setting + # it down and flushing addresses. + if ! ip link delete $1; then + ip link set $1 down + ip addr flush dev $1 + fi +} + +# Iterate through the interfaces in the machine and take them down. +# Note that in the futre we would like to possibly use `nmcli` networking off` +# for this. See the following two comments for details: +# https://github.com/coreos/fedora-coreos-tracker/issues/394#issuecomment-599721763 +# https://github.com/coreos/fedora-coreos-tracker/issues/394#issuecomment-599746049 +down_interfaces() { + if ! [ -z "$(ls /sys/class/net)" ]; then + for f in /sys/class/net/*; do + interface=$(basename "$f") + # The `bonding_masters` entry is not a true interface and thus + # cannot be taken down. Also skip local loopback + case "$interface" in + "lo" | "bonding_masters") + continue + ;; + esac + # When we start taking down devices some other devices can + # start to disappear (for example vlan on top of interface). + # If the device we're about to take down has disappeared + # since the start of this loop then skip taking it down. + if [ ! -e "$f" ]; then + echo "info: skipping teardown of ${interface}; no longer exists." + continue + fi + down_interface $interface + done + fi +} + +main() { + # Load libraries from dracut + load_dracut_libs + + # Take down all interfaces set up in the initramfs + down_interfaces + + # Clean up all routing + echo "info: flushing all routing" + ip route flush table main + ip route flush cache + + # Hopefully our logic is sound enough that this is never needed, but + # user's can explicitly disable initramfs network/hostname propagation + # with the coreos.no_persist_ip karg. + if dracut_func getargbool 0 'coreos.no_persist_ip'; then + echo "info: coreos.no_persist_ip karg detected" + echo "info: skipping propagating initramfs settings" + else + propagate_initramfs_hostname + propagate_initramfs_networking + fi + + # Now that the configuration has been propagated (or not) + # clean it up so that no information from outside of the + # real root is passed on to NetworkManager in the real root + rm -rf /run/NetworkManager/ + + rm -f /run/udev/rules.d/80-coreos-boot-disk.rules + rm -f /dev/disk/by-id/coreos-boot-disk +} + +main diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-unique-boot.service b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-unique-boot.service new file mode 100644 index 0000000..7505ff5 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-unique-boot.service @@ -0,0 +1,22 @@ +[Unit] +Description=Ensure filesystem labeled `boot` is unique +ConditionPathExists=/etc/initrd-release +DefaultDependencies=no +Before=ignition-diskful.target +Wants=systemd-udevd.service +After=systemd-udevd.service +# And since the boot device may be on multipath; optionally wait for it to +# appear via the dynamic target. +After=coreos-multipath-wait.target +Requires=dev-disk-by\x2dlabel-boot.device +After=dev-disk-by\x2dlabel-boot.device +# Run before services that modify/use `boot` partition +Before=coreos-gpt-setup.service coreos-boot-edit.service + +OnFailure=emergency.target +OnFailureJobMode=isolate + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/bin/rdcore verify-unique-fs-label boot diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/module-setup.sh b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/module-setup.sh new file mode 100755 index 0000000..f53564d --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/module-setup.sh @@ -0,0 +1,79 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh + +depends() { + echo systemd network ignition coreos-live +} + +install_ignition_unit() { + local unit="$1"; shift + local target="${1:-ignition-complete.target}"; shift + local instantiated="${1:-$unit}"; shift + inst_simple "$moddir/$unit" "$systemdsystemunitdir/$unit" + # note we `|| exit 1` here so we error out if e.g. the units are missing + # see https://github.com/coreos/fedora-coreos-config/issues/799 + systemctl -q --root="$initdir" add-requires "$target" "$instantiated" || exit 1 +} + +install() { + inst_multiple \ + basename \ + diff \ + lsblk \ + sed \ + grep \ + sgdisk \ + uname + + inst_simple "$moddir/coreos-diskful-generator" \ + "$systemdutildir/system-generators/coreos-diskful-generator" + + inst_script "$moddir/coreos-gpt-setup.sh" \ + "/usr/sbin/coreos-gpt-setup" + + # This has to work only on diskful systems during firstboot. + # coreos-diskful-generator will create a symlink + inst_simple "$moddir/80-coreos-boot-disk.rules" \ + "/usr/lib/coreos/80-coreos-boot-disk.rules" + + inst_script "$moddir/coreos-disk-contains-fs.sh" \ + "/usr/lib/udev/coreos-disk-contains-fs" + + inst_script "$moddir/coreos-ignition-setup-user.sh" \ + "/usr/sbin/coreos-ignition-setup-user" + + inst_script "$moddir/coreos-post-ignition-checks.sh" \ + "/usr/sbin/coreos-post-ignition-checks" + + install_ignition_unit coreos-post-ignition-checks.service + + # For consistency tear down the network and persist multipath between the initramfs and + # real root. See https://github.com/coreos/fedora-coreos-tracker/issues/394#issuecomment-599721763 + inst_script "$moddir/coreos-teardown-initramfs.sh" \ + "/usr/sbin/coreos-teardown-initramfs" + install_ignition_unit coreos-teardown-initramfs.service + + # units only started when we have a boot disk + # path generated by systemd-escape --path /dev/disk/by-label/root + install_ignition_unit coreos-gpt-setup.service ignition-diskful.target + + # dracut inst_script doesn't allow overwrites and we are replacing + # the default script placed by Ignition + binpath="/usr/sbin/ignition-kargs-helper" + cp "$moddir/coreos-kargs.sh" "$initdir$binpath" + install_ignition_unit coreos-kargs-reboot.service + + inst_script "$moddir/coreos-boot-edit.sh" \ + "/usr/sbin/coreos-boot-edit" + # Only start when the system has disks since we are editing /boot. + install_ignition_unit "coreos-boot-edit.service" \ + "ignition-diskful.target" + + install_ignition_unit coreos-ignition-unique-boot.service ignition-diskful.target + install_ignition_unit coreos-unique-boot.service ignition-diskful.target + install_ignition_unit coreos-ignition-setup-user.service + + # IBM Secure Execution. Ignition config for reencryption of / and /boot + inst_simple "$moddir/01-secex.ign" /usr/lib/coreos/01-secex.ign +} diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-live-clear-sssd-cache.service b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-live-clear-sssd-cache.service new file mode 100644 index 0000000..758bb61 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-live-clear-sssd-cache.service @@ -0,0 +1,18 @@ +# SSSD caches passwd data from /etc in /var. If we have a persistent /var +# but not a persistent /etc, ignition-files.service can think a user +# already exists when in fact it needs to be (re-)created. Clear the +# cache to avoid this. + +[Unit] +Description=Clear SSSD NSS cache in persistent /var +DefaultDependencies=false +ConditionPathExists=/run/ostree-live +ConditionPathExists=/sysroot/var/lib/sss/mc + +After=ignition-mount.service +Before=ignition-files.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/bin/rm -r /sysroot/var/lib/sss/mc diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-live-unmount-tmpfs-var.service b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-live-unmount-tmpfs-var.service new file mode 100644 index 0000000..de5080f --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-live-unmount-tmpfs-var.service @@ -0,0 +1,24 @@ +# If the user specified a persistent /var, ideally it'd just be mounted +# overtop of our tmpfs /var and everything would be fine. That works +# fine in the initramfs, where ignition-mount handles the mounting. +# But in the real root, the user's mount unit is ignored by systemd, +# since there's already a filesystem mounted on /var. To fix this, we +# notice that the user wants to mount /var, and unmount our tmpfs /var +# before switching roots. + +[Unit] +Description=Unmount live /var if persistent /var is configured +DefaultDependencies=false +ConditionPathExists=/run/ostree-live +ConditionPathExists=|/sysroot/etc/systemd/system/var.mount +ConditionPathExists=|/sysroot/etc/fstab +Before=initrd-switch-root.target + +# Run after Ignition mounts are unmounted, since the Ignition config +# presumably mounted overtop /sysroot/var +After=ignition-mount.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/sbin/coreos-live-unmount-tmpfs-var diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-live-unmount-tmpfs-var.sh b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-live-unmount-tmpfs-var.sh new file mode 100755 index 0000000..9b61d89 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-live-unmount-tmpfs-var.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# If the user specified a persistent /var, ideally it'd just be mounted +# overtop of our tmpfs /var and everything would be fine. That works +# fine in the initramfs, where ignition-mount handles the mounting. +# But in the real root, the user's mount unit is ignored by systemd, +# since there's already a filesystem mounted on /var. To fix this, we +# notice that the user wants to mount /var, and unmount our tmpfs /var +# before switching roots. + +set -euo pipefail + +should_unmount() { + # Did the user specify a mount unit for /var? + if [ -e /sysroot/etc/systemd/system/var.mount ]; then + return 0 + fi + + # Is there an fstab entry for /var? + if [ -e /sysroot/etc/fstab ]; then + # Uncommented entry with mountpoint on /var, without noauto in options + result=$(awk '(! /^\s*#/) && ($2 == "/var") && ($4 !~ /noauto/) {print "found"}' /sysroot/etc/fstab) + if [ -n "$result" ]; then + return 0 + fi + fi + + return 1 +} + +if should_unmount; then + echo "Unmounting /sysroot/var" + umount /sysroot/var +fi diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-liveiso-persist-osmet.service b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-liveiso-persist-osmet.service new file mode 100644 index 0000000..ea82d77 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-liveiso-persist-osmet.service @@ -0,0 +1,17 @@ +[Unit] +Description=Persist osmet files (ISO) +DefaultDependencies=false +ConditionPathExists=/run/ostree-live +ConditionKernelCommandLine=coreos.liveiso +RequiresMountsFor=/run/media/iso +# on el8, the ISO is mounted by our own systemd unit +After=run-media-iso-mount.service +Before=initrd-switch-root.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/bin/mkdir -p /run/coreos-installer/osmet +# bsdtar reads cpio archives, and unlike cpio(1L), knows how to seek over +# members it isn't reading +ExecStart=/usr/bin/bsdtar -x -C /run/coreos-installer/osmet -f /run/media/iso/images/pxeboot/rootfs.img *.osmet diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-livepxe-persist-osmet.service b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-livepxe-persist-osmet.service new file mode 100644 index 0000000..17484e6 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-livepxe-persist-osmet.service @@ -0,0 +1,14 @@ +[Unit] +Description=Persist osmet files (PXE) +DefaultDependencies=false +ConditionPathExists=/run/ostree-live +ConditionKernelCommandLine=!coreos.liveiso +# Downloads and unpacks the osmet files if not already appended +After=coreos-livepxe-rootfs.service +Before=initrd-switch-root.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/bin/mkdir -p /run/coreos-installer/osmet +ExecStart=/usr/bin/sh -c "if ls /*.osmet &>/dev/null; then cp /*.osmet /run/coreos-installer/osmet; fi" diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-livepxe-rootfs.service b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-livepxe-rootfs.service new file mode 100644 index 0000000..ed935ba --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-livepxe-rootfs.service @@ -0,0 +1,21 @@ +[Unit] +Description=Acquire live PXE rootfs image +DefaultDependencies=false +ConditionPathExists=/usr/lib/initrd-release +ConditionPathExists=/run/ostree-live +ConditionKernelCommandLine=!coreos.liveiso + +After=basic.target +# Network is enabled here +After=nm-run.service +# compat: remove when everyone is on dracut 053+ +After=dracut-initqueue.service + +# If we fail, the boot will fail. Be explicit about it. +OnFailure=emergency.target +OnFailureJobMode=isolate + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/sbin/coreos-livepxe-rootfs diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-livepxe-rootfs.sh b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-livepxe-rootfs.sh new file mode 100755 index 0000000..c7188bf --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/coreos-livepxe-rootfs.sh @@ -0,0 +1,70 @@ +#!/bin/bash +# Ensure that a PXE-booted system has a valid rootfs. + +set -euo pipefail + +# Get rootfs_url karg +set +euo pipefail +. /usr/lib/dracut-lib.sh +rootfs_url=$(getarg coreos.live.rootfs_url=) +set -euo pipefail + +if [[ -f /etc/coreos-live-rootfs ]]; then + # rootfs image was injected via PXE. Verify that the initramfs and + # rootfs versions match. + initramfs_ver=$(cat /etc/coreos-live-initramfs) + rootfs_ver=$(cat /etc/coreos-live-rootfs) + if [[ $initramfs_ver != $rootfs_ver ]]; then + echo "Found initramfs version $initramfs_ver but rootfs version $rootfs_ver." >&2 + echo "Please fix your PXE configuration." >&2 + exit 1 + fi +elif [[ -n "${rootfs_url}" ]]; then + # rootfs URL was provided as karg. Fetch image, check its hash, and + # unpack it. + echo "Fetching rootfs image from ${rootfs_url}..." + if [[ ${rootfs_url} != http:* && ${rootfs_url} != https:* && ${rootfs_url} != tftp:* ]]; then + # Don't commit to supporting protocols we might not want to expose in + # the long term. + echo "Unsupported scheme for image specified by:" >&2 + echo "coreos.live.rootfs_url=${rootfs_url}" >&2 + echo "Only HTTP, HTTPS, and TFTP are supported. Please fix your PXE configuration." >&2 + exit 1 + fi + + # First, reach out to the server to verify connectivity before + # trying to download and pipe content through other programs. + # Doing this allows us to retry all errors (including transient + # "no route to host" errors during startup). Note we can't use + # curl's --retry-all-errors here because it's not in el8's curl yet. + # We retry forever, matching Ignition's semantics. + curl_common_args="--silent --show-error --insecure --location" + while ! curl --head $curl_common_args "${rootfs_url}" >/dev/null; do + echo "Couldn't establish connectivity with the server specified by:" >&2 + echo "coreos.live.rootfs_url=${rootfs_url}" >&2 + echo "Retrying in 5s..." >&2 + sleep 5 + done + + # We don't need to verify TLS certificates because we're checking the + # image hash. + # bsdtar can read cpio archives and we already depend on it for + # coreos-liveiso-persist-osmet.service, so use it instead of cpio. + # We shouldn't need a --retry here since we've just successfully HEADed the + # file, but let's add one just to be safe (e.g. if the connection just went + # online and flickers or something). + if ! curl $curl_common_args --retry 5 "${rootfs_url}" | \ + rdcore stream-hash /etc/coreos-live-want-rootfs | \ + bsdtar -xf - -C / ; then + echo "Couldn't fetch, verify, and unpack image specified by:" >&2 + echo "coreos.live.rootfs_url=${rootfs_url}" >&2 + echo "Check that the URL is correct and that the rootfs version matches the initramfs." >&2 + exit 1 + fi +else + # Nothing. Fail. + echo "No rootfs image found. Modify your PXE configuration to add the rootfs" >&2 + echo "image as a second initrd, or use the coreos.live.rootfs_url kernel parameter" >&2 + echo "to specify an HTTP or HTTPS URL to the rootfs." >&2 + exit 1 +fi diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/is-live-image.sh b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/is-live-image.sh new file mode 100755 index 0000000..318ad0b --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/is-live-image.sh @@ -0,0 +1,6 @@ +#!/bin/sh +# Script invoked by ignition-dracut generator to detect whether this is a +# live system without a root device. We can't test for /run/ostree-live +# because it's created by a generator. +# This file is created by coreos-assembler buildextend-live. +test -f /etc/coreos-live-initramfs diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/live-generator b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/live-generator new file mode 100755 index 0000000..dfca346 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-live/live-generator @@ -0,0 +1,271 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh + +# Generators don't have logging right now +# https://github.com/systemd/systemd/issues/15638 +exec 1>/dev/kmsg; exec 2>&1 + +command -v getarg >/dev/null || . /usr/lib/dracut-lib.sh + +set -e + +UNIT_DIR="${1:-/tmp}" + +add_requires() { + local name="$1"; shift + local target="$1"; shift + local requires_dir="${UNIT_DIR}/${target}.requires" + mkdir -p "${requires_dir}" + ln -sf "../${name}" "${requires_dir}/${name}" +} + +if ! is-live-image; then + exit 0 +fi + +# Create stamp file that everything else should use to detect a live boot +> /run/ostree-live + +add_requires sysroot.mount initrd-root-fs.target +add_requires sysroot-etc.mount initrd-root-fs.target +add_requires sysroot-var.mount initrd-root-fs.target + +mkdir -p "${UNIT_DIR}/ostree-prepare-root.service.d" +cat > "${UNIT_DIR}/ostree-prepare-root.service.d/10-live.conf" <"${UNIT_DIR}/sysroot.mount" < "${initrd_rootdev_target_d}/50-root-device.conf" <"${UNIT_DIR}/run-media-iso-mount.service" <"${UNIT_DIR}/run-media-iso.mount" <"${UNIT_DIR}/sysroot.mount" <"${UNIT_DIR}/workaround-stalled-media-iso-mount.service" <"${UNIT_DIR}/sysroot-xfs-ephemeral-mkfs.service" <<'EOF' +[Unit] +DefaultDependencies=false +# Let's be sure we have basic devices, but other than that we +# can run really early. +After=systemd-tmpfiles-setup-dev.service +ConditionPathExists=/usr/lib/initrd-release +# Something seems to be causing us to rerun? +ConditionPathExists=!/run/ephemeral + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/bin/sh -c 'set -euo pipefail; mem=$$(($$(stat -f -c "%%b * %%s / 1024" /run))) && /bin/truncate -s $${mem}k /run/ephemeral.xfsloop' +ExecStart=/sbin/mkfs.xfs /run/ephemeral.xfsloop +ExecStart=/bin/mkdir /run/ephemeral +EOF +add_requires sysroot-xfs-ephemeral-mkfs.service initrd-root-fs.target + +cat >>"${UNIT_DIR}/run-ephemeral.mount" <"${UNIT_DIR}/sysroot-xfs-ephemeral-setup.service" < "${UNIT_DIR}/sysroot-etc.mount" +cat >>"${UNIT_DIR}/sysroot-etc.mount" <"${UNIT_DIR}/sysroot-var.mount" +cat >>"${UNIT_DIR}/sysroot-var.mount" <>"${UNIT_DIR}/sysroot-relabel.service" < /tmp/cmdline + mount --bind /tmp/cmdline /proc/cmdline + ;; + stop) + umount /proc/cmdline + rm /tmp/cmdline + ;; + *) + echo "Usage: $0 {start|stop}" >&2 + exit 1 + ;; +esac diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-multipath/coreos-multipath-generator b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-multipath/coreos-multipath-generator new file mode 100755 index 0000000..7165620 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-multipath/coreos-multipath-generator @@ -0,0 +1,30 @@ +#!/bin/bash + +# Generators don't have logging right now +# https://github.com/systemd/systemd/issues/15638 +exec 1>/dev/kmsg; exec 2>&1 + +command -v getargbool >/dev/null || . /usr/lib/dracut-lib.sh + +set -e + +if is-live-image; then + exit 0 +fi + +UNIT_DIR="${1:-/tmp}" + +add_requires() { + local name="$1"; shift + local target="$1"; shift + local requires_dir="${UNIT_DIR}/${target}.requires" + mkdir -p "${requires_dir}" + ln -sf "../${name}" "${requires_dir}/${name}" +} + +if getargbool 0 rd.multipath; then + add_requires coreos-multipath-wait.target initrd.target + if ! getargbool 0 ignition.firstboot; then + add_requires coreos-multipath-trigger.service initrd.target + fi +fi diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-multipath/coreos-multipath-trigger.service b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-multipath/coreos-multipath-trigger.service new file mode 100644 index 0000000..524dc91 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-multipath/coreos-multipath-trigger.service @@ -0,0 +1,19 @@ +# This unit is needed in the LUKS-on-multipath case on subsequent boots. When +# multipathd takes ownership of the individual paths, the by-uuid/ symlink +# which systemd-cryptsetup@.service binds to gets lost. So we retrigger udev +# here to make sure it's re-added. +# +# This is tracked at: +# https://bugzilla.redhat.com/show_bug.cgi?id=1963242 + +[Unit] +Description=CoreOS Trigger Multipath +DefaultDependencies=false +Requires=coreos-multipath-wait.target +After=coreos-multipath-wait.target +Before=cryptsetup-pre.target + +[Service] +Type=oneshot +ExecStart=/usr/sbin/udevadm trigger --settle --subsystem-match block +RemainAfterExit=yes diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-multipath/coreos-multipath-wait.target b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-multipath/coreos-multipath-wait.target new file mode 100644 index 0000000..b003f4d --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-multipath/coreos-multipath-wait.target @@ -0,0 +1,17 @@ +[Unit] +Description=CoreOS Wait For Multipathed Boot +DefaultDependencies=false +Before=dracut-initqueue.service +After=dracut-cmdline.service +Requires=dev-disk-by\x2dlabel-dm\x2dmpath\x2dboot.device +After=dev-disk-by\x2dlabel-dm\x2dmpath\x2dboot.device +Requires=multipathd.service +After=multipathd.service + +# This is already enforced transitively by coreos-gpt-setup.service, but +# let's be more explicit and list it directly here too. +Before=coreos-ignition-setup-user.service + +# This is already enforced by coreos-multipath-trigger.service, though ideally +# eventually we can get rid of that one and then we *would* need this. +Before=cryptsetup-pre.target diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-multipath/coreos-propagate-multipath-conf.service b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-multipath/coreos-propagate-multipath-conf.service new file mode 100644 index 0000000..9eefee8 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-multipath/coreos-propagate-multipath-conf.service @@ -0,0 +1,24 @@ +[Unit] +Description=CoreOS Propagate Multipath Configuration +Before=initrd.target + +# we write to the rootfs, so run after it's ready +After=initrd-root-fs.target + +# we only propagate if multipath wasn't configured via Ignition +After=ignition-files.service + +# That service starts initrd-cleanup.service which will race with us completing +# before we get nuked. Need to get to the bottom of it, but for now we need +# this (XXX: add link to systemd issue here). +Before=initrd-parse-etc.service + +ConditionKernelCommandLine=rd.multipath=default + +OnFailure=emergency.target +OnFailureJobMode=isolate + +[Service] +Type=oneshot +ExecStart=/usr/sbin/coreos-propagate-multipath-conf +RemainAfterExit=yes diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-multipath/coreos-propagate-multipath-conf.sh b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-multipath/coreos-propagate-multipath-conf.sh new file mode 100755 index 0000000..eb6d12a --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-multipath/coreos-propagate-multipath-conf.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -euo pipefail + +# Persist automatic multipath configuration, if any. +# When booting with `rd.multipath=default`, the default multipath +# configuration is written. We need to ensure that the multipath configuration +# is persisted to the rootfs. + +if [ ! -f /etc/multipath.conf ]; then + echo "info: initrd file /etc/multipath.conf does not exist" + echo "info: no initrd multipath configuration to propagate" + exit 0 +fi + +if [ -f /sysroot/etc/multipath.conf ]; then + echo "info: real root file /etc/multipath.conf exists" + echo "info: not propagating initrd multipath configuration" + exit 0 +fi + +echo "info: propagating initrd multipath configuration" +cp -v /etc/multipath.conf /sysroot/etc/ +coreos-relabel /etc/multipath.conf diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-multipath/module-setup.sh b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-multipath/module-setup.sh new file mode 100755 index 0000000..92a33e7 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-multipath/module-setup.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh + +install_unit() { + local unit=$1; shift + local target=${1:-initrd} + inst_simple "$moddir/$unit" "$systemdsystemunitdir/$unit" + # note we `|| exit 1` here so we error out if e.g. the units are missing + # see https://github.com/coreos/fedora-coreos-config/issues/799 + systemctl -q --root="$initdir" add-requires "${target}.target" "$unit" || exit 1 +} + +install() { + inst_script "$moddir/coreos-propagate-multipath-conf.sh" \ + "/usr/sbin/coreos-propagate-multipath-conf" + + install_unit coreos-propagate-multipath-conf.service + + inst_simple "$moddir/coreos-multipath-generator" \ + "$systemdutildir/system-generators/coreos-multipath-generator" + + # we don't enable these; they're enabled dynamically via the generator + inst_simple "$moddir/coreos-multipath-wait.target" \ + "$systemdsystemunitdir/coreos-multipath-wait.target" + inst_simple "$moddir/coreos-multipath-trigger.service" \ + "$systemdsystemunitdir/coreos-multipath-trigger.service" +} diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-network/50-afterburn-network-kargs-default.conf b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-network/50-afterburn-network-kargs-default.conf new file mode 100644 index 0000000..8c411e5 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-network/50-afterburn-network-kargs-default.conf @@ -0,0 +1,7 @@ +# This contains the default kargs for firstboot network configuration. +# Default values can be dynamically overridden by platform-specific +# logic (e.g. injected via a back-channel). +# https://github.com/coreos/fedora-coreos-tracker/issues/460 + +[Service] +Environment=AFTERBURN_NETWORK_KARGS_DEFAULT='ip=auto' diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-network/coreos-copy-firstboot-network.service b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-network/coreos-copy-firstboot-network.service new file mode 100644 index 0000000..a1dd64b --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-network/coreos-copy-firstboot-network.service @@ -0,0 +1,65 @@ +# This unit will run early in boot and detect if: +# - In the diskful case, the user copied in firstboot networking config files +# into `/boot` (most likely by using `coreos-installer install +# --copy-network`). +# - In the live case, the user provided firstboot networking config files in +# `/etc` (most likely by using `coreos-installer iso network embed`). +# +# Since this unit is modifying network configuration there are some +# dependencies that we have: +# +# - In the diskful case, we need to look for networking configuration on the +# /boot partition +# - i.e. after /dev/disk/by-label/boot is available +# - which is implied by running after coreos-gpt-setup (see below) +# - Need to run before networking is brought up. +# - This is done in nm-initrd.service [1] +# - i.e. Before=nm-initrd.service +# - Need to make sure karg networking configuration isn't applied +# - There are two ways to do this. +# - One is to run *before* the nm-config.sh [2] that runs as part of +# dracut-cmdline [3] and `ln -sf /bin/true /usr/libexec/nm-initrd-generator`. +# - i.e. Before=dracut-cmdline.service +# - Another is to run *after* nm-config.sh [2] in dracut-cmdline [3] +# and just delete all the files created by nm-initrd-generator. +# - i.e. After=dracut-cmdline.service, but Before=nm-initrd.service +# - We'll go with the second option here because the need for the /boot +# device (mentioned above) means we can't start before dracut-cmdline.service +# +# [1] https://github.com/dracutdevs/dracut/blob/master/modules.d/35network-manager/nm-initrd.service +# [2] https://github.com/dracutdevs/dracut/blob/master/modules.d/35network-manager/nm-config.sh +# [3] https://github.com/dracutdevs/dracut/blob/master/modules.d/35network-manager/module-setup.sh#L34 +# +[Unit] +Description=Copy CoreOS Firstboot Networking Config +ConditionPathExists=/usr/lib/initrd-release +DefaultDependencies=false +# We're pulled in by ignition-complete.target; as good practice, add a matching +# Before to be explicit about it gating on this unit passing. +Before=ignition-complete.target +Before=nm-initrd.service +# compat: remove when everyone is on dracut 054+ +Before=dracut-initqueue.service +After=dracut-cmdline.service +# Any services looking at mounts need to order after this +# because it causes device re-probing. +After=coreos-gpt-setup.service +# And since the boot device may be on multipath; optionally wait for it to +# appear via the dynamic target. +After=coreos-multipath-wait.target +# Need to run after coreos-enable-network since it may re-run the NM cmdline +# hook which will generate NM configs from the network kargs, but we want to +# have precedence. +After=coreos-enable-network.service +# We've seen races with ignition-kargs.service, which accesses /boot rw. +# Let's introduce some ordering here. Need to use `Before` because otherwise +# we get a systemd ordering cycle. https://github.com/coreos/fedora-coreos-tracker/issues/883 +Before=ignition-kargs.service + +[Service] +Type=oneshot +RemainAfterExit=yes +# The MountFlags=slave is so the umount of /boot is guaranteed to happen +# /boot will only be mounted for the lifetime of the unit. +MountFlags=slave +ExecStart=/usr/sbin/coreos-copy-firstboot-network diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-network/coreos-copy-firstboot-network.sh b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-network/coreos-copy-firstboot-network.sh new file mode 100755 index 0000000..51ea283 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-network/coreos-copy-firstboot-network.sh @@ -0,0 +1,49 @@ +#!/bin/bash +set -euo pipefail + +# For a description of how this is used see coreos-copy-firstboot-network.service + +bootmnt=/mnt/boot_partition +bootdev=/dev/disk/by-label/boot +firstboot_network_dir_basename="coreos-firstboot-network" +boot_firstboot_network_dir="${bootmnt}/${firstboot_network_dir_basename}" +etc_firstboot_network_dir="/etc/${firstboot_network_dir_basename}" +initramfs_network_dir="/run/NetworkManager/system-connections/" + +copy_firstboot_network() { + local src=$1; shift + + # Clear out any files that may have already been generated from + # kargs by nm-initrd-generator + rm -f ${initramfs_network_dir}/* + # Copy files that were placed into the source + # to the appropriate location for NetworkManager to use the configuration. + echo "info: copying files from ${src} to ${initramfs_network_dir}" + mkdir -p ${initramfs_network_dir} + cp -v ${src}/* ${initramfs_network_dir}/ +} + +if ! is-live-image; then + # Mount /boot. Note that we mount /boot but we don't unmount boot because we + # are run in a systemd unit with MountFlags=slave so it is unmounted for us. + # Mount as read-only since we don't strictly need write access and we may be + # running alongside other code that also has it mounted ro + mkdir -p ${bootmnt} + mount -o ro ${bootdev} ${bootmnt} + + if [ -n "$(ls -A ${boot_firstboot_network_dir} 2>/dev/null)" ]; then + # Likely placed there by coreos-installer, see: + # https://github.com/coreos/coreos-installer/pull/212 + copy_firstboot_network "${boot_firstboot_network_dir}" + else + echo "info: no files to copy from ${boot_firstboot_network_dir}; skipping" + fi +else + if [ -n "$(ls -A ${etc_firstboot_network_dir} 2>/dev/null)" ]; then + # Also placed there by coreos-installer but in a different flow, see: + # https://github.com/coreos/coreos-installer/pull/713 + copy_firstboot_network "${etc_firstboot_network_dir}" + else + echo "info: no files to copy from ${etc_firstboot_network_dir}; skipping" + fi +fi diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-network/coreos-enable-network.service b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-network/coreos-enable-network.service new file mode 100644 index 0000000..92c4829 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-network/coreos-enable-network.service @@ -0,0 +1,30 @@ +[Unit] +Description=CoreOS Enable Network +ConditionPathExists=/etc/initrd-release +DefaultDependencies=false +After=basic.target + +# Triggering conditions for cases where we need network: +# * when Ignition signals that it is required for provisioning. +# * on live systems fetching the remote rootfs in initramfs. +# * on Azure and Azure Stack Hub, for hostname fetching (metadata endpoint) and boot check-in (wireserver). +ConditionPathExists=|/run/ignition/neednet +ConditionKernelCommandLine=|coreos.live.rootfs_url +ConditionKernelCommandLine=|ignition.platform.id=azure +ConditionKernelCommandLine=|ignition.platform.id=azurestack + +# Creates /run/ignition/neednet +After=ignition-fetch-offline.service +# Needs networking +Before=ignition-fetch.service + +# See hack in coreos-enable-network, as well as coreos-copy-firstboot-network.service. +After=dracut-cmdline.service +Before=nm-initrd.service +# compat: remove when everyone is on dracut 054+ +Before=dracut-initqueue.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/sbin/coreos-enable-network diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-network/coreos-enable-network.sh b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-network/coreos-enable-network.sh new file mode 100755 index 0000000..6c54f49 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-network/coreos-enable-network.sh @@ -0,0 +1,27 @@ +#!/bin/bash +set -euo pipefail + +set +euo pipefail +. /usr/lib/dracut-lib.sh +set -euo pipefail + +dracut_func() { + # dracut is not friendly to set -eu + set +euo pipefail + "$@"; local rc=$? + set -euo pipefail + return $rc +} + +# If networking hasn't been requested yet, request it. +if ! dracut_func getargbool 0 'rd.neednet'; then + echo "rd.neednet=1" > /etc/cmdline.d/40-coreos-neednet.conf + + # Hack: we need to rerun the NM cmdline hook because we run after + # dracut-cmdline.service because we need udev. We should be able to move + # away from this once we run NM as a systemd unit. See also: + # https://github.com/coreos/fedora-coreos-config/pull/346#discussion_r409843428 + set +euo pipefail + . /usr/lib/dracut/hooks/cmdline/99-nm-config.sh + set -euo pipefail +fi diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-network/module-setup.sh b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-network/module-setup.sh new file mode 100644 index 0000000..0cf3a1a --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/35coreos-network/module-setup.sh @@ -0,0 +1,26 @@ +install_and_enable_unit() { + unit="$1"; shift + target="$1"; shift + inst_simple "$moddir/$unit" "$systemdsystemunitdir/$unit" + # note we `|| exit 1` here so we error out if e.g. the units are missing + # see https://github.com/coreos/fedora-coreos-config/issues/799 + systemctl -q --root="$initdir" add-requires "$target" "$unit" || exit 1 +} + +install() { + inst_simple "$moddir/coreos-enable-network.sh" \ + "/usr/sbin/coreos-enable-network" + install_and_enable_unit "coreos-enable-network.service" \ + "initrd.target" + + inst_simple "$moddir/coreos-copy-firstboot-network.sh" \ + "/usr/sbin/coreos-copy-firstboot-network" + install_and_enable_unit "coreos-copy-firstboot-network.service" \ + "ignition-complete.target" + + # Dropin with firstboot network configuration kargs, applied via + # Afterburn. + inst_simple "$moddir/50-afterburn-network-kargs-default.conf" \ + "/usr/lib/systemd/system/afterburn-network-kargs.service.d/50-afterburn-network-kargs-default.conf" + +} diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-conf/00-core.ign b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-conf/00-core.ign new file mode 100644 index 0000000..3ddac11 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-conf/00-core.ign @@ -0,0 +1,19 @@ +{ + "ignition": { + "version": "3.0.0" + }, + "passwd": { + "users": [ + { + "name": "core", + "gecos": "CoreOS Admin", + "groups": [ + "adm", + "sudo", + "systemd-journal", + "wheel" + ] + } + ] + } +} diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-conf/README.md b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-conf/README.md new file mode 100644 index 0000000..793e519 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-conf/README.md @@ -0,0 +1 @@ +`00-core.ign` is the base config shared between FCOS and RHCOS. The configs specific to FCOS are in [50ignition-conf-fcos](../../../../../../15fcos/usr/lib/dracut/modules.d/50ignition-conf-fcos). \ No newline at end of file diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-conf/module-setup.sh b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-conf/module-setup.sh new file mode 100755 index 0000000..7e06855 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-conf/module-setup.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh + +depends() { + echo ignition +} + +install() { + mkdir -p "$initdir/usr/lib/ignition/base.d" + inst "$moddir/00-core.ign" \ + "/usr/lib/ignition/base.d/00-core.ign" +} diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/coreos-check-rootfs-size b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/coreos-check-rootfs-size new file mode 100755 index 0000000..2c320be --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/coreos-check-rootfs-size @@ -0,0 +1,37 @@ +#!/bin/bash +set -euo pipefail + +# See also ignition-ostree-check-rootfs-size.service +# https://github.com/coreos/fedora-coreos-tracker/issues/586#issuecomment-777220000 + +srcdev=$(findmnt -nvr -o SOURCE /sysroot | tail -n1) +size=$(lsblk --nodeps --noheadings --bytes -o SIZE "${srcdev}") + +MINIMUM_GB=8 +MINIMUM_BYTES=$((1024 * 1024 * 1024 * MINIMUM_GB)) + +MOTD_DROPIN=/etc/motd.d/60-coreos-rootfs-size.motd + +YELLOW=$(echo -e '\033[0;33m') +RESET=$(echo -e '\033[0m') + +if [ "${size}" -lt "${MINIMUM_BYTES}" ]; then + mkdir -p "/sysroot/$(dirname "${MOTD_DROPIN}")" + cat > "/sysroot/${MOTD_DROPIN}" <&2 +} + +fatal() { + err "$@" + exit 1 +} + +if [ $# -eq 0 ]; then + err "Usage: $0 [PATTERN...]" + err " e.g.: $0 /etc/passwd '/etc/group*'" +fi + +if [ ! -f /sysroot/etc/selinux/config ]; then + exit 0 +fi + +source /sysroot/etc/selinux/config + +if [ -z "${SELINUXTYPE:-}" ]; then + fatal "Couldn't find SELINUXTYPE in /sysroot/etc/selinux/config" +fi + +file_contexts="/sysroot/etc/selinux/${SELINUXTYPE}/contexts/files/file_contexts" + +prefixed_patterns=() +while [ $# -ne 0 ]; do + pattern=$1; shift + prefixed_patterns+=("/sysroot/$pattern") +done +setfiles -vFi0 -r /sysroot "$file_contexts" "${prefixed_patterns[@]}" diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/coreos-rootflags.sh b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/coreos-rootflags.sh new file mode 100755 index 0000000..1a7c0a2 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/coreos-rootflags.sh @@ -0,0 +1,30 @@ +#!/bin/bash +set -euo pipefail + +# see related comment block in transposefs.sh re. inspecting the config directly +ignition_cfg=/run/ignition.json +rootpath=/dev/disk/by-label/root + +query_rootfs() { + local filter=$1 + jq -re ".storage?.filesystems? // [] | + map(select(.label == \"root\" and .wipeFilesystem == true)) | + .[0] | $filter" "${ignition_cfg}" +} + +# If the rootfs was reprovisioned, then the mountOptions from the Ignition +# config has priority. +if [ -d /run/ignition-ostree-transposefs/root ]; then + if query_rootfs 'has("mountOptions")' >/dev/null; then + query_rootfs '.mountOptions | join(",")' + exit 0 + fi +fi + +eval $(blkid -o export ${rootpath}) +if [ "${TYPE}" == "xfs" ]; then + # We use prjquota on XFS by default to aid multi-tenant Kubernetes (and + # other container) clusters. See + # https://github.com/coreos/coreos-assembler/pull/303/commits/6103effbd006bb6109467830d6a3e42dd847668d + echo "prjquota" +fi diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-check-rootfs-size.service b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-check-rootfs-size.service new file mode 100644 index 0000000..610c469 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-check-rootfs-size.service @@ -0,0 +1,15 @@ +[Unit] +Description=Ignition OSTree: Check Root Filesystem Size +Documentation=https://docs.fedoraproject.org/en-US/fedora-coreos/storage/ +DefaultDependencies=false +ConditionKernelCommandLine=ostree +ConditionPathExists=!/run/ostree-live +After=ignition-ostree-growfs.service +After=ostree-prepare-root.service +# Allow Ignition config to blank out the warning +Before=ignition-files.service + +[Service] +Type=oneshot +ExecStart=/usr/libexec/coreos-check-rootfs-size +RemainAfterExit=yes diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-firstboot-uuid b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-firstboot-uuid new file mode 100755 index 0000000..b217735 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-firstboot-uuid @@ -0,0 +1,68 @@ +#!/bin/bash +set -euo pipefail +# https://github.com/coreos/fedora-coreos-tracker/issues/465 +# coreos-assembler generates disk images which are installed bit-for-bit +# or booted directly in the cloud. +# Generate new UUID on firstboot; this is general best practice, but in the future +# we may use this for mounting by e.g. adding a boot= and root= kernel args. + +label=$1 + +# Keep this in sync with https://github.com/coreos/coreos-assembler/blob/e3905fd2e138de04184c1cd86b99b0fd83cbe5cf/src/create_disk.sh#L17 +bootfs_uuid="96d15588-3596-4b3c-adca-a2ff7279ea63" +rootfs_uuid="910678ff-f77e-4a7d-8d53-86f2ac47a823" + +target=/dev/disk/by-label/${label} +if ! [ -b "${target}" ]; then + echo "$0: Failed to find block device ${target}" 1>&2 + exit 1 +fi + +eval $(blkid -o export ${target}) +case "${label}" in + root) orig_uuid="${rootfs_uuid}"; orig_type=xfs ;; + boot) orig_uuid="${bootfs_uuid}"; orig_type=ext4 ;; + *) echo "unexpected ${label}"; exit 1 ;; +esac + +if [ "${TYPE}" == "${orig_type}" ] && [ "${UUID}" == "${orig_uuid}" ]; then + case "${TYPE}" in + ext4) + # If the filesystem supports metadata_csum_seed then the UUID is stored + # in the superblock and there is no need to worry with an fsck. For the + # boot filesystem this FS feature wasn't supported by GRUB until recently. + # https://lists.gnu.org/archive/html/grub-devel/2021-06/msg00031.html + # Once grub is updated in all systems we care about we can standardize + # on the metadata_csum_seed and delete the `else` code block. + if tune2fs -l ${target} | grep 'metadata_csum_seed'; then + tune2fs -U random "${target}" + else + # Run an fsck since tune2fs -U requires the FS to be clean + e2fsck -fy "${target}" + # We just ran an fsck, but there is a bug where tune2fs -U will still + # complain. It will still error if the last checked timestamp (just + # set by the e2fsck above) is older than the last mount timestamp (happens + # on systems with out of date or non-functioning hardware clocks). + # See https://github.com/coreos/fedora-coreos-tracker/issues/735#issuecomment-859605953 + # Potentially fixed in future by: https://www.spinics.net/lists/linux-ext4/msg78012.html + tune2fsinfo="$(tune2fs -l ${target})" + lastmount=$(echo "$tune2fsinfo" | grep '^Last mount time:' | cut -d ':' -f 2,3,4) + lastfsck=$(echo "$tune2fsinfo" | grep '^Last checked:' | cut -d ':' -f 2,3,4) + lastmountsse=$(date --date="$lastmount" +%s) + lastfscksse=$(date --date="$lastfsck" +%s) + if (( lastfscksse < lastmountsse )); then + echo "Detected timestamp of last fsck is older than timestamp of last mount." + echo "Setting "${target}" timestamp of last fsck to same time as last mount." + tune2fs -T $(date --date="$lastmount" +%Y%m%d%H%M%S) "${target}" + fi + # Finally, we can randomize the UUID + tune2fs -U random "${target}" + fi ;; + xfs) xfs_admin -U generate "${target}" ;; + *) echo "unexpected filesystem type ${TYPE}" 1>&2; exit 1 ;; + esac + udevadm settle || : + echo "Regenerated UUID for ${target}" +else + echo "No changes required for ${target} TYPE=${TYPE} UUID=${UUID}" +fi diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-growfs.service b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-growfs.service new file mode 100644 index 0000000..8704894 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-growfs.service @@ -0,0 +1,15 @@ +[Unit] +Description=Ignition OSTree: Grow root filesystem +DefaultDependencies=false +ConditionKernelCommandLine=ostree +ConditionPathExists=!/run/ostree-live +Before=initrd-root-fs.target +After=sysroot.mount ignition-ostree-mount-firstboot-sysroot.service +# This shouldn't be strictly necessary, but it's cleaner to not have OSTree muck +# around with moving mounts while we're still resizing the filesystem. +Before=ostree-prepare-root.service + +[Service] +Type=oneshot +ExecStart=/usr/sbin/ignition-ostree-growfs +RemainAfterExit=yes diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-growfs.sh b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-growfs.sh new file mode 100755 index 0000000..0717c32 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-growfs.sh @@ -0,0 +1,126 @@ +#!/bin/bash +set -euo pipefail + +# This script is run by ignition-ostree-growfs.service. It grows the root +# partition, unless it determines that either the rootfs was moved or the +# partition was already resized (e.g. via Ignition). + +# If root reprovisioning was triggered, this file contains state of the root +# partition *before* ignition-disks. +saved_partstate=/run/ignition-ostree-rootfs-partstate.sh + +# We run after the rootfs is mounted at /sysroot, but before ostree-prepare-root +# moves it to /sysroot/sysroot. +path=/sysroot + +# The use of tail is to avoid errors from duplicate mounts; +# this shouldn't happen for us but we're being conservative. +src=$(findmnt -nvr -o SOURCE "$path" | tail -n1) + +# In the IBM Secure Execution case we use Ignition to grow and reencrypt rootfs +# see overlay.d/05core/usr/lib/dracut/modules.d/35coreos-ignition/coreos-diskful-generator +if [[ -f /run/coreos/secure-execution ]]; then + exit 0 +fi + +if [ ! -f "${saved_partstate}" ]; then + partition=$(realpath /dev/disk/by-label/root) +else + # The rootfs was reprovisioned. Our rule in this case is: we only grow if + # the partition backing the rootfs is the same and its size didn't change + # (IOW, it was an in-place reprovisioning; e.g. LUKS or xfs -> btrfs). + source "${saved_partstate}" + if [ "${TYPE}" != "part" ]; then + # this really should never happen; but play nice + echo "$0: original rootfs blockdev not of type 'part'; not auto-growing" + exit 0 + fi + partition=$(realpath "${NAME}") + if [ "${SIZE}" != "$(lsblk --nodeps -bno SIZE "${partition}")" ]; then + echo "$0: original root partition changed size; not auto-growing" + exit 0 + fi + if ! lsblk -no MOUNTPOINT "${partition}" | grep -q '^/sysroot$'; then + echo "$0: original root partition no longer backing rootfs; not auto-growing" + exit 0 + fi +fi + +# Go through each blockdev in the hierarchy and verify we know how to grow them +lsblk -no TYPE "${partition}" | while read dev; do + case "${dev}" in + part|crypt) ;; + *) echo "error: Unsupported blockdev type ${dev}" 1>&2; exit 1 ;; + esac +done + +# Get the filesystem type before extending the partition. This matters +# because the partition, once extended, might include leftover superblocks +# from the previous contents of the disk (notably ZFS), causing blkid to +# refuse to return any filesystem type at all. +eval $(blkid -o export "${src}") +ROOTFS_TYPE=${TYPE:-} +case "${ROOTFS_TYPE}" in + xfs|ext4|btrfs) ;; + *) echo "error: Unsupported filesystem for ${path}: '${ROOTFS_TYPE}'" 1>&2; exit 1 ;; +esac + +# Now, go through the hierarchy, growing everything. Note we go one device at a +# time using --nodeps, because ordering is buggy in el8: +# https://bugzilla.redhat.com/show_bug.cgi?id=1940607 +current_blkdev=${partition} +while true; do + eval "$(lsblk --paths --nodeps --pairs -o NAME,TYPE,PKNAME "${current_blkdev}")" + MAJMIN=$(echo $(lsblk -dno MAJ:MIN "${NAME}")) + case "${TYPE}" in + part) + eval $(udevadm info --query property --export "${current_blkdev}" | grep ^DM_ || :) + if [ -n "${DM_MPATH:-}" ]; then + # Since growpart does not understand device mapper, we have to use sfdisk. + echo ", +" | sfdisk --no-reread --no-tell-kernel --force -N "${DM_PART}" "/dev/mapper/${DM_MPATH}" + udevadm settle || : # Wait for udev-triggered kpartx to update mappings + else + partnum=$(cat "/sys/dev/block/${MAJMIN}/partition") + # XXX: ideally this'd be idempotent and we wouldn't `|| :` + growpart "${PKNAME}" "${partnum}" || : + fi + ;; + crypt) + # XXX: yuck... we need to expose this sanely in clevis + (. /usr/bin/clevis-luks-common-functions + eval $(udevadm info --query=property --export "${NAME}") + # lsblk doesn't print PKNAME of crypt devices with --nodeps + PKNAME=/dev/$(ls "/sys/dev/block/${MAJMIN}/slaves") + clevis_luks_unlock_device "${PKNAME}" | cryptsetup resize -d- "${DM_NAME}" + ) + ;; + # already checked + *) echo "unreachable" 1>&2; exit 1 ;; + esac + holders="/sys/dev/block/${MAJMIN}/holders" + [ -d "${holders}" ] || break + nholders="$(ls "${holders}" | wc -l)" + if [ "${nholders}" -eq 0 ]; then + break + elif [ "${nholders}" -gt 1 ]; then + # this shouldn't happen since we've checked the partition types already + echo "error: Unsupported block device with multiple children: ${NAME}" 1>&2 + exit 1 + fi + current_blkdev=/dev/$(ls "${holders}") +done + +# Wipe any filesystem signatures from the extended partition that don't +# correspond to the FS type we detected earlier. +wipefs -af -t "no${ROOTFS_TYPE}" "${src}" + +# TODO: Add XFS to https://github.com/systemd/systemd/blob/master/src/partition/growfs.c +# and use it instead. +case "${ROOTFS_TYPE}" in + xfs) xfs_growfs "${path}" ;; + ext4) resize2fs "${src}" ;; + btrfs) btrfs filesystem resize max ${path} ;; +esac + +# this is useful for tests +touch /run/ignition-ostree-growfs.stamp diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-mount-firstboot-sysroot.service b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-mount-firstboot-sysroot.service new file mode 100644 index 0000000..3ba677d --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-mount-firstboot-sysroot.service @@ -0,0 +1,25 @@ +[Unit] +Description=Ignition OSTree: Mount (firstboot) /sysroot +# These dependencies should match the "other" in +# ignition-ostree-mount-subsequent-sysroot.service +DefaultDependencies=false +# If root is specified, then systemd's generator will win +ConditionKernelCommandLine=!root +ConditionKernelCommandLine=ostree +# This is redundant since we're queued on -diskful.target, but eh. +ConditionPathExists=!/run/ostree-live +# There can be only one, Highlander style +Conflicts=ignition-ostree-mount-subsequent-sysroot.service +Before=initrd-root-fs.target +After=ignition-disks.service +# Note we don't have a Requires: /dev/disk/by-label/root here like +# the -subsequent service does because ignition-disks may have +# regenerated it. +Requires=ignition-disks.service +# These have an explicit dependency on After=sysroot.mount today +Before=ostree-prepare-root.service ignition-remount-sysroot.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/sbin/ignition-ostree-mount-sysroot diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-mount-subsequent-sysroot.service b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-mount-subsequent-sysroot.service new file mode 100644 index 0000000..92dde88 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-mount-subsequent-sysroot.service @@ -0,0 +1,24 @@ +# Note this unit is conditionally enabled by ignition-ostree-generator +[Unit] +Description=CoreOS: Mount (subsequent) /sysroot +# These dependencies should match the "other" in +# ignition-ostree-mount-firsboot-sysroot.service +DefaultDependencies=false +# If root is specified, then systemd's generator will win +ConditionKernelCommandLine=!root +ConditionKernelCommandLine=ostree +ConditionPathExists=!/run/ostree-live +# There can be only one, Highlander style +Conflicts=ignition-ostree-mount-firstboot-sysroot.service +# And in contrast to the firstboot, we expect +# the root device to be ready. +Requires=dev-disk-by\x2dlabel-root.device +After=dev-disk-by\x2dlabel-root.device +Before=initrd-root-fs.target +# This has an explicit dependency on After=sysroot.mount today +Before=ostree-prepare-root.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/sbin/ignition-ostree-mount-sysroot diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-mount-sysroot.sh b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-mount-sysroot.sh new file mode 100755 index 0000000..a51c4b2 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-mount-sysroot.sh @@ -0,0 +1,18 @@ +#!/bin/bash +set -euo pipefail + +# Note that on *new machines* this script is now only ever used on firstboot. On +# subsequent boots, systemd-fstab-generator mounts /sysroot from the +# root=UUID=... and rootflags=... kargs. + +# We may do a migration window at some point where older machines have these +# kargs injected so that we can simplify the model further. + +rootpath=/dev/disk/by-label/root +if ! [ -b "${rootpath}" ]; then + echo "ignition-ostree-mount-sysroot: Failed to find ${rootpath}" 1>&2 + exit 1 +fi + +echo "Mounting ${rootpath} ($(realpath "${rootpath}")) to /sysroot" +mount -o "$(coreos-rootflags)" "${rootpath}" /sysroot diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-mount-var.service b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-mount-var.service new file mode 100644 index 0000000..09d6c15 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-mount-var.service @@ -0,0 +1,26 @@ +[Unit] +Description=Mount OSTree /var +DefaultDependencies=false +ConditionKernelCommandLine=ostree +ConditionPathExists=!/run/ostree-live + +# Make sure ExecStop= runs before we switch root +Before=initrd-switch-root.target + +# Make sure if ExecStop= fails, the boot fails +OnFailure=emergency.target +OnFailureJobMode=isolate + +# Make sure /sysroot is mounted first, since we're mounting under there +Requires=initrd-root-fs.target +After=initrd-root-fs.target + +# Need to do this before Ignition mounts any other filesystems (potentially +# shadowing our own bind mount). +Before=ignition-mount.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/sbin/ignition-ostree-mount-var mount +ExecStop=/usr/sbin/ignition-ostree-mount-var umount diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-mount-var.sh b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-mount-var.sh new file mode 100755 index 0000000..885598e --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-mount-var.sh @@ -0,0 +1,52 @@ +#!/bin/bash +set -euo pipefail + +fatal() { + echo "$@" >&2 + exit 1 +} + +if [ $# -ne 1 ] || { [[ $1 != mount ]] && [[ $1 != umount ]]; }; then + fatal "Usage: $0 " +fi + +get_ostree_arg() { + # yes, this doesn't account for spaces within args, e.g. myarg="my val", but + # it still works for our purposes + ( + IFS=$' ' + # shellcheck disable=SC2013 + for arg in $(cat /proc/cmdline); do + if [[ $arg == ostree=* ]]; then + echo "${arg#ostree=}" + fi + done + ) +} + +do_mount() { + ostree=$(get_ostree_arg) + if [ -z "${ostree}" ]; then + fatal "No ostree= kernel argument in /proc/cmdline" + fi + + deployment_path=/sysroot/${ostree} + if [ ! -L "${deployment_path}" ]; then + fatal "${deployment_path} is not a symlink" + fi + + stateroot_var_path=$(realpath "${deployment_path}/../../var") + if [ ! -d "${stateroot_var_path}" ]; then + fatal "${stateroot_var_path} is not a directory" + fi + + echo "Mounting $stateroot_var_path" + mount --bind "$stateroot_var_path" /sysroot/var +} + +do_umount() { + echo "Unmounting /sysroot/var" + umount /sysroot/var +} + +"do_$1" diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-populate-var.service b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-populate-var.service new file mode 100644 index 0000000..d7aa622 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-populate-var.service @@ -0,0 +1,16 @@ +[Unit] +Description=Populate OSTree /var +DefaultDependencies=false +ConditionKernelCommandLine=|ostree +ConditionPathExists=|/run/ostree-live + +# Need to do this with all mount points active +After=ignition-mount.service + +# But *before* we start dumping files in there +Before=ignition-files.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/sbin/ignition-ostree-populate-var diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-populate-var.sh b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-populate-var.sh new file mode 100755 index 0000000..01212db --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-populate-var.sh @@ -0,0 +1,45 @@ +#!/bin/bash +set -euo pipefail + +fatal() { + echo "$@" >&2 + exit 1 +} + +if [ $# -ne 0 ]; then + fatal "Usage: $0" +fi + +# See the similar code block in Anaconda, which handles this today for Atomic +# Host and Silverblue: +# https://github.com/rhinstaller/anaconda/blob/b9ea8ce4e68196b30a524c1cc5680dcdc4b89371/pyanaconda/payload/rpmostreepayload.py#L332 + +for varsubdir in lib log home roothome opt srv usrlocal mnt media; do + + # If the directory already existed, just ignore. This addresses the live + # image case with persistent `/var`; we don't want to relabel all the files + # there on each boot. + if [ -d "/sysroot/var/${varsubdir}" ]; then + continue + fi + + if [[ $varsubdir == lib ]] || [[ $varsubdir == log ]]; then + # Simply manually mkdir /var/{lib,log}; the tmpfiles.d entries otherwise + # reference users/groups which we don't have access to from here + # (though... we *could* import them from the sysroot, and have + # nss-altfiles in the initrd, but meh... let's just wait for + # systemd-sysusers which will make this way easier: + # https://github.com/coreos/fedora-coreos-config/pull/56/files#r262592361). + mkdir -p /sysroot/var/${varsubdir} + else + systemd-tmpfiles --create --boot --root=/sysroot --prefix="/var/${varsubdir}" + fi + + if [[ $varsubdir == roothome ]]; then + # TODO move this to tmpfiles.d once systemd-tmpfiles handles C! with --root correctly. + # See https://github.com/coreos/fedora-coreos-config/pull/137 + cp /sysroot/etc/skel/.bash* /sysroot/var/${varsubdir} + fi + + coreos-relabel "/var/${varsubdir}" +done diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-secex-config.service b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-secex-config.service new file mode 100644 index 0000000..292f571 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-secex-config.service @@ -0,0 +1,18 @@ +# RHOCS 4.12.s390x has an old kernel with a known issue: https://bugzilla.redhat.com/show_bug.cgi?id=2075085 +# Once we have kernel >= 4.18.0-387.el8.s390x we should drop this unit and copy config in coreos-diskful-generator +[Unit] +Description=Ignition OSTree: Inject Secure Execution Config +DefaultDependencies=false +ConditionArchitecture=s390x +ConditionKernelCommandLine=ostree +ConditionPathExists=/run/coreos/secure-execution +OnFailure=emergency.target +OnFailureJobMode=isolate + +After=coreos-gpt-setup.service +Before=ignition-fetch-offline.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/libexec/ignition-ostree-secex-config diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-secex-config.sh b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-secex-config.sh new file mode 100755 index 0000000..5a9736e --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-secex-config.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -euo pipefail + +bootdev=$(blkid --list-one --output device --match-token PARTLABEL=boot | sed 's,[0-9]\+$,,') +sed "s,\${BOOTDEV},$bootdev," < /usr/lib/coreos/01-secex.ign > /usr/lib/ignition/base.d/01-secex.ign diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-transposefs-detect.service b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-transposefs-detect.service new file mode 100644 index 0000000..389dc9e --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-transposefs-detect.service @@ -0,0 +1,20 @@ +[Unit] +Description=Ignition OSTree: Detect Partition Transposition +DefaultDependencies=false +After=ignition-fetch.service +Before=ignition-disks.service +Before=initrd-root-fs.target +Before=sysroot.mount +ConditionKernelCommandLine=ostree +OnFailure=emergency.target +OnFailureJobMode=isolate + +# This stage requires udevd to detect disks +Requires=systemd-udevd.service +After=systemd-udevd.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/libexec/ignition-ostree-transposefs detect +ExecStop=/usr/libexec/ignition-ostree-transposefs cleanup diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-transposefs-restore.service b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-transposefs-restore.service new file mode 100644 index 0000000..4eca578 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-transposefs-restore.service @@ -0,0 +1,20 @@ +[Unit] +Description=Ignition OSTree: Restore Partitions +DefaultDependencies=false +After=ignition-disks.service +# Avoid racing with UUID regeneration +After=ignition-ostree-uuid-root.service +Before=ignition-ostree-growfs.service +Before=ignition-ostree-mount-firstboot-sysroot.service +OnFailure=emergency.target +OnFailureJobMode=isolate + +ConditionKernelCommandLine=ostree +ConditionPathIsDirectory=/run/ignition-ostree-transposefs + +[Service] +Type=oneshot +RemainAfterExit=yes +# So we can transiently mount sysroot +MountFlags=slave +ExecStart=/usr/libexec/ignition-ostree-transposefs restore diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-transposefs-save.service b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-transposefs-save.service new file mode 100644 index 0000000..bc03499 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-transposefs-save.service @@ -0,0 +1,19 @@ +[Unit] +Description=Ignition OSTree: Save Partitions +DefaultDependencies=false +After=ignition-ostree-transposefs-detect.service +Before=ignition-disks.service +ConditionKernelCommandLine=ostree +ConditionPathIsDirectory=/run/ignition-ostree-transposefs +# Any services looking at mounts need to order after this +# because it causes device re-probing. +After=coreos-gpt-setup.service +OnFailure=emergency.target +OnFailureJobMode=isolate + +[Service] +Type=oneshot +RemainAfterExit=yes +# So we can transiently mount sysroot +MountFlags=slave +ExecStart=/usr/libexec/ignition-ostree-transposefs save diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-transposefs.sh b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-transposefs.sh new file mode 100755 index 0000000..4578531 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-transposefs.sh @@ -0,0 +1,299 @@ +#!/bin/bash +set -euo pipefail + +boot_sector_size=440 +esp_typeguid=c12a7328-f81f-11d2-ba4b-00a0c93ec93b +bios_typeguid=21686148-6449-6e6f-744e-656564454649 +prep_typeguid=9e1a2d38-c612-4316-aa26-8b49521e5a8b + +# This is implementation details of Ignition; in the future, we should figure +# out a way to ask Ignition directly whether there's a filesystem with label +# "root" being set up. +ignition_cfg=/run/ignition.json +root_part=/dev/disk/by-label/root +boot_part=/dev/disk/by-label/boot +esp_part=/dev/disk/by-label/EFI-SYSTEM +bios_part=/dev/disk/by-partlabel/BIOS-BOOT +prep_part=/dev/disk/by-partlabel/PowerPC-PReP-boot +saved_data=/run/ignition-ostree-transposefs +saved_root=${saved_data}/root +saved_boot=${saved_data}/boot +saved_esp=${saved_data}/esp +saved_bios=${saved_data}/bios +saved_prep=${saved_data}/prep +zram_dev=${saved_data}/zram_dev +partstate_root=/run/ignition-ostree-rootfs-partstate.sh + +# Print jq query string for wiped filesystems with label $1 +query_fslabel() { + echo ".storage?.filesystems? // [] | map(select(.label == \"$1\" and .wipeFilesystem == true))" +} + +# Print jq query string for partitions with type GUID $1 +query_parttype() { + echo ".storage?.disks? // [] | map(.partitions?) | flatten | map(select(try .typeGuid catch \"\" | ascii_downcase == \"$1\"))" +} + +# Print partition labels for partitions with type GUID $1 +get_partlabels_for_parttype() { + jq -r "$(query_parttype $1) | .[].label" "${ignition_cfg}" +} + +# Mounts device to directory, with extra logging of the src device +mount_verbose() { + local srcdev=$1; shift + local destdir=$1; shift + local mode=${1:-ro} + echo "Mounting ${srcdev} ${mode} ($(realpath "$srcdev")) to $destdir" + mkdir -p "${destdir}" + mount -o "${mode}" "${srcdev}" "${destdir}" +} + +# Sometimes, for some reason the by-label symlinks aren't updated. Detect these +# cases, and explicitly `udevadm trigger`. +# See: https://bugzilla.redhat.com/show_bug.cgi?id=1908780 +udev_trigger_on_label_mismatch() { + local label=$1; shift + local expected_dev=$1; shift + local actual_dev + expected_dev=$(realpath "${expected_dev}") + # We `|| :` here because sometimes /dev/disk/by-label/$label is missing. + # We've seen this on Fedora kernels with debug enabled (common in `rawhide`). + # See https://github.com/coreos/fedora-coreos-tracker/issues/1092 + actual_dev=$(realpath "/dev/disk/by-label/$label" || :) + if [ "$actual_dev" != "$expected_dev" ]; then + echo "Expected /dev/disk/by-label/$label to point to $expected_dev, but points to $actual_dev; triggering udev" + udevadm trigger --settle "$expected_dev" + fi +} + +# Print partition offset for device node $1 +get_partition_offset() { + local devpath=$(udevadm info --query=path "$1") + cat "/sys${devpath}/start" +} + +# copied from generator-lib.sh +karg() { + local name="$1" value="${2:-}" + local cmdline=( $(&2 + exit 1 + fi + mem_available=$(grep MemAvailable /proc/meminfo | awk '{print $2}') + # Just error out early if we don't even have 1G to work with. This + # commonly happens if you `cosa run` but forget to add `--memory`. That + # way you get a nicer error instead of the spew of EIO errors from `cp`. + # The amount we need is really dependent on a bunch of factors, but just + # ballpark it at 3G. + if [ "${mem_available}" -lt $((1*1024*1024)) ] && [ "${wipes_root}" != 0 ]; then + echo "Root reprovisioning requires at least 3G of RAM" >&2 + exit 1 + fi + modprobe zram num_devices=0 + read dev < /sys/class/zram-control/hot_add + # disksize is set arbitrarily large, as zram is capped by mem_limit + echo 10G > /sys/block/zram"${dev}"/disksize + # Limit zram to 90% of available RAM: we want to be greedy since the + # boot breaks anyway, but we still want to leave room for everything + # else so it hits ENOSPC and doesn't invoke the OOM killer + echo $(( mem_available * 90 / 100 ))K > /sys/block/zram"${dev}"/mem_limit + mkfs.xfs -q /dev/zram"${dev}" + mkdir "${saved_data}" + mount /dev/zram"${dev}" "${saved_data}" + # save the zram device number created for when called to cleanup + echo "${dev}" > "${zram_dev}" + + if [ "${wipes_root}" != "0" ]; then + mkdir "${saved_root}" + fi + if [ "${wipes_boot}" != "0" ]; then + mkdir "${saved_boot}" + fi + if [ "${creates_esp}" != "0" ]; then + mkdir "${saved_esp}" + fi + if [ "${creates_bios}" != "0" ]; then + mkdir "${saved_bios}" + fi + if [ "${creates_prep}" != "0" ]; then + mkdir "${saved_prep}" + fi + ;; + save) + # Mounts happen in a private mount namespace since we're not "offically" mounting + if [ -d "${saved_root}" ]; then + echo "Moving rootfs to RAM..." + mount_and_save_filesystem_by_label root "${saved_root}" + # also store the state of the partition + lsblk "${root_part}" --nodeps --pairs -b --paths -o NAME,TYPE,SIZE > "${partstate_root}" + fi + if [ -d "${saved_boot}" ]; then + echo "Moving bootfs to RAM..." + mount_and_save_filesystem_by_label boot "${saved_boot}" + fi + if [ -d "${saved_esp}" ]; then + echo "Moving EFI System Partition to RAM..." + mount_verbose "${esp_part}" /sysroot/boot/efi + cp -aT /sysroot/boot/efi "${saved_esp}" + fi + if [ -d "${saved_bios}" ]; then + echo "Moving BIOS Boot partition and boot sector to RAM..." + # save partition + cat "${bios_part}" > "${saved_bios}/partition" + # save boot sector + bios_disk=$(lsblk --noheadings --output PKNAME --paths "${bios_part}") + dd if="${bios_disk}" of="${saved_bios}/boot-sector" bs="${boot_sector_size}" count=1 status=none + # store partition start offset so we can check it later + get_partition_offset "${bios_part}" > "${saved_bios}/start" + fi + if [ -d "${saved_prep}" ]; then + echo "Moving PReP partition to RAM..." + cat "${prep_part}" > "${saved_prep}/partition" + fi + echo "zram usage:" + read dev < "${zram_dev}" + cat /sys/block/zram"${dev}"/mm_stat + ;; + restore) + # Mounts happen in a private mount namespace since we're not "offically" mounting + if [ -d "${saved_root}" ]; then + echo "Restoring rootfs from RAM..." + mount_and_restore_filesystem_by_label root /sysroot "${saved_root}" + chcon -v --reference "${saved_root}" /sysroot # the root of the fs itself + chattr +i $(ls -d /sysroot/ostree/deploy/*/deploy/*/) + fi + if [ -d "${saved_boot}" ]; then + echo "Restoring bootfs from RAM..." + mount_and_restore_filesystem_by_label boot /sysroot/boot "${saved_boot}" + chcon -v --reference "${saved_boot}" /sysroot/boot # the root of the fs itself + fi + if [ -d "${saved_esp}" ]; then + echo "Restoring EFI System Partition from RAM..." + get_partlabels_for_parttype "${esp_typeguid}" | while read label; do + # Don't use mount_and_restore_filesystem_by_label because: + # 1. We're mounting by partlabel, not FS label + # 2. We need to copy the contents to each partition, not move + # them once + # 3. We don't need the by-label symlink to be correct and + # nothing later in boot will be mounting the filesystem + mountpoint="/mnt/esp-${label}" + mount_verbose "/dev/disk/by-partlabel/${label}" "${mountpoint}" rw + find "${saved_esp}" -mindepth 1 -maxdepth 1 -exec cp -at "${mountpoint}" {} + + done + fi + if [ -d "${saved_bios}" ]; then + echo "Restoring BIOS Boot partition and boot sector from RAM..." + expected_start=$(cat "${saved_bios}/start") + get_partlabels_for_parttype "${bios_typeguid}" | while read label; do + cur_part="/dev/disk/by-partlabel/${label}" + # boot sector hardcodes the partition start; ensure it matches + cur_start=$(get_partition_offset "${cur_part}") + if [ "${cur_start}" != "${expected_start}" ]; then + echo "Partition ${cur_part} starts at ${cur_start}; expected ${expected_start}" >&2 + exit 1 + fi + # copy partition contents + cat "${saved_bios}/partition" > "${cur_part}" + # copy boot sector + cur_disk=$(lsblk --noheadings --output PKNAME --paths "${cur_part}") + cat "${saved_bios}/boot-sector" > "${cur_disk}" + done + fi + if [ -d "${saved_prep}" ]; then + echo "Restoring PReP partition from RAM..." + get_partlabels_for_parttype "${prep_typeguid}" | while read label; do + cat "${saved_prep}/partition" > "/dev/disk/by-partlabel/${label}" + done + fi + ;; + cleanup) + # Mounts are not in a private namespace so we can unmount ${saved_data} + if [ -d "${saved_data}" ]; then + read dev < "${zram_dev}" + umount "${saved_data}" + rm -rf "${saved_data}" "${partstate_root}" + echo "${dev}" > /sys/class/zram-control/hot_remove + fi + ;; + *) + echo "Unsupported operation: ${1:-}" 1>&2; exit 1 + ;; +esac diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-uuid-boot.service b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-uuid-boot.service new file mode 100644 index 0000000..8041562 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-uuid-boot.service @@ -0,0 +1,24 @@ +[Unit] +Description=Ignition OSTree: Regenerate Filesystem UUID (boot) +DefaultDependencies=false +ConditionPathExists=/usr/lib/initrd-release +ConditionKernelCommandLine=ostree +ConditionPathExists=!/run/ostree-live +# We run pretty early +Before=coreos-copy-firstboot-network.service +Before=coreos-ignition-setup-user.service +Before=ignition-fetch-offline.service +# Any services looking at mounts need to order after this +# because it causes device re-probing. +After=coreos-gpt-setup.service +# If we're going to reprovision the bootfs, then there's no need to restamp +ConditionKernelCommandLine=!bootfs.roothash + +Before=systemd-fsck@dev-disk-by\x2dlabel-boot.service +Requires=dev-disk-by\x2dlabel-boot.device +After=dev-disk-by\x2dlabel-boot.device + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/sbin/ignition-ostree-firstboot-uuid boot diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-uuid-root.service b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-uuid-root.service new file mode 100644 index 0000000..2648011 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-uuid-root.service @@ -0,0 +1,26 @@ +[Unit] +Description=Ignition OSTree: Regenerate Filesystem UUID (root) +# These conditions match ignition-ostree-mount-firstboot-sysroot.service +DefaultDependencies=false +ConditionKernelCommandLine=ostree +ConditionPathExists=!/run/ostree-live +Before=sysroot.mount initrd-root-fs.target +After=ignition-disks.service +# If we've reprovisioned the rootfs, then there's no need to restamp +ConditionPathExists=!/run/ignition-ostree-transposefs +ConditionKernelCommandLine=!rootfs.roothash + +After=dev-disk-by\x2dlabel-root.device +# Avoid racing with fsck +Before=systemd-fsck@dev-disk-by\x2dlabel-root.service +Before=systemd-fsck@dev-disk-by\x2dlabel-dm-mpath-root.service + +# Note we don't have a Requires: /dev/disk/by-label/root here like +# the -subsequent service does because ignition-disks may have +# regenerated it. +Before=ignition-ostree-mount-firstboot-sysroot.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/sbin/ignition-ostree-firstboot-uuid root diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/module-setup.sh b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/module-setup.sh new file mode 100755 index 0000000..f027b2c --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/module-setup.sh @@ -0,0 +1,115 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh + +depends() { + echo ignition rdcore +} + +install_ignition_unit() { + local unit=$1; shift + local target=${1:-complete} + inst_simple "$moddir/$unit" "$systemdsystemunitdir/$unit" + # note we `|| exit 1` here so we error out if e.g. the units are missing + # see https://github.com/coreos/fedora-coreos-config/issues/799 + systemctl -q --root="$initdir" add-requires "ignition-${target}.target" "$unit" || exit 1 +} + +installkernel() { + # Used by ignition-ostree-transposefs + instmods -c zram +} + +install() { + inst_multiple \ + realpath \ + setfiles \ + chcon \ + systemd-sysusers \ + systemd-tmpfiles \ + sort \ + uniq + + if [[ $(uname -m) = s390x ]]; then + # for Secure Execution + inst_multiple \ + veritysetup + fi + + # ignition-ostree-growfs deps + inst_multiple \ + basename \ + blkid \ + cat \ + dirname \ + findmnt \ + growpart \ + realpath \ + resize2fs \ + tail \ + tune2fs \ + touch \ + xfs_admin \ + xfs_growfs \ + wc \ + wipefs + + # growpart deps + # Mostly generated from the following command: + # $ bash --rpm-requires /usr/bin/growpart | sort | uniq | grep executable + # with a few false positives (rq, rqe, -v) and one missed (mktemp) + inst_multiple \ + awk \ + cat \ + dd \ + grep \ + mktemp \ + partx \ + rm \ + sed \ + sfdisk \ + sgdisk \ + find + + for x in mount populate; do + install_ignition_unit ignition-ostree-${x}-var.service + inst_script "$moddir/ignition-ostree-${x}-var.sh" "/usr/sbin/ignition-ostree-${x}-var" + done + + inst_simple \ + /usr/lib/udev/rules.d/90-coreos-device-mapper.rules + + inst_multiple jq chattr + inst_script "$moddir/ignition-ostree-transposefs.sh" "/usr/libexec/ignition-ostree-transposefs" + for x in detect save restore; do + install_ignition_unit ignition-ostree-transposefs-${x}.service + done + + # Disk support + install_ignition_unit ignition-ostree-mount-firstboot-sysroot.service diskful + for p in boot root; do + install_ignition_unit ignition-ostree-uuid-${p}.service diskful + done + inst_script "$moddir/ignition-ostree-firstboot-uuid" \ + "/usr/sbin/ignition-ostree-firstboot-uuid" + install_ignition_unit ignition-ostree-mount-subsequent-sysroot.service diskful-subsequent + inst_script "$moddir/ignition-ostree-mount-sysroot.sh" \ + "/usr/sbin/ignition-ostree-mount-sysroot" + inst_script "$moddir/coreos-rootflags.sh" \ + "/usr/sbin/coreos-rootflags" + + install_ignition_unit ignition-ostree-growfs.service + inst_script "$moddir/ignition-ostree-growfs.sh" \ + /usr/sbin/ignition-ostree-growfs + + install_ignition_unit ignition-ostree-check-rootfs-size.service + inst_script "$moddir/coreos-check-rootfs-size" \ + /usr/libexec/coreos-check-rootfs-size + + inst_script "$moddir/coreos-relabel" /usr/bin/coreos-relabel + + # Workaround for https://bugzilla.redhat.com/show_bug.cgi?id=2075085 + install_ignition_unit ignition-ostree-secex-config.service + inst_script "$moddir/ignition-ostree-secex-config.sh" \ + /usr/libexec/ignition-ostree-secex-config +} diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/50coreos-kernel/coreos-check-kernel.service b/overlay.d/05core/usr/lib/dracut/modules.d/50coreos-kernel/coreos-check-kernel.service new file mode 100644 index 0000000..ce8a0ac --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/50coreos-kernel/coreos-check-kernel.service @@ -0,0 +1,10 @@ +[Unit] +Description=Check that initrd matches kernel +DefaultDependencies=false +Before=sysinit.target systemd-modules-load.service +ConditionPathIsDirectory=!/usr/lib/modules/%v + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/bin/false diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/50coreos-kernel/module-setup.sh b/overlay.d/05core/usr/lib/dracut/modules.d/50coreos-kernel/module-setup.sh new file mode 100644 index 0000000..cac7b64 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/50coreos-kernel/module-setup.sh @@ -0,0 +1,15 @@ +install_unit() { + unit="$1"; shift + target="$1"; shift + inst_simple "$moddir/$unit" "$systemdsystemunitdir/$unit" + # note we `|| exit 1` here so we error out if e.g. the units are missing + # see https://github.com/coreos/fedora-coreos-config/issues/799 + systemctl -q --root="$initdir" add-requires "$target" "$unit" || exit 1 +} + +install() { + inst_multiple \ + false + + install_unit "coreos-check-kernel.service" "sysinit.target" +} diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/60coreos-agetty-workaround/coreos-touch-run-agetty.service b/overlay.d/05core/usr/lib/dracut/modules.d/60coreos-agetty-workaround/coreos-touch-run-agetty.service new file mode 100644 index 0000000..b6984b1 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/60coreos-agetty-workaround/coreos-touch-run-agetty.service @@ -0,0 +1,13 @@ +# Temporary hack to work around agetty SELinux denials. +# https://github.com/coreos/fedora-coreos-config/pull/859#issuecomment-783713383 +# https://bugzilla.redhat.com/show_bug.cgi?id=1932053 +[Unit] +Description=CoreOS: Touch /run/agetty.reload +Documentation=https://bugzilla.redhat.com/show_bug.cgi?id=1932053 +DefaultDependencies=false +Before=initrd.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/bin/touch /run/agetty.reload diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/60coreos-agetty-workaround/module-setup.sh b/overlay.d/05core/usr/lib/dracut/modules.d/60coreos-agetty-workaround/module-setup.sh new file mode 100755 index 0000000..1423fd5 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/60coreos-agetty-workaround/module-setup.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh + +# Temporary workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1932053. + +install_unit() { + local unit=$1; shift + inst_simple "$moddir/$unit" "$systemdsystemunitdir/$unit" + # note we `|| exit 1` here so we error out if e.g. the units are missing + # see https://github.com/coreos/fedora-coreos-config/issues/799 + systemctl -q --root="$initdir" add-requires initrd.target "$unit" || exit 1 +} + +install() { + inst_multiple \ + touch + + # TODO f35: check if we can drop this whole module + install_unit coreos-touch-run-agetty.service +} diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/99emergency-shell-setup/emergency-shell.sh b/overlay.d/05core/usr/lib/dracut/modules.d/99emergency-shell-setup/emergency-shell.sh new file mode 100644 index 0000000..8fa214e --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/99emergency-shell-setup/emergency-shell.sh @@ -0,0 +1,78 @@ +# Display relevant errors then enter emergency shell + +# _wait_for_journalctl_to_stop will block until either: +# - no messages have appeared in journalctl for the past 5 seconds +# - 15 seconds have elapsed +_wait_for_journalctl_to_stop() { + local time_since_last_log=0 + + local time_started="$(date '+%s')" + local now="$(date '+%s')" + + while [ ${time_since_last_log} -lt 5 -a $((now-time_started)) -lt 15 ]; do + sleep 1 + + local last_log_timestamp="$(journalctl -e -n 1 -q -o short-unix | cut -d '.' -f 1)" + local now="$(date '+%s')" + + local time_since_last_log=$((now-last_log_timestamp)) + done +} + +_display_relevant_errors() { + failed=$(systemctl --failed --no-legend --plain | cut -f 1 -d ' ') + if [ -n "${failed}" ]; then + # Something failed, suppress kernel logs so that it's more likely + # the useful bits from the journal are available. + dmesg --console-off + + # There's a couple straggler systemd messages. Wait until it's been 5 + # seconds since something was written to the journal. + _wait_for_journalctl_to_stop + + # Print Ignition logs + if echo ${failed} | grep -qFe 'ignition-'; then + cat </dev/null; then + cat < /dev/"$_tty" +done < /proc/consoles diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/99emergency-shell-setup/ignition-virtio-dump-journal.service b/overlay.d/05core/usr/lib/dracut/modules.d/99emergency-shell-setup/ignition-virtio-dump-journal.service new file mode 100644 index 0000000..513043a --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/99emergency-shell-setup/ignition-virtio-dump-journal.service @@ -0,0 +1,16 @@ +[Unit] +Description=Dump journal to virtio port +ConditionPathExists=/etc/initrd-release +DefaultDependencies=false +ConditionVirtualization=|kvm +ConditionVirtualization=|qemu +Requires=systemd-journald.service +After=systemd-journald.service +After=basic.target +Before=initrd.target + +[Service] +Type=oneshot +RemainAfterExit=yes +EnvironmentFile=/run/ignition.env +ExecStart=/usr/bin/ignition-virtio-dump-journal diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/99emergency-shell-setup/ignition-virtio-dump-journal.sh b/overlay.d/05core/usr/lib/dracut/modules.d/99emergency-shell-setup/ignition-virtio-dump-journal.sh new file mode 100755 index 0000000..806b374 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/99emergency-shell-setup/ignition-virtio-dump-journal.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -euo pipefail + +port=/dev/virtio-ports/com.coreos.ignition.journal +if [ -e "${port}" ]; then + # Sync to backing filesystem before dumping what's there + journalctl --sync + journalctl -o json > "${port}" + # And this signals end of stream + echo '{}' > "${port}" +else + echo "Didn't find virtio port ${port}" +fi diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/99emergency-shell-setup/module-setup.sh b/overlay.d/05core/usr/lib/dracut/modules.d/99emergency-shell-setup/module-setup.sh new file mode 100755 index 0000000..df52cba --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/99emergency-shell-setup/module-setup.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh + +install_unit_wants() { + local unit="$1"; shift + local target="$1"; shift + local instantiated="${1:-$unit}"; shift + inst_simple "$moddir/$unit" "$systemdsystemunitdir/$unit" + # note we `|| exit 1` here so we error out if e.g. the units are missing + # see https://github.com/coreos/fedora-coreos-config/issues/799 + systemctl -q --root="$initdir" add-wants "$target" "$instantiated" || exit 1 +} + +install() { + inst_multiple \ + cut \ + date \ + dd + + inst_hook emergency 99 "${moddir}/emergency-shell.sh" + + inst_script "$moddir/ignition-virtio-dump-journal.sh" "/usr/bin/ignition-virtio-dump-journal" + install_unit_wants ignition-virtio-dump-journal.service emergency.target +} diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/99journal-conf/00-journal-log-forwarding.conf b/overlay.d/05core/usr/lib/dracut/modules.d/99journal-conf/00-journal-log-forwarding.conf new file mode 100644 index 0000000..c7654af --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/99journal-conf/00-journal-log-forwarding.conf @@ -0,0 +1,12 @@ +[Journal] +# For now we are using kmsg for multiplexing output to +# multiple console devices during early boot. +# +# We do not want to use kmsg in the future as there may be sensitive +# ignition data that leaks to non-root users (by reading the kernel +# ring buffer using `dmesg`). In the future we will rely on kernel +# console multiplexing (link below) for this and will not use kmsg. +# +# https://github.com/coreos/fedora-coreos-tracker/issues/136 +ForwardToKMsg=yes +MaxLevelKMsg=info diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/99journal-conf/module-setup.sh b/overlay.d/05core/usr/lib/dracut/modules.d/99journal-conf/module-setup.sh new file mode 100755 index 0000000..e6626b2 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/99journal-conf/module-setup.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh + +depends() { + echo systemd +} + +install() { + inst_simple "$moddir/00-journal-log-forwarding.conf" \ + "/etc/systemd/journald.conf.d/00-journal-log-forwarding.conf" +} diff --git a/overlay.d/05core/usr/lib/sysctl.d/10-coreos-ratelimit-kmsg.conf b/overlay.d/05core/usr/lib/sysctl.d/10-coreos-ratelimit-kmsg.conf new file mode 100644 index 0000000..e605a61 --- /dev/null +++ b/overlay.d/05core/usr/lib/sysctl.d/10-coreos-ratelimit-kmsg.conf @@ -0,0 +1,3 @@ +# See also 10coreos-sysctl dracut module, which turns off ratelimiting in the +# initrd. +kernel.printk_devkmsg = ratelimit diff --git a/overlay.d/05core/usr/lib/systemd/journald.conf.d/10-coreos-persistent.conf b/overlay.d/05core/usr/lib/systemd/journald.conf.d/10-coreos-persistent.conf new file mode 100644 index 0000000..7910c16 --- /dev/null +++ b/overlay.d/05core/usr/lib/systemd/journald.conf.d/10-coreos-persistent.conf @@ -0,0 +1,6 @@ +# Hardcode persistent journal by default. journald has this "auto" behaviour +# that only makes logs persistent if `/var/log/journal` exists, which it won't +# on first boot because `/var` isn't fully populated. We should be able to get +# rid of this once we move to sysusers and create the dir in the initrd. +[Journal] +Storage=persistent diff --git a/overlay.d/05core/usr/lib/systemd/system-generators/coreos-boot-mount-generator b/overlay.d/05core/usr/lib/systemd/system-generators/coreos-boot-mount-generator new file mode 100755 index 0000000..5724fdc --- /dev/null +++ b/overlay.d/05core/usr/lib/systemd/system-generators/coreos-boot-mount-generator @@ -0,0 +1,115 @@ +#!/bin/bash +export PATH="/usr/bin:/usr/sbin:${PATH}" +set -euo pipefail + +. /usr/lib/coreos/generator-lib.sh + +# Turn out if you boot with "root=..." $UNIT_DIR is not writable. +[ -w "${UNIT_DIR}" ] || { + echo "skipping coreos-boot-mount-generator: ${UNIT_DIR} is not writable" + exit 0 +} + +# If there's already an /etc/fstab entries for /boot, then this is is a non-FCOS +# system, likely RHCOS pre-4.3 (which still used Anaconda). In that case, we +# don't want to overwrite what the systemd-fstab-generator will do. +if findmnt --fstab /boot &>/dev/null; then + exit 0 +fi + +# Don't create mount units for /boot on live systems. +# ConditionPathExists won't work here because conditions don't affect +# the dependency on the underlying device unit. +if [ -f /run/ostree-live ]; then + exit 0 +fi + +add_wants() { + local name="$1"; shift + local wants_dir="${UNIT_DIR}/local-fs.target.wants" + mkdir -p "${wants_dir}" + ln -sf "../${name}" "${wants_dir}/${name}" +} + +# Generate mount units that work with device mapper. The traditional +# device unit (dev-disk-by\x2dlabel...) does not work since it is not the +# device that systemd will fsck. This code ensures that if the label +# is backed by a device-mapper target the dev-mapper.*.device is used. +mk_mount() { + local mount_pt="${1}"; shift + local path="${1}"; shift + local options="${1}"; shift + + local devservice=$(systemd-escape -p ${path} --suffix=service) + local unit_name=$(systemd-escape -p ${mount_pt} --suffix=mount) + + cat > "${UNIT_DIR}/${unit_name}" < "${out_dir}/10-autologin.conf" < /etc/sysctl.d/20-coreos-autologin-kernel-printk.conf +# Raise console message logging level from DEBUG (7) to WARNING (4) +# so that kernel debug message don't get interspersed on the console +# that +# may frustrate a user trying to interactively do an install with +# nmtui and coreos-installer. +kernel.printk=4 +EOF +} + +write_interactive_live_motd() { + # Write motd to a tmp file and not directly to /etc/motd because + # SELinux denies write from init_t to etc_t + cat < /run/interactive-live-motd + +########################################################################### +Welcome to the CoreOS live environment. This system is running completely +from memory, making it a good candidate for hardware discovery and +installing persistently to disk. Here is an example of running an install +to disk via coreos-installer: + +sudo coreos-installer install /dev/sda \\ + --ignition-url https://example.com/example.ign + +You may configure networking via 'sudo nmcli' or 'sudo nmtui' and have +that configuration persist into the installed system by passing the +'--copy-network' argument to 'coreos-installer install'. Please run +'coreos-installer install --help' for more information on the possible +install options. +########################################################################### + +EOF + # Create coreos-cp-interactive-live-motd.service to copy over the motd in + # place. Note this intentionally overwrites the existing motd, which is + # blank on FCOS and populated on RHCOS. + service="coreos-cp-interactive-live-motd.service" + cat < "${UNIT_DIR}/${service}" +# generated by coreos-liveiso-autologin-generator +[Unit] +Description=Copy CoreOS Interactive Live MOTD +Before=systemd-user-sessions.service +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/bin/cp -v /run/interactive-live-motd /etc/motd +EOF + mkdir -p "${UNIT_DIR}/multi-user.target.wants" + ln -sf "../${service}" "${UNIT_DIR}/multi-user.target.wants/" +} + +# Only allow automatic autologin on live systems +if [ ! -e /run/ostree-live ]; then + exit 0 +fi + +# Autologin on ISO boots but not PXE boots. The only way to tell the +# difference is a kernel argument. +if ! have_karg coreos.liveiso; then + exit 0 +fi + +# If the user supplied an Ignition config, they have the ability to enable +# autologin themselves. Don't automatically render them insecure, since +# they might be running in production and booting via e.g. IPMI. +if jq -e .userConfigProvided /etc/.ignition-result.json &>/dev/null; then + exit 0 +fi + +write_dropin "getty@.service" "--noclear" +# Also autologin on serial console if someone enables that +write_dropin "serial-getty@.service" "--keep-baud 115200,38400,9600" + +# When the installer runs a lot of things happen on the system (audit +# messages from running via sudo, re-reading partition table messages, +# mounting filesystem messages, etc.). Quieting the verbosity of the +# kernel console will help us keep our sanity. +quiet_kernel_console_messages + + +# Write an motd that will let the user know about the live environment +# and what is possible. +write_interactive_live_motd diff --git a/overlay.d/05core/usr/lib/systemd/system-preset/40-coreos-systemd.preset b/overlay.d/05core/usr/lib/systemd/system-preset/40-coreos-systemd.preset new file mode 100644 index 0000000..a242eba --- /dev/null +++ b/overlay.d/05core/usr/lib/systemd/system-preset/40-coreos-systemd.preset @@ -0,0 +1,16 @@ +# This file contains overrides for systemd services that are +# enabled by default, but conflict with things we ship. + +# We don't have swap by default, and systemd-oomd hard requires it. +disable systemd-oomd.service + +# Disable systemd-firstboot because it conflicts with Ignition. +# In most cases this is handled via the remove-from-packages +# bits in the manifest (ignition-and-ostree.yaml), but +# we want to support overlaying builds of systemd from git. +disable systemd-firstboot.service + +# This hasn't been tested with ostree/rpm-ostree and heavily overlaps +# with the latter. Preemptively disable the service; it will hopefully +# be subpackaged though for Fedora. +disable systemd-sysext.service diff --git a/overlay.d/05core/usr/lib/systemd/system-preset/40-coreos.preset b/overlay.d/05core/usr/lib/systemd/system-preset/40-coreos.preset new file mode 100644 index 0000000..f4577d8 --- /dev/null +++ b/overlay.d/05core/usr/lib/systemd/system-preset/40-coreos.preset @@ -0,0 +1,34 @@ +# Presets here that eventually should live in the generic fedora presets + +# console-login-helper-messages - https://github.com/coreos/console-login-helper-messages +enable console-login-helper-messages-gensnippet-os-release.service +enable console-login-helper-messages-gensnippet-ssh-keys.service +# CA certs (probably to add to base fedora eventually) +enable coreos-update-ca-trust.service +# Set kernel console log level +enable coreos-printk-quiet.service +# https://github.com/coreos/ignition/issues/1125 +enable coreos-ignition-firstboot-complete.service +# Delete Ignition config from provider on platforms where it's possible +# https://github.com/coreos/ignition/pull/1350 +enable ignition-delete-config.service +# Delete Ignition config from provider when upgrading existing nodes +enable coreos-ignition-delete-config.service +# Boot checkin services for cloud providers. +enable afterburn-checkin.service +enable afterburn-firstboot-checkin.service +# Target to write SSH key snippets from cloud providers. +enable afterburn-sshkeys.target +# Update agent +enable zincati.service +# Testing aid +enable coreos-liveiso-success.service +# See bootupd.yaml +enable bootupd.socket +# Enable rtas_errd for ppc64le to discover dynamically attached pci devices - https://bugzilla.redhat.com/show_bug.cgi?id=1811537 +# The event for the attached device comes as a diag event. +# Ideally it should have been added as part of base Fedora - but since it was arch specific, it was not added: https://bugzilla.redhat.com/show_bug.cgi?id=1433859 +enable rtas_errd.service +enable clevis-luks-askpass.path +# Provide status information about the Ignition run +enable coreos-ignition-write-issues.service diff --git a/overlay.d/05core/usr/lib/systemd/system/coreos-ignition-delete-config.service b/overlay.d/05core/usr/lib/systemd/system/coreos-ignition-delete-config.service new file mode 100644 index 0000000..cdcea62 --- /dev/null +++ b/overlay.d/05core/usr/lib/systemd/system/coreos-ignition-delete-config.service @@ -0,0 +1,28 @@ +# Can be removed from FCOS in Fedora 37 or after the next barrier release, +# whichever comes first. Can be removed from RHCOS in the first release +# after every node is guaranteed to have booted at least once with 4.11 or +# higher. + +[Unit] +Description=CoreOS Delete Ignition Config From Hypervisor +Documentation=https://coreos.github.io/ignition/ + +ConditionKernelCommandLine=|ignition.platform.id=virtualbox +ConditionKernelCommandLine=|ignition.platform.id=vmware +ConditionPathExists=!/var/lib/coreos-ignition-delete-config.stamp +# Hack: if the user masked ignition-delete-config.service, we shouldn't run +# either. +ConditionPathIsSymbolicLink=!/etc/systemd/system/ignition-delete-config.service + +# We check a stamp file written by ignition-delete-config.service. That +# service runs Before=sysinit.target, on which we have a default dependency, +# so this is really just documentation. +After=ignition-delete-config.service + +[Service] +Type=oneshot +ExecStart=/usr/libexec/coreos-ignition-delete-config +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/overlay.d/05core/usr/lib/systemd/system/coreos-ignition-firstboot-complete.service b/overlay.d/05core/usr/lib/systemd/system/coreos-ignition-firstboot-complete.service new file mode 100644 index 0000000..42adf1e --- /dev/null +++ b/overlay.d/05core/usr/lib/systemd/system/coreos-ignition-firstboot-complete.service @@ -0,0 +1,21 @@ +[Unit] +Description=CoreOS Mark Ignition Boot Complete +Documentation=https://docs.fedoraproject.org/en-US/fedora-coreos/ +ConditionKernelCommandLine=ignition.firstboot +ConditionPathExists=!/run/ostree-live +RequiresMountsFor=/boot + +[Service] +Type=oneshot +RemainAfterExit=yes +# The MountFlags=slave is so we remount /boot temporarily writable; +# see https://github.com/ostreedev/ostree/issues/1265 for the bigger picture. +# This option creates a new mount namespace; from the point of view of +# everything else, /boot stays readonly. We only have a transient writable mount +# for the lifetime of the unit. +MountFlags=slave +ExecStart=/usr/libexec/coreos-ignition-firstboot-complete + +[Install] +# Part of basic.target so this happens early on in firstboot +WantedBy=basic.target diff --git a/overlay.d/05core/usr/lib/systemd/system/coreos-ignition-write-issues.service b/overlay.d/05core/usr/lib/systemd/system/coreos-ignition-write-issues.service new file mode 100644 index 0000000..a6268b8 --- /dev/null +++ b/overlay.d/05core/usr/lib/systemd/system/coreos-ignition-write-issues.service @@ -0,0 +1,16 @@ +# This service writes issue files describing status +# information about the Ignition run, which includes +# Ignition warnings and information if no Ignition +# config is provided. +[Unit] +Description=Create Ignition Status Issue Files +Before=systemd-user-sessions.service +ConditionPathExists=/etc/.ignition-result.json + +[Service] +Type=oneshot +ExecStart=/usr/libexec/coreos-ignition-write-issues +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/overlay.d/05core/usr/lib/systemd/system/coreos-liveiso-success.service b/overlay.d/05core/usr/lib/systemd/system/coreos-liveiso-success.service new file mode 100644 index 0000000..d148d12 --- /dev/null +++ b/overlay.d/05core/usr/lib/systemd/system/coreos-liveiso-success.service @@ -0,0 +1,26 @@ +# This is used by our test framework in coreos-assembler +# since for the "live ISO without Ignition" case we +# don't have an easy way to test it. +[Unit] +Description=CoreOS Live ISO virtio success +Documentation=https://github.com/coreos/fedora-coreos-config +# Only run on the Live ISO, and only if there's no Ignition config +ConditionKernelCommandLine=coreos.liveiso +ConditionPathExists=!/config.ign +ConditionVirtualization=|kvm +ConditionVirtualization=|qemu +# Start running late to help ensure that the below conditional works +After=systemd-user-sessions.service +ConditionPathExists=/dev/virtio-ports/coreos.liveiso-success + +[Service] +Type=simple +# Wait for a user session to start, then write a static message to the +# virtio channel, which https://github.com/coreos/coreos-assembler/pull/1330 +# knows how to read. We previously did "journalctl -f ... | head -1" here, +# but RHEL 8 has systemd 239, which has +# https://github.com/systemd/systemd/issues/9374. +ExecStart=/bin/sh -c 'while [ -z "$(loginctl list-sessions --no-legend)" ]; do sleep 1; done; echo coreos-liveiso-success > /dev/virtio-ports/coreos.liveiso-success' + +[Install] +WantedBy=multi-user.target diff --git a/overlay.d/05core/usr/lib/systemd/system/coreos-printk-quiet.service b/overlay.d/05core/usr/lib/systemd/system/coreos-printk-quiet.service new file mode 100644 index 0000000..d93a32a --- /dev/null +++ b/overlay.d/05core/usr/lib/systemd/system/coreos-printk-quiet.service @@ -0,0 +1,27 @@ +[Unit] +Description=CoreOS: Set printk To Level 4 (warn) +Documentation=https://github.com/coreos/fedora-coreos-tracker/issues/1244 +# We can run right after `/proc` being mounted at least +DefaultDependencies=no +# We run as early as possible; the only dependency we have really +# is the implicit After=systemd-journald.socket injected by the +# default of our stdout writing to the journal. +Conflicts=shutdown.target +Before=sysinit.target shutdown.target +# We want this service to read what we wrote +Before=systemd-sysctl.service +# Relatedly, we don't want to override an explicitly specified kernel argument +ConditionKernelCommandLine=!debug +ConditionKernelCommandLine=!quiet +ConditionKernelCommandLine=!loglevel + +[Service] +Type=oneshot +RemainAfterExit=yes +# We need to make /run/sysctl.d if it doesn't exist and also +# ensure it has a SELinux label that works for systemd-sysctl.service. +# Then we just generate a sysctl file which is read by systemd-sysctl.service. +ExecStart=/bin/bash -euo pipefail -c 'mkdir -p /run/sysctl.d && chcon --reference=/etc/sysctl.d /run/sysctl.d && echo "kernel.printk = 4" > /run/sysctl.d/01-coreos-printk.conf' + +[Install] +WantedBy=sysinit.target diff --git a/overlay.d/05core/usr/lib/systemd/system/coreos-update-ca-trust.service b/overlay.d/05core/usr/lib/systemd/system/coreos-update-ca-trust.service new file mode 100644 index 0000000..d5e811f --- /dev/null +++ b/overlay.d/05core/usr/lib/systemd/system/coreos-update-ca-trust.service @@ -0,0 +1,31 @@ +# This service is currently specific to Fedora CoreOS, +# but we may want to add it to the base OS in the future. +# The idea here is to allow users to just drop in CA roots +# via Ignition without having to know to run the special +# update command. +[Unit] +Description=Run update-ca-trust +ConditionFirstBoot=true +# All services which use ConditionFirstBoot=yes should use +# Before=first-boot-complete.target, which is a target that +# was introduced in https://github.com/systemd/systemd/issues/4511 +# and hasn't propagated everywhere yet. Once the target propagates +# everywhere, we can drop the systemd-machine-id-commit.service +# from the Before= line. +Before=first-boot-complete.target systemd-machine-id-commit.service +Wants=first-boot-complete.target +ConditionDirectoryNotEmpty=/etc/pki/ca-trust/source/anchors/ +# We want to run quite early, in particular before anything +# that may speak TLS to external services. In the future, +# it may make sense to do this in the initramfs too. +DefaultDependencies=no +After=local-fs.target +Requires=local-fs.target + +[Service] +ExecStart=/usr/bin/update-ca-trust extract +Type=oneshot +RemainAfterExit=yes + +[Install] +WantedBy=basic.target diff --git a/overlay.d/05core/usr/lib/systemd/system/emergency.service.d/coreos-sulogin-force.conf b/overlay.d/05core/usr/lib/systemd/system/emergency.service.d/coreos-sulogin-force.conf new file mode 100644 index 0000000..d58bda6 --- /dev/null +++ b/overlay.d/05core/usr/lib/systemd/system/emergency.service.d/coreos-sulogin-force.conf @@ -0,0 +1,7 @@ +# https://github.com/coreos/coreos-installer/commit/15a79263d0bd5d72056a6080f6687dc10cba2dda +# https://github.com/systemd/systemd/pull/10397 +# We want things like `systemd.unit=emergency.target` and `single` on the +# kernel command line to just work even with our locked root account. +# This file is used as an override for both emergency.target and rescue.target. +[Service] +Environment=SYSTEMD_SULOGIN_FORCE=1 diff --git a/overlay.d/05core/usr/lib/systemd/system/ignition-delete-config.service.d/10-flag-file.conf b/overlay.d/05core/usr/lib/systemd/system/ignition-delete-config.service.d/10-flag-file.conf new file mode 100644 index 0000000..e501d74 --- /dev/null +++ b/overlay.d/05core/usr/lib/systemd/system/ignition-delete-config.service.d/10-flag-file.conf @@ -0,0 +1,7 @@ +# Create a flag file to notify coreos-ignition-delete-config.service that +# we've run, and put it in /run because /var isn't mounted yet. +# coreos-ignition-delete-config.service will then avoid trying to delete +# the config again, and will create a persistent stamp file in /var/lib. + +[Service] +ExecStart=/bin/touch /run/coreos-ignition-delete-config.stamp diff --git a/overlay.d/05core/usr/lib/systemd/system/rescue.service.d/coreos-sulogin-force.conf b/overlay.d/05core/usr/lib/systemd/system/rescue.service.d/coreos-sulogin-force.conf new file mode 120000 index 0000000..a8a1f7a --- /dev/null +++ b/overlay.d/05core/usr/lib/systemd/system/rescue.service.d/coreos-sulogin-force.conf @@ -0,0 +1 @@ +../emergency.service.d/coreos-sulogin-force.conf \ No newline at end of file diff --git a/overlay.d/05core/usr/lib/systemd/system/systemd-backlight@.service.d/45-after-ostree-remount.conf b/overlay.d/05core/usr/lib/systemd/system/systemd-backlight@.service.d/45-after-ostree-remount.conf new file mode 100644 index 0000000..fc1c821 --- /dev/null +++ b/overlay.d/05core/usr/lib/systemd/system/systemd-backlight@.service.d/45-after-ostree-remount.conf @@ -0,0 +1,4 @@ +# Temporary fix for https://github.com/coreos/fedora-coreos-tracker/issues/975 +# until https://github.com/ostreedev/ostree/issues/2115 is fixed. +[Unit] +After=ostree-remount.service diff --git a/overlay.d/05core/usr/lib/systemd/system/systemd-firstboot.service.d/fcos-disable.conf b/overlay.d/05core/usr/lib/systemd/system/systemd-firstboot.service.d/fcos-disable.conf new file mode 100644 index 0000000..fc7f005 --- /dev/null +++ b/overlay.d/05core/usr/lib/systemd/system/systemd-firstboot.service.d/fcos-disable.conf @@ -0,0 +1,5 @@ +# See the comment in 40-coreos-systemd.preset; we're +# keeping this even stronger disable override for now, +# but it may not really be necessary. +[Unit] +ConditionPathExists=/run/nosuchfile diff --git a/overlay.d/05core/usr/lib/udev/rules.d/65-gce-disk-naming.rules b/overlay.d/05core/usr/lib/udev/rules.d/65-gce-disk-naming.rules new file mode 100644 index 0000000..e19c1c5 --- /dev/null +++ b/overlay.d/05core/usr/lib/udev/rules.d/65-gce-disk-naming.rules @@ -0,0 +1,38 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Name the attached disks as the specified by deviceName. + +ACTION!="add|change", GOTO="gce_disk_naming_end" +SUBSYSTEM!="block", GOTO="gce_disk_naming_end" + +# SCSI naming +KERNEL=="sd*|vd*", ENV{ID_VENDOR}=="Google", IMPORT{program}="scsi_id --export --whitelisted -d $tempnode" + +# NVME naming +KERNEL=="nvme0n1*", ENV{ID_VENDOR}=="Google", ENV{ID_SERIAL_SHORT}="local-nvme-ssd-0" +KERNEL=="nvme0n2*", ENV{ID_VENDOR}=="Google", ENV{ID_SERIAL_SHORT}="local-nvme-ssd-1" +KERNEL=="nvme0n3*", ENV{ID_VENDOR}=="Google", ENV{ID_SERIAL_SHORT}="local-nvme-ssd-2" +KERNEL=="nvme0n4*", ENV{ID_VENDOR}=="Google", ENV{ID_SERIAL_SHORT}="local-nvme-ssd-3" +KERNEL=="nvme0n5*", ENV{ID_VENDOR}=="Google", ENV{ID_SERIAL_SHORT}="local-nvme-ssd-4" +KERNEL=="nvme0n6*", ENV{ID_VENDOR}=="Google", ENV{ID_SERIAL_SHORT}="local-nvme-ssd-5" +KERNEL=="nvme0n7*", ENV{ID_VENDOR}=="Google", ENV{ID_SERIAL_SHORT}="local-nvme-ssd-6" +KERNEL=="nvme0n8*", ENV{ID_VENDOR}=="Google", ENV{ID_SERIAL_SHORT}="local-nvme-ssd-7" +KERNEL=="nvme*", ENV{ID_VENDOR}=="Google", ENV{ID_SERIAL}="Google_EphemeralDisk_$env{ID_SERIAL_SHORT}" + +# Symlinks +KERNEL=="sd*|vd*|nvme*", ENV{DEVTYPE}=="disk", ENV{ID_VENDOR}=="Google", SYMLINK+="disk/by-id/google-$env{ID_SERIAL_SHORT}" +KERNEL=="sd*|vd*|nvme*", ENV{DEVTYPE}=="partition", ENV{ID_VENDOR}=="Google", SYMLINK+="disk/by-id/google-$env{ID_SERIAL_SHORT}-part%n" + +LABEL="gce_disk_naming_end" diff --git a/overlay.d/05core/usr/lib/udev/rules.d/68-azure-sriov-nm-unmanaged.rules b/overlay.d/05core/usr/lib/udev/rules.d/68-azure-sriov-nm-unmanaged.rules new file mode 100644 index 0000000..59cf73b --- /dev/null +++ b/overlay.d/05core/usr/lib/udev/rules.d/68-azure-sriov-nm-unmanaged.rules @@ -0,0 +1,4 @@ +# Accelerated Networking on Azure exposes a new SRIOV interface to the VM. +# This interface is transparently bonded to the synthetic interface, +# so NetworkManager should just ignore any SRIOV interfaces. +SUBSYSTEM=="net", DRIVERS=="hv_pci", ACTION=="add", ENV{NM_UNMANAGED}="1" diff --git a/overlay.d/05core/usr/lib/udev/rules.d/90-coreos-device-mapper.rules b/overlay.d/05core/usr/lib/udev/rules.d/90-coreos-device-mapper.rules new file mode 100644 index 0000000..385f262 --- /dev/null +++ b/overlay.d/05core/usr/lib/udev/rules.d/90-coreos-device-mapper.rules @@ -0,0 +1,27 @@ +# CoreOS-specific symlinks for dm-multipath filesystem labels, +# used for `label=boot` and `label=root`. + +ACTION=="remove", GOTO="dm_label_end" +SUBSYSTEM!="block", GOTO="dm_label_end" +KERNEL!="dm-*", GOTO="dm_label_end" + +# Ensure that the device mapper target is active +ENV{DM_SUSPENDED}=="1", GOTO="dm_label_end" + +# Only act on filesystems. This should prevent layered devices +# such as Raid on Multipath devices from appearing. +ENV{ID_FS_USAGE}!="filesystem", GOTO="dm_label_end" + +# And if the filesystem doesn't have a label+uuid, we're done. +ENV{ID_FS_LABEL_ENC}!="?*", GOTO="dm_label_end" +ENV{ID_FS_UUID_ENC}!="?*", GOTO="dm_label_end" + +# Setup up Multipath labels and UUID's. Match on DM_UUID which +# is stable regardless of whether friendly names are used or not. +# 66-kpartx.rules use DM_UUID to match for linear mappings on multipath +# targets. +ENV{DM_UUID}=="*mpath*" \ + , SYMLINK+="disk/by-label/dm-mpath-$env{ID_FS_LABEL_ENC}" \ + , SYMLINK+="disk/by-uuid/dm-mpath-$env{ID_FS_UUID_ENC}" + +LABEL="dm_label_end" diff --git a/overlay.d/05core/usr/libexec/coreos-ignition-delete-config b/overlay.d/05core/usr/libexec/coreos-ignition-delete-config new file mode 100755 index 0000000..59d4f0c --- /dev/null +++ b/overlay.d/05core/usr/libexec/coreos-ignition-delete-config @@ -0,0 +1,23 @@ +#!/bin/bash + +set -euo pipefail + +cmdline=( $( /run/issue.d/30_coreos_ignition_provisioning.issue + + # checking for /run/ostree-live as the live system with persistent storage can run Ignition more than once + if ! test -f /run/ostree-live && jq -e .previousReport.provisioningDate "${IGNITION_RESULT}" &>/dev/null; then + prevdate=$(date --date "$(jq -r .previousReport.provisioningDate "${IGNITION_RESULT}")" +"%Y/%m/%d %H:%M:%S %Z") + cat << EOF > /etc/issue.d/30_coreos_ignition_run_more_than_once.issue +${WARN} +############################################################################ +WARNING: Ignition previously ran on ${prevdate}. Unexpected +behavior may occur. Ignition is not designed to run more than once per system. +############################################################################ +${RESET} +EOF + fi + # In Ignition, we've two config validation checks, the one after + # fetching a config and the second after merging configs. Sometimes, + # a warning goes away after merging, however, it's possible that a + # warning appears in case merging creates a contradiction between + # two fields. So this workflow eventually sends duplicate warnings + # in journal entries. Hence, we need to avoid displaying duplicate + # Ignition warnings on the console. + # For e.g. In the journal entries, we might see the following logs: + # + # warning at $.systemd.units.0.contents, line 1 col 997: unit "echo@.service" is enabled, but has no install section so enable does nothing + # warning at $.systemd.units.0.contents: unit "echo@.service" is enabled, but has no install section so enable does nothing + # + # In order to normalize these logs, we'd need to get rid of the line + # and column numbers entirely using the sed command, and then use + # `sort -u` to remove duplicate content. After this, we'd see the + # following warning on the console: + # + # warning at $.systemd.units.0.contents: unit "echo@.service" is enabled, but has no install section so enable does nothing + # + # TODO: find a way to query journal entries recorded before the + # system switches to real root + journalctl -t ignition -o cat -p warning | sed -r 's/, line [0-9]+ col [0-9]+//g' | sort -u | while read line; do + echo -e "${WARN}Ignition: $line${RESET}" >> /etc/issue.d/30_coreos_ignition_warnings.issue + done +else + nreboots=$(($(journalctl --list-boots | wc -l) - 1)) + [ "${nreboots}" -eq 1 ] && boot="boot" || boot="boots" + echo "Ignition: ran on ${d} (at least $nreboots $boot ago)" \ + > /run/issue.d/30_coreos_ignition_provisioning.issue +fi + +if jq -e .userConfigProvided "${IGNITION_RESULT}" &>/dev/null; then + echo "Ignition: user-provided config was applied" \ + >> /run/issue.d/30_coreos_ignition_provisioning.issue +else + echo -e "${WARN}Ignition: no config provided by user${RESET}" \ + >> /run/issue.d/30_coreos_ignition_provisioning.issue +fi + +# Our makeshift way of getting /run/issue.d semantics. See: +# https://github.com/coreos/console-login-helper-messages/blob/e06fc88ae8fbcc3a422bc8c686f70c15aebb9d9a/usr/lib/console-login-helper-messages/issue.defs#L8-L17 +ln -sf /run/issue.d/30_coreos_ignition_provisioning.issue /etc/issue.d/ diff --git a/overlay.d/05core/usr/share/licenses/fedora-coreos-config/LICENSE b/overlay.d/05core/usr/share/licenses/fedora-coreos-config/LICENSE new file mode 100644 index 0000000..b81e261 --- /dev/null +++ b/overlay.d/05core/usr/share/licenses/fedora-coreos-config/LICENSE @@ -0,0 +1,21 @@ +Copyright 2018 Fedora CoreOS Authors. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/overlay.d/05core/usr/share/licenses/fedora-coreos-config/README.md b/overlay.d/05core/usr/share/licenses/fedora-coreos-config/README.md new file mode 100644 index 0000000..ba7a326 --- /dev/null +++ b/overlay.d/05core/usr/share/licenses/fedora-coreos-config/README.md @@ -0,0 +1,17 @@ +# fedora-coreos-config + +Today most components of Fedora CoreOS are built as RPMs; this +is the main exception. fedora-coreos-config is "architecture-independent glue" +and the overhead of building an RPM for each change is onerous. + +It's also *the* central point of management (e.g. it contains lockfiles), so having it be +an RPM too would become circular. Instead, coreos-assembler directly consumes it. + +The upstream git repository is: https://github.com/coreos/fedora-coreos-config + +From a running system, to find the source commit use: +``` +$ rpm-ostree status -b --json | jq -r '.deployments[0]."base-commit-meta"."coreos-assembler.config-gitrev"' +c8dbed9ce223bf86737c82dd763670c8a34e950f +$ +``` diff --git a/overlay.d/06el9/statoverride b/overlay.d/06el9/statoverride new file mode 100644 index 0000000..27a95af --- /dev/null +++ b/overlay.d/06el9/statoverride @@ -0,0 +1,2 @@ +# Config file for overriding permission bits on overlay files/dirs +# Format: = diff --git a/overlay.d/06el9/usr/lib/dracut/dracut.conf.d/coreos-zstd.conf b/overlay.d/06el9/usr/lib/dracut/dracut.conf.d/coreos-zstd.conf new file mode 100644 index 0000000..9a9c067 --- /dev/null +++ b/overlay.d/06el9/usr/lib/dracut/dracut.conf.d/coreos-zstd.conf @@ -0,0 +1,8 @@ +# Compress initrd with zstd. dracut defaults to -15, but we want the +# maximum reasonable compression, so override the command line to use +# dracut's defaults along with -19. +# +# We can't use this in RHCOS 8 because the kernel doesn't enable +# CONFIG_RD_ZSTD. + +compress="zstd -19 -q -T0" diff --git a/overlay.d/08nouveau/etc/modprobe.d/blacklist-nouveau.conf b/overlay.d/08nouveau/etc/modprobe.d/blacklist-nouveau.conf new file mode 100644 index 0000000..0cc994e --- /dev/null +++ b/overlay.d/08nouveau/etc/modprobe.d/blacklist-nouveau.conf @@ -0,0 +1,2 @@ +# See https://bugzilla.redhat.com/show_bug.cgi?id=1700056 +blacklist nouveau diff --git a/overlay.d/08nouveau/statoverride b/overlay.d/08nouveau/statoverride new file mode 100644 index 0000000..27a95af --- /dev/null +++ b/overlay.d/08nouveau/statoverride @@ -0,0 +1,2 @@ +# Config file for overriding permission bits on overlay files/dirs +# Format: = diff --git a/overlay.d/09misc/etc/sysconfig/README b/overlay.d/09misc/etc/sysconfig/README new file mode 100644 index 0000000..4d8d9bb --- /dev/null +++ b/overlay.d/09misc/etc/sysconfig/README @@ -0,0 +1,9 @@ +This directory is a legacy of Red Hat Linux days. +Do not write new software that uses configuration +files here. Instead your software should use a regular +config file in `/etc/foo.conf`, a configuration directory +such as `/etc/foo/`. + +Where appropriate, it's also best practice to use "systemd style config" +where default config files live in `/usr/lib/foo` that can be +overridden in `/etc` and `/run`. diff --git a/overlay.d/09misc/statoverride b/overlay.d/09misc/statoverride new file mode 100644 index 0000000..27a95af --- /dev/null +++ b/overlay.d/09misc/statoverride @@ -0,0 +1,2 @@ +# Config file for overriding permission bits on overlay files/dirs +# Format: = diff --git a/overlay.d/15fcos/etc/ssh/sshd_config.d/40-disable-passwords.conf b/overlay.d/15fcos/etc/ssh/sshd_config.d/40-disable-passwords.conf new file mode 100644 index 0000000..5785acd --- /dev/null +++ b/overlay.d/15fcos/etc/ssh/sshd_config.d/40-disable-passwords.conf @@ -0,0 +1,5 @@ +# Disable password logins by default. +# https://github.com/coreos/fedora-coreos-tracker/issues/138 +# This file must sort before 50-redhat.conf, which enables +# PasswordAuthentication. +PasswordAuthentication no diff --git a/overlay.d/15fcos/statoverride b/overlay.d/15fcos/statoverride new file mode 100644 index 0000000..27a95af --- /dev/null +++ b/overlay.d/15fcos/statoverride @@ -0,0 +1,2 @@ +# Config file for overriding permission bits on overlay files/dirs +# Format: = diff --git a/overlay.d/15fcos/usr/lib/dracut/modules.d/50ignition-conf-fcos/20-aws-nm-cloud-setup.ign b/overlay.d/15fcos/usr/lib/dracut/modules.d/50ignition-conf-fcos/20-aws-nm-cloud-setup.ign new file mode 100644 index 0000000..0d39b16 --- /dev/null +++ b/overlay.d/15fcos/usr/lib/dracut/modules.d/50ignition-conf-fcos/20-aws-nm-cloud-setup.ign @@ -0,0 +1,16 @@ +{ + "ignition": { + "version": "3.0.0" + }, + "storage": { + "files": [ + { + "path": "/etc/systemd/system/nm-cloud-setup.service.d/env-aws.conf", + "contents": { + "source": "data:,%5BService%5D%0AEnvironment%3DNM_CLOUD_SETUP_EC2%3Dyes%0A" + }, + "mode": 420 + } + ] + } +} diff --git a/overlay.d/15fcos/usr/lib/dracut/modules.d/50ignition-conf-fcos/20-azure-nm-cloud-setup.ign b/overlay.d/15fcos/usr/lib/dracut/modules.d/50ignition-conf-fcos/20-azure-nm-cloud-setup.ign new file mode 100644 index 0000000..ed2a5c5 --- /dev/null +++ b/overlay.d/15fcos/usr/lib/dracut/modules.d/50ignition-conf-fcos/20-azure-nm-cloud-setup.ign @@ -0,0 +1,16 @@ +{ + "ignition": { + "version": "3.0.0" + }, + "storage": { + "files": [ + { + "path": "/etc/systemd/system/nm-cloud-setup.service.d/env-azure.conf", + "contents": { + "source": "data:,%5BService%5D%0AEnvironment%3DNM_CLOUD_SETUP_AZURE%3Dyes%0A" + }, + "mode": 420 + } + ] + } +} diff --git a/overlay.d/15fcos/usr/lib/dracut/modules.d/50ignition-conf-fcos/20-gcp-nm-cloud-setup.ign b/overlay.d/15fcos/usr/lib/dracut/modules.d/50ignition-conf-fcos/20-gcp-nm-cloud-setup.ign new file mode 100644 index 0000000..22966dd --- /dev/null +++ b/overlay.d/15fcos/usr/lib/dracut/modules.d/50ignition-conf-fcos/20-gcp-nm-cloud-setup.ign @@ -0,0 +1,16 @@ +{ + "ignition": { + "version": "3.0.0" + }, + "storage": { + "files": [ + { + "path": "/etc/systemd/system/nm-cloud-setup.service.d/env-gcp.conf", + "contents": { + "source": "data:,%5BService%5D%0AEnvironment%3DNM_CLOUD_SETUP_GCP%3Dyes%0A" + }, + "mode": 420 + } + ] + } +} diff --git a/overlay.d/15fcos/usr/lib/dracut/modules.d/50ignition-conf-fcos/30-afterburn-sshkeys-core.ign b/overlay.d/15fcos/usr/lib/dracut/modules.d/50ignition-conf-fcos/30-afterburn-sshkeys-core.ign new file mode 100644 index 0000000..98fc47a --- /dev/null +++ b/overlay.d/15fcos/usr/lib/dracut/modules.d/50ignition-conf-fcos/30-afterburn-sshkeys-core.ign @@ -0,0 +1,13 @@ +{ + "ignition": { + "version": "3.0.0" + }, + "systemd": { + "units": [ + { + "enabled": true, + "name": "afterburn-sshkeys@core.service" + } + ] + } +} diff --git a/overlay.d/15fcos/usr/lib/dracut/modules.d/50ignition-conf-fcos/README.md b/overlay.d/15fcos/usr/lib/dracut/modules.d/50ignition-conf-fcos/README.md new file mode 100644 index 0000000..a9a2be9 --- /dev/null +++ b/overlay.d/15fcos/usr/lib/dracut/modules.d/50ignition-conf-fcos/README.md @@ -0,0 +1 @@ +FCOS enables `afterburn-sshkeys@core.service` from `30-afterburn-sshkeys-core.ign`, allowing the user to prevent Ignition from enabling the service with a user config if the user wants to change the username. Unlike FCOS, RHCOS doesn't fetch SSH keys from cloud providers and thus doesn't need `afterburn-sshkeys@core.service`. diff --git a/overlay.d/15fcos/usr/lib/dracut/modules.d/50ignition-conf-fcos/module-setup.sh b/overlay.d/15fcos/usr/lib/dracut/modules.d/50ignition-conf-fcos/module-setup.sh new file mode 100755 index 0000000..8e9f9d9 --- /dev/null +++ b/overlay.d/15fcos/usr/lib/dracut/modules.d/50ignition-conf-fcos/module-setup.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh + +depends() { + echo ignition +} + +install() { + mkdir -p "$initdir/usr/lib/ignition/base.d" + mkdir -p "$initdir/usr/lib/ignition/base.platform.d" + + # Common entries + inst "$moddir/30-afterburn-sshkeys-core.ign" \ + "/usr/lib/ignition/base.d/30-afterburn-sshkeys-core.ign" + + # Platform specific: aws + mkdir -p "$initdir/usr/lib/ignition/base.platform.d/aws" + inst "$moddir/20-aws-nm-cloud-setup.ign" \ + "/usr/lib/ignition/base.platform.d/aws/20-aws-nm-cloud-setup.ign" + + # Platform specific: azure + mkdir -p "$initdir/usr/lib/ignition/base.platform.d/azure" + inst "$moddir/20-azure-nm-cloud-setup.ign" \ + "/usr/lib/ignition/base.platform.d/azure/20-azure-nm-cloud-setup.ign" + + # Platform specific: gcp + mkdir -p "$initdir/usr/lib/ignition/base.platform.d/gcp" + inst "$moddir/20-gcp-nm-cloud-setup.ign" \ + "/usr/lib/ignition/base.platform.d/gcp/20-gcp-nm-cloud-setup.ign" +} diff --git a/overlay.d/15fcos/usr/lib/motd.d/tracker.motd b/overlay.d/15fcos/usr/lib/motd.d/tracker.motd new file mode 100644 index 0000000..aff5d6b --- /dev/null +++ b/overlay.d/15fcos/usr/lib/motd.d/tracker.motd @@ -0,0 +1,3 @@ +Tracker: https://github.com/coreos/fedora-coreos-tracker +Discuss: https://discussion.fedoraproject.org/tag/coreos + diff --git a/overlay.d/15fcos/usr/lib/systemd/system-preset/45-fcos.preset b/overlay.d/15fcos/usr/lib/systemd/system-preset/45-fcos.preset new file mode 100644 index 0000000..fd18bec --- /dev/null +++ b/overlay.d/15fcos/usr/lib/systemd/system-preset/45-fcos.preset @@ -0,0 +1,3 @@ +enable coreos-check-ssh-keys.service +# Check if cgroupsv1 is still being used +enable coreos-check-cgroups.service diff --git a/overlay.d/15fcos/usr/lib/systemd/system/coreos-check-cgroups.service b/overlay.d/15fcos/usr/lib/systemd/system/coreos-check-cgroups.service new file mode 100644 index 0000000..18e4b85 --- /dev/null +++ b/overlay.d/15fcos/usr/lib/systemd/system/coreos-check-cgroups.service @@ -0,0 +1,11 @@ +# This service is used for printing a message if +# cgroups v1 is still being used +[Unit] +Description=Check if cgroupsv1 is still being used +ConditionControlGroupController=v1 +[Service] +Type=oneshot +ExecStart=/usr/libexec/coreos-check-cgroups +RemainAfterExit=yes +[Install] +WantedBy=multi-user.target diff --git a/overlay.d/15fcos/usr/lib/systemd/system/coreos-check-ssh-keys.service b/overlay.d/15fcos/usr/lib/systemd/system/coreos-check-ssh-keys.service new file mode 100644 index 0000000..6c97fa1 --- /dev/null +++ b/overlay.d/15fcos/usr/lib/systemd/system/coreos-check-ssh-keys.service @@ -0,0 +1,24 @@ +# This service is used for printing a message if no ssh keys were added +# by Ignition/Afterburn +[Unit] +Description=Check that ssh-keys are added by Afterburn/Ignition +# It allows other units to synchronize around any instance +# of `afterburn-sshkeys@` and not just the `core` user. +# See https://github.com/coreos/afterburn/pull/481 +After=afterburn-sshkeys.target +# Only perform checks on the first (Ignition) boot as they are +# mostly useful only on that boot. This ensures systems started +# before Ignition/Afterburn started logging structured data don't +# get misleading messages. Also handles the case where the journal +# gets rotated and no longer has the structured log messages. +ConditionKernelCommandLine=ignition.firstboot +# Run before user sessions to avoid reloading agetty +Before=systemd-user-sessions.service + +[Service] +Type=oneshot +ProtectHome=read-only +ExecStart=/usr/libexec/coreos-check-ssh-keys +RemainAfterExit=yes +[Install] +WantedBy=multi-user.target diff --git a/overlay.d/15fcos/usr/lib/sysusers.d/00-coreos-nobody.conf b/overlay.d/15fcos/usr/lib/sysusers.d/00-coreos-nobody.conf new file mode 100644 index 0000000..86e5d56 --- /dev/null +++ b/overlay.d/15fcos/usr/lib/sysusers.d/00-coreos-nobody.conf @@ -0,0 +1,9 @@ +# Legacy IDs for 'nobody' user/group. This is a CoreOS mismatched entry +# which will need to be migrated: +# https://github.com/coreos/fedora-coreos-tracker/issues/1201 + +# g nobody 65534 +# u nobody 65534:65534 "Kernel Overflow User" - - + +g nobody 99 +u nobody 99:99 "Kernel Overflow User" - - diff --git a/overlay.d/15fcos/usr/lib/sysusers.d/00-coreos-static.conf b/overlay.d/15fcos/usr/lib/sysusers.d/00-coreos-static.conf new file mode 100644 index 0000000..9678fe6 --- /dev/null +++ b/overlay.d/15fcos/usr/lib/sysusers.d/00-coreos-static.conf @@ -0,0 +1,32 @@ +# These are pinned users/groups whose static IDs are only used +# this way on CoreOS nodes. + +g cgred 996 +g chrony 992 +g cockpit-ws 987 +g dockerroot 986 +g etcd 997 +g input 104 +g kube 994 +g nfsnobody 65534 +g polkitd 998 +g ssh_keys 999 +g sssd 993 +g sudo 16 +g systemd-bus-proxy 988 +g systemd-network 990 +g systemd-resolve 989 +g systemd-timesync 991 + +u chrony 994:992 - /var/lib/chrony - +u cockpit-ws 988:987 "User for cockpit-ws" - - +u dockerroot 997:986 "Docker User" /var/lib/docker - +u etcd 998:997 "etcd user" /var/lib/etcd - +u kube 996:994 "Kubernetes user" - - +u nfsnobody 65534:65534 "Anonymous NFS User" /var/lib/nfs - +u polkitd 999:998 "User for polkitd" - - +u sssd 995:993 "User for sssd" - - +u systemd-bus-proxy 989:988 "systemd Bus Proxy" - - +u systemd-network 991:990 "systemd Network Management" - - +u systemd-resolve 990:989 "systemd Resolver" - - +u systemd-timesync 993:991 "systemd Time Synchronization" - - diff --git a/overlay.d/15fcos/usr/lib/sysusers.d/10-setup-basic.conf b/overlay.d/15fcos/usr/lib/sysusers.d/10-setup-basic.conf new file mode 100644 index 0000000..597b8d2 --- /dev/null +++ b/overlay.d/15fcos/usr/lib/sysusers.d/10-setup-basic.conf @@ -0,0 +1,43 @@ +# These are basic users/groups coming from the default entries +# in the 'setup' package. They can be dropped once that package +# starts shipping its own sysusers.d entries. + +g adm 4 +g audio 63 +g bin 1 +g cdrom 11 +g daemon 2 +g dialout 18 +g disk 6 +g floppy 19 +g ftp 50 +g games 20 +g kmem 9 +g lock 54 +g lp 7 +g mail 12 +g man 15 +g mem 8 +g root 0 +g sys 3 +g tape 33 +g tty 5 +g users 100 +g video 39 +g wheel 10 + +u adm 3:4 "adm" /var/adm - +u bin 1:1 "bin" /bin - +u daemon 2:2 "daemon" /sbin - +u ftp 14:50 "FTP User" /var/ftp - +# Workaround for systemd-sysusers bug, will be fixed in v252: +# https://github.com/systemd/systemd/issues/24217 +# u games 12:100 "games" /usr/games - +u games 12:users "games" /usr/games - +u halt 7:0 "halt" /sbin /sbin/halt +u lp 4:7 "lp" /var/spool/lpd - +u mail 8:12 "mail" /var/spool/mail - +u operator 11:0 "operator" /root - +u root 0:0 "root" /root /bin/bash +u shutdown 6:0 "shutdown" /sbin /sbin/shutdown +u sync 5:0 "sync" /sbin /bin/sync diff --git a/overlay.d/15fcos/usr/lib/sysusers.d/10-static-extra.conf b/overlay.d/15fcos/usr/lib/sysusers.d/10-static-extra.conf new file mode 100644 index 0000000..38f65ee --- /dev/null +++ b/overlay.d/15fcos/usr/lib/sysusers.d/10-static-extra.conf @@ -0,0 +1,24 @@ +# These are users/groups with static IDs which follow usual Fedora-wide +# allocation. They are usually coming from relevant packages, but we also +# pre-populate them on CoreOS. + +g avahi-autoipd 170 +g ceph 167 +g dbus 81 +g dip 40 +g rpc 32 +g rpcuser 29 +g sshd 74 +g systemd-journal 190 +g tcpdump 72 +g utempter 35 +g utmp 22 + +u avahi-autoipd 170:170 "Avahi IPv4LL Stack" /var/lib/avahi-autoipd - +u ceph 167:167 "Ceph daemons" /var/lib/ceph - +u dbus 81:81 "System Message Bus" - - +u nfsnobody 65534:65534 "Anonymous NFS User" /var/lib/nfs - +u rpc 32:32 "Rpcbind Daemon" /var/lib/rpcbind - +u rpcuser 29:29 "RPC Service User" /var/lib/nfs - +u sshd 74:74 "Privilege-separated SSH" /var/empty/sshd - +u tcpdump 72:72 - - - diff --git a/overlay.d/15fcos/usr/libexec/coreos-check-cgroups b/overlay.d/15fcos/usr/libexec/coreos-check-cgroups new file mode 100755 index 0000000..39a68b7 --- /dev/null +++ b/overlay.d/15fcos/usr/libexec/coreos-check-cgroups @@ -0,0 +1,25 @@ +#!/usr/bin/bash +# This script checks if the system is still using cgroups v1 +# and prints a message to the serial console. + +# Change the output color to yellow +warn=$(echo -e '\033[0;33m') +# No color +nc=$(echo -e '\033[0m') + +motd_path=/run/motd.d/30_cgroupsv1_warning.motd + +cat << EOF > "${motd_path}" +${warn} +############################################################################ +WARNING: This system is using cgroups v1. For increased reliability +it is strongly recommended to migrate this system and your workloads +to use cgroups v2. For instructions on how to adjust kernel arguments +to use cgroups v2, see: +https://docs.fedoraproject.org/en-US/fedora-coreos/kernel-args/ + +To disable this warning, use: +sudo systemctl disable coreos-check-cgroups.service +############################################################################ +${nc} +EOF diff --git a/overlay.d/15fcos/usr/libexec/coreos-check-ssh-keys b/overlay.d/15fcos/usr/libexec/coreos-check-ssh-keys new file mode 100755 index 0000000..fc8d4b9 --- /dev/null +++ b/overlay.d/15fcos/usr/libexec/coreos-check-ssh-keys @@ -0,0 +1,49 @@ +#!/usr/bin/bash +# This script will print a message in the serial console +# if no ssh keys were added by Ignition/Afterburn. +main() { + # Change the output color to yellow + warn='\033[0;33m' + # No color + nc='\033[0m' + + # See https://github.com/coreos/ignition/pull/964 for the MESSAGE_ID + # source. It will track the authorized-ssh-keys entries in journald + # provided via Ignition. Limit journal output to the most recent boot + # so we don't get output from re-used /var/ partitions. + ignitionusers=$( + journalctl -b 0 -o json-pretty MESSAGE_ID=225067b87bbd4a0cb6ab151f82fa364b | \ + jq -r '.MESSAGE' | \ + xargs -I{} echo "Ignition: {}") + + # See https://github.com/coreos/afterburn/pull/397 for the MESSAGE_ID + # source. It will track the authorized-ssh-keys entries in journald + # provided via Afterburn.Limit journal output to the most recent boot + # so we don't get output from re-used /var/ partitions. + + afterburnusers=$( + journalctl -b 0 -o json-pretty MESSAGE_ID=0f7d7a502f2d433caa1323440a6b4190 | \ + jq -r '.MESSAGE' | \ + xargs -I{} echo "Afterburn: {}") + + output='' + if [ -n "$ignitionusers" ]; then + output+="$ignitionusers" + fi + if [ -n "$afterburnusers" ]; then + # add newline if needed + if [ -n "$output" ]; then + output+=$'\n' + fi + output+="$afterburnusers" + fi + + if [ -n "$output" ]; then + echo "$output" > /etc/issue.d/30_ssh_authorized_keys.issue + else + echo -e "${warn}No SSH authorized keys provided by Ignition or Afterburn${nc}" \ + > /etc/issue.d/30_ssh_authorized_keys.issue + fi +} + +main diff --git a/overlay.d/20platform-chrony/statoverride b/overlay.d/20platform-chrony/statoverride new file mode 100644 index 0000000..27a95af --- /dev/null +++ b/overlay.d/20platform-chrony/statoverride @@ -0,0 +1,2 @@ +# Config file for overriding permission bits on overlay files/dirs +# Format: = diff --git a/overlay.d/20platform-chrony/usr/lib/systemd/system-generators/coreos-platform-chrony b/overlay.d/20platform-chrony/usr/lib/systemd/system-generators/coreos-platform-chrony new file mode 100755 index 0000000..c917af2 --- /dev/null +++ b/overlay.d/20platform-chrony/usr/lib/systemd/system-generators/coreos-platform-chrony @@ -0,0 +1,95 @@ +#!/bin/bash +set -euo pipefail +# Configuring the timeserver for the platform is often handled +# by pre-baking a config into a particular image for a platform, but +# that doesn't work for us because we have a single update stream. Hence +# this generator dynamically inspects the platform and reconfigures chrony. +# +# AWS: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/set-time.html +# Azure: https://docs.microsoft.com/en-us/azure/virtual-machines/linux/time-sync +# GCP: https://cloud.google.com/compute/docs/instances/managing-instances#configure-ntp +# +# Originally spawned from discussion in https://github.com/openshift/installer/pull/3513 + +. /usr/lib/coreos/generator-lib.sh + +self=$(basename $0) +confpath=/run/coreos-platform-chrony.conf + +platform=$(karg ignition.platform.id) +case "${platform}" in + azure|azurestack|aws|gcp) ;; # OK, this is a platform we know how to support + *) exit 0 ;; +esac + +# Exit early if we have already been run once +if [[ -f "${confpath}" ]]; then + echo "$self: ${confpath} already exists; skipping" + exit 0 +fi + +# Exit early if chrony configuration as been changed from the image default +if ! cmp {/usr,}/etc/chrony.conf >/dev/null; then + echo "$self: /etc/chrony.conf is modified; not changing the default" + exit 0 +fi + +# If not set already (by host customization or this script), set +# PEERNTP=no so that DHCP-provided NTP servers are not added to chrony. +# By doing this we assume the better NTP server choice is the +# platform-provided link-local NTP server rather than others from DHCP. +# TODO: once https://bugzilla.redhat.com/show_bug.cgi?id=1828434 is +# resolved, this won't be required. +if [ ! -e /etc/sysconfig/network ] || ! grep -q "PEERNTP" /etc/sysconfig/network; then + cat <> /etc/sysconfig/network +# PEERNTP=no is automatically added by default when a platform-provided time +# source is available, but this behavior may be overridden through an Ignition +# config specifying PEERNTP=yes. See https://github.com/coreos/fedora-coreos-config/pull/412. +PEERNTP=no +EOF +fi + +(echo "# Generated by $self - do not edit directly" + sed -e s,'^makestep,#makestep,' -e s,'^pool,#pool,' -e s,'^leapsectz,#leapsectz,' < /etc/chrony.conf +cat < "${confpath}" +case "${platform}" in + azure | azurestack) + # the /dev/ptp_hyperv symlink is created by: + # https://github.com/systemd/systemd/blob/e67a5c14f0345f5ac456cfa109324dd9e70114d3/rules.d/50-udev-default.rules.in#L106 + (echo '# See also https://docs.microsoft.com/en-us/azure/virtual-machines/linux/time-sync' + echo 'refclock PHC /dev/ptp_hyperv poll 3 dpoll -2 offset 0' + echo 'leapsectz right/UTC' + ) >> "${confpath}" ;; + aws) + (echo '# See also https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/set-time.html' + echo 'server 169.254.169.123 prefer iburst minpoll 4 maxpoll 4' + ) >> "${confpath}" ;; + gcp) + (echo '# See also https://cloud.google.com/compute/docs/instances/managing-instances#configure-ntp' + echo '# and https://cloud.google.com/compute/docs/images/configuring-imported-images' + echo 'server metadata.google.internal prefer iburst' + ) >> "${confpath}" ;; + *) echo "should not be reached" 1>&2; exit 1 ;; +esac +# Policy doesn't allow chronyd to read run_t +chcon --reference=/etc/chrony.conf "${confpath}" + +UNIT_DIR="${1:-/tmp}" + +unitconfpath="${UNIT_DIR}/chronyd.service.d/coreos-platform-chrony.conf" +mkdir -p $(dirname "${unitconfpath}") +cat >"${unitconfpath}" << EOF +[Service] +ExecStart= +ExecStart=/usr/sbin/chronyd -f ${confpath} \$OPTIONS +EOF + +echo "$self: Updated chrony to use ${platform} configuration ${confpath}" diff --git a/overlay.d/README.md b/overlay.d/README.md new file mode 100644 index 0000000..ece8485 --- /dev/null +++ b/overlay.d/README.md @@ -0,0 +1,55 @@ +These overlay directories are automatically committed to the build OSTree repo +by coreos-assembler. They are then explicitly included in our various manifest +files via `ostree-layers` (this used to be done automatically, but that's no +longer the case). + +05core +------ + +This overlay matches `fedora-coreos-base.yaml`; core Ignition+ostree bits. + +06el9 +----- + +This overlay includes content shared between FCOS and RHCOS/SCOS 9, but not +RHCOS 8. + +08nouveau +--------- + +Blacklist the nouveau driver because it causes issues with some NVidia GPUs in EC2, +and we don't have a use case for FCOS with nouveau. + +"Cannot boot an p3.2xlarge instance with RHCOS (g3.4xlarge is working)" +https://bugzilla.redhat.com/show_bug.cgi?id=1700056 + +09misc +------ + +Warning about `/etc/sysconfig`. + +15fcos +------ + +Things that are more closely "Fedora CoreOS": + +* disable password logins by default over SSH +* enable SSH keys written by Ignition and Afterburn +* branding (MOTD) +* enable FCOS-specific services by default +* display warnings on the console if no ignition config was provided or no ssh + key found. + +16disable-zincati +----------------- + +Disable Zincati on non-production streams: +https://github.com/coreos/fedora-coreos-tracker/issues/163 + +20platform-chrony +----------------- + +Add static chrony configuration for NTP servers provided on platforms +such as `azure`, `aws`, `gcp`. The chrony config for these NTP servers +should override other chrony configuration (e.g. DHCP-provided) +configuration. diff --git a/rocky-86-baseos.repo b/rocky-86-baseos.repo deleted file mode 100644 index bc60787..0000000 --- a/rocky-86-baseos.repo +++ /dev/null @@ -1,8 +0,0 @@ -[baseos] -name=Rocky Linux $releasever - BaseOS -mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=BaseOS-$releasever -#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/BaseOS/$basearch/os/ -gpgcheck=1 -enabled=1 -countme=1 -gpgkey=file:///usr/share/distribution-gpg-keys/rocky/RPM-GPG-KEY-Rocky-9 diff --git a/rocky-86-appstream.repo b/rocky.repo similarity index 50% rename from rocky-86-appstream.repo rename to rocky.repo index 3f7fae0..10952a3 100644 --- a/rocky-86-appstream.repo +++ b/rocky.repo @@ -6,3 +6,12 @@ gpgcheck=1 enabled=1 countme=1 gpgkey=file:///usr/share/distribution-gpg-keys/rocky/RPM-GPG-KEY-Rocky-9 + +[baseos] +name=Rocky Linux $releasever - BaseOS +mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=BaseOS-$releasever +#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/BaseOS/$basearch/os/ +gpgcheck=1 +enabled=1 +countme=1 +gpgkey=file:///usr/share/distribution-gpg-keys/rocky/RPM-GPG-KEY-Rocky-9