@compforge/harness-toolbox 0.4.3 → 0.4.5
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/README.md +18 -0
- package/dist/chunk-835fssgz.js +37 -0
- package/dist/{chunk-0s27bgga.js → chunk-ae84rzq5.js} +1 -1
- package/dist/{chunk-age65q4n.js → chunk-db4an9td.js} +1 -1
- package/dist/{chunk-ftkrjqkc.js → chunk-dpcge1xt.js} +1 -1
- package/dist/{chunk-grpygk6f.js → chunk-dx6yvj81.js} +2 -2
- package/dist/{chunk-sqbew04a.js → chunk-f3vq900j.js} +2 -2
- package/dist/{chunk-yp6tcw22.js → chunk-f98qrpx1.js} +38 -78
- package/dist/{chunk-8kts470p.js → chunk-g2bac2jd.js} +12 -6
- package/dist/chunk-gm4swndx.js +106 -0
- package/dist/{chunk-shsabpc1.js → chunk-r3rnsvwv.js} +1 -1
- package/dist/{chunk-20kv4wc3.js → chunk-rkt41za2.js} +7 -1
- package/dist/{chunk-8mb6natq.js → chunk-sbt20n84.js} +53 -35
- package/dist/{chunk-h73h2b7y.js → chunk-t4hrnaj0.js} +44 -39
- package/dist/{chunk-kkts16w9.js → chunk-ww11q58v.js} +1 -1
- package/dist/{chunk-4ms037k2.js → chunk-x0yhfg29.js} +2 -2
- package/dist/chunk-z15gwjvg.js +145 -0
- package/dist/connection/acquire.d.ts +34 -0
- package/dist/connection/acquire.js +9 -0
- package/dist/datasource.js +1 -1
- package/dist/errors.d.ts +4 -0
- package/dist/errors.js +3 -1
- package/dist/file/client.js +2 -2
- package/dist/file/index.js +4 -4
- package/dist/file/local.js +3 -3
- package/dist/file/pod.js +3 -3
- package/dist/kubernetes/client.d.ts +4 -0
- package/dist/kubernetes/client.js +6 -6
- package/dist/kubernetes/compute-model.d.ts +115 -0
- package/dist/kubernetes/compute-model.js +0 -0
- package/dist/kubernetes/compute-quantity.d.ts +18 -0
- package/dist/kubernetes/compute-quantity.js +23 -0
- package/dist/kubernetes/compute.d.ts +17 -0
- package/dist/kubernetes/compute.js +211 -0
- package/dist/kubernetes/environment.js +6 -6
- package/dist/kubernetes/exec-transport.js +2 -2
- package/dist/kubernetes/pod-log-datasource.js +1 -1
- package/dist/kubernetes/resource-transport.js +3 -3
- package/dist/kubernetes/resources.js +2 -2
- package/dist/kubernetes/workload.js +2 -2
- package/dist/mysql/client.d.ts +5 -2
- package/dist/mysql/client.js +5 -4
- package/dist/mysql/connection.d.ts +3 -0
- package/dist/mysql/connection.js +4 -2
- package/dist/mysql/index.js +6 -5
- package/dist/mysql/readonly.js +2 -2
- package/dist/opensearch/client.d.ts +3 -1
- package/dist/opensearch/client.js +3 -2
- package/dist/opensearch/index.js +3 -2
- package/dist/redis/client.js +3 -2
- package/dist/redis/index.js +7 -6
- package/dist/s3/datasource.js +1 -1
- package/dist/s3/index.js +1 -1
- package/package.json +4 -1
- package/dist/chunk-136egyff.js +0 -11
|
@@ -5,13 +5,18 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
queryReadonlySession,
|
|
7
7
|
validateQueryLimits
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-db4an9td.js";
|
|
9
9
|
import {
|
|
10
|
+
connectMysql,
|
|
10
11
|
destroyMysqlConnection
|
|
11
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-835fssgz.js";
|
|
13
|
+
import {
|
|
14
|
+
acquireConnection,
|
|
15
|
+
awaitWithSignal
|
|
16
|
+
} from "./chunk-gm4swndx.js";
|
|
12
17
|
import {
|
|
13
18
|
ToolboxError
|
|
14
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-rkt41za2.js";
|
|
15
20
|
import {
|
|
16
21
|
ConcurrencyPool
|
|
17
22
|
} from "./chunk-v3hxvnrc.js";
|
|
@@ -20,7 +25,6 @@ import {
|
|
|
20
25
|
} from "./chunk-h8fwx0k7.js";
|
|
21
26
|
|
|
22
27
|
// src/mysql/client.ts
|
|
23
|
-
import { createConnection } from "mysql2/promise";
|
|
24
28
|
function mysqlOperationError(error, phase) {
|
|
25
29
|
if (!error || typeof error !== "object" || !("code" in error) || error.code !== "PROTOCOL_CONNECTION_LOST")
|
|
26
30
|
return error;
|
|
@@ -37,7 +41,7 @@ class MysqlDatabase {
|
|
|
37
41
|
connect;
|
|
38
42
|
#queries = new ConcurrencyPool(1);
|
|
39
43
|
#connections = new Map;
|
|
40
|
-
constructor(transports, options, connect =
|
|
44
|
+
constructor(transports, options, connect = connectMysql) {
|
|
41
45
|
this.transports = transports;
|
|
42
46
|
this.options = options;
|
|
43
47
|
this.connect = connect;
|
|
@@ -120,39 +124,40 @@ class MysqlDatabase {
|
|
|
120
124
|
return rows;
|
|
121
125
|
});
|
|
122
126
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
127
|
+
#open(target) {
|
|
128
|
+
return acquireConnection(this.transports, {
|
|
129
|
+
name: "MySQL connection",
|
|
130
|
+
...this.options,
|
|
131
|
+
open: async (transport, attempt) => {
|
|
132
|
+
if (transport.kind === "python")
|
|
133
|
+
return { connection: { kind: "python", transport }, transport: transport.name };
|
|
134
|
+
try {
|
|
135
|
+
const endpoint = await transport.connect(target);
|
|
136
|
+
const connection = await this.connect({
|
|
137
|
+
host: endpoint.host,
|
|
138
|
+
port: endpoint.port,
|
|
139
|
+
user: target.user,
|
|
140
|
+
password: target.password,
|
|
141
|
+
database: target.database,
|
|
142
|
+
connectTimeout: attempt.remainingMs(),
|
|
143
|
+
dateStrings: true,
|
|
144
|
+
supportBigNumbers: true,
|
|
145
|
+
bigNumberStrings: true
|
|
146
|
+
}, attempt.signal);
|
|
147
|
+
return {
|
|
148
|
+
connection: { kind: "tcp", connection },
|
|
149
|
+
transport: endpoint.host === target.host && endpoint.port === target.port ? "direct" : transport.name
|
|
150
|
+
};
|
|
151
|
+
} catch (error) {
|
|
152
|
+
throw mysqlOperationError(error, "connect");
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
close: (session) => {
|
|
156
|
+
if (session.kind === "tcp")
|
|
157
|
+
destroyMysqlConnection(session.connection);
|
|
158
|
+
},
|
|
159
|
+
retryReason: (error) => isConnectionNetworkError(error) || error instanceof ToolboxError && error.kind === "connection_lost" ? String(error.code) : undefined
|
|
160
|
+
});
|
|
156
161
|
}
|
|
157
162
|
async queryOne(target, sql, values) {
|
|
158
163
|
return (await this.query(target, sql, values))[0];
|
|
@@ -186,7 +191,7 @@ class MysqlClient {
|
|
|
186
191
|
initialize() {
|
|
187
192
|
this.signal.throwIfAborted();
|
|
188
193
|
return this.#initialization ??= (async () => {
|
|
189
|
-
this.#target = await this.source.resolve();
|
|
194
|
+
this.#target = await awaitWithSignal(this.source.resolve(), this.signal);
|
|
190
195
|
this.signal.throwIfAborted();
|
|
191
196
|
this.#database = new MysqlDatabase(this.source.transports, { ...this.options, signal: this.signal });
|
|
192
197
|
await this.#database.initialize(this.#target);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
resourcePath
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-dpcge1xt.js";
|
|
4
4
|
import {
|
|
5
5
|
clientKey
|
|
6
6
|
} from "./chunk-a9htb6cr.js";
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
KubernetesError,
|
|
9
9
|
ToolboxError,
|
|
10
10
|
kubernetesHttpError
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-rkt41za2.js";
|
|
12
12
|
import {
|
|
13
13
|
ConcurrencyPool
|
|
14
14
|
} from "./chunk-v3hxvnrc.js";
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import {
|
|
2
|
+
KubernetesError
|
|
3
|
+
} from "./chunk-rkt41za2.js";
|
|
4
|
+
|
|
5
|
+
// src/kubernetes/compute-quantity.ts
|
|
6
|
+
function object(value) {
|
|
7
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
8
|
+
}
|
|
9
|
+
function invalid(message) {
|
|
10
|
+
throw new KubernetesError(message, { kind: "invalid_response" });
|
|
11
|
+
}
|
|
12
|
+
function requiredString(value, field) {
|
|
13
|
+
if (typeof value !== "string" || !value)
|
|
14
|
+
return invalid(`Kubernetes response lacks ${field}`);
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
function parseComputeQuantity(value) {
|
|
18
|
+
if (typeof value !== "string")
|
|
19
|
+
return invalid("Kubernetes quantity must be a string");
|
|
20
|
+
const match = /^([+-]?(?:\d+(?:\.\d*)?|\.\d+))([eE][+-]?\d+|[numkMGTPE]|[KMGTPE]i)?$/.exec(value);
|
|
21
|
+
if (!match)
|
|
22
|
+
return invalid("Invalid Kubernetes quantity");
|
|
23
|
+
const suffix = match[2] ?? "";
|
|
24
|
+
const factors = {
|
|
25
|
+
"": 1,
|
|
26
|
+
n: 0.000000001,
|
|
27
|
+
u: 0.000001,
|
|
28
|
+
m: 0.001,
|
|
29
|
+
k: 1000,
|
|
30
|
+
M: 1e6,
|
|
31
|
+
G: 1e9,
|
|
32
|
+
T: 1000000000000,
|
|
33
|
+
P: 1000000000000000,
|
|
34
|
+
E: 1000000000000000000,
|
|
35
|
+
Ki: 2 ** 10,
|
|
36
|
+
Mi: 2 ** 20,
|
|
37
|
+
Gi: 2 ** 30,
|
|
38
|
+
Ti: 2 ** 40,
|
|
39
|
+
Pi: 2 ** 50,
|
|
40
|
+
Ei: 2 ** 60
|
|
41
|
+
};
|
|
42
|
+
const result = Number(match[1]) * (/^[eE][+-]?\d+$/.test(suffix) ? 10 ** Number(suffix.slice(1)) : factors[suffix]);
|
|
43
|
+
if (!Number.isFinite(result) || result < 0 || result > Number.MAX_SAFE_INTEGER) {
|
|
44
|
+
return invalid("Kubernetes quantity is outside the supported numeric range");
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
var zero = () => ({ cpu: 0, memory: 0 });
|
|
49
|
+
function add(left, right) {
|
|
50
|
+
return { cpu: left.cpu + right.cpu, memory: left.memory + right.memory };
|
|
51
|
+
}
|
|
52
|
+
function max(left, right) {
|
|
53
|
+
return { cpu: Math.max(left.cpu, right.cpu), memory: Math.max(left.memory, right.memory) };
|
|
54
|
+
}
|
|
55
|
+
function quantities(value, required = false) {
|
|
56
|
+
const input = object(value);
|
|
57
|
+
return {
|
|
58
|
+
cpu: input.cpu === undefined && !required ? 0 : parseComputeQuantity(input.cpu),
|
|
59
|
+
memory: input.memory === undefined && !required ? 0 : parseComputeQuantity(input.memory)
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function sum(values) {
|
|
63
|
+
return values.reduce(add, zero());
|
|
64
|
+
}
|
|
65
|
+
function containers(value) {
|
|
66
|
+
if (!Array.isArray(value))
|
|
67
|
+
return invalid("Pod response lacks containers");
|
|
68
|
+
return value.map((item) => {
|
|
69
|
+
const container = object(item);
|
|
70
|
+
requiredString(container.name, "container.name");
|
|
71
|
+
return container;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function podCompute(value) {
|
|
75
|
+
const meta = object(value.metadata), spec = object(value.spec), status = object(value.status);
|
|
76
|
+
const app = containers(spec.containers);
|
|
77
|
+
if (!app.length)
|
|
78
|
+
return invalid("Pod must contain an application container");
|
|
79
|
+
const init = containers(spec.initContainers ?? []);
|
|
80
|
+
const effective = (field) => {
|
|
81
|
+
let steady = sum(app.map((c) => quantities(object(c.resources)[field])));
|
|
82
|
+
let sidecars = zero(), peak = zero();
|
|
83
|
+
for (const container of init) {
|
|
84
|
+
const current = quantities(object(container.resources)[field]);
|
|
85
|
+
if (container.restartPolicy === "Always") {
|
|
86
|
+
sidecars = add(sidecars, current);
|
|
87
|
+
steady = add(steady, current);
|
|
88
|
+
peak = max(peak, sidecars);
|
|
89
|
+
} else
|
|
90
|
+
peak = max(peak, add(sidecars, current));
|
|
91
|
+
}
|
|
92
|
+
const result = max(steady, peak);
|
|
93
|
+
const podLevel = object(object(spec.resources)[field]);
|
|
94
|
+
const overhead = quantities(spec.overhead);
|
|
95
|
+
for (const key of ["cpu", "memory"]) {
|
|
96
|
+
if (podLevel[key] !== undefined)
|
|
97
|
+
result[key] = parseComputeQuantity(podLevel[key]);
|
|
98
|
+
if (field === "requests" || result[key] > 0)
|
|
99
|
+
result[key] += overhead[key];
|
|
100
|
+
}
|
|
101
|
+
return result;
|
|
102
|
+
};
|
|
103
|
+
const without = zero();
|
|
104
|
+
for (const container of [...app, ...init]) {
|
|
105
|
+
const limits = object(object(container.resources).limits);
|
|
106
|
+
for (const key of ["cpu", "memory"])
|
|
107
|
+
if (limits[key] === undefined)
|
|
108
|
+
without[key]++;
|
|
109
|
+
}
|
|
110
|
+
const conditions = Array.isArray(status.conditions) ? status.conditions.map(object) : [];
|
|
111
|
+
const states = [
|
|
112
|
+
...Array.isArray(status.containerStatuses) ? status.containerStatuses : [],
|
|
113
|
+
...Array.isArray(status.initContainerStatuses) ? status.initContainerStatuses : []
|
|
114
|
+
].map(object);
|
|
115
|
+
return {
|
|
116
|
+
namespace: requiredString(meta.namespace, "metadata.namespace"),
|
|
117
|
+
name: requiredString(meta.name, "metadata.name"),
|
|
118
|
+
uid: requiredString(meta.uid, "metadata.uid"),
|
|
119
|
+
createdAt: typeof meta.creationTimestamp === "string" ? meta.creationTimestamp : undefined,
|
|
120
|
+
node: typeof spec.nodeName === "string" && spec.nodeName ? spec.nodeName : undefined,
|
|
121
|
+
phase: requiredString(status.phase, "status.phase"),
|
|
122
|
+
ready: conditions.some((c) => c.type === "Ready" && c.status === "True"),
|
|
123
|
+
restarts: states.reduce((n, c) => n + (typeof c.restartCount === "number" ? c.restartCount : 0), 0),
|
|
124
|
+
containers: [...app, ...init.filter((c) => c.restartPolicy === "Always")].map((c) => String(c.name)),
|
|
125
|
+
requests: effective("requests"),
|
|
126
|
+
configuredLimits: effective("limits"),
|
|
127
|
+
containersWithoutLimits: without
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function summarizePods(pods) {
|
|
131
|
+
const active = pods.filter((p) => p.phase !== "Succeeded" && p.phase !== "Failed");
|
|
132
|
+
const scheduled = active.filter((p) => p.node);
|
|
133
|
+
return {
|
|
134
|
+
pods: pods.length,
|
|
135
|
+
activePods: active.length,
|
|
136
|
+
scheduledPods: scheduled.length,
|
|
137
|
+
readyPods: active.filter((p) => p.ready).length,
|
|
138
|
+
requests: sum(active.map((p) => p.requests)),
|
|
139
|
+
scheduledRequests: sum(scheduled.map((p) => p.requests)),
|
|
140
|
+
configuredLimits: sum(active.map((p) => p.configuredLimits)),
|
|
141
|
+
containersWithoutLimits: sum(active.map((p) => p.containersWithoutLimits))
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export { object, requiredString, parseComputeQuantity, zero, add, quantities, sum, podCompute, summarizePods };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ClientLifecycle } from "../datasource";
|
|
2
|
+
/** Stop waiting without leaving rejected preparation promises unobserved. */
|
|
3
|
+
export declare function awaitWithSignal<T>(pending: Promise<T>, signal: AbortSignal, cancel?: () => void): Promise<T>;
|
|
4
|
+
export interface ConnectionAttempt {
|
|
5
|
+
readonly signal: AbortSignal;
|
|
6
|
+
/** Remaining mapping + handshake budget, not a fresh timeout for each phase. */
|
|
7
|
+
remainingMs(): number;
|
|
8
|
+
}
|
|
9
|
+
interface Acquisition<R, C> {
|
|
10
|
+
name: string;
|
|
11
|
+
connectTimeoutMs: number;
|
|
12
|
+
acquireTimeoutMs?: number;
|
|
13
|
+
signal?: AbortSignal;
|
|
14
|
+
open(route: R, attempt: ConnectionAttempt): Promise<{
|
|
15
|
+
connection: C;
|
|
16
|
+
transport: string;
|
|
17
|
+
}>;
|
|
18
|
+
close(connection: C): void | Promise<void>;
|
|
19
|
+
/** Undefined means terminal; authentication and protocol errors must not change route. */
|
|
20
|
+
retryReason(error: unknown): string | undefined;
|
|
21
|
+
onRoute?: ClientLifecycle["onRoute"];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* @spec One acquisition owns ordered attempts and a deadline covering mapping and handshake.
|
|
25
|
+
* @spec Cancellation keeps its original reason; a late successful connection is closed, never published.
|
|
26
|
+
* @rule Only connection preparation enters this function. Commands and queries must never be replayed.
|
|
27
|
+
* @why Protocol adapters own partial handles and error classification; all protocols share the same lifecycle.
|
|
28
|
+
* @see {@link component://docs/toolbox.md}
|
|
29
|
+
* @case id=connection_mapping_cancel,desc=`Cancel while mapping a route`,expect=`Acquisition exits without a late handshake`
|
|
30
|
+
*/
|
|
31
|
+
export declare function acquireConnection<R extends {
|
|
32
|
+
readonly name: string;
|
|
33
|
+
}, C>(routes: readonly R[], options: Acquisition<R, C>): Promise<C>;
|
|
34
|
+
export {};
|
package/dist/datasource.js
CHANGED
package/dist/errors.d.ts
CHANGED
|
@@ -13,6 +13,10 @@ export declare class KubernetesError extends ToolboxError {
|
|
|
13
13
|
}
|
|
14
14
|
export declare class FileError extends ToolboxError {
|
|
15
15
|
}
|
|
16
|
+
/** A local deadline expiry, distinct from a connection failure reported by a driver. */
|
|
17
|
+
export declare class TimeoutError extends ToolboxError {
|
|
18
|
+
constructor(message: string, options?: ErrorOptions);
|
|
19
|
+
}
|
|
16
20
|
export declare function kubernetesHttpError(status: number): KubernetesError;
|
|
17
21
|
/**
|
|
18
22
|
* Normalize a failed kubectl resource request at the transport boundary.
|
package/dist/errors.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
FileError,
|
|
3
3
|
KubernetesError,
|
|
4
|
+
TimeoutError,
|
|
4
5
|
ToolboxError,
|
|
5
6
|
kubernetesCommandError,
|
|
6
7
|
kubernetesHttpError
|
|
7
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-rkt41za2.js";
|
|
8
9
|
export {
|
|
9
10
|
kubernetesHttpError,
|
|
10
11
|
kubernetesCommandError,
|
|
11
12
|
ToolboxError,
|
|
13
|
+
TimeoutError,
|
|
12
14
|
KubernetesError,
|
|
13
15
|
FileError
|
|
14
16
|
};
|
package/dist/file/client.js
CHANGED
package/dist/file/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PodFileClient,
|
|
3
3
|
PodFileDataSource
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-dx6yvj81.js";
|
|
5
5
|
import {
|
|
6
6
|
LocalFileClient,
|
|
7
7
|
LocalFileDataSource
|
|
8
|
-
} from "../chunk-
|
|
9
|
-
import"../chunk-
|
|
8
|
+
} from "../chunk-f3vq900j.js";
|
|
9
|
+
import"../chunk-ww11q58v.js";
|
|
10
10
|
import {
|
|
11
11
|
FileError
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-rkt41za2.js";
|
|
13
13
|
import"../chunk-v3hxvnrc.js";
|
|
14
14
|
|
|
15
15
|
// src/file/index.ts
|
package/dist/file/local.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
LocalFileClient,
|
|
3
3
|
LocalFileDataSource
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import"../chunk-
|
|
6
|
-
import"../chunk-
|
|
4
|
+
} from "../chunk-f3vq900j.js";
|
|
5
|
+
import"../chunk-ww11q58v.js";
|
|
6
|
+
import"../chunk-rkt41za2.js";
|
|
7
7
|
import"../chunk-v3hxvnrc.js";
|
|
8
8
|
export {
|
|
9
9
|
LocalFileDataSource,
|
package/dist/file/pod.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PodFileClient,
|
|
3
3
|
PodFileDataSource
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import"../chunk-
|
|
6
|
-
import"../chunk-
|
|
4
|
+
} from "../chunk-dx6yvj81.js";
|
|
5
|
+
import"../chunk-ww11q58v.js";
|
|
6
|
+
import"../chunk-rkt41za2.js";
|
|
7
7
|
import"../chunk-v3hxvnrc.js";
|
|
8
8
|
export {
|
|
9
9
|
PodFileDataSource,
|
|
@@ -23,6 +23,10 @@ export declare class KubernetesClient implements Client {
|
|
|
23
23
|
*/
|
|
24
24
|
get(ref: ResourceRef, options?: ResourceRequestOptions): Promise<import("./resources").Resource>;
|
|
25
25
|
list(query: ResourceListQuery, options?: ResourceRequestOptions): Promise<import("./resources").ResourceList>;
|
|
26
|
+
/** Explicit root scope for Nodes and all-namespace lists; no default namespace is inserted.
|
|
27
|
+
* @spec This view borrows root transport, cancellation and cleanup just like namespace views.
|
|
28
|
+
*/
|
|
29
|
+
clusterResources(): ResourceAccess;
|
|
26
30
|
inNamespace(namespace: string): NamespaceResources;
|
|
27
31
|
exec(namespace: string, target: ExecTarget, command: string[], options?: RunOptions): Promise<import("./executor").ExecResult>;
|
|
28
32
|
forward(namespace: string, target: KubernetesEndpoint): Promise<import("./service-port-forward").ForwardedEndpoint>;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
KubernetesClient
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import"../chunk-
|
|
5
|
-
import"../chunk-0s27bgga.js";
|
|
3
|
+
} from "../chunk-g2bac2jd.js";
|
|
4
|
+
import"../chunk-ae84rzq5.js";
|
|
6
5
|
import"../chunk-2171tajs.js";
|
|
7
6
|
import"../chunk-j46x7j7c.js";
|
|
8
7
|
import"../chunk-6fnhzhdb.js";
|
|
9
|
-
import"../chunk-
|
|
10
|
-
import"../chunk-
|
|
8
|
+
import"../chunk-x0yhfg29.js";
|
|
9
|
+
import"../chunk-dpcge1xt.js";
|
|
10
|
+
import"../chunk-r3rnsvwv.js";
|
|
11
11
|
import"../chunk-a9htb6cr.js";
|
|
12
|
-
import"../chunk-
|
|
12
|
+
import"../chunk-rkt41za2.js";
|
|
13
13
|
import"../chunk-v3hxvnrc.js";
|
|
14
14
|
import"../chunk-631vce5z.js";
|
|
15
15
|
import"../chunk-hmah9t8e.js";
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { ErrorKind } from "../errors";
|
|
2
|
+
/** CPU cores and bytes; never percentages or unitless Kubernetes quantity strings. */
|
|
3
|
+
export interface ComputeQuantity {
|
|
4
|
+
cpu: number;
|
|
5
|
+
memory: number;
|
|
6
|
+
}
|
|
7
|
+
export interface ComputeIssue {
|
|
8
|
+
source: string;
|
|
9
|
+
kind: ErrorKind;
|
|
10
|
+
message: string;
|
|
11
|
+
code?: string | number;
|
|
12
|
+
}
|
|
13
|
+
export interface ComputeRead<T> {
|
|
14
|
+
status: "complete" | "partial" | "unavailable";
|
|
15
|
+
items: T[];
|
|
16
|
+
issues: ComputeIssue[];
|
|
17
|
+
}
|
|
18
|
+
export interface ComputeUsage extends ComputeQuantity {
|
|
19
|
+
timestamp: string;
|
|
20
|
+
window: string;
|
|
21
|
+
}
|
|
22
|
+
export interface NodeCompute {
|
|
23
|
+
name: string;
|
|
24
|
+
uid: string;
|
|
25
|
+
ready: boolean;
|
|
26
|
+
unschedulable: boolean;
|
|
27
|
+
capacity: ComputeQuantity;
|
|
28
|
+
allocatable: ComputeQuantity;
|
|
29
|
+
}
|
|
30
|
+
export interface PodCompute {
|
|
31
|
+
namespace: string;
|
|
32
|
+
name: string;
|
|
33
|
+
uid: string;
|
|
34
|
+
createdAt?: string;
|
|
35
|
+
node?: string;
|
|
36
|
+
phase: string;
|
|
37
|
+
ready: boolean;
|
|
38
|
+
restarts: number;
|
|
39
|
+
/** Steady-state application and native sidecar container names, for metrics coverage. */
|
|
40
|
+
containers: string[];
|
|
41
|
+
/** Spec-based effective requests, including init/sidecar peak, Pod-level overrides and overhead. */
|
|
42
|
+
requests: ComputeQuantity;
|
|
43
|
+
/** Sum/peak of declared limits, NOT an upper bound when containers have no limit. */
|
|
44
|
+
configuredLimits: ComputeQuantity;
|
|
45
|
+
/** Container counts, not cores/bytes; a Pod-level budget can still apply. */
|
|
46
|
+
containersWithoutLimits: {
|
|
47
|
+
cpu: number;
|
|
48
|
+
memory: number;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export interface NodeComputeUsage extends ComputeUsage {
|
|
52
|
+
name: string;
|
|
53
|
+
}
|
|
54
|
+
export interface PodComputeUsage extends ComputeUsage {
|
|
55
|
+
namespace: string;
|
|
56
|
+
name: string;
|
|
57
|
+
uid: string;
|
|
58
|
+
}
|
|
59
|
+
export interface PodComputeSummary {
|
|
60
|
+
pods: number;
|
|
61
|
+
activePods: number;
|
|
62
|
+
scheduledPods: number;
|
|
63
|
+
readyPods: number;
|
|
64
|
+
/** Active Pods only; unscheduled requests are demand, not allocated node capacity. */
|
|
65
|
+
requests: ComputeQuantity;
|
|
66
|
+
scheduledRequests: ComputeQuantity;
|
|
67
|
+
configuredLimits: ComputeQuantity;
|
|
68
|
+
/** Container counts, not cores/bytes; a Pod-level budget can still apply. */
|
|
69
|
+
containersWithoutLimits: {
|
|
70
|
+
cpu: number;
|
|
71
|
+
memory: number;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export interface ClusterCompute {
|
|
75
|
+
environment: string;
|
|
76
|
+
observedAt: string;
|
|
77
|
+
scope: "cluster";
|
|
78
|
+
nodes: ComputeRead<NodeCompute>;
|
|
79
|
+
pods: ComputeRead<PodCompute>;
|
|
80
|
+
usage: ComputeRead<NodeComputeUsage>;
|
|
81
|
+
/** Totals describe acquired evidence only; consult each read's coverage before claiming cluster totals. */
|
|
82
|
+
summary: {
|
|
83
|
+
capacity?: ComputeQuantity;
|
|
84
|
+
allocatable?: ComputeQuantity;
|
|
85
|
+
pods?: PodComputeSummary;
|
|
86
|
+
usage?: ComputeQuantity;
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
export interface WorkloadCompute {
|
|
90
|
+
environment: string;
|
|
91
|
+
observedAt: string;
|
|
92
|
+
/** Scope is exactly the supplied instance set, not a claim of complete Service discovery. */
|
|
93
|
+
scope: "instances";
|
|
94
|
+
workloads: readonly {
|
|
95
|
+
namespace: string;
|
|
96
|
+
workload: string;
|
|
97
|
+
pod: string;
|
|
98
|
+
uid: string;
|
|
99
|
+
}[];
|
|
100
|
+
pods: ComputeRead<PodCompute>;
|
|
101
|
+
usage: ComputeRead<PodComputeUsage>;
|
|
102
|
+
summary: {
|
|
103
|
+
pods?: PodComputeSummary;
|
|
104
|
+
usage?: ComputeQuantity;
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
export interface ComputeOptions {
|
|
108
|
+
environment: string;
|
|
109
|
+
signal?: AbortSignal;
|
|
110
|
+
/** Whole collection budget, including all pages and metrics reads. */
|
|
111
|
+
timeoutMs: number;
|
|
112
|
+
maxPods: number;
|
|
113
|
+
maxNodes: number;
|
|
114
|
+
pageSize: number;
|
|
115
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ComputeQuantity, PodCompute, PodComputeSummary } from "./compute-model";
|
|
2
|
+
import type { Resource } from "./resources";
|
|
3
|
+
type ObjectValue = Record<string, unknown>;
|
|
4
|
+
export declare function object(value: unknown): ObjectValue;
|
|
5
|
+
export declare function requiredString(value: unknown, field: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* @why client-node 1.4 quantityToScalar uses BigInt for binary suffixes and rejects valid fractional Gi values.
|
|
8
|
+
* @spec Quantities normalize to cores/bytes; invalid or unrepresentable values never become zero usage.
|
|
9
|
+
*/
|
|
10
|
+
export declare function parseComputeQuantity(value: unknown): number;
|
|
11
|
+
export declare const zero: () => ComputeQuantity;
|
|
12
|
+
export declare function add(left: ComputeQuantity, right: ComputeQuantity): ComputeQuantity;
|
|
13
|
+
export declare function quantities(value: unknown, required?: boolean): ComputeQuantity;
|
|
14
|
+
export declare function sum(values: readonly ComputeQuantity[]): ComputeQuantity;
|
|
15
|
+
/** Spec projection only: do not claim current cgroup allocation or scheduler admission headroom. */
|
|
16
|
+
export declare function podCompute(value: Resource): PodCompute;
|
|
17
|
+
export declare function summarizePods(pods: readonly PodCompute[]): PodComputeSummary;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {
|
|
2
|
+
add,
|
|
3
|
+
object,
|
|
4
|
+
parseComputeQuantity,
|
|
5
|
+
podCompute,
|
|
6
|
+
quantities,
|
|
7
|
+
requiredString,
|
|
8
|
+
sum,
|
|
9
|
+
summarizePods,
|
|
10
|
+
zero
|
|
11
|
+
} from "../chunk-z15gwjvg.js";
|
|
12
|
+
import"../chunk-rkt41za2.js";
|
|
13
|
+
export {
|
|
14
|
+
zero,
|
|
15
|
+
summarizePods,
|
|
16
|
+
sum,
|
|
17
|
+
requiredString,
|
|
18
|
+
quantities,
|
|
19
|
+
podCompute,
|
|
20
|
+
parseComputeQuantity,
|
|
21
|
+
object,
|
|
22
|
+
add
|
|
23
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { WorkloadInstance } from "@compforge/harness-common";
|
|
2
|
+
import type { ResourceAccess } from "./resources";
|
|
3
|
+
import type { ClusterCompute, ComputeOptions, WorkloadCompute } from "./compute-model";
|
|
4
|
+
export type * from "./compute-model";
|
|
5
|
+
export { parseComputeQuantity } from "./compute-quantity";
|
|
6
|
+
/**
|
|
7
|
+
* @spec Cluster reads are independent: forbidden Nodes/metrics are coverage gaps, not cluster-health failures.
|
|
8
|
+
* @rule access must be an explicit cluster-scoped view, e.g. KubernetesClient.clusterResources().
|
|
9
|
+
* No namespace fallback, client creation or cleanup occurs here.
|
|
10
|
+
*/
|
|
11
|
+
export declare function collectClusterCompute(access: ResourceAccess, options: ComputeOptions): Promise<ClusterCompute>;
|
|
12
|
+
/**
|
|
13
|
+
* @spec Whole-Pod accounting deduplicates physical UID across Workload aliases and container defaults.
|
|
14
|
+
* @spec Only caller-supplied instances are read; cluster permissions are not needed.
|
|
15
|
+
* @rule The caller retains discovery coverage. This result never asserts that input covers all Service instances.
|
|
16
|
+
*/
|
|
17
|
+
export declare function collectWorkloadCompute(access: ResourceAccess, instances: readonly WorkloadInstance[], options: ComputeOptions): Promise<WorkloadCompute>;
|