@aristanetworks/eos-mcp-server 0.8.1-beta → 0.9.0-beta

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +17 -14
  3. package/dist/commands/probe.js +2 -1
  4. package/dist/commands/probe.js.map +1 -1
  5. package/dist/config/diagnostics.d.ts +5 -0
  6. package/dist/config/diagnostics.js +5 -1
  7. package/dist/config/diagnostics.js.map +1 -1
  8. package/dist/config/loadConfig.js +1 -0
  9. package/dist/config/loadConfig.js.map +1 -1
  10. package/dist/config/schema.d.ts +95 -1
  11. package/dist/config/schema.js +14 -1
  12. package/dist/config/schema.js.map +1 -1
  13. package/dist/connection/eosDeviceReader.d.ts +6 -1
  14. package/dist/connection/eosDeviceReader.js +14 -3
  15. package/dist/connection/eosDeviceReader.js.map +1 -1
  16. package/dist/diagnostics/executor.d.ts +7 -3
  17. package/dist/diagnostics/executor.js +16 -13
  18. package/dist/diagnostics/executor.js.map +1 -1
  19. package/dist/diagnostics/types.d.ts +19 -2
  20. package/dist/mcp/createServer.js +20 -3
  21. package/dist/mcp/createServer.js.map +1 -1
  22. package/dist/mcp/tools/ping.d.ts +2 -2
  23. package/dist/operations/eapiSlots.d.ts +68 -0
  24. package/dist/operations/eapiSlots.js +237 -0
  25. package/dist/operations/eapiSlots.js.map +1 -0
  26. package/dist/operations/readExecution.js +1 -1
  27. package/dist/operations/readExecution.js.map +1 -1
  28. package/dist/serverInfo/buildServerInfo.js +2 -0
  29. package/dist/serverInfo/buildServerInfo.js.map +1 -1
  30. package/dist/serverInfo/types.d.ts +2 -0
  31. package/docs/CODE_WALKTHROUGH.md +3 -3
  32. package/docs/DEMO_SKILLS_YOUTUBE.md +346 -0
  33. package/docs/DESIGN.md +3 -3
  34. package/docs/DIAGNOSTICS.md +14 -11
  35. package/docs/adr/0005-multi-destination-ping.md +4 -0
  36. package/docs/adr/0006-in-memory-timed-diagnostic-capacity.md +2 -0
  37. package/docs/adr/0007-per-device-diagnostic-concurrency.md +16 -0
  38. package/docs/adr/0008-read-only-tool-annotations.md +16 -0
  39. package/docs/adr/0009-shared-per-device-eapi-slots.md +40 -0
  40. package/docs/research/eos-linter-integration.md +70 -0
  41. package/package.json +1 -1
  42. package/dist/diagnostics/concurrency.d.ts +0 -29
  43. package/dist/diagnostics/concurrency.js +0 -115
  44. package/dist/diagnostics/concurrency.js.map +0 -1
@@ -1,31 +1,34 @@
1
1
  import { AppError, toErrorCode } from "../core/errors.js";
2
2
  import { resolveInventoryTarget } from "../inventory/resolveTarget.js";
3
- import { buildDeviceResultSummary, buildReadDeviceFailure, buildReadDeviceSuccess, buildReadOperationResultEnvelope, enforceReadTargetLimit, mapWithConcurrency, runWithOperationTimeout } from "../operations/readExecution.js";
4
- import { DiagnosticConcurrency } from "./concurrency.js";
3
+ import { buildDeviceResultSummary, buildReadDeviceFailure, buildReadDeviceSuccess, buildReadOperationResultEnvelope, enforceReadTargetLimit, runWithOperationTimeout } from "../operations/readExecution.js";
4
+ import { EapiSlots, eapiSlotLimits } from "../operations/eapiSlots.js";
5
5
  import { DiagnosticExecutionError } from "./executionError.js";
6
6
  import { pingDiagnostic } from "./ping.js";
7
7
  const diagnosticDefinitions = {
8
8
  ping: pingDiagnostic
9
9
  };
