cisco-axl 2.0.0 → 2.1.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.
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "cisco-axl",
3
+ "description": "Cisco CUCM AXL CLI skills for provisioning phones, lines, route patterns, partitions, CSS, and more via the Administrative XML API",
4
+ "version": "2.0.0",
5
+ "author": {
6
+ "name": "Jeremy Worden",
7
+ "url": "https://github.com/sieteunoseis"
8
+ },
9
+ "homepage": "https://github.com/sieteunoseis/cisco-axl#readme",
10
+ "repository": "https://github.com/sieteunoseis/cisco-axl",
11
+ "license": "MIT",
12
+ "keywords": [
13
+ "cisco",
14
+ "cucm",
15
+ "axl",
16
+ "unified-communications",
17
+ "voip",
18
+ "telephony",
19
+ "provisioning",
20
+ "soap",
21
+ "callmanager",
22
+ "cli",
23
+ "automation",
24
+ "bulk-provisioning"
25
+ ]
26
+ }
@@ -0,0 +1 @@
1
+ buy_me_a_coffee: automatebldrs
@@ -12,7 +12,7 @@ jobs:
12
12
 
13
13
  strategy:
14
14
  matrix:
15
- node-version: [18, 20, 22]
15
+ node-version: [20, 22]
16
16
 
17
17
  steps:
18
18
  - uses: actions/checkout@v4
@@ -3,11 +3,11 @@ name: Release
3
3
  on:
4
4
  push:
5
5
  tags:
6
- - 'v*'
6
+ - "v*"
7
7
 
8
8
  permissions:
9
- id-token: write # Required for OIDC authentication
10
- contents: write # Required for creating GitHub Release
9
+ id-token: write # Required for OIDC authentication
10
+ contents: write # Required for creating GitHub Release
11
11
 
12
12
  jobs:
13
13
  publish:
@@ -19,8 +19,8 @@ jobs:
19
19
  - name: Setup Node.js
20
20
  uses: actions/setup-node@v4
21
21
  with:
22
- node-version: '22'
23
- registry-url: 'https://registry.npmjs.org'
22
+ node-version: "22"
23
+ registry-url: "https://registry.npmjs.org"
24
24
 
25
25
  - name: Update npm
26
26
  run: npm install -g npm@latest
@@ -41,7 +41,7 @@ jobs:
41
41
  run: node -e "const axlService = require('./dist/index.js'); console.log('CJS require OK');"
42
42
 
43
43
  - name: Publish to npm
44
- run: npm publish --access public
44
+ run: npm publish --access public --provenance
45
45
 
46
46
  - name: Create GitHub Release
47
47
  uses: softprops/action-gh-release@v2
