@sonde/packs 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.
Files changed (105) hide show
  1. package/.turbo/turbo-build.log +6 -4
  2. package/.turbo/turbo-test.log +1343 -53
  3. package/CHANGELOG.md +18 -0
  4. package/dist/docker/manifest (# Edit conflict 2026-02-19 LIl7ilN #).js +54 -0
  5. package/dist/index.d.ts +9 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +9 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/integrations/a10.d.ts +3 -0
  10. package/dist/integrations/a10.d.ts.map +1 -0
  11. package/dist/integrations/a10.js +218 -0
  12. package/dist/integrations/a10.js.map +1 -0
  13. package/dist/integrations/checkpoint.d.ts +3 -0
  14. package/dist/integrations/checkpoint.d.ts.map +1 -0
  15. package/dist/integrations/checkpoint.js +249 -0
  16. package/dist/integrations/checkpoint.js.map +1 -0
  17. package/dist/integrations/datadog.d.ts +3 -0
  18. package/dist/integrations/datadog.d.ts.map +1 -0
  19. package/dist/integrations/datadog.js +195 -0
  20. package/dist/integrations/datadog.js.map +1 -0
  21. package/dist/integrations/jira.d.ts +3 -0
  22. package/dist/integrations/jira.d.ts.map +1 -0
  23. package/dist/integrations/jira.js +199 -0
  24. package/dist/integrations/jira.js.map +1 -0
  25. package/dist/integrations/loki.d.ts +3 -0
  26. package/dist/integrations/loki.d.ts.map +1 -0
  27. package/dist/integrations/loki.js +178 -0
  28. package/dist/integrations/loki.js.map +1 -0
  29. package/dist/integrations/meraki.d.ts +3 -0
  30. package/dist/integrations/meraki.d.ts.map +1 -0
  31. package/dist/integrations/meraki.js +238 -0
  32. package/dist/integrations/meraki.js.map +1 -0
  33. package/dist/integrations/pagerduty.d.ts +3 -0
  34. package/dist/integrations/pagerduty.d.ts.map +1 -0
  35. package/dist/integrations/pagerduty.js +229 -0
  36. package/dist/integrations/pagerduty.js.map +1 -0
  37. package/dist/integrations/thousandeyes.d.ts +3 -0
  38. package/dist/integrations/thousandeyes.d.ts.map +1 -0
  39. package/dist/integrations/thousandeyes.js +263 -0
  40. package/dist/integrations/thousandeyes.js.map +1 -0
  41. package/dist/integrations/vcenter.d.ts +3 -0
  42. package/dist/integrations/vcenter.d.ts.map +1 -0
  43. package/dist/integrations/vcenter.js +190 -0
  44. package/dist/integrations/vcenter.js.map +1 -0
  45. package/dist/proxmox/probes/ceph-status.test.d.ts (# Edit conflict 2026-02-19 N25hAvJ #).map +1 -0
  46. package/dist/system/index.d.ts.map +1 -1
  47. package/dist/system/index.js +8 -0
  48. package/dist/system/index.js.map +1 -1
  49. package/dist/system/manifest.d.ts.map +1 -1
  50. package/dist/system/manifest.js +82 -3
  51. package/dist/system/manifest.js.map +1 -1
  52. package/dist/system/probes/logs-dmesg.d.ts +13 -0
  53. package/dist/system/probes/logs-dmesg.d.ts.map +1 -0
  54. package/dist/system/probes/logs-dmesg.js +22 -0
  55. package/dist/system/probes/logs-dmesg.js.map +1 -0
  56. package/dist/system/probes/logs-dmesg.test.d.ts +2 -0
  57. package/dist/system/probes/logs-dmesg.test.d.ts.map +1 -0
  58. package/dist/system/probes/logs-dmesg.test.js +55 -0
  59. package/dist/system/probes/logs-dmesg.test.js.map +1 -0
  60. package/dist/system/probes/logs-journal.d.ts +21 -0
  61. package/dist/system/probes/logs-journal.d.ts.map +1 -0
  62. package/dist/system/probes/logs-journal.js +70 -0
  63. package/dist/system/probes/logs-journal.js.map +1 -0
  64. package/dist/system/probes/logs-journal.test.d.ts +2 -0
  65. package/dist/system/probes/logs-journal.test.d.ts.map +1 -0
  66. package/dist/system/probes/logs-journal.test.js +113 -0
  67. package/dist/system/probes/logs-journal.test.js.map +1 -0
  68. package/dist/system/probes/logs-tail.d.ts +14 -0
  69. package/dist/system/probes/logs-tail.d.ts.map +1 -0
  70. package/dist/system/probes/logs-tail.js +40 -0
  71. package/dist/system/probes/logs-tail.js.map +1 -0
  72. package/dist/system/probes/logs-tail.test.d.ts +2 -0
  73. package/dist/system/probes/logs-tail.test.d.ts.map +1 -0
  74. package/dist/system/probes/logs-tail.test.js +82 -0
  75. package/dist/system/probes/logs-tail.test.js.map +1 -0
  76. package/dist/system/probes/traceroute.d.ts +17 -0
  77. package/dist/system/probes/traceroute.d.ts.map +1 -0
  78. package/dist/system/probes/traceroute.js +72 -0
  79. package/dist/system/probes/traceroute.js.map +1 -0
  80. package/dist/system/probes/traceroute.test.d.ts +2 -0
  81. package/dist/system/probes/traceroute.test.d.ts.map +1 -0
  82. package/dist/system/probes/traceroute.test.js +98 -0
  83. package/dist/system/probes/traceroute.test.js.map +1 -0
  84. package/package.json +1 -1
  85. package/src/index.ts +9 -0
  86. package/src/integrations/a10.ts +370 -0
  87. package/src/integrations/checkpoint.ts +381 -0
  88. package/src/integrations/datadog.ts +281 -0
  89. package/src/integrations/jira.ts +272 -0
  90. package/src/integrations/loki.ts +228 -0
  91. package/src/integrations/meraki.ts +344 -0
  92. package/src/integrations/pagerduty.ts +319 -0
  93. package/src/integrations/thousandeyes.ts +353 -0
  94. package/src/integrations/vcenter.ts +261 -0
  95. package/src/system/index.ts +8 -0
  96. package/src/system/manifest.ts +93 -3
  97. package/src/system/probes/logs-dmesg.test.ts +83 -0
  98. package/src/system/probes/logs-dmesg.ts +38 -0
  99. package/src/system/probes/logs-journal.test.ts +142 -0
  100. package/src/system/probes/logs-journal.ts +103 -0
  101. package/src/system/probes/logs-tail.test.ts +140 -0
  102. package/src/system/probes/logs-tail.ts +70 -0
  103. package/src/system/probes/traceroute.test.ts +149 -0
  104. package/src/system/probes/traceroute.ts +99 -0
  105. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,98 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { parseTracerouteOutput, traceroute, } from './traceroute.js';
3
+ const LINUX_TRACEROUTE = `traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets
4
+ 1 192.168.1.1 1.234 ms 1.100 ms 1.050 ms
5
+ 2 10.0.0.1 5.432 ms 5.300 ms 5.200 ms
6
+ 3 * * *
7
+ 4 172.16.0.1 15.678 ms 15.500 ms 15.400 ms
8
+ 5 8.8.8.8 20.123 ms 20.050 ms 19.900 ms`;
9
+ const MACOS_TRACEROUTE = `traceroute to 1.1.1.1 (1.1.1.1), 30 hops max, 60 byte packets
10
+ 1 192.168.0.1 2.345 ms 2.100 ms 2.050 ms
11
+ 2 * * *
12
+ 3 1.1.1.1 10.567 ms 10.400 ms 10.300 ms`;
13
+ const ALL_TIMEOUT = `traceroute to 10.0.0.99 (10.0.0.99), 5 hops max, 60 byte packets
14
+ 1 * * *
15
+ 2 * * *
16
+ 3 * * *`;
17
+ describe('parseTracerouteOutput', () => {
18
+ it('parses Linux traceroute with mixed hops', () => {
19
+ const result = parseTracerouteOutput(LINUX_TRACEROUTE, '8.8.8.8');
20
+ expect(result.host).toBe('8.8.8.8');
21
+ expect(result.hops).toHaveLength(5);
22
+ // Hop 1: normal response
23
+ expect(result.hops[0]?.hop).toBe(1);
24
+ expect(result.hops[0]?.ip).toBe('192.168.1.1');
25
+ expect(result.hops[0]?.rttMs).toEqual([1.234, 1.1, 1.05]);
26
+ // Hop 3: all timeouts
27
+ expect(result.hops[2]?.hop).toBe(3);
28
+ expect(result.hops[2]?.ip).toBeNull();
29
+ expect(result.hops[2]?.rttMs).toEqual([null, null, null]);
30
+ // Hop 5: destination
31
+ expect(result.hops[4]?.hop).toBe(5);
32
+ expect(result.hops[4]?.ip).toBe('8.8.8.8');
33
+ expect(result.hops[4]?.rttMs).toEqual([20.123, 20.05, 19.9]);
34
+ });
35
+ it('parses macOS traceroute output', () => {
36
+ const result = parseTracerouteOutput(MACOS_TRACEROUTE, '1.1.1.1');
37
+ expect(result.host).toBe('1.1.1.1');
38
+ expect(result.hops).toHaveLength(3);
39
+ expect(result.hops[0]?.ip).toBe('192.168.0.1');
40
+ expect(result.hops[1]?.ip).toBeNull();
41
+ expect(result.hops[2]?.ip).toBe('1.1.1.1');
42
+ });
43
+ it('handles all-timeout output', () => {
44
+ const result = parseTracerouteOutput(ALL_TIMEOUT, '10.0.0.99');
45
+ expect(result.hops).toHaveLength(3);
46
+ for (const hop of result.hops) {
47
+ expect(hop.ip).toBeNull();
48
+ expect(hop.rttMs).toEqual([null, null, null]);
49
+ }
50
+ });
51
+ it('handles empty output', () => {
52
+ const result = parseTracerouteOutput('', '8.8.8.8');
53
+ expect(result.hops).toHaveLength(0);
54
+ });
55
+ });
56
+ describe('traceroute handler', () => {
57
+ it('throws when host is missing', async () => {
58
+ const mockExec = async () => '';
59
+ await expect(traceroute(undefined, mockExec)).rejects.toThrow('Missing required parameter: host');
60
+ await expect(traceroute({}, mockExec)).rejects.toThrow('Missing required parameter: host');
61
+ });
62
+ it('passes correct args with defaults', async () => {
63
+ const calls = [];
64
+ const mockExec = async (cmd, args) => {
65
+ calls.push({ cmd, args });
66
+ return LINUX_TRACEROUTE;
67
+ };
68
+ const result = (await traceroute({ host: '8.8.8.8' }, mockExec));
69
+ expect(calls).toHaveLength(1);
70
+ expect(calls[0]?.cmd).toBe('traceroute');
71
+ expect(calls[0]?.args).toEqual([
72
+ '-n', '-m', '30', '-w', '2', '8.8.8.8',
73
+ ]);
74
+ expect(result.host).toBe('8.8.8.8');
75
+ expect(result.hops).toHaveLength(5);
76
+ });
77
+ it('respects custom maxHops', async () => {
78
+ const calls = [];
79
+ const mockExec = async (cmd, args) => {
80
+ calls.push({ cmd, args });
81
+ return '';
82
+ };
83
+ await traceroute({ host: '8.8.8.8', maxHops: 10 }, mockExec);
84
+ expect(calls[0]?.args).toContain('10');
85
+ });
86
+ it('clamps maxHops to valid range', async () => {
87
+ const calls = [];
88
+ const mockExec = async (cmd, args) => {
89
+ calls.push({ cmd, args });
90
+ return '';
91
+ };
92
+ await traceroute({ host: '8.8.8.8', maxHops: 999 }, mockExec);
93
+ expect(calls[0]?.args).toContain('64');
94
+ await traceroute({ host: '8.8.8.8', maxHops: 0 }, mockExec);
95
+ expect(calls[1]?.args).toContain('1');
96
+ });
97
+ });
98
+ //# sourceMappingURL=traceroute.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traceroute.test.js","sourceRoot":"","sources":["../../../src/system/probes/traceroute.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sonde/packs",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/src/index.ts CHANGED
@@ -39,6 +39,15 @@ export { graphPack } from './integrations/graph.js';
39
39
  export { splunkPack } from './integrations/splunk.js';
40
40
  export { proxmoxPack } from './integrations/proxmox.js';
41
41
  export { nutanixPack } from './integrations/nutanix.js';
42
+ export { vcenterPack } from './integrations/vcenter.js';
43
+ export { datadogPack } from './integrations/datadog.js';
44
+ export { lokiPack } from './integrations/loki.js';
45
+ export { jiraPack } from './integrations/jira.js';
46
+ export { pagerdutyPack } from './integrations/pagerduty.js';
47
+ export { thousandeyesPack } from './integrations/thousandeyes.js';
48
+ export { merakiPack } from './integrations/meraki.js';
49
+ export { checkpointPack } from './integrations/checkpoint.js';
50
+ export { a10Pack } from './integrations/a10.js';
42
51
  export { proxmoxDiagnosticRunbooks } from './runbooks/proxmox.js';
43
52
  export { nutanixDiagnosticRunbooks } from './runbooks/nutanix.js';
44
53
 
@@ -0,0 +1,370 @@
1
+ import type {
2
+ FetchFn,
3
+ IntegrationConfig,
4
+ IntegrationCredentials,
5
+ IntegrationPack,
6
+ IntegrationProbeHandler,
7
+ } from '@sonde/shared';
8
+
9
+ // --- Session-based auth ---
10
+
11
+ /** Auth signature cache: signature + expiry timestamp */
12
+ let cachedSession: { signature: string; expiresAt: number } | null = null;
13
+
14
+ /** Acquire an A10 auth signature via POST /axapi/v3/auth */
15
+ async function getSignature(
16
+ config: IntegrationConfig,
17
+ credentials: IntegrationCredentials,
18
+ fetchFn: FetchFn,
19
+ ): Promise<string> {
20
+ const now = Date.now();
21
+ if (cachedSession && cachedSession.expiresAt > now) {
22
+ return cachedSession.signature;
23
+ }
24
+
25
+ const { username, password } = credentials.credentials;
26
+ if (!username || !password) {
27
+ throw new Error('A10 Networks requires username and password credentials');
28
+ }
29
+
30
+ const url = `${config.endpoint.replace(/\/$/, '')}/axapi/v3/auth`;
31
+ const res = await fetchFn(url, {
32
+ method: 'POST',
33
+ headers: {
34
+ 'Content-Type': 'application/json',
35
+ ...config.headers,
36
+ },
37
+ body: JSON.stringify({ credentials: { username, password } }),
38
+ });
39
+
40
+ if (!res.ok) {
41
+ throw new Error(`A10 auth failed: ${res.status} ${res.statusText}`);
42
+ }
43
+
44
+ const data = (await res.json()) as {
45
+ authresponse?: { signature?: string };
46
+ };
47
+ const signature = data.authresponse?.signature;
48
+ if (!signature) {
49
+ throw new Error('A10 auth response missing signature');
50
+ }
51
+
52
+ cachedSession = { signature, expiresAt: now + 5 * 60 * 1000 };
53
+ return signature;
54
+ }
55
+
56
+ // --- REST helper ---
57
+
58
+ async function a10Get<T>(
59
+ apiPath: string,
60
+ config: IntegrationConfig,
61
+ credentials: IntegrationCredentials,
62
+ fetchFn: FetchFn,
63
+ params?: Record<string, string>,
64
+ ): Promise<T> {
65
+ const signature = await getSignature(config, credentials, fetchFn);
66
+ const base = `${config.endpoint.replace(/\/$/, '')}/axapi/v3/${apiPath}`;
67
+ const url = new URL(base);
68
+ if (params) {
69
+ for (const [key, value] of Object.entries(params)) {
70
+ url.searchParams.set(key, value);
71
+ }
72
+ }
73
+
74
+ const headers: Record<string, string> = {
75
+ Accept: 'application/json',
76
+ Authorization: `A10 ${signature}`,
77
+ ...config.headers,
78
+ };
79
+
80
+ const res = await fetchFn(url.toString(), { headers });
81
+ if (!res.ok) {
82
+ throw new Error(`A10 API returned ${res.status}: ${res.statusText}`);
83
+ }
84
+ return (await res.json()) as T;
85
+ }
86
+
87
+ // --- Probe handlers ---
88
+
89
+ const systemInfo: IntegrationProbeHandler = async (
90
+ _params,
91
+ config,
92
+ credentials,
93
+ fetchFn,
94
+ ) => {
95
+ const data = await a10Get<{
96
+ version?: {
97
+ oper?: {
98
+ 'sw-version'?: string;
99
+ 'serial-number'?: string;
100
+ 'platform-name'?: string;
101
+ 'up-time'?: string;
102
+ };
103
+ };
104
+ }>('version/oper', config, credentials, fetchFn);
105
+
106
+ const oper = data.version?.oper ?? {};
107
+ return {
108
+ version: oper['sw-version'] ?? null,
109
+ serialNumber: oper['serial-number'] ?? null,
110
+ platform: oper['platform-name'] ?? null,
111
+ uptime: oper['up-time'] ?? null,
112
+ };
113
+ };
114
+
115
+ const virtualServersList: IntegrationProbeHandler = async (
116
+ _params,
117
+ config,
118
+ credentials,
119
+ fetchFn,
120
+ ) => {
121
+ const data = await a10Get<{
122
+ 'virtual-server-list'?: Array<{
123
+ name?: string;
124
+ 'ip-address'?: string;
125
+ status?: string;
126
+ 'port-list'?: Array<{
127
+ 'port-number'?: number;
128
+ protocol?: string;
129
+ status?: string;
130
+ }>;
131
+ }>;
132
+ }>('slb/virtual-server', config, credentials, fetchFn);
133
+
134
+ const servers = (data['virtual-server-list'] ?? []).map((vs) => ({
135
+ name: vs.name ?? null,
136
+ ipAddress: vs['ip-address'] ?? null,
137
+ status: vs.status ?? null,
138
+ ports: (vs['port-list'] ?? []).map((p) => ({
139
+ portNumber: p['port-number'] ?? null,
140
+ protocol: p.protocol ?? null,
141
+ status: p.status ?? null,
142
+ })),
143
+ }));
144
+
145
+ return { virtualServers: servers, count: servers.length };
146
+ };
147
+
148
+ const virtualServerStats: IntegrationProbeHandler = async (
149
+ params,
150
+ config,
151
+ credentials,
152
+ fetchFn,
153
+ ) => {
154
+ const name = params?.name as string;
155
+ if (!name) throw new Error('name parameter is required (virtual server name)');
156
+
157
+ const data = await a10Get<{
158
+ 'virtual-server'?: {
159
+ stats?: {
160
+ 'curr-conn'?: number;
161
+ 'total-conn'?: number;
162
+ 'bytes-in'?: number;
163
+ 'bytes-out'?: number;
164
+ };
165
+ };
166
+ }>(
167
+ `slb/virtual-server/${encodeURIComponent(name)}/stats`,
168
+ config,
169
+ credentials,
170
+ fetchFn,
171
+ );
172
+
173
+ const stats = data['virtual-server']?.stats ?? {};
174
+ return {
175
+ name,
176
+ currConn: stats['curr-conn'] ?? 0,
177
+ totalConn: stats['total-conn'] ?? 0,
178
+ bytesIn: stats['bytes-in'] ?? 0,
179
+ bytesOut: stats['bytes-out'] ?? 0,
180
+ };
181
+ };
182
+
183
+ const serviceGroupsList: IntegrationProbeHandler = async (
184
+ _params,
185
+ config,
186
+ credentials,
187
+ fetchFn,
188
+ ) => {
189
+ const data = await a10Get<{
190
+ 'service-group-list'?: Array<{
191
+ name?: string;
192
+ protocol?: string;
193
+ 'lb-method'?: string;
194
+ 'member-list'?: Array<{
195
+ name?: string;
196
+ port?: number;
197
+ 'member-state'?: string;
198
+ }>;
199
+ }>;
200
+ }>('slb/service-group', config, credentials, fetchFn);
201
+
202
+ const groups = (data['service-group-list'] ?? []).map((sg) => ({
203
+ name: sg.name ?? null,
204
+ protocol: sg.protocol ?? null,
205
+ lbMethod: sg['lb-method'] ?? null,
206
+ members: (sg['member-list'] ?? []).map((m) => ({
207
+ name: m.name ?? null,
208
+ port: m.port ?? null,
209
+ state: m['member-state'] ?? null,
210
+ })),
211
+ }));
212
+
213
+ return { serviceGroups: groups, count: groups.length };
214
+ };
215
+
216
+ const serversList: IntegrationProbeHandler = async (
217
+ _params,
218
+ config,
219
+ credentials,
220
+ fetchFn,
221
+ ) => {
222
+ const data = await a10Get<{
223
+ 'server-list'?: Array<{
224
+ name?: string;
225
+ host?: string;
226
+ status?: string;
227
+ 'port-list'?: Array<{
228
+ 'port-number'?: number;
229
+ protocol?: string;
230
+ 'health-check'?: string;
231
+ status?: string;
232
+ }>;
233
+ }>;
234
+ }>('slb/server', config, credentials, fetchFn);
235
+
236
+ const servers = (data['server-list'] ?? []).map((s) => ({
237
+ name: s.name ?? null,
238
+ host: s.host ?? null,
239
+ status: s.status ?? null,
240
+ ports: (s['port-list'] ?? []).map((p) => ({
241
+ portNumber: p['port-number'] ?? null,
242
+ protocol: p.protocol ?? null,
243
+ healthCheck: p['health-check'] ?? null,
244
+ status: p.status ?? null,
245
+ })),
246
+ }));
247
+
248
+ return { servers, count: servers.length };
249
+ };
250
+
251
+ const interfacesStats: IntegrationProbeHandler = async (
252
+ _params,
253
+ config,
254
+ credentials,
255
+ fetchFn,
256
+ ) => {
257
+ const data = await a10Get<{
258
+ ethernet?: {
259
+ oper?: {
260
+ 'interface-list'?: Array<{
261
+ 'port-num'?: number;
262
+ status?: string;
263
+ speed?: string;
264
+ 'rx-pkts'?: number;
265
+ 'tx-pkts'?: number;
266
+ 'rx-errors'?: number;
267
+ 'tx-errors'?: number;
268
+ }>;
269
+ };
270
+ };
271
+ }>('interface/ethernet/oper', config, credentials, fetchFn);
272
+
273
+ const interfaces = (data.ethernet?.oper?.['interface-list'] ?? []).map((iface) => ({
274
+ portNum: iface['port-num'] ?? null,
275
+ status: iface.status ?? null,
276
+ speed: iface.speed ?? null,
277
+ rxPackets: iface['rx-pkts'] ?? 0,
278
+ txPackets: iface['tx-pkts'] ?? 0,
279
+ rxErrors: iface['rx-errors'] ?? 0,
280
+ txErrors: iface['tx-errors'] ?? 0,
281
+ }));
282
+
283
+ return { interfaces, count: interfaces.length };
284
+ };
285
+
286
+ // --- Pack definition ---
287
+
288
+ export const a10Pack: IntegrationPack = {
289
+ manifest: {
290
+ name: 'a10',
291
+ type: 'integration',
292
+ version: '0.1.0',
293
+ description:
294
+ 'A10 Networks — virtual servers, service groups, real server health, and interface stats',
295
+ requires: { groups: [], files: [], commands: [] },
296
+ probes: [
297
+ {
298
+ name: 'system.info',
299
+ description: 'System version, serial number, platform, and uptime',
300
+ capability: 'observe',
301
+ params: {},
302
+ timeout: 15000,
303
+ },
304
+ {
305
+ name: 'virtual-servers.list',
306
+ description: 'List virtual servers (VIPs) with port and status info',
307
+ capability: 'observe',
308
+ params: {},
309
+ timeout: 15000,
310
+ },
311
+ {
312
+ name: 'virtual-server.stats',
313
+ description: 'Connection and throughput stats for a virtual server',
314
+ capability: 'observe',
315
+ params: {
316
+ name: {
317
+ type: 'string',
318
+ description: 'Virtual server name',
319
+ required: true,
320
+ },
321
+ },
322
+ timeout: 15000,
323
+ },
324
+ {
325
+ name: 'service-groups.list',
326
+ description: 'List service groups with members and health status',
327
+ capability: 'observe',
328
+ params: {},
329
+ timeout: 15000,
330
+ },
331
+ {
332
+ name: 'servers.list',
333
+ description: 'List real servers with port health checks',
334
+ capability: 'observe',
335
+ params: {},
336
+ timeout: 15000,
337
+ },
338
+ {
339
+ name: 'interfaces.stats',
340
+ description: 'Ethernet interface stats: packets, errors, speed, and status',
341
+ capability: 'observe',
342
+ params: {},
343
+ timeout: 15000,
344
+ },
345
+ ],
346
+ runbook: {
347
+ category: 'load-balancer',
348
+ probes: ['system.info', 'virtual-servers.list'],
349
+ parallel: true,
350
+ },
351
+ },
352
+
353
+ handlers: {
354
+ 'system.info': systemInfo,
355
+ 'virtual-servers.list': virtualServersList,
356
+ 'virtual-server.stats': virtualServerStats,
357
+ 'service-groups.list': serviceGroupsList,
358
+ 'servers.list': serversList,
359
+ 'interfaces.stats': interfacesStats,
360
+ },
361
+
362
+ testConnection: async (config, credentials, fetchFn) => {
363
+ try {
364
+ await getSignature(config, credentials, fetchFn);
365
+ return true;
366
+ } catch {
367
+ return false;
368
+ }
369
+ },
370
+ };