1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as gkeonprem from "@distilled.cloud/gcp/gkeonprem_v1";
4import { expect } from "alchemy-test";
5import * as Effect from "effect/Effect";
6import { MinimumLogLevel } from "effect/References";
7import * as Schedule from "effect/Schedule";
8import {
9 bareMetalControlPlane,
10 bareMetalLoadBalancer,
11 bareMetalNetwork,
12 bareMetalStorage,
13 missingMembership,
14 currentProject,
15 bareMetalAdminMembership,
16 runBareMetalLifecycle,
17} from "./common.ts";
18
19const { test } = Test.make({ providers: GCP.providers() });
20
21const logLevel = Effect.provideService(
22 MinimumLogLevel,
23 process.env.DEBUG ? "Debug" : "Info",
24);
25
26const waitUntilGone = (name: string) =>
27 gkeonprem.getProjectsLocationsBareMetalClusters({ name }).pipe(
28 Effect.as("found" as const),
29 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
30 Effect.repeat({
31 schedule: Schedule.spaced("2 seconds"),
32 until: (status) => status === "gone",
33 times: 10,
34 }),
35 );
36
37test.provider(
38 "getProjectsLocationsBareMetalClusters on a missing cluster fails with a typed tag",
39 (stack) =>
40 Effect.gen(function* () {
41 const project = yield* currentProject;
42
43 yield* stack.destroy();
44
45 const error = yield* Effect.flip(
46 gkeonprem.getProjectsLocationsBareMetalClusters({
47 name: `projects/${project}/locations/us-central1/bareMetalClusters/alchemy-missing-bmc`,
48 }),
49 );
50 expect(error._tag).toEqual("NotFound");
51
52 yield* stack.destroy();
53 }).pipe(logLevel),
54 { tags: ["provider:gcp", "provider:gcp:gkeonprem", "live"], timeout: 90_000 },
55);
56
57test.provider.skipIf(runBareMetalLifecycle)(
58 "create without an admin cluster fails with AdminClusterUnreachable",
59 (stack) =>
60 Effect.gen(function* () {
61 const project = yield* currentProject;
62
63 yield* stack.destroy();
64
65 const error = yield* Effect.flip(
66 stack.deploy(
67 Effect.gen(function* () {
68 return yield* GCP.GKEOnPrem.BareMetalCluster("Workload", {
69 adminClusterMembership: missingMembership(project),
70 bareMetalVersion: "1.28.0-gke.1",
71 controlPlane: bareMetalControlPlane,
72 storage: bareMetalStorage,
73 networkConfig: bareMetalNetwork,
74 loadBalancer: bareMetalLoadBalancer,
75 description: "alchemy-test-bmc",
76 labels: { env: "test" },
77 });
78 }),
79 ),
80 );
81 expect(error._tag).toEqual("AdminClusterUnreachable");
82
83 yield* stack.destroy();
84 }).pipe(logLevel),
85 { tags: ["provider:gcp", "provider:gcp:gkeonprem", "live"], timeout: 90_000 },
86);
87
88test.provider.skipIf(!runBareMetalLifecycle)(
89 "create, update, and delete a bare metal cluster",
90 (stack) =>
91 Effect.gen(function* () {
92 const project = yield* currentProject;
93
94 yield* stack.destroy();
95
96 const created = yield* stack.deploy(
97 Effect.gen(function* () {
98 return yield* GCP.GKEOnPrem.BareMetalCluster("Workload", {
99 adminClusterMembership:
100 bareMetalAdminMembership ?? missingMembership(project),
101 bareMetalVersion: "1.28.0-gke.1",
102 controlPlane: bareMetalControlPlane,
103 storage: bareMetalStorage,
104 networkConfig: bareMetalNetwork,
105 loadBalancer: bareMetalLoadBalancer,
106 description: "alchemy-test-bmc",
107 labels: { env: "test" },
108 });
109 }),
110 );
111
112 expect(created.name).toContain("/bareMetalClusters/");
113 expect(created.description).toEqual("alchemy-test-bmc");
114 expect(created.labels.env).toEqual("test");
115
116 const fetched = yield* gkeonprem.getProjectsLocationsBareMetalClusters({
117 name: created.name,
118 });
119 expect(fetched.name).toEqual(created.name);
120 expect(fetched.description).toContain("alchemy-id=");
121 expect(fetched.description).toContain("alchemy-test-bmc");
122 expect(fetched.annotations?.["alchemy-id"]).toBeDefined();
123
124 const updated = yield* stack.deploy(
125 Effect.gen(function* () {
126 return yield* GCP.GKEOnPrem.BareMetalCluster("Workload", {
127 bareMetalClusterId: created.bareMetalClusterId,
128 location: created.location,
129 adminClusterMembership:
130 created.adminClusterMembership ??
131 bareMetalAdminMembership ??
132 missingMembership(project),
133 bareMetalVersion: created.bareMetalVersion ?? "1.28.0-gke.1",
134 controlPlane: created.controlPlane ?? bareMetalControlPlane,
135 storage: created.storage ?? bareMetalStorage,
136 networkConfig: created.networkConfig ?? bareMetalNetwork,
137 loadBalancer: created.loadBalancer ?? bareMetalLoadBalancer,
138 description: "alchemy-test-bmc-v2",
139 labels: { env: "test", team: "platform" },
140 });
141 }),
142 );
143
144 expect(updated.description).toEqual("alchemy-test-bmc-v2");
145 expect(updated.labels.team).toEqual("platform");
146 expect(updated.bareMetalClusterId).toEqual(created.bareMetalClusterId);
147
148 yield* stack.destroy();
149 yield* waitUntilGone(created.name);
150 }).pipe(logLevel),
151 {
152 tags: ["provider:gcp", "provider:gcp:gkeonprem", "live"],
153 timeout: 120_000,
154 },
155);