@calltelemetry/ct-lab-mcp 0.8.68 → 0.8.70
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 +5 -1
- package/dist/src/appliance/executor.d.ts.map +1 -1
- package/dist/src/appliance/executor.js +3 -172
- package/dist/src/appliance/executor.js.map +1 -1
- package/dist/src/hypervisors/esxi/client.d.ts.map +1 -1
- package/dist/src/hypervisors/esxi/client.js +5 -0
- package/dist/src/hypervisors/esxi/client.js.map +1 -1
- package/dist/src/hypervisors/manager.d.ts +1 -0
- package/dist/src/hypervisors/manager.d.ts.map +1 -1
- package/dist/src/hypervisors/manager.js +5 -2
- package/dist/src/hypervisors/manager.js.map +1 -1
- package/dist/src/proxmox/client.d.ts.map +1 -1
- package/dist/src/proxmox/client.js +17 -0
- package/dist/src/proxmox/client.js.map +1 -1
- package/dist/src/slot/manager.d.ts +12 -2
- package/dist/src/slot/manager.d.ts.map +1 -1
- package/dist/src/slot/manager.js +37 -4
- package/dist/src/slot/manager.js.map +1 -1
- package/dist/src/slot/purge-controller.d.ts +1 -0
- package/dist/src/slot/purge-controller.d.ts.map +1 -1
- package/dist/src/slot/purge-controller.js +4 -33
- package/dist/src/slot/purge-controller.js.map +1 -1
- package/dist/src/tools/appliance-claim-tools.d.ts +11 -7
- package/dist/src/tools/appliance-claim-tools.d.ts.map +1 -1
- package/dist/src/tools/appliance-claim-tools.js +28 -81
- package/dist/src/tools/appliance-claim-tools.js.map +1 -1
- package/dist/src/tools/appliance-exec.d.ts +4 -4
- package/dist/src/tools/claim-creation-projection.d.ts +7 -0
- package/dist/src/tools/claim-creation-projection.d.ts.map +1 -0
- package/dist/src/tools/claim-creation-projection.js +112 -0
- package/dist/src/tools/claim-creation-projection.js.map +1 -0
- package/dist/src/tools/claim-first.d.ts.map +1 -1
- package/dist/src/tools/claim-first.js +19 -15
- package/dist/src/tools/claim-first.js.map +1 -1
- package/dist/src/tools/claimed-import-qcow.d.ts +2 -2
- package/dist/src/tools/find-slot.d.ts +1 -1
- package/dist/src/tools/import-qcow.d.ts +6 -6
- package/dist/src/tools/index.d.ts.map +1 -1
- package/dist/src/tools/index.js +5 -1
- package/dist/src/tools/index.js.map +1 -1
- package/dist/src/tools/legacy-guest-guard.d.ts +4 -0
- package/dist/src/tools/legacy-guest-guard.d.ts.map +1 -0
- package/dist/src/tools/legacy-guest-guard.js +26 -0
- package/dist/src/tools/legacy-guest-guard.js.map +1 -0
- package/dist/src/tools/license-tools.d.ts +2 -2
- package/dist/src/tools/list-hosts.d.ts.map +1 -1
- package/dist/src/tools/list-hosts.js +17 -9
- package/dist/src/tools/list-hosts.js.map +1 -1
- package/dist/src/tools/physical-slot-claim-spec-schema.v1.json +1 -0
- package/dist/src/tools/physical-slot.d.ts +205 -0
- package/dist/src/tools/physical-slot.d.ts.map +1 -0
- package/dist/src/tools/physical-slot.js +295 -0
- package/dist/src/tools/physical-slot.js.map +1 -0
- package/dist/src/tools/provision-tools.d.ts +18 -18
- package/dist/src/tools/sandbox-tools.d.ts +2 -2
- package/dist/src/tools/slot-kubernetes.d.ts +13 -0
- package/dist/src/tools/slot-kubernetes.d.ts.map +1 -0
- package/dist/src/tools/slot-kubernetes.js +108 -0
- package/dist/src/tools/slot-kubernetes.js.map +1 -0
- package/dist/src/tools/slot-tools.d.ts +8 -8
- package/dist/src/tools/vm-action.d.ts +4 -4
- package/dist/src/transports/sse.d.ts.map +1 -1
- package/dist/src/transports/sse.js +61 -30
- package/dist/src/transports/sse.js.map +1 -1
- package/package.json +2 -2
|
@@ -137,8 +137,8 @@ export declare const ProvisionVmInputSchema: z.ZodEffects<z.ZodEffects<z.ZodObje
|
|
|
137
137
|
}, "strip", z.ZodTypeAny, {
|
|
138
138
|
hypervisorType: "proxmox" | "esxi" | "any";
|
|
139
139
|
format: "table" | "json";
|
|
140
|
-
apply: boolean;
|
|
141
140
|
source: "template" | "alma97-cloud" | "alma97-iso";
|
|
141
|
+
apply: boolean;
|
|
142
142
|
recoverIncomplete: boolean;
|
|
143
143
|
finalizeInstalled: boolean;
|
|
144
144
|
startOnDeploy: boolean;
|
|
@@ -165,8 +165,8 @@ export declare const ProvisionVmInputSchema: z.ZodEffects<z.ZodEffects<z.ZodObje
|
|
|
165
165
|
requester?: string | undefined;
|
|
166
166
|
purpose?: string | undefined;
|
|
167
167
|
ttlHours?: number | undefined;
|
|
168
|
-
assetId?: string | undefined;
|
|
169
168
|
hostAssetId?: string | undefined;
|
|
169
|
+
assetId?: string | undefined;
|
|
170
170
|
operationId?: string | undefined;
|
|
171
171
|
networkBridge?: string | undefined;
|
|
172
172
|
templateAssetId?: string | undefined;
|
|
@@ -220,8 +220,9 @@ export declare const ProvisionVmInputSchema: z.ZodEffects<z.ZodEffects<z.ZodObje
|
|
|
220
220
|
requester?: string | undefined;
|
|
221
221
|
purpose?: string | undefined;
|
|
222
222
|
ttlHours?: number | undefined;
|
|
223
|
-
assetId?: string | undefined;
|
|
224
223
|
hostAssetId?: string | undefined;
|
|
224
|
+
source?: "template" | "alma97-cloud" | "alma97-iso" | undefined;
|
|
225
|
+
assetId?: string | undefined;
|
|
225
226
|
operationId?: string | undefined;
|
|
226
227
|
networkBridge?: string | undefined;
|
|
227
228
|
templateAssetId?: string | undefined;
|
|
@@ -232,7 +233,6 @@ export declare const ProvisionVmInputSchema: z.ZodEffects<z.ZodEffects<z.ZodObje
|
|
|
232
233
|
confirmAssetId?: string | undefined;
|
|
233
234
|
targetHost?: string | undefined;
|
|
234
235
|
outputFile?: string | undefined;
|
|
235
|
-
source?: "template" | "alma97-cloud" | "alma97-iso" | undefined;
|
|
236
236
|
webImage?: string | undefined;
|
|
237
237
|
baseVersion?: string | undefined;
|
|
238
238
|
nativeCliDir?: string | undefined;
|
|
@@ -263,8 +263,8 @@ export declare const ProvisionVmInputSchema: z.ZodEffects<z.ZodEffects<z.ZodObje
|
|
|
263
263
|
}>, {
|
|
264
264
|
hypervisorType: "proxmox" | "esxi" | "any";
|
|
265
265
|
format: "table" | "json";
|
|
266
|
-
apply: boolean;
|
|
267
266
|
source: "template" | "alma97-cloud" | "alma97-iso";
|
|
267
|
+
apply: boolean;
|
|
268
268
|
recoverIncomplete: boolean;
|
|
269
269
|
finalizeInstalled: boolean;
|
|
270
270
|
startOnDeploy: boolean;
|
|
@@ -291,8 +291,8 @@ export declare const ProvisionVmInputSchema: z.ZodEffects<z.ZodEffects<z.ZodObje
|
|
|
291
291
|
requester?: string | undefined;
|
|
292
292
|
purpose?: string | undefined;
|
|
293
293
|
ttlHours?: number | undefined;
|
|
294
|
-
assetId?: string | undefined;
|
|
295
294
|
hostAssetId?: string | undefined;
|
|
295
|
+
assetId?: string | undefined;
|
|
296
296
|
operationId?: string | undefined;
|
|
297
297
|
networkBridge?: string | undefined;
|
|
298
298
|
templateAssetId?: string | undefined;
|
|
@@ -346,8 +346,9 @@ export declare const ProvisionVmInputSchema: z.ZodEffects<z.ZodEffects<z.ZodObje
|
|
|
346
346
|
requester?: string | undefined;
|
|
347
347
|
purpose?: string | undefined;
|
|
348
348
|
ttlHours?: number | undefined;
|
|
349
|
-
assetId?: string | undefined;
|
|
350
349
|
hostAssetId?: string | undefined;
|
|
350
|
+
source?: "template" | "alma97-cloud" | "alma97-iso" | undefined;
|
|
351
|
+
assetId?: string | undefined;
|
|
351
352
|
operationId?: string | undefined;
|
|
352
353
|
networkBridge?: string | undefined;
|
|
353
354
|
templateAssetId?: string | undefined;
|
|
@@ -358,7 +359,6 @@ export declare const ProvisionVmInputSchema: z.ZodEffects<z.ZodEffects<z.ZodObje
|
|
|
358
359
|
confirmAssetId?: string | undefined;
|
|
359
360
|
targetHost?: string | undefined;
|
|
360
361
|
outputFile?: string | undefined;
|
|
361
|
-
source?: "template" | "alma97-cloud" | "alma97-iso" | undefined;
|
|
362
362
|
webImage?: string | undefined;
|
|
363
363
|
baseVersion?: string | undefined;
|
|
364
364
|
nativeCliDir?: string | undefined;
|
|
@@ -389,8 +389,8 @@ export declare const ProvisionVmInputSchema: z.ZodEffects<z.ZodEffects<z.ZodObje
|
|
|
389
389
|
}>, {
|
|
390
390
|
hypervisorType: "proxmox" | "esxi" | "any";
|
|
391
391
|
format: "table" | "json";
|
|
392
|
-
apply: boolean;
|
|
393
392
|
source: "template" | "alma97-cloud" | "alma97-iso";
|
|
393
|
+
apply: boolean;
|
|
394
394
|
recoverIncomplete: boolean;
|
|
395
395
|
finalizeInstalled: boolean;
|
|
396
396
|
startOnDeploy: boolean;
|
|
@@ -417,8 +417,8 @@ export declare const ProvisionVmInputSchema: z.ZodEffects<z.ZodEffects<z.ZodObje
|
|
|
417
417
|
requester?: string | undefined;
|
|
418
418
|
purpose?: string | undefined;
|
|
419
419
|
ttlHours?: number | undefined;
|
|
420
|
-
assetId?: string | undefined;
|
|
421
420
|
hostAssetId?: string | undefined;
|
|
421
|
+
assetId?: string | undefined;
|
|
422
422
|
operationId?: string | undefined;
|
|
423
423
|
networkBridge?: string | undefined;
|
|
424
424
|
templateAssetId?: string | undefined;
|
|
@@ -472,8 +472,9 @@ export declare const ProvisionVmInputSchema: z.ZodEffects<z.ZodEffects<z.ZodObje
|
|
|
472
472
|
requester?: string | undefined;
|
|
473
473
|
purpose?: string | undefined;
|
|
474
474
|
ttlHours?: number | undefined;
|
|
475
|
-
assetId?: string | undefined;
|
|
476
475
|
hostAssetId?: string | undefined;
|
|
476
|
+
source?: "template" | "alma97-cloud" | "alma97-iso" | undefined;
|
|
477
|
+
assetId?: string | undefined;
|
|
477
478
|
operationId?: string | undefined;
|
|
478
479
|
networkBridge?: string | undefined;
|
|
479
480
|
templateAssetId?: string | undefined;
|
|
@@ -484,7 +485,6 @@ export declare const ProvisionVmInputSchema: z.ZodEffects<z.ZodEffects<z.ZodObje
|
|
|
484
485
|
confirmAssetId?: string | undefined;
|
|
485
486
|
targetHost?: string | undefined;
|
|
486
487
|
outputFile?: string | undefined;
|
|
487
|
-
source?: "template" | "alma97-cloud" | "alma97-iso" | undefined;
|
|
488
488
|
webImage?: string | undefined;
|
|
489
489
|
baseVersion?: string | undefined;
|
|
490
490
|
nativeCliDir?: string | undefined;
|
|
@@ -653,9 +653,9 @@ export declare const AutoProvisionVmInputSchema: z.ZodObject<{
|
|
|
653
653
|
hypervisorType: "proxmox" | "esxi" | "any";
|
|
654
654
|
ttlMinutes: number;
|
|
655
655
|
format: "table" | "json";
|
|
656
|
+
source: "template" | "alma97-cloud" | "alma97-iso";
|
|
656
657
|
apply: boolean;
|
|
657
658
|
purgeIfFull: boolean;
|
|
658
|
-
source: "template" | "alma97-cloud" | "alma97-iso";
|
|
659
659
|
recoverIncomplete: boolean;
|
|
660
660
|
finalizeInstalled: boolean;
|
|
661
661
|
fullClone: boolean;
|
|
@@ -682,18 +682,18 @@ export declare const AutoProvisionVmInputSchema: z.ZodObject<{
|
|
|
682
682
|
requester?: string | undefined;
|
|
683
683
|
purpose?: string | undefined;
|
|
684
684
|
ttlHours?: number | undefined;
|
|
685
|
-
assetId?: string | undefined;
|
|
686
685
|
hostAssetId?: string | undefined;
|
|
686
|
+
assetId?: string | undefined;
|
|
687
687
|
operationId?: string | undefined;
|
|
688
688
|
networkBridge?: string | undefined;
|
|
689
689
|
templateAssetId?: string | undefined;
|
|
690
690
|
workspaceRoot?: string | undefined;
|
|
691
691
|
importStorage?: string | undefined;
|
|
692
|
+
allowEsxiSlots?: boolean | undefined;
|
|
692
693
|
receiptFile?: string | undefined;
|
|
693
694
|
confirmAssetId?: string | undefined;
|
|
694
695
|
placementSeed?: string | undefined;
|
|
695
696
|
targetHost?: string | undefined;
|
|
696
|
-
allowEsxiSlots?: boolean | undefined;
|
|
697
697
|
outputFile?: string | undefined;
|
|
698
698
|
webImage?: string | undefined;
|
|
699
699
|
baseVersion?: string | undefined;
|
|
@@ -740,22 +740,22 @@ export declare const AutoProvisionVmInputSchema: z.ZodObject<{
|
|
|
740
740
|
requester?: string | undefined;
|
|
741
741
|
purpose?: string | undefined;
|
|
742
742
|
ttlHours?: number | undefined;
|
|
743
|
-
assetId?: string | undefined;
|
|
744
743
|
hostAssetId?: string | undefined;
|
|
744
|
+
source?: "template" | "alma97-cloud" | "alma97-iso" | undefined;
|
|
745
|
+
assetId?: string | undefined;
|
|
745
746
|
operationId?: string | undefined;
|
|
746
747
|
networkBridge?: string | undefined;
|
|
747
748
|
templateAssetId?: string | undefined;
|
|
748
749
|
workspaceRoot?: string | undefined;
|
|
749
750
|
importStorage?: string | undefined;
|
|
751
|
+
allowEsxiSlots?: boolean | undefined;
|
|
750
752
|
apply?: boolean | undefined;
|
|
751
753
|
receiptFile?: string | undefined;
|
|
752
754
|
confirmAssetId?: string | undefined;
|
|
753
755
|
placementSeed?: string | undefined;
|
|
754
756
|
targetHost?: string | undefined;
|
|
755
757
|
purgeIfFull?: boolean | undefined;
|
|
756
|
-
allowEsxiSlots?: boolean | undefined;
|
|
757
758
|
outputFile?: string | undefined;
|
|
758
|
-
source?: "template" | "alma97-cloud" | "alma97-iso" | undefined;
|
|
759
759
|
webImage?: string | undefined;
|
|
760
760
|
baseVersion?: string | undefined;
|
|
761
761
|
nativeCliDir?: string | undefined;
|
|
@@ -162,8 +162,8 @@ export declare const SandboxResetInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
162
162
|
receiptFile: z.ZodOptional<z.ZodString>;
|
|
163
163
|
}, "strip", z.ZodTypeAny, {
|
|
164
164
|
linearIssue: string;
|
|
165
|
-
assetId: string;
|
|
166
165
|
hostAssetId: "proxmox-lab" | "proxmox-mini" | "proxmox-minis-lab";
|
|
166
|
+
assetId: string;
|
|
167
167
|
operationId: string;
|
|
168
168
|
apply: boolean;
|
|
169
169
|
snapshotName: string;
|
|
@@ -186,8 +186,8 @@ export declare const SandboxResetInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
186
186
|
waitAgent?: boolean | undefined;
|
|
187
187
|
}>, {
|
|
188
188
|
linearIssue: string;
|
|
189
|
-
assetId: string;
|
|
190
189
|
hostAssetId: "proxmox-lab" | "proxmox-mini" | "proxmox-minis-lab";
|
|
190
|
+
assetId: string;
|
|
191
191
|
operationId: string;
|
|
192
192
|
apply: boolean;
|
|
193
193
|
snapshotName: string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type SlotMethod = "GET" | "POST" | "PUT" | "DELETE";
|
|
2
|
+
export interface SlotApi {
|
|
3
|
+
request(path: string, method: SlotMethod, body?: unknown): Promise<any | null>;
|
|
4
|
+
}
|
|
5
|
+
export declare class SlotApiError extends Error {
|
|
6
|
+
readonly status: number | null;
|
|
7
|
+
constructor(status: number | null, message: string);
|
|
8
|
+
}
|
|
9
|
+
export declare const SLOT_CONTEXT = "do-nyc1-cluster-ny1";
|
|
10
|
+
export declare const SLOT_SERVER = "https://28a6e4a4-fbff-4b51-a9bd-6073ffd8cdb2.k8s.ondigitalocean.com";
|
|
11
|
+
export declare function assertSlotPath(path: string, method: SlotMethod): void;
|
|
12
|
+
export declare function createSlotApi(): SlotApi;
|
|
13
|
+
//# sourceMappingURL=slot-kubernetes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot-kubernetes.d.ts","sourceRoot":"","sources":["../../../src/tools/slot-kubernetes.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;AAC3D,MAAM,WAAW,OAAO;IAAG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;CAAE;AAC5G,qBAAa,YAAa,SAAQ,KAAK;aACT,MAAM,EAAE,MAAM,GAAG,IAAI;gBAArB,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM;CACnE;AAGD,eAAO,MAAM,YAAY,wBAAwB,CAAC;AAClD,eAAO,MAAM,WAAW,wEAAwE,CAAC;AAGjG,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAUrE;AAmBD,wBAAgB,aAAa,IAAI,OAAO,CAgCvC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/** Fixed namespace transport for physical-slot custody. Never retry an unknown write. */
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import * as fs from "node:fs";
|
|
4
|
+
import { userInfo } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { fetch, Agent } from "undici";
|
|
7
|
+
export class SlotApiError extends Error {
|
|
8
|
+
status;
|
|
9
|
+
constructor(status, message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.status = status;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const TOKEN = "/var/run/secrets/kubernetes.io/serviceaccount/token";
|
|
15
|
+
const CA = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt";
|
|
16
|
+
export const SLOT_CONTEXT = "do-nyc1-cluster-ny1";
|
|
17
|
+
export const SLOT_SERVER = "https://28a6e4a4-fbff-4b51-a9bd-6073ffd8cdb2.k8s.ondigitalocean.com";
|
|
18
|
+
const MAX_BYTES = 1_048_576;
|
|
19
|
+
const COLLECTIONS = ["/apis/coordination.k8s.io/v1/namespaces/ct-lab/leases", "/apis/calltelemetry.com/v1alpha1/namespaces/ct-lab/applianceclaims"];
|
|
20
|
+
export function assertSlotPath(path, method) {
|
|
21
|
+
const cleanPath = path.split("?")[0];
|
|
22
|
+
if (path !== cleanPath && !/^\?limit=500(?:&continue=[A-Za-z0-9%._~-]+)?$/.test(path.slice(cleanPath.length)))
|
|
23
|
+
throw new Error("physical slot query refused");
|
|
24
|
+
const collection = COLLECTIONS.find(p => cleanPath === p || cleanPath.startsWith(p + "/"));
|
|
25
|
+
if (!collection)
|
|
26
|
+
throw new Error("physical slot API path refused");
|
|
27
|
+
const name = cleanPath.slice(collection.length + 1);
|
|
28
|
+
if (cleanPath !== collection && (name.length > 253 || !name.split(".").every(label => /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(label))))
|
|
29
|
+
throw new Error("physical slot object name refused");
|
|
30
|
+
if (method === "POST" && cleanPath !== collection || method !== "POST" && cleanPath === collection && !(method === "GET" && collection === COLLECTIONS[1]))
|
|
31
|
+
throw new Error("physical slot method refused");
|
|
32
|
+
if (collection === COLLECTIONS[0] && method === "DELETE")
|
|
33
|
+
throw new Error("MCP cannot release a durable physical reservation");
|
|
34
|
+
if (collection === COLLECTIONS[1] && method === "PUT")
|
|
35
|
+
throw new Error("physical slot adapter cannot replace a claim");
|
|
36
|
+
}
|
|
37
|
+
function parse(text) {
|
|
38
|
+
if (Buffer.byteLength(text) > MAX_BYTES)
|
|
39
|
+
throw new Error("physical slot response exceeds bound");
|
|
40
|
+
const value = JSON.parse(text);
|
|
41
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
42
|
+
throw new Error("physical slot response is not an object");
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
function kubectl(args, body, env) {
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
const child = execFile("kubectl", args, { env, timeout: 10_000, maxBuffer: MAX_BYTES }, (err, stdout, stderr) => {
|
|
48
|
+
if (err) {
|
|
49
|
+
// kubectl has no machine-readable HTTP code. Only exact NotFound is absence.
|
|
50
|
+
const status = /\(NotFound\)/.test(stderr) ? 404 : /\(AlreadyExists\)|\(Conflict\)/.test(stderr) ? 409 : null;
|
|
51
|
+
reject(new SlotApiError(status, `physical slot Kubernetes request failed (${status ?? "unknown"}); retain custody`));
|
|
52
|
+
}
|
|
53
|
+
else
|
|
54
|
+
resolve(stdout);
|
|
55
|
+
});
|
|
56
|
+
if (body !== undefined)
|
|
57
|
+
child.stdin?.end(JSON.stringify(body));
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
export function createSlotApi() {
|
|
61
|
+
// The selected transport cannot change after a timeout or failed mutation.
|
|
62
|
+
const inCluster = fs.existsSync(TOKEN);
|
|
63
|
+
let localReady;
|
|
64
|
+
const env = { ...process.env };
|
|
65
|
+
for (const key of ["KUBECONFIG", "KUBERNETES_MASTER", "KUBECTL_KUBERC", "HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", "http_proxy", "https_proxy", "all_proxy"])
|
|
66
|
+
delete env[key];
|
|
67
|
+
env.KUBECTL_KUBERC = "false";
|
|
68
|
+
const base = ["--kubeconfig", join(userInfo().homedir, ".kube", "config"), "--context", SLOT_CONTEXT, "--server", SLOT_SERVER, "--insecure-skip-tls-verify=false", "--request-timeout=10s"];
|
|
69
|
+
return { async request(path, method, body) {
|
|
70
|
+
assertSlotPath(path, method);
|
|
71
|
+
if (inCluster) {
|
|
72
|
+
if (!fs.existsSync(CA))
|
|
73
|
+
throw new Error("physical slot Kubernetes CA unavailable");
|
|
74
|
+
const host = process.env.KUBERNETES_SERVICE_HOST || "kubernetes.default.svc";
|
|
75
|
+
const port = process.env.KUBERNETES_SERVICE_PORT || "443";
|
|
76
|
+
if (!/^[a-zA-Z0-9.-]+$/.test(host) || !/^\d{1,5}$/.test(port))
|
|
77
|
+
throw new Error("physical slot Kubernetes service identity refused");
|
|
78
|
+
const agent = new Agent({ connect: { ca: fs.readFileSync(CA), rejectUnauthorized: true } });
|
|
79
|
+
try {
|
|
80
|
+
const response = await fetch(`https://${host}:${port}${path}`, { method, headers: { Authorization: `Bearer ${fs.readFileSync(TOKEN, "utf8").trim()}`, "Content-Type": "application/json" }, body: body === undefined ? undefined : JSON.stringify(body), dispatcher: agent, signal: AbortSignal.timeout(10_000) });
|
|
81
|
+
if (response.status === 404 && method === "GET")
|
|
82
|
+
return null;
|
|
83
|
+
if (!response.ok)
|
|
84
|
+
throw new SlotApiError(response.status, `physical slot Kubernetes request failed (${response.status}); retain custody`);
|
|
85
|
+
return parse(await response.text());
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
await agent.close();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
localReady ??= (async () => {
|
|
92
|
+
const cluster = parse(await kubectl([...base, "config", "view", "--minify", "--raw", "-o", "jsonpath={.clusters[0].cluster}"], undefined, env));
|
|
93
|
+
if (cluster.server !== SLOT_SERVER || cluster["insecure-skip-tls-verify"] === true || !(cluster["certificate-authority-data"] || cluster["certificate-authority"]) || cluster["proxy-url"] || cluster["tls-server-name"] && cluster["tls-server-name"] !== new URL(SLOT_SERVER).hostname)
|
|
94
|
+
throw new Error("physical slot fixed cluster TLS binding refused");
|
|
95
|
+
})();
|
|
96
|
+
await localReady;
|
|
97
|
+
const command = method === "GET" ? "get" : method === "POST" ? "create" : method === "PUT" ? "replace" : "delete";
|
|
98
|
+
try {
|
|
99
|
+
return parse(await kubectl([...base, command, "--raw", path, ...(body === undefined ? [] : ["-f", "-"])], body, env));
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
if (method === "GET" && err instanceof SlotApiError && err.status === 404)
|
|
103
|
+
return null;
|
|
104
|
+
throw err;
|
|
105
|
+
}
|
|
106
|
+
} };
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=slot-kubernetes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot-kubernetes.js","sourceRoot":"","sources":["../../../src/tools/slot-kubernetes.ts"],"names":[],"mappings":"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"}
|
|
@@ -99,11 +99,12 @@ export declare const ClaimSlotInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
99
99
|
diskGb?: number | undefined;
|
|
100
100
|
customTags?: string | string[] | undefined;
|
|
101
101
|
requester?: string | undefined;
|
|
102
|
-
purpose?: string | undefined;
|
|
103
102
|
sessionId?: string | undefined;
|
|
103
|
+
purpose?: string | undefined;
|
|
104
104
|
ttlHours?: number | undefined;
|
|
105
105
|
assetId?: string | undefined;
|
|
106
106
|
operationId?: string | undefined;
|
|
107
|
+
allowEsxiSlots?: boolean | undefined;
|
|
107
108
|
receiptFile?: string | undefined;
|
|
108
109
|
confirmAssetId?: string | undefined;
|
|
109
110
|
claimNode?: "proxmox" | "esxi" | "minis" | undefined;
|
|
@@ -111,7 +112,6 @@ export declare const ClaimSlotInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
111
112
|
claimVmName?: string | undefined;
|
|
112
113
|
placementSeed?: string | undefined;
|
|
113
114
|
targetHost?: string | undefined;
|
|
114
|
-
allowEsxiSlots?: boolean | undefined;
|
|
115
115
|
}, {
|
|
116
116
|
tags?: string | string[] | undefined;
|
|
117
117
|
hypervisorType?: "proxmox" | "esxi" | "any" | undefined;
|
|
@@ -130,11 +130,12 @@ export declare const ClaimSlotInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
130
130
|
diskGb?: number | undefined;
|
|
131
131
|
customTags?: string | string[] | undefined;
|
|
132
132
|
requester?: string | undefined;
|
|
133
|
-
purpose?: string | undefined;
|
|
134
133
|
sessionId?: string | undefined;
|
|
134
|
+
purpose?: string | undefined;
|
|
135
135
|
ttlHours?: number | undefined;
|
|
136
136
|
assetId?: string | undefined;
|
|
137
137
|
operationId?: string | undefined;
|
|
138
|
+
allowEsxiSlots?: boolean | undefined;
|
|
138
139
|
apply?: boolean | undefined;
|
|
139
140
|
receiptFile?: string | undefined;
|
|
140
141
|
confirmAssetId?: string | undefined;
|
|
@@ -145,7 +146,6 @@ export declare const ClaimSlotInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
145
146
|
placementSeed?: string | undefined;
|
|
146
147
|
targetHost?: string | undefined;
|
|
147
148
|
purgeIfFull?: boolean | undefined;
|
|
148
|
-
allowEsxiSlots?: boolean | undefined;
|
|
149
149
|
}>, {
|
|
150
150
|
hypervisorType: "proxmox" | "esxi" | "any";
|
|
151
151
|
durationMinutes: number;
|
|
@@ -167,11 +167,12 @@ export declare const ClaimSlotInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
167
167
|
diskGb?: number | undefined;
|
|
168
168
|
customTags?: string | string[] | undefined;
|
|
169
169
|
requester?: string | undefined;
|
|
170
|
-
purpose?: string | undefined;
|
|
171
170
|
sessionId?: string | undefined;
|
|
171
|
+
purpose?: string | undefined;
|
|
172
172
|
ttlHours?: number | undefined;
|
|
173
173
|
assetId?: string | undefined;
|
|
174
174
|
operationId?: string | undefined;
|
|
175
|
+
allowEsxiSlots?: boolean | undefined;
|
|
175
176
|
receiptFile?: string | undefined;
|
|
176
177
|
confirmAssetId?: string | undefined;
|
|
177
178
|
claimNode?: "proxmox" | "esxi" | "minis" | undefined;
|
|
@@ -179,7 +180,6 @@ export declare const ClaimSlotInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
179
180
|
claimVmName?: string | undefined;
|
|
180
181
|
placementSeed?: string | undefined;
|
|
181
182
|
targetHost?: string | undefined;
|
|
182
|
-
allowEsxiSlots?: boolean | undefined;
|
|
183
183
|
}, {
|
|
184
184
|
tags?: string | string[] | undefined;
|
|
185
185
|
hypervisorType?: "proxmox" | "esxi" | "any" | undefined;
|
|
@@ -198,11 +198,12 @@ export declare const ClaimSlotInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
198
198
|
diskGb?: number | undefined;
|
|
199
199
|
customTags?: string | string[] | undefined;
|
|
200
200
|
requester?: string | undefined;
|
|
201
|
-
purpose?: string | undefined;
|
|
202
201
|
sessionId?: string | undefined;
|
|
202
|
+
purpose?: string | undefined;
|
|
203
203
|
ttlHours?: number | undefined;
|
|
204
204
|
assetId?: string | undefined;
|
|
205
205
|
operationId?: string | undefined;
|
|
206
|
+
allowEsxiSlots?: boolean | undefined;
|
|
206
207
|
apply?: boolean | undefined;
|
|
207
208
|
receiptFile?: string | undefined;
|
|
208
209
|
confirmAssetId?: string | undefined;
|
|
@@ -213,7 +214,6 @@ export declare const ClaimSlotInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
213
214
|
placementSeed?: string | undefined;
|
|
214
215
|
targetHost?: string | undefined;
|
|
215
216
|
purgeIfFull?: boolean | undefined;
|
|
216
|
-
allowEsxiSlots?: boolean | undefined;
|
|
217
217
|
}>;
|
|
218
218
|
export type ClaimSlotInput = z.infer<typeof ClaimSlotInputSchema>;
|
|
219
219
|
export type ClaimSlotRawInput = z.input<typeof ClaimSlotInputSchema>;
|
|
@@ -137,8 +137,8 @@ export declare const VmActionInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
137
137
|
vmid?: string | number | undefined;
|
|
138
138
|
reason?: string | undefined;
|
|
139
139
|
timeoutSeconds?: number | undefined;
|
|
140
|
-
assetId?: string | undefined;
|
|
141
140
|
hostAssetId?: string | undefined;
|
|
141
|
+
assetId?: string | undefined;
|
|
142
142
|
artifactReceipt?: string | undefined;
|
|
143
143
|
receiptFile?: string | undefined;
|
|
144
144
|
confirmAssetId?: string | undefined;
|
|
@@ -168,8 +168,8 @@ export declare const VmActionInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
168
168
|
format?: "table" | "json" | undefined;
|
|
169
169
|
reason?: string | undefined;
|
|
170
170
|
timeoutSeconds?: number | undefined;
|
|
171
|
-
assetId?: string | undefined;
|
|
172
171
|
hostAssetId?: string | undefined;
|
|
172
|
+
assetId?: string | undefined;
|
|
173
173
|
artifactReceipt?: string | undefined;
|
|
174
174
|
apply?: boolean | undefined;
|
|
175
175
|
receiptFile?: string | undefined;
|
|
@@ -207,8 +207,8 @@ export declare const VmActionInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
207
207
|
vmid?: string | number | undefined;
|
|
208
208
|
reason?: string | undefined;
|
|
209
209
|
timeoutSeconds?: number | undefined;
|
|
210
|
-
assetId?: string | undefined;
|
|
211
210
|
hostAssetId?: string | undefined;
|
|
211
|
+
assetId?: string | undefined;
|
|
212
212
|
artifactReceipt?: string | undefined;
|
|
213
213
|
receiptFile?: string | undefined;
|
|
214
214
|
confirmAssetId?: string | undefined;
|
|
@@ -238,8 +238,8 @@ export declare const VmActionInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
238
238
|
format?: "table" | "json" | undefined;
|
|
239
239
|
reason?: string | undefined;
|
|
240
240
|
timeoutSeconds?: number | undefined;
|
|
241
|
-
assetId?: string | undefined;
|
|
242
241
|
hostAssetId?: string | undefined;
|
|
242
|
+
assetId?: string | undefined;
|
|
243
243
|
artifactReceipt?: string | undefined;
|
|
244
244
|
apply?: boolean | undefined;
|
|
245
245
|
receiptFile?: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../../src/transports/sse.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AACrD,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAE7E,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../../src/transports/sse.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AACrD,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAE7E,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAKnE,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,kBAAkB,CAAC;IAC9B,MAAM,EAAE,SAAS,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,iBAAiB,CAAC,EAAE,sBAAsB,CAAC;IAC3C,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,OAAO,CAAC;IACb,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACrC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,uBAAuB,EAAE,SAAS,GAAG,CAAC,MAAM,SAAS,CAAC,EACtD,OAAO,GAAE,gBAAqB,GAC7B,iBAAiB,CA8TnB"}
|
|
@@ -5,19 +5,9 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
7
7
|
import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
|
|
8
|
-
import
|
|
9
|
-
import path from "node:path";
|
|
10
|
-
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { RUNTIME_VERSION } from "../provenance.js";
|
|
11
9
|
import { logger } from "../utils/logger.js";
|
|
12
|
-
const
|
|
13
|
-
const pkgPath = path.resolve(__dirname, "../../package.json");
|
|
14
|
-
let pkgVersion = "0.1.2";
|
|
15
|
-
try {
|
|
16
|
-
if (fs.existsSync(pkgPath)) {
|
|
17
|
-
pkgVersion = JSON.parse(fs.readFileSync(pkgPath, "utf-8")).version || "0.1.2";
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
catch { }
|
|
10
|
+
const pkgVersion = RUNTIME_VERSION;
|
|
21
11
|
/**
|
|
22
12
|
* Creates an Express application and SSE server instance configured for Call Telemetry Lab MCP.
|
|
23
13
|
*/
|
|
@@ -31,6 +21,7 @@ export function createSseServer(serverFactoryOrInstance, options = {}) {
|
|
|
31
21
|
: { host });
|
|
32
22
|
const sessions = new Map();
|
|
33
23
|
let activeHttpServer;
|
|
24
|
+
let isClosing = false;
|
|
34
25
|
// Background session cleanup timer
|
|
35
26
|
const cleanupInterval = setInterval(() => {
|
|
36
27
|
const now = Date.now();
|
|
@@ -49,14 +40,19 @@ export function createSseServer(serverFactoryOrInstance, options = {}) {
|
|
|
49
40
|
// Background caching for external hypervisor capacity checks to keep /health sub-millisecond
|
|
50
41
|
let cachedHostCapacities = null;
|
|
51
42
|
let isRefreshingHostCapacities = false;
|
|
43
|
+
let hostCapacitiesObservedAt = null;
|
|
44
|
+
let hostCapacityRefreshFailed = false;
|
|
52
45
|
const refreshHostCapacities = async () => {
|
|
53
46
|
if (isRefreshingHostCapacities || !options.hypervisorManager)
|
|
54
47
|
return;
|
|
55
48
|
isRefreshingHostCapacities = true;
|
|
56
49
|
try {
|
|
57
|
-
cachedHostCapacities = await options.hypervisorManager.listAllHostsCapacity();
|
|
50
|
+
cachedHostCapacities = await options.hypervisorManager.listAllHostsCapacity({ allowEsxiSlots: options.slotManager?.allowsEsxiSlots ?? process.env.ALLOW_ESXI_SLOTS === "true" });
|
|
51
|
+
hostCapacitiesObservedAt = new Date().toISOString();
|
|
52
|
+
hostCapacityRefreshFailed = false;
|
|
58
53
|
}
|
|
59
54
|
catch (err) {
|
|
55
|
+
hostCapacityRefreshFailed = true;
|
|
60
56
|
logger.error("Failed to query hypervisor capacities in background:", err);
|
|
61
57
|
}
|
|
62
58
|
finally {
|
|
@@ -72,24 +68,39 @@ export function createSseServer(serverFactoryOrInstance, options = {}) {
|
|
|
72
68
|
if (capacityRefreshInterval.unref) {
|
|
73
69
|
capacityRefreshInterval.unref();
|
|
74
70
|
}
|
|
71
|
+
const freshness = (observedAt) => {
|
|
72
|
+
const elapsed = observedAt ? Date.now() - Date.parse(observedAt) : NaN;
|
|
73
|
+
const ageMs = Number.isFinite(elapsed) ? Math.max(0, elapsed) : null;
|
|
74
|
+
return { ageMs, stale: ageMs === null || ageMs > 40_000, state: ageMs === null ? "unknown" : ageMs > 40_000 ? "stale" : "cached" };
|
|
75
|
+
};
|
|
75
76
|
// 1. Health Status Endpoint (GET /health)
|
|
76
|
-
app.get("/health",
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
res.status(200).json({
|
|
87
|
-
status: "healthy",
|
|
77
|
+
app.get("/health", (_req, res) => {
|
|
78
|
+
const diagnostics = options.slotManager?.getDiagnosticSnapshot?.();
|
|
79
|
+
const ready = Boolean(activeHttpServer?.listening && !isClosing);
|
|
80
|
+
res.status(ready ? 200 : 503).json({
|
|
81
|
+
status: ready ? "healthy" : "not_ready",
|
|
82
|
+
healthScope: "process",
|
|
83
|
+
processHealthy: true,
|
|
84
|
+
sessionRoutingReady: ready,
|
|
85
|
+
ready,
|
|
86
|
+
lifecycle: isClosing ? "draining" : activeHttpServer?.listening ? "listening" : "starting",
|
|
88
87
|
timestamp: new Date().toISOString(),
|
|
89
88
|
version: pkgVersion,
|
|
90
89
|
activeSessions: sessions.size,
|
|
91
|
-
capacity,
|
|
92
|
-
|
|
90
|
+
capacity: diagnostics?.capacity ?? null,
|
|
91
|
+
capacitySource: "cached_diagnostics",
|
|
92
|
+
capacityObservedAt: diagnostics?.capacityObservedAt ?? null,
|
|
93
|
+
capacityFreshness: freshness(diagnostics?.capacityObservedAt ?? null),
|
|
94
|
+
hostCapacities: Array.isArray(cachedHostCapacities) ? cachedHostCapacities.map((capacity) => ({
|
|
95
|
+
name: capacity.name, type: capacity.type, status: capacity.status,
|
|
96
|
+
cpuTotalCores: capacity.cpuTotalCores, cpuUsedPercent: capacity.cpuUsedPercent,
|
|
97
|
+
memoryTotalBytes: capacity.memoryTotalBytes, memoryUsedBytes: capacity.memoryUsedBytes, memoryFreeBytes: capacity.memoryFreeBytes,
|
|
98
|
+
storageTotalBytes: capacity.storageTotalBytes, storageFreeBytes: capacity.storageFreeBytes,
|
|
99
|
+
})) : null,
|
|
100
|
+
hostCapacitiesObservedAt,
|
|
101
|
+
hostCapacityFreshness: freshness(hostCapacitiesObservedAt),
|
|
102
|
+
hostCapacityRefreshing: isRefreshingHostCapacities,
|
|
103
|
+
hostCapacityRefreshFailed,
|
|
93
104
|
});
|
|
94
105
|
});
|
|
95
106
|
// 1.1 Prometheus / OpenMetrics Metrics Exporter (GET /metrics)
|
|
@@ -105,9 +116,22 @@ export function createSseServer(serverFactoryOrInstance, options = {}) {
|
|
|
105
116
|
`ct_lab_active_sessions ${sessions.size}`,
|
|
106
117
|
"",
|
|
107
118
|
];
|
|
119
|
+
const diagnostics = options.slotManager?.getDiagnosticSnapshot?.();
|
|
120
|
+
const capacityAge = freshness(diagnostics?.capacityObservedAt ?? null);
|
|
121
|
+
const hostAge = freshness(hostCapacitiesObservedAt);
|
|
122
|
+
lines.push("# HELP ct_lab_capacity_observed Whether a cached capacity observation exists");
|
|
123
|
+
lines.push("# TYPE ct_lab_capacity_observed gauge", `ct_lab_capacity_observed ${capacityAge.ageMs === null ? 0 : 1}`);
|
|
124
|
+
lines.push("# HELP ct_lab_capacity_stale Whether cached capacity is stale or unknown");
|
|
125
|
+
lines.push("# TYPE ct_lab_capacity_stale gauge", `ct_lab_capacity_stale ${capacityAge.stale ? 1 : 0}`);
|
|
126
|
+
if (capacityAge.ageMs !== null)
|
|
127
|
+
lines.push("# TYPE ct_lab_capacity_age_seconds gauge", `ct_lab_capacity_age_seconds ${capacityAge.ageMs / 1000}`);
|
|
128
|
+
lines.push("# TYPE ct_lab_host_capacity_observed gauge", `ct_lab_host_capacity_observed ${hostAge.ageMs === null ? 0 : 1}`);
|
|
129
|
+
lines.push("# TYPE ct_lab_host_capacity_stale gauge", `ct_lab_host_capacity_stale ${hostAge.stale ? 1 : 0}`);
|
|
130
|
+
if (hostAge.ageMs !== null)
|
|
131
|
+
lines.push("# TYPE ct_lab_host_capacity_age_seconds gauge", `ct_lab_host_capacity_age_seconds ${hostAge.ageMs / 1000}`);
|
|
108
132
|
if (options.slotManager) {
|
|
109
133
|
try {
|
|
110
|
-
const hostsData =
|
|
134
|
+
const hostsData = diagnostics?.capacity;
|
|
111
135
|
const hostList = Array.isArray(hostsData) ? hostsData : hostsData?.hosts ? Object.values(hostsData.hosts) : [];
|
|
112
136
|
lines.push("# HELP ct_lab_fleet_capacity_pure_slots Total pure hardware 8GB slots per host");
|
|
113
137
|
lines.push("# TYPE ct_lab_fleet_capacity_pure_slots gauge");
|
|
@@ -133,8 +157,9 @@ export function createSseServer(serverFactoryOrInstance, options = {}) {
|
|
|
133
157
|
lines.push(`ct_lab_fleet_capacity_allocated_slots{host="${hostId}",hypervisor="${hyp}"} ${h.allocatedSlots ?? 0}`);
|
|
134
158
|
}
|
|
135
159
|
lines.push("");
|
|
136
|
-
const allSlots =
|
|
137
|
-
const activeCount = allSlots.filter((s) => s.status === "CLAIMED" || s.status === "active")
|
|
160
|
+
const allSlots = diagnostics?.leases ?? [];
|
|
161
|
+
const activeCount = allSlots.filter((s) => (s.status === "CLAIMED" || s.status === "active")
|
|
162
|
+
&& s.expiresAt && Number.isFinite(Date.parse(s.expiresAt)) && Date.parse(s.expiresAt) > Date.now()).length;
|
|
138
163
|
const expiredCount = allSlots.filter((s) => s.status === "EXPIRED" || (s.expiresAt && new Date(s.expiresAt).getTime() <= Date.now())).length;
|
|
139
164
|
lines.push("# HELP ct_lab_active_leases_count Total active claimed slot leases in fleet");
|
|
140
165
|
lines.push("# TYPE ct_lab_active_leases_count gauge");
|
|
@@ -172,6 +197,10 @@ export function createSseServer(serverFactoryOrInstance, options = {}) {
|
|
|
172
197
|
});
|
|
173
198
|
// 2. SSE Connection Endpoint (GET /sse)
|
|
174
199
|
app.get("/sse", async (_req, res) => {
|
|
200
|
+
if (isClosing) {
|
|
201
|
+
res.status(503).json({ error: "MCP session routing is draining" });
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
175
204
|
try {
|
|
176
205
|
const serverInstance = typeof serverFactoryOrInstance === "function"
|
|
177
206
|
? serverFactoryOrInstance()
|
|
@@ -232,6 +261,7 @@ export function createSseServer(serverFactoryOrInstance, options = {}) {
|
|
|
232
261
|
app,
|
|
233
262
|
sessions,
|
|
234
263
|
async listen(customPort, customHost) {
|
|
264
|
+
isClosing = false;
|
|
235
265
|
const targetPort = customPort !== undefined ? customPort : port;
|
|
236
266
|
const targetHost = customHost || host;
|
|
237
267
|
return new Promise((resolve) => {
|
|
@@ -243,6 +273,7 @@ export function createSseServer(serverFactoryOrInstance, options = {}) {
|
|
|
243
273
|
});
|
|
244
274
|
},
|
|
245
275
|
async close() {
|
|
276
|
+
isClosing = true;
|
|
246
277
|
clearInterval(cleanupInterval);
|
|
247
278
|
clearInterval(capacityRefreshInterval);
|
|
248
279
|
for (const [id, session] of sessions.entries()) {
|