cisco-axl 1.2.5 → 1.3.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/README.md +34 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.js +265 -0
- package/dist/index.js.map +1 -0
- package/examples/typescript/README.md +44 -0
- package/examples/typescript/example.ts +94 -0
- package/package.json +12 -4
- package/src/index.ts +286 -0
- package/src/types/strong-soap.d.ts +13 -0
- package/tsconfig.json +20 -0
package/README.md
CHANGED
|
@@ -34,6 +34,7 @@ NODE_TLS_REJECT_UNAUTHORIZED=0
|
|
|
34
34
|
- Supports the Promise API. Can chain procedures together or you could use Promise.all() to run multiple "get" operations at the same time.
|
|
35
35
|
- Returns all results in JSON rather than XML. Function has options to remove all blank or empty fields from JSON results via optional clean parameter.
|
|
36
36
|
- Support for [json-variables](https://codsen.com/os/json-variables). The executeOperation function will recognize the dataContainerIdentifierTails from json-variables and remove them from your call. This avoids any SOAP fault issues from having extra information in call. See examples folder for use case.
|
|
37
|
+
- TypeScript support with type definitions for better developer experience and code reliability
|
|
37
38
|
|
|
38
39
|
## Usage
|
|
39
40
|
|
|
@@ -184,6 +185,39 @@ service.executeOperation("updateLine", lineTags,{ dataContainerIdentifierTails:
|
|
|
184
185
|
|
|
185
186
|
Currently there is an issue with strong-soap regarding returning nillable values for element tags. These values show if a particular tags is optional or not. Once resolved a method will be added to return tags nillable status (true or false).
|
|
186
187
|
|
|
188
|
+
## TypeScript Support
|
|
189
|
+
|
|
190
|
+
This library includes TypeScript declarations to provide type safety and improved developer experience.
|
|
191
|
+
|
|
192
|
+
### TypeScript Usage
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
import axlService from 'cisco-axl';
|
|
196
|
+
|
|
197
|
+
const service = new axlService(
|
|
198
|
+
"10.10.20.1",
|
|
199
|
+
"administrator",
|
|
200
|
+
"ciscopsdt",
|
|
201
|
+
"14.0"
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
async function getPartitions() {
|
|
205
|
+
try {
|
|
206
|
+
const operation = "listRoutePartition";
|
|
207
|
+
const tags = await service.getOperationTags(operation);
|
|
208
|
+
tags.searchCriteria.name = "%%";
|
|
209
|
+
|
|
210
|
+
const result = await service.executeOperation(operation, tags);
|
|
211
|
+
return result.routePartition;
|
|
212
|
+
} catch (error) {
|
|
213
|
+
console.error("Error fetching partitions:", error);
|
|
214
|
+
throw error;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
See the `examples/typescript` directory for more TypeScript examples.
|
|
220
|
+
|
|
187
221
|
## TODO
|
|
188
222
|
|
|
189
223
|
- Add more promised based examples, particularly a Promise.All() example.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
interface OperationOptions {
|
|
2
|
+
clean?: boolean;
|
|
3
|
+
dataContainerIdentifierTails?: string;
|
|
4
|
+
removeAttributes?: boolean;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Cisco axlService Service
|
|
8
|
+
* This is a service class that uses fetch and promises to pull AXL data from Cisco CUCM
|
|
9
|
+
*
|
|
10
|
+
* @class axlService
|
|
11
|
+
*/
|
|
12
|
+
declare class axlService {
|
|
13
|
+
private _OPTIONS;
|
|
14
|
+
/**
|
|
15
|
+
* Creates an instance of axlService.
|
|
16
|
+
* @param {string} host - CUCM hostname or IP address
|
|
17
|
+
* @param {string} username - CUCM username with AXL permissions
|
|
18
|
+
* @param {string} password - CUCM password
|
|
19
|
+
* @param {string} version - CUCM version (e.g. "14.0")
|
|
20
|
+
* @memberof axlService
|
|
21
|
+
*/
|
|
22
|
+
constructor(host: string, username: string, password: string, version: string);
|
|
23
|
+
/**
|
|
24
|
+
* Returns a list of available AXL operations
|
|
25
|
+
* @param {string} [filter] - Optional filter to narrow down operations
|
|
26
|
+
* @returns {Promise<string[]>} - Array of operation names
|
|
27
|
+
* @memberof axlService
|
|
28
|
+
*/
|
|
29
|
+
returnOperations(filter?: string): Promise<string[]>;
|
|
30
|
+
/**
|
|
31
|
+
* Gets the tags required for a specific AXL operation
|
|
32
|
+
* @param {string} operation - The AXL operation name
|
|
33
|
+
* @returns {Promise<any>} - Object containing the required tags
|
|
34
|
+
* @memberof axlService
|
|
35
|
+
*/
|
|
36
|
+
getOperationTags(operation: string): Promise<any>;
|
|
37
|
+
/**
|
|
38
|
+
* Executes an AXL operation against the CUCM
|
|
39
|
+
* @param {string} operation - The AXL operation to execute
|
|
40
|
+
* @param {any} tags - The tags required for the operation
|
|
41
|
+
* @param {OperationOptions} [opts] - Optional parameters for customizing the operation
|
|
42
|
+
* @returns {Promise<any>} - Result of the operation
|
|
43
|
+
* @memberof axlService
|
|
44
|
+
*/
|
|
45
|
+
executeOperation(operation: string, tags: any, opts?: OperationOptions): Promise<any>;
|
|
46
|
+
}
|
|
47
|
+
export = axlService;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
const soap = __importStar(require("strong-soap"));
|
|
36
|
+
const path = __importStar(require("path"));
|
|
37
|
+
const WSDL = soap.soap.WSDL;
|
|
38
|
+
const wsdlOptions = {
|
|
39
|
+
attributesKey: "attributes",
|
|
40
|
+
valueKey: "value",
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Cisco axlService Service
|
|
44
|
+
* This is a service class that uses fetch and promises to pull AXL data from Cisco CUCM
|
|
45
|
+
*
|
|
46
|
+
* @class axlService
|
|
47
|
+
*/
|
|
48
|
+
class axlService {
|
|
49
|
+
/**
|
|
50
|
+
* Creates an instance of axlService.
|
|
51
|
+
* @param {string} host - CUCM hostname or IP address
|
|
52
|
+
* @param {string} username - CUCM username with AXL permissions
|
|
53
|
+
* @param {string} password - CUCM password
|
|
54
|
+
* @param {string} version - CUCM version (e.g. "14.0")
|
|
55
|
+
* @memberof axlService
|
|
56
|
+
*/
|
|
57
|
+
constructor(host, username, password, version) {
|
|
58
|
+
if (!host || !username || !password || !version)
|
|
59
|
+
throw new TypeError("missing parameters");
|
|
60
|
+
this._OPTIONS = {
|
|
61
|
+
username: username,
|
|
62
|
+
password: password,
|
|
63
|
+
url: path.join(__dirname, `../schema/${version}/AXLAPI.wsdl`),
|
|
64
|
+
endpoint: `https://${host}:8443/axl/`,
|
|
65
|
+
version: version,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Returns a list of available AXL operations
|
|
70
|
+
* @param {string} [filter] - Optional filter to narrow down operations
|
|
71
|
+
* @returns {Promise<string[]>} - Array of operation names
|
|
72
|
+
* @memberof axlService
|
|
73
|
+
*/
|
|
74
|
+
returnOperations(filter) {
|
|
75
|
+
const options = this._OPTIONS;
|
|
76
|
+
return new Promise((resolve, reject) => {
|
|
77
|
+
soap.soap.createClient(options.url, wsdlOptions, function (err, client) {
|
|
78
|
+
if (err) {
|
|
79
|
+
reject(err);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
client.setSecurity(new soap.soap.BasicAuthSecurity(options.username, options.password));
|
|
83
|
+
client.setEndpoint(options.endpoint);
|
|
84
|
+
const description = client.describe();
|
|
85
|
+
const outputArr = [];
|
|
86
|
+
for (const [, value] of Object.entries(description.AXLAPIService.AXLPort)) {
|
|
87
|
+
outputArr.push(value.name);
|
|
88
|
+
}
|
|
89
|
+
const sortAlphaNum = (a, b) => a.localeCompare(b, "en", { numeric: true });
|
|
90
|
+
const matches = (substring, array) => array.filter((element) => {
|
|
91
|
+
if (element.toLowerCase().includes(substring.toLowerCase())) {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
});
|
|
96
|
+
if (filter) {
|
|
97
|
+
resolve(matches(filter, outputArr).sort(sortAlphaNum));
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
resolve(outputArr.sort(sortAlphaNum));
|
|
101
|
+
}
|
|
102
|
+
client.on("soapError", function (err) {
|
|
103
|
+
reject(err.root.Envelope.Body.Fault);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Gets the tags required for a specific AXL operation
|
|
110
|
+
* @param {string} operation - The AXL operation name
|
|
111
|
+
* @returns {Promise<any>} - Object containing the required tags
|
|
112
|
+
* @memberof axlService
|
|
113
|
+
*/
|
|
114
|
+
getOperationTags(operation) {
|
|
115
|
+
const options = this._OPTIONS;
|
|
116
|
+
return new Promise((resolve, reject) => {
|
|
117
|
+
WSDL.open(path.join(__dirname, `../schema/${options.version}/AXLAPI.wsdl`), wsdlOptions, function (err, wsdl) {
|
|
118
|
+
if (err) {
|
|
119
|
+
reject(err);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const operationDef = wsdl.definitions.bindings.AXLAPIBinding.operations[operation];
|
|
123
|
+
const operName = operationDef.$name;
|
|
124
|
+
const operationDesc = operationDef.describe(wsdl);
|
|
125
|
+
const envelopeBody = {};
|
|
126
|
+
operationDesc.input.body.elements.map((object) => {
|
|
127
|
+
const operMatch = new RegExp(object.qname.name, "i");
|
|
128
|
+
envelopeBody[object.qname.name] = "";
|
|
129
|
+
if (object.qname.name === "searchCriteria") {
|
|
130
|
+
const output = nestedObj(object);
|
|
131
|
+
envelopeBody.searchCriteria = output;
|
|
132
|
+
}
|
|
133
|
+
if (object.qname.name === "returnedTags") {
|
|
134
|
+
const output = nestedObj(object);
|
|
135
|
+
envelopeBody.returnedTags = output;
|
|
136
|
+
}
|
|
137
|
+
if (operName.match(operMatch)) {
|
|
138
|
+
const output = nestedObj(object);
|
|
139
|
+
envelopeBody[object.qname.name] = output;
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
resolve(envelopeBody);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Executes an AXL operation against the CUCM
|
|
148
|
+
* @param {string} operation - The AXL operation to execute
|
|
149
|
+
* @param {any} tags - The tags required for the operation
|
|
150
|
+
* @param {OperationOptions} [opts] - Optional parameters for customizing the operation
|
|
151
|
+
* @returns {Promise<any>} - Result of the operation
|
|
152
|
+
* @memberof axlService
|
|
153
|
+
*/
|
|
154
|
+
executeOperation(operation, tags, opts) {
|
|
155
|
+
var _a, _b, _c;
|
|
156
|
+
const options = this._OPTIONS;
|
|
157
|
+
const clean = (_a = opts === null || opts === void 0 ? void 0 : opts.clean) !== null && _a !== void 0 ? _a : false;
|
|
158
|
+
const dataContainerIdentifierTails = (_b = opts === null || opts === void 0 ? void 0 : opts.dataContainerIdentifierTails) !== null && _b !== void 0 ? _b : "_data";
|
|
159
|
+
const removeAttributes = (_c = opts === null || opts === void 0 ? void 0 : opts.removeAttributes) !== null && _c !== void 0 ? _c : false;
|
|
160
|
+
// Let's remove empty top level strings. Also filter out json-variables
|
|
161
|
+
Object.keys(tags).forEach((k) => (tags[k] === "" || k.includes(dataContainerIdentifierTails)) && delete tags[k]);
|
|
162
|
+
return new Promise((resolve, reject) => {
|
|
163
|
+
soap.soap.createClient(options.url, wsdlOptions, function (err, client) {
|
|
164
|
+
const customRequestHeader = { connection: "keep-alive" };
|
|
165
|
+
if (err) {
|
|
166
|
+
reject(err);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
client.setSecurity(new soap.soap.BasicAuthSecurity(options.username, options.password));
|
|
170
|
+
client.setEndpoint(options.endpoint);
|
|
171
|
+
client.on("soapError", function (err) {
|
|
172
|
+
reject(err.root.Envelope.Body.Fault);
|
|
173
|
+
});
|
|
174
|
+
const axlFunc = client.AXLAPIService.AXLPort[operation];
|
|
175
|
+
axlFunc(tags, function (err, result) {
|
|
176
|
+
if (err) {
|
|
177
|
+
reject(err);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (result === null || result === void 0 ? void 0 : result.hasOwnProperty("return")) {
|
|
181
|
+
const output = result.return;
|
|
182
|
+
if (clean) {
|
|
183
|
+
cleanObj(output);
|
|
184
|
+
}
|
|
185
|
+
if (removeAttributes) {
|
|
186
|
+
cleanAttributes(output);
|
|
187
|
+
}
|
|
188
|
+
resolve(output);
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
reject("No return results");
|
|
192
|
+
}
|
|
193
|
+
}, null, customRequestHeader);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Creates a nested object from WSDL elements
|
|
200
|
+
* @param {any} object - The WSDL object to process
|
|
201
|
+
* @returns {any} - Processed object
|
|
202
|
+
*/
|
|
203
|
+
const nestedObj = (object) => {
|
|
204
|
+
const operObj = {};
|
|
205
|
+
object.elements.map((object) => {
|
|
206
|
+
operObj[object.qname.name] = "";
|
|
207
|
+
if (Array.isArray(object.elements) && object.elements.length > 0) {
|
|
208
|
+
const nestName = object.qname.name;
|
|
209
|
+
operObj[nestName] = {};
|
|
210
|
+
const nestObj = nestedObj(object);
|
|
211
|
+
operObj[nestName] = nestObj;
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
const isEmpty = Object.keys(operObj).length === 0;
|
|
215
|
+
if (isEmpty) {
|
|
216
|
+
return "";
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
return operObj;
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
/**
|
|
223
|
+
* Cleans an object by removing null, undefined, or empty values
|
|
224
|
+
* @param {any} object - The object to clean
|
|
225
|
+
* @returns {any} - Cleaned object
|
|
226
|
+
*/
|
|
227
|
+
const cleanObj = (object) => {
|
|
228
|
+
Object.entries(object).forEach(([k, v]) => {
|
|
229
|
+
if (v && typeof v === "object") {
|
|
230
|
+
cleanObj(v);
|
|
231
|
+
}
|
|
232
|
+
if ((v && typeof v === "object" && !Object.keys(v).length) || v === null || v === undefined) {
|
|
233
|
+
if (Array.isArray(object)) {
|
|
234
|
+
object.splice(parseInt(k), 1);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
delete object[k];
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
return object;
|
|
242
|
+
};
|
|
243
|
+
/**
|
|
244
|
+
* Removes attribute fields from an object
|
|
245
|
+
* @param {any} object - The object to clean
|
|
246
|
+
* @returns {any} - Cleaned object
|
|
247
|
+
*/
|
|
248
|
+
const cleanAttributes = (object) => {
|
|
249
|
+
Object.entries(object).forEach(([k, v]) => {
|
|
250
|
+
if (v && typeof v === "object") {
|
|
251
|
+
cleanAttributes(v);
|
|
252
|
+
}
|
|
253
|
+
if (v && typeof v === "object" && "attributes" in object) {
|
|
254
|
+
if (Array.isArray(object)) {
|
|
255
|
+
object.splice(parseInt(k), 1);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
delete object[k];
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
return object;
|
|
263
|
+
};
|
|
264
|
+
module.exports = axlService;
|
|
265
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# TypeScript Example
|
|
2
|
+
|
|
3
|
+
This example demonstrates how to use the cisco-axl library with TypeScript.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Node.js v16.15.0 or later
|
|
8
|
+
- TypeScript installed globally: `npm install -g typescript`
|
|
9
|
+
|
|
10
|
+
## Running the Example
|
|
11
|
+
|
|
12
|
+
1. Build the project first:
|
|
13
|
+
```
|
|
14
|
+
npm run build
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
2. Update the example.ts file with your CUCM server details:
|
|
18
|
+
```typescript
|
|
19
|
+
const service = new axlService(
|
|
20
|
+
"your-cucm-hostname",
|
|
21
|
+
"username",
|
|
22
|
+
"password",
|
|
23
|
+
"14.0" // CUCM version
|
|
24
|
+
);
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
3. Run the example:
|
|
28
|
+
```
|
|
29
|
+
npx ts-node example.ts
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Features Demonstrated
|
|
33
|
+
|
|
34
|
+
- TypeScript type definitions
|
|
35
|
+
- Async/await syntax with proper error handling
|
|
36
|
+
- Adding a route partition
|
|
37
|
+
- Listing route partitions
|
|
38
|
+
|
|
39
|
+
## TypeScript Benefits
|
|
40
|
+
|
|
41
|
+
- Static type checking
|
|
42
|
+
- Better IDE autocompletion
|
|
43
|
+
- Improved documentation with JSDoc comments
|
|
44
|
+
- More maintainable codebase
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import axlService from '../../src/index';
|
|
2
|
+
import { cleanEnv, str, host, makeValidator } from 'envalid';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import dotenv from 'dotenv';
|
|
5
|
+
|
|
6
|
+
// Load environment variables from the appropriate .env file
|
|
7
|
+
if (process.env.NODE_ENV === "development") {
|
|
8
|
+
dotenv.config({ path: path.join(__dirname, '..', '..', 'env', 'development.env') });
|
|
9
|
+
} else if (process.env.NODE_ENV === "test") {
|
|
10
|
+
dotenv.config({ path: path.join(__dirname, '..', '..', 'env', 'test.env') });
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Validator for CUCM version format
|
|
14
|
+
const versionValid = makeValidator(x => {
|
|
15
|
+
if (/.*\..*[^\\]/.test(x)) return x.toUpperCase();
|
|
16
|
+
else throw new Error('CUCM_VERSION must be in the format of ##.#');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// Clean and validate environment variables
|
|
20
|
+
const env = cleanEnv(process.env, {
|
|
21
|
+
NODE_ENV: str({
|
|
22
|
+
choices: ["development", "test", "production", "staging"],
|
|
23
|
+
desc: "Node environment",
|
|
24
|
+
default: "development"
|
|
25
|
+
}),
|
|
26
|
+
CUCM_HOSTNAME: host({
|
|
27
|
+
desc: "Cisco CUCM Hostname or IP Address.",
|
|
28
|
+
default: "cucm01-pub.automate.builder"
|
|
29
|
+
}),
|
|
30
|
+
CUCM_USERNAME: str({
|
|
31
|
+
desc: "Cisco CUCM AXL Username.",
|
|
32
|
+
default: "perfmon"
|
|
33
|
+
}),
|
|
34
|
+
CUCM_PASSWORD: str({
|
|
35
|
+
desc: "Cisco CUCM AXL Password.",
|
|
36
|
+
default: "perfmon"
|
|
37
|
+
}),
|
|
38
|
+
CUCM_VERSION: versionValid({
|
|
39
|
+
desc: "Cisco CUCM Version.",
|
|
40
|
+
example: "12.5",
|
|
41
|
+
default: "15.0"
|
|
42
|
+
})
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
async function main() {
|
|
46
|
+
try {
|
|
47
|
+
// Initialize AXL service using environment variables
|
|
48
|
+
const service = new axlService(
|
|
49
|
+
env.CUCM_HOSTNAME,
|
|
50
|
+
env.CUCM_USERNAME,
|
|
51
|
+
env.CUCM_PASSWORD,
|
|
52
|
+
env.CUCM_VERSION
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
// Example of adding a route partition
|
|
56
|
+
const operation = "addRoutePartition";
|
|
57
|
+
const tags = {
|
|
58
|
+
routePartition: {
|
|
59
|
+
name: "TYPESCRIPT-PT",
|
|
60
|
+
description: "Created with TypeScript",
|
|
61
|
+
timeScheduleIdName: "",
|
|
62
|
+
useOriginatingDeviceTimeZone: "",
|
|
63
|
+
timeZone: "",
|
|
64
|
+
partitionUsage: "",
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
console.log("Adding route partition...");
|
|
69
|
+
const result = await service.executeOperation(operation, tags);
|
|
70
|
+
console.log("Route partition added with UUID:", result);
|
|
71
|
+
|
|
72
|
+
// Example of listing route partitions
|
|
73
|
+
const listOperation = "listRoutePartition";
|
|
74
|
+
const listTags = await service.getOperationTags(listOperation);
|
|
75
|
+
listTags.searchCriteria.name = "%%";
|
|
76
|
+
|
|
77
|
+
console.log("Listing route partitions...");
|
|
78
|
+
const partitions = await service.executeOperation(listOperation, listTags);
|
|
79
|
+
|
|
80
|
+
// Display the partitions
|
|
81
|
+
console.log("Route partitions:");
|
|
82
|
+
if (Array.isArray(partitions.routePartition)) {
|
|
83
|
+
partitions.routePartition.forEach((partition: any) => {
|
|
84
|
+
console.log(`- ${partition.name}`);
|
|
85
|
+
});
|
|
86
|
+
} else if (partitions.routePartition) {
|
|
87
|
+
console.log(`- ${partitions.routePartition.name}`);
|
|
88
|
+
}
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error("Error:", error);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cisco-axl",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "A library to make Cisco AXL a lot easier",
|
|
5
|
-
"main": "index.js",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
6
7
|
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"prepare": "npm run build",
|
|
7
10
|
"test": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 NODE_TLS_REJECT_UNAUTHORIZED=0 NODE_ENV=test node ./test/tests.js",
|
|
8
11
|
"development": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 NODE_TLS_REJECT_UNAUTHORIZED=0 NODE_ENV=development node ./test/tests.js",
|
|
9
12
|
"staging": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 NODE_TLS_REJECT_UNAUTHORIZED=0 NODE_ENV=staging node ./test/tests.js",
|
|
10
|
-
"wsdl": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 NODE_TLS_REJECT_UNAUTHORIZED=0 NODE_ENV=staging node ./test/wsdl.js"
|
|
13
|
+
"wsdl": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 NODE_TLS_REJECT_UNAUTHORIZED=0 NODE_ENV=staging node ./test/wsdl.js",
|
|
14
|
+
"type-check": "tsc --noEmit",
|
|
15
|
+
"ts-example": "ts-node examples/typescript/example.ts"
|
|
11
16
|
},
|
|
12
17
|
"repository": {
|
|
13
18
|
"type": "git",
|
|
@@ -31,9 +36,12 @@
|
|
|
31
36
|
"strong-soap": "^4.1.5"
|
|
32
37
|
},
|
|
33
38
|
"devDependencies": {
|
|
39
|
+
"@types/node": "^22.13.5",
|
|
34
40
|
"dotenv": "*",
|
|
35
41
|
"envalid": "*",
|
|
36
42
|
"json-variables": "^10.1.0",
|
|
37
|
-
"node-emoji": "*"
|
|
43
|
+
"node-emoji": "*",
|
|
44
|
+
"ts-node": "^10.9.2",
|
|
45
|
+
"typescript": "^5.7.3"
|
|
38
46
|
}
|
|
39
47
|
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import * as soap from 'strong-soap';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
|
|
4
|
+
const WSDL = soap.soap.WSDL;
|
|
5
|
+
|
|
6
|
+
const wsdlOptions = {
|
|
7
|
+
attributesKey: "attributes",
|
|
8
|
+
valueKey: "value",
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
interface AXLServiceOptions {
|
|
12
|
+
username: string;
|
|
13
|
+
password: string;
|
|
14
|
+
url: string;
|
|
15
|
+
endpoint: string;
|
|
16
|
+
version: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface OperationOptions {
|
|
20
|
+
clean?: boolean;
|
|
21
|
+
dataContainerIdentifierTails?: string;
|
|
22
|
+
removeAttributes?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Cisco axlService Service
|
|
27
|
+
* This is a service class that uses fetch and promises to pull AXL data from Cisco CUCM
|
|
28
|
+
*
|
|
29
|
+
* @class axlService
|
|
30
|
+
*/
|
|
31
|
+
class axlService {
|
|
32
|
+
private _OPTIONS: AXLServiceOptions;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Creates an instance of axlService.
|
|
36
|
+
* @param {string} host - CUCM hostname or IP address
|
|
37
|
+
* @param {string} username - CUCM username with AXL permissions
|
|
38
|
+
* @param {string} password - CUCM password
|
|
39
|
+
* @param {string} version - CUCM version (e.g. "14.0")
|
|
40
|
+
* @memberof axlService
|
|
41
|
+
*/
|
|
42
|
+
constructor(host: string, username: string, password: string, version: string) {
|
|
43
|
+
if (!host || !username || !password || !version) throw new TypeError("missing parameters");
|
|
44
|
+
this._OPTIONS = {
|
|
45
|
+
username: username,
|
|
46
|
+
password: password,
|
|
47
|
+
url: path.join(__dirname, `../schema/${version}/AXLAPI.wsdl`),
|
|
48
|
+
endpoint: `https://${host}:8443/axl/`,
|
|
49
|
+
version: version,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Returns a list of available AXL operations
|
|
55
|
+
* @param {string} [filter] - Optional filter to narrow down operations
|
|
56
|
+
* @returns {Promise<string[]>} - Array of operation names
|
|
57
|
+
* @memberof axlService
|
|
58
|
+
*/
|
|
59
|
+
returnOperations(filter?: string): Promise<string[]> {
|
|
60
|
+
const options = this._OPTIONS;
|
|
61
|
+
return new Promise((resolve, reject) => {
|
|
62
|
+
soap.soap.createClient(options.url, wsdlOptions, function (err: any, client: any) {
|
|
63
|
+
if (err) {
|
|
64
|
+
reject(err);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
client.setSecurity(new soap.soap.BasicAuthSecurity(options.username, options.password));
|
|
69
|
+
client.setEndpoint(options.endpoint);
|
|
70
|
+
|
|
71
|
+
const description = client.describe();
|
|
72
|
+
const outputArr: string[] = [];
|
|
73
|
+
|
|
74
|
+
for (const [, value] of Object.entries(description.AXLAPIService.AXLPort)) {
|
|
75
|
+
outputArr.push((value as any).name);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const sortAlphaNum = (a: string, b: string) => a.localeCompare(b, "en", { numeric: true });
|
|
79
|
+
const matches = (substring: string, array: string[]) =>
|
|
80
|
+
array.filter((element) => {
|
|
81
|
+
if (element.toLowerCase().includes(substring.toLowerCase())) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
if (filter) {
|
|
88
|
+
resolve(matches(filter, outputArr).sort(sortAlphaNum));
|
|
89
|
+
} else {
|
|
90
|
+
resolve(outputArr.sort(sortAlphaNum));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
client.on("soapError", function (err: any) {
|
|
94
|
+
reject(err.root.Envelope.Body.Fault);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Gets the tags required for a specific AXL operation
|
|
102
|
+
* @param {string} operation - The AXL operation name
|
|
103
|
+
* @returns {Promise<any>} - Object containing the required tags
|
|
104
|
+
* @memberof axlService
|
|
105
|
+
*/
|
|
106
|
+
getOperationTags(operation: string): Promise<any> {
|
|
107
|
+
const options = this._OPTIONS;
|
|
108
|
+
return new Promise((resolve, reject) => {
|
|
109
|
+
WSDL.open(path.join(__dirname, `../schema/${options.version}/AXLAPI.wsdl`), wsdlOptions, function (err: any, wsdl: any) {
|
|
110
|
+
if (err) {
|
|
111
|
+
reject(err);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const operationDef = wsdl.definitions.bindings.AXLAPIBinding.operations[operation];
|
|
115
|
+
const operName = operationDef.$name;
|
|
116
|
+
const operationDesc = operationDef.describe(wsdl);
|
|
117
|
+
const envelopeBody: any = {};
|
|
118
|
+
|
|
119
|
+
operationDesc.input.body.elements.map((object: any) => {
|
|
120
|
+
const operMatch = new RegExp(object.qname.name, "i");
|
|
121
|
+
envelopeBody[object.qname.name] = "";
|
|
122
|
+
|
|
123
|
+
if (object.qname.name === "searchCriteria") {
|
|
124
|
+
const output = nestedObj(object);
|
|
125
|
+
envelopeBody.searchCriteria = output;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (object.qname.name === "returnedTags") {
|
|
129
|
+
const output = nestedObj(object);
|
|
130
|
+
envelopeBody.returnedTags = output;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (operName.match(operMatch)) {
|
|
134
|
+
const output = nestedObj(object);
|
|
135
|
+
envelopeBody[object.qname.name] = output;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
resolve(envelopeBody);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Executes an AXL operation against the CUCM
|
|
146
|
+
* @param {string} operation - The AXL operation to execute
|
|
147
|
+
* @param {any} tags - The tags required for the operation
|
|
148
|
+
* @param {OperationOptions} [opts] - Optional parameters for customizing the operation
|
|
149
|
+
* @returns {Promise<any>} - Result of the operation
|
|
150
|
+
* @memberof axlService
|
|
151
|
+
*/
|
|
152
|
+
executeOperation(operation: string, tags: any, opts?: OperationOptions): Promise<any> {
|
|
153
|
+
const options = this._OPTIONS;
|
|
154
|
+
|
|
155
|
+
const clean = opts?.clean ?? false;
|
|
156
|
+
const dataContainerIdentifierTails = opts?.dataContainerIdentifierTails ?? "_data";
|
|
157
|
+
const removeAttributes = opts?.removeAttributes ?? false;
|
|
158
|
+
|
|
159
|
+
// Let's remove empty top level strings. Also filter out json-variables
|
|
160
|
+
Object.keys(tags).forEach((k) => (tags[k] === "" || k.includes(dataContainerIdentifierTails)) && delete tags[k]);
|
|
161
|
+
|
|
162
|
+
return new Promise((resolve, reject) => {
|
|
163
|
+
soap.soap.createClient(options.url, wsdlOptions, function (err: any, client: any) {
|
|
164
|
+
const customRequestHeader = { connection: "keep-alive" };
|
|
165
|
+
|
|
166
|
+
if (err) {
|
|
167
|
+
reject(err);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
client.setSecurity(new soap.soap.BasicAuthSecurity(options.username, options.password));
|
|
172
|
+
client.setEndpoint(options.endpoint);
|
|
173
|
+
|
|
174
|
+
client.on("soapError", function (err: any) {
|
|
175
|
+
reject(err.root.Envelope.Body.Fault);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const axlFunc = client.AXLAPIService.AXLPort[operation];
|
|
179
|
+
|
|
180
|
+
axlFunc(
|
|
181
|
+
tags,
|
|
182
|
+
function (err: any, result: any) {
|
|
183
|
+
if (err) {
|
|
184
|
+
reject(err);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (result?.hasOwnProperty("return")) {
|
|
189
|
+
const output = result.return;
|
|
190
|
+
|
|
191
|
+
if (clean) {
|
|
192
|
+
cleanObj(output);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (removeAttributes) {
|
|
196
|
+
cleanAttributes(output);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
resolve(output);
|
|
200
|
+
} else {
|
|
201
|
+
reject("No return results");
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
null,
|
|
205
|
+
customRequestHeader
|
|
206
|
+
);
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Creates a nested object from WSDL elements
|
|
214
|
+
* @param {any} object - The WSDL object to process
|
|
215
|
+
* @returns {any} - Processed object
|
|
216
|
+
*/
|
|
217
|
+
const nestedObj = (object: any): any => {
|
|
218
|
+
const operObj: any = {};
|
|
219
|
+
|
|
220
|
+
object.elements.map((object: any) => {
|
|
221
|
+
operObj[object.qname.name] = "";
|
|
222
|
+
|
|
223
|
+
if (Array.isArray(object.elements) && object.elements.length > 0) {
|
|
224
|
+
const nestName = object.qname.name;
|
|
225
|
+
operObj[nestName] = {};
|
|
226
|
+
const nestObj = nestedObj(object);
|
|
227
|
+
operObj[nestName] = nestObj;
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
const isEmpty = Object.keys(operObj).length === 0;
|
|
232
|
+
|
|
233
|
+
if (isEmpty) {
|
|
234
|
+
return "";
|
|
235
|
+
} else {
|
|
236
|
+
return operObj;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Cleans an object by removing null, undefined, or empty values
|
|
242
|
+
* @param {any} object - The object to clean
|
|
243
|
+
* @returns {any} - Cleaned object
|
|
244
|
+
*/
|
|
245
|
+
const cleanObj = (object: any): any => {
|
|
246
|
+
Object.entries(object).forEach(([k, v]) => {
|
|
247
|
+
if (v && typeof v === "object") {
|
|
248
|
+
cleanObj(v);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if ((v && typeof v === "object" && !Object.keys(v).length) || v === null || v === undefined) {
|
|
252
|
+
if (Array.isArray(object)) {
|
|
253
|
+
object.splice(parseInt(k), 1);
|
|
254
|
+
} else {
|
|
255
|
+
delete object[k];
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
return object;
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Removes attribute fields from an object
|
|
265
|
+
* @param {any} object - The object to clean
|
|
266
|
+
* @returns {any} - Cleaned object
|
|
267
|
+
*/
|
|
268
|
+
const cleanAttributes = (object: any): any => {
|
|
269
|
+
Object.entries(object).forEach(([k, v]) => {
|
|
270
|
+
if (v && typeof v === "object") {
|
|
271
|
+
cleanAttributes(v);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (v && typeof v === "object" && "attributes" in object) {
|
|
275
|
+
if (Array.isArray(object)) {
|
|
276
|
+
object.splice(parseInt(k), 1);
|
|
277
|
+
} else {
|
|
278
|
+
delete object[k];
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
return object;
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
export = axlService;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
declare module 'strong-soap' {
|
|
2
|
+
export namespace soap {
|
|
3
|
+
export class WSDL {
|
|
4
|
+
static open(wsdlUri: string, options: any, callback: (err: any, wsdl: any) => void): void;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function createClient(wsdlPath: string, options: any, callback: (err: any, client: any) => void): void;
|
|
8
|
+
|
|
9
|
+
export class BasicAuthSecurity {
|
|
10
|
+
constructor(username: string, password: string);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2018",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"sourceMap": true,
|
|
13
|
+
"typeRoots": [
|
|
14
|
+
"./node_modules/@types",
|
|
15
|
+
"./src/types"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*"],
|
|
19
|
+
"exclude": ["node_modules", "**/*.test.ts"]
|
|
20
|
+
}
|