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 missingMembership,
10 missingVmwareCluster,
11 currentProject,
12 vmwareAdminMembership,
13 runVmwareLifecycle,
14 vmwareControlPlane,
15 vmwareLoadBalancer,
16 vmwareNetwork,
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.getProjectsLocationsVmwareClustersVmwareNodePools({ 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 "getProjectsLocationsVmwareClustersVmwareNodePools on a missing pool 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.getProjectsLocationsVmwareClustersVmwareNodePools({
47 name: `${missingVmwareCluster(project)}/vmwareNodePools/alchemy-missing-pool`,
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(runVmwareLifecycle)(
58 "create under a missing cluster is rejected with a typed tag",
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.VmwareClustersVmwareNodePool(
69 "Workers",
70 {
71 vmwareCluster: missingVmwareCluster(project),
72 config: {
73 imageType: "ubuntu_containerd",
74 replicas: "3",
75 cpus: "4",
76 memoryMb: "8192",
77 },
78 displayName: "alchemy-test-vmnp",
79 labels: { env: "test" },
80 },
81 );
82 }),
83 ),
84 );
85 expect(error._tag).toEqual("NotFound");
86
87 yield* stack.destroy();
88 }).pipe(logLevel),
89 { tags: ["provider:gcp", "provider:gcp:gkeonprem", "live"], timeout: 90_000 },
90);
91
92test.provider.skipIf(!runVmwareLifecycle)(
93 "create, update, and delete a vmware node pool",
94 (stack) =>
95 Effect.gen(function* () {
96 const project = yield* currentProject;
97
98 yield* stack.destroy();
99
100 const created = yield* stack.deploy(
101 Effect.gen(function* () {
102 const cluster = yield* GCP.GKEOnPrem.VmwareCluster("Workload", {
103 adminClusterMembership:
104 vmwareAdminMembership ?? missingMembership(project),
105 onPremVersion: "1.28.0-gke.1",
106 controlPlaneNode: vmwareControlPlane,
107 networkConfig: vmwareNetwork,
108 loadBalancer: vmwareLoadBalancer,
109 description: "node pool parent",
110 });
111 const pool = yield* GCP.GKEOnPrem.VmwareClustersVmwareNodePool(
112 "Workers",
113 {
114 vmwareCluster: cluster.name,
115 config: {
116 imageType: "ubuntu_containerd",
117 replicas: "3",
118 cpus: "4",
119 memoryMb: "8192",
120 },
121 displayName: "alchemy-test-vmnp",
122 labels: { env: "test" },
123 },
124 );
125 return { cluster, pool };
126 }),
127 );
128
129 expect(created.pool.name).toContain("/vmwareNodePools/");
130 expect(created.pool.vmwareCluster).toEqual(created.cluster.name);
131 expect(created.pool.displayName).toEqual("alchemy-test-vmnp");
132
133 const fetched =
134 yield* gkeonprem.getProjectsLocationsVmwareClustersVmwareNodePools({
135 name: created.pool.name,
136 });
137 expect(fetched.name).toEqual(created.pool.name);
138 expect(fetched.displayName).toContain("alchemy-id=");
139 expect(fetched.annotations?.["alchemy-id"]).toBeDefined();
140
141 const updated = yield* stack.deploy(
142 Effect.gen(function* () {
143 const cluster = yield* GCP.GKEOnPrem.VmwareCluster("Workload", {
144 vmwareClusterId: created.cluster.vmwareClusterId,
145 location: created.cluster.location,
146 adminClusterMembership:
147 created.cluster.adminClusterMembership ??
148 vmwareAdminMembership ??
149 missingMembership(project),
150 onPremVersion: created.cluster.onPremVersion ?? "1.28.0-gke.1",
151 controlPlaneNode:
152 created.cluster.controlPlaneNode ?? vmwareControlPlane,
153 networkConfig: created.cluster.networkConfig ?? vmwareNetwork,
154 loadBalancer: created.cluster.loadBalancer ?? vmwareLoadBalancer,
155 description: "node pool parent",
156 });
157 const pool = yield* GCP.GKEOnPrem.VmwareClustersVmwareNodePool(
158 "Workers",
159 {
160 vmwareNodePoolId: created.pool.vmwareNodePoolId,
161 vmwareCluster: cluster.name,
162 config: {
163 imageType: "ubuntu_containerd",
164 replicas: "5",
165 cpus: "4",
166 memoryMb: "8192",
167 },
168 displayName: "alchemy-test-vmnp-v2",
169 },
170 );
171 return { cluster, pool };
172 }),
173 );
174
175 expect(updated.pool.displayName).toEqual("alchemy-test-vmnp-v2");
176 expect(updated.pool.vmwareNodePoolId).toEqual(
177 created.pool.vmwareNodePoolId,
178 );
179
180 yield* stack.destroy();
181 yield* waitUntilGone(created.pool.name);
182 }).pipe(logLevel),
183 {
184 tags: ["provider:gcp", "provider:gcp:gkeonprem", "live"],
185 timeout: 120_000,
186 },
187);