wip: save current ks debugging state before bisect revert

All accumulated changes to kickstart template, test infrastructure,
and dnsmasq config. None of these produce a clean boot yet — saving
state before reverting to baseline for bisection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Michal
2026-03-28 20:24:14 +00:00
parent cc289c0f94
commit a664074fa3
7 changed files with 258 additions and 166 deletions

View File

@@ -88,6 +88,9 @@ pxe-service=tag:!ipxe,ARM64_EFI,"PXE Boot",ipxe-arm64.efi` : `# Full DHCP mode -
# Discovery protocol which some UEFI implementations don't support). The dhcp-boot
# directives above provide the boot filename directly in the DHCP offer.`}
# Lease file in bastion directory (avoid default /var/lib/dnsmasq which needs root)
dhcp-leasefile=${config.bastionDir}/dnsmasq.leases
# Verbose logging
log-dhcp
`;

View File

@@ -41,9 +41,10 @@ export function renderInstallKickstart(params: InstallKickstartParams): string {
const isVanilla = role === "vanilla";
// -- Auth section --
// Always set a root password (for serial console debugging) + SSH keys
const auth = sshKeys.length > 0
? `rootpw --lock\nsshkey --username=root "${sshKeys[0]}"`
: "rootpw --plaintext changeme";
? `rootpw --plaintext lab-root-pw\nsshkey --username=root "${sshKeys[0]}"`
: "rootpw --plaintext lab-root-pw";
// -- Admin user directive --
const userDirective = adminUser
@@ -73,8 +74,9 @@ cp /root/.ssh/authorized_keys "$ADMIN_HOME/.ssh/authorized_keys"
chown -R ${adminUser}:${adminUser} "$ADMIN_HOME/.ssh"
chmod 600 "$ADMIN_HOME/.ssh/authorized_keys"
# Fix SELinux contexts for SSH
restorecon -R /root/.ssh "$ADMIN_HOME/.ssh" 2>/dev/null || true
# Fix SELinux contexts for SSH (restorecon may not work in Anaconda chroot, use chcon)
chcon -R -t ssh_home_t /root/.ssh "$ADMIN_HOME/.ssh" 2>/dev/null || true
chcon -t user_home_dir_t "$ADMIN_HOME" 2>/dev/null || true
# Passwordless sudo for ${adminUser}
echo '${adminUser} ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/${adminUser}
@@ -279,6 +281,7 @@ bastion_log "partition config written to /tmp/part.ks"
%packages
@core
kernel-modules
openssh-server
vim-enhanced
tmux
@@ -328,6 +331,7 @@ ruby-libs
-gdm
-PackageKit
-PackageKit-glib
dosfstools
%end
%post --log=/root/bastion-post-install.log
@@ -396,7 +400,7 @@ bastion_progress "installing" "packages installed, starting post-install"
# -- SSH --
bastion_progress "post-install" "configuring SSH"
systemctl enable --now sshd
systemctl enable sshd
sed -i 's/^#\\?PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
sed -i 's/^#\\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
${sshPostBlock}
@@ -406,13 +410,22 @@ bastion_log "SSH configured: root login by key only, password auth disabled"
bastion_progress "post-install" "setting hostname to ${fqdn}"
hostnamectl set-hostname ${fqdn}
# -- tmpfs for /tmp --
echo "tmpfs /tmp tmpfs defaults,noatime,nosuid,nodev,size=4G 0 0" >> /etc/fstab
# -- Rebuild module dependencies (Anaconda's depmod runs against host kernel, not installed kernel) --
INSTALLED_KVER=$(ls /lib/modules/ | grep -v "$(uname -r)" | head -1)
if [ -n "$INSTALLED_KVER" ]; then
depmod -a "$INSTALLED_KVER"
bastion_log "depmod rebuilt for kernel $INSTALLED_KVER"
fi
# Make /boot/efi mount non-fatal (prevents emergency mode if EFI partition isn't found)
# Make /boot/efi mount non-fatal — on first boot SELinux labels on kernel module
# files are wrong (Anaconda chroot issue), so vfat may fail to load.
# autorelabel fixes labels and reboots; second boot mounts /boot/efi normally.
sed -i '/boot\\/efi/ s/defaults/defaults,nofail/' /etc/fstab
bastion_log "fstab /boot/efi set to nofail"
# -- tmpfs for /tmp --
echo "tmpfs /tmp tmpfs defaults,noatime,nosuid,nodev,size=4G 0 0" >> /etc/fstab
${isVanilla ? `# -- vanilla role: skip k3s kernel/sysctl/firewall setup --
bastion_progress "post-install" "vanilla role -- skipping k3s setup"
# -- Enable chronyd for time sync --
@@ -502,6 +515,10 @@ bastion_progress "post-install" "pre-installing k3s server"
curl -sfL https://get.k3s.io | INSTALL_K3S_SKIP_START=true sh -
bastion_log "k3s server pre-installed (not started)"
` : ""}
# -- Fix SELinux labels (Anaconda %post creates files with wrong contexts) --
restorecon -R /etc /var /root 2>/dev/null || true
bastion_log "SELinux contexts restored for /etc /var /root"
# Stop log streamer and flush remaining lines
_flush_log_streamer

View File

@@ -188,4 +188,36 @@ describe("renderInstallKickstart", () => {
expect(ks).toContain('"configuring k3s sysctl"');
expect(ks).toContain('"disabling firewalld"');
});
it("kickstart syntax: no merged partition lines", () => {
for (const role of ["vanilla", "worker", "infra"] as const) {
const ks = renderInstallKickstart(baseParams({ role }));
const lines = ks.split("\n");
for (let i = 0; i < lines.length; i++) {
const l = lines[i].trim();
if (l.startsWith("part ")) {
const partCount = (l.match(/\bpart\b/g) || []).length;
expect(partCount, `line ${i + 1} has ${partCount} 'part' commands (role=${role}): ${l}`).toBe(1);
}
}
}
});
it("kickstart syntax: each section-opening has a %end", () => {
const ks = renderInstallKickstart(baseParams());
// Only match section openers at start of line
const sections = (ks.match(/^%(?:pre|post|packages)\b/gm) || []).length;
const ends = (ks.match(/^%end$/gm) || []).length;
expect(ends, `${sections} sections but ${ends} %end markers`).toBe(sections);
});
it("kernel-modules package is included", () => {
const ks = renderInstallKickstart(baseParams());
expect(ks).toContain("kernel-modules");
});
it("dosfstools package is included", () => {
const ks = renderInstallKickstart(baseParams());
expect(ks).toContain("dosfstools");
});
});