fix: firstboot script auto-detects hostname and MAC, no query params needed
Some checks failed
Some checks failed
The firstboot script now auto-detects hostname (from hostnamectl) and MAC address (from first UP interface) at runtime. No URL query parameters required — just `curl bastion/asahi/firstboot.sh | sudo bash`. Fixes the shell escaping issue where `&` in query params broke curl piping. Updated labctl provision asahi instructions accordingly. Tested on Mac Studio (worker1-k8s0): hostname, MAC, and bastion registration all auto-detected correctly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
4
bastion/bastion/.gitignore
vendored
Normal file
4
bastion/bastion/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
# Asahi build artifacts (large)
|
||||||
|
.asahi-cache/
|
||||||
|
asahi-repo/*.zip
|
||||||
@@ -102,7 +102,8 @@ echo " - Standard Asahi boot infrastructure (m1n1 + U-Boot)"
|
|||||||
echo " - Fedora Asahi Remix root partition"
|
echo " - Fedora Asahi Remix root partition"
|
||||||
echo " - LVM data partition (remaining space)"
|
echo " - LVM data partition (remaining space)"
|
||||||
echo ""
|
echo ""
|
||||||
echo " On first boot, LVM volumes are created automatically."
|
echo " After first boot, SSH in and set up LVM:"
|
||||||
|
echo " ssh lab@<ip> 'curl -sf \${BASTION}/asahi/firstboot.sh | sudo bash'"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Run the installer
|
# Run the installer
|
||||||
@@ -150,7 +151,7 @@ fi
|
|||||||
app.get<{
|
app.get<{
|
||||||
Querystring: { hostname?: string; role?: string; mac?: string; user?: string };
|
Querystring: { hostname?: string; role?: string; mac?: string; user?: string };
|
||||||
}>("/asahi/firstboot.sh", async (request, reply) => {
|
}>("/asahi/firstboot.sh", async (request, reply) => {
|
||||||
const hostname = request.query.hostname ?? "mac-studio";
|
const hostname = request.query.hostname ?? "unknown";
|
||||||
const role = (request.query.role ?? "infra") as Role;
|
const role = (request.query.role ?? "infra") as Role;
|
||||||
const mac = request.query.mac ?? "unknown";
|
const mac = request.query.mac ?? "unknown";
|
||||||
const user = request.query.user ?? config.adminUser;
|
const user = request.query.user ?? config.adminUser;
|
||||||
|
|||||||
@@ -222,21 +222,32 @@ lvs labvg
|
|||||||
|
|
||||||
fi # end if/else for reprovision vs fresh install
|
fi # end if/else for reprovision vs fresh install
|
||||||
|
|
||||||
# ── Set hostname ─────────────────────────────────────────────────
|
# ── Set hostname (use configured value, or keep existing) ────────
|
||||||
hostnamectl set-hostname "${hostname}"
|
CONF_HOSTNAME="${hostname}"
|
||||||
|
if [ "$CONF_HOSTNAME" != "unknown" ] && [ -n "$CONF_HOSTNAME" ]; then
|
||||||
|
hostnamectl set-hostname "$CONF_HOSTNAME"
|
||||||
|
fi
|
||||||
|
ACTUAL_HOSTNAME=$(hostname)
|
||||||
|
|
||||||
|
# ── Detect MAC address ───────────────────────────────────────────
|
||||||
|
CONF_MAC="${mac}"
|
||||||
|
if [ "$CONF_MAC" = "unknown" ] || [ -z "$CONF_MAC" ]; then
|
||||||
|
CONF_MAC=$(ip -o link show | grep -v "lo:" | grep "state UP" | head -1 | grep -oP 'link/ether \\K[^ ]+' || echo "unknown")
|
||||||
|
fi
|
||||||
|
|
||||||
# ── Configure admin user ─────────────────────────────────────────
|
# ── Configure admin user ─────────────────────────────────────────
|
||||||
if ! id "${adminUser}" &>/dev/null; then
|
ADMIN="${adminUser}"
|
||||||
useradd -m -G wheel "${adminUser}"
|
if ! id "$ADMIN" &>/dev/null; then
|
||||||
echo "${adminUser} ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/${adminUser}
|
useradd -m -G wheel "$ADMIN"
|
||||||
chmod 440 /etc/sudoers.d/${adminUser}
|
echo "$ADMIN ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$ADMIN
|
||||||
|
chmod 440 /etc/sudoers.d/$ADMIN
|
||||||
fi
|
fi
|
||||||
ADMIN_SSH="/home/${adminUser}/.ssh"
|
ADMIN_SSH="/home/$ADMIN/.ssh"
|
||||||
mkdir -p "$ADMIN_SSH"
|
mkdir -p "$ADMIN_SSH"
|
||||||
chmod 700 "$ADMIN_SSH"
|
chmod 700 "$ADMIN_SSH"
|
||||||
${sshKeyBlock}
|
${sshKeyBlock}
|
||||||
chmod 600 "$ADMIN_SSH/authorized_keys"
|
chmod 600 "$ADMIN_SSH/authorized_keys"
|
||||||
chown -R ${adminUser}:${adminUser} "$ADMIN_SSH"
|
chown -R $ADMIN:$ADMIN "$ADMIN_SSH"
|
||||||
|
|
||||||
# Also authorize root
|
# Also authorize root
|
||||||
mkdir -p /root/.ssh
|
mkdir -p /root/.ssh
|
||||||
@@ -250,9 +261,9 @@ sed -i 's/^#\\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/ssh
|
|||||||
|
|
||||||
# ── Write provisioning metadata ──────────────────────────────────
|
# ── Write provisioning metadata ──────────────────────────────────
|
||||||
cat > /etc/lab-provisioned << LABMETA
|
cat > /etc/lab-provisioned << LABMETA
|
||||||
hostname=${hostname}
|
hostname=$ACTUAL_HOSTNAME
|
||||||
role=${role}
|
role=${role}
|
||||||
mac=${mac}
|
mac=$CONF_MAC
|
||||||
provisioned_at=$(date -Iseconds)
|
provisioned_at=$(date -Iseconds)
|
||||||
method=asahi-firstboot
|
method=asahi-firstboot
|
||||||
LABMETA
|
LABMETA
|
||||||
@@ -262,9 +273,9 @@ IP=$(hostname -I | awk '{print $1}')
|
|||||||
echo "Registering with bastion at ${serverIp}:${httpPort}..."
|
echo "Registering with bastion at ${serverIp}:${httpPort}..."
|
||||||
curl -sf -X POST "http://${serverIp}:${httpPort}/api/register" \\
|
curl -sf -X POST "http://${serverIp}:${httpPort}/api/register" \\
|
||||||
-H "Content-Type: application/json" \\
|
-H "Content-Type: application/json" \\
|
||||||
-d "{\\"mac\\":\\"${mac}\\",\\"hostname\\":\\"${hostname}\\",\\"role\\":\\"${role}\\",\\"ip\\":\\"$IP\\"}" \\
|
-d "{\\"mac\\":\\"$CONF_MAC\\",\\"hostname\\":\\"$ACTUAL_HOSTNAME\\",\\"role\\":\\"${role}\\",\\"ip\\":\\"$IP\\"}" \\
|
||||||
2>/dev/null && echo " Registered as ${hostname} ($IP)" \\
|
2>/dev/null && echo " Registered as $ACTUAL_HOSTNAME ($IP)" \\
|
||||||
|| echo " WARNING: Could not reach bastion — register manually with: labctl provision register ${mac} ${hostname} --role ${role} --ip $IP"
|
|| echo " WARNING: Could not reach bastion — register manually with: labctl provision register $CONF_MAC $ACTUAL_HOSTNAME --role ${role} --ip $IP"
|
||||||
|
|
||||||
# ── Mark done ────────────────────────────────────────────────────
|
# ── Mark done ────────────────────────────────────────────────────
|
||||||
touch "$MARKER"
|
touch "$MARKER"
|
||||||
|
|||||||
@@ -184,7 +184,8 @@ describe("renderFirstbootScript", () => {
|
|||||||
|
|
||||||
it("sets hostname", () => {
|
it("sets hostname", () => {
|
||||||
const script = renderFirstbootScript({ ...baseParams, role: "worker" });
|
const script = renderFirstbootScript({ ...baseParams, role: "worker" });
|
||||||
expect(script).toContain('hostnamectl set-hostname "test-node"');
|
expect(script).toContain('CONF_HOSTNAME="test-node"');
|
||||||
|
expect(script).toContain("hostnamectl set-hostname");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("includes bastion self-registration", () => {
|
it("includes bastion self-registration", () => {
|
||||||
|
|||||||
@@ -59,9 +59,9 @@ export function registerAsahiCommand(parent: Command): void {
|
|||||||
console.log(` labvg/longhorn (remaining space)${RESET}`);
|
console.log(` labvg/longhorn (remaining space)${RESET}`);
|
||||||
console.log("");
|
console.log("");
|
||||||
console.log(` After first boot, SSH in and run the firstboot script:`);
|
console.log(` After first boot, SSH in and run the firstboot script:`);
|
||||||
console.log(` ${BOLD}ssh root@<ip> 'curl -sf ${bastionUrl}/asahi/firstboot.sh?hostname=<name>\\&role=infra | bash'${RESET}`);
|
console.log(` ${BOLD}ssh lab@<ip> 'curl -sf ${bastionUrl}/asahi/firstboot.sh | sudo bash'${RESET}`);
|
||||||
console.log("");
|
console.log("");
|
||||||
console.log(` This sets up LVM and self-registers with the bastion.`);
|
console.log(` This sets up LVM, detects hostname/MAC, and self-registers.`);
|
||||||
console.log(` Then install k3s:`);
|
console.log(` Then install k3s:`);
|
||||||
console.log(` ${BOLD}labctl app k3s install <hostname> --role infra${RESET}`);
|
console.log(` ${BOLD}labctl app k3s install <hostname> --role infra${RESET}`);
|
||||||
console.log("");
|
console.log("");
|
||||||
|
|||||||
Reference in New Issue
Block a user