@intentius/chant-lexicon-k8s 0.41.13 → 0.41.15
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/dist/integrity.json +2 -2
- package/dist/manifest.json +1 -1
- package/dist/op/activities/index.d.ts +4 -3
- package/dist/op/activities/index.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/lint/post-synth/post-synth.test.ts +39 -0
- package/src/op/activities/index.ts +4 -4
- package/dist/op/activities/k3d.d.ts +0 -44
- package/dist/op/activities/k3d.d.ts.map +0 -1
- package/src/op/activities/k3d.test.ts +0 -68
- package/src/op/activities/k3d.ts +0 -96
package/dist/integrity.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"algorithm": "sha256",
|
|
3
3
|
"artifacts": {
|
|
4
|
-
"manifest.json": "
|
|
4
|
+
"manifest.json": "de51ffb566f7b4346cfb33021dbca84d7e7d7a3d0c096640dbe1d38f831187ee",
|
|
5
5
|
"meta.json": "c0b141b882c51483c1d1aead748a0eb171aceca7432edd2a0404b062bf6d7831",
|
|
6
6
|
"types/index.d.ts": "3be2af7494aca94adfa16269cb9c4e7a155529872207a3d70b0c4d39914f9eec",
|
|
7
7
|
"rules/argo-appset-single-project.ts": "afa9f310753aa2d475f35012b13135b2dfaebed2a35d44edbe185ebc07673674",
|
|
@@ -50,5 +50,5 @@
|
|
|
50
50
|
"skills/chant-k8s-aks.md": "e18f0e2b055f72cd7a37deaf258d7027c2d4d3e286e8fd4975b27a1f981a3ad9",
|
|
51
51
|
"skills/chant-k8s-argo.md": "b1a0b826559d8c5033a479c5781efaf650320f0aee4419d8841170bd3393cea5"
|
|
52
52
|
},
|
|
53
|
-
"composite": "
|
|
53
|
+
"composite": "2a0b689bdb3e0a2d672e703b751bf91685ee52070385d52fb03c997cc06afb36"
|
|
54
54
|
}
|
package/dist/manifest.json
CHANGED
|
@@ -6,9 +6,12 @@
|
|
|
6
6
|
* #1075, prune chant-owned objects it no longer declares; `applyManifest`
|
|
7
7
|
* is the same work with a report of what it did, which is what the
|
|
8
8
|
* Temporal lexicon's `nativeApply` dispatcher calls for a kubectl target)
|
|
9
|
-
* - k3dUp / k3dDown — boot/tear down a local k3d cluster
|
|
10
9
|
* - waitForArgoSync — block until an Argo CD Application is Healthy && Synced
|
|
11
10
|
*
|
|
11
|
+
* k3dUp / k3dDown moved again, to the k3d lexicon (chant #1410) — a lexicon
|
|
12
|
+
* owns its own product's activities, and k3d is its own product now. Projects
|
|
13
|
+
* using them list `k3d` in `lexicons`; loadActivities(["k3d"]) provides them.
|
|
14
|
+
*
|
|
12
15
|
* The step builders (kubectlApply, k3dUp, k3dDown) stay in core, re-exported from
|
|
13
16
|
* the temporal Op-authoring barrel like the other core builders. Each activity is
|
|
14
17
|
* dependency-light — it shells out to a CLI and does not import the k8s declarable
|
|
@@ -16,8 +19,6 @@
|
|
|
16
19
|
*/
|
|
17
20
|
export { kubectlApply, applyManifest, readManifestDocuments } from "./kubectl.js";
|
|
18
21
|
export type { KubectlApplyArgs, ApplyManifestResult, AppliedRef, ApplyDeleteMode } from "./kubectl.js";
|
|
19
|
-
export { k3dUp, k3dDown, k3dUpCommand, k3dDownCommand, k3dExistsCommand } from "./k3d.js";
|
|
20
|
-
export type { K3dUpArgs, K3dDownArgs } from "./k3d.js";
|
|
21
22
|
export { waitForArgoSync, defaultArgoStatusFetcher, ArgoSyncFailedError } from "./argo.js";
|
|
22
23
|
export type { WaitForArgoSyncArgs, ArgoAppStatus, ArgoStatusFetcher } from "./argo.js";
|
|
23
24
|
export { waitForReady, defaultResourceFetcher, apiResourceFetcher, ReadinessFailedError, readinessFor, isReady, firstTerminal, DEFAULT_READINESS, READINESS_OVERRIDES, } from "./wait-for-ready.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/op/activities/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/op/activities/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAC/E,YAAY,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEpG,OAAO,EAAE,eAAe,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AACxF,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAEpF,OAAO,EACL,YAAY,EACZ,sBAAsB,EACtB,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,EACZ,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,cAAc,EACd,cAAc,EACd,SAAS,GACV,MAAM,kBAAkB,CAAC;AAW1B,OAAO,EAAE,oBAAoB,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AACrG,YAAY,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant-lexicon-k8s",
|
|
3
|
-
"version": "0.41.
|
|
3
|
+
"version": "0.41.15",
|
|
4
4
|
"description": "Kubernetes lexicon for chant — declarative IaC in TypeScript",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://intentius.io/chant",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
},
|
|
85
85
|
"peerDependencies": {
|
|
86
86
|
"zod": "^4.3.6",
|
|
87
|
-
"@intentius/chant": "^0.41.
|
|
87
|
+
"@intentius/chant": "^0.41.15",
|
|
88
88
|
"typescript": "^5.9.3"
|
|
89
89
|
}
|
|
90
90
|
}
|
|
@@ -667,6 +667,45 @@ describe("WK8204: runAsNonRoot", () => {
|
|
|
667
667
|
expect(diags.length).toBe(0);
|
|
668
668
|
});
|
|
669
669
|
|
|
670
|
+
// #1482 — the manifest arrives as real YAML, and the initContainer's args is
|
|
671
|
+
// a block scalar. The parser bug turned `- |` into the string "|" and hoisted
|
|
672
|
+
// every key after it (securityContext, the containers list itself) to the
|
|
673
|
+
// document root, so this check warned on a compliant initContainer and never
|
|
674
|
+
// saw the app container at all.
|
|
675
|
+
test("initContainer with a block-scalar arg keeps its securityContext, and the app container is still checked (#1482)", () => {
|
|
676
|
+
const yaml = [
|
|
677
|
+
"apiVersion: apps/v1",
|
|
678
|
+
"kind: Deployment",
|
|
679
|
+
"metadata:",
|
|
680
|
+
" name: app",
|
|
681
|
+
"spec:",
|
|
682
|
+
" template:",
|
|
683
|
+
" spec:",
|
|
684
|
+
" initContainers:",
|
|
685
|
+
" - name: wait",
|
|
686
|
+
" image: pg:16",
|
|
687
|
+
" args:",
|
|
688
|
+
" - |",
|
|
689
|
+
" set -eu",
|
|
690
|
+
" echo ready",
|
|
691
|
+
" securityContext:",
|
|
692
|
+
" runAsNonRoot: true",
|
|
693
|
+
" runAsUser: 1001",
|
|
694
|
+
" containers:",
|
|
695
|
+
" - name: app",
|
|
696
|
+
" image: app:1.0",
|
|
697
|
+
" securityContext: {}",
|
|
698
|
+
"",
|
|
699
|
+
].join("\n");
|
|
700
|
+
const ctx = makeCtx(yaml);
|
|
701
|
+
const diags = wk8204.check(ctx);
|
|
702
|
+
// The compliant initContainer produces nothing; the bare app container is
|
|
703
|
+
// the one — and the only one — that warns.
|
|
704
|
+
expect(diags.length).toBe(1);
|
|
705
|
+
expect(diags[0].message).toContain('"app"');
|
|
706
|
+
expect(diags[0].message).not.toContain("wait");
|
|
707
|
+
});
|
|
708
|
+
|
|
670
709
|
test("pod-level runAsUser satisfies container-level runAsNonRoot", () => {
|
|
671
710
|
const ctx = makeCtx(JSON.stringify({
|
|
672
711
|
apiVersion: "apps/v1",
|
|
@@ -6,9 +6,12 @@
|
|
|
6
6
|
* #1075, prune chant-owned objects it no longer declares; `applyManifest`
|
|
7
7
|
* is the same work with a report of what it did, which is what the
|
|
8
8
|
* Temporal lexicon's `nativeApply` dispatcher calls for a kubectl target)
|
|
9
|
-
* - k3dUp / k3dDown — boot/tear down a local k3d cluster
|
|
10
9
|
* - waitForArgoSync — block until an Argo CD Application is Healthy && Synced
|
|
11
10
|
*
|
|
11
|
+
* k3dUp / k3dDown moved again, to the k3d lexicon (chant #1410) — a lexicon
|
|
12
|
+
* owns its own product's activities, and k3d is its own product now. Projects
|
|
13
|
+
* using them list `k3d` in `lexicons`; loadActivities(["k3d"]) provides them.
|
|
14
|
+
*
|
|
12
15
|
* The step builders (kubectlApply, k3dUp, k3dDown) stay in core, re-exported from
|
|
13
16
|
* the temporal Op-authoring barrel like the other core builders. Each activity is
|
|
14
17
|
* dependency-light — it shells out to a CLI and does not import the k8s declarable
|
|
@@ -17,9 +20,6 @@
|
|
|
17
20
|
export { kubectlApply, applyManifest, readManifestDocuments } from "./kubectl";
|
|
18
21
|
export type { KubectlApplyArgs, ApplyManifestResult, AppliedRef, ApplyDeleteMode } from "./kubectl";
|
|
19
22
|
|
|
20
|
-
export { k3dUp, k3dDown, k3dUpCommand, k3dDownCommand, k3dExistsCommand } from "./k3d";
|
|
21
|
-
export type { K3dUpArgs, K3dDownArgs } from "./k3d";
|
|
22
|
-
|
|
23
23
|
export { waitForArgoSync, defaultArgoStatusFetcher, ArgoSyncFailedError } from "./argo";
|
|
24
24
|
export type { WaitForArgoSyncArgs, ArgoAppStatus, ArgoStatusFetcher } from "./argo";
|
|
25
25
|
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
export interface K3dUpArgs {
|
|
2
|
-
/** Cluster name (`k3d cluster create <name>`). */
|
|
3
|
-
name: string;
|
|
4
|
-
/** Number of server (control-plane) nodes. */
|
|
5
|
-
servers?: number;
|
|
6
|
-
/** Number of agent (worker) nodes. */
|
|
7
|
-
agents?: number;
|
|
8
|
-
/** k3s image, e.g. `rancher/k3s:v1.31.4-k3s1`. */
|
|
9
|
-
image?: string;
|
|
10
|
-
/** Port mappings, e.g. `["8080:80@loadbalancer"]`. */
|
|
11
|
-
ports?: string[];
|
|
12
|
-
/** Create a managed local registry with this name (`--registry-create`). */
|
|
13
|
-
registryCreate?: string;
|
|
14
|
-
/** Path to a k3d config file (`--config`). */
|
|
15
|
-
configFile?: string;
|
|
16
|
-
/** Readiness timeout for `--wait`. Default: `120s`. */
|
|
17
|
-
timeout?: string;
|
|
18
|
-
}
|
|
19
|
-
export interface K3dDownArgs {
|
|
20
|
-
/** Cluster name to delete. */
|
|
21
|
-
name: string;
|
|
22
|
-
}
|
|
23
|
-
/** `k3d cluster list <name> --no-headers` — non-empty stdout means the cluster exists. */
|
|
24
|
-
export declare function k3dExistsCommand(name: string): string;
|
|
25
|
-
/**
|
|
26
|
-
* Build the `k3d cluster create` command. k3d merges the new cluster into the
|
|
27
|
-
* default kubeconfig and switches context by default, so no extra flags are
|
|
28
|
-
* needed for the manifests to be `kubectl apply`-able afterward.
|
|
29
|
-
*/
|
|
30
|
-
export declare function k3dUpCommand(args: K3dUpArgs): string;
|
|
31
|
-
/** Build the `k3d cluster delete` command. */
|
|
32
|
-
export declare function k3dDownCommand(args: K3dDownArgs): string;
|
|
33
|
-
/**
|
|
34
|
-
* Create a local k3d cluster (vanilla Kubernetes in Docker). Idempotent: if a
|
|
35
|
-
* cluster of the same name already exists it is left as-is. Uses longInfra
|
|
36
|
-
* profile — 20m timeout, heartbeat every 15s (creation may pull the k3s image).
|
|
37
|
-
*/
|
|
38
|
-
export declare function k3dUp(args: K3dUpArgs, signal?: AbortSignal): Promise<void>;
|
|
39
|
-
/**
|
|
40
|
-
* Delete a local k3d cluster. Uses fastIdempotent profile — 5m timeout.
|
|
41
|
-
* `k3d cluster delete` is a no-op success when the cluster is already gone.
|
|
42
|
-
*/
|
|
43
|
-
export declare function k3dDown(args: K3dDownArgs, signal?: AbortSignal): Promise<void>;
|
|
44
|
-
//# sourceMappingURL=k3d.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"k3d.d.ts","sourceRoot":"","sources":["../../../src/op/activities/k3d.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,SAAS;IACxB,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,4EAA4E;IAC5E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,0FAA0F;AAC1F,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAWpD;AAED,8CAA8C;AAC9C,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAExD;AAED;;;;GAIG;AACH,wBAAsB,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBhF;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAIpF"}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect } from "vitest";
|
|
2
|
-
import { k3dUpCommand, k3dDownCommand, k3dExistsCommand } from "./k3d";
|
|
3
|
-
|
|
4
|
-
describe("k3dUpCommand (#704)", () => {
|
|
5
|
-
test("minimal — name only, defaults to --wait with a 120s timeout", () => {
|
|
6
|
-
const cmd = k3dUpCommand({ name: "chant-local" });
|
|
7
|
-
expect(cmd).toBe("k3d cluster create chant-local --wait --timeout 120s");
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
test("servers/agents/image flags", () => {
|
|
11
|
-
const cmd = k3dUpCommand({
|
|
12
|
-
name: "dev",
|
|
13
|
-
servers: 1,
|
|
14
|
-
agents: 2,
|
|
15
|
-
image: "rancher/k3s:v1.31.4-k3s1",
|
|
16
|
-
});
|
|
17
|
-
expect(cmd).toContain("--servers 1");
|
|
18
|
-
expect(cmd).toContain("--agents 2");
|
|
19
|
-
expect(cmd).toContain("--image rancher/k3s:v1.31.4-k3s1");
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
test("each port becomes a quoted -p flag", () => {
|
|
23
|
-
const cmd = k3dUpCommand({
|
|
24
|
-
name: "dev",
|
|
25
|
-
ports: ["8080:80@loadbalancer", "8443:443@loadbalancer"],
|
|
26
|
-
});
|
|
27
|
-
expect(cmd).toContain('-p "8080:80@loadbalancer"');
|
|
28
|
-
expect(cmd).toContain('-p "8443:443@loadbalancer"');
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
test("registry and config file", () => {
|
|
32
|
-
const cmd = k3dUpCommand({
|
|
33
|
-
name: "dev",
|
|
34
|
-
registryCreate: "chant-registry",
|
|
35
|
-
configFile: "k3d.yaml",
|
|
36
|
-
});
|
|
37
|
-
expect(cmd).toContain("--registry-create chant-registry");
|
|
38
|
-
expect(cmd).toContain("--config k3d.yaml");
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
test("custom timeout overrides the default", () => {
|
|
42
|
-
const cmd = k3dUpCommand({ name: "dev", timeout: "300s" });
|
|
43
|
-
expect(cmd).toContain("--timeout 300s");
|
|
44
|
-
expect(cmd).not.toContain("120s");
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
test("zero servers is emitted (not dropped as falsy)", () => {
|
|
48
|
-
// servers: 0 is unusual but must round-trip — guarded by `!== undefined`.
|
|
49
|
-
const cmd = k3dUpCommand({ name: "dev", servers: 0 });
|
|
50
|
-
expect(cmd).toContain("--servers 0");
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
describe("k3dDownCommand (#704)", () => {
|
|
55
|
-
test("deletes the named cluster", () => {
|
|
56
|
-
expect(k3dDownCommand({ name: "chant-local" })).toBe(
|
|
57
|
-
"k3d cluster delete chant-local",
|
|
58
|
-
);
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
describe("k3dExistsCommand (#704)", () => {
|
|
63
|
-
test("lists a single cluster with no headers for an emptiness check", () => {
|
|
64
|
-
expect(k3dExistsCommand("chant-local")).toBe(
|
|
65
|
-
"k3d cluster list chant-local --no-headers",
|
|
66
|
-
);
|
|
67
|
-
});
|
|
68
|
-
});
|
package/src/op/activities/k3d.ts
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { exec } from "node:child_process";
|
|
2
|
-
import { promisify } from "node:util";
|
|
3
|
-
import { safeHeartbeat } from "@intentius/chant/op";
|
|
4
|
-
|
|
5
|
-
const execAsync = promisify(exec);
|
|
6
|
-
|
|
7
|
-
export interface K3dUpArgs {
|
|
8
|
-
/** Cluster name (`k3d cluster create <name>`). */
|
|
9
|
-
name: string;
|
|
10
|
-
/** Number of server (control-plane) nodes. */
|
|
11
|
-
servers?: number;
|
|
12
|
-
/** Number of agent (worker) nodes. */
|
|
13
|
-
agents?: number;
|
|
14
|
-
/** k3s image, e.g. `rancher/k3s:v1.31.4-k3s1`. */
|
|
15
|
-
image?: string;
|
|
16
|
-
/** Port mappings, e.g. `["8080:80@loadbalancer"]`. */
|
|
17
|
-
ports?: string[];
|
|
18
|
-
/** Create a managed local registry with this name (`--registry-create`). */
|
|
19
|
-
registryCreate?: string;
|
|
20
|
-
/** Path to a k3d config file (`--config`). */
|
|
21
|
-
configFile?: string;
|
|
22
|
-
/** Readiness timeout for `--wait`. Default: `120s`. */
|
|
23
|
-
timeout?: string;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface K3dDownArgs {
|
|
27
|
-
/** Cluster name to delete. */
|
|
28
|
-
name: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** `k3d cluster list <name> --no-headers` — non-empty stdout means the cluster exists. */
|
|
32
|
-
export function k3dExistsCommand(name: string): string {
|
|
33
|
-
return `k3d cluster list ${name} --no-headers`;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Build the `k3d cluster create` command. k3d merges the new cluster into the
|
|
38
|
-
* default kubeconfig and switches context by default, so no extra flags are
|
|
39
|
-
* needed for the manifests to be `kubectl apply`-able afterward.
|
|
40
|
-
*/
|
|
41
|
-
export function k3dUpCommand(args: K3dUpArgs): string {
|
|
42
|
-
const parts = ["k3d", "cluster", "create", args.name];
|
|
43
|
-
if (args.servers !== undefined) parts.push(`--servers ${args.servers}`);
|
|
44
|
-
if (args.agents !== undefined) parts.push(`--agents ${args.agents}`);
|
|
45
|
-
if (args.image) parts.push(`--image ${args.image}`);
|
|
46
|
-
for (const p of args.ports ?? []) parts.push(`-p "${p}"`);
|
|
47
|
-
if (args.registryCreate) parts.push(`--registry-create ${args.registryCreate}`);
|
|
48
|
-
if (args.configFile) parts.push(`--config ${args.configFile}`);
|
|
49
|
-
parts.push("--wait");
|
|
50
|
-
parts.push(`--timeout ${args.timeout ?? "120s"}`);
|
|
51
|
-
return parts.join(" ");
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/** Build the `k3d cluster delete` command. */
|
|
55
|
-
export function k3dDownCommand(args: K3dDownArgs): string {
|
|
56
|
-
return `k3d cluster delete ${args.name}`;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Create a local k3d cluster (vanilla Kubernetes in Docker). Idempotent: if a
|
|
61
|
-
* cluster of the same name already exists it is left as-is. Uses longInfra
|
|
62
|
-
* profile — 20m timeout, heartbeat every 15s (creation may pull the k3s image).
|
|
63
|
-
*/
|
|
64
|
-
export async function k3dUp(args: K3dUpArgs, signal?: AbortSignal): Promise<void> {
|
|
65
|
-
try {
|
|
66
|
-
const { stdout } = await execAsync(k3dExistsCommand(args.name), { signal });
|
|
67
|
-
if (stdout.trim()) {
|
|
68
|
-
console.log(`k3d cluster "${args.name}" already exists — skipping create`);
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
} catch {
|
|
72
|
-
// `cluster list` errors when the cluster is absent — fall through to create.
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const heartbeatInterval = setInterval(() => {
|
|
76
|
-
safeHeartbeat({ step: "k3d cluster create", cluster: args.name });
|
|
77
|
-
}, 15_000);
|
|
78
|
-
|
|
79
|
-
try {
|
|
80
|
-
const { stdout, stderr } = await execAsync(k3dUpCommand(args), { signal });
|
|
81
|
-
if (stdout) console.log(stdout);
|
|
82
|
-
if (stderr) console.error(stderr);
|
|
83
|
-
} finally {
|
|
84
|
-
clearInterval(heartbeatInterval);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Delete a local k3d cluster. Uses fastIdempotent profile — 5m timeout.
|
|
90
|
-
* `k3d cluster delete` is a no-op success when the cluster is already gone.
|
|
91
|
-
*/
|
|
92
|
-
export async function k3dDown(args: K3dDownArgs, signal?: AbortSignal): Promise<void> {
|
|
93
|
-
const { stdout, stderr } = await execAsync(k3dDownCommand(args), { signal });
|
|
94
|
-
if (stdout) console.log(stdout);
|
|
95
|
-
if (stderr) console.error(stderr);
|
|
96
|
-
}
|