Phase B-3: first-boot sshd install
New internal/imagepull/assets/first-boot.sh: POSIX-sh oneshot that detects the guest distro from /etc/os-release (ID + ID_LIKE fallback), installs openssh-server via the native package manager, and enables/starts sshd. Covers debian/ubuntu/kali/raspbian/pop, alpine, fedora/rhel/centos/rocky/almalinux, arch/manjaro, and opensuse/suse. Unknown distros fail clearly with a pointer at editing the script to add a branch. Marker-driven: the service has ConditionPathExists= /var/lib/banger/first-boot-pending, and the script removes the marker on success. Subsequent boots no-op. Testability seams in the script: RUN_PLAN=1 skips the sshd-already-present short-circuit and makes the dispatch echo the planned command instead of executing it. OS_RELEASE_FILE and BANGER_FIRST_BOOT_MARKER env vars override paths so the Go tests exercise the real dispatch logic in a tempdir without touching /etc or /var/lib on the host. Embedding: internal/imagepull/firstboot.go go:embeds both the script and the systemd unit; exposes FirstBootScript() and FirstBootUnit() plus the FirstBootScriptPath / FirstBootMarkerPath / FirstBootUnitName constants. Injection: InjectGuestAgents now drops /usr/local/libexec/ banger-first-boot (0755), /etc/systemd/system/banger-first-boot. service (0644), the empty /var/lib/banger/first-boot-pending marker (0644), and the multi-user.target.wants enable symlink. All uid=0, gid=0. Tests: eight-case dispatch-by-distro (debian, ubuntu, alpine, fedora, arch, opensuse, plus ID_LIKE fallbacks for weird derivatives). Script syntax check via `sh -n`. Unit-contains- expected-fields check. Existing inject round-trip test extended to assert the first-boot bits land in the ext4. Deferred: per-image FirstBootPending flag + extended SSH wait timeout at VM start. Will add if live verification (B-4) shows the naive retry UX is unacceptable. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
491c8e1ebb
commit
c3fb4ccc3e
6 changed files with 304 additions and 0 deletions
|
|
@ -72,6 +72,21 @@ func InjectGuestAgents(ctx context.Context, runner system.CommandRunner, ext4Fil
|
|||
guestPath: "/etc/modules-load.d/banger-vsock.conf",
|
||||
mode: 0o644,
|
||||
},
|
||||
{
|
||||
content: []byte(FirstBootScript()),
|
||||
guestPath: FirstBootScriptPath, // /usr/local/libexec/banger-first-boot
|
||||
mode: 0o755,
|
||||
},
|
||||
{
|
||||
content: []byte(FirstBootUnit()),
|
||||
guestPath: "/etc/systemd/system/" + FirstBootUnitName,
|
||||
mode: 0o644,
|
||||
},
|
||||
{
|
||||
content: nil, // empty marker file — its existence triggers the service
|
||||
guestPath: FirstBootMarkerPath,
|
||||
mode: 0o644,
|
||||
},
|
||||
}
|
||||
|
||||
// Resolve content-backed steps to on-disk temp files.
|
||||
|
|
@ -95,6 +110,10 @@ func InjectGuestAgents(ctx context.Context, runner system.CommandRunner, ext4Fil
|
|||
target: "/etc/systemd/system/" + vsockagent.ServiceName,
|
||||
link: "/etc/systemd/system/multi-user.target.wants/" + vsockagent.ServiceName,
|
||||
},
|
||||
{
|
||||
target: "/etc/systemd/system/" + FirstBootUnitName,
|
||||
link: "/etc/systemd/system/multi-user.target.wants/" + FirstBootUnitName,
|
||||
},
|
||||
}
|
||||
|
||||
script := buildInjectScript(steps, symlinks)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue