mirror of
https://github.com/vvsviridov/enm-cli.git
synced 2025-10-23 00:12:23 +00:00
shell app improvements
This commit is contained in:
@@ -12,6 +12,7 @@ require('dotenv').config({ path: [...__dirname.split(path.sep).slice(0, -1), '.e
|
||||
const AutoProvisioning = require('../lib/applications/AutoProvisioning/AutoProvisioning')
|
||||
const TopologyBrowser = require('../lib/applications/TopologyBrowser/TopologyBrowser')
|
||||
const BulkImport = require('../lib/applications/BulkImport/BulkImport')
|
||||
const ShellTerminal = require('../lib/applications/ShellTerminal/ShellTerminal')
|
||||
|
||||
const logError = require('../util/logError')
|
||||
|
||||
@@ -35,6 +36,11 @@ const applications = [
|
||||
appClass: BulkImport,
|
||||
name: 'Bulk Import',
|
||||
},
|
||||
{
|
||||
id: 'shll',
|
||||
appClass: ShellTerminal,
|
||||
name: 'Shell Terminal',
|
||||
},
|
||||
]
|
||||
const appIds = applications.map(item => item.id)
|
||||
|
||||
|
19
lib/applications/ShellTerminal/ShellTerminal.js
Executable file
19
lib/applications/ShellTerminal/ShellTerminal.js
Executable file
@@ -0,0 +1,19 @@
|
||||
const ENM = require('../../components/ENM')
|
||||
|
||||
const inputHandler = require('./inputHandler')
|
||||
|
||||
|
||||
class ShellTerminal extends ENM {
|
||||
constructor(username, password, url) {
|
||||
super(username, password, url)
|
||||
this.fdn = ''
|
||||
}
|
||||
|
||||
async inputHandler() {
|
||||
await inputHandler.call(this)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
module.exports = ShellTerminal
|
48
lib/applications/ShellTerminal/inputHandler.js
Executable file
48
lib/applications/ShellTerminal/inputHandler.js
Executable file
@@ -0,0 +1,48 @@
|
||||
const inquirer = require('inquirer')
|
||||
const { amos, scripting, wfcli } = require('./terminals')
|
||||
|
||||
|
||||
async function inputHandler() {
|
||||
const input = await inquirer.prompt([{
|
||||
type: 'list',
|
||||
name: 'vm',
|
||||
prefix: '💻',
|
||||
message: 'Select Terminal:',
|
||||
choices: [
|
||||
{
|
||||
name: 'Shell Terminal on Scripting',
|
||||
value: 'scripting',
|
||||
short: 'scripting',
|
||||
},
|
||||
{
|
||||
name: 'Shell Terminal on AMOS',
|
||||
value: 'amos',
|
||||
short: 'amos',
|
||||
},
|
||||
{
|
||||
name: 'WinFIOL CLI',
|
||||
value: 'wfcli',
|
||||
short: 'wfcli',
|
||||
},
|
||||
]
|
||||
}])
|
||||
|
||||
switch (input.vm) {
|
||||
case 'amos':
|
||||
await amos.call(this)
|
||||
break
|
||||
case 'scripting':
|
||||
await scripting.call(this)
|
||||
break
|
||||
case 'wfcli':
|
||||
await wfcli.call(this)
|
||||
break
|
||||
}
|
||||
if (process.stdin.isRaw) {
|
||||
process.stdin.setRawMode(false)
|
||||
}
|
||||
process.stdin.pause()
|
||||
}
|
||||
|
||||
|
||||
module.exports = inputHandler
|
130
lib/applications/ShellTerminal/terminals.js
Executable file
130
lib/applications/ShellTerminal/terminals.js
Executable file
@@ -0,0 +1,130 @@
|
||||
|
||||
const amosUrl = '/amos-service/amos/launch/info'
|
||||
|
||||
|
||||
async function getNeType() {
|
||||
const axiosConfig = {
|
||||
text: 'Getting Network Element Type...',
|
||||
method: 'get',
|
||||
url: `${this.objectUrl}${this.currentPoId}`,
|
||||
params: {
|
||||
includeNonPersistent: false,
|
||||
stringifyLong: false
|
||||
}
|
||||
}
|
||||
const { data: { neType } } = await this.httpClient.request(axiosConfig)
|
||||
return neType
|
||||
}
|
||||
|
||||
|
||||
async function getActions(type, neType) {
|
||||
const axiosConfig = {
|
||||
text: 'Matching Actions...',
|
||||
method: 'post',
|
||||
url: '/rest/v1/apps/action-matches',
|
||||
data: {
|
||||
application: 'topologybrowser',
|
||||
multipleSelection: false,
|
||||
conditions: [
|
||||
{
|
||||
dataType: 'ManagedObject',
|
||||
properties: [
|
||||
{ name: 'type', value: type },
|
||||
{ name: 'type', value: type },
|
||||
{ name: 'neType', value: neType },
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
const { data: { actions } } = await this.httpClient.request(axiosConfig)
|
||||
return actions
|
||||
}
|
||||
|
||||
|
||||
async function amos() {
|
||||
const axiosConfig = {
|
||||
text: 'Launching AMOS...',
|
||||
method: 'get',
|
||||
url: amosUrl,
|
||||
}
|
||||
const amosCommand = { command: 'shell' }
|
||||
const meContextFind = this.fdn.match(/(NetworkElement|MeContext)=([\w-]+),?/)
|
||||
if (meContextFind) {
|
||||
const type = meContextFind[1]
|
||||
const nodeName = meContextFind[2]
|
||||
const neType = await getNeType.call(this)
|
||||
const actions = await getActions.call(this, type, neType)
|
||||
const hasAmos = actions.find(action => action.applicationId === 'advancedmoscripting')
|
||||
if (hasAmos) {
|
||||
axiosConfig['params'] = { poid: this.currentPoId }
|
||||
amosCommand.command = 'amos'
|
||||
amosCommand['poid'] = nodeName
|
||||
}
|
||||
}
|
||||
const response = await this.httpClient.request(axiosConfig)
|
||||
await this.webSocketSession(response.config.headers, '/terminal-websocket/command', amosCommand)
|
||||
}
|
||||
|
||||
|
||||
async function scripting() {
|
||||
const axiosConfig = {
|
||||
text: 'Launching Scripting Shell...',
|
||||
method: 'get',
|
||||
url: amosUrl,
|
||||
}
|
||||
const response = await this.httpClient.request(axiosConfig)
|
||||
await this.webSocketSession(response.config.headers, '/scripting-terminal-ws/command', { command: 'scripting' })
|
||||
}
|
||||
|
||||
|
||||
async function wfcli() {
|
||||
const axiosConfig = {
|
||||
text: 'Launching WinFIOL CLI...',
|
||||
method: 'get',
|
||||
url: `/neconnection-service/v1/networkelement-data/${this.currentPoId}`,
|
||||
}
|
||||
const wfcliCommand = { command: 'wfcli' }
|
||||
const meContextFind = this.fdn.match(/(NetworkElement|MeContext)=([\w-]+),?/)
|
||||
if (meContextFind) {
|
||||
const type = meContextFind[1]
|
||||
const neType = await getNeType.call(this)
|
||||
const actions = await getActions.call(this, type, neType)
|
||||
const hasWinfiol = actions.find(action => action.applicationId === 'winfiol')
|
||||
if (hasWinfiol) {
|
||||
wfcliCommand['poid'] = this.currentPoId
|
||||
}
|
||||
}
|
||||
let response
|
||||
try {
|
||||
response = await this.httpClient.request(axiosConfig)
|
||||
} catch (error) {
|
||||
response = error.response
|
||||
}
|
||||
await this.webSocketSession(response.config.headers, '/winfiol-websocket/command', wfcliCommand)
|
||||
}
|
||||
|
||||
|
||||
async function nodecli() {
|
||||
const axiosConfig = {
|
||||
text: 'Launching Node CLI...',
|
||||
method: 'get',
|
||||
url: `/oss/idm/usermanagement/users/${this.username}?username=true`,
|
||||
}
|
||||
const meContextFind = this.fdn.match(/(NetworkElement|MeContext)=([\w-]+),?/)
|
||||
if (!meContextFind) {
|
||||
throw new Error('Can\'t launch node cli here❗')
|
||||
}
|
||||
const type = meContextFind[1]
|
||||
const neType = await getNeType.call(this)
|
||||
const actions = await getActions.call(this, type, neType)
|
||||
const hasNodeCli = actions.find(action => action.applicationId === 'nodecli')
|
||||
if (!hasNodeCli) {
|
||||
throw new Error('Can\'t launch node cli here❗')
|
||||
}
|
||||
const response = await this.httpClient.request(axiosConfig)
|
||||
await this.webSocketSession(response.config.headers, '/nodecli-websocket', { poid: this.currentPoId })
|
||||
}
|
||||
|
||||
|
||||
module.exports = { amos, scripting, wfcli, nodecli }
|
@@ -2,9 +2,7 @@ const logAttributes = require('../../../util/logAttributes')
|
||||
const inputHandler = require('./inputHandler')
|
||||
const alarms = require('./commands/alarms')
|
||||
const sync = require('./commands/sync')
|
||||
const amos = require('./commands/amos')
|
||||
const scripting = require('./commands/scripting')
|
||||
const wfcli = require('./commands/wfcli')
|
||||
const { amos, scripting, wfcli, nodecli } = require('../ShellTerminal/terminals')
|
||||
const initialPrompt = require('./commands/initialPrompt')
|
||||
const nextObjects = require('./commands/nextObjects')
|
||||
const nextAttributes = require('./commands/nextAttributes')
|
||||
@@ -35,7 +33,6 @@ class TopologyBrowser extends ENM {
|
||||
this.nodeTypesUrl = '/modelInfo/model/nodeTypes/'
|
||||
this.nodeSearchUrl = '/managedObjects/search/v2'
|
||||
this.nodePoIdsUrl = '/managedObjects/getPosByPoIds'
|
||||
this.amosUrl = '/amos-service/amos/launch/info'
|
||||
|
||||
this.currentPoId = 0
|
||||
this.nextPoId = 1
|
||||
@@ -154,6 +151,10 @@ class TopologyBrowser extends ENM {
|
||||
await wfcli.call(this)
|
||||
}
|
||||
|
||||
async nodecli() {
|
||||
await nodecli.call(this)
|
||||
}
|
||||
|
||||
async inputHandler() {
|
||||
await inputHandler.call(this)
|
||||
}
|
||||
|
@@ -1,29 +0,0 @@
|
||||
const { getActions, getNeType } = require('../../../../util/getActions')
|
||||
|
||||
|
||||
async function amos() {
|
||||
const axiosConfig = {
|
||||
text: 'Launching AMOS...',
|
||||
method: 'get',
|
||||
url: this.amosUrl,
|
||||
}
|
||||
const amosCommand = { command: 'shell' }
|
||||
const meContextFind = this.fdn.match(/(NetworkElement|MeContext)=([\w-]+),?/)
|
||||
if (meContextFind) {
|
||||
const type = meContextFind[1]
|
||||
const nodeName = meContextFind[2]
|
||||
const neType = await getNeType.call(this)
|
||||
const actions = await getActions.call(this, type, neType)
|
||||
const hasAmos = actions.find(action => action.applicationId === 'advancedmoscripting')
|
||||
if (hasAmos) {
|
||||
axiosConfig['params'] = { poid: this.currentPoId }
|
||||
amosCommand.command = 'amos'
|
||||
amosCommand['poid'] = nodeName
|
||||
}
|
||||
}
|
||||
const response = await this.httpClient.request(axiosConfig)
|
||||
await this.webSocketSession(response.config.headers, '/terminal-websocket/command', amosCommand)
|
||||
}
|
||||
|
||||
|
||||
module.exports = amos
|
@@ -6,7 +6,7 @@ const tableChoices = require('../../../../util/tableChoices')
|
||||
const otherCommands = [
|
||||
'show', 'config', 'up', 'home',
|
||||
'fdn', 'search', 'persistent', 'alarms',
|
||||
'sync', 'amos', 'scripting', 'wfcli', 'exit'
|
||||
'sync', 'amos', 'scripting', 'wfcli', 'nodecli', 'exit'
|
||||
]
|
||||
|
||||
|
||||
|
@@ -1,14 +0,0 @@
|
||||
|
||||
|
||||
async function scripting() {
|
||||
const axiosConfig = {
|
||||
text: 'Launching Scripting Shell...',
|
||||
method: 'get',
|
||||
url: this.amosUrl,
|
||||
}
|
||||
const response = await this.httpClient.request(axiosConfig)
|
||||
await this.webSocketSession(response.config.headers, '/scripting-terminal-ws/command', { command: 'scripting' })
|
||||
}
|
||||
|
||||
|
||||
module.exports = scripting
|
@@ -1,31 +0,0 @@
|
||||
const { getActions, getNeType } = require('../../../../util/getActions')
|
||||
|
||||
|
||||
async function wfcli() {
|
||||
const axiosConfig = {
|
||||
text: 'Launching WinFIOL CLI...',
|
||||
method: 'get',
|
||||
url: `/neconnection-service/v1/networkelement-data/${this.currentPoId}`,
|
||||
}
|
||||
const wfcliCommand = { command: 'wfcli' }
|
||||
const meContextFind = this.fdn.match(/(NetworkElement|MeContext)=([\w-]+),?/)
|
||||
if (meContextFind) {
|
||||
const type = meContextFind[1]
|
||||
const neType = await getNeType.call(this)
|
||||
const actions = await getActions.call(this, type, neType)
|
||||
const hasWinfiol = actions.find(action => action.applicationId === 'winfiol')
|
||||
if (hasWinfiol) {
|
||||
wfcliCommand['poid'] = this.currentPoId
|
||||
}
|
||||
}
|
||||
let response
|
||||
try {
|
||||
response = await this.httpClient.request(axiosConfig)
|
||||
} catch (error) {
|
||||
response = error.response
|
||||
}
|
||||
await this.webSocketSession(response.config.headers, '/winfiol-websocket/command', wfcliCommand)
|
||||
}
|
||||
|
||||
|
||||
module.exports = wfcli
|
@@ -12,6 +12,7 @@ const mainHelp = [
|
||||
'amos - launching Advanced MO Shell Scripting (amos)',
|
||||
'scripting - open shell terminal towards scripting VM',
|
||||
'wfcli - launching WinFIOL CLI app',
|
||||
'nodecli - launching node CLI app',
|
||||
'exit - logout and exit application',
|
||||
].join('\n')
|
||||
|
||||
|
@@ -80,6 +80,9 @@ async function handleCommand(tplg, command) {
|
||||
case '_wfcli':
|
||||
await tplg.wfcli()
|
||||
break
|
||||
case '_nodecli':
|
||||
await tplg.nodecli()
|
||||
break
|
||||
|
||||
default:
|
||||
commandOther(tplg, command)
|
||||
|
@@ -1,10 +1,16 @@
|
||||
const WebSocket = require('ws')
|
||||
const chalk = require('chalk')
|
||||
const ora = require('ora')
|
||||
|
||||
|
||||
let spinner = ora({
|
||||
text: 'Starting connection...',
|
||||
spinner: 'speaker',
|
||||
})
|
||||
|
||||
function socketOnOpen(socket) {
|
||||
console.log('📡 Connection started...')
|
||||
socket.send(`{"type":"resize","cols":"${process.stdout.columns}","rows":"${process.stdout.rows}"}`)
|
||||
spinner.succeed()
|
||||
}
|
||||
|
||||
|
||||
@@ -15,21 +21,26 @@ function socketOnMessage(event) {
|
||||
|
||||
function socketOnClose(event, resolve, reject) {
|
||||
if (event.wasClean) {
|
||||
console.log(`\n${chalk.green('✔')} Connection closed: ${event.code} ${event.reason}.`)
|
||||
console.log(`\n${chalk.green('✔')} Connection closed: ${chalk.green(event.code)} ${event.reason}.`)
|
||||
resolve()
|
||||
} else {
|
||||
reject(`Connection unexpectedly closed: ${event.code} ${event.reason}.`)
|
||||
process.stdin.setRawMode(false)
|
||||
process.stdin.pause()
|
||||
reject(new Error(`Connection unexpectedly closed: ${event.code} ${event.reason}.`))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function socketOnError(error, reject) {
|
||||
process.stdin.setRawMode(false)
|
||||
process.stdin.pause()
|
||||
reject(error)
|
||||
}
|
||||
|
||||
|
||||
async function webSocketSession(headers, socketUrl) {
|
||||
return new Promise((resolve, reject) => {
|
||||
spinner.start()
|
||||
const socket = new WebSocket(socketUrl, {
|
||||
headers,
|
||||
rejectUnauthorized: false,
|
||||
|
@@ -1,41 +0,0 @@
|
||||
async function getNeType() {
|
||||
const axiosConfig = {
|
||||
text: 'Getting Network Element Type...',
|
||||
method: 'get',
|
||||
url: `${this.objectUrl}${this.currentPoId}`,
|
||||
params: {
|
||||
includeNonPersistent: false,
|
||||
stringifyLong: false
|
||||
}
|
||||
}
|
||||
const { data: { neType } } = await this.httpClient.request(axiosConfig)
|
||||
return neType
|
||||
}
|
||||
|
||||
|
||||
async function getActions(type, neType) {
|
||||
const axiosConfig = {
|
||||
text: 'Matching Actions...',
|
||||
method: 'post',
|
||||
url: '/rest/v1/apps/action-matches',
|
||||
data: {
|
||||
application: 'topologybrowser',
|
||||
multipleSelection: false,
|
||||
conditions: [
|
||||
{
|
||||
dataType: 'ManagedObject',
|
||||
properties: [
|
||||
{ name: 'type', value: type },
|
||||
{ name: 'type', value: type },
|
||||
{ name: 'neType', value: neType },
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
const { data: { actions } } = await this.httpClient.request(axiosConfig)
|
||||
return actions
|
||||
}
|
||||
|
||||
|
||||
module.exports = { getNeType, getActions }
|
Reference in New Issue
Block a user