@alchemy.run/kubernetes 0.0.0 → 2.0.0-beta.84

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +41 -4
  3. package/lib/BuiltinAdapters.d.ts +23 -0
  4. package/lib/BuiltinAdapters.d.ts.map +1 -0
  5. package/lib/BuiltinAdapters.js +124 -0
  6. package/lib/BuiltinAdapters.js.map +1 -0
  7. package/lib/Client.d.ts +80 -0
  8. package/lib/Client.d.ts.map +1 -0
  9. package/lib/Client.js +296 -0
  10. package/lib/Client.js.map +1 -0
  11. package/lib/ClusterAdapter.d.ts +322 -0
  12. package/lib/ClusterAdapter.d.ts.map +1 -0
  13. package/lib/ClusterAdapter.js +65 -0
  14. package/lib/ClusterAdapter.js.map +1 -0
  15. package/lib/Connection.d.ts +210 -0
  16. package/lib/Connection.d.ts.map +1 -0
  17. package/lib/Connection.js +58 -0
  18. package/lib/Connection.js.map +1 -0
  19. package/lib/Deployment.d.ts +382 -0
  20. package/lib/Deployment.d.ts.map +1 -0
  21. package/lib/Deployment.js +533 -0
  22. package/lib/Deployment.js.map +1 -0
  23. package/lib/HelmChart.d.ts +147 -0
  24. package/lib/HelmChart.d.ts.map +1 -0
  25. package/lib/HelmChart.js +248 -0
  26. package/lib/HelmChart.js.map +1 -0
  27. package/lib/Job.d.ts +314 -0
  28. package/lib/Job.d.ts.map +1 -0
  29. package/lib/Job.js +426 -0
  30. package/lib/Job.js.map +1 -0
  31. package/lib/LocalCluster.d.ts +243 -0
  32. package/lib/LocalCluster.d.ts.map +1 -0
  33. package/lib/LocalCluster.js +359 -0
  34. package/lib/LocalCluster.js.map +1 -0
  35. package/lib/Manifest.d.ts +148 -0
  36. package/lib/Manifest.d.ts.map +1 -0
  37. package/lib/Manifest.js +200 -0
  38. package/lib/Manifest.js.map +1 -0
  39. package/lib/Objects.d.ts +60 -0
  40. package/lib/Objects.d.ts.map +1 -0
  41. package/lib/Objects.js +132 -0
  42. package/lib/Objects.js.map +1 -0
  43. package/lib/Providers.d.ts +24 -0
  44. package/lib/Providers.d.ts.map +1 -0
  45. package/lib/Providers.js +36 -0
  46. package/lib/Providers.js.map +1 -0
  47. package/lib/index.d.ts +10 -0
  48. package/lib/index.d.ts.map +1 -0
  49. package/lib/index.js +10 -0
  50. package/lib/index.js.map +1 -0
  51. package/lib/internal/declared.d.ts +19 -0
  52. package/lib/internal/declared.d.ts.map +1 -0
  53. package/lib/internal/declared.js +435 -0
  54. package/lib/internal/declared.js.map +1 -0
  55. package/lib/internal/helm.d.ts +65 -0
  56. package/lib/internal/helm.d.ts.map +1 -0
  57. package/lib/internal/helm.js +173 -0
  58. package/lib/internal/helm.js.map +1 -0
  59. package/lib/internal/kind.d.ts +17 -0
  60. package/lib/internal/kind.d.ts.map +1 -0
  61. package/lib/internal/kind.js +31 -0
  62. package/lib/internal/kind.js.map +1 -0
  63. package/lib/internal/kubeconfig.d.ts +79 -0
  64. package/lib/internal/kubeconfig.d.ts.map +1 -0
  65. package/lib/internal/kubeconfig.js +222 -0
  66. package/lib/internal/kubeconfig.js.map +1 -0
  67. package/lib/internal/registry.d.ts +44 -0
  68. package/lib/internal/registry.d.ts.map +1 -0
  69. package/lib/internal/registry.js +72 -0
  70. package/lib/internal/registry.js.map +1 -0
  71. package/lib/internal/workload.d.ts +127 -0
  72. package/lib/internal/workload.d.ts.map +1 -0
  73. package/lib/internal/workload.js +411 -0
  74. package/lib/internal/workload.js.map +1 -0
  75. package/package.json +55 -3
  76. package/src/BuiltinAdapters.ts +194 -0
  77. package/src/Client.ts +465 -0
  78. package/src/ClusterAdapter.ts +370 -0
  79. package/src/Connection.ts +234 -0
  80. package/src/Deployment.ts +851 -0
  81. package/src/HelmChart.ts +388 -0
  82. package/src/Job.ts +689 -0
  83. package/src/LocalCluster.ts +631 -0
  84. package/src/Manifest.ts +295 -0
  85. package/src/Objects.ts +213 -0
  86. package/src/Providers.ts +52 -0
  87. package/src/globals.d.ts +2 -0
  88. package/src/index.ts +9 -0
  89. package/src/internal/declared.ts +471 -0
  90. package/src/internal/helm.ts +245 -0
  91. package/src/internal/kind.ts +43 -0
  92. package/src/internal/kubeconfig.ts +364 -0
  93. package/src/internal/registry.ts +108 -0
  94. package/src/internal/workload.ts +503 -0
