| 1 | import * as s3 from "@distilled.cloud/aws/s3"; |
| 2 | import * as Alchemy from "alchemy"; |
| 3 | import * 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 | */ |
| 11 | const ON_CREATE_SH = `#!/bin/bash |
| 12 | set -euo pipefail |
| 13 | echo "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 | */ |
| 23 | export 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 | ); |