10
- /** Owns policy, budgets, fan-out, global admission, cancellation, and result normalization. */
10
+ /** Owns policy, budgets, fan-out, cancellation, and result normalization. Admission, per device and
11
+ * server-wide, belongs to the EapiSlots it shares with read tools.
12
+ */
11
13
  export class DiagnosticExecutor {
12
14
  model;
13
15
  config;
14
16
  runner;
15
- concurrency;
17
+ slots;
16
18
  shutdown = new AbortController();
17
- constructor(model, config, runner) {
19
+ /** A running server passes its shared `slots`; tests may omit it to get a private instance. */
20
+ constructor(model, config, runner, slots = new EapiSlots(eapiSlotLimits(config), config.diagnostics.commandTimeoutMs)) {
18
21
  this.model = model;
19
22
  this.config = config;
20
23
  this.runner = runner;
21
- this.concurrency = new DiagnosticConcurrency(config.diagnostics.deviceConcurrency, config.diagnostics.commandTimeoutMs);
24
+ this.slots = slots;
22
25
  }
23
26
  close() {
24
27
  this.shutdown.abort(new AppError("diagnostic_server_stopping", "Diagnostic executor is stopping"));
25
- this.concurrency.close();
28
+ this.slots.close();
26
29
  }
27
30
  getCapacity() {
28
- return this.concurrency.snapshot();
31
+ return this.slots.snapshot();
29
32
  }
30
33
  async execute(options) {
31
34
  const signal = options.signal === undefined ? this.shutdown.signal : AbortSignal.any([options.signal, this.shutdown.signal]);
@@ -34,7 +37,6 @@ export class DiagnosticExecutor {
34
37
  const operationName = `eos_${options.request.kind}`;
35
38
  const operationConfig = {
36
39
  ...this.config,
37
- deviceConcurrency: this.config.diagnostics.deviceConcurrency,
38
40
  overallOperationTimeoutMs: this.config.diagnostics.overallOperationTimeoutMs
39
41
  };
40
42
  const resolvedTarget = resolveInventoryTarget(this.model, { target: options.target });
@@ -47,9 +49,10 @@ export class DiagnosticExecutor {
47
49
  if (resolvedTarget.resolvedHosts.length * probesPerHost > this.config.diagnostics.maxProbesPerRequest) {
48
50
  throw new AppError("diagnostic_probe_limit_exceeded", `Request exceeds maxProbesPerRequest ${this.config.diagnostics.maxProbesPerRequest}`);
49
51
  }
50
- // Each host/execution pair takes its own reservation; results stay in host-then-execution order.
52
+ // Each host/execution pair takes its own reservation, and all are queued at once so the admission
53
+ // controller, not fan-out order, decides which device runs next. Results stay in host-then-execution order.
51
54
  const hostExecutions = resolvedTarget.resolvedHosts.flatMap((host) => prepared.executions.map((execution) => ({ host, execution })));
52
- const results = await runWithOperationTimeout(operationConfig, operationName, (operationSignal) => mapWithConcurrency(hostExecutions, operationConfig.deviceConcurrency, async ({ host, execution }) => {
55
+ const results = await runWithOperationTimeout(operationConfig, operationName, (operationSignal) => Promise.all(hostExecutions.map(async ({ host, execution }) => {
53
56
  try {
54
57
  return await this.runExecution(definition, host, execution, operationSignal, options.includeRaw === true);
55
58
  }
@@ -62,7 +65,7 @@ export class DiagnosticExecutor {
62
65
  : {})
63
66
  };
64
67
  }
65
- }, operationSignal), signal);
68
+ })), signal);
66
69
  return buildReadOperationResultEnvelope(options.target, { resolvedTarget, results, summary: buildDeviceResultSummary(results) }, {
67
70
  extra: { request: prepared.request },
68
71
  responseSizeLimit: { config: this.config, operationName }
@@ -85,7 +88,7 @@ export class DiagnosticExecutor {
85
88
  }
86
89
  }
87
90
  async executeOnDevice(host, request, signal) {
88
- const reservation = await this.concurrency.acquire(signal, { inventoryHostname: host.inventoryHostname, diagnostic: request.kind });
91
+ const reservation = await this.slots.acquireDiagnostic(signal, { inventoryHostname: host.inventoryHostname, diagnostic: request.kind });
89
92
  if (signal.aborted) {
90
93
  reservation.complete();
91
94
  throw new AppError("operation_aborted", "Diagnostic was cancelled before dispatch");
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/diagnostics/executor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/diagnostics/executor.ts"],"names":[],"mappings":"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"}
@@ -61,12 +61,28 @@ export interface DiagnosticReservationInfo {
61
61
  releases_at?: string;
62
62
  reason_code?: string;
63
63
  }
64
- export interface DiagnosticCapacitySnapshot {
65
- limit: number;
64
+ interface DiagnosticSlotCounts {
66
65
  available_count: number;
67
66
  active_count: number;
68
67
  uncertain_count: number;
69
68
  queued_count: number;
69
+ }
70
+ /** Slot usage of one inventory host; only hosts holding or awaiting a slot are listed.
71
+ * The four shared counts are diagnostic slots; `available_count` is the diagnostic headroom,
72
+ * capped by the host's shared eAPI headroom and server-wide availability.
73
+ */
74
+ export interface DiagnosticDeviceCapacity extends DiagnosticSlotCounts {
75
+ inventory_hostname: string;
76
+ read_active_count: number;
77
+ read_queued_count: number;
78
+ }
79
+ /** Top-level counts are server-wide diagnostics; `devices` breaks them down per host, with reads. */
80
+ export interface DiagnosticCapacitySnapshot extends DiagnosticSlotCounts {
81
+ limit: number;
82
+ device_limit: number;
83
+ /** eAPI slots one host may hold across reads and diagnostics. */
84
+ eapi_device_limit: number;
85
+ devices: DiagnosticDeviceCapacity[];
70
86
  reservations: DiagnosticReservationInfo[];
71
87
  }
72
88
  export interface DiagnosticExecutionContext {
@@ -79,3 +95,4 @@ export interface DiagnosticExecutionContext {
79
95
  export interface DiagnosticDeviceRunner {
80
96
  execute(host: InventoryHostModel, request: PreparedDiagnostic, context: DiagnosticExecutionContext): Promise<DiagnosticObservation>;
81
97
  }
98
+ export {};
@@ -7,6 +7,7 @@ import { toErrorMessage } from "../core/errors.js";
7
7
  import { EapiClient } from "../eapi/client.js";
8
8
  import { EapiDiagnosticRunner } from "../diagnostics/eapiRunner.js";
9
9
  import { DiagnosticExecutor } from "../diagnostics/executor.js";
10
+ import { EapiSlots, eapiSlotLimits } from "../operations/eapiSlots.js";
10
11
  import { buildPingToolResult, pingInputSchema } from "./tools/ping.js";
11
12
  import { buildGetFactsToolResult, getFactsInputSchema } from "./tools/getFacts.js";
12
13
  import { buildGetRunningConfigToolResult, getRunningConfigInputSchema } from "./tools/getRunningConfig.js";
@@ -15,54 +16,68 @@ import { buildListInventoryToolResult, listInventoryInputSchema } from "./tools/
15
16
  import { buildProbeDevicesToolResult, probeDevicesInputSchema } from "./tools/probeDevices.js";
16
17
  import { buildRunShowToolResult, runShowInputSchema } from "./tools/runShow.js";
17
18
  import { buildShowLoggingToolResult, showLoggingInputSchema } from "./tools/showLogging.js";
19
+ // Every tool leaves device state unchanged, which lets clients run independent
20
+ // calls concurrently; server-side limits still bound diagnostics (ADR 0008).
21
+ // Most tools reach only inventory devices.
22
+ const closedWorldReadOnly = { readOnlyHint: true, openWorldHint: false };
23
+ // Ping destinations need not be in inventory.
24
+ const openWorldReadOnly = { readOnlyHint: true, openWorldHint: true };
18
25
  function buildToolDefinitions(deps) {
19
26
  return [
20
27
  {
21
28
  name: "eos_get_server_info",
22
29
  description: "Return a sanitized summary of current server capabilities, limits, runtime mode, and inventory summary.",
23
30
  inputSchema: getServerInfoInputSchema,
31
+ annotations: closedWorldReadOnly,
24
32
  handler: async () => buildGetServerInfoToolResult(deps.runtimeContext, deps.diagnostics.getCapacity())
25
33
  },
26
34
  {
27
35
  name: "eos_list_inventory",
28
36
  description: "Return a sanitized operational view of the loaded inventory. By default only EOS-eligible hosts are shown, while all groups remain visible with actionable status.",
29
37
  inputSchema: listInventoryInputSchema,
38
+ annotations: closedWorldReadOnly,
30
39
  handler: async (args) => buildListInventoryToolResult(deps.inventoryModel, args)
31
40
  },
32
41
  {
33
42
  name: "eos_probe_devices",
34
43
  description: "Probe EOS device readiness for a host or group target by validating connectivity, authentication, and harmless command execution.",
35
44
  inputSchema: probeDevicesInputSchema,
45
+ annotations: closedWorldReadOnly,
36
46
  handler: async (args) => buildProbeDevicesToolResult(deps.inventoryModel, deps.config, args, deps.deviceReader)
37
47
  },
38
48
  {
39
49
  name: "eos_ping",
40
50
  description: "Run bounded, non-configuring ping diagnostics from an inventory host or group to one or more destinations concurrently. Requires explicit diagnostic permission. Destinations are unicast IP literals. Returns one result per host and destination; execution success is separate from reachability, and no replies do not identify a cause.",
41
51
  inputSchema: pingInputSchema,
52
+ annotations: openWorldReadOnly,
42
53
  handler: async (args, extra) => buildPingToolResult(args, deps.diagnostics, extra.signal)
43
54
  },
44
55
  {
45
56
  name: "eos_run_show",
46
57
  description: "Run one or more EOS show commands against a host or group target. Supports auto/json/text output modes with strict show-only validation.",
47
58
  inputSchema: runShowInputSchema,
59
+ annotations: closedWorldReadOnly,
48
60
  handler: async (args) => buildRunShowToolResult(deps.inventoryModel, deps.config, args, deps.deviceReader)
49
61
  },
50
62
  {
51
63
  name: "eos_show_logging",
52
64
  description: "Retrieve bounded EOS logging output for a host or group target using a minimum severity threshold and message-count limit.",
53
65
  inputSchema: showLoggingInputSchema,
66
+ annotations: closedWorldReadOnly,
54
67
  handler: async (args) => buildShowLoggingToolResult(deps.inventoryModel, deps.config, args, deps.deviceReader)
55
68
  },
56
69
  {
57
70
  name: "eos_get_facts",
58
71
  description: "Collect a fixed core set of EOS device facts for a host or group target.",
59
72
  inputSchema: getFactsInputSchema,
73
+ annotations: closedWorldReadOnly,
60
74
  handler: async (args) => buildGetFactsToolResult(deps.inventoryModel, deps.config, args, deps.deviceReader)
61
75
  },
62
76
  {
63
77
  name: "eos_get_running_config",
64
78
  description: "Retrieve running configuration text for a host target, or for a group target when a raw EOS section selector is provided.",
65
79
  inputSchema: getRunningConfigInputSchema,
80
+ annotations: closedWorldReadOnly,
66
81
  handler: async (args) => buildGetRunningConfigToolResult(deps.inventoryModel, deps.config, args, deps.deviceReader)
67
82
  }
68
83
  ];
@@ -75,8 +90,9 @@ export async function startMcpServer(config, inventoryModel) {
75
90
  inventorySummary: inventoryModel.summary
76
91
  };
77
92
  const client = new EapiClient();
78
- const deviceReader = new EapiDeviceReader(config, client);
79
- const diagnostics = new DiagnosticExecutor(inventoryModel, config, new EapiDiagnosticRunner(config, client));
93
+ const slots = new EapiSlots(eapiSlotLimits(config), config.diagnostics.commandTimeoutMs);
94
+ const deviceReader = new EapiDeviceReader(config, client, slots);
95
+ const diagnostics = new DiagnosticExecutor(inventoryModel, config, new EapiDiagnosticRunner(config, client), slots);
80
96
  const server = new McpServer({
81
97
  name: APP_NAME,
82
98
  version: APP_VERSION
@@ -85,7 +101,8 @@ export async function startMcpServer(config, inventoryModel) {
85
101
  for (const tool of buildToolDefinitions({ runtimeContext, inventoryModel, config, deviceReader, diagnostics })) {
86
102
  registerTool(tool.name, {
87
103
  description: tool.description,
88
- inputSchema: tool.inputSchema
104
+ inputSchema: tool.inputSchema,
105
+ annotations: tool.annotations
89
106
  }, tool.handler);
90
107
  }
91
108
  const stop = () => {
@@ -1 +1 @@
1
- {"version":3,"file":"createServer.js","sourceRoot":"","sources":["../../src/mcp/createServer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"createServer.js","sourceRoot":"","sources":["../../src/mcp/createServer.ts"],"names":[],"mappings":"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"}
@@ -8,15 +8,15 @@ export declare const pingInputSchema: z.ZodObject<{
8
8
  source: z.ZodOptional<z.ZodString>;
9
9
  include_raw: z.ZodDefault<z.ZodBoolean>;
10
10
  }, "strict", z.ZodTypeAny, {
11
- target: string;
12
11
  destinations: string[];
12
+ target: string;
13
13
  include_raw: boolean;
14
14
  count?: number | undefined;
15
15
  vrf?: string | undefined;
16
16
  source?: string | undefined;
17
17
  }, {
18
- target: string;
19
18
  destinations: string[];
19
+ target: string;
20
20
  count?: number | undefined;
21
21
  vrf?: string | undefined;
22
22
  source?: string | undefined;
@@ -0,0 +1,68 @@
1
+ import type { DiagnosticCapacitySnapshot, DiagnosticRequest } from "../diagnostics/types.js";
2
+ interface DiagnosticReservationIntent {
3
+ inventoryHostname: string;
4
+ diagnostic: DiagnosticRequest["kind"];
5
+ }
6
+ export interface DiagnosticReservation {
7
+ readonly requestId: string;
8
+ complete(): void;
9
+ markUncertain(reasonCode: string): void;
10
+ }
11
+ export interface EapiSlotLimits {
12
+ /** Slots one inventory host may hold across reads and diagnostics. */
13
+ deviceLimit: number;
14
+ /** Of those, the slots diagnostics may hold on one host, so the rest stay free for reads. */
15
+ diagnosticDeviceLimit: number;
16
+ /** Diagnostic slots shared by every device in the server process. Reads have no server-wide limit. */
17
+ diagnosticServerLimit: number;
18
+ }
19
+ /** One instance per server process, shared by every eAPI request (ADR 0009). A slot is granted only
20
+ * while its device has room and, for a diagnostic, its device's diagnostic share and the server-wide
21
+ * diagnostic ceiling have room; waiters are served oldest first, skipping those that cannot run yet
22
+ * (ADR 0007). A read frees its slot when its request settles. A diagnostic slot with unknown remote
23
+ * completion stays held for the execution budget, then frees itself; a late confirmed response frees
24
+ * it sooner (ADR 0006).
25
+ */
26
+ export declare class EapiSlots {
27
+ private readonly limits;
28
+ private readonly uncertainHoldMs;
29
+ /** Held diagnostic slots; an uncertain slot carries the timer that frees it. */
30
+ private readonly reservations;
31
+ private readonly readsHeldByDevice;
32
+ private readonly waiting;
33
+ private closed;
34
+ constructor(limits: EapiSlotLimits, uncertainHoldMs: number);
35
+ close(): void;
36
+ /** Top-level counts cover diagnostics; `devices` also shows each host's read slots. */
37
+ snapshot(): DiagnosticCapacitySnapshot;
38
+ /** Per-host counts for every host holding or awaiting a slot, sorted by hostname. */
39
+ private deviceBreakdown;
40
+ /** Waits for a read slot on the host; the returned function frees it. */
41
+ acquireRead(signal: AbortSignal | undefined, inventoryHostname: string): Promise<() => void>;
42
+ acquireDiagnostic(signal: AbortSignal | undefined, intent: DiagnosticReservationIntent): Promise<DiagnosticReservation>;
43
+ private enqueue;
44
+ private hasRoom;
45
+ /** Diagnostic slots a host could take now: the tightest of its diagnostic share, its shared device
46
+ * slots, and the server-wide diagnostic slots still free. Admission and the snapshot both use it.
47
+ */
48
+ private diagnosticHeadroom;
49
+ /** Counted from the held reservations, which never exceed the server-wide diagnostic limit. */
50
+ private diagnosticSlotsHeldBy;
51
+ private reserveRead;
52
+ /** Keeps only hosts that hold reads, so the snapshot lists no idle hosts. */
53
+ private adjustReadsHeld;
54
+ private reserveDiagnostic;
55
+ private freeDiagnostic;
56
+ /** Grant the oldest waiters that can run now; a waiter that cannot run yet keeps its place. */
57
+ private grantWaiting;
58
+ private markUncertain;
59
+ }
60
+ /** Limits from config: top-level `deviceConcurrency` per device, `diagnostics.*` for the diagnostic share. */
61
+ export declare function eapiSlotLimits(config: {
62
+ deviceConcurrency: number;
63
+ diagnostics: {
64
+ deviceConcurrency: number;
65
+ maxConcurrentDiagnostics: number;
66
+ };
67
+ }): EapiSlotLimits;
68
+ export {};
@@ -0,0 +1,237 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { AppError } from "../core/errors.js";
3
+ /** One instance per server process, shared by every eAPI request (ADR 0009). A slot is granted only
4
+ * while its device has room and, for a diagnostic, its device's diagnostic share and the server-wide
5
+ * diagnostic ceiling have room; waiters are served oldest first, skipping those that cannot run yet
6
+ * (ADR 0007). A read frees its slot when its request settles. A diagnostic slot with unknown remote
7
+ * completion stays held for the execution budget, then frees itself; a late confirmed response frees
8
+ * it sooner (ADR 0006).
9
+ */
10
+ export class EapiSlots {
11
+ limits;
12
+ uncertainHoldMs;
13
+ /** Held diagnostic slots; an uncertain slot carries the timer that frees it. */
14
+ reservations = new Map();
15
+ readsHeldByDevice = new Map();
16
+ waiting = [];
17
+ closed = false;
18
+ constructor(limits, uncertainHoldMs) {
19
+ this.limits = limits;
20
+ this.uncertainHoldMs = uncertainHoldMs;
21
+ }
22
+ close() {
23
+ if (this.closed)
24
+ return;
25
+ this.closed = true;
26
+ for (const timer of this.reservations.values())
27
+ clearTimeout(timer);
28
+ const error = closedError();
29
+ for (const waiter of this.waiting.splice(0))
30
+ waiter.reject(error);
31
+ }
32
+ /** Top-level counts cover diagnostics; `devices` also shows each host's read slots. */
33
+ snapshot() {
34
+ const reservations = Array.from(this.reservations.keys(), (reservation) => ({ ...reservation }));
35
+ const uncertain = reservations.filter((reservation) => reservation.state === "uncertain").length;
36
+ const serverAvailable = this.closed ? 0 : Math.max(0, this.limits.diagnosticServerLimit - reservations.length);
37
+ const queuedDiagnostics = this.waiting.filter((waiter) => waiter.kind === "diagnostic").length;
38
+ return {
39
+ limit: this.limits.diagnosticServerLimit,
40
+ device_limit: this.limits.diagnosticDeviceLimit,
41
+ eapi_device_limit: this.limits.deviceLimit,
42
+ available_count: serverAvailable,
43
+ active_count: reservations.length - uncertain,
44
+ uncertain_count: uncertain,
45
+ queued_count: queuedDiagnostics,
46
+ devices: this.deviceBreakdown(reservations, serverAvailable),
47
+ reservations
48
+ };
49
+ }
50
+ /** Per-host counts for every host holding or awaiting a slot, sorted by hostname. */
51
+ deviceBreakdown(reservations, serverAvailable) {
52
+ const devices = new Map();
53
+ const deviceEntry = (inventoryHostname) => {
54
+ let entry = devices.get(inventoryHostname);
55
+ if (entry === undefined) {
56
+ entry = {
57
+ inventory_hostname: inventoryHostname,
58
+ available_count: 0, active_count: 0, uncertain_count: 0, queued_count: 0,
59
+ read_active_count: 0, read_queued_count: 0
60
+ };
61
+ devices.set(inventoryHostname, entry);
62
+ }
63
+ return entry;
64
+ };
65
+ for (const reservation of reservations) {
66
+ const entry = deviceEntry(reservation.inventory_hostname);
67
+ if (reservation.state === "uncertain")
68
+ entry.uncertain_count += 1;
69
+ else
70
+ entry.active_count += 1;
71
+ }
72
+ for (const [inventoryHostname, readsHeld] of this.readsHeldByDevice)
73
+ deviceEntry(inventoryHostname).read_active_count = readsHeld;
74
+ for (const waiter of this.waiting) {
75
+ const entry = deviceEntry(waiter.inventoryHostname);
76
+ if (waiter.kind === "diagnostic")
77
+ entry.queued_count += 1;
78
+ else
79
+ entry.read_queued_count += 1;
80
+ }
81
+ for (const entry of devices.values()) {
82
+ entry.available_count = this.diagnosticHeadroom(entry.active_count + entry.uncertain_count, entry.read_active_count, serverAvailable);
83
+ }
84
+ return Array.from(devices.values()).sort((left, right) => left.inventory_hostname.localeCompare(right.inventory_hostname));
85
+ }
86
+ /** Waits for a read slot on the host; the returned function frees it. */
87
+ acquireRead(signal, inventoryHostname) {
88
+ return this.enqueue(signal, inventoryHostname, "read", () => this.reserveRead(inventoryHostname));
89
+ }
90
+ acquireDiagnostic(signal, intent) {
91
+ return this.enqueue(signal, intent.inventoryHostname, "diagnostic", () => this.reserveDiagnostic(intent));
92
+ }
93
+ enqueue(signal, inventoryHostname, kind, reserve) {
94
+ return new Promise((resolve, reject) => {
95
+ if (signal?.aborted === true) {
96
+ reject(abortedError());
97
+ return;
98
+ }
99
+ if (this.closed) {
100
+ reject(closedError());
101
+ return;
102
+ }
103
+ const cancelled = () => {
104
+ const index = this.waiting.indexOf(waiter);
105
+ if (index >= 0)
106
+ this.waiting.splice(index, 1);
107
+ waiter.reject(abortedError());
108
+ };
109
+ const stopListening = () => signal?.removeEventListener("abort", cancelled);
110
+ const waiter = {
111
+ inventoryHostname,
112
+ kind,
113
+ reject: (error) => {
114
+ stopListening();
115
+ reject(error);
116
+ },
117
+ grant: () => {
118
+ stopListening();
119
+ resolve(reserve());
120
+ }
121
+ };
122
+ if (this.hasRoom(waiter)) {
123
+ waiter.grant();
124
+ }
125
+ else {
126
+ this.waiting.push(waiter);
127
+ signal?.addEventListener("abort", cancelled, { once: true });
128
+ }
129
+ });
130
+ }
131
+ hasRoom(waiter) {
132
+ const diagnosticsHeld = this.diagnosticSlotsHeldBy(waiter.inventoryHostname);
133
+ const readsHeld = this.readsHeldByDevice.get(waiter.inventoryHostname) ?? 0;
134
+ if (waiter.kind === "read")
135
+ return diagnosticsHeld + readsHeld < this.limits.deviceLimit;
136
+ return this.diagnosticHeadroom(diagnosticsHeld, readsHeld, this.limits.diagnosticServerLimit - this.reservations.size) > 0;
137
+ }
138
+ /** Diagnostic slots a host could take now: the tightest of its diagnostic share, its shared device
139
+ * slots, and the server-wide diagnostic slots still free. Admission and the snapshot both use it.
140
+ */
141
+ diagnosticHeadroom(diagnosticsHeld, readsHeld, serverAvailable) {
142
+ const diagnosticShareLeft = this.limits.diagnosticDeviceLimit - diagnosticsHeld;
143
+ const deviceSlotsLeft = this.limits.deviceLimit - diagnosticsHeld - readsHeld;
144
+ return Math.max(0, Math.min(diagnosticShareLeft, deviceSlotsLeft, serverAvailable));
145
+ }
146
+ /** Counted from the held reservations, which never exceed the server-wide diagnostic limit. */
147
+ diagnosticSlotsHeldBy(inventoryHostname) {
148
+ let held = 0;
149
+ for (const reservation of this.reservations.keys()) {
150
+ if (reservation.inventory_hostname === inventoryHostname)
151
+ held += 1;
152
+ }
153
+ return held;
154
+ }
155
+ reserveRead(inventoryHostname) {
156
+ this.adjustReadsHeld(inventoryHostname, 1);
157
+ let released = false;
158
+ return () => {
159
+ if (released)
160
+ return;
161
+ released = true;
162
+ this.adjustReadsHeld(inventoryHostname, -1);
163
+ this.grantWaiting();
164
+ };
165
+ }
166
+ /** Keeps only hosts that hold reads, so the snapshot lists no idle hosts. */
167
+ adjustReadsHeld(inventoryHostname, change) {
168
+ const readsHeld = (this.readsHeldByDevice.get(inventoryHostname) ?? 0) + change;
169
+ if (readsHeld > 0)
170
+ this.readsHeldByDevice.set(inventoryHostname, readsHeld);
171
+ else
172
+ this.readsHeldByDevice.delete(inventoryHostname);
173
+ }
174
+ reserveDiagnostic(intent) {
175
+ const requestId = randomUUID();
176
+ const state = {
177
+ reservation_id: requestId,
178
+ inventory_hostname: intent.inventoryHostname,
179
+ diagnostic: intent.diagnostic,
180
+ state: "active",
181
+ reserved_at: new Date().toISOString()
182
+ };
183
+ this.reservations.set(state, undefined);
184
+ return {
185
+ requestId,
186
+ complete: () => this.freeDiagnostic(state),
187
+ markUncertain: (reasonCode) => this.markUncertain(state, reasonCode)
188
+ };
189
+ }
190
+ freeDiagnostic(state) {
191
+ if (!this.reservations.has(state))
192
+ return;
193
+ clearTimeout(this.reservations.get(state));
194
+ this.reservations.delete(state);
195
+ this.grantWaiting();
196
+ }
197
+ /** Grant the oldest waiters that can run now; a waiter that cannot run yet keeps its place. */
198
+ grantWaiting() {
199
+ let index = 0;
200
+ while (index < this.waiting.length) {
201
+ const waiter = this.waiting[index];
202
+ if (waiter !== undefined && this.hasRoom(waiter)) {
203
+ this.waiting.splice(index, 1);
204
+ waiter.grant();
205
+ }
206
+ else {
207
+ index += 1;
208
+ }
209
+ }
210
+ }
211
+ markUncertain(state, reasonCode) {
212
+ if (this.closed || !this.reservations.has(state) || state.state === "uncertain")
213
+ return;
214
+ const now = Date.now();
215
+ state.state = "uncertain";
216
+ state.uncertain_since = new Date(now).toISOString();
217
+ state.releases_at = new Date(now + this.uncertainHoldMs).toISOString();
218
+ state.reason_code = reasonCode;
219
+ // Unref so a held slot never keeps a stopping server alive.
220
+ this.reservations.set(state, setTimeout(() => this.freeDiagnostic(state), this.uncertainHoldMs).unref());
221
+ }
222
+ }
223
+ /** Limits from config: top-level `deviceConcurrency` per device, `diagnostics.*` for the diagnostic share. */
224
+ export function eapiSlotLimits(config) {
225
+ return {
226
+ deviceLimit: config.deviceConcurrency,
227
+ diagnosticDeviceLimit: config.diagnostics.deviceConcurrency,
228
+ diagnosticServerLimit: config.diagnostics.maxConcurrentDiagnostics
229
+ };
230
+ }
231
+ function closedError() {
232
+ return new AppError("diagnostic_server_stopping", "eAPI execution is shutting down");
233
+ }
234
+ function abortedError() {
235
+ return new AppError("operation_aborted", "Request was cancelled while waiting for device capacity");
236
+ }
237
+ //# sourceMappingURL=eapiSlots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eapiSlots.js","sourceRoot":"","sources":["../../src/operations/eapiSlots.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,7 @@ export async function executeReadOperation(model, config, options) {
4
4
  const resolvedTarget = resolveInventoryTarget(model, { target: options.target });
5
5
  enforceReadTargetLimit(config, resolvedTarget.resolvedHosts.length);
6
6
  options.validateTarget?.(resolvedTarget);
7
- const results = await runWithOperationTimeout(config, options.operationName, (signal) => mapWithConcurrency(resolvedTarget.resolvedHosts, config.deviceConcurrency, async (host) => {
7
+ const results = await runWithOperationTimeout(config, options.operationName, (signal) => mapWithConcurrency(resolvedTarget.resolvedHosts, config.readFanOut, async (host) => {
8
8
  try {
9
9
  return await options.run(host, signal);
10
10
  }