1import * as s3 from "@distilled.cloud/aws/s3";
2import * as Alchemy from "alchemy";
3import * as Effect from "effect/Effect";
4
5/**
6 * The script every node runs when it joins the cluster. Real clusters
7 * install schedulers, mount FSx volumes, and configure observability here —
8 * see https://github.com/aws-samples/awsome-distributed-training for the
9 * full-featured base configuration.
10 */
11const ON_CREATE_SH = `#!/bin/bash
12set -euo pipefail
13echo "HyperPod node $(hostname) provisioned by alchemy"
14`;
15
16/**
17 * Deploy-time Action that uploads the lifecycle script to the bucket. It
18 * runs after the bucket exists (its input captures the bucket's resolved
19 * name) and before the cluster is created (the cluster's props capture its
20 * output) — the dependency chain is inferred, and the body only re-runs
21 * when its input changes.
22 */
23export const UploadLifecycleScript = Alchemy.Action(
24 "UploadLifecycleScript",
25 (input: { bucketName: string }) =>
26 Effect.gen(function* () {
27 yield* s3.putObject({
28 Bucket: input.bucketName,
29 Key: "lifecycle/on_create.sh",
30 Body: new TextEncoder().encode(ON_CREATE_SH),
31 ContentType: "text/x-shellscript",
32 });
33 return {
34 sourceS3Uri: `s3://${input.bucketName}/lifecycle`,
35 onCreate: "on_create.sh",
36 };
37 }),
38);