Fabian Vogt
ec1e979ea6
Changed the "Try disks next" section to check for both lower and upper case volume names. This is necessary for FAT/FAT32 volumes created under Windows. OBS-URL: https://build.opensuse.org/request/show/929857 OBS-URL: https://build.opensuse.org/package/show/devel:kubic:ignition/combustion?expand=0&rev=22
184 lines
5.5 KiB
Bash
184 lines
5.5 KiB
Bash
#!/bin/bash
|
|
# SPDX-FileCopyrightText: 2020 SUSE LLC
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
set -euo pipefail
|
|
|
|
config_mount="/run/combustion/mount"
|
|
|
|
if [ "${1-}" = "--prepare" ]; then
|
|
# Mount config drive
|
|
mkdir -p "${config_mount}"
|
|
|
|
config_drive_found=0
|
|
|
|
# Try fw_cfg first
|
|
if [ -e "/sys/firmware/qemu_fw_cfg/by_name/opt/org.opensuse.combustion" ]; then
|
|
mkdir -p "${config_mount}/combustion"
|
|
if ! cp /sys/firmware/qemu_fw_cfg/by_name/opt/org.opensuse.combustion/script/raw \
|
|
"${config_mount}/combustion/script"; then
|
|
echo "Failed to copy script from fw_cfg!"
|
|
exit 1
|
|
fi
|
|
# TODO: Support other files, e.g. with a tarball or fs image?
|
|
|
|
config_drive_found=1
|
|
fi
|
|
|
|
# Try disks next - both lower and upper case
|
|
for label in combustion COMBUSTION ignition IGNITION; do
|
|
[ "${config_drive_found}" = "1" ] && break
|
|
[ -e "/dev/disk/by-label/${label}" ] || continue
|
|
|
|
if ! mount -o ro /dev/disk/by-label/${label} "${config_mount}"; then
|
|
echo "Failed to mount config drive!"
|
|
exit 1
|
|
fi
|
|
|
|
config_drive_found=1
|
|
done
|
|
|
|
if [ "${config_drive_found}" = "0" ]; then
|
|
echo "No config drive found"
|
|
exit 0
|
|
fi
|
|
|
|
# Check for the magic flag "# combustion: network" in the script
|
|
if [ -e "${config_mount}/combustion/script" ] \
|
|
&& grep -qE '^# combustion:(.*)\<network\>' "${config_mount}/combustion/script"; then
|
|
sh -s <<EOF
|
|
. /lib/dracut-lib.sh
|
|
getargbool 0 'rd.neednet' && exit 0
|
|
echo rd.neednet=1 > /etc/cmdline.d/40-combustion-neednet.conf
|
|
# Re-trigger generation of network rules and apply them
|
|
. /lib/dracut/hooks/pre-udev/60-net-genrules.sh
|
|
udevadm control --reload
|
|
udevadm trigger --subsystem-match net --action add
|
|
EOF
|
|
fi
|
|
|
|
exit 0
|
|
fi
|
|
|
|
# Use /dev/shm for data exchange
|
|
exchangedir="/dev/shm/combustion/"
|
|
delete_resolv_conf=0
|
|
|
|
cleanup() {
|
|
if findmnt "${config_mount}" >/dev/null; then
|
|
umount "${config_mount}" || true
|
|
rmdir "${config_mount}" || true
|
|
else
|
|
rm -rf "${config_mount}" || true
|
|
fi
|
|
|
|
rm -rf "${exchangedir}" || true
|
|
|
|
if [ "${delete_resolv_conf}" -eq 1 ]; then
|
|
rm -f /sysroot/etc/resolv.conf || true
|
|
fi
|
|
|
|
# umount and remount so that the new default subvol is used
|
|
umount -R /sysroot
|
|
# Manual umount confuses systemd sometimes because it's async and the
|
|
# .mount unit might still be active when the "start" is queued, making
|
|
# it a noop, which ultimately leaves /sysroot unmounted
|
|
# (https://github.com/systemd/systemd/issues/20329). To avoid that,
|
|
# wait until systemd processed the umount events. In a chroot (or with
|
|
# SYSTEMD_OFFLINE=1) systemctl always succeeds, so avoid an infinite loop.
|
|
if ! systemctl is-active does-not-exist.mount; then
|
|
while systemctl is-active sysroot.mount; do sleep 0.5; done
|
|
fi
|
|
systemctl start sysroot.mount
|
|
}
|
|
|
|
trap cleanup EXIT
|
|
|
|
# ignition-mount.service mounts stuff below /sysroot in ExecStart and umounts
|
|
# it on ExecStop, failing if umounting fails. This conflicts with the
|
|
# mounts/umounts done by combustion. Ignition is already done, so just stop it.
|
|
if systemctl --quiet is-active ignition-mount.service; then
|
|
systemctl stop ignition-mount.service
|
|
fi
|
|
|
|
if ! [ -d "${config_mount}/combustion" ]; then
|
|
echo "No config found - doing nothing."
|
|
exit 0
|
|
fi
|
|
|
|
# Make sure /sysroot is mounted
|
|
systemctl start sysroot.mount
|
|
|
|
# Copy config
|
|
mkdir "${exchangedir}"
|
|
config_dir="${exchangedir}/config"
|
|
cp -R "${config_mount}/combustion" "${config_dir}"
|
|
|
|
if ! [ -e "${config_dir}/script" ]; then
|
|
echo "No config script found."
|
|
exit 1
|
|
fi
|
|
|
|
# Have to take care of x-initrd.mount first and from the outside
|
|
awk '$4 ~ /x-initrd.mount/ { system("findmnt /sysroot" $2 " >/dev/null || mount -t " $3 " -o " $4 " " $1 " /sysroot" $2) }' /sysroot/etc/fstab
|
|
|
|
# Make sure the old snapshot is relabeled too, otherwise syncing its /etc fails.
|
|
if [ -e /sysroot/etc/selinux/.autorelabel ]; then
|
|
NEWROOT=/sysroot bash -c '. /lib/dracut-lib.sh; . /lib/dracut/hooks/pre-pivot/50-selinux-microos-relabel.sh'
|
|
fi
|
|
|
|
# Prepare chroot
|
|
for i in proc sys dev; do
|
|
mount --rbind /$i /sysroot/$i
|
|
done
|
|
mount --make-rslave /sysroot
|
|
|
|
# Mount everything we can, errors deliberately ignored
|
|
chroot /sysroot mount -a || true
|
|
# t-u needs writable /var/run and /tmp
|
|
findmnt /sysroot/run >/dev/null || mount -t tmpfs tmpfs /sysroot/run
|
|
findmnt /sysroot/tmp >/dev/null || mount -t tmpfs tmpfs /sysroot/tmp
|
|
|
|
# Fake a netconfig setup
|
|
if [ -r /etc/resolv.conf ]; then
|
|
mkdir -p /sysroot/run/netconfig/
|
|
cp /etc/resolv.conf /sysroot/run/netconfig/resolv.conf
|
|
|
|
if ! [ -e /sysroot/etc/resolv.conf ]; then
|
|
if ln -sf /run/netconfig/resolv.conf /sysroot/etc/resolv.conf; then
|
|
delete_resolv_conf=1
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [ -x /sysroot/usr/sbin/transactional-update ]; then
|
|
# t-u doesn't allow running arbitrary commands and
|
|
# also ignores the shell's exit code, so DIY.
|
|
if ! chroot /sysroot transactional-update shell <<EOF; then
|
|
cd "${config_dir}"
|
|
chmod a+x script
|
|
./script
|
|
echo \$? > "${exchangedir}/retval"
|
|
EOF
|
|
echo "transactional-update failed"
|
|
exit 1
|
|
fi
|
|
|
|
if ! [ -e "${exchangedir}/retval" ] || [ "$(cat "${exchangedir}/retval")" -ne 0 ]; then
|
|
echo "Command failed, rolling back"
|
|
chroot /sysroot transactional-update --no-selfupdate rollback
|
|
exit 1
|
|
fi
|
|
|
|
# Snapshot got touched while the policy isn't active, needs relabeling again.
|
|
[ -e /sysroot/etc/selinux/.relabelled ] && >> /sysroot/etc/selinux/.autorelabel
|
|
else
|
|
mount -o remount,rw /sysroot
|
|
if ! chroot /sysroot sh -e -c "cd '${config_dir}'; chmod a+x script; ./script"; then
|
|
echo "Command failed"
|
|
exit 1
|
|
fi
|
|
chroot /sysroot snapper --no-dbus create -d "After combustion configuration" || :
|
|
fi
|
|
|
|
exit 0
|