#!/bin/bash
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
# ex: ts=8 sw=4 sts=4 et filetype=sh

set -e

# 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}"

cmdline=( $(</proc/cmdline) )
cmdline_arg() {
    local name="$1" value="$2"
    for arg in "${cmdline[@]}"; do
        if [[ "${arg%%=*}" == "${name}" ]]; then
            value="${arg#*=}"
        fi
    done
    echo "${value}"
}

cmdline_bool() {
    local value=$(cmdline_arg "$@")
    case "$value" in
        ""|0|no|off) return 1;;
        *) return 0;;
    esac
}

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}"
}

add_wants() {
    local name="$1"
    local wants_dir="${UNIT_DIR}/initrd.target.wants"
    mkdir -p "${wants_dir}"
    ln -sf "../${name}" "${wants_dir}/${name}"
}


# This can't be done with ConditionKernelCommandLine because that always
# starts the unit's dependencies. We want to start networking only on first
# boot.
if $(cmdline_bool flatcar.first_boot 0) || $(cmdline_bool coreos.first_boot 0); then
    add_requires ignition-complete.target initrd.target
    # Only try to mount the ESP if GRUB detected a first_boot file
    if [[ $(cmdline_arg flatcar.first_boot) = "detected" ]] || [[ $(cmdline_arg coreos.first_boot) = "detected" ]]; then
        add_requires ignition-quench.service initrd.target
    fi
    if [[ $(cmdline_arg flatcar.oem.id) == "packet" ]] || [[ $(cmdline_arg coreos.oem.id) == "packet" ]]; then
        add_requires flatcar-static-network.service initrd.target
    fi

    # On EC2, shut down systemd-networkd if ignition fails so that the instance
    # fails EC2 instance checks.
    if [[ $(cmdline_arg flatcar.oem.id) == "ec2" ]] || [[ $(cmdline_arg coreos.oem.id) == "ec2" ]]; then
        mkdir -p ${UNIT_DIR}/systemd-networkd.service.d
        cat > ${UNIT_DIR}/systemd-networkd.service.d/10-conflict-emergency.conf <<EOF
[Unit]
Conflicts=emergency.target
Conflicts=emergency.service
Conflicts=dracut-emergency.service
EOF
    fi
    # Configure hostname from metadata through afterburn on platforms that don't set it via DHCP
    add_wants flatcar-metadata-hostname.service
    if [[ $(cmdline_arg flatcar.oem.id) == "openstack" ]] || [[ $(cmdline_arg coreos.oem.id) == "openstack" ]]; then
        add_wants flatcar-openstack-hostname.service
    fi
else
    # If we're doing a non-Ignition (subsequent) boot, then
    # queue a different target.  This is necessary so that units
    # like `ignition-ostree-mount-sysroot.service`
    # can cleanly distinguish between the two.
    add_requires ignition-subsequent.target initrd.target
fi

# Write ignition-setup.service customized for PXE/ISO or regular boot
pxe=
nopxe=
usr=$(cmdline_arg mount.usr "$(cmdline_arg usr)")
if [[ -z "${usr}" && -f /usr.squashfs ]]; then
    # PXE-booted system, with or without persistent root
    # (see 10diskless-generator)
    pxe=1
else
    nopxe=1
    if $(cmdline_bool flatcar.first_boot 0) || $(cmdline_bool coreos.first_boot 0); then
        add_requires ignition-diskful.target ignition-complete.target
    else
        add_requires ignition-diskful-subsequent.target ignition-subsequent.target
    fi
fi
cat > ${UNIT_DIR}/ignition-setup-pre.service <<EOF
[Unit]
Description=Ignition env setup
DefaultDependencies=false

Requires=local-fs-pre.target
Before=local-fs-pre.target

OnFailure=emergency.target
OnFailureJobMode=isolate

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/sbin/ignition-setup-pre
EOF

cat > ${UNIT_DIR}/ignition-setup.service <<EOF
[Unit]
Description=Ignition (setup)
DefaultDependencies=false

# Flatcar: Load Ignition binary
Requires=sysusr-usr.mount ignition-setup-pre.service
After=sysusr-usr.mount ignition-setup-pre.service

Requires=local-fs-pre.target
Before=local-fs-pre.target

# pull in OEM device if it should exist
${nopxe:+Requires=dev-disk-by\x2dlabel-OEM.device
After=dev-disk-by\x2dlabel-OEM.device}

OnFailure=emergency.target
OnFailureJobMode=isolate

[Service]
Type=oneshot
RemainAfterExit=yes
MountFlags=slave
ExecStart=/usr/sbin/ignition-setup ${nopxe:+normal} ${pxe:+pxe}
EOF

# Call the disk UUID randomizer whenever we're not PXE booting
# The unit will check if it needs to act or not.
if [ "${nopxe}" = 1 ]; then
    add_requires "disk-uuid.service" initrd.target
fi

if [[ $(cmdline_arg flatcar.oem.id) == "digitalocean" ]] || [[ $(cmdline_arg coreos.oem.id) == "digitalocean" ]] || [[ $(cmdline_arg flatcar.oem.id) == "proxmoxve" ]]; then
    add_requires flatcar-afterburn-network.service initrd.target
fi