package/README.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Cisco AXL Library & CLI
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/cisco-axl.svg)](https://www.npmjs.com/package/cisco-axl)
4
+ [![CI](https://github.com/sieteunoseis/cisco-axl/actions/workflows/ci.yml/badge.svg)](https://github.com/sieteunoseis/cisco-axl/actions/workflows/ci.yml)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+ [![Node.js Version](https://img.shields.io/node/v/cisco-axl.svg)](https://nodejs.org)
7
+ [![Skills](https://img.shields.io/badge/skills.sh-cisco--axl--cli-blue)](https://skills.sh/sieteunoseis/cisco-axl)
8
+ [![Buy Me a Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-support-orange?logo=buy-me-a-coffee)](https://buymeacoffee.com/automatebldrs)
9
+
3
10
  A JavaScript library and CLI to interact with Cisco CUCM via AXL SOAP API. Dynamically discovers all AXL operations from the WSDL schema — any operation for your specified version is available without static definitions.
4
11
 
5
12
  Administrative XML (AXL) information can be found at:
@@ -26,7 +33,7 @@ npx cisco-axl --help
26
33
  ### AI Agent Skills
27
34
 
28
35
  ```bash
29
- npx skillsadd sieteunoseis/cisco-axl
36
+ npx skills add sieteunoseis/cisco-axl
30
37
  ```
31
38
 
32
39
  ## Requirements
@@ -35,11 +42,7 @@ If you are using self-signed certificates on Cisco VOS products you may need to
35
42
 
36
43
  Supported CUCM versions: `11.0`, `11.5`, `12.0`, `12.5`, `14.0`, `15.0`
37
44
 
38
- ## CLI
39
-
40
- The CLI provides full AXL access from the command line — CRUD operations, SQL queries, operation discovery, bulk provisioning from CSV, and a raw execute escape hatch for any AXL operation.
41
-
42
- ### Quick Start
45
+ ## Quick Start
43
46
 
44
47
  ```bash
45
48
  # Configure a cluster
@@ -52,27 +55,31 @@ cisco-axl config test
52
55
  cisco-axl list Phone --search "name=SEP%"
53
56
 
54
57
  # Get a specific phone
55
- cisco-axl get Phone SEP001122334455 --returned-tags "name,model,description"
58
+ cisco-axl get Phone SEP001122334455
56
59
 
57
60
  # SQL query
58
61
  cisco-axl sql query "SELECT name, description FROM device WHERE name LIKE 'SEP%'"
62
+ ```
59
63
 
60
- # Discover available operations
61
- cisco-axl operations --filter phone
62
- cisco-axl operations --type action --filter phone
63
-
64
- # Describe what tags an operation needs
65
- cisco-axl describe getPhone --detailed
64
+ ## Configuration
66
65
 
67
- # Execute any AXL operation
68
- cisco-axl execute doLdapSync --tags '{"name":"LDAP_Main"}'
66
+ ```bash
67
+ cisco-axl config add <name> --host <host> --username <user> --password <pass> --cucm-version <ver> --insecure
68
+ cisco-axl config use <name> # switch active cluster
69
+ cisco-axl config list # list all clusters
70
+ cisco-axl config show # show active cluster (masks passwords)
71
+ cisco-axl config remove <name> # remove a cluster
72
+ cisco-axl config test # test connectivity
69
73
  ```
70
74
 
71
- ### Commands
75
+ Auth precedence: CLI flags > env vars (`CUCM_HOST`, `CUCM_USERNAME`, `CUCM_PASSWORD`, `CUCM_VERSION`) > config file.
76
+
77
+ Config stored at `~/.cisco-axl/config.json`. Supports [ss-cli](https://github.com/sieteunoseis/ss-cli) `<ss:ID:field>` placeholders.
78
+
79
+ ## CLI Commands
72
80
 
73
81
  | Command | Description |
74
82
  |---------|-------------|
75
- | `config add/use/list/show/remove/test` | Manage multi-cluster configurations |
76
83
  | `get <type> <identifier>` | Get a single item |
77
84
  | `list <type>` | List items with search, pagination, returned tags |
78
85
  | `add <type>` | Add an item (inline JSON, template, or bulk CSV) |
@@ -80,281 +87,52 @@ cisco-axl execute doLdapSync --tags '{"name":"LDAP_Main"}'
80
87
  | `remove <type> <identifier>` | Remove an item |
81
88
  | `sql query/update` | Execute SQL against CUCM |
82
89
  | `execute <operation>` | Run any raw AXL operation |
83
- | `operations` | List available operations with `--filter` and `--type crud\|action` |
84
- | `describe <operation>` | Show tag schema with `--detailed` for required/optional/type info |
85
-
86
- ### Configuration
87
-
88
- ```bash
89
- # Multiple clusters
90
- cisco-axl config add lab --host 10.0.0.1 --username admin --password secret --cucm-version 14.0 --insecure
91
- cisco-axl config add prod --host 10.0.0.2 --username axladmin --password secret --cucm-version 15.0 --insecure
92
- cisco-axl config use prod
93
- cisco-axl config list
90
+ | `operations` | List available operations |
91
+ | `describe <operation>` | Show tag schema for an operation |
92
+ | `doctor` | Check AXL connectivity and health |
94
93
 
95
- # Per-command cluster override
96
- cisco-axl list Phone --search "name=SEP%" --cluster lab
94
+ See [full CLI reference](docs/cli.md) for bulk CSV, command chaining, piping with `--stdin`, and operation discovery.
97
95
 
98
- # Environment variables (CI/CD, AI agents)
99
- export CUCM_HOST=10.0.0.1 CUCM_USERNAME=admin CUCM_PASSWORD=secret CUCM_VERSION=14.0
100
- ```
101
-
102
- Config stored at `~/.cisco-axl/config.json`. Supports optional [Secret Server](https://github.com/sieteunoseis/ss-cli) integration via `<ss:ID:field>` placeholders.
103
-
104
- ### Output Formats
105
-
106
- ```bash
107
- cisco-axl list Phone --search "name=SEP%" --format table # default, human-readable
108
- cisco-axl list Phone --search "name=SEP%" --format json # structured JSON
109
- cisco-axl list Phone --search "name=SEP%" --format toon # token-efficient for AI agents
110
- cisco-axl list Phone --search "name=SEP%" --format csv # spreadsheet export
111
- ```
96
+ ## Global Flags
112
97
 
113
- ### Bulk Operations from CSV
114
-
115
- Requires optional packages: `npm install json-variables csv-parse`
116
-
117
- ```bash
118
- # Bulk add phones from template + CSV
119
- cisco-axl add Phone --template phone-template.json --csv phones.csv
120
- cisco-axl add Phone --template phone-template.json --csv phones.csv --dry-run # preview first
121
-
122
- # Single template with inline vars
123
- cisco-axl add Phone --template phone-template.json --vars '{"mac":"001122334455","dp":"DP_HQ"}'
124
- ```
125
-
126
- Template file (`phone-template.json`):
127
- ```json
128
- {
129
- "name": "SEP%%mac%%",
130
- "devicePoolName": "%%devicePool%%",
131
- "description": "%%description%%",
132
- "protocol": "SIP"
133
- }
134
- ```
135
-
136
- ### Global Flags
137
-
138
- ```
139
- --format table|json|toon|csv Output format (default: table)
140
- --insecure Skip TLS certificate verification
141
- --clean Remove empty/null values from results
142
- --no-attributes Remove XML attributes from results
143
- --read-only Restrict to read-only operations
144
- --no-audit Disable audit logging for this command
145
- --debug Enable debug logging
146
- ```
147
-
148
- ### Audit Trail
149
-
150
- All operations are logged to `~/.cisco-axl/audit.jsonl` (JSONL format). Credentials are never logged. Use `--no-audit` to skip.
98
+ | Flag | Description |
99
+ |------|-------------|
100
+ | `--format table\|json\|toon\|csv` | Output format (default: table) |
101
+ | `--insecure` | Skip TLS certificate verification |
102
+ | `--clean` | Remove empty/null values from results |
103
+ | `--no-attributes` | Remove XML attributes from results |
104
+ | `--read-only` | Restrict to read-only operations |
105
+ | `--no-audit` | Disable audit logging for this command |
106
+ | `--debug` | Enable debug logging |
151
107
 
152
108
  ## Library API
153
109
 
154
- ### Setup
155
-
156
110
  ```javascript
157
111
  const axlService = require("cisco-axl");
112
+ const service = new axlService("10.10.20.1", "administrator", "ciscopsdt", "14.0");
158
113
 
159
- let service = new axlService("10.10.20.1", "administrator", "ciscopsdt", "14.0");
160
-
161
- // With options
162
- let service = new axlService("10.10.20.1", "administrator", "ciscopsdt", "14.0", {
163
- logging: { level: "info" },
164
- retry: { retries: 3, retryDelay: 1000 }
165
- });
166
- ```
167
-
168
- ### Logging
169
-
170
- ```javascript
171
- // Via environment variable
172
- // DEBUG=true
173
-
174
- // Via constructor
175
- let service = new axlService("10.10.20.1", "administrator", "ciscopsdt", "14.0", {
176
- logging: {
177
- level: "info", // "error" | "warn" | "info" | "debug"
178
- handler: (level, message, data) => {
179
- myLogger[level](message, data);
180
- }
181
- }
182
- });
183
-
184
- // Change at runtime
185
- service.setLogLevel("debug");
186
- ```
187
-
188
- ### Convenience Methods
189
-
190
- ```javascript
191
- // Get a single item by name or UUID
114
+ // Get, list, add, update, remove
192
115
  await service.getItem("Phone", "SEP001122334455");
193
- await service.getItem("Phone", { uuid: "abc-123" });
194
-
195
- // List items with search criteria and returned tags
196
- await service.listItems("RoutePartition"); // all partitions
197
- await service.listItems("Phone", { name: "SEP%" }, { name: "", model: "" });
198
-
199
- // Add, update, remove
116
+ await service.listItems("Phone", { name: "SEP%" });
200
117
  await service.addItem("RoutePartition", { name: "NEW-PT", description: "New" });
201
- await service.updateItem("Phone", "SEP001122334455", { description: "Updated" });
202
- await service.removeItem("RoutePartition", "NEW-PT");
203
118
 
204
119
  // SQL
205
- const rows = await service.executeSqlQuery("SELECT name FROM routepartition");
206
- await service.executeSqlUpdate("UPDATE routepartition SET description='test' WHERE name='NEW-PT'");
207
- ```
208
-
209
- ### Operation Discovery
210
-
211
- ```javascript
212
- // List all operations
213
- const ops = await service.returnOperations();
214
- const phoneOps = await service.returnOperations("phone");
215
-
216
- // Get tag schema
217
- const tags = await service.getOperationTags("addRoutePartition");
218
-
219
- // Get detailed metadata (required, nillable, type)
220
- const detailed = await service.getOperationTagsDetailed("addRoutePartition");
221
- console.log(detailed.routePartition.required); // true
222
- console.log(detailed.routePartition.children.name.type); // "string"
223
- ```
224
-
225
- ### Execute Any Operation
120
+ await service.executeSqlQuery("SELECT name FROM routepartition");
226
121
 
227
- ```javascript
122
+ // Any AXL operation
228
123
  const tags = await service.getOperationTags("addRoutePartition");
229
124
  tags.routePartition.name = "INTERNAL-PT";
230
- tags.routePartition.description = "Internal directory numbers";
231
-
232
- const result = await service.executeOperation("addRoutePartition", tags);
233
- console.log("UUID:", result);
234
- ```
235
-
236
- ### Batch Operations
237
-
238
- ```javascript
239
- const results = await service.executeBatch([
240
- { operation: "getPhone", tags: { name: "SEP001122334455" } },
241
- { operation: "getPhone", tags: { name: "SEP556677889900" } },
242
- ], 5); // concurrency limit
243
-
244
- results.forEach((r) => {
245
- console.log(r.success ? `${r.operation}: OK` : `${r.operation}: ${r.error.message}`);
246
- });
125
+ await service.executeOperation("addRoutePartition", tags);
247
126
  ```
248
127
 
249
- ### Error Handling
128
+ See [full API documentation](docs/api.md) for all methods, error handling, batch operations, TypeScript, retry config, and logging.
250
129
 
251
- ```javascript
252
- const { AXLAuthError, AXLNotFoundError, AXLOperationError, AXLValidationError } = require("cisco-axl");
253
-
254
- try {
255
- await service.executeOperation("getPhone", { name: "INVALID" });
256
- } catch (error) {
257
- if (error instanceof AXLAuthError) console.log("Bad credentials");
258
- else if (error instanceof AXLNotFoundError) console.log("Operation not found:", error.operation);
259
- else if (error instanceof AXLOperationError) console.log("SOAP fault:", error.message);
260
- else if (error instanceof AXLValidationError) console.log("Invalid input:", error.message);
261
- }
262
- ```
263
-
264
- ### Retry Configuration
265
-
266
- ```javascript
267
- let service = new axlService("10.10.20.1", "admin", "pass", "14.0", {
268
- retry: {
269
- retries: 3,
270
- retryDelay: 1000,
271
- retryOn: (error) => error.message.includes("ECONNRESET")
272
- }
273
- });
274
- ```
275
-
276
- ### ESM Support
277
-
278
- ```javascript
279
- // CommonJS
280
- const axlService = require("cisco-axl");
281
-
282
- // ESM
283
- import axlService from "cisco-axl";
284
- import { AXLAuthError, AXLOperationError } from "cisco-axl";
285
- ```
286
-
287
- ### json-variables Support
288
-
289
- ```javascript
290
- var lineTemplate = {
291
- pattern: "%%_extension_%%",
292
- alertingName: "%%_firstName_%% %%_lastName_%%",
293
- description: "%%_firstName_%% %%_lastName_%%",
294
- _data: {
295
- extension: "1001",
296
- firstName: "Tom",
297
- lastName: "Smith",
298
- },
299
- };
300
-
301
- const lineTags = jVar(lineTemplate);
302
- await service.executeOperation("updateLine", lineTags);
303
- ```
304
-
305
- ## Methods Reference
306
-
307
- ### Core
308
-
309
- | Method | Description |
310
- |--------|-------------|
311
- | `new axlService(host, user, pass, version, opts?)` | Constructor |
312
- | `testAuthentication()` | Test credentials against AXL endpoint |
313
- | `returnOperations(filter?)` | List available operations |
314
- | `getOperationTags(operation)` | Get tag schema for an operation |
315
- | `getOperationTagsDetailed(operation)` | Get detailed tag metadata (required/nillable/type) |
316
- | `executeOperation(operation, tags, opts?)` | Execute any AXL operation |
317
- | `executeBatch(operations[], concurrency?)` | Parallel batch execution |
318
- | `setLogLevel(level)` | Change log level at runtime |
319
-
320
- ### Convenience
321
-
322
- | Method | Description |
323
- |--------|-------------|
324
- | `getItem(type, identifier, opts?)` | Get single item by name or UUID |
325
- | `listItems(type, search?, returnedTags?, opts?)` | List items with filtering |
326
- | `addItem(type, data, opts?)` | Add a new item |
327
- | `updateItem(type, identifier, updates, opts?)` | Update an existing item |
328
- | `removeItem(type, identifier, opts?)` | Remove an item |
329
- | `executeSqlQuery(sql)` | Run a SQL SELECT query |
330
- | `executeSqlUpdate(sql)` | Run a SQL INSERT/UPDATE/DELETE |
331
-
332
- ## Examples
333
-
334
- Check the **examples** folder for different ways to use this library.
335
-
336
- Run the integration tests against a CUCM cluster:
337
-
338
- ```bash
339
- npm run staging
340
- ```
341
-
342
- ## TypeScript Support
343
-
344
- ```typescript
345
- import axlService from 'cisco-axl';
346
-
347
- const service = new axlService("10.10.20.1", "administrator", "ciscopsdt", "14.0");
348
-
349
- const tags = await service.getOperationTags("listRoutePartition");
350
- tags.searchCriteria.name = "%%";
351
- const result = await service.executeOperation("listRoutePartition", tags);
352
- ```
130
+ ## Giving Back
353
131
 
354
- See the `examples/typescript` directory for more examples.
132
+ If you found this helpful, consider:
355
133
 
356
- ## Giving Back
134
+ [!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://buymeacoffee.com/automatebldrs)
357
135
 
358
- If you would like to support my work and the time I put in creating the code, you can click the image below to get me a coffee. I would really appreciate it (but is not required).
136
+ ## License
359
137
 
360
- [Buy Me a Coffee](https://www.buymeacoffee.com/automatebldrs)
138
+ MIT
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "cisco-axl",
3
+ "description": "Hooks for Cisco CUCM AXL CLI",
4
+ "author": "sieteunoseis",
5
+ "version": "1.0.0",
6
+ "hooks": [
7
+ {
8
+ "name": "Block write operations",
9
+ "description": "Blocks add, update, remove, execute, and sql update commands",
10
+ "default": true,
11
+ "event": "PreToolUse",
12
+ "matcher": "Bash",
13
+ "hook": {
14
+ "type": "command",
15
+ "command": "jq -r '.tool_input.command' | { read -r cmd; if echo \"$cmd\" | grep -qE '^(npx )?cisco-axl (add|update|remove|execute|sql update)'; then echo '{\"decision\":\"block\",\"reason\":\"BLOCKED: cisco-axl write operation. Use --read-only or get explicit user approval.\"}'; fi; }"
16
+ }
17
+ },
18
+ {
19
+ "name": "Enforce --read-only flag",
20
+ "description": "Requires --read-only on every cisco-axl command",
21
+ "default": false,
22
+ "event": "PreToolUse",
23
+ "matcher": "Bash",
24
+ "hook": {
25
+ "type": "command",
26
+ "command": "jq -r '.tool_input.command' | { read -r cmd; if echo \"$cmd\" | grep -qE '^(npx )?cisco-axl ' && ! echo \"$cmd\" | grep -q '\\-\\-read-only'; then echo '{\"decision\":\"block\",\"reason\":\"BLOCKED: cisco-axl must be run with --read-only. Retry with the flag.\"}'; fi; }"
27
+ }
28
+ }
29
+ ]
30
+ }
@@ -10,6 +10,7 @@
10
10
  const { createService } = require("../utils/connection.js");
11
11
  const { printResult, printError } = require("../utils/output.js");
12
12
  const { enforceReadOnly } = require("../utils/readonly.js");
13
+ const { readStdin } = require("../utils/stdin.js");
13
14
 
14
15
  /**
15
16
  * Registers the add command on the given Commander program.
@@ -20,6 +21,7 @@ module.exports = function registerAddCommand(program) {
20
21
  .command("add <type>")
21
22
  .description("Add a new AXL item of the given type")
22
23
  .option("--data <json>", "JSON definition of the item to add")
24
+ .option("--stdin", "read JSON data from stdin (for piping)")
23
25
  .option("--template <file>", "JSON template file with %%var%% placeholders")
24
26
  .option("--vars <json>", "variables to resolve in template (JSON)")
25
27
  .option("--csv <file>", "CSV file for bulk operations (use with --template)")
@@ -32,14 +34,22 @@ module.exports = function registerAddCommand(program) {
32
34
  let errorMsg;
33
35
 
34
36
  try {
35
- enforceReadOnly(globalOpts, "add");
37
+ await enforceReadOnly(globalOpts, "add");
38
+
39
+ // Read from stdin if --stdin flag is set
40
+ if (cmdOpts.stdin) {
41
+ const stdinData = await readStdin();
42
+ if (!stdinData) throw new Error("--stdin specified but no data piped. Pipe JSON via: echo '{...}' | cisco-axl add <type> --stdin");
43
+ cmdOpts.data = stdinData.trim();
44
+ }
36
45
 
37
46
  // Validate mutual exclusivity
38
- if (cmdOpts.data && cmdOpts.template) {
39
- throw new Error("--data and --template are mutually exclusive");
47
+ const inputCount = [cmdOpts.data, cmdOpts.template].filter(Boolean).length;
48
+ if (inputCount > 1) {
49
+ throw new Error("--data, --stdin, and --template are mutually exclusive");
40
50
  }
41
- if (!cmdOpts.data && !cmdOpts.template) {
42
- throw new Error("Either --data or --template must be provided");
51
+ if (inputCount === 0) {
52
+ throw new Error("Provide input via --data, --stdin, or --template");
43
53
  }
44
54
 
45
55
  const opts = {
@@ -14,38 +14,32 @@ const { createService } = require("../utils/connection.js");
14
14
  * @param {import("commander").Command} program
15
15
  */
16
16
  module.exports = function registerConfigCommand(program) {
17
- const config = program.command("config").description("Manage CUCM cluster configuration");
17
+ const config = program
18
+ .command("config")
19
+ .description("Manage CUCM cluster configuration");
18
20
 
19
21
  // ── config add <name> ───────────────────────────────────────────────────────
20
22
 
21
23
  config
22
24
  .command("add <name>")
23
- .description("Add a named CUCM cluster to config")
24
- .requiredOption("--cucm-version <ver>", "CUCM version (e.g. 14.0)")
25
- .action((name, opts) => {
25
+ .description("Add a named CUCM cluster to config (use --host, --username, --password, --version-cucm)")
26
+ .option("--cucm-version <ver>", "CUCM version (e.g. 14.0)")
27
+ .option("--insecure", "skip TLS verification for this cluster")
28
+ .action((name, opts, cmd) => {
26
29
  try {
27
- // --host, --username, --password, --insecure come from global program options
28
- const globalOpts = program.opts();
29
-
30
+ const globalOpts = cmd.optsWithGlobals();
30
31
  const host = globalOpts.host;
31
32
  const username = globalOpts.username;
32
33
  const password = globalOpts.password;
33
- const insecure = globalOpts.insecure;
34
-
35
- if (!host) {
36
- throw new Error("Missing required option: --host");
37
- }
38
- if (!username) {
39
- throw new Error("Missing required option: --username");
40
- }
41
- if (!password) {
42
- throw new Error("Missing required option: --password");
43
- }
44
-
45
- // Commander camelCases --cucm-version to cucmVersion; addCluster expects version
46
- const clusterOpts = { host, username, password, version: opts.cucmVersion };
47
- if (insecure !== undefined) {
48
- clusterOpts.insecure = insecure;
34
+ const version = opts.cucmVersion || globalOpts.versionCucm;
35
+ if (!host) throw new Error("Missing required option: --host");
36
+ if (!username) throw new Error("Missing required option: --username");
37
+ if (!password) throw new Error("Missing required option: --password");
38
+ if (!version) throw new Error("Missing required option: --cucm-version or --version-cucm");
39
+
40
+ const clusterOpts = { host, username, password, version };
41
+ if (opts.insecure || globalOpts.insecure) {
42
+ clusterOpts.insecure = true;
49
43
  }
50
44
 
51
45
  configUtil.addCluster(name, clusterOpts);