cisco-perfmon 1.5.0 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -1
- package/main.js +13 -11
- package/package.json +1 -1
- package/test/rateLimitTest.js +49 -12
- package/test/tests.js +76 -83
package/README.md
CHANGED
|
@@ -43,8 +43,9 @@ let service = new perfMonService(
|
|
|
43
43
|
);
|
|
44
44
|
|
|
45
45
|
var counterObj = {
|
|
46
|
-
host:
|
|
46
|
+
host: cucmServerName,
|
|
47
47
|
object: "Cisco CallManager",
|
|
48
|
+
instance: "",
|
|
48
49
|
counter: "CallsActive",
|
|
49
50
|
};
|
|
50
51
|
|
|
@@ -65,4 +66,27 @@ service
|
|
|
65
66
|
npm run test
|
|
66
67
|
```
|
|
67
68
|
|
|
69
|
+
## Output Examples
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
Success Example
|
|
73
|
+
{
|
|
74
|
+
host: 'cucm01-pub',
|
|
75
|
+
object: 'Cisco CallManager',
|
|
76
|
+
instance: '',
|
|
77
|
+
counter: 'PRIChannelsActive',
|
|
78
|
+
value: '0',
|
|
79
|
+
cstatus: '1'
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
Error Example
|
|
83
|
+
{
|
|
84
|
+
status: 500,
|
|
85
|
+
code: 'Internal Server Error',
|
|
86
|
+
host: 'cucm01-pub',
|
|
87
|
+
counter: 'SAML SSO',
|
|
88
|
+
message: 'Exceeded allowed rate for Perfmon information. Current allowed rate for perfmon information is 80 requests per minute.PerfmonService'
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
68
92
|
Note: Test are using Cisco's DevNet sandbox information. Find more information here: [Cisco DevNet](https://devnetsandbox.cisco.com/)
|
package/main.js
CHANGED
|
@@ -104,13 +104,13 @@ class perfMonService {
|
|
|
104
104
|
if (!retry) {
|
|
105
105
|
return false;
|
|
106
106
|
}
|
|
107
|
-
if (attempt > (process.env.
|
|
107
|
+
if (attempt > (process.env.PM_RETRY ? parseInt(process.env.PM_RETRY) : 3)) {
|
|
108
108
|
return false;
|
|
109
109
|
}
|
|
110
110
|
// retry on any network error, or 4xx or 5xx status codes
|
|
111
111
|
if (error !== null || response.status >= 400) {
|
|
112
112
|
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
113
|
-
await delay(process.env.
|
|
113
|
+
await delay(process.env.PM_RETRY_DELAY ? parseInt(process.env.PM_RETRY_DELAY) : 5000);
|
|
114
114
|
return true;
|
|
115
115
|
}
|
|
116
116
|
},
|
|
@@ -168,13 +168,14 @@ class perfMonService {
|
|
|
168
168
|
|
|
169
169
|
if (!response.ok) {
|
|
170
170
|
// Local throw; if it weren't, I'd use Error or a subclass
|
|
171
|
-
throw { status: response.status, code: http.STATUS_CODES[response.status], message: output?.Body?.Fault?.faultstring ? output.Body.Fault.faultstring : "Unknown" };
|
|
171
|
+
throw { status: response.status, code: http.STATUS_CODES[response.status], host: host, object: object, message: output?.Body?.Fault?.faultstring ? output.Body.Fault.faultstring : "Unknown" };
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
// Let's check if the response contains the key we are looking for. This is the return data.
|
|
175
175
|
if (output?.Body?.perfmonCollectCounterDataResponse?.perfmonCollectCounterDataReturn) {
|
|
176
176
|
var returnResults = output.Body.perfmonCollectCounterDataResponse.perfmonCollectCounterDataReturn;
|
|
177
|
-
|
|
177
|
+
promiseResults.results = cleanResponse(returnResults);
|
|
178
|
+
return promiseResults;
|
|
178
179
|
} else {
|
|
179
180
|
// Return JSON with no results.
|
|
180
181
|
return promiseResults;
|
|
@@ -219,7 +220,7 @@ class perfMonService {
|
|
|
219
220
|
|
|
220
221
|
if (!response.ok) {
|
|
221
222
|
// Local throw; if it weren't, I'd use Error or a subclass
|
|
222
|
-
throw { status: response.status, code: http.STATUS_CODES[response.status], message: output?.Body?.Fault?.faultstring ? output.Body.Fault.faultstring : "Unknown" };
|
|
223
|
+
throw { status: response.status, code: http.STATUS_CODES[response.status], sessionId: SessionHandle, message: output?.Body?.Fault?.faultstring ? output.Body.Fault.faultstring : "Unknown" };
|
|
223
224
|
}
|
|
224
225
|
|
|
225
226
|
if (output?.Body?.perfmonCollectSessionDataResponse?.perfmonCollectSessionDataReturn) {
|
|
@@ -267,7 +268,7 @@ class perfMonService {
|
|
|
267
268
|
|
|
268
269
|
if (!response.ok) {
|
|
269
270
|
// Local throw; if it weren't, I'd use Error or a subclass
|
|
270
|
-
throw { status: response.status, code: http.STATUS_CODES[response.status], message: output?.Body?.Fault?.faultstring ? output.Body.Fault.faultstring : "Unknown" };
|
|
271
|
+
throw { status: response.status, code: http.STATUS_CODES[response.status], host: host, message: output?.Body?.Fault?.faultstring ? output.Body.Fault.faultstring : "Unknown" };
|
|
271
272
|
}
|
|
272
273
|
|
|
273
274
|
if (output?.Body?.perfmonListCounterResponse?.perfmonListCounterReturn) {
|
|
@@ -321,7 +322,7 @@ class perfMonService {
|
|
|
321
322
|
|
|
322
323
|
if (!response.ok) {
|
|
323
324
|
// Local throw; if it weren't, I'd use Error or a subclass
|
|
324
|
-
throw { status: response.status, code: http.STATUS_CODES[response.status], message: output?.Body?.Fault?.faultstring ? output.Body.Fault.faultstring : "Unknown" };
|
|
325
|
+
throw { status: response.status, code: http.STATUS_CODES[response.status], host: host, object: object, message: output?.Body?.Fault?.faultstring ? output.Body.Fault.faultstring : "Unknown" };
|
|
325
326
|
}
|
|
326
327
|
|
|
327
328
|
if (output?.Body?.perfmonListInstanceResponse?.perfmonListInstanceReturn) {
|
|
@@ -383,6 +384,7 @@ class perfMonService {
|
|
|
383
384
|
if (output?.Body?.perfmonOpenSessionResponse?.perfmonOpenSessionReturn) {
|
|
384
385
|
var returnResults = output.Body.perfmonOpenSessionResponse.perfmonOpenSessionReturn;
|
|
385
386
|
promiseResults.results = clean(returnResults);
|
|
387
|
+
return promiseResults;
|
|
386
388
|
} else {
|
|
387
389
|
// Return JSON with no results.
|
|
388
390
|
return promiseResults;
|
|
@@ -424,7 +426,7 @@ class perfMonService {
|
|
|
424
426
|
|
|
425
427
|
if (!response.ok) {
|
|
426
428
|
// Local throw; if it weren't, I'd use Error or a subclass
|
|
427
|
-
throw { status: response.status, code: http.STATUS_CODES[response.status], message: output?.Body?.Fault?.faultstring ? output.Body.Fault.faultstring : "Unknown" };
|
|
429
|
+
throw { status: response.status, code: http.STATUS_CODES[response.status], sessionId: sessionHandle, message: output?.Body?.Fault?.faultstring ? output.Body.Fault.faultstring : "Unknown" };
|
|
428
430
|
}
|
|
429
431
|
|
|
430
432
|
if (output?.Body?.perfmonCloseSessionResponse) {
|
|
@@ -478,7 +480,7 @@ class perfMonService {
|
|
|
478
480
|
|
|
479
481
|
if (!response.ok) {
|
|
480
482
|
// Local throw; if it weren't, I'd use Error or a subclass
|
|
481
|
-
throw { status: response.status, code: http.STATUS_CODES[response.status], message: output?.Body?.Fault?.faultstring ? output.Body.Fault.faultstring : "Unknown" };
|
|
483
|
+
throw { status: response.status, code: http.STATUS_CODES[response.status], sessionId: sessionHandle, message: output?.Body?.Fault?.faultstring ? output.Body.Fault.faultstring : "Unknown" };
|
|
482
484
|
}
|
|
483
485
|
|
|
484
486
|
if (output?.Body?.perfmonAddCounterResponse) {
|
|
@@ -533,7 +535,7 @@ class perfMonService {
|
|
|
533
535
|
|
|
534
536
|
if (!response.ok) {
|
|
535
537
|
// Local throw; if it weren't, I'd use Error or a subclass
|
|
536
|
-
throw { status: response.status, code: http.STATUS_CODES[response.status], message: output?.Body?.Fault?.faultstring ? output.Body.Fault.faultstring : "Unknown" };
|
|
538
|
+
throw { status: response.status, code: http.STATUS_CODES[response.status], sessionId: sessionHandle, message: output?.Body?.Fault?.faultstring ? output.Body.Fault.faultstring : "Unknown" };
|
|
537
539
|
}
|
|
538
540
|
|
|
539
541
|
if (output?.Body?.perfmonRemoveCounterResponse) {
|
|
@@ -581,7 +583,7 @@ class perfMonService {
|
|
|
581
583
|
|
|
582
584
|
if (!response.ok) {
|
|
583
585
|
// Local throw; if it weren't, I'd use Error or a subclass
|
|
584
|
-
throw { status: response.status, code: http.STATUS_CODES[response.status], message: output?.Body?.Fault?.faultstring ? output.Body.Fault.faultstring : "Unknown" };
|
|
586
|
+
throw { status: response.status, code: http.STATUS_CODES[response.status], object: object, message: output?.Body?.Fault?.faultstring ? output.Body.Fault.faultstring : "Unknown" };
|
|
585
587
|
}
|
|
586
588
|
|
|
587
589
|
if (output?.Body?.perfmonQueryCounterDescriptionResponse?.perfmonQueryCounterDescriptionReturn) {
|
package/package.json
CHANGED
package/test/rateLimitTest.js
CHANGED
|
@@ -140,20 +140,57 @@ const retry = (fn, retriesLeft = 1, retryInteveral = 1000, promiseDelay = 0) =>
|
|
|
140
140
|
try {
|
|
141
141
|
// Let's run the perfmon loop for each counter
|
|
142
142
|
console.log("Running rate limit test. This will take a while...");
|
|
143
|
-
var promises = [];
|
|
144
|
-
for (const counter of counterArr) {
|
|
145
|
-
promises.push(objectLimit(() => retry(() => perfmon_service.collectCounterData(cucmServerName, counter), 5, 5000, 1000)));
|
|
146
|
-
}
|
|
147
143
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
144
|
+
const promises = await counterArr.map((counter) => {
|
|
145
|
+
return objectLimit(() => retry(() => perfmon_service.collectCounterData(cucmServerName, counter), 0, 0, 0));
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
let output = await Promise.allSettled(promises);
|
|
149
|
+
output = output.map((el) => {
|
|
150
|
+
if (el.status === "fulfilled") {
|
|
151
|
+
return el.value;
|
|
152
|
+
} else {
|
|
153
|
+
return el.reason;
|
|
154
|
+
}
|
|
156
155
|
});
|
|
156
|
+
|
|
157
|
+
output = output.flat(1);
|
|
158
|
+
|
|
159
|
+
let errors = {};
|
|
160
|
+
let success = {};
|
|
161
|
+
|
|
162
|
+
output.forEach((el) => {
|
|
163
|
+
if (el?.status > 400) {
|
|
164
|
+
errors[el.object] = (errors[el.object] || 0) + 1;
|
|
165
|
+
} else if (el?.results?.length > 0) {
|
|
166
|
+
el.results.forEach((result) => {
|
|
167
|
+
success[result.object] = (success[result.object] || 0) + 1;
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
const nonPercentageObjects = output.reduce((acc, obj) => {
|
|
173
|
+
if (obj?.results?.length > 0) {
|
|
174
|
+
const matchingItems = obj.results.filter((item) => !item?.counter.includes("%") && !item.counter?.includes("Percentage"));
|
|
175
|
+
|
|
176
|
+
if (matchingItems.length > 0) {
|
|
177
|
+
acc.push(matchingItems);
|
|
178
|
+
}
|
|
179
|
+
return acc.flat(1);
|
|
180
|
+
} else {
|
|
181
|
+
return acc;
|
|
182
|
+
}
|
|
183
|
+
}, []);
|
|
184
|
+
|
|
185
|
+
console.log(`Total number of objects: ${output.length}, matching non percentage objects: ${nonPercentageObjects.length}`);
|
|
186
|
+
|
|
187
|
+
var results = {
|
|
188
|
+
success: success,
|
|
189
|
+
errors: errors,
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
console.log(results);
|
|
193
|
+
console.log("Rate limit test completed.");
|
|
157
194
|
} catch (err) {
|
|
158
195
|
console.error("Error:", err);
|
|
159
196
|
}
|
package/test/tests.js
CHANGED
|
@@ -28,8 +28,8 @@ var cucmServerName = env.CUCM_SERVER_NAME;
|
|
|
28
28
|
|
|
29
29
|
// Variables to hold our SessionID and our Session Counter
|
|
30
30
|
var SessionID;
|
|
31
|
-
var
|
|
32
|
-
var
|
|
31
|
+
var perfmonObject = "Cisco CallManager";
|
|
32
|
+
var perfmonSessionObj = {
|
|
33
33
|
host: cucmServerName,
|
|
34
34
|
object: "Cisco CallManager",
|
|
35
35
|
instance: "",
|
|
@@ -37,9 +37,9 @@ var sessionObj = {
|
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
(async () => {
|
|
40
|
-
console.log("Let's get a description of our
|
|
40
|
+
console.log("Let's get a description of our object. We will also retrieve a cookie to use for the rest of the session.");
|
|
41
41
|
await service
|
|
42
|
-
.queryCounterDescription(
|
|
42
|
+
.queryCounterDescription(perfmonSessionObj)
|
|
43
43
|
.then((response) => {
|
|
44
44
|
console.log("queryCounterDescription: ", response.results);
|
|
45
45
|
if (response.cookie) {
|
|
@@ -50,86 +50,79 @@ var sessionObj = {
|
|
|
50
50
|
console.log("Error",JSON.stringify(error));
|
|
51
51
|
});
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
console.log(
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
// .collectCounterData(cucmServerName, counterObject)
|
|
63
|
-
// .then((response) => {
|
|
64
|
-
// console.log("collectCounterData", response);
|
|
65
|
-
// })
|
|
66
|
-
// .catch((error) => {
|
|
67
|
-
// console.log(error.message);
|
|
68
|
-
// });
|
|
53
|
+
console.log("Let's collect some non session object data.");
|
|
54
|
+
await service
|
|
55
|
+
.collectCounterData(cucmServerName, perfmonObject)
|
|
56
|
+
.then((response) => {
|
|
57
|
+
console.log("collectCounterData", response.results);
|
|
58
|
+
})
|
|
59
|
+
.catch((error) => {
|
|
60
|
+
console.log(error.message);
|
|
61
|
+
});
|
|
69
62
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
63
|
+
console.log("Let's open a session, add some object counters, wait 30 seconds, collect the session data, remove the object and finally close the session");
|
|
64
|
+
await service
|
|
65
|
+
.openSession()
|
|
66
|
+
.then(async (response) => {
|
|
67
|
+
console.log("SessionID", response.results);
|
|
68
|
+
SessionID = response.results;
|
|
69
|
+
await service
|
|
70
|
+
.addCounter(SessionID, perfmonSessionObj)
|
|
71
|
+
.then(async (response) => {
|
|
72
|
+
console.log("addCounter", response.results);
|
|
73
|
+
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
74
|
+
console.log("Wait 15 seconds");
|
|
75
|
+
await delay(15000); // waiting 15 second.
|
|
76
|
+
await service
|
|
77
|
+
.collectSessionData(SessionID)
|
|
78
|
+
.then(async (response) => {
|
|
79
|
+
console.log("collectSessionData", response.results);
|
|
80
|
+
await service
|
|
81
|
+
.removeCounter(SessionID, response.results)
|
|
82
|
+
.then(async (response) => {
|
|
83
|
+
console.log("removeCounter", response.results);
|
|
84
|
+
await service
|
|
85
|
+
.closeSession(SessionID)
|
|
86
|
+
.then((response) => {
|
|
87
|
+
console.log("closeSession", response.results);
|
|
88
|
+
})
|
|
89
|
+
.catch((error) => {
|
|
90
|
+
console.log(error.message);
|
|
91
|
+
});
|
|
92
|
+
})
|
|
93
|
+
.catch((error) => {
|
|
94
|
+
console.log(error.message);
|
|
95
|
+
});
|
|
96
|
+
})
|
|
97
|
+
.catch((error) => {
|
|
98
|
+
console.log(error.message);
|
|
99
|
+
});
|
|
100
|
+
})
|
|
101
|
+
.catch((error) => {
|
|
102
|
+
console.log(error.message);
|
|
103
|
+
});
|
|
104
|
+
})
|
|
105
|
+
.catch((error) => {
|
|
106
|
+
console.log(error.message);
|
|
107
|
+
});
|
|
115
108
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
109
|
+
console.log("Let's returns the list of available PerfMon objects and counters on a particular host");
|
|
110
|
+
await service
|
|
111
|
+
.listCounter(cucmServerName)
|
|
112
|
+
.then((response) => {
|
|
113
|
+
console.log("listCounter", response.results);
|
|
114
|
+
})
|
|
115
|
+
.catch((error) => {
|
|
116
|
+
console.log(error.message);
|
|
117
|
+
});
|
|
125
118
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
119
|
+
console.log("Let's return a list of instances of a PerfMon object on a particular host. Instances of an object can dynamically change. This operation returns the most recent list.");
|
|
120
|
+
await service
|
|
121
|
+
.listInstance(cucmServerName, "Processor")
|
|
122
|
+
.then((results) => {
|
|
123
|
+
console.log("listInstance", results.results);
|
|
124
|
+
})
|
|
125
|
+
.catch((error) => {
|
|
126
|
+
console.log(error.message);
|
|
127
|
+
});
|
|
135
128
|
})();
|