@specific.dev/spectest 0.120.1 → 0.121.0
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/components/k3s-nodes.d.ts +5 -0
- package/dist/components/k3s-nodes.js +37 -0
- package/dist/components/k3s.d.ts +7 -41
- package/dist/components/k3s.js +260 -215
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -3
- package/package.json +1 -1
- package/src/components/k3s-concurrency.test.ts +76 -3
- package/src/components/k3s-docker.test.ts +140 -0
- package/src/components/k3s-nodes.test.ts +73 -0
- package/src/components/k3s-nodes.ts +35 -0
- package/src/components/k3s-registry.test.ts +13 -8
- package/src/components/k3s.ts +268 -223
- package/src/index.ts +11 -4
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { SpectestContext } from "../index.js";
|
|
2
|
+
/** /readyz only checks the API server. Check the expected identities, not just
|
|
3
|
+
* a count: an unregistered agent must not be hidden by an unrelated node.
|
|
4
|
+
* This runs alongside image imports and infrastructure rollouts. */
|
|
5
|
+
export declare function waitForK3sNodes(server: string, names: readonly string[], exec: SpectestContext["exec"], timeoutMs: number): Promise<void>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** /readyz only checks the API server. Check the expected identities, not just
|
|
2
|
+
* a count: an unregistered agent must not be hidden by an unrelated node.
|
|
3
|
+
* This runs alongside image imports and infrastructure rollouts. */
|
|
4
|
+
export async function waitForK3sNodes(server, names, exec, timeoutMs) {
|
|
5
|
+
const deadline = Date.now() + timeoutMs;
|
|
6
|
+
let detail = "no nodes registered";
|
|
7
|
+
for (;;) {
|
|
8
|
+
const result = await exec(server, ["kubectl", "get", "nodes", "-o", "json", "--request-timeout=5s"], { timeoutMs: 10_000 });
|
|
9
|
+
if (result.exitCode === 0) {
|
|
10
|
+
const nodes = JSON.parse(result.stdout).items;
|
|
11
|
+
const pending = names.flatMap(name => {
|
|
12
|
+
const node = nodes.find(node => node.metadata?.name === name);
|
|
13
|
+
const ready = node?.status?.conditions?.find(condition => condition.type === "Ready");
|
|
14
|
+
return ready?.status === "True" ? [] : [`${name}: ${node ? ready?.message || `Ready=${ready?.status ?? "Unknown"}` : "not registered"}`];
|
|
15
|
+
});
|
|
16
|
+
if (!pending.length)
|
|
17
|
+
return;
|
|
18
|
+
detail = pending.join("; ");
|
|
19
|
+
}
|
|
20
|
+
else
|
|
21
|
+
detail = result.stderr || result.stdout;
|
|
22
|
+
if (Date.now() >= deadline) {
|
|
23
|
+
// Agent startup errors otherwise look like a missing Kubernetes Node.
|
|
24
|
+
const diagnostics = await Promise.all(names.map(async (name) => {
|
|
25
|
+
try {
|
|
26
|
+
const result = await exec(name, ["sh", "-c", "test -S /run/k3s/containerd/containerd.sock"], { timeoutMs: 5_000 });
|
|
27
|
+
return `${name}: ${result.exitCode === 0 ? "containerd socket present" : result.stderr || "containerd socket missing"}`;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
return `${name}: ${String(error)}`;
|
|
31
|
+
}
|
|
32
|
+
}));
|
|
33
|
+
throw new Error(`k3s(${server}): nodes did not become Ready within ${timeoutMs / 1000}s: ${detail}\n${diagnostics.join("\n")}`);
|
|
34
|
+
}
|
|
35
|
+
await new Promise(resolve => setTimeout(resolve, 250));
|
|
36
|
+
}
|
|
37
|
+
}
|
package/dist/components/k3s.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AppsV1Api, BatchV1Api, CoreV1Api, KubeConfig, PatchStrategy, type KubernetesListObject, type KubernetesObject, type V1DeleteOptions, type V1Job, type V1Status } from "@kubernetes/client-node";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ServiceConfig } from "../index.js";
|
|
3
3
|
import { type KubernetesImage } from "../harness/component-images.js";
|
|
4
4
|
export type { KubernetesImage } from "../harness/component-images.js";
|
|
5
5
|
import type { Wrapped } from "../inspect.js";
|
|
@@ -15,6 +15,9 @@ export interface K3sRegistryOptions {
|
|
|
15
15
|
/** Kubernetes pods receive read-only environment CA mounts during admission.
|
|
16
16
|
* Image bytes and digests stay unchanged; explicit pod trust settings win. */
|
|
17
17
|
export interface K3sOptions {
|
|
18
|
+
/** Total schedulable nodes, including the server node. Defaults to 1.
|
|
19
|
+
* Additional nodes run k3s agents in separate containers inside the same VM. */
|
|
20
|
+
nodes?: number;
|
|
18
21
|
/** Images available to kubelet before project setup. Use registry strings,
|
|
19
22
|
* or Dockerfile builds with a full `reference` matching your manifests. Builds
|
|
20
23
|
* support path/content, context, exclude, target and buildArgs, and run in
|
|
@@ -248,6 +251,8 @@ export interface LogsOptions {
|
|
|
248
251
|
}
|
|
249
252
|
/** Helpers a `k3s(...)` service exposes on `ctx.svc.<name>`. */
|
|
250
253
|
export interface K3sHelpers {
|
|
254
|
+
/** Kubernetes node names, also their Spectest container/service names. */
|
|
255
|
+
nodes: readonly string[];
|
|
251
256
|
/**
|
|
252
257
|
* Fully-loaded `KubeConfig`. The cluster server URL is rewritten to
|
|
253
258
|
* `https://<service-name>.internal:6443`, the auto-assigned DNS name
|
|
@@ -343,43 +348,4 @@ export interface K3sHelpers {
|
|
|
343
348
|
}
|
|
344
349
|
/** @internal Exported for regression tests; not part of the components API. */
|
|
345
350
|
export declare function isTransientApplyError(err: unknown): boolean;
|
|
346
|
-
export declare function k3s(opts?: K3sOptions):
|
|
347
|
-
image: {
|
|
348
|
-
type: "registry";
|
|
349
|
-
reference: string;
|
|
350
|
-
};
|
|
351
|
-
imageBuilds: import("../index.js").ComponentImageBuild[];
|
|
352
|
-
tls: {
|
|
353
|
-
hostname: string;
|
|
354
|
-
port: number;
|
|
355
|
-
}[];
|
|
356
|
-
command: string;
|
|
357
|
-
privileged: true;
|
|
358
|
-
tmpfs: string[];
|
|
359
|
-
cgroupns: string;
|
|
360
|
-
ports: number[];
|
|
361
|
-
volumes: ({
|
|
362
|
-
source: string;
|
|
363
|
-
target: string;
|
|
364
|
-
readOnly?: undefined;
|
|
365
|
-
} | {
|
|
366
|
-
target: string;
|
|
367
|
-
source?: undefined;
|
|
368
|
-
readOnly?: undefined;
|
|
369
|
-
} | {
|
|
370
|
-
source: string;
|
|
371
|
-
target: string;
|
|
372
|
-
readOnly: boolean;
|
|
373
|
-
})[];
|
|
374
|
-
files: {
|
|
375
|
-
path: string;
|
|
376
|
-
content: string;
|
|
377
|
-
}[];
|
|
378
|
-
readyCheck: {
|
|
379
|
-
type: "exec";
|
|
380
|
-
command: string;
|
|
381
|
-
timeoutSecs: number;
|
|
382
|
-
};
|
|
383
|
-
setup: (ctx: ServiceSetupContext<K3sHelpers>) => Promise<void>;
|
|
384
|
-
helpers: ({ name, exec, poll }: ServiceHelpersContext) => Promise<K3sHelpers>;
|
|
385
|
-
};
|
|
351
|
+
export declare function k3s(opts?: K3sOptions): import("../index.js").ServiceGroup<Record<string, ServiceConfig>, K3sHelpers, "server">;
|