cisco-axl 2.0.0 → 2.1.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/.claude-plugin/plugin.json +26 -0
- package/.github/FUNDING.yml +1 -0
- package/.github/workflows/ci.yml +1 -1
- package/README.md +40 -1
- package/cli/commands/add.js +14 -4
- package/cli/commands/config.js +17 -23
- package/cli/commands/execute.js +14 -4
- package/cli/commands/update.js +14 -4
- package/cli/index.js +6 -2
- package/cli/utils/config.js +19 -4
- package/cli/utils/connection.js +5 -1
- package/cli/utils/stdin.js +20 -0
- package/package.json +3 -2
- package/skills/cisco-axl-cli/SKILL.md +43 -0
|
@@ -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
|
package/.github/workflows/ci.yml
CHANGED
package/README.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Cisco AXL Library & CLI
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/cisco-axl)
|
|
4
|
+
[](https://github.com/sieteunoseis/cisco-axl/actions/workflows/ci.yml)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://nodejs.org)
|
|
7
|
+
[](https://skills.sh/sieteunoseis/cisco-axl)
|
|
8
|
+
[](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
|
|
36
|
+
npx skills add sieteunoseis/cisco-axl
|
|
30
37
|
```
|
|
31
38
|
|
|
32
39
|
## Requirements
|
|
@@ -145,6 +152,38 @@ Template file (`phone-template.json`):
|
|
|
145
152
|
--debug Enable debug logging
|
|
146
153
|
```
|
|
147
154
|
|
|
155
|
+
### Command Chaining
|
|
156
|
+
|
|
157
|
+
Shell `&&` chains commands sequentially — each waits for the previous to complete, and the chain stops on the first failure:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# Create a partition, CSS, and line in order
|
|
161
|
+
cisco-axl add RoutePartition --data '{"name":"PT_INTERNAL","description":"Internal"}' && \
|
|
162
|
+
cisco-axl add Css --data '{"name":"CSS_INTERNAL","members":{"member":{"routePartitionName":"PT_INTERNAL","index":"1"}}}' && \
|
|
163
|
+
cisco-axl add Line --data '{"pattern":"1000","routePartitionName":"PT_INTERNAL"}'
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Piping with --stdin
|
|
167
|
+
|
|
168
|
+
Use `--stdin` to pipe JSON between commands or from other tools like `jq`:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# Get a phone's config, modify it with jq, update it
|
|
172
|
+
cisco-axl get Phone SEP001122334455 --format json | \
|
|
173
|
+
jq '.description = "Updated via pipe"' | \
|
|
174
|
+
cisco-axl update Phone SEP001122334455 --stdin
|
|
175
|
+
|
|
176
|
+
# Pipe JSON from a file
|
|
177
|
+
cat phone-config.json | cisco-axl add Phone --stdin
|
|
178
|
+
|
|
179
|
+
# Discover tags, fill them in, execute
|
|
180
|
+
cisco-axl describe applyPhone --format json | \
|
|
181
|
+
jq '.name = "SEP001122334455"' | \
|
|
182
|
+
cisco-axl execute applyPhone --stdin
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
The `--stdin` flag is available on `add`, `update`, and `execute`. It is mutually exclusive with `--data`/`--tags` and `--template`.
|
|
186
|
+
|
|
148
187
|
### Audit Trail
|
|
149
188
|
|
|
150
189
|
All operations are logged to `~/.cisco-axl/audit.jsonl` (JSONL format). Credentials are never logged. Use `--no-audit` to skip.
|
package/cli/commands/add.js
CHANGED
|
@@ -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)")
|
|
@@ -34,12 +36,20 @@ module.exports = function registerAddCommand(program) {
|
|
|
34
36
|
try {
|
|
35
37
|
enforceReadOnly(globalOpts, "add");
|
|
36
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
|
+
}
|
|
45
|
+
|
|
37
46
|
// Validate mutual exclusivity
|
|
38
|
-
|
|
39
|
-
|
|
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 (
|
|
42
|
-
throw new Error("
|
|
51
|
+
if (inputCount === 0) {
|
|
52
|
+
throw new Error("Provide input via --data, --stdin, or --template");
|
|
43
53
|
}
|
|
44
54
|
|
|
45
55
|
const opts = {
|
package/cli/commands/config.js
CHANGED
|
@@ -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
|
|
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
|
-
.
|
|
25
|
-
.
|
|
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
|
-
|
|
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
|
|
34
|
-
|
|
35
|
-
if (!
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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);
|
package/cli/commands/execute.js
CHANGED
|
@@ -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 execute command on the given Commander program.
|
|
@@ -20,6 +21,7 @@ module.exports = function registerExecuteCommand(program) {
|
|
|
20
21
|
.command("execute <operation>")
|
|
21
22
|
.description("Execute a raw AXL operation with JSON tags")
|
|
22
23
|
.option("--tags <json>", "JSON object of operation tags")
|
|
24
|
+
.option("--stdin", "read JSON tags 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)")
|
|
@@ -34,12 +36,20 @@ module.exports = function registerExecuteCommand(program) {
|
|
|
34
36
|
try {
|
|
35
37
|
enforceReadOnly(globalOpts, "execute");
|
|
36
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 execute <op> --stdin");
|
|
43
|
+
cmdOpts.tags = stdinData.trim();
|
|
44
|
+
}
|
|
45
|
+
|
|
37
46
|
// Validate mutual exclusivity
|
|
38
|
-
|
|
39
|
-
|
|
47
|
+
const inputCount = [cmdOpts.tags, cmdOpts.template].filter(Boolean).length;
|
|
48
|
+
if (inputCount > 1) {
|
|
49
|
+
throw new Error("--tags, --stdin, and --template are mutually exclusive");
|
|
40
50
|
}
|
|
41
|
-
if (
|
|
42
|
-
throw new Error("
|
|
51
|
+
if (inputCount === 0) {
|
|
52
|
+
throw new Error("Provide input via --tags, --stdin, or --template");
|
|
43
53
|
}
|
|
44
54
|
|
|
45
55
|
const opts = {
|
package/cli/commands/update.js
CHANGED
|
@@ -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 update command on the given Commander program.
|
|
@@ -20,6 +21,7 @@ module.exports = function registerUpdateCommand(program) {
|
|
|
20
21
|
.command("update <type> [identifier]")
|
|
21
22
|
.description("Update an existing AXL item by type and name or UUID")
|
|
22
23
|
.option("--data <json>", "JSON object of fields to update")
|
|
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)")
|
|
@@ -34,12 +36,20 @@ module.exports = function registerUpdateCommand(program) {
|
|
|
34
36
|
try {
|
|
35
37
|
enforceReadOnly(globalOpts, "update");
|
|
36
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 update <type> <id> --stdin");
|
|
43
|
+
cmdOpts.data = stdinData.trim();
|
|
44
|
+
}
|
|
45
|
+
|
|
37
46
|
// Validate mutual exclusivity
|
|
38
|
-
|
|
39
|
-
|
|
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 (
|
|
42
|
-
throw new Error("
|
|
51
|
+
if (inputCount === 0) {
|
|
52
|
+
throw new Error("Provide input via --data, --stdin, or --template");
|
|
43
53
|
}
|
|
44
54
|
|
|
45
55
|
const opts = {
|
package/cli/index.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const { Command } = require("commander");
|
|
4
|
-
const
|
|
4
|
+
const pkg = require("../package.json");
|
|
5
|
+
|
|
6
|
+
import("update-notifier").then(({ default: updateNotifier }) => {
|
|
7
|
+
updateNotifier({ pkg }).notify();
|
|
8
|
+
}).catch(() => {});
|
|
5
9
|
|
|
6
10
|
const program = new Command();
|
|
7
11
|
|
|
8
12
|
program
|
|
9
13
|
.name("cisco-axl")
|
|
10
14
|
.description("CLI for Cisco CUCM AXL operations")
|
|
11
|
-
.version(version)
|
|
15
|
+
.version(pkg.version)
|
|
12
16
|
.option("--format <type>", "output format: table, json, toon, csv", "table")
|
|
13
17
|
.option("--host <host>", "CUCM hostname (overrides config/env)")
|
|
14
18
|
.option("--username <user>", "CUCM username (overrides config/env)")
|
package/cli/utils/config.js
CHANGED
|
@@ -263,15 +263,30 @@ function resolveSsValue(id, field) {
|
|
|
263
263
|
|
|
264
264
|
try {
|
|
265
265
|
const data = JSON.parse(stdout);
|
|
266
|
-
// ss-cli returns an object; find the field case-insensitively
|
|
267
266
|
const fieldLower = field.toLowerCase();
|
|
267
|
+
|
|
268
|
+
// First: check top-level keys (simple key-value secrets)
|
|
268
269
|
const foundKey = Object.keys(data).find(
|
|
269
270
|
(k) => k.toLowerCase() === fieldLower
|
|
270
271
|
);
|
|
271
|
-
if (foundKey
|
|
272
|
-
return
|
|
272
|
+
if (foundKey !== undefined) {
|
|
273
|
+
return resolve(data[foundKey]);
|
|
273
274
|
}
|
|
274
|
-
|
|
275
|
+
|
|
276
|
+
// Second: check items array (Secret Server template secrets)
|
|
277
|
+
// Items have fieldName, slug, and itemValue properties
|
|
278
|
+
if (Array.isArray(data.items)) {
|
|
279
|
+
const item = data.items.find(
|
|
280
|
+
(i) =>
|
|
281
|
+
(i.slug && i.slug.toLowerCase() === fieldLower) ||
|
|
282
|
+
(i.fieldName && i.fieldName.toLowerCase() === fieldLower)
|
|
283
|
+
);
|
|
284
|
+
if (item) {
|
|
285
|
+
return resolve(item.itemValue);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return reject(new Error(`Field "${field}" not found in secret ${id}`));
|
|
275
290
|
} catch (parseErr) {
|
|
276
291
|
reject(new Error(`Failed to parse ss-cli output for secret ${id}: ${parseErr.message}`));
|
|
277
292
|
}
|
package/cli/utils/connection.js
CHANGED
|
@@ -119,9 +119,13 @@ async function resolveConfig(flags = {}) {
|
|
|
119
119
|
async function createService(flags = {}) {
|
|
120
120
|
const config = await resolveConfig(flags);
|
|
121
121
|
|
|
122
|
-
// Handle --insecure flag
|
|
122
|
+
// Handle --insecure flag — suppress Node's TLS warning since user opted in
|
|
123
123
|
if (config.insecure || flags.insecure) {
|
|
124
124
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
125
|
+
process.emitWarning = ((orig) => function (warning, ...args) {
|
|
126
|
+
if (typeof warning === "string" && warning.includes("NODE_TLS_REJECT_UNAUTHORIZED")) return;
|
|
127
|
+
return orig.call(process, warning, ...args);
|
|
128
|
+
})(process.emitWarning);
|
|
125
129
|
}
|
|
126
130
|
|
|
127
131
|
// Build axlService options
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Read all data from stdin as a string.
|
|
5
|
+
* Returns null if stdin is a TTY (no piped input).
|
|
6
|
+
*/
|
|
7
|
+
function readStdin() {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
if (process.stdin.isTTY) {
|
|
10
|
+
return resolve(null);
|
|
11
|
+
}
|
|
12
|
+
const chunks = [];
|
|
13
|
+
process.stdin.setEncoding("utf-8");
|
|
14
|
+
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
15
|
+
process.stdin.on("end", () => resolve(chunks.join("")));
|
|
16
|
+
process.stdin.on("error", reject);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = { readStdin };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cisco-axl",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "A library and CLI for Cisco CUCM AXL operations",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "main.mjs",
|
|
@@ -50,7 +50,8 @@
|
|
|
50
50
|
"cli-table3": "^0.6.5",
|
|
51
51
|
"commander": "^14.0.3",
|
|
52
52
|
"csv-stringify": "^6.7.0",
|
|
53
|
-
"strong-soap": "^5.0.8"
|
|
53
|
+
"strong-soap": "^5.0.8",
|
|
54
|
+
"update-notifier": "^7.3.1"
|
|
54
55
|
},
|
|
55
56
|
"devDependencies": {
|
|
56
57
|
"@types/node": "^22.19.15",
|
|
@@ -7,6 +7,21 @@ description: Use when managing Cisco CUCM via the cisco-axl CLI — phones, line
|
|
|
7
7
|
|
|
8
8
|
A CLI for Cisco Unified Communications Manager (CUCM) Administrative XML (AXL) operations.
|
|
9
9
|
|
|
10
|
+
## Prerequisites
|
|
11
|
+
|
|
12
|
+
The CLI must be available. Either:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# Option 1: Use npx (no install needed, works immediately)
|
|
16
|
+
npx cisco-axl --help
|
|
17
|
+
|
|
18
|
+
# Option 2: Install globally for faster repeated use
|
|
19
|
+
npm install -g cisco-axl
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
If using npx, prefix all commands with `npx`: `npx cisco-axl list Phone ...`
|
|
23
|
+
If installed globally, use directly: `cisco-axl list Phone ...`
|
|
24
|
+
|
|
10
25
|
## Setup
|
|
11
26
|
|
|
12
27
|
Configure a CUCM cluster:
|
|
@@ -167,6 +182,34 @@ cisco-axl config use prod
|
|
|
167
182
|
cisco-axl list Phone --search "name=SEP%" --cluster lab # override per-command
|
|
168
183
|
```
|
|
169
184
|
|
|
185
|
+
## Command Chaining
|
|
186
|
+
|
|
187
|
+
Shell `&&` chains commands sequentially — each waits for the previous to complete, and the chain stops on the first failure:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
# Create a partition, CSS, and line in order
|
|
191
|
+
cisco-axl add RoutePartition --data '{"name":"PT_INTERNAL","description":"Internal"}' && \
|
|
192
|
+
cisco-axl add Css --data '{"name":"CSS_INTERNAL","members":{"member":{"routePartitionName":"PT_INTERNAL","index":"1"}}}' && \
|
|
193
|
+
cisco-axl add Line --data '{"pattern":"1000","routePartitionName":"PT_INTERNAL"}'
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Piping with --stdin
|
|
197
|
+
|
|
198
|
+
Use `--stdin` to pipe JSON between commands or from other tools:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
# Get a phone's config, modify it with jq, update it
|
|
202
|
+
cisco-axl get Phone SEP001122334455 --format json | jq '.description = "Updated via pipe"' | cisco-axl update Phone SEP001122334455 --stdin
|
|
203
|
+
|
|
204
|
+
# Pipe JSON from a file
|
|
205
|
+
cat phone-config.json | cisco-axl add Phone --stdin
|
|
206
|
+
|
|
207
|
+
# Chain get → transform → execute
|
|
208
|
+
cisco-axl describe applyPhone --format json | jq '.name = "SEP001122334455"' | cisco-axl execute applyPhone --stdin
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
The `--stdin` flag is available on `add`, `update`, and `execute` commands. It is mutually exclusive with `--data`/`--tags` and `--template`.
|
|
212
|
+
|
|
170
213
|
## Tips
|
|
171
214
|
|
|
172
215
|
- Item types are PascalCase matching AXL: `Phone`, `Line`, `RoutePartition`, `Css`, `DevicePool`, `SipTrunk`, `TransPattern`, `RouteGroup`, `RouteList`, etc.
|