#cloud-config autoinstall: version: 1 # Locale, keyboard, timezone locale: en_US.UTF-8 keyboard: layout: us variant: "" timezone: America/New_York # Network: DHCP only, on every wired NIC. On the standard two-NIC box the # GE corporate NIC gets an address and the imaging NIC (no DHCP server on # the imaging LAN) stays without one. No static 172.16.9.1 here: matched # by name it would land on EVERY NIC, the GE one included, and the box # would answer as 172.16.9.1 on the corporate network. First boot's # playbook replaces this file with the two-NIC config pinned by MAC # (pxe_nic_mac / corp_nic_mac in playbook/site-vars.yml). optional: the # install and boot never wait for a lease (air-gapped is fine). network: version: 2 ethernets: any-eth: match: name: "en*" dhcp4: true dhcp6: false optional: true # The install is always offline, even when the corp NIC has a lease and # internet: the mirror points at a closed local port, so subiquity's # mirror check fails and it installs from the ISO alone (no "security # updates" step from the archive). The base is then exactly the ISO's, # which is what download-packages.sh resolved the offline set against; # late-commands patch it from CIDATA. The real archive sources are # written back at the end of late-commands. apt: geoip: false preserve_sources_list: false primary: - arches: [default] uri: "http://127.0.0.1:9/ubuntu" fallback: offline-install # Storage configuration storage: layout: name: lvm match: size: largest swap: size: 0 # User identity identity: hostname: pxeserver username: pxe password: '$6$MV3UwfSxKqxDYCwt$2IPUfSvqpzUdH6QVKHfPH8I9E0SPqNCh0lLvn.D9btxhZUYmceOGcB51Ryfg1Fojlroin.qguSKYFoIDGUIC20' # Enable SSH ssh: install-server: true allow-pw: true # Installer-stage late commands late-commands: # Step 1: Upgrade and install from the offline set on CIDATA # (packages/ is an apt repo: debs + Packages + explicit.list). Any apt # error fails the install; the log is /var/log/offline-apt-install.log. - | curtin in-target --target=/target -- bash -euc ' mkdir -p /mnt/cidata CIDATA_DEV=$(blkid -L CIDATA) mount -o ro "$CIDATA_DEV" /mnt/cidata set +e bash /mnt/cidata/offline-apt-install.sh /mnt/cidata/packages 2>&1 | tee /var/log/offline-apt-install.log rc=${PIPESTATUS[0]} set -e umount /mnt/cidata if [ "$rc" -ne 0 ]; then echo "offline package install FAILED (rc=$rc), see /var/log/offline-apt-install.log" >&2 exit "$rc" fi if command -v nmcli >/dev/null; then systemctl enable NetworkManager fi ' # Step 2: Disable networkd-wait-online (hangs on air-gapped network) - ln -sf /dev/null /target/etc/systemd/system/systemd-networkd-wait-online.service # Step 3: Create first-boot.sh - | curtin in-target --target=/target -- bash -c ' cat <<"EOF" > /opt/first-boot.sh #!/bin/bash # Expand root LV to full disk BEFORE playbook (playbook copies ~130GB of drivers+PPKGs) ROOT_DEV=$(findmnt -n -o SOURCE /) ROOT_DISK=$(lsblk -n -o PKNAME "$(readlink -f "$ROOT_DEV")" | tail -1) PV_PART=$(pvs --noheadings -o pv_name 2>/dev/null | tr -d "[:space:]" | head -1) if [ -n "$ROOT_DISK" ] && [ -n "$PV_PART" ]; then PART_NUM=$(echo "$PV_PART" | grep -o "[0-9]*$") growpart "/dev/${ROOT_DISK}" "${PART_NUM}" 2>&1 || true pvresize "$PV_PART" 2>&1 || true fi lvextend -r -l +100%FREE /dev/mapper/ubuntu--vg-ubuntu--lv 2>&1 || true CIDATA_DEV=$(blkid -L CIDATA) if [ -n "$CIDATA_DEV" ]; then mkdir -p /mnt/usb mount "$CIDATA_DEV" /mnt/usb if [ -f /mnt/usb/playbook/pxe_server_setup.yml ]; then cd /mnt/usb/playbook ansible-playbook -i localhost, -c local pxe_server_setup.yml cd / fi umount /mnt/usb fi sed -i "s|^/opt/first-boot.sh.*|# &|" /etc/rc.local EOF chmod +x /opt/first-boot.sh ' # Step 4: Create rc.local - | curtin in-target --target=/target -- bash -c ' cat <<"EOF" > /etc/rc.local #!/bin/bash /opt/first-boot.sh > /var/log/first-boot.log 2>&1 & exit 0 EOF chmod +x /etc/rc.local ' # Step 5: Real archive sources for later online maintenance (the # install used a dead mirror on purpose, see apt: above). - | rm -f /target/etc/apt/sources.list.d/*.list /target/etc/apt/sources.list.d/*.curtin.orig echo "# Ubuntu sources have moved to /etc/apt/sources.list.d/ubuntu.sources" > /target/etc/apt/sources.list cat > /target/etc/apt/sources.list.d/ubuntu.sources <<"EOF" Types: deb URIs: http://archive.ubuntu.com/ubuntu/ Suites: noble noble-updates noble-backports Components: main restricted universe multiverse Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg Types: deb URIs: http://security.ubuntu.com/ubuntu/ Suites: noble-security Components: main restricted universe multiverse Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg EOF user-data: disable_root: false refresh-installer: update: no