cisco-perfmon 1.5.2 → 1.6.0
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/.github/workflows/release.yml +37 -0
- package/main.js +149 -69
- package/main.mjs +5 -0
- package/package.json +15 -7
- package/types/index.d.ts +162 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
id-token: write
|
|
10
|
+
contents: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
publish:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout
|
|
17
|
+
uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Setup Node.js
|
|
20
|
+
uses: actions/setup-node@v4
|
|
21
|
+
with:
|
|
22
|
+
node-version: '22'
|
|
23
|
+
registry-url: 'https://registry.npmjs.org'
|
|
24
|
+
|
|
25
|
+
- name: Update npm
|
|
26
|
+
run: npm install -g npm@latest
|
|
27
|
+
|
|
28
|
+
- name: Install dependencies
|
|
29
|
+
run: npm ci
|
|
30
|
+
|
|
31
|
+
- name: Publish to npm
|
|
32
|
+
run: npm publish --access public
|
|
33
|
+
|
|
34
|
+
- name: Create GitHub Release
|
|
35
|
+
uses: softprops/action-gh-release@v2
|
|
36
|
+
with:
|
|
37
|
+
generate_release_notes: true
|
package/main.js
CHANGED
|
@@ -1,86 +1,104 @@
|
|
|
1
1
|
const fetch = require("fetch-retry")(global.fetch);
|
|
2
|
-
const util = require("util");
|
|
3
2
|
const parseString = require("xml2js").parseString;
|
|
4
3
|
const stripPrefix = require("xml2js").processors.stripPrefix;
|
|
5
4
|
const http = require("http");
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
const escapeXml = (str) => {
|
|
7
|
+
if (typeof str !== "string") return str;
|
|
8
|
+
return str
|
|
9
|
+
.replace(/&/g, "&")
|
|
10
|
+
.replace(/</g, "<")
|
|
11
|
+
.replace(/>/g, ">")
|
|
12
|
+
.replace(/"/g, """)
|
|
13
|
+
.replace(/'/g, "'");
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const buildCounterStr = (c) => {
|
|
17
|
+
const host = escapeXml(c.host);
|
|
18
|
+
const object = escapeXml(c.object);
|
|
19
|
+
const instance = c.instance ? escapeXml(c.instance) : "";
|
|
20
|
+
const counter = c.counter ? escapeXml(c.counter) : "";
|
|
21
|
+
const objectPart = instance ? `${object}(${instance})` : object;
|
|
22
|
+
return `<soap:Counter><soap:Name>\\\\${host}\\${objectPart}\\${counter}</soap:Name></soap:Counter>`;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const XML_ADD_COUNTER_ENVELOPE = (sessionHandle, counters) => `<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://schemas.cisco.com/ast/soap">
|
|
8
26
|
<soapenv:Header/>
|
|
9
27
|
<soapenv:Body>
|
|
10
28
|
<soap:perfmonAddCounter>
|
|
11
|
-
<soap:SessionHandle
|
|
12
|
-
<soap:ArrayOfCounter
|
|
29
|
+
<soap:SessionHandle>${sessionHandle}</soap:SessionHandle>
|
|
30
|
+
<soap:ArrayOfCounter>${counters}</soap:ArrayOfCounter>
|
|
13
31
|
</soap:perfmonAddCounter>
|
|
14
32
|
</soapenv:Body>
|
|
15
33
|
</soapenv:Envelope>`;
|
|
16
34
|
|
|
17
|
-
|
|
35
|
+
const XML_CLOSE_SESSION_ENVELOPE = (sessionHandle) => `<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://schemas.cisco.com/ast/soap">
|
|
18
36
|
<soapenv:Header/>
|
|
19
37
|
<soapenv:Body>
|
|
20
38
|
<soap:perfmonCloseSession>
|
|
21
|
-
<soap:SessionHandle
|
|
39
|
+
<soap:SessionHandle>${sessionHandle}</soap:SessionHandle>
|
|
22
40
|
</soap:perfmonCloseSession>
|
|
23
41
|
</soapenv:Body>
|
|
24
42
|
</soapenv:Envelope>`;
|
|
25
43
|
|
|
26
|
-
|
|
44
|
+
const XML_COLLECT_COUNTER_ENVELOPE = (host, object) => `<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://schemas.cisco.com/ast/soap">
|
|
27
45
|
<soapenv:Header/>
|
|
28
46
|
<soapenv:Body>
|
|
29
47
|
<soap:perfmonCollectCounterData>
|
|
30
|
-
<soap:Host
|
|
31
|
-
<soap:Object
|
|
48
|
+
<soap:Host>${host}</soap:Host>
|
|
49
|
+
<soap:Object>${object}</soap:Object>
|
|
32
50
|
</soap:perfmonCollectCounterData>
|
|
33
51
|
</soapenv:Body>
|
|
34
52
|
</soapenv:Envelope>`;
|
|
35
53
|
|
|
36
|
-
|
|
54
|
+
const XML_COLLECT_SESSION_ENVELOPE = (sessionHandle) => `<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://schemas.cisco.com/ast/soap">
|
|
37
55
|
<soapenv:Header/>
|
|
38
56
|
<soapenv:Body>
|
|
39
57
|
<soap:perfmonCollectSessionData>
|
|
40
|
-
<soap:SessionHandle
|
|
58
|
+
<soap:SessionHandle>${sessionHandle}</soap:SessionHandle>
|
|
41
59
|
</soap:perfmonCollectSessionData>
|
|
42
60
|
</soapenv:Body>
|
|
43
61
|
</soapenv:Envelope>`;
|
|
44
62
|
|
|
45
|
-
|
|
63
|
+
const XML_LIST_COUNTER_ENVELOPE = (host) => `<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://schemas.cisco.com/ast/soap">
|
|
46
64
|
<soapenv:Header/>
|
|
47
65
|
<soapenv:Body>
|
|
48
66
|
<soap:perfmonListCounter>
|
|
49
|
-
<soap:Host
|
|
67
|
+
<soap:Host>${host}</soap:Host>
|
|
50
68
|
</soap:perfmonListCounter>
|
|
51
69
|
</soapenv:Body>
|
|
52
70
|
</soapenv:Envelope>`;
|
|
53
71
|
|
|
54
|
-
|
|
72
|
+
const XML_LIST_INSTANCE_ENVELOPE = (host, object) => `<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://schemas.cisco.com/ast/soap">
|
|
55
73
|
<soapenv:Header/>
|
|
56
74
|
<soapenv:Body>
|
|
57
75
|
<soap:perfmonListInstance>
|
|
58
|
-
<soap:Host
|
|
59
|
-
<soap:Object
|
|
76
|
+
<soap:Host>${host}</soap:Host>
|
|
77
|
+
<soap:Object>${object}</soap:Object>
|
|
60
78
|
</soap:perfmonListInstance>
|
|
61
79
|
</soapenv:Body>
|
|
62
80
|
</soapenv:Envelope>`;
|
|
63
81
|
|
|
64
|
-
|
|
82
|
+
const XML_OPEN_SESSION_ENVELOPE = () => `<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://schemas.cisco.com/ast/soap">
|
|
65
83
|
<soapenv:Header/>
|
|
66
84
|
<soapenv:Body>
|
|
67
85
|
<soap:perfmonOpenSession/>
|
|
68
86
|
</soapenv:Body>
|
|
69
87
|
</soapenv:Envelope>`;
|
|
70
88
|
|
|
71
|
-
|
|
89
|
+
const XML_QUERY_COUNTER_ENVELOPE = (counter) => `<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://schemas.cisco.com/ast/soap">
|
|
72
90
|
<soapenv:Header/>
|
|
73
91
|
<soapenv:Body>
|
|
74
|
-
<soap:perfmonQueryCounterDescription
|
|
92
|
+
<soap:perfmonQueryCounterDescription>${counter}</soap:perfmonQueryCounterDescription>
|
|
75
93
|
</soapenv:Body>
|
|
76
94
|
</soapenv:Envelope>`;
|
|
77
95
|
|
|
78
|
-
|
|
96
|
+
const XML_REMOVE_COUNTER_ENVELOPE = (sessionHandle, counters) => `<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://schemas.cisco.com/ast/soap">
|
|
79
97
|
<soapenv:Header/>
|
|
80
98
|
<soapenv:Body>
|
|
81
99
|
<soap:perfmonRemoveCounter>
|
|
82
|
-
<soap:SessionHandle
|
|
83
|
-
<soap:ArrayOfCounter
|
|
100
|
+
<soap:SessionHandle>${sessionHandle}</soap:SessionHandle>
|
|
101
|
+
<soap:ArrayOfCounter>${counters}</soap:ArrayOfCounter>
|
|
84
102
|
</soap:perfmonRemoveCounter>
|
|
85
103
|
</soapenv:Body>
|
|
86
104
|
</soapenv:Envelope>`;
|
|
@@ -99,6 +117,8 @@ var XML_REMOVE_COUNTER_ENVELOPE = `<soapenv:Envelope xmlns:soapenv="http://schem
|
|
|
99
117
|
*/
|
|
100
118
|
class perfMonService {
|
|
101
119
|
constructor(host, username, password, options = {}, retry = true) {
|
|
120
|
+
const RATE_LIMIT_DELAYS = [30000, 60000, 120000]; // 30s, 60s, 120s exponential backoff
|
|
121
|
+
|
|
102
122
|
this._OPTIONS = {
|
|
103
123
|
retryOn: async function (attempt, error, response) {
|
|
104
124
|
if (!retry) {
|
|
@@ -107,6 +127,23 @@ class perfMonService {
|
|
|
107
127
|
if (attempt > (process.env.PM_RETRY ? parseInt(process.env.PM_RETRY) : 3)) {
|
|
108
128
|
return false;
|
|
109
129
|
}
|
|
130
|
+
|
|
131
|
+
// Check for SOAP-level rate limiting (CUCM 80 req/min limit)
|
|
132
|
+
if (response && response.status === 500) {
|
|
133
|
+
try {
|
|
134
|
+
const clonedResponse = response.clone();
|
|
135
|
+
const body = await clonedResponse.text();
|
|
136
|
+
if (body.includes("Exceeded allowed rate for Perfmon")) {
|
|
137
|
+
const backoff = RATE_LIMIT_DELAYS[Math.min(attempt, RATE_LIMIT_DELAYS.length - 1)];
|
|
138
|
+
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
139
|
+
await delay(backoff);
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
} catch (e) {
|
|
143
|
+
// If we can't read the body, fall through to normal retry
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
110
147
|
// retry on any network error, or 4xx or 5xx status codes
|
|
111
148
|
if (error !== null || response.status >= 400) {
|
|
112
149
|
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -128,6 +165,28 @@ class perfMonService {
|
|
|
128
165
|
}
|
|
129
166
|
|
|
130
167
|
this._HOST = host;
|
|
168
|
+
this._COOKIE = "";
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Get the current stored cookie
|
|
172
|
+
*
|
|
173
|
+
* @getCookie
|
|
174
|
+
* @memberof perfMonService
|
|
175
|
+
* @returns {string} returns the stored cookie string.
|
|
176
|
+
*/
|
|
177
|
+
getCookie() {
|
|
178
|
+
return this._COOKIE;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Set a cookie to be used for subsequent requests
|
|
182
|
+
*
|
|
183
|
+
* @setCookie
|
|
184
|
+
* @memberof perfMonService
|
|
185
|
+
* @param {string} cookie - The cookie string to set.
|
|
186
|
+
*/
|
|
187
|
+
setCookie(cookie) {
|
|
188
|
+
this._COOKIE = cookie;
|
|
189
|
+
this._OPTIONS.headers.Cookie = cookie;
|
|
131
190
|
}
|
|
132
191
|
/**
|
|
133
192
|
* Post Fetch using Cisco PerfMon API
|
|
@@ -147,7 +206,7 @@ class perfMonService {
|
|
|
147
206
|
try {
|
|
148
207
|
let options = this._OPTIONS;
|
|
149
208
|
let server = this._HOST;
|
|
150
|
-
let XML =
|
|
209
|
+
let XML = XML_COLLECT_COUNTER_ENVELOPE(escapeXml(host), escapeXml(object));
|
|
151
210
|
let soapBody = Buffer.from(XML);
|
|
152
211
|
options.body = soapBody;
|
|
153
212
|
options.SOAPAction = `perfmonCollectCounterData`;
|
|
@@ -161,6 +220,12 @@ class perfMonService {
|
|
|
161
220
|
};
|
|
162
221
|
|
|
163
222
|
promiseResults.cookie = response.headers.get("set-cookie") ? response.headers.get("set-cookie") : "";
|
|
223
|
+
if (promiseResults.cookie) {
|
|
224
|
+
this.setCookie(promiseResults.cookie);
|
|
225
|
+
}
|
|
226
|
+
if (promiseResults.cookie) {
|
|
227
|
+
this.setCookie(promiseResults.cookie);
|
|
228
|
+
}
|
|
164
229
|
|
|
165
230
|
let output = await parseXml(await response.text());
|
|
166
231
|
// Remove unnecessary keys
|
|
@@ -198,9 +263,9 @@ class perfMonService {
|
|
|
198
263
|
* @returns {object} returns JSON via a Promise. JSON contains Session Cookie (If availible) and Results.
|
|
199
264
|
*/
|
|
200
265
|
async collectSessionData(SessionHandle) {
|
|
201
|
-
let options = this._OPTIONS;
|
|
266
|
+
let options = { ...this._OPTIONS, headers: { ...this._OPTIONS.headers } };
|
|
202
267
|
let server = this._HOST;
|
|
203
|
-
let XML =
|
|
268
|
+
let XML = XML_COLLECT_SESSION_ENVELOPE(SessionHandle);
|
|
204
269
|
let soapBody = Buffer.from(XML);
|
|
205
270
|
options.body = soapBody;
|
|
206
271
|
options.SOAPAction = `perfmonCollectSessionData`;
|
|
@@ -213,6 +278,9 @@ class perfMonService {
|
|
|
213
278
|
};
|
|
214
279
|
|
|
215
280
|
promiseResults.cookie = response.headers.get("set-cookie") ? response.headers.get("set-cookie") : "";
|
|
281
|
+
if (promiseResults.cookie) {
|
|
282
|
+
this.setCookie(promiseResults.cookie);
|
|
283
|
+
}
|
|
216
284
|
|
|
217
285
|
let output = await parseXml(await response.text());
|
|
218
286
|
// Remove unnecessary keys
|
|
@@ -246,9 +314,9 @@ class perfMonService {
|
|
|
246
314
|
* @returns {object} returns JSON via a Promise. JSON contains Session Cookie (If availible) and Results.
|
|
247
315
|
*/
|
|
248
316
|
async listCounter(host, filtered = []) {
|
|
249
|
-
let options = this._OPTIONS;
|
|
317
|
+
let options = { ...this._OPTIONS, headers: { ...this._OPTIONS.headers } };
|
|
250
318
|
let server = this._HOST;
|
|
251
|
-
let XML =
|
|
319
|
+
let XML = XML_LIST_COUNTER_ENVELOPE(escapeXml(host));
|
|
252
320
|
let soapBody = Buffer.from(XML);
|
|
253
321
|
options.body = soapBody;
|
|
254
322
|
options.SOAPAction = `perfmonListCounter`;
|
|
@@ -261,6 +329,9 @@ class perfMonService {
|
|
|
261
329
|
};
|
|
262
330
|
|
|
263
331
|
promiseResults.cookie = response.headers.get("set-cookie") ? response.headers.get("set-cookie") : "";
|
|
332
|
+
if (promiseResults.cookie) {
|
|
333
|
+
this.setCookie(promiseResults.cookie);
|
|
334
|
+
}
|
|
264
335
|
|
|
265
336
|
let output = await parseXml(await response.text());
|
|
266
337
|
// Remove unnecessary keys
|
|
@@ -299,9 +370,9 @@ class perfMonService {
|
|
|
299
370
|
* @returns {object} returns JSON via a Promise. JSON contains Session Cookie (If availible) and Results.
|
|
300
371
|
*/
|
|
301
372
|
async listInstance(host, object) {
|
|
302
|
-
let options = this._OPTIONS;
|
|
373
|
+
let options = { ...this._OPTIONS, headers: { ...this._OPTIONS.headers } };
|
|
303
374
|
let server = this._HOST;
|
|
304
|
-
let XML =
|
|
375
|
+
let XML = XML_LIST_INSTANCE_ENVELOPE(escapeXml(host), escapeXml(object));
|
|
305
376
|
let soapBody = Buffer.from(XML);
|
|
306
377
|
options.body = soapBody;
|
|
307
378
|
options.SOAPAction = `perfmonListInstance`;
|
|
@@ -315,6 +386,9 @@ class perfMonService {
|
|
|
315
386
|
};
|
|
316
387
|
|
|
317
388
|
promiseResults.cookie = response.headers.get("set-cookie") ? response.headers.get("set-cookie") : "";
|
|
389
|
+
if (promiseResults.cookie) {
|
|
390
|
+
this.setCookie(promiseResults.cookie);
|
|
391
|
+
}
|
|
318
392
|
|
|
319
393
|
let output = await parseXml(await response.text());
|
|
320
394
|
// Remove unnecessary keys
|
|
@@ -331,11 +405,7 @@ class perfMonService {
|
|
|
331
405
|
|
|
332
406
|
// If the results are not an array, we make it an array.
|
|
333
407
|
if (!Array.isArray(promiseResults.results)) {
|
|
334
|
-
|
|
335
|
-
promiseResults = {
|
|
336
|
-
results: [],
|
|
337
|
-
};
|
|
338
|
-
promiseResults.results.push(temp);
|
|
408
|
+
promiseResults.results = [promiseResults.results];
|
|
339
409
|
}
|
|
340
410
|
return promiseResults;
|
|
341
411
|
} else {
|
|
@@ -356,9 +426,9 @@ class perfMonService {
|
|
|
356
426
|
* @returns {object} returns JSON via a Promise. JSON contains Session Cookie (If availible) and Results.
|
|
357
427
|
*/
|
|
358
428
|
async openSession() {
|
|
359
|
-
let options = this._OPTIONS;
|
|
429
|
+
let options = { ...this._OPTIONS, headers: { ...this._OPTIONS.headers } };
|
|
360
430
|
let server = this._HOST;
|
|
361
|
-
let XML =
|
|
431
|
+
let XML = XML_OPEN_SESSION_ENVELOPE();
|
|
362
432
|
let soapBody = Buffer.from(XML);
|
|
363
433
|
options.body = soapBody;
|
|
364
434
|
options.SOAPAction = `perfmonOpenSession`;
|
|
@@ -371,6 +441,9 @@ class perfMonService {
|
|
|
371
441
|
};
|
|
372
442
|
|
|
373
443
|
promiseResults.cookie = response.headers.get("set-cookie") ? response.headers.get("set-cookie") : "";
|
|
444
|
+
if (promiseResults.cookie) {
|
|
445
|
+
this.setCookie(promiseResults.cookie);
|
|
446
|
+
}
|
|
374
447
|
|
|
375
448
|
let output = await parseXml(await response.text());
|
|
376
449
|
// Remove unnecessary keys
|
|
@@ -404,9 +477,9 @@ class perfMonService {
|
|
|
404
477
|
* @returns {object} returns JSON via a Promise. JSON contains Session Cookie (If availible) and Results.
|
|
405
478
|
*/
|
|
406
479
|
async closeSession(sessionHandle) {
|
|
407
|
-
let options = this._OPTIONS;
|
|
480
|
+
let options = { ...this._OPTIONS, headers: { ...this._OPTIONS.headers } };
|
|
408
481
|
let server = this._HOST;
|
|
409
|
-
let XML =
|
|
482
|
+
let XML = XML_CLOSE_SESSION_ENVELOPE(sessionHandle);
|
|
410
483
|
let soapBody = Buffer.from(XML);
|
|
411
484
|
options.body = soapBody;
|
|
412
485
|
options.SOAPAction = `perfmonCloseSession`;
|
|
@@ -419,6 +492,9 @@ class perfMonService {
|
|
|
419
492
|
};
|
|
420
493
|
|
|
421
494
|
promiseResults.cookie = response.headers.get("set-cookie") ? response.headers.get("set-cookie") : "";
|
|
495
|
+
if (promiseResults.cookie) {
|
|
496
|
+
this.setCookie(promiseResults.cookie);
|
|
497
|
+
}
|
|
422
498
|
|
|
423
499
|
let output = await parseXml(await response.text());
|
|
424
500
|
// Remove unnecessary keys
|
|
@@ -451,16 +527,10 @@ class perfMonService {
|
|
|
451
527
|
* @returns {object} returns JSON via a Promise. JSON contains Session Cookie (If availible) and Results.
|
|
452
528
|
*/
|
|
453
529
|
async addCounter(sessionHandle, counter) {
|
|
454
|
-
let options = this._OPTIONS;
|
|
530
|
+
let options = { ...this._OPTIONS, headers: { ...this._OPTIONS.headers } };
|
|
455
531
|
let server = this._HOST;
|
|
456
|
-
let counterStr;
|
|
457
|
-
|
|
458
|
-
if (Array.isArray(counter)) {
|
|
459
|
-
counter.forEach((counter) => (counterStr += "<soap:Counter>" + "<soap:Name>" + "\\\\" + counter.host + "\\" + (counter.instance ? `${counter.object}(${counter.instance})` : counter.object) + "\\" + counter.counter + "</soap:Name>" + "</soap:Counter>"));
|
|
460
|
-
} else {
|
|
461
|
-
counterStr = "<soap:Counter>" + "<soap:Name>" + "\\\\" + counter.host + "\\" + (counter.instance ? `${counter.object}(${counter.instance})` : counter.object) + "\\" + counter.counter + "</soap:Name>" + "</soap:Counter>";
|
|
462
|
-
}
|
|
463
|
-
let XML = util.format(XML_ADD_COUNTER_ENVELOPE, sessionHandle, counterStr);
|
|
532
|
+
let counterStr = Array.isArray(counter) ? counter.map(buildCounterStr).join("") : buildCounterStr(counter);
|
|
533
|
+
let XML = XML_ADD_COUNTER_ENVELOPE(sessionHandle, counterStr);
|
|
464
534
|
let soapBody = Buffer.from(XML);
|
|
465
535
|
options.body = soapBody;
|
|
466
536
|
options.SOAPAction = `perfmonAddCounter`;
|
|
@@ -473,6 +543,9 @@ class perfMonService {
|
|
|
473
543
|
};
|
|
474
544
|
|
|
475
545
|
promiseResults.cookie = response.headers.get("set-cookie") ? response.headers.get("set-cookie") : "";
|
|
546
|
+
if (promiseResults.cookie) {
|
|
547
|
+
this.setCookie(promiseResults.cookie);
|
|
548
|
+
}
|
|
476
549
|
|
|
477
550
|
let output = await parseXml(await response.text());
|
|
478
551
|
// Remove unnecessary keys
|
|
@@ -505,17 +578,10 @@ class perfMonService {
|
|
|
505
578
|
* @returns {object} returns JSON via a Promise. JSON contains Session Cookie (If availible) and Results.
|
|
506
579
|
*/
|
|
507
580
|
async removeCounter(sessionHandle, counter) {
|
|
508
|
-
let options = this._OPTIONS;
|
|
581
|
+
let options = { ...this._OPTIONS, headers: { ...this._OPTIONS.headers } };
|
|
509
582
|
let server = this._HOST;
|
|
510
|
-
|
|
511
|
-
let counterStr;
|
|
512
|
-
if (Array.isArray(counter)) {
|
|
513
|
-
counter.forEach((counter) => (counterStr += "<soap:Counter>" + "<soap:Name>" + "\\\\" + counter.host + "\\" + (counter.instance ? `${counter.object}(${counter.instance})` : counter.object) + "\\" + counter.counter + "</soap:Name>" + "</soap:Counter>"));
|
|
514
|
-
} else {
|
|
515
|
-
counterStr = "<soap:Counter>" + "<soap:Name>" + "\\\\" + counter.host + "\\" + (counter.instance ? `${counter.object}(${counter.instance})` : counter.object) + "\\" + counter.counter + "</soap:Name>" + "</soap:Counter>";
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
let XML = util.format(XML_REMOVE_COUNTER_ENVELOPE, sessionHandle, counterStr);
|
|
583
|
+
let counterStr = Array.isArray(counter) ? counter.map(buildCounterStr).join("") : buildCounterStr(counter);
|
|
584
|
+
let XML = XML_REMOVE_COUNTER_ENVELOPE(sessionHandle, counterStr);
|
|
519
585
|
let soapBody = Buffer.from(XML);
|
|
520
586
|
options.body = soapBody;
|
|
521
587
|
options.SOAPAction = `perfmonRemoveCounter`;
|
|
@@ -528,6 +594,9 @@ class perfMonService {
|
|
|
528
594
|
};
|
|
529
595
|
|
|
530
596
|
promiseResults.cookie = response.headers.get("set-cookie") ? response.headers.get("set-cookie") : "";
|
|
597
|
+
if (promiseResults.cookie) {
|
|
598
|
+
this.setCookie(promiseResults.cookie);
|
|
599
|
+
}
|
|
531
600
|
|
|
532
601
|
let output = await parseXml(await response.text());
|
|
533
602
|
// Remove unnecessary keys
|
|
@@ -559,10 +628,10 @@ class perfMonService {
|
|
|
559
628
|
* @returns {object} returns JSON via a Promise. JSON contains Session Cookie (If availible) and Results.
|
|
560
629
|
*/
|
|
561
630
|
async queryCounterDescription(object) {
|
|
562
|
-
let options = this._OPTIONS;
|
|
631
|
+
let options = { ...this._OPTIONS, headers: { ...this._OPTIONS.headers } };
|
|
563
632
|
let server = this._HOST;
|
|
564
|
-
let counterStr =
|
|
565
|
-
let XML =
|
|
633
|
+
let counterStr = buildCounterStr(object);
|
|
634
|
+
let XML = XML_QUERY_COUNTER_ENVELOPE(counterStr);
|
|
566
635
|
let soapBody = Buffer.from(XML);
|
|
567
636
|
options.body = soapBody;
|
|
568
637
|
options.SOAPAction = `perfmonQueryCounterDescription`;
|
|
@@ -576,6 +645,9 @@ class perfMonService {
|
|
|
576
645
|
};
|
|
577
646
|
|
|
578
647
|
promiseResults.cookie = response.headers.get("set-cookie") ? response.headers.get("set-cookie") : "";
|
|
648
|
+
if (promiseResults.cookie) {
|
|
649
|
+
this.setCookie(promiseResults.cookie);
|
|
650
|
+
}
|
|
579
651
|
|
|
580
652
|
let output = await parseXml(await response.text());
|
|
581
653
|
// Remove unnecessary keys
|
|
@@ -627,18 +699,26 @@ const removeKeys = (obj, keys) => {
|
|
|
627
699
|
};
|
|
628
700
|
|
|
629
701
|
const clean = (object) => {
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
702
|
+
if (Array.isArray(object)) {
|
|
703
|
+
for (let i = object.length - 1; i >= 0; i--) {
|
|
704
|
+
const v = object[i];
|
|
705
|
+
if (v && typeof v === "object") {
|
|
706
|
+
clean(v);
|
|
707
|
+
}
|
|
708
|
+
if ((v && typeof v === "object" && !Object.keys(v).length) || v === null || v === undefined) {
|
|
709
|
+
object.splice(i, 1);
|
|
710
|
+
}
|
|
633
711
|
}
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
712
|
+
} else {
|
|
713
|
+
Object.entries(object).forEach(([k, v]) => {
|
|
714
|
+
if (v && typeof v === "object") {
|
|
715
|
+
clean(v);
|
|
716
|
+
}
|
|
717
|
+
if ((v && typeof v === "object" && !Object.keys(v).length) || v === null || v === undefined) {
|
|
638
718
|
delete object[k];
|
|
639
719
|
}
|
|
640
|
-
}
|
|
641
|
-
}
|
|
720
|
+
});
|
|
721
|
+
}
|
|
642
722
|
return object;
|
|
643
723
|
};
|
|
644
724
|
|
package/main.mjs
ADDED
package/package.json
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cisco-perfmon",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "A library to pull Perfmon data from Cisco VOS applications via SOAP",
|
|
5
5
|
"main": "main.js",
|
|
6
|
+
"module": "main.mjs",
|
|
7
|
+
"types": "types/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./main.mjs",
|
|
11
|
+
"require": "./main.js",
|
|
12
|
+
"types": "./types/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
6
15
|
"scripts": {
|
|
7
16
|
"test": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 NODE_TLS_REJECT_UNAUTHORIZED=0 NODE_ENV=test node ./test/tests.js",
|
|
8
17
|
"development": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 NODE_TLS_REJECT_UNAUTHORIZED=0 NODE_ENV=development node ./test/tests.js",
|
|
@@ -20,7 +29,7 @@
|
|
|
20
29
|
"cucm",
|
|
21
30
|
"vos"
|
|
22
31
|
],
|
|
23
|
-
"author": "
|
|
32
|
+
"author": "sieteunoseis <jeremy.worden@gmail.com>",
|
|
24
33
|
"license": "MIT",
|
|
25
34
|
"bugs": {
|
|
26
35
|
"url": "https://github.com/sieteunoseis/cisco-perfmon/issues"
|
|
@@ -28,13 +37,12 @@
|
|
|
28
37
|
"homepage": "https://github.com/sieteunoseis/cisco-perfmon#readme",
|
|
29
38
|
"dependencies": {
|
|
30
39
|
"fetch-retry": "^6.0.0",
|
|
31
|
-
"
|
|
32
|
-
"xml2js": "*"
|
|
40
|
+
"xml2js": "^0.6.0"
|
|
33
41
|
},
|
|
34
42
|
"devDependencies": {
|
|
35
|
-
"dotenv": "
|
|
36
|
-
"envalid": "^8.
|
|
37
|
-
"jsdoc-to-markdown": "^9.0
|
|
43
|
+
"dotenv": "^17.0.0",
|
|
44
|
+
"envalid": "^8.1.0",
|
|
45
|
+
"jsdoc-to-markdown": "^9.1.0",
|
|
38
46
|
"p-limit": "^3.1.0"
|
|
39
47
|
}
|
|
40
48
|
}
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
export interface PerfmonOptions {
|
|
2
|
+
Cookie?: string;
|
|
3
|
+
[key: string]: string | undefined;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface PerfmonResult {
|
|
7
|
+
cookie: string;
|
|
8
|
+
results: any;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface PerfmonCounterResult extends PerfmonResult {
|
|
12
|
+
object: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface CounterData {
|
|
16
|
+
host: string;
|
|
17
|
+
object: string;
|
|
18
|
+
instance: string;
|
|
19
|
+
counter: string;
|
|
20
|
+
value: string;
|
|
21
|
+
cstatus: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface CounterInfo {
|
|
25
|
+
Name: string;
|
|
26
|
+
MultiInstance: string;
|
|
27
|
+
ArrayOfCounter?: {
|
|
28
|
+
Counter: Array<{
|
|
29
|
+
Name: string;
|
|
30
|
+
}>;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface CounterDescription {
|
|
35
|
+
Description: string;
|
|
36
|
+
Name: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface Counter {
|
|
40
|
+
host: string;
|
|
41
|
+
object: string;
|
|
42
|
+
instance?: string;
|
|
43
|
+
counter: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
declare class perfMonService {
|
|
47
|
+
constructor(
|
|
48
|
+
host: string,
|
|
49
|
+
username: string,
|
|
50
|
+
password: string,
|
|
51
|
+
options?: PerfmonOptions,
|
|
52
|
+
retry?: boolean
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get the current stored cookie
|
|
57
|
+
*/
|
|
58
|
+
getCookie(): string;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Set a cookie to be used for subsequent requests
|
|
62
|
+
*/
|
|
63
|
+
setCookie(cookie: string): void;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Collect counter data without a session
|
|
67
|
+
*/
|
|
68
|
+
collectCounterData(
|
|
69
|
+
host: string,
|
|
70
|
+
object: string
|
|
71
|
+
): Promise<{
|
|
72
|
+
cookie: string;
|
|
73
|
+
object: string;
|
|
74
|
+
results: CounterData[] | CounterData | string;
|
|
75
|
+
}>;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Collect data for an open session
|
|
79
|
+
*/
|
|
80
|
+
collectSessionData(
|
|
81
|
+
SessionHandle: string
|
|
82
|
+
): Promise<{
|
|
83
|
+
cookie: string;
|
|
84
|
+
results: CounterData[] | CounterData | string;
|
|
85
|
+
}>;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* List available counters on a host
|
|
89
|
+
*/
|
|
90
|
+
listCounter(
|
|
91
|
+
host: string,
|
|
92
|
+
filtered?: string[]
|
|
93
|
+
): Promise<{
|
|
94
|
+
cookie: string;
|
|
95
|
+
results: CounterInfo[] | string;
|
|
96
|
+
}>;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* List instances of a perfmon object on a host
|
|
100
|
+
*/
|
|
101
|
+
listInstance(
|
|
102
|
+
host: string,
|
|
103
|
+
object: string
|
|
104
|
+
): Promise<{
|
|
105
|
+
cookie: string;
|
|
106
|
+
object: string;
|
|
107
|
+
results: any[] | string;
|
|
108
|
+
}>;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Open a perfmon session
|
|
112
|
+
*/
|
|
113
|
+
openSession(): Promise<{
|
|
114
|
+
cookie: string;
|
|
115
|
+
results: string;
|
|
116
|
+
}>;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Close a perfmon session
|
|
120
|
+
*/
|
|
121
|
+
closeSession(
|
|
122
|
+
sessionHandle: string
|
|
123
|
+
): Promise<{
|
|
124
|
+
cookie: string;
|
|
125
|
+
results: "success";
|
|
126
|
+
}>;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Add counter(s) to a session
|
|
130
|
+
*/
|
|
131
|
+
addCounter(
|
|
132
|
+
sessionHandle: string,
|
|
133
|
+
counter: Counter | Counter[]
|
|
134
|
+
): Promise<{
|
|
135
|
+
cookie: string;
|
|
136
|
+
results: "success";
|
|
137
|
+
}>;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Remove counter(s) from a session
|
|
141
|
+
*/
|
|
142
|
+
removeCounter(
|
|
143
|
+
sessionHandle: string,
|
|
144
|
+
counter: Counter | Counter[]
|
|
145
|
+
): Promise<{
|
|
146
|
+
cookie: string;
|
|
147
|
+
results: "success";
|
|
148
|
+
}>;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Get counter description
|
|
152
|
+
*/
|
|
153
|
+
queryCounterDescription(
|
|
154
|
+
object: Counter
|
|
155
|
+
): Promise<{
|
|
156
|
+
cookie: string;
|
|
157
|
+
object: string;
|
|
158
|
+
results: CounterDescription | string;
|
|
159
|
+
}>;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export = perfMonService;
|