@@ -0,0 +1,533 @@
1
+ import { isResolved } from "alchemy/Diff";
2
+ import { createPhysicalName } from "alchemy/PhysicalName";
3
+ import { Platform } from "alchemy/Platform";
4
+ import * as Provider from "alchemy/Provider";
5
+ import { Resource } from "alchemy/Resource";
6
+ import { createHostRuntimeContext, } from "alchemy/Runtime/Process";
7
+ import { Stack } from "alchemy/Stack";
8
+ import { createInternalTags } from "alchemy/Tags";
9
+ import * as Data from "effect/Data";
10
+ import * as Effect from "effect/Effect";
11
+ import * as Schedule from "effect/Schedule";
12
+ import { connectCluster, deleteObjects, ifClusterExists, readObject, reconcileObjects, } from "./Client.js";
13
+ import { findClusterAdapter, } from "./ClusterAdapter.js";
14
+ import { toConnection } from "./Connection.js";
15
+ import { makeConnectionRegistry } from "./internal/registry.js";
16
+ import { collectBindingEnv, containerEnvValue, connectionIdentity, connectionOfOutput, deepMerge, imagePlatformOf, makeServerBootstrap, resolveWorkloadImage, tryConnectionOf, workloadImageHash, } from "./internal/workload.js";
17
+ import { toKubernetesObjectRef, } from "./Objects.js";
18
+ export const isDeployment = (value) => typeof value === "object" &&
19
+ value !== null &&
20
+ "Type" in value &&
21
+ value.Type === "Kubernetes.Deployment";
22
+ /**
23
+ * A replicated Kubernetes server on any cluster, running a container image
24
+ * or an HTTP server written in Effect.
25
+ *
26
+ * `Deployment` provisions a Kubernetes `Deployment` + `Service` (+
27
+ * `ServiceAccount`) via server-side apply, with the container image from
28
+ * exactly one of three sources flat on props: `main` (bundle an inline
29
+ * Effect program), `context` (build your own Dockerfile), or `image` (a
30
+ * pre-built registry reference). `main` and `context` images are built on
31
+ * the deploying machine and pushed to the connection's registry
32
+ * (`Kubernetes.LocalCluster` includes one; EKS uses ECR; GKE uses
33
+ * Artifact Registry). Bindings attach environment variables on any
34
+ * cluster; cloud credential grants need a platform with workload identity.
35
+ * On `AWS.EKS.Cluster` targets it accepts the `{ env, policyStatements }`
36
+ * contract of `AWS.Lambda.Function`: IAM policy statements go to a
37
+ * generated pod-identity role. On `GCP.Container.Cluster` targets it
38
+ * accepts the `{ env, iam }` contract of `GCP.Run.Service`: IAM roles are
39
+ * granted to the Kubernetes ServiceAccount's Workload Identity Federation
40
+ * principal.
41
+ * ### Creating a Deployment
42
+ * **Example:** Run an image on a local cluster
43
+ * ```typescript
44
+ * const cluster = yield* Kubernetes.LocalCluster("Cluster", {
45
+ * name: "alchemy",
46
+ * });
47
+ *
48
+ * const web = yield* Kubernetes.Deployment("Web", {
49
+ * cluster,
50
+ * image: "ghcr.io/stefanprodan/podinfo:6.15.0",
51
+ * replicas: 2,
52
+ * port: 9898,
53
+ * serviceType: "ClusterIP",
54
+ * });
55
+ * web.serviceName; // K8s-native attrs
56
+ * ```
57
+ *
58
+ * **Example:** Any cluster via kubeconfig
59
+ * ```typescript
60
+ * const cluster = Kubernetes.KubeConfig({ context: "prod-east" });
61
+ *
62
+ * const nginx = yield* Kubernetes.Deployment("Nginx", {
63
+ * cluster,
64
+ * image: "nginx:1.27",
65
+ * replicas: 3,
66
+ * port: 80,
67
+ * serviceType: "LoadBalancer",
68
+ * });
69
+ * nginx.url; // the load balancer's address
70
+ * ```
71
+ *
72
+ * **Example:** Build your own Dockerfile
73
+ * ```typescript
74
+ * const legacy = yield* Kubernetes.Deployment("LegacyApp", {
75
+ * cluster,
76
+ * context: "./legacy",
77
+ * replicas: 2,
78
+ * port: 8080,
79
+ * });
80
+ * ```
81
+ *
82
+ * ### Effect Servers
83
+ * **Example:** Inline Effect server
84
+ * ```typescript
85
+ * const api = yield* Kubernetes.Deployment(
86
+ * "Api",
87
+ * { cluster, main: import.meta.url, port: 3000, replicas: 2 },
88
+ * Effect.gen(function* () {
89
+ * return {
90
+ * fetch: Effect.succeed(HttpServerResponse.text("ok")),
91
+ * };
92
+ * }),
93
+ * );
94
+ * ```
95
+ *
96
+ * **Example:** Push to your own registry
97
+ * ```typescript
98
+ * const cluster = Kubernetes.KubeConfig({
99
+ * context: "prod-east",
100
+ * registry: { server: "ghcr.io/acme" },
101
+ * });
102
+ *
103
+ * const api = yield* Kubernetes.Deployment(
104
+ * "Api",
105
+ * { cluster, main: import.meta.url, port: 3000 },
106
+ * Effect.gen(function* () {
107
+ * return {
108
+ * fetch: Effect.succeed(HttpServerResponse.text("ok")),
109
+ * };
110
+ * }),
111
+ * );
112
+ * ```
113
+ *
114
+ * **Example:** DynamoDB binding on EKS
115
+ * ```typescript
116
+ * const cluster = yield* AWS.EKS.Cluster("Cluster", { compute: "auto" });
117
+ *
118
+ * const api = yield* Kubernetes.Deployment(
119
+ * "Api",
120
+ * { cluster, main: import.meta.url, port: 3000 },
121
+ * Effect.gen(function* () {
122
+ * const putItem = yield* AWS.DynamoDB.PutItem(table);
123
+ * return {
124
+ * fetch: Effect.gen(function* () {
125
+ * yield* putItem({ Item: { id: { S: "1" } } });
126
+ * return HttpServerResponse.text("ok");
127
+ * }),
128
+ * };
129
+ * }).pipe(Effect.provide(AWS.DynamoDB.PutItemHttp)),
130
+ * );
131
+ * ```
132
+ *
133
+ * **Example:** Tagged Effect server
134
+ * ```typescript
135
+ * export class Api extends Kubernetes.Deployment<Api, {
136
+ * health: () => Effect.Effect<string>;
137
+ * }>()("Api") {}
138
+ *
139
+ * export default Api.make(
140
+ * { cluster, main: import.meta.url, port: 3000 },
141
+ * Effect.gen(function* () {
142
+ * return {
143
+ * fetch: Effect.gen(function* () {
144
+ * return HttpServerResponse.text("ok");
145
+ * }),
146
+ * health: () => Effect.succeed("ok"),
147
+ * };
148
+ * }),
149
+ * );
150
+ * ```
151
+ *
152
+ * ### Bundling & Tree-shaking
153
+ * `main` is bundled with rolldown at deploy time. Unused code is
154
+ * tree-shaken. `effect`, alchemy, and `@distilled.cloud` are marked
155
+ * pure so unused parts prune more aggressively. Your app is not
156
+ * marked pure.
157
+ *
158
+ * **Example:** Mark additional packages as pure
159
+ * Only list packages with no top-level side effects.
160
+ * ```typescript
161
+ * {
162
+ * main: import.meta.url,
163
+ * build: {
164
+ * pure: { packages: ["my-lib", "@my-scope/*"] },
165
+ * },
166
+ * }
167
+ * ```
168
+ *
169
+ * **Example:** Turn it off
170
+ * ```typescript
171
+ * {
172
+ * main: import.meta.url,
173
+ * build: { pure: false },
174
+ * }
175
+ * ```
176
+ *
177
+ * ### Kubernetes Escape Hatch
178
+ * **Example:** Tune the synthesized pod template
179
+ * ```typescript
180
+ * const tuned = yield* Kubernetes.Deployment("Api", {
181
+ * cluster,
182
+ * main: import.meta.url,
183
+ * port: 3000,
184
+ * podTemplate: {
185
+ * spec: {
186
+ * tolerations: [{ key: "gpu", operator: "Exists" }],
187
+ * nodeSelector: { pool: "arm" },
188
+ * },
189
+ * },
190
+ * });
191
+ * ```
192
+ *
193
+ * @resource
194
+ * @product Workloads
195
+ */
196
+ export const Deployment = Platform("Kubernetes.Deployment", {
197
+ aliases: ["AWS.EKS.Deployment"],
198
+ // `{ cluster: Cluster }` at module scope is an Effect. Yield it here so the
199
+ // cluster is registered and `news.cluster` is resolved at reconcile (same
200
+ // as `yield* Cluster` inside Effect.gen).
201
+ transformProps: (_id, props) => Effect.gen(function* () {
202
+ if (globalThis.__ALCHEMY_RUNTIME__)
203
+ return props;
204
+ const cluster = Effect.isEffect(props.cluster)
205
+ ? yield* props.cluster
206
+ : props.cluster;
207
+ return { ...props, cluster };
208
+ }),
209
+ createRuntimeContext: createHostRuntimeContext("Kubernetes.Deployment"),
210
+ });
211
+ /**
212
+ * `cluster` as the provider sees it. `transformProps` yields an Effect-valued
213
+ * `cluster` before any lifecycle operation runs, so only the resolved shape
214
+ * reaches the provider.
215
+ */
216
+ const clusterOf = (cluster) => cluster;
217
+ class ServiceNotReady extends Data.TaggedError("Kubernetes.ServiceNotReady") {
218
+ }
219
+ // Bounded ~3 min wait for the cloud load balancer to publish its hostname
220
+ // (an EKS Auto Mode NLB typically appears within 2–3 min of the Service
221
+ // apply).
222
+ const loadBalancerRetrySchedule = Schedule.max([Schedule.spaced("5 seconds"), Schedule.recurs(36)]);
223
+ /**
224
+ * Explicitly-typed pipeable retry for the LB-hostname wait. An inline
225
+ * `Effect.retry` in the provider leaks `Retry.Return`'s conditional into
226
+ * declaration emit and widens the provider layer to `unknown` R.
227
+ */
228
+ const retryUntilServiceReady = (self) => Effect.retry(self, {
229
+ while: (error) => error instanceof ServiceNotReady,
230
+ schedule: loadBalancerRetrySchedule,
231
+ });
232
+ class ServiceStillExists extends Data.TaggedError("Kubernetes.ServiceStillExists") {
233
+ }
234
+ /**
235
+ * Bounded (~3 min) wait for a deleted Service to disappear, i.e. for the
236
+ * cloud controller to tear down its load balancer and drop the finalizer.
237
+ */
238
+ const waitForServiceGone = (transport, service) => Effect.retry(readObject({ transport, object: service }).pipe(Effect.flatMap(() => Effect.fail(new ServiceStillExists())), Effect.catchTag("KubernetesNotFound", () => Effect.void)), { while: (error) => error instanceof ServiceStillExists, schedule: loadBalancerRetrySchedule });
239
+ export const DeploymentProvider = () => Provider.effect(Deployment, Effect.gen(function* () {
240
+ const stack = yield* Stack;
241
+ const connectionRegistry = yield* makeConnectionRegistry;
242
+ const alchemyEnv = {
243
+ ALCHEMY_STACK_NAME: stack.name,
244
+ ALCHEMY_STAGE: stack.stage,
245
+ ALCHEMY_PHASE: "runtime",
246
+ };
247
+ // The base name doubles as the `app.kubernetes.io/name` label value
248
+ // (and the Service name), both capped at 63 characters.
249
+ const toBaseName = (id, props = {}) => props.name
250
+ ? Effect.succeed(props.name)
251
+ : createPhysicalName({ id, maxLength: 63, lowercase: true }).pipe(Effect.map((name) => name.replaceAll(/[^a-z0-9-]/g, "-")));
252
+ // Read a LoadBalancer Service's assigned hostname (bounded wait).
253
+ const waitForLoadBalancer = (transport, service) => readObject({ transport, object: service }).pipe(Effect.map((response) => {
254
+ const ingress = response?.status?.loadBalancer?.ingress?.[0];
255
+ return ingress?.hostname ?? ingress?.ip;
256
+ }), Effect.flatMap((hostname) => hostname ? Effect.succeed(hostname) : Effect.fail(new ServiceNotReady())), retryUntilServiceReady, Effect.catchTag("Kubernetes.ServiceNotReady", () => Effect.succeed(undefined)));
257
+ return {
258
+ stables: [
259
+ "connection",
260
+ "namespace",
261
+ "serviceAccountName",
262
+ "deploymentName",
263
+ "serviceName",
264
+ "identity",
265
+ "registry",
266
+ ],
267
+ // A Deployment's identity spans in-cluster Kubernetes objects plus
268
+ // adapter-owned cloud resources (identity role, image repository).
269
+ // There is no single enumeration that faithfully reconstructs that
270
+ // composite, so enumeration is intentionally empty — `read` (below)
271
+ // refreshes a known instance from its persisted output.
272
+ list: () => Effect.succeed([]),
273
+ diff: Effect.fn(function* ({ olds = {}, news: input, output }) {
274
+ // `exports` carries the program's runtime Effects (never plain
275
+ // data); everything else must be resolved to diff.
276
+ const { exports: _exports, ...declared } = input;
277
+ if (!isResolved(declared))
278
+ return;
279
+ const news = input;
280
+ const oldCluster = connectionIdentity(tryConnectionOf(clusterOf(olds.cluster)));
281
+ const newCluster = connectionIdentity(tryConnectionOf(clusterOf(news.cluster)));
282
+ // Workload identity keys on (cluster, namespace, serviceAccount);
283
+ // a change to either forces a replacement. Only compare when the
284
+ // old value is present so a first create (empty `olds`) doesn't
285
+ // spuriously replace.
286
+ if (oldCluster !== undefined && newCluster !== undefined && oldCluster !== newCluster) {
287
+ return { action: "replace" };
288
+ }
289
+ if (oldCluster !== undefined &&
290
+ (olds.namespace ?? "default") !== (news.namespace ?? "default")) {
291
+ return { action: "replace" };
292
+ }
293
+ // Content drift: the props don't change when files under a build
294
+ // context (or the bundled program) do, so surface hash drift as
295
+ // an update.
296
+ const connection = tryConnectionOf(clusterOf(news.cluster));
297
+ if (output && connection) {
298
+ const adapter = yield* findClusterAdapter(connection.auth.kind);
299
+ const source = news;
300
+ const hash = yield* workloadImageHash({
301
+ adapter,
302
+ connection,
303
+ connectionRegistry,
304
+ source,
305
+ platform: imagePlatformOf(news.architecture, connection),
306
+ port: news.port ?? 3000,
307
+ isExternal: news.isExternal,
308
+ bootstrap: (adapter.bootstrap?.server ?? makeServerBootstrap)(source.handler ?? "default"),
309
+ });
310
+ if (hash !== undefined && hash !== output.code.hash) {
311
+ return { action: "update" };
312
+ }
313
+ }
314
+ }),
315
+ read: Effect.fn(function* ({ output }) {
316
+ if (!output)
317
+ return undefined;
318
+ const connection = connectionOfOutput(output);
319
+ if (!connection)
320
+ return undefined;
321
+ const transport = yield* connectCluster(connection);
322
+ // The ServiceAccount is the stable first object of the workload
323
+ // (one-shot Job objects are content-addressed and may have been
324
+ // TTL-collected, so they are not an existence signal).
325
+ const anchor = (output.kubernetesObjects ?? [])[0];
326
+ if (!anchor)
327
+ return output;
328
+ const observed = yield* readObject({ transport, object: anchor }).pipe(Effect.catchTag("KubernetesNotFound", () => Effect.succeed(undefined)));
329
+ if (observed === undefined)
330
+ return undefined;
331
+ return output;
332
+ }),
333
+ reconcile: Effect.fn(function* ({ id, news, bindings, output, session }) {
334
+ const connection = toConnection(clusterOf(news.cluster));
335
+ const adapter = yield* findClusterAdapter(connection.auth.kind);
336
+ const transport = yield* adapter.connect(connection);
337
+ const namespace = news.namespace ?? "default";
338
+ const port = news.port ?? 3000;
339
+ const serviceType = news.serviceType ?? "LoadBalancer";
340
+ const baseName = output?.deploymentName ?? (yield* toBaseName(id, news));
341
+ const serviceAccountName = output?.serviceAccountName ?? baseName;
342
+ const tags = { ...(yield* createInternalTags(id)), ...news.tags };
343
+ // Environment from bindings is collected generically; cloud
344
+ // credential grants (any non-env binding channel) require the
345
+ // cluster platform's identity adapter.
346
+ const { env: bindingEnv, grantKeys } = collectBindingEnv(bindings);
347
+ if (grantKeys.length > 0 && adapter.identity === undefined) {
348
+ return yield* Effect.die(new Error(`'${id}': bindings carry cloud credential grants ` +
349
+ `(${grantKeys.join(", ")}) but this cluster's platform ` +
350
+ "has no workload-identity adapter. Target a managed " +
351
+ "cluster (e.g. AWS.EKS.Cluster) or bind through " +
352
+ "environment variables instead."));
353
+ }
354
+ const identity = adapter.identity
355
+ ? yield* adapter.identity.reconcile({
356
+ id,
357
+ connection,
358
+ namespace,
359
+ serviceAccount: serviceAccountName,
360
+ bindings,
361
+ options: news.identity,
362
+ state: output?.identity ??
363
+ output,
364
+ tags,
365
+ })
366
+ : undefined;
367
+ // Resolve the container image from whichever source the props
368
+ // declare (`main` | `context` | `image`) through the platform's
369
+ // registry adapter (pre-built `image` refs pass through verbatim
370
+ // on registry-less clusters).
371
+ const source = news;
372
+ const resolved = yield* resolveWorkloadImage({
373
+ adapter,
374
+ connection,
375
+ connectionRegistry,
376
+ id,
377
+ source,
378
+ platform: imagePlatformOf(news.architecture, connection),
379
+ port,
380
+ isExternal: news.isExternal,
381
+ bootstrap: (adapter.bootstrap?.server ?? makeServerBootstrap)(source.handler ?? "default"),
382
+ tags,
383
+ state: output?.registry ??
384
+ output,
385
+ session,
386
+ });
387
+ // Synthesize the Kubernetes objects. Container env merges binding
388
+ // env (Output-referenced resource attributes flow via the
389
+ // RuntimeContext into `news.env`), adapter env (e.g. AWS_REGION on
390
+ // EKS), alchemy env, and user env. The generated name label is
391
+ // always present so the Service selector stays workload-unique
392
+ // even when user labels are set.
393
+ const labels = { "app.kubernetes.io/name": baseName, ...news.labels };
394
+ const containerEnv = {
395
+ ...bindingEnv,
396
+ ...identity?.env,
397
+ ...alchemyEnv,
398
+ PORT: String(port),
399
+ ...news.env,
400
+ };
401
+ const serviceAccountObject = {
402
+ apiVersion: "v1",
403
+ kind: "ServiceAccount",
404
+ metadata: {
405
+ name: serviceAccountName,
406
+ namespace,
407
+ labels,
408
+ ...(identity?.serviceAccountAnnotations
409
+ ? { annotations: identity.serviceAccountAnnotations }
410
+ : {}),
411
+ },
412
+ };
413
+ const podTemplate = deepMerge({
414
+ metadata: { labels },
415
+ spec: {
416
+ serviceAccountName,
417
+ containers: [
418
+ {
419
+ name: baseName,
420
+ image: resolved.imageUri,
421
+ command: news.command,
422
+ args: news.args,
423
+ ports: [{ containerPort: port }],
424
+ env: Object.entries(containerEnv).map(([name, value]) => ({
425
+ name,
426
+ value: containerEnvValue(value),
427
+ })),
428
+ resources: news.resources,
429
+ },
430
+ ],
431
+ },
432
+ }, news.podTemplate);
433
+ const deploymentObject = {
434
+ apiVersion: "apps/v1",
435
+ kind: "Deployment",
436
+ metadata: { name: baseName, namespace, labels },
437
+ spec: {
438
+ replicas: news.replicas ?? 1,
439
+ selector: { matchLabels: labels },
440
+ template: podTemplate,
441
+ },
442
+ };
443
+ // `LoadBalancer` Services need platform defaults on some managed
444
+ // clouds (EKS Auto Mode only reconciles Services carrying its
445
+ // `loadBalancerClass`, and defaults new NLBs to the internal
446
+ // scheme) — ask the adapter. User `serviceAnnotations` always win.
447
+ let loadBalancerClass;
448
+ let serviceAnnotations = news.serviceAnnotations;
449
+ if (serviceType === "LoadBalancer") {
450
+ const defaults = adapter.loadBalancerDefaults
451
+ ? yield* adapter.loadBalancerDefaults({ connection })
452
+ : undefined;
453
+ loadBalancerClass = defaults?.loadBalancerClass;
454
+ serviceAnnotations = { ...defaults?.annotations, ...news.serviceAnnotations };
455
+ }
456
+ const serviceObject = {
457
+ apiVersion: "v1",
458
+ kind: "Service",
459
+ metadata: { name: baseName, namespace, labels, annotations: serviceAnnotations },
460
+ spec: {
461
+ type: serviceType,
462
+ ...(loadBalancerClass !== undefined ? { loadBalancerClass } : {}),
463
+ selector: labels,
464
+ ports: [{ port, targetPort: port, protocol: "TCP" }],
465
+ },
466
+ };
467
+ const desiredObjects = [serviceAccountObject, deploymentObject, serviceObject];
468
+ const kubernetesObjects = yield* reconcileObjects({
469
+ transport,
470
+ previousObjects: output?.kubernetesObjects ?? [],
471
+ desiredObjects,
472
+ });
473
+ yield* session.note(`Applied Kubernetes Deployment ${namespace}/${baseName}`);
474
+ // Resolve the LoadBalancer URL if applicable. The cloud listener
475
+ // is the Service `port` (Kubernetes maps `spec.ports[].port` 1:1
476
+ // to it), so the URL carries the port unless it's 80 — mirroring
477
+ // `AWS.ECS.Service`'s url semantics.
478
+ const hostname = serviceType === "LoadBalancer"
479
+ ? yield* waitForLoadBalancer(transport, toKubernetesObjectRef(serviceObject))
480
+ : undefined;
481
+ const url = hostname === undefined
482
+ ? undefined
483
+ : port === 80
484
+ ? `http://${hostname}`
485
+ : `http://${hostname}:${port}`;
486
+ return {
487
+ connection,
488
+ namespace,
489
+ deploymentName: baseName,
490
+ serviceName: baseName,
491
+ serviceAccountName,
492
+ port,
493
+ imageUri: resolved.imageUri,
494
+ identity: identity?.state,
495
+ registry: resolved.state,
496
+ url,
497
+ kubernetesObjects,
498
+ code: { hash: resolved.codeHash },
499
+ };
500
+ }),
501
+ delete: Effect.fn(function* ({ output }) {
502
+ const connection = connectionOfOutput(output);
503
+ if (!connection)
504
+ return;
505
+ const adapter = yield* findClusterAdapter(connection.auth.kind);
506
+ // Skip only a missing cluster, then still clean up adapter-owned
507
+ // cloud resources (image repository, identity role).
508
+ const transport = yield* ifClusterExists(adapter.connect(connection));
509
+ if (transport && (output.kubernetesObjects ?? []).length > 0) {
510
+ yield* deleteObjects({ transport, objects: output.kubernetesObjects ?? [] });
511
+ // A LoadBalancer Service carries the cloud controller's cleanup
512
+ // finalizer; wait for it so the cloud load balancer is gone
513
+ // before the cluster (and its controller) can be deleted —
514
+ // deleting the cluster first leaks the load balancer.
515
+ yield* Effect.forEach((output.kubernetesObjects ?? []).filter((object) => object.kind === "Service"), (service) => waitForServiceGone(transport, service), { discard: true });
516
+ }
517
+ if (adapter.identity) {
518
+ yield* adapter.identity.delete({
519
+ connection,
520
+ state: output.identity ??
521
+ output,
522
+ });
523
+ }
524
+ if (adapter.registry) {
525
+ yield* adapter.registry.delete({
526
+ state: output.registry ??
527
+ output,
528
+ });
529
+ }
530
+ }),
531
+ };
532
+ }));
533
+ //# sourceMappingURL=Deployment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Deployment.js","sourceRoot":"","sources":["../src/Deployment.ts"],"names":[],"mappings":"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"}