@calltelemetry/ct-lab-mcp 0.1.2 → 0.1.4
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/src/appliance/commands.d.ts +4 -0
- package/dist/src/appliance/commands.d.ts.map +1 -1
- package/dist/src/appliance/commands.js +32 -0
- package/dist/src/appliance/commands.js.map +1 -1
- package/dist/src/appliance/mock.d.ts.map +1 -1
- package/dist/src/appliance/mock.js +42 -0
- package/dist/src/appliance/mock.js.map +1 -1
- package/dist/src/appliance/types.d.ts +8 -1
- package/dist/src/appliance/types.d.ts.map +1 -1
- package/dist/src/appliance/types.js.map +1 -1
- package/dist/src/credentials/resolver.js +1 -1
- package/dist/src/credentials/resolver.js.map +1 -1
- package/dist/src/hypervisors/proxmox/client.d.ts +1 -0
- package/dist/src/hypervisors/proxmox/client.d.ts.map +1 -1
- package/dist/src/hypervisors/proxmox/client.js +63 -3
- package/dist/src/hypervisors/proxmox/client.js.map +1 -1
- package/dist/src/server.d.ts +3 -1
- package/dist/src/server.d.ts.map +1 -1
- package/dist/src/server.js +14 -4
- package/dist/src/server.js.map +1 -1
- package/dist/src/slot/gc.d.ts +11 -2
- package/dist/src/slot/gc.d.ts.map +1 -1
- package/dist/src/slot/gc.js +20 -2
- package/dist/src/slot/gc.js.map +1 -1
- package/dist/src/slot/manager.d.ts +34 -3
- package/dist/src/slot/manager.d.ts.map +1 -1
- package/dist/src/slot/manager.js +572 -3
- package/dist/src/slot/manager.js.map +1 -1
- package/dist/src/slot/types.d.ts +96 -1
- package/dist/src/slot/types.d.ts.map +1 -1
- package/dist/src/slot/types.js.map +1 -1
- package/dist/src/telemetry/index.d.ts +3 -0
- package/dist/src/telemetry/index.d.ts.map +1 -0
- package/dist/src/telemetry/index.js +3 -0
- package/dist/src/telemetry/index.js.map +1 -0
- package/dist/src/telemetry/registry.d.ts +43 -0
- package/dist/src/telemetry/registry.d.ts.map +1 -0
- package/dist/src/telemetry/registry.js +146 -0
- package/dist/src/telemetry/registry.js.map +1 -0
- package/dist/src/telemetry/types.d.ts +37 -0
- package/dist/src/telemetry/types.d.ts.map +1 -0
- package/dist/src/telemetry/types.js +6 -0
- package/dist/src/telemetry/types.js.map +1 -0
- package/dist/src/tools/appliance-exec.js +1 -1
- package/dist/src/tools/appliance-exec.js.map +1 -1
- package/dist/src/tools/factory-reset.d.ts +54 -0
- package/dist/src/tools/factory-reset.d.ts.map +1 -0
- package/dist/src/tools/factory-reset.js +215 -0
- package/dist/src/tools/factory-reset.js.map +1 -0
- package/dist/src/tools/index.d.ts +4 -1
- package/dist/src/tools/index.d.ts.map +1 -1
- package/dist/src/tools/index.js +25 -8
- package/dist/src/tools/index.js.map +1 -1
- package/dist/src/tools/list-hosts.d.ts +2 -2
- package/dist/src/tools/list-inventory.d.ts +3 -3
- package/dist/src/tools/provision-tools.d.ts +122 -21
- package/dist/src/tools/provision-tools.d.ts.map +1 -1
- package/dist/src/tools/provision-tools.js +384 -1
- package/dist/src/tools/provision-tools.js.map +1 -1
- package/dist/src/tools/purge-slots.d.ts +52 -0
- package/dist/src/tools/purge-slots.d.ts.map +1 -0
- package/dist/src/tools/purge-slots.js +107 -0
- package/dist/src/tools/purge-slots.js.map +1 -0
- package/dist/src/tools/slot-tools.d.ts +92 -30
- package/dist/src/tools/slot-tools.d.ts.map +1 -1
- package/dist/src/tools/slot-tools.js +67 -5
- package/dist/src/tools/slot-tools.js.map +1 -1
- package/dist/src/tools/vm-action.d.ts +22 -22
- package/dist/src/utils/formatters.d.ts +38 -4
- package/dist/src/utils/formatters.d.ts.map +1 -1
- package/dist/src/utils/formatters.js +179 -23
- package/dist/src/utils/formatters.js.map +1 -1
- package/dist/src/utils/license.d.ts +27 -0
- package/dist/src/utils/license.d.ts.map +1 -0
- package/dist/src/utils/license.js +59 -0
- package/dist/src/utils/license.js.map +1 -0
- package/package.json +1 -1
|
@@ -73,14 +73,14 @@ export declare const ProvisionVmInputSchema: z.ZodEffects<z.ZodEffects<z.ZodObje
|
|
|
73
73
|
template?: string | number | undefined;
|
|
74
74
|
description?: string | undefined;
|
|
75
75
|
start?: boolean | undefined;
|
|
76
|
+
memoryMb?: number | undefined;
|
|
76
77
|
host?: string | undefined;
|
|
77
78
|
vmid?: string | number | undefined;
|
|
78
|
-
|
|
79
|
+
ipAddress?: string | undefined;
|
|
79
80
|
linearIssue?: string | undefined;
|
|
81
|
+
vlan?: number | undefined;
|
|
80
82
|
slotClaimId?: string | undefined;
|
|
81
83
|
cpuCores?: number | undefined;
|
|
82
|
-
ipAddress?: string | undefined;
|
|
83
|
-
memoryMb?: number | undefined;
|
|
84
84
|
requester?: string | undefined;
|
|
85
85
|
targetHost?: string | undefined;
|
|
86
86
|
sourceVmIdOrName?: string | number | undefined;
|
|
@@ -97,15 +97,15 @@ export declare const ProvisionVmInputSchema: z.ZodEffects<z.ZodEffects<z.ZodObje
|
|
|
97
97
|
template?: string | number | undefined;
|
|
98
98
|
description?: string | undefined;
|
|
99
99
|
start?: boolean | undefined;
|
|
100
|
+
hypervisorType?: "proxmox" | "esxi" | "any" | undefined;
|
|
101
|
+
memoryMb?: number | undefined;
|
|
100
102
|
host?: string | undefined;
|
|
101
103
|
vmid?: string | number | undefined;
|
|
102
|
-
|
|
104
|
+
ipAddress?: string | undefined;
|
|
103
105
|
linearIssue?: string | undefined;
|
|
106
|
+
vlan?: number | undefined;
|
|
104
107
|
slotClaimId?: string | undefined;
|
|
105
108
|
cpuCores?: number | undefined;
|
|
106
|
-
ipAddress?: string | undefined;
|
|
107
|
-
hypervisorType?: "proxmox" | "esxi" | "any" | undefined;
|
|
108
|
-
memoryMb?: number | undefined;
|
|
109
109
|
requester?: string | undefined;
|
|
110
110
|
targetHost?: string | undefined;
|
|
111
111
|
sourceVmIdOrName?: string | number | undefined;
|
|
@@ -127,14 +127,14 @@ export declare const ProvisionVmInputSchema: z.ZodEffects<z.ZodEffects<z.ZodObje
|
|
|
127
127
|
template?: string | number | undefined;
|
|
128
128
|
description?: string | undefined;
|
|
129
129
|
start?: boolean | undefined;
|
|
130
|
+
memoryMb?: number | undefined;
|
|
130
131
|
host?: string | undefined;
|
|
131
132
|
vmid?: string | number | undefined;
|
|
132
|
-
|
|
133
|
+
ipAddress?: string | undefined;
|
|
133
134
|
linearIssue?: string | undefined;
|
|
135
|
+
vlan?: number | undefined;
|
|
134
136
|
slotClaimId?: string | undefined;
|
|
135
137
|
cpuCores?: number | undefined;
|
|
136
|
-
ipAddress?: string | undefined;
|
|
137
|
-
memoryMb?: number | undefined;
|
|
138
138
|
requester?: string | undefined;
|
|
139
139
|
targetHost?: string | undefined;
|
|
140
140
|
sourceVmIdOrName?: string | number | undefined;
|
|
@@ -151,15 +151,15 @@ export declare const ProvisionVmInputSchema: z.ZodEffects<z.ZodEffects<z.ZodObje
|
|
|
151
151
|
template?: string | number | undefined;
|
|
152
152
|
description?: string | undefined;
|
|
153
153
|
start?: boolean | undefined;
|
|
154
|
+
hypervisorType?: "proxmox" | "esxi" | "any" | undefined;
|
|
155
|
+
memoryMb?: number | undefined;
|
|
154
156
|
host?: string | undefined;
|
|
155
157
|
vmid?: string | number | undefined;
|
|
156
|
-
|
|
158
|
+
ipAddress?: string | undefined;
|
|
157
159
|
linearIssue?: string | undefined;
|
|
160
|
+
vlan?: number | undefined;
|
|
158
161
|
slotClaimId?: string | undefined;
|
|
159
162
|
cpuCores?: number | undefined;
|
|
160
|
-
ipAddress?: string | undefined;
|
|
161
|
-
hypervisorType?: "proxmox" | "esxi" | "any" | undefined;
|
|
162
|
-
memoryMb?: number | undefined;
|
|
163
163
|
requester?: string | undefined;
|
|
164
164
|
targetHost?: string | undefined;
|
|
165
165
|
sourceVmIdOrName?: string | number | undefined;
|
|
@@ -181,14 +181,14 @@ export declare const ProvisionVmInputSchema: z.ZodEffects<z.ZodEffects<z.ZodObje
|
|
|
181
181
|
template?: string | number | undefined;
|
|
182
182
|
description?: string | undefined;
|
|
183
183
|
start?: boolean | undefined;
|
|
184
|
+
memoryMb?: number | undefined;
|
|
184
185
|
host?: string | undefined;
|
|
185
186
|
vmid?: string | number | undefined;
|
|
186
|
-
|
|
187
|
+
ipAddress?: string | undefined;
|
|
187
188
|
linearIssue?: string | undefined;
|
|
189
|
+
vlan?: number | undefined;
|
|
188
190
|
slotClaimId?: string | undefined;
|
|
189
191
|
cpuCores?: number | undefined;
|
|
190
|
-
ipAddress?: string | undefined;
|
|
191
|
-
memoryMb?: number | undefined;
|
|
192
192
|
requester?: string | undefined;
|
|
193
193
|
targetHost?: string | undefined;
|
|
194
194
|
sourceVmIdOrName?: string | number | undefined;
|
|
@@ -205,15 +205,15 @@ export declare const ProvisionVmInputSchema: z.ZodEffects<z.ZodEffects<z.ZodObje
|
|
|
205
205
|
template?: string | number | undefined;
|
|
206
206
|
description?: string | undefined;
|
|
207
207
|
start?: boolean | undefined;
|
|
208
|
+
hypervisorType?: "proxmox" | "esxi" | "any" | undefined;
|
|
209
|
+
memoryMb?: number | undefined;
|
|
208
210
|
host?: string | undefined;
|
|
209
211
|
vmid?: string | number | undefined;
|
|
210
|
-
|
|
212
|
+
ipAddress?: string | undefined;
|
|
211
213
|
linearIssue?: string | undefined;
|
|
214
|
+
vlan?: number | undefined;
|
|
212
215
|
slotClaimId?: string | undefined;
|
|
213
216
|
cpuCores?: number | undefined;
|
|
214
|
-
ipAddress?: string | undefined;
|
|
215
|
-
hypervisorType?: "proxmox" | "esxi" | "any" | undefined;
|
|
216
|
-
memoryMb?: number | undefined;
|
|
217
217
|
requester?: string | undefined;
|
|
218
218
|
targetHost?: string | undefined;
|
|
219
219
|
sourceVmIdOrName?: string | number | undefined;
|
|
@@ -228,4 +228,105 @@ export declare const ProvisionVmInputSchema: z.ZodEffects<z.ZodEffects<z.ZodObje
|
|
|
228
228
|
export type ProvisionVmInput = z.infer<typeof ProvisionVmInputSchema>;
|
|
229
229
|
export type ProvisionVmRawInput = z.input<typeof ProvisionVmInputSchema>;
|
|
230
230
|
export declare function handleProvisionVm(rawArgs: ProvisionVmRawInput, context: ToolContext): Promise<CallToolResult>;
|
|
231
|
+
export declare const AutoProvisionVmInputShape: {
|
|
232
|
+
template: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
|
|
233
|
+
sourceVmIdOrName: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
|
|
234
|
+
name: z.ZodOptional<z.ZodString>;
|
|
235
|
+
newVmName: z.ZodOptional<z.ZodString>;
|
|
236
|
+
host: z.ZodOptional<z.ZodString>;
|
|
237
|
+
targetHost: z.ZodOptional<z.ZodString>;
|
|
238
|
+
hypervisorType: z.ZodDefault<z.ZodOptional<z.ZodEnum<["proxmox", "esxi", "any"]>>>;
|
|
239
|
+
targetVersion: z.ZodOptional<z.ZodString>;
|
|
240
|
+
version: z.ZodOptional<z.ZodString>;
|
|
241
|
+
workloadType: z.ZodOptional<z.ZodEnum<["uat", "perf", "soak", "dev", "regression", "reproduction", "demo"]>>;
|
|
242
|
+
label: z.ZodOptional<z.ZodString>;
|
|
243
|
+
linearIssue: z.ZodOptional<z.ZodString>;
|
|
244
|
+
branch: z.ZodOptional<z.ZodString>;
|
|
245
|
+
tags: z.ZodOptional<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodString]>>;
|
|
246
|
+
requester: z.ZodOptional<z.ZodString>;
|
|
247
|
+
ttlMinutes: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
248
|
+
durationMinutes: z.ZodOptional<z.ZodNumber>;
|
|
249
|
+
vlan: z.ZodOptional<z.ZodNumber>;
|
|
250
|
+
ipAddress: z.ZodOptional<z.ZodString>;
|
|
251
|
+
networkBridge: z.ZodOptional<z.ZodString>;
|
|
252
|
+
storage: z.ZodOptional<z.ZodString>;
|
|
253
|
+
waitForReady: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
254
|
+
readyTimeoutSeconds: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
255
|
+
};
|
|
256
|
+
export declare const AutoProvisionVmInputSchema: z.ZodObject<{
|
|
257
|
+
template: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
|
|
258
|
+
sourceVmIdOrName: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
|
|
259
|
+
name: z.ZodOptional<z.ZodString>;
|
|
260
|
+
newVmName: z.ZodOptional<z.ZodString>;
|
|
261
|
+
host: z.ZodOptional<z.ZodString>;
|
|
262
|
+
targetHost: z.ZodOptional<z.ZodString>;
|
|
263
|
+
hypervisorType: z.ZodDefault<z.ZodOptional<z.ZodEnum<["proxmox", "esxi", "any"]>>>;
|
|
264
|
+
targetVersion: z.ZodOptional<z.ZodString>;
|
|
265
|
+
version: z.ZodOptional<z.ZodString>;
|
|
266
|
+
workloadType: z.ZodOptional<z.ZodEnum<["uat", "perf", "soak", "dev", "regression", "reproduction", "demo"]>>;
|
|
267
|
+
label: z.ZodOptional<z.ZodString>;
|
|
268
|
+
linearIssue: z.ZodOptional<z.ZodString>;
|
|
269
|
+
branch: z.ZodOptional<z.ZodString>;
|
|
270
|
+
tags: z.ZodOptional<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodString]>>;
|
|
271
|
+
requester: z.ZodOptional<z.ZodString>;
|
|
272
|
+
ttlMinutes: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
273
|
+
durationMinutes: z.ZodOptional<z.ZodNumber>;
|
|
274
|
+
vlan: z.ZodOptional<z.ZodNumber>;
|
|
275
|
+
ipAddress: z.ZodOptional<z.ZodString>;
|
|
276
|
+
networkBridge: z.ZodOptional<z.ZodString>;
|
|
277
|
+
storage: z.ZodOptional<z.ZodString>;
|
|
278
|
+
waitForReady: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
279
|
+
readyTimeoutSeconds: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
280
|
+
}, "strip", z.ZodTypeAny, {
|
|
281
|
+
hypervisorType: "proxmox" | "esxi" | "any";
|
|
282
|
+
ttlMinutes: number;
|
|
283
|
+
waitForReady: boolean;
|
|
284
|
+
readyTimeoutSeconds: number;
|
|
285
|
+
storage?: string | undefined;
|
|
286
|
+
name?: string | undefined;
|
|
287
|
+
tags?: string | string[] | undefined;
|
|
288
|
+
template?: string | number | undefined;
|
|
289
|
+
version?: string | undefined;
|
|
290
|
+
durationMinutes?: number | undefined;
|
|
291
|
+
host?: string | undefined;
|
|
292
|
+
ipAddress?: string | undefined;
|
|
293
|
+
targetVersion?: string | undefined;
|
|
294
|
+
workloadType?: "uat" | "perf" | "soak" | "dev" | "regression" | "reproduction" | "demo" | undefined;
|
|
295
|
+
label?: string | undefined;
|
|
296
|
+
linearIssue?: string | undefined;
|
|
297
|
+
branch?: string | undefined;
|
|
298
|
+
vlan?: number | undefined;
|
|
299
|
+
requester?: string | undefined;
|
|
300
|
+
targetHost?: string | undefined;
|
|
301
|
+
sourceVmIdOrName?: string | number | undefined;
|
|
302
|
+
newVmName?: string | undefined;
|
|
303
|
+
networkBridge?: string | undefined;
|
|
304
|
+
}, {
|
|
305
|
+
storage?: string | undefined;
|
|
306
|
+
name?: string | undefined;
|
|
307
|
+
tags?: string | string[] | undefined;
|
|
308
|
+
template?: string | number | undefined;
|
|
309
|
+
version?: string | undefined;
|
|
310
|
+
hypervisorType?: "proxmox" | "esxi" | "any" | undefined;
|
|
311
|
+
durationMinutes?: number | undefined;
|
|
312
|
+
ttlMinutes?: number | undefined;
|
|
313
|
+
host?: string | undefined;
|
|
314
|
+
ipAddress?: string | undefined;
|
|
315
|
+
targetVersion?: string | undefined;
|
|
316
|
+
workloadType?: "uat" | "perf" | "soak" | "dev" | "regression" | "reproduction" | "demo" | undefined;
|
|
317
|
+
label?: string | undefined;
|
|
318
|
+
linearIssue?: string | undefined;
|
|
319
|
+
branch?: string | undefined;
|
|
320
|
+
vlan?: number | undefined;
|
|
321
|
+
requester?: string | undefined;
|
|
322
|
+
targetHost?: string | undefined;
|
|
323
|
+
sourceVmIdOrName?: string | number | undefined;
|
|
324
|
+
newVmName?: string | undefined;
|
|
325
|
+
networkBridge?: string | undefined;
|
|
326
|
+
waitForReady?: boolean | undefined;
|
|
327
|
+
readyTimeoutSeconds?: number | undefined;
|
|
328
|
+
}>;
|
|
329
|
+
export type AutoProvisionVmInput = z.infer<typeof AutoProvisionVmInputSchema>;
|
|
330
|
+
export type AutoProvisionVmRawInput = z.input<typeof AutoProvisionVmInputSchema>;
|
|
331
|
+
export declare function handleAutoProvisionVm(rawArgs: AutoProvisionVmRawInput, context: ToolContext): Promise<CallToolResult>;
|
|
231
332
|
//# sourceMappingURL=provision-tools.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provision-tools.d.ts","sourceRoot":"","sources":["../../../src/tools/provision-tools.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAA2C,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"provision-tools.d.ts","sourceRoot":"","sources":["../../../src/tools/provision-tools.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAA2C,MAAM,iBAAiB,CAAC;AAM1F,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAW9C,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmHjC,CAAC;AAEF,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAShC,CAAC;AAEJ,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACtE,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEzE,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,mBAAmB,EAC5B,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,cAAc,CAAC,CAuKzB;AAMD,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;CA6GrC,CAAC;AAEF,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAsC,CAAC;AAC9E,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAC9E,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAEjF,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,uBAAuB,EAChC,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,cAAc,CAAC,CAuSzB"}
|
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
import { ProxmoxErrorCode, createToolErrorResult } from "../types/mcp.js";
|
|
9
|
-
import { formatProvisionResult } from "../utils/formatters.js";
|
|
9
|
+
import { formatProvisionResult, formatAutoProvisionResult, } from "../utils/formatters.js";
|
|
10
10
|
import { CapacityExceededError, GlobalCapacityExceededError, DatastoreCapacityExceededError, } from "../slot/types.js";
|
|
11
11
|
import { ProtectedVmViolationError } from "../guardrails/types.js";
|
|
12
|
+
import { applianceSshExecutor } from "../appliance/executor.js";
|
|
12
13
|
export const ProvisionVmInputShape = {
|
|
13
14
|
sourceVmIdOrName: z
|
|
14
15
|
.union([z.string(), z.number()])
|
|
@@ -286,4 +287,386 @@ export async function handleProvisionVm(rawArgs, context) {
|
|
|
286
287
|
return createToolErrorResult(ProxmoxErrorCode.UPSTREAM_API_ERROR, msg);
|
|
287
288
|
}
|
|
288
289
|
}
|
|
290
|
+
// ============================================================================
|
|
291
|
+
// Auto Provision VM (Milestone M4)
|
|
292
|
+
// ============================================================================
|
|
293
|
+
export const AutoProvisionVmInputShape = {
|
|
294
|
+
template: z
|
|
295
|
+
.union([z.string(), z.number()])
|
|
296
|
+
.optional()
|
|
297
|
+
.describe("Source VM template name or numeric VMID to clone from (e.g. '9000', 'CT-ALMALINUX9-TEMPLATE', 'CT-087-STABLE-TEMPLATE')."),
|
|
298
|
+
sourceVmIdOrName: z
|
|
299
|
+
.union([z.string(), z.number()])
|
|
300
|
+
.optional()
|
|
301
|
+
.describe("Alias for template."),
|
|
302
|
+
name: z
|
|
303
|
+
.string()
|
|
304
|
+
.optional()
|
|
305
|
+
.describe("Target VM name (e.g. 'ct-appliance-uat-105'). Auto-generated if omitted."),
|
|
306
|
+
newVmName: z
|
|
307
|
+
.string()
|
|
308
|
+
.optional()
|
|
309
|
+
.describe("Alias for name."),
|
|
310
|
+
host: z
|
|
311
|
+
.string()
|
|
312
|
+
.optional()
|
|
313
|
+
.describe("Target hypervisor host ('auto', 'proxmox-lab', 'proxmox-mini', 'esxi-intel-192-168-123-176'). Defaults to 'auto' for least-loaded placement."),
|
|
314
|
+
targetHost: z
|
|
315
|
+
.string()
|
|
316
|
+
.optional()
|
|
317
|
+
.describe("Alias for host."),
|
|
318
|
+
hypervisorType: z
|
|
319
|
+
.enum(["proxmox", "esxi", "any"])
|
|
320
|
+
.optional()
|
|
321
|
+
.default("any")
|
|
322
|
+
.describe("Target hypervisor platform preference: 'proxmox', 'esxi', or 'any'."),
|
|
323
|
+
targetVersion: z
|
|
324
|
+
.string()
|
|
325
|
+
.optional()
|
|
326
|
+
.describe("Call Telemetry release version to deploy/pin (e.g. '0.8.7-stable', '0.8.8')."),
|
|
327
|
+
version: z
|
|
328
|
+
.string()
|
|
329
|
+
.optional()
|
|
330
|
+
.describe("Alias for targetVersion."),
|
|
331
|
+
workloadType: z
|
|
332
|
+
.enum(["uat", "perf", "soak", "dev", "regression", "reproduction", "demo"])
|
|
333
|
+
.optional()
|
|
334
|
+
.describe("Workload category for the test slot lease (e.g. 'uat', 'perf', 'dev')."),
|
|
335
|
+
label: z
|
|
336
|
+
.string()
|
|
337
|
+
.optional()
|
|
338
|
+
.describe("Human-readable label for the slot claim and VM."),
|
|
339
|
+
linearIssue: z
|
|
340
|
+
.string()
|
|
341
|
+
.optional()
|
|
342
|
+
.describe("Linear issue key tracking this test VM (e.g. 'CTUAT-693')."),
|
|
343
|
+
branch: z
|
|
344
|
+
.string()
|
|
345
|
+
.optional()
|
|
346
|
+
.describe("Git feature/fix branch name."),
|
|
347
|
+
tags: z
|
|
348
|
+
.union([z.array(z.string()), z.string()])
|
|
349
|
+
.optional()
|
|
350
|
+
.describe("Custom tags to attach to the VM and slot lease."),
|
|
351
|
+
requester: z
|
|
352
|
+
.string()
|
|
353
|
+
.optional()
|
|
354
|
+
.describe("Requester name or agent identifier."),
|
|
355
|
+
ttlMinutes: z
|
|
356
|
+
.number()
|
|
357
|
+
.int()
|
|
358
|
+
.min(1)
|
|
359
|
+
.max(1440)
|
|
360
|
+
.optional()
|
|
361
|
+
.default(60)
|
|
362
|
+
.describe("Slot lease TTL in minutes (default: 60)."),
|
|
363
|
+
durationMinutes: z
|
|
364
|
+
.number()
|
|
365
|
+
.int()
|
|
366
|
+
.min(1)
|
|
367
|
+
.max(1440)
|
|
368
|
+
.optional()
|
|
369
|
+
.describe("Alias for ttlMinutes."),
|
|
370
|
+
vlan: z
|
|
371
|
+
.number()
|
|
372
|
+
.int()
|
|
373
|
+
.min(1)
|
|
374
|
+
.max(4094)
|
|
375
|
+
.optional()
|
|
376
|
+
.describe("VLAN tag assignment (e.g. 124, 125)."),
|
|
377
|
+
ipAddress: z
|
|
378
|
+
.string()
|
|
379
|
+
.optional()
|
|
380
|
+
.describe("Static IP address assignment for the guest VM (e.g. '192.168.124.105')."),
|
|
381
|
+
networkBridge: z
|
|
382
|
+
.string()
|
|
383
|
+
.optional()
|
|
384
|
+
.describe("Network bridge interface (e.g. 'vmbr0', 'VM Network')."),
|
|
385
|
+
storage: z
|
|
386
|
+
.string()
|
|
387
|
+
.optional()
|
|
388
|
+
.describe("Target storage pool / datastore name."),
|
|
389
|
+
waitForReady: z
|
|
390
|
+
.boolean()
|
|
391
|
+
.optional()
|
|
392
|
+
.default(true)
|
|
393
|
+
.describe("Whether to poll SSH:2222 / API health until the VM is ready (default: true)."),
|
|
394
|
+
readyTimeoutSeconds: z
|
|
395
|
+
.number()
|
|
396
|
+
.int()
|
|
397
|
+
.min(5)
|
|
398
|
+
.max(600)
|
|
399
|
+
.optional()
|
|
400
|
+
.default(180)
|
|
401
|
+
.describe("Readiness polling timeout in seconds (default: 180)."),
|
|
402
|
+
};
|
|
403
|
+
export const AutoProvisionVmInputSchema = z.object(AutoProvisionVmInputShape);
|
|
404
|
+
export async function handleAutoProvisionVm(rawArgs, context) {
|
|
405
|
+
let claimedSlot;
|
|
406
|
+
let createdVmId;
|
|
407
|
+
let createdHost;
|
|
408
|
+
const startTime = Date.now();
|
|
409
|
+
try {
|
|
410
|
+
const parseResult = AutoProvisionVmInputSchema.safeParse(rawArgs);
|
|
411
|
+
if (!parseResult.success) {
|
|
412
|
+
const errMsg = parseResult.error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join("; ");
|
|
413
|
+
return createToolErrorResult(ProxmoxErrorCode.VALIDATION_ERROR, errMsg);
|
|
414
|
+
}
|
|
415
|
+
const args = parseResult.data;
|
|
416
|
+
const rawHost = args.host || args.targetHost;
|
|
417
|
+
const targetHost = !rawHost || rawHost === "auto" ? undefined : rawHost;
|
|
418
|
+
const hypervisorType = args.hypervisorType || "any";
|
|
419
|
+
const targetVersion = args.targetVersion || args.version;
|
|
420
|
+
const workloadType = args.workloadType || "uat";
|
|
421
|
+
const linearIssue = args.linearIssue;
|
|
422
|
+
const label = args.label;
|
|
423
|
+
const branch = args.branch;
|
|
424
|
+
const durationMinutes = args.durationMinutes ?? args.ttlMinutes ?? 60;
|
|
425
|
+
const vmName = args.name ||
|
|
426
|
+
args.newVmName ||
|
|
427
|
+
`ct-appliance-${workloadType}-${Date.now().toString(36)}`;
|
|
428
|
+
const requester = args.requester || linearIssue || label || vmName;
|
|
429
|
+
const waitForReady = args.waitForReady !== false;
|
|
430
|
+
const readyTimeoutSeconds = args.readyTimeoutSeconds ?? 180;
|
|
431
|
+
let parsedTags = [];
|
|
432
|
+
if (args.tags) {
|
|
433
|
+
if (Array.isArray(args.tags)) {
|
|
434
|
+
parsedTags = args.tags;
|
|
435
|
+
}
|
|
436
|
+
else if (typeof args.tags === "string") {
|
|
437
|
+
parsedTags = args.tags.split(/[;, ]+/).map((t) => t.trim()).filter(Boolean);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
// 1. Atomically Claim 8GB Slot Lease
|
|
441
|
+
claimedSlot = await context.slotManager.claimSlot({
|
|
442
|
+
tag: label || linearIssue || vmName,
|
|
443
|
+
requester,
|
|
444
|
+
linearIssue: linearIssue || (vmName.startsWith("CTUAT-") ? vmName : undefined),
|
|
445
|
+
label,
|
|
446
|
+
workloadType,
|
|
447
|
+
targetVersion,
|
|
448
|
+
branch,
|
|
449
|
+
customTags: parsedTags,
|
|
450
|
+
targetHost,
|
|
451
|
+
hypervisorType,
|
|
452
|
+
durationMinutes,
|
|
453
|
+
purpose: `Auto-provisioned ${workloadType} VM: ${vmName}`,
|
|
454
|
+
});
|
|
455
|
+
const hostId = claimedSlot.hostId;
|
|
456
|
+
createdHost = hostId;
|
|
457
|
+
const hypType = hostId.startsWith("esxi") ? "esxi" : "proxmox";
|
|
458
|
+
// 2. Resolve Base Template
|
|
459
|
+
let template = args.template ?? args.sourceVmIdOrName;
|
|
460
|
+
if (!template && context.hypervisorManager) {
|
|
461
|
+
try {
|
|
462
|
+
const vms = await context.hypervisorManager.listUnifiedInventory({
|
|
463
|
+
includeTemplates: true,
|
|
464
|
+
host: hostId,
|
|
465
|
+
});
|
|
466
|
+
const templateVm = vms.find((v) => v.isTemplate) ||
|
|
467
|
+
vms.find((v) => v.name.toLowerCase().includes("template") ||
|
|
468
|
+
v.name.toLowerCase().includes("tmpl") ||
|
|
469
|
+
(v.tags && v.tags.some((t) => t.toLowerCase().includes("template"))));
|
|
470
|
+
if (templateVm) {
|
|
471
|
+
template = templateVm.id || templateVm.name;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
catch {
|
|
475
|
+
// fallback to default IDs
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
if (!template) {
|
|
479
|
+
if (hypType === "esxi") {
|
|
480
|
+
template = "CT-087-STABLE-TEMPLATE";
|
|
481
|
+
}
|
|
482
|
+
else if (hostId === "proxmox-mini") {
|
|
483
|
+
template = "200";
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
template = "102";
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
// 3. Clone VM from Template
|
|
490
|
+
const cloneParams = {
|
|
491
|
+
sourceVmIdOrName: template,
|
|
492
|
+
newVmName: vmName,
|
|
493
|
+
targetHost: hostId,
|
|
494
|
+
hypervisorType: hypType,
|
|
495
|
+
fullClone: true,
|
|
496
|
+
description: `Auto-provisioned ${workloadType} VM (${linearIssue || label || "disposable"})`,
|
|
497
|
+
memoryBytes: 8192 * 1024 * 1024,
|
|
498
|
+
cpuCores: 2,
|
|
499
|
+
vlan: args.vlan,
|
|
500
|
+
ipAddress: args.ipAddress,
|
|
501
|
+
networkBridge: args.networkBridge,
|
|
502
|
+
storage: args.storage,
|
|
503
|
+
linearIssue,
|
|
504
|
+
startOnDeploy: true,
|
|
505
|
+
tags: ["disposable", workloadType, ...(targetVersion ? [targetVersion] : []), ...parsedTags],
|
|
506
|
+
requester,
|
|
507
|
+
slotClaimId: claimedSlot.claimId,
|
|
508
|
+
};
|
|
509
|
+
let provisionResult;
|
|
510
|
+
if (context.hypervisorManager) {
|
|
511
|
+
provisionResult = await context.hypervisorManager.provisionVm(cloneParams);
|
|
512
|
+
}
|
|
513
|
+
else if (context.proxmoxManager) {
|
|
514
|
+
const client = context.proxmoxManager.getClient(hostId);
|
|
515
|
+
const targetVmid = 500;
|
|
516
|
+
const sourceNum = typeof template === "number" ? template : parseInt(String(template), 10) || 9000;
|
|
517
|
+
const cloneTask = await client.cloneVm(sourceNum, targetVmid, vmName, { full: true });
|
|
518
|
+
await client.startVm(targetVmid).catch(() => { });
|
|
519
|
+
provisionResult = {
|
|
520
|
+
vmId: String(targetVmid),
|
|
521
|
+
name: vmName,
|
|
522
|
+
hostName: hostId,
|
|
523
|
+
hypervisor: "proxmox",
|
|
524
|
+
status: "running",
|
|
525
|
+
ipAddresses: args.ipAddress ? [args.ipAddress] : [],
|
|
526
|
+
vlan: args.vlan,
|
|
527
|
+
linearIssue,
|
|
528
|
+
slotClaimId: claimedSlot.claimId,
|
|
529
|
+
taskUpid: cloneTask.upid,
|
|
530
|
+
createdAt: new Date().toISOString(),
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
else {
|
|
534
|
+
throw new Error("No hypervisor manager available to provision VM.");
|
|
535
|
+
}
|
|
536
|
+
createdVmId = provisionResult.vmId;
|
|
537
|
+
// 4. Attach VM ID/Name to Slot Lease
|
|
538
|
+
await context.slotManager.attachVm(claimedSlot.claimId, provisionResult.vmId, provisionResult.name);
|
|
539
|
+
// 5. Determine Guest IP Address
|
|
540
|
+
const assignedIp = args.ipAddress ||
|
|
541
|
+
(provisionResult.ipAddresses && provisionResult.ipAddresses.length > 0
|
|
542
|
+
? provisionResult.ipAddresses[0]
|
|
543
|
+
: `192.168.124.${100 + (Number(provisionResult.vmId) % 100 || 5)}`);
|
|
544
|
+
// 6. Polling Loop for SSH / Health Readiness
|
|
545
|
+
let healthStatus = "unverified";
|
|
546
|
+
let readyDurationMs = Date.now() - startTime;
|
|
547
|
+
if (waitForReady) {
|
|
548
|
+
const executor = context.applianceExecutor || applianceSshExecutor;
|
|
549
|
+
const pollStart = Date.now();
|
|
550
|
+
const timeoutMs = readyTimeoutSeconds * 1000;
|
|
551
|
+
let isReady = false;
|
|
552
|
+
while (Date.now() - pollStart < timeoutMs) {
|
|
553
|
+
try {
|
|
554
|
+
const connected = await executor.testConnection(assignedIp, 2222, 2000);
|
|
555
|
+
if (connected) {
|
|
556
|
+
isReady = true;
|
|
557
|
+
healthStatus = "healthy";
|
|
558
|
+
break;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
catch {
|
|
562
|
+
// continue polling
|
|
563
|
+
}
|
|
564
|
+
const elapsed = Date.now() - pollStart;
|
|
565
|
+
if (elapsed + 1000 < timeoutMs) {
|
|
566
|
+
await new Promise((r) => setTimeout(r, Math.min(1000, timeoutMs - elapsed)));
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
break;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
readyDurationMs = Date.now() - startTime;
|
|
573
|
+
if (!isReady) {
|
|
574
|
+
throw new Error(`VM readiness timed out after ${readyTimeoutSeconds}s on ${assignedIp}:2222 (healthStatus unverified).`);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
// 7. Deploy/Pin Target Release Version if Requested
|
|
578
|
+
let deployedVersion;
|
|
579
|
+
if (targetVersion) {
|
|
580
|
+
const executor = context.applianceExecutor || applianceSshExecutor;
|
|
581
|
+
const verRes = await executor.execute({
|
|
582
|
+
targetIp: assignedIp,
|
|
583
|
+
port: 2222,
|
|
584
|
+
commandType: "set_version",
|
|
585
|
+
args: { version: targetVersion },
|
|
586
|
+
timeoutMs: 60000,
|
|
587
|
+
});
|
|
588
|
+
if (verRes.exitCode !== 0) {
|
|
589
|
+
throw new Error(`Failed to deploy requested version '${targetVersion}' on ${assignedIp}: ${verRes.stderr || verRes.stdout}`);
|
|
590
|
+
}
|
|
591
|
+
deployedVersion = targetVersion;
|
|
592
|
+
}
|
|
593
|
+
// 8. Return Verified Endpoints & Summary
|
|
594
|
+
const autoResult = {
|
|
595
|
+
success: true,
|
|
596
|
+
slotId: claimedSlot.slotId,
|
|
597
|
+
claimId: claimedSlot.claimId,
|
|
598
|
+
vmId: provisionResult.vmId,
|
|
599
|
+
vmName: provisionResult.name,
|
|
600
|
+
host: claimedSlot.hostId,
|
|
601
|
+
hypervisorType: hypType,
|
|
602
|
+
ipAddress: assignedIp,
|
|
603
|
+
sshEndpoint: {
|
|
604
|
+
host: assignedIp,
|
|
605
|
+
port: 2222,
|
|
606
|
+
user: "admin",
|
|
607
|
+
},
|
|
608
|
+
apiEndpoint: `https://${assignedIp}:443`,
|
|
609
|
+
targetVersion,
|
|
610
|
+
deployedVersion,
|
|
611
|
+
workloadType,
|
|
612
|
+
label,
|
|
613
|
+
linearIssue,
|
|
614
|
+
branch,
|
|
615
|
+
tags: parsedTags,
|
|
616
|
+
expiresAt: claimedSlot.expiresAt,
|
|
617
|
+
readyDurationMs,
|
|
618
|
+
healthStatus,
|
|
619
|
+
};
|
|
620
|
+
const formatted = formatAutoProvisionResult(autoResult);
|
|
621
|
+
return {
|
|
622
|
+
content: [
|
|
623
|
+
{
|
|
624
|
+
type: "text",
|
|
625
|
+
text: formatted.markdown,
|
|
626
|
+
},
|
|
627
|
+
],
|
|
628
|
+
structuredContent: formatted.structuredContent,
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
catch (error) {
|
|
632
|
+
// Atomic Rollback: Release claimed slot if lease was acquired
|
|
633
|
+
if (claimedSlot) {
|
|
634
|
+
try {
|
|
635
|
+
await context.slotManager.releaseSlot(claimedSlot.claimId);
|
|
636
|
+
}
|
|
637
|
+
catch {
|
|
638
|
+
// ignore lease rollback error
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
// Atomic Rollback: Destroy created VM on hypervisor if created before failure
|
|
642
|
+
if (createdVmId && createdHost && context.hypervisorManager) {
|
|
643
|
+
try {
|
|
644
|
+
await context.hypervisorManager.vmAction({
|
|
645
|
+
targetHost: createdHost,
|
|
646
|
+
vmIdOrName: String(createdVmId),
|
|
647
|
+
action: "destroy",
|
|
648
|
+
force: true,
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
catch {
|
|
652
|
+
// ignore VM teardown error
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
if (error instanceof ProtectedVmViolationError) {
|
|
656
|
+
return createToolErrorResult(ProxmoxErrorCode.PROTECTED_VM_ACTION_DENIED, error.message, {
|
|
657
|
+
vmid: error.vmid,
|
|
658
|
+
vmName: error.vmName,
|
|
659
|
+
action: error.action,
|
|
660
|
+
reason: error.reason,
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
if (error instanceof CapacityExceededError ||
|
|
664
|
+
error instanceof GlobalCapacityExceededError ||
|
|
665
|
+
error instanceof DatastoreCapacityExceededError) {
|
|
666
|
+
return createToolErrorResult(ProxmoxErrorCode.CAPACITY_EXCEEDED, error.message);
|
|
667
|
+
}
|
|
668
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
669
|
+
return createToolErrorResult(ProxmoxErrorCode.UPSTREAM_API_ERROR, msg);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
289
672
|
//# sourceMappingURL=provision-tools.js.map
|