UNPKG

netconf-client

Version:
121 lines 6.93 kB
#!/usr/bin/env node import { firstValueFrom, NEVER, of, Subject, timer } from 'rxjs'; import { defaultIfEmpty, filter, map, switchMap, takeUntil, tap } from 'rxjs/operators'; import { Netconf, SSH_TIMEOUT } from "../lib/index.js"; import { catchMultipleEditError, setEditConfigStatus, setRpcConfigStatus, writeData } from "./output-operators.js"; import { Output } from "./output.js"; import { OperationType, parseArgs } from "./parse-args.js"; import { resolveXPath } from "./resolve-xpath.js"; /** * Execute the requested netconf operation * * @param client - The netconf client * @param cliOptions - The parsed command line arguments * @returns An observable that emits when the operation is complete */ function execNetconfOperation(client, cliOptions) { Output.debug(`Performing operation: ${cliOptions.operation.type}`); switch (cliOptions.operation.type) { case OperationType.HELLO: return client.hello().pipe(writeData(cliOptions.resultFormat), switchMap(() => client.close())); case OperationType.GET: const getOptions = cliOptions.operation.options; return client.getData(getOptions.xpath, getOptions.configFilter).pipe(map(data => { let result; if (getOptions.fullTree) { result = data.result; } else { // result = stripParents(data.result); result = resolveXPath(data.result, getOptions.xpath); } const isRootResult = data.result === result; data.result = result; return [data, isRootResult]; }), writeData(cliOptions.resultFormat), // writeData(cliOptions.resultFormat), switchMap(() => client.close())); case OperationType.RPC: const rpcOptions = cliOptions.operation.options; return client.rpc(rpcOptions.cmd, rpcOptions.values ?? {}).pipe(setRpcConfigStatus(), writeData(cliOptions.resultFormat), switchMap(() => client.close())); case OperationType.MERGE: const mergeOptions = cliOptions.operation.options; return client.editConfigMerge(mergeOptions.xpath, mergeOptions.values ?? {}).pipe(catchMultipleEditError(), setEditConfigStatus(), writeData(cliOptions.resultFormat), switchMap(() => client.connectionState === 'uninitialized' ? of(void 0) : client.close())); case OperationType.CREATE: { const createOptions = cliOptions.operation.options; const operation = createOptions.editConfigValues?.type === 'keyvalue' ? client.editConfigCreate(createOptions.xpath, createOptions.editConfigValues.values, createOptions.beforeKey) : client.editConfigCreateListItems(createOptions.xpath, createOptions.editConfigValues.values); return operation.pipe(catchMultipleEditError(), setEditConfigStatus(), writeData(cliOptions.resultFormat), switchMap(() => client.connectionState === 'uninitialized' ? of(void 0) : client.close())); } case OperationType.DELETE: { const deleteOptions = cliOptions.operation.options; const operation = deleteOptions.editConfigValues?.type === 'keyvalue' ? client.editConfigDelete(deleteOptions.xpath, deleteOptions.editConfigValues.values) : client.editConfigDeleteListItems(deleteOptions.xpath, deleteOptions.editConfigValues.values); return operation.pipe(catchMultipleEditError(), setEditConfigStatus(), writeData(cliOptions.resultFormat), switchMap(() => client.connectionState === 'uninitialized' ? of(void 0) : client.close())); } case OperationType.REPLACE: { const replaceOptions = cliOptions.operation.options; const operation = replaceOptions.editConfigValues?.type === 'keyvalue' ? client.editConfigReplace(replaceOptions.xpath, replaceOptions.editConfigValues.values) : client.editConfigReplaceListItems(replaceOptions.xpath, replaceOptions.editConfigValues.values); return operation.pipe(catchMultipleEditError(), setEditConfigStatus(), writeData(cliOptions.resultFormat), switchMap(() => client.connectionState === 'uninitialized' ? of(void 0) : client.close())); } case OperationType.SUBSCRIBE: const subscribeOptions = cliOptions.operation.options; const stop$ = new Subject(); const closed$ = new Subject(); process.on('SIGINT', async () => { Output.info('\nStopping subscription'); stop$.next(); stop$.complete(); await firstValueFrom(timer(SSH_TIMEOUT).pipe(takeUntil(closed$), defaultIfEmpty(void 0))); }); return client.subscription(subscribeOptions.type === 'stream' ? { stream: subscribeOptions.stream } : { xpath: subscribeOptions.xpath }, stop$).pipe(filter((data) => { if (data?.result?.hasOwnProperty('ok')) { // This is a RPC Reply with OK, we skip it Output.info(`Started subscription. Ctrl+C to stop. PID=${process.pid}`); return false; } return true; }), switchMap(data => data ? of(data).pipe(writeData(cliOptions.resultFormat)) : of(data)), switchMap(data => data ? NEVER : client.close().pipe(tap(() => closed$.next()), tap(() => closed$.complete())))); default: throw new Error(`Invalid operation: ${cliOptions.operation.type}`); } } async function main() { const cliOptions = await parseArgs(); if (!cliOptions) { return; } const showNamespaces = cliOptions.operation.type === OperationType.GET && cliOptions.operation.options.showNamespaces; const allowMultipleEdit = (cliOptions.operation.type === OperationType.MERGE || cliOptions.operation.type === OperationType.CREATE || cliOptions.operation.type === OperationType.DELETE) && cliOptions.operation.options.allowMultiple; const client = new Netconf({ host: cliOptions.host, port: cliOptions.port, user: cliOptions.user, pass: cliOptions.pass, ignoreAttrs: !showNamespaces, readOnly: cliOptions.readOnly, allowMultipleEdit, namespace: cliOptions.namespaces, debug: (msg, level) => Output.debug(msg, undefined, level), }); await firstValueFrom(execNetconfOperation(client, cliOptions)); } main().then(() => { Output.debug('Exit (success)'); }).catch((error) => { Output.error(`${error.message}`); Output.printStackTrace(error); Output.debug('Exit (error)'); process.exit(1); }); // Export functions for testing if (process.env.NODE_ENV === 'test') { module.exports = { writeData, catchMultipleEditError, setEditConfigStatus }; } //# sourceMappingURL=main.js.map