Initial Commit
This commit is contained in:
Executable
+120
@@ -0,0 +1,120 @@
|
||||
#!/bin/bash
|
||||
# =====================================================================
|
||||
# Everything the autoinstall does to a base image, for an image that was
|
||||
# installed by hand instead.
|
||||
#
|
||||
# run INSIDE the Ubuntu guest, as root, during a maintenance boot:
|
||||
# sudo bash by-hand.sh
|
||||
#
|
||||
# WHY THIS EXISTS
|
||||
#
|
||||
# user-data builds an image unattended and this file is its late-commands
|
||||
# written out longhand. An image installed interactively - which is a
|
||||
# perfectly reasonable way to build one, and how this host's first Ubuntu
|
||||
# image was made - misses every one of them, and most of the misses are
|
||||
# silent: the machine works, and something about it is wrong once a
|
||||
# session is running and nobody is watching.
|
||||
#
|
||||
# Idempotent on purpose. It is meant to be run again after the operator
|
||||
# installs something else, without having to remember what it already did.
|
||||
# =====================================================================
|
||||
set -uo pipefail
|
||||
[ "$(id -u)" -eq 0 ] || { echo "run this with sudo" >&2; exit 1; }
|
||||
|
||||
say() { printf '\n== %s\n' "$*"; }
|
||||
user=$(id -nu 1000 2>/dev/null || echo "")
|
||||
|
||||
say "the control channel"
|
||||
# THE ONE THING WITHOUT WHICH NOTHING WORKS.
|
||||
# It is how every command reaches this machine. No agent, no session -
|
||||
# and the failure looks exactly like a machine that did not boot.
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq qemu-guest-agent
|
||||
systemctl enable --now qemu-guest-agent
|
||||
|
||||
say "what scripts under test tend to reach for"
|
||||
apt-get install -y -qq python3 python3-pip python3-venv git curl jq unzip ca-certificates
|
||||
|
||||
say "the project share"
|
||||
# The session mounts this itself over the guest channel, so the fstab
|
||||
# line is belt and braces - it makes the mount happen on a boot nobody
|
||||
# is driving, and `nofail` is what keeps a machine with no share from
|
||||
# dropping into an emergency shell where nothing can reach it.
|
||||
mkdir -p /mnt/project
|
||||
grep -q '^project /mnt/project virtiofs' /etc/fstab \
|
||||
|| printf 'project /mnt/project virtiofs rw,nofail,x-systemd.device-timeout=5 0 0\n' >> /etc/fstab
|
||||
|
||||
say "two minutes of every boot"
|
||||
# MEASURED on this image: systemd-networkd-wait-online 2min 0.072s, with
|
||||
# graphical.target reached at 2min 3s. The desktop is rendered by
|
||||
# NetworkManager, so networkd has no links to wait for and sits out its
|
||||
# entire timeout. The guest agent answers at multi-user, so a CLI session
|
||||
# never noticed - which is why this stayed invisible until a GUI session
|
||||
# spent two minutes photographing a black screen.
|
||||
systemctl mask systemd-networkd-wait-online.service NetworkManager-wait-online.service
|
||||
|
||||
say "a desktop with nobody at the keyboard"
|
||||
if [ -n "$user" ]; then
|
||||
mkdir -p /etc/gdm3
|
||||
cat > /etc/gdm3/custom.conf <<EOF
|
||||
[daemon]
|
||||
AutomaticLoginEnable=true
|
||||
AutomaticLogin=$user
|
||||
EOF
|
||||
# MEASURED ON 26.04: `WaylandEnable=false` used to be here, with an
|
||||
# xorg.conf.d file pinning the mode, because the agent clicks at
|
||||
# absolute coordinates and a screen that changes size makes every
|
||||
# learned position wrong.
|
||||
#
|
||||
# This release has no Xorg to fall back to - xserver-xorg-core is not
|
||||
# installed and /usr/share/xsessions is empty - so that line does not
|
||||
# choose X, it leaves GDM with no session to log in to at all, and an
|
||||
# autologin into nothing looks exactly like a machine that failed to
|
||||
# boot a desktop.
|
||||
#
|
||||
# Wayland costs nothing here: the agent's eyes and hands are QMP
|
||||
# `screendump` and `input-send-event`, which are the virtual hardware
|
||||
# and know nothing about the display server. The mode comes from the
|
||||
# virtio-vga device instead of from a config file, and it is stable
|
||||
# for the same reason the netdev is - the qemu argv is a constant.
|
||||
rm -f /etc/X11/xorg.conf.d/10-owuivm-resolution.conf
|
||||
# Every session IS the first one - the disk is restored from the same
|
||||
# frozen base every time - so the first-run wizard would open a modal
|
||||
# dialog over the desktop in front of the agent, every single run.
|
||||
install -d -o 1000 -g 1000 "/home/$user/.config"
|
||||
echo yes > "/home/$user/.config/gnome-initial-setup-done"
|
||||
chown 1000:1000 "/home/$user/.config/gnome-initial-setup-done"
|
||||
else
|
||||
echo " no uid 1000, skipping the desktop settings"
|
||||
fi
|
||||
|
||||
say "sources of background change"
|
||||
# Every session starts from this frozen disk. Anything that updates
|
||||
# itself in the background makes two runs of the same script differ, and
|
||||
# the difference shows up as a script that is flaky rather than as a
|
||||
# machine that changed underneath it.
|
||||
systemctl disable --now unattended-upgrades.service 2>/dev/null
|
||||
systemctl disable --now apt-daily.timer apt-daily-upgrade.timer 2>/dev/null
|
||||
# SNAPD IS HELD, NOT DISABLED, AND THAT IS A DELIBERATE DIFFERENCE.
|
||||
#
|
||||
# The autoinstall disables it outright. On a desktop image that also
|
||||
# takes Firefox away, because Firefox IS a snap here - and a GUI session
|
||||
# whose agent cannot open a browser has lost something real. What was
|
||||
# actually wanted is "stop changing underneath me", and holding refreshes
|
||||
# says exactly that while leaving the snaps that are installed working.
|
||||
snap refresh --hold >/dev/null 2>&1 && echo " snap refreshes held" \
|
||||
|| echo " could not hold snap refreshes (old snapd?); check 'snap refresh --hold'"
|
||||
# A remote desktop server inside the sandbox is a listening socket with
|
||||
# no route to it and no reason to exist; the operator's console comes
|
||||
# from QEMU's own VNC.
|
||||
systemctl disable --now gnome-remote-desktop.service 2>/dev/null
|
||||
[ -d /etc/cloud ] && touch /etc/cloud/cloud-init.disabled
|
||||
|
||||
say "what this machine looks like now"
|
||||
printf ' guest agent : %s\n' "$(systemctl is-active qemu-guest-agent)"
|
||||
printf ' autologin : %s\n' "$(grep -h '^AutomaticLogin=' /etc/gdm3/custom.conf 2>/dev/null || echo 'not set')"
|
||||
printf ' fstab : %s\n' "$(grep -h '^project ' /etc/fstab 2>/dev/null || echo 'no share line')"
|
||||
printf ' resolver : %s\n' "$(awk '/^nameserver/{printf "%s ", $2}' /etc/resolv.conf)"
|
||||
printf ' internet : %s\n' "$(curl -sS -o /dev/null -w '%{http_code}' --max-time 10 https://example.com/ 2>&1 || echo unreachable)"
|
||||
echo
|
||||
echo "Shut the machine down from Tool Server VM Maintenance, then press Freeze."
|
||||
Reference in New Issue
Block a user