@alchemy.run/kubernetes 0.0.0 → 2.0.0-beta.85
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.
- package/LICENSE +201 -0
- package/README.md +41 -4
- package/lib/BuiltinAdapters.d.ts +43 -0
- package/lib/BuiltinAdapters.d.ts.map +1 -0
- package/lib/BuiltinAdapters.js +129 -0
- package/lib/BuiltinAdapters.js.map +1 -0
- package/lib/Client.d.ts +97 -0
- package/lib/Client.d.ts.map +1 -0
- package/lib/Client.js +312 -0
- package/lib/Client.js.map +1 -0
- package/lib/ClusterAdapter.d.ts +324 -0
- package/lib/ClusterAdapter.d.ts.map +1 -0
- package/lib/ClusterAdapter.js +65 -0
- package/lib/ClusterAdapter.js.map +1 -0
- package/lib/Connection.d.ts +210 -0
- package/lib/Connection.d.ts.map +1 -0
- package/lib/Connection.js +58 -0
- package/lib/Connection.js.map +1 -0
- package/lib/Deployment.d.ts +401 -0
- package/lib/Deployment.d.ts.map +1 -0
- package/lib/Deployment.js +550 -0
- package/lib/Deployment.js.map +1 -0
- package/lib/HelmChart.d.ts +147 -0
- package/lib/HelmChart.d.ts.map +1 -0
- package/lib/HelmChart.js +248 -0
- package/lib/HelmChart.js.map +1 -0
- package/lib/Job.d.ts +333 -0
- package/lib/Job.d.ts.map +1 -0
- package/lib/Job.js +443 -0
- package/lib/Job.js.map +1 -0
- package/lib/LocalCluster.d.ts +243 -0
- package/lib/LocalCluster.d.ts.map +1 -0
- package/lib/LocalCluster.js +359 -0
- package/lib/LocalCluster.js.map +1 -0
- package/lib/Manifest.d.ts +157 -0
- package/lib/Manifest.d.ts.map +1 -0
- package/lib/Manifest.js +205 -0
- package/lib/Manifest.js.map +1 -0
- package/lib/Objects.d.ts +60 -0
- package/lib/Objects.d.ts.map +1 -0
- package/lib/Objects.js +132 -0
- package/lib/Objects.js.map +1 -0
- package/lib/Providers.d.ts +24 -0
- package/lib/Providers.d.ts.map +1 -0
- package/lib/Providers.js +36 -0
- package/lib/Providers.js.map +1 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +10 -0
- package/lib/index.js.map +1 -0
- package/lib/internal/declared.d.ts +19 -0
- package/lib/internal/declared.d.ts.map +1 -0
- package/lib/internal/declared.js +435 -0
- package/lib/internal/declared.js.map +1 -0
- package/lib/internal/helm.d.ts +65 -0
- package/lib/internal/helm.d.ts.map +1 -0
- package/lib/internal/helm.js +173 -0
- package/lib/internal/helm.js.map +1 -0
- package/lib/internal/kind.d.ts +17 -0
- package/lib/internal/kind.d.ts.map +1 -0
- package/lib/internal/kind.js +31 -0
- package/lib/internal/kind.js.map +1 -0
- package/lib/internal/kubeconfig.d.ts +79 -0
- package/lib/internal/kubeconfig.d.ts.map +1 -0
- package/lib/internal/kubeconfig.js +222 -0
- package/lib/internal/kubeconfig.js.map +1 -0
- package/lib/internal/registry.d.ts +44 -0
- package/lib/internal/registry.d.ts.map +1 -0
- package/lib/internal/registry.js +72 -0
- package/lib/internal/registry.js.map +1 -0
- package/lib/internal/workload.d.ts +127 -0
- package/lib/internal/workload.d.ts.map +1 -0
- package/lib/internal/workload.js +411 -0
- package/lib/internal/workload.js.map +1 -0
- package/package.json +55 -3
- package/src/BuiltinAdapters.ts +202 -0
- package/src/Client.ts +496 -0
- package/src/ClusterAdapter.ts +373 -0
- package/src/Connection.ts +234 -0
- package/src/Deployment.ts +872 -0
- package/src/HelmChart.ts +388 -0
- package/src/Job.ts +709 -0
- package/src/LocalCluster.ts +631 -0
- package/src/Manifest.ts +301 -0
- package/src/Objects.ts +213 -0
- package/src/Providers.ts +52 -0
- package/src/globals.d.ts +2 -0
- package/src/index.ts +9 -0
- package/src/internal/declared.ts +471 -0
- package/src/internal/helm.ts +245 -0
- package/src/internal/kind.ts +43 -0
- package/src/internal/kubeconfig.ts +364 -0
- package/src/internal/registry.ts +108 -0
- package/src/internal/workload.ts +504 -0
package/lib/Job.js
ADDED
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
import { isResolved } from "alchemy/Diff";
|
|
2
|
+
import * as Output from "alchemy/Output";
|
|
3
|
+
import { createPhysicalName } from "alchemy/PhysicalName";
|
|
4
|
+
import { Platform } from "alchemy/Platform";
|
|
5
|
+
import * as Provider from "alchemy/Provider";
|
|
6
|
+
import { Resource } from "alchemy/Resource";
|
|
7
|
+
import { packEnvValue, unpackEnvValue, RuntimeContext } from "alchemy/RuntimeContext";
|
|
8
|
+
import { Stack } from "alchemy/Stack";
|
|
9
|
+
import { createInternalTags } from "alchemy/Tags";
|
|
10
|
+
import { unwrapRedacted } from "alchemy/Util/data";
|
|
11
|
+
import { sha256Object } from "alchemy/Util/sha256";
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import { connectCluster, deleteObjects, ifClusterExists, readObject, reconcileObjects, } from "./Client.js";
|
|
14
|
+
import { findClusterAdapter, } from "./ClusterAdapter.js";
|
|
15
|
+
import { toConnection } from "./Connection.js";
|
|
16
|
+
import { makeConnectionRegistry } from "./internal/registry.js";
|
|
17
|
+
import { collectBindingEnv, containerEnvValue, connectionIdentity, connectionOfOutput, deepMerge, imagePlatformOf, makeJobBootstrap, resolveWorkloadImage, tryConnectionOf, workloadImageHash, } from "./internal/workload.js";
|
|
18
|
+
export const isJob = (value) => typeof value === "object" && value !== null && "Type" in value && value.Type === "Kubernetes.Job";
|
|
19
|
+
/**
|
|
20
|
+
* Run-to-completion work on any Kubernetes cluster, as a container image
|
|
21
|
+
* or an Effect program.
|
|
22
|
+
*
|
|
23
|
+
* `Job` provisions a Kubernetes `Job` (or `CronJob` when `schedule` is
|
|
24
|
+
* set) via server-side apply and a ServiceAccount, plus — through the
|
|
25
|
+
* target cluster's platform adapter — workload identity and a container
|
|
26
|
+
* image from exactly one of three sources flat on props: `main` (bundle an
|
|
27
|
+
* inline Effect program whose impl returns `{ run }`), `context` (build
|
|
28
|
+
* your own Dockerfile), or `image` (a pre-built registry reference).
|
|
29
|
+
* `main` and `context` images are built on the deploying machine and
|
|
30
|
+
* pushed to the connection's registry (`Kubernetes.LocalCluster` includes
|
|
31
|
+
* one; EKS uses ECR; GKE uses Artifact Registry). On `AWS.EKS.Cluster`
|
|
32
|
+
* targets, bindings attach IAM policy statements to a generated
|
|
33
|
+
* pod-identity role; on `GCP.Container.Cluster` targets, GCP bindings grant
|
|
34
|
+
* their IAM roles to the Kubernetes ServiceAccount's Workload Identity
|
|
35
|
+
* Federation principal — exactly like `Kubernetes.Deployment`.
|
|
36
|
+
* ### Creating a Job
|
|
37
|
+
* **Example:** Remote image (external — no Effect runtime in the container)
|
|
38
|
+
* ```typescript
|
|
39
|
+
* const migrate = yield* Kubernetes.Job("DbMigrate", {
|
|
40
|
+
* cluster,
|
|
41
|
+
* image: "ghcr.io/acme/migrator:v3",
|
|
42
|
+
* backoffLimit: 2,
|
|
43
|
+
* });
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* **Example:** Your own Dockerfile with build args and secrets
|
|
47
|
+
* ```typescript
|
|
48
|
+
* // Dockerfile:
|
|
49
|
+
* // ARG NODE_ENV
|
|
50
|
+
* // RUN --mount=type=secret,id=NPM_TOKEN,env=NPM_TOKEN npm ci
|
|
51
|
+
* const migrate = yield* Kubernetes.Job("DbMigrate", {
|
|
52
|
+
* cluster,
|
|
53
|
+
* context: "./migrator",
|
|
54
|
+
* build: {
|
|
55
|
+
* args: { NODE_ENV: "production" },
|
|
56
|
+
* // Mounted only into the RUN step that asks for it; never in the image.
|
|
57
|
+
* secrets: { NPM_TOKEN: Config.Redacted("NPM_TOKEN") },
|
|
58
|
+
* },
|
|
59
|
+
* backoffLimit: 2,
|
|
60
|
+
* });
|
|
61
|
+
* ```
|
|
62
|
+
*
|
|
63
|
+
* **Example:** Inline Effect program
|
|
64
|
+
* ```typescript
|
|
65
|
+
* const cluster = yield* Kubernetes.LocalCluster("Cluster", {
|
|
66
|
+
* name: "alchemy",
|
|
67
|
+
* });
|
|
68
|
+
*
|
|
69
|
+
* const hello = yield* Kubernetes.Job(
|
|
70
|
+
* "Hello",
|
|
71
|
+
* { cluster, main: import.meta.url, backoffLimit: 2 },
|
|
72
|
+
* Effect.gen(function* () {
|
|
73
|
+
* return {
|
|
74
|
+
* run: Effect.log("hello from a Job"),
|
|
75
|
+
* };
|
|
76
|
+
* }),
|
|
77
|
+
* );
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* **Example:** Inline Effect program with a DynamoDB binding (EKS)
|
|
81
|
+
* ```typescript
|
|
82
|
+
* const seed = yield* Kubernetes.Job(
|
|
83
|
+
* "SeedData",
|
|
84
|
+
* { cluster, main: import.meta.url },
|
|
85
|
+
* Effect.gen(function* () {
|
|
86
|
+
* const putItem = yield* AWS.DynamoDB.PutItem(table);
|
|
87
|
+
* return {
|
|
88
|
+
* run: Effect.gen(function* () {
|
|
89
|
+
* yield* putItem({ Item: { id: { S: "seed" } } });
|
|
90
|
+
* }),
|
|
91
|
+
* };
|
|
92
|
+
* }).pipe(Effect.provide(AWS.DynamoDB.PutItemHttp)),
|
|
93
|
+
* );
|
|
94
|
+
* ```
|
|
95
|
+
*
|
|
96
|
+
* **Example:** Tagged Effect program
|
|
97
|
+
* ```typescript
|
|
98
|
+
* export class Backfill extends Kubernetes.Job<Backfill, {
|
|
99
|
+
* progress: () => Effect.Effect<number>;
|
|
100
|
+
* }>()("Backfill") {}
|
|
101
|
+
*
|
|
102
|
+
* export default Backfill.make(
|
|
103
|
+
* { cluster, main: import.meta.url, backoffLimit: 1 },
|
|
104
|
+
* Effect.gen(function* () {
|
|
105
|
+
* return {
|
|
106
|
+
* run: Effect.gen(function* () { }),
|
|
107
|
+
* progress: () => Effect.succeed(0),
|
|
108
|
+
* };
|
|
109
|
+
* }),
|
|
110
|
+
* );
|
|
111
|
+
* ```
|
|
112
|
+
*
|
|
113
|
+
* ### Bundling & Tree-shaking
|
|
114
|
+
* `main` is bundled with rolldown at deploy time. Unused code is
|
|
115
|
+
* tree-shaken. `effect`, alchemy, and `@distilled.cloud` are marked
|
|
116
|
+
* pure so unused parts prune more aggressively. Your app is not
|
|
117
|
+
* marked pure.
|
|
118
|
+
*
|
|
119
|
+
* **Example:** Mark additional packages as pure
|
|
120
|
+
* Only list packages with no top-level side effects.
|
|
121
|
+
* ```typescript
|
|
122
|
+
* {
|
|
123
|
+
* main: import.meta.url,
|
|
124
|
+
* build: {
|
|
125
|
+
* pure: { packages: ["my-lib", "@my-scope/*"] },
|
|
126
|
+
* },
|
|
127
|
+
* }
|
|
128
|
+
* ```
|
|
129
|
+
*
|
|
130
|
+
* **Example:** Turn it off
|
|
131
|
+
* ```typescript
|
|
132
|
+
* {
|
|
133
|
+
* main: import.meta.url,
|
|
134
|
+
* build: { pure: false },
|
|
135
|
+
* }
|
|
136
|
+
* ```
|
|
137
|
+
*
|
|
138
|
+
* ### Scheduling
|
|
139
|
+
* **Example:** Nightly CronJob
|
|
140
|
+
* ```typescript
|
|
141
|
+
* const nightly = yield* Kubernetes.Job("NightlyBackfill", {
|
|
142
|
+
* cluster,
|
|
143
|
+
* main: import.meta.url,
|
|
144
|
+
* schedule: "0 3 * * *",
|
|
145
|
+
* });
|
|
146
|
+
* ```
|
|
147
|
+
*
|
|
148
|
+
* @resource
|
|
149
|
+
* @product Workloads
|
|
150
|
+
*/
|
|
151
|
+
export const Job = Platform("Kubernetes.Job", {
|
|
152
|
+
aliases: ["AWS.EKS.Job"],
|
|
153
|
+
createRuntimeContext: (id) => {
|
|
154
|
+
// A one-shot host context: `serve` (invoked by the Platform machinery
|
|
155
|
+
// with the impl shape) registers the shape's `run` effect as the
|
|
156
|
+
// program instead of an HTTP server, so the generated entry executes
|
|
157
|
+
// it to completion and exits.
|
|
158
|
+
const runners = [];
|
|
159
|
+
const env = {};
|
|
160
|
+
const context = {
|
|
161
|
+
Type: "Kubernetes.Job",
|
|
162
|
+
id,
|
|
163
|
+
env,
|
|
164
|
+
set: (bindingId, output) => Effect.sync(() => {
|
|
165
|
+
const key = bindingId.replaceAll(/[^a-zA-Z0-9]/g, "_");
|
|
166
|
+
env[key] = output.pipe(Output.map(packEnvValue));
|
|
167
|
+
return key;
|
|
168
|
+
}),
|
|
169
|
+
get: (key) => Effect.sync(() => unpackEnvValue(process.env[key])),
|
|
170
|
+
run: (effect) => Effect.sync(() => {
|
|
171
|
+
runners.push(effect);
|
|
172
|
+
}),
|
|
173
|
+
serve: ((_handler, options) => Effect.sync(() => {
|
|
174
|
+
const run = options?.shape?.run;
|
|
175
|
+
if (Effect.isEffect(run)) {
|
|
176
|
+
// oxlint-disable-next-line effecttsgo/unsafe-effect-type-assertion -- `run` is a user program; the host runner surfaces its failures
|
|
177
|
+
runners.push(run);
|
|
178
|
+
}
|
|
179
|
+
})),
|
|
180
|
+
exports: Effect.sync(() => ({
|
|
181
|
+
program: Effect.all(runners, { concurrency: "unbounded" }).pipe(Effect.asVoid),
|
|
182
|
+
})),
|
|
183
|
+
};
|
|
184
|
+
return context;
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
export const JobProvider = () => Provider.effect(Job, Effect.gen(function* () {
|
|
188
|
+
const stack = yield* Stack;
|
|
189
|
+
const connectionRegistry = yield* makeConnectionRegistry;
|
|
190
|
+
const alchemyEnv = {
|
|
191
|
+
ALCHEMY_STACK_NAME: stack.name,
|
|
192
|
+
ALCHEMY_STAGE: stack.stage,
|
|
193
|
+
ALCHEMY_PHASE: "runtime",
|
|
194
|
+
};
|
|
195
|
+
// The base name doubles as the `app.kubernetes.io/name` label value
|
|
196
|
+
// (and the Service name), both capped at 63 characters.
|
|
197
|
+
const toBaseName = (id, props = {}) => props.name
|
|
198
|
+
? Effect.succeed(props.name)
|
|
199
|
+
: createPhysicalName({ id, maxLength: 63, lowercase: true }).pipe(Effect.map((name) => name.replaceAll(/[^a-z0-9-]/g, "-")));
|
|
200
|
+
return {
|
|
201
|
+
stables: ["connection", "namespace", "serviceAccountName", "identity", "registry"],
|
|
202
|
+
// A Job's identity spans in-cluster Kubernetes objects plus
|
|
203
|
+
// adapter-owned cloud resources — no single enumeration
|
|
204
|
+
// reconstructs the composite, so enumeration is empty; `read`
|
|
205
|
+
// refreshes known instances.
|
|
206
|
+
list: () => Effect.succeed([]),
|
|
207
|
+
diff: Effect.fn(function* ({ olds = {}, news: input, output }) {
|
|
208
|
+
// `exports` carries the program's runtime Effects (never plain
|
|
209
|
+
// data); everything else must be resolved to diff.
|
|
210
|
+
const { exports: _exports, ...declared } = input;
|
|
211
|
+
if (!isResolved(declared))
|
|
212
|
+
return;
|
|
213
|
+
const news = input;
|
|
214
|
+
const oldCluster = connectionIdentity(tryConnectionOf(olds.cluster));
|
|
215
|
+
const newCluster = connectionIdentity(tryConnectionOf(news.cluster));
|
|
216
|
+
if (oldCluster !== undefined && newCluster !== undefined && oldCluster !== newCluster) {
|
|
217
|
+
return { action: "replace" };
|
|
218
|
+
}
|
|
219
|
+
if (oldCluster !== undefined &&
|
|
220
|
+
(olds.namespace ?? "default") !== (news.namespace ?? "default")) {
|
|
221
|
+
return { action: "replace" };
|
|
222
|
+
}
|
|
223
|
+
// Content drift (see Deployment).
|
|
224
|
+
const connection = tryConnectionOf(news.cluster);
|
|
225
|
+
if (output && connection) {
|
|
226
|
+
const adapter = yield* findClusterAdapter(connection.auth.kind);
|
|
227
|
+
const source = news;
|
|
228
|
+
const hash = yield* workloadImageHash({
|
|
229
|
+
adapter,
|
|
230
|
+
connection,
|
|
231
|
+
connectionRegistry,
|
|
232
|
+
source,
|
|
233
|
+
platform: imagePlatformOf(news.architecture, connection),
|
|
234
|
+
isExternal: news.isExternal,
|
|
235
|
+
bootstrap: (adapter.bootstrap?.job ?? makeJobBootstrap)(source.handler ?? "default"),
|
|
236
|
+
});
|
|
237
|
+
if (hash !== undefined && hash !== output.code.hash) {
|
|
238
|
+
return { action: "update" };
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}),
|
|
242
|
+
read: Effect.fn(function* ({ output }) {
|
|
243
|
+
if (!output)
|
|
244
|
+
return undefined;
|
|
245
|
+
const connection = connectionOfOutput(output);
|
|
246
|
+
if (!connection)
|
|
247
|
+
return undefined;
|
|
248
|
+
const transport = yield* connectCluster(connection);
|
|
249
|
+
// The ServiceAccount is the stable existence anchor: one-shot Job
|
|
250
|
+
// objects are content-addressed and may have been TTL-collected.
|
|
251
|
+
const anchor = (output.kubernetesObjects ?? [])[0];
|
|
252
|
+
if (!anchor)
|
|
253
|
+
return output;
|
|
254
|
+
const observed = yield* readObject({
|
|
255
|
+
transport,
|
|
256
|
+
object: anchor,
|
|
257
|
+
}).pipe(Effect.catchTag("KubernetesNotFound", () => Effect.undefined));
|
|
258
|
+
if (observed === undefined)
|
|
259
|
+
return undefined;
|
|
260
|
+
return output;
|
|
261
|
+
}),
|
|
262
|
+
reconcile: Effect.fn(function* ({ id, news, bindings, output, session }) {
|
|
263
|
+
const connection = toConnection(news.cluster);
|
|
264
|
+
const adapter = yield* findClusterAdapter(connection.auth.kind);
|
|
265
|
+
const transport = yield* adapter.connect(connection);
|
|
266
|
+
const namespace = news.namespace ?? "default";
|
|
267
|
+
const baseName = yield* toBaseName(id, news);
|
|
268
|
+
const serviceAccountName = output?.serviceAccountName ?? baseName;
|
|
269
|
+
const tags = {
|
|
270
|
+
...(yield* createInternalTags(id)),
|
|
271
|
+
...news.tags,
|
|
272
|
+
};
|
|
273
|
+
const { env: bindingEnv, grantKeys } = collectBindingEnv(bindings);
|
|
274
|
+
if (grantKeys.length > 0 && adapter.identity === undefined) {
|
|
275
|
+
return yield* Effect.die(new Error(`'${id}': bindings carry cloud credential grants ` +
|
|
276
|
+
`(${grantKeys.join(", ")}) but this cluster's platform ` +
|
|
277
|
+
"has no workload-identity adapter. Target a managed " +
|
|
278
|
+
"cluster (e.g. AWS.EKS.Cluster) or bind through " +
|
|
279
|
+
"environment variables instead."));
|
|
280
|
+
}
|
|
281
|
+
const identity = adapter.identity
|
|
282
|
+
? yield* adapter.identity.reconcile({
|
|
283
|
+
id,
|
|
284
|
+
connection,
|
|
285
|
+
namespace,
|
|
286
|
+
serviceAccount: serviceAccountName,
|
|
287
|
+
bindings,
|
|
288
|
+
options: news.identity,
|
|
289
|
+
state: output?.identity ??
|
|
290
|
+
output,
|
|
291
|
+
tags,
|
|
292
|
+
})
|
|
293
|
+
: undefined;
|
|
294
|
+
// Resolve the container image (`main` | `context` | `image`).
|
|
295
|
+
const source = news;
|
|
296
|
+
const resolved = yield* resolveWorkloadImage({
|
|
297
|
+
adapter,
|
|
298
|
+
connection,
|
|
299
|
+
connectionRegistry,
|
|
300
|
+
id,
|
|
301
|
+
source,
|
|
302
|
+
platform: imagePlatformOf(news.architecture, connection),
|
|
303
|
+
isExternal: news.isExternal,
|
|
304
|
+
bootstrap: (adapter.bootstrap?.job ?? makeJobBootstrap)(source.handler ?? "default"),
|
|
305
|
+
tags,
|
|
306
|
+
state: output?.registry ??
|
|
307
|
+
output,
|
|
308
|
+
session,
|
|
309
|
+
});
|
|
310
|
+
// Synthesize the Kubernetes objects. The generated name label is
|
|
311
|
+
// always present so selectors and Kueue-style extra labels
|
|
312
|
+
// compose without erasing the workload's identity label.
|
|
313
|
+
const labels = {
|
|
314
|
+
"app.kubernetes.io/name": baseName,
|
|
315
|
+
...news.labels,
|
|
316
|
+
};
|
|
317
|
+
const containerEnv = {
|
|
318
|
+
...bindingEnv,
|
|
319
|
+
...identity?.env,
|
|
320
|
+
...alchemyEnv,
|
|
321
|
+
...news.env,
|
|
322
|
+
};
|
|
323
|
+
const serviceAccountObject = {
|
|
324
|
+
apiVersion: "v1",
|
|
325
|
+
kind: "ServiceAccount",
|
|
326
|
+
metadata: {
|
|
327
|
+
name: serviceAccountName,
|
|
328
|
+
namespace,
|
|
329
|
+
labels,
|
|
330
|
+
...(identity?.serviceAccountAnnotations
|
|
331
|
+
? { annotations: identity.serviceAccountAnnotations }
|
|
332
|
+
: {}),
|
|
333
|
+
},
|
|
334
|
+
};
|
|
335
|
+
const podTemplate = deepMerge({
|
|
336
|
+
metadata: { labels },
|
|
337
|
+
spec: {
|
|
338
|
+
serviceAccountName,
|
|
339
|
+
restartPolicy: news.restartPolicy ?? "Never",
|
|
340
|
+
containers: [
|
|
341
|
+
{
|
|
342
|
+
name: baseName,
|
|
343
|
+
image: resolved.imageUri,
|
|
344
|
+
command: news.command,
|
|
345
|
+
args: news.args,
|
|
346
|
+
env: Object.entries(containerEnv).map(([name, value]) => ({
|
|
347
|
+
name,
|
|
348
|
+
value: containerEnvValue(value),
|
|
349
|
+
})),
|
|
350
|
+
resources: news.resources,
|
|
351
|
+
},
|
|
352
|
+
],
|
|
353
|
+
},
|
|
354
|
+
}, news.podTemplate);
|
|
355
|
+
const jobSpec = {
|
|
356
|
+
backoffLimit: news.backoffLimit,
|
|
357
|
+
ttlSecondsAfterFinished: news.ttlSecondsAfterFinished,
|
|
358
|
+
template: podTemplate,
|
|
359
|
+
};
|
|
360
|
+
const kind = news.schedule ? "CronJob" : "Job";
|
|
361
|
+
// A Kubernetes Job's pod template is immutable after creation, so
|
|
362
|
+
// one-shot Jobs are content-addressed: the object name embeds a
|
|
363
|
+
// hash of the spec, and a spec change applies a NEW Job (which
|
|
364
|
+
// runs) while `reconcileObjects` deletes the previous one.
|
|
365
|
+
// CronJobs are mutable and keep the stable base name.
|
|
366
|
+
// Kubernetes rejects Job names over 63 characters (the API
|
|
367
|
+
// stamps the name into the batch.kubernetes.io/job-name pod
|
|
368
|
+
// label, and label values cap at 63) — truncate the base so the
|
|
369
|
+
// content-address suffix always fits.
|
|
370
|
+
const jobName = news.schedule
|
|
371
|
+
? baseName.slice(0, 52).replace(/-+$/, "")
|
|
372
|
+
: `${baseName.slice(0, 54).replace(/-+$/, "")}-${(yield* sha256Object(unwrapRedacted(jobSpec))).slice(0, 8)}`;
|
|
373
|
+
const workloadObject = news.schedule
|
|
374
|
+
? {
|
|
375
|
+
apiVersion: "batch/v1",
|
|
376
|
+
kind: "CronJob",
|
|
377
|
+
metadata: { name: jobName, namespace, labels },
|
|
378
|
+
spec: {
|
|
379
|
+
schedule: news.schedule,
|
|
380
|
+
jobTemplate: {
|
|
381
|
+
metadata: { labels },
|
|
382
|
+
spec: jobSpec,
|
|
383
|
+
},
|
|
384
|
+
},
|
|
385
|
+
}
|
|
386
|
+
: {
|
|
387
|
+
apiVersion: "batch/v1",
|
|
388
|
+
kind: "Job",
|
|
389
|
+
metadata: { name: jobName, namespace, labels },
|
|
390
|
+
spec: jobSpec,
|
|
391
|
+
};
|
|
392
|
+
const desiredObjects = [serviceAccountObject, workloadObject];
|
|
393
|
+
const kubernetesObjects = yield* reconcileObjects({
|
|
394
|
+
transport,
|
|
395
|
+
previousObjects: output?.kubernetesObjects ?? [],
|
|
396
|
+
desiredObjects,
|
|
397
|
+
});
|
|
398
|
+
yield* session.note(`Applied Kubernetes ${kind} ${namespace}/${jobName}`);
|
|
399
|
+
return {
|
|
400
|
+
connection,
|
|
401
|
+
namespace,
|
|
402
|
+
kind,
|
|
403
|
+
jobName,
|
|
404
|
+
schedule: news.schedule,
|
|
405
|
+
serviceAccountName,
|
|
406
|
+
imageUri: resolved.imageUri,
|
|
407
|
+
identity: identity?.state,
|
|
408
|
+
registry: resolved.state,
|
|
409
|
+
kubernetesObjects,
|
|
410
|
+
code: { hash: resolved.codeHash },
|
|
411
|
+
};
|
|
412
|
+
}),
|
|
413
|
+
delete: Effect.fn(function* ({ output }) {
|
|
414
|
+
const connection = connectionOfOutput(output);
|
|
415
|
+
if (!connection)
|
|
416
|
+
return;
|
|
417
|
+
const adapter = yield* findClusterAdapter(connection.auth.kind);
|
|
418
|
+
// Skip only a missing cluster, then still clean up adapter-owned
|
|
419
|
+
// cloud resources (image repository, identity role).
|
|
420
|
+
const transport = yield* ifClusterExists(adapter.connect(connection));
|
|
421
|
+
if (transport && (output.kubernetesObjects ?? []).length > 0) {
|
|
422
|
+
yield* deleteObjects({
|
|
423
|
+
transport,
|
|
424
|
+
objects: output.kubernetesObjects ?? [],
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
if (adapter.identity) {
|
|
428
|
+
yield* adapter.identity.delete({
|
|
429
|
+
connection,
|
|
430
|
+
state: output.identity ??
|
|
431
|
+
output,
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
if (adapter.registry) {
|
|
435
|
+
yield* adapter.registry.delete({
|
|
436
|
+
state: output.registry ??
|
|
437
|
+
output,
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
}),
|
|
441
|
+
};
|
|
442
|
+
}));
|
|
443
|
+
//# sourceMappingURL=Job.js.map
|
package/lib/Job.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Job.js","sourceRoot":"","sources":["../src/Job.ts"],"names":[],"mappings":"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"}
|