shell app improvements

This commit is contained in:
Vyacheslav.Sviridov
2023-01-14 19:38:19 +06:00
parent 1f875d9e1e
commit e9607924ef
13 changed files with 227 additions and 123 deletions

View File

@@ -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)

View 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

View 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

View 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 }

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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'
]

View File

@@ -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

View File

@@ -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

View File

@@ -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')

View File

@@ -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)

View File

@@ -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,

View File

@@ -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 }