51 lines
1.9 KiB
TypeScript
51 lines
1.9 KiB
TypeScript
import { join } from "node:path";
|
|||
|
|
import { config, toolchain } from "./config";
|
||
|
|
import { ensureHostKey, guest } from "./guest";
|
||
|
|
import { fail, log } from "./shell";
|
||
|
|
import { tart } from "./tart";
|
||
|
|
|
||
|
|
type BakeOptions = { base: string; ref: string };
|
||
|
|
|
||
|
|
export async function bake({ base, ref }: BakeOptions): Promise<void> {
|
||
|
|
const { image, cpu, memoryMb } = config.tart;
|
||
|
|
const staging = `${image}-new`;
|
||
|
|
const publicKey = await ensureHostKey();
|
||
|
|
|
||
|
|
log(`pull ${base}`);
|
||
|
|
await tart.pull(base);
|
||
|
|
|
||
|
|
await tart.destroy(staging);
|
||
|
|
log(`clone ${base} -> ${staging} (cpu=${cpu} mem=${memoryMb}MB)`);
|
||
|
|
await tart.clone(base, staging);
|
||
|
|
await tart.configure(staging, cpu, memoryMb);
|
||
|
|
|
||
|
|
log(`boot ${staging}`);
|
||
|
|
const vm = tart.start(staging, `/tmp/bake-${staging}.log`);
|
||
|
|
const ip = (await tart.waitForSsh(staging, 60)) ?? fail(`${staging} never came up; see /tmp/bake-${staging}.log`);
|
||
|
|
log(`guest up at ${ip}`);
|
||
|
|
|
||
|
|
(await tart.waitForAgent(staging)) ?? fail("tart guest agent not responding");
|
||
|
|
await tart.exec(
|
||
|
|
staging,
|
||
|
|
`mkdir -p ~/.ssh && chmod 700 ~/.ssh && echo '${publicKey}' > ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys`,
|
||
|
|
);
|
||
|
|
|
||
|
|
const g = guest(ip);
|
||
|
|
await g.push(join(import.meta.dir, "..", "guest", "bake.sh"), "/tmp/bake.sh");
|
||
|
|
|
||
|
|
log(`bootstrap toolchain in guest (${config.bun.repo}@${ref})`);
|
||
|
|
const status = await g.run(
|
||
|
|
`/bin/bash -l /tmp/bake.sh ${config.bun.repo} ${ref} ${config.buildkiteAgent.version} '${toolchain.join(" ")}' 2>&1 | tee /tmp/bake.log; grep -qx BAKE_OK /tmp/bake.log`,
|
||
|
|
);
|
||
|
|
if (status !== 0) fail(`bake failed in guest; ${image} untouched, ${staging} left running at ${ip} for inspection`);
|
||
|
|
|
||
|
|
await g.run("sync; sudo shutdown -h now").catch(() => {});
|
||
|
|
log("waiting for guest to power off");
|
||
|
|
await Promise.race([vm.exited, Bun.sleep(180_000)]);
|
||
|
|
await tart.stop(staging);
|
||
|
|
|
||
|
|
await tart.remove(image);
|
||
|
|
await tart.rename(staging, image);
|
||
|
|
log(`${image} ready`);
|
||
|
|
}
|