mirror of
https://github.com/vvsviridov/enm-cli.git
synced 2025-11-01 12:44:01 +00:00
first alpha
This commit is contained in:
72
bin/enm-cli.js
Normal file → Executable file
72
bin/enm-cli.js
Normal file → Executable file
@@ -3,43 +3,59 @@
|
||||
const { Command, Option } = require('commander')
|
||||
const pkg = require('../package.json')
|
||||
const inquirer = require('inquirer')
|
||||
const path = require('path')
|
||||
|
||||
const { isEmpty } = require('../util/validation')
|
||||
|
||||
require('dotenv').config()
|
||||
require('dotenv').config({ path: [...__dirname.split(path.sep).slice(0,-1), '.env'].join(path.sep) })
|
||||
|
||||
const AutoProvisioning = require('../lib/components/AutoProvisioning/AutoProvisioning')
|
||||
const TopologyBrowser = require('../lib/components/TopologyBrowser/TopologyBrowser')
|
||||
const AutoProvisioning = require('../lib/applications/AutoProvisioning/AutoProvisioning')
|
||||
const TopologyBrowser = require('../lib/applications/TopologyBrowser/TopologyBrowser')
|
||||
|
||||
const logError = require('../util/logError')
|
||||
|
||||
const applications = ['tplg', 'prvn']
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
process.on('uncaughtException', function (exception) {
|
||||
console.log(exception);
|
||||
})
|
||||
}
|
||||
|
||||
const applications = [
|
||||
{
|
||||
id: 'tplg',
|
||||
appClass: TopologyBrowser,
|
||||
name: 'Topology Browser',
|
||||
},
|
||||
{
|
||||
id: 'prvn',
|
||||
appClass: AutoProvisioning,
|
||||
name: 'Auto Provisioning',
|
||||
}
|
||||
]
|
||||
const appIds = applications.map(item => item.id)
|
||||
|
||||
const program = new Command()
|
||||
program
|
||||
.version(pkg.version)
|
||||
// .option('-l, --login <letters>', 'ENM User Login')
|
||||
// .option('-p, --password <letters>', 'ENM User Password')
|
||||
.addOption(new Option('-l, --login <letters>', 'ENM User Login').env('LOGIN'))
|
||||
.addOption(new Option('-p, --password <letters>', 'ENM User Password').env('PASSWORD'))
|
||||
.addOption(new Option('-a, --application <letters>', 'Start specified application')
|
||||
.choices(applications)
|
||||
.default('tplg')
|
||||
.choices(appIds)
|
||||
)
|
||||
.requiredOption('-u, --url <letters>', 'ENM Url')
|
||||
.requiredOption('-u, --url <valid URL>', 'ENM Url')
|
||||
.parse(process.argv)
|
||||
|
||||
|
||||
const options = program.opts()
|
||||
|
||||
|
||||
|
||||
async function promptUsername() {
|
||||
const input = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'value',
|
||||
suffix: chalk.bgGreen('?'),
|
||||
message: 'Type ENM login',
|
||||
prefix: '👤',
|
||||
message: 'Type ENM login:',
|
||||
validate: isEmpty,
|
||||
}
|
||||
])
|
||||
@@ -52,7 +68,8 @@ async function promptPassword() {
|
||||
{
|
||||
type: 'password',
|
||||
name: 'value',
|
||||
message: `Type ${options.login}'s ENM password`,
|
||||
prefix: '🔑',
|
||||
message: 'Type ENM password:',
|
||||
validate: isEmpty,
|
||||
}
|
||||
])
|
||||
@@ -62,37 +79,34 @@ async function promptPassword() {
|
||||
|
||||
async function selectApplication() {
|
||||
let selectedApp
|
||||
if (options.application && options.application in applications) {
|
||||
if (options.application && appIds.includes(options.application)) {
|
||||
selectedApp = options.application
|
||||
} else {
|
||||
const input = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'application',
|
||||
suffix: '💾',
|
||||
message,
|
||||
choices: applications
|
||||
prefix: '💾',
|
||||
message: 'Select Application:',
|
||||
choices: applications.map(item => ({name: item.name, value: item.id, short: item.id}))
|
||||
}])
|
||||
selectedApp = input.application
|
||||
}
|
||||
return {
|
||||
tplg: TopologyBrowser,
|
||||
prvn: AutoProvisioning
|
||||
}[selectedApp]
|
||||
const { appClass } = applications.find(item => item.id === selectedApp)
|
||||
const login = options.login || await promptUsername()
|
||||
const password = options.password || await promptPassword()
|
||||
return new appClass(login, password, options.url)
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
const app = new selectApplication()(options.login || await promptUsername(), options.password || await promptPassword(), options.url)
|
||||
const result = await app.login()
|
||||
const { code } = result
|
||||
if (code === 'SUCCESS') {
|
||||
await app.inputHandler()
|
||||
await app.logout()
|
||||
}
|
||||
const app = await selectApplication()
|
||||
await app.login()
|
||||
await app.inputHandler()
|
||||
await app.logout()
|
||||
} catch (error) {
|
||||
logError(error)
|
||||
}
|
||||
}
|
||||
|
||||
; (async () => await main())()
|
||||
;(async () => await main())()
|
||||
|
||||
5
lib/components/AutoProvisioning/AutoProvisioning.js → lib/applications/AutoProvisioning/AutoProvisioning.js
Normal file → Executable file
5
lib/components/AutoProvisioning/AutoProvisioning.js → lib/applications/AutoProvisioning/AutoProvisioning.js
Normal file → Executable file
@@ -1,4 +1,4 @@
|
||||
const ENM = require('../ENM/ENM')
|
||||
const ENM = require('../../components/ENM')
|
||||
|
||||
const { getProjects, getProjectData, deleteProject, newProject } = require('./projects')
|
||||
const {
|
||||
@@ -23,8 +23,7 @@ class AutoProvisioning extends ENM {
|
||||
this.projectIndex = -1
|
||||
this.nodes = null
|
||||
this.nodeIndex = -1
|
||||
this.commands = null
|
||||
this.choices = null
|
||||
this.prompt = ''
|
||||
this.help = 'No results...'
|
||||
}
|
||||
|
||||
43
lib/components/AutoProvisioning/inputHandler.js → lib/applications/AutoProvisioning/inputHandler.js
Normal file → Executable file
43
lib/components/AutoProvisioning/inputHandler.js → lib/applications/AutoProvisioning/inputHandler.js
Normal file → Executable file
@@ -8,32 +8,32 @@ const { isEmpty } = require('../../../util/validation')
|
||||
inquirer.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt'))
|
||||
|
||||
|
||||
async function commandOther(prvn, prompt, command) {
|
||||
async function commandOther(prvn, command) {
|
||||
const choosedIndex = prvn.choices.indexOf(command)
|
||||
if (choosedIndex !== -1) {
|
||||
if (prvn.nodes) {
|
||||
prvn.nodeIndex = choosedIndex
|
||||
prompt = prvn.getNode()
|
||||
prvn.getNode()
|
||||
} else {
|
||||
prvn.projectIndex = choosedIndex
|
||||
prompt = await prvn.getProjectData()
|
||||
await prvn.getProjectData()
|
||||
}
|
||||
}
|
||||
return prompt
|
||||
}
|
||||
|
||||
|
||||
async function handleCommand(prvn, prompt, command) {
|
||||
async function handleCommand(prvn, command) {
|
||||
const [, cmd] = command.match(/\[(\w+)\]/) || [, command]
|
||||
switch (cmd) {
|
||||
|
||||
case 'exit':
|
||||
return
|
||||
prvn.prompt = ''
|
||||
break
|
||||
case 'new':
|
||||
await prvn.newProject()
|
||||
break
|
||||
case 'back':
|
||||
prompt = prvn.nodeIndex ? await prvn.getProjects() : await prvn.getProjectData()
|
||||
prvn.nodeIndex ? await prvn.getProjects() : await prvn.getProjectData()
|
||||
break
|
||||
case 'delete':
|
||||
prvn.nodeIndex ? prvn.deleteNode() : await prvn.deleteProject()
|
||||
@@ -62,32 +62,30 @@ async function handleCommand(prvn, prompt, command) {
|
||||
break
|
||||
|
||||
default:
|
||||
prompt = await commandOther(prvn, prompt, command)
|
||||
await commandOther(prvn, command)
|
||||
}
|
||||
return prompt
|
||||
}
|
||||
|
||||
|
||||
async function inputHandlerLoop(prvn) {
|
||||
let prompt = await prvn.getProjects()
|
||||
let prefix = ''
|
||||
async function inputHandler() {
|
||||
await this.getProjects()
|
||||
while (true) {
|
||||
try {
|
||||
const input = await inquirer.prompt([
|
||||
{
|
||||
type: 'autocomplete',
|
||||
name: 'command',
|
||||
message: chalk.bold.blue(prompt),
|
||||
message: chalk.bold.blue(this.prompt),
|
||||
pageSize: 10,
|
||||
prefix: chalk.bold.grey(prefix),
|
||||
prefix: '',
|
||||
suffix: chalk.bold.blue('>'),
|
||||
validate: isEmpty,
|
||||
source: async (answers, input) => await prvn.next(input),
|
||||
emptyText: prvn.help,
|
||||
source: async (answers, input) => await this.next(input),
|
||||
emptyText: this.help,
|
||||
}
|
||||
])
|
||||
prompt = await handleCommand(prvn, prompt, input.command)
|
||||
if (!prompt) break
|
||||
await handleCommand(this, input.command)
|
||||
if (!this.prompt) break
|
||||
} catch (error) {
|
||||
logError(error)
|
||||
}
|
||||
@@ -95,13 +93,4 @@ async function inputHandlerLoop(prvn) {
|
||||
}
|
||||
|
||||
|
||||
async function inputHandler() {
|
||||
try {
|
||||
await inputHandlerLoop(this)
|
||||
} catch (error) {
|
||||
logError(error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = inputHandler
|
||||
2
lib/components/AutoProvisioning/nodes.js → lib/applications/AutoProvisioning/nodes.js
Normal file → Executable file
2
lib/components/AutoProvisioning/nodes.js → lib/applications/AutoProvisioning/nodes.js
Normal file → Executable file
@@ -35,7 +35,7 @@ async function getNode() {
|
||||
this.commands = nodeCommands
|
||||
this.help = nodeCommandsHelp.join('\n ')
|
||||
this.choices = [] // this.nodes.filter(item => item !== nodeId)
|
||||
return `${projectId} (${nodeId}) `
|
||||
this.prompt = `${projectId} (${nodeId}) `
|
||||
}
|
||||
|
||||
|
||||
4
lib/components/AutoProvisioning/projects.js → lib/applications/AutoProvisioning/projects.js
Normal file → Executable file
4
lib/components/AutoProvisioning/projects.js → lib/applications/AutoProvisioning/projects.js
Normal file → Executable file
@@ -34,7 +34,7 @@ async function getProjects() {
|
||||
this.commands = projectsCommands
|
||||
this.help = projectsCommandsHelp.join('\n ')
|
||||
this.nodes = null
|
||||
return `${this.projects.length} projects`
|
||||
this.prompt = `${this.projects.length} projects`
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ async function getProjectData() {
|
||||
this.commands = projectCommands
|
||||
this.help = projectCommandsHelp.join('\n ')
|
||||
this.nodeIndex = -1
|
||||
return projectId
|
||||
this.prompt = projectId
|
||||
}
|
||||
|
||||
|
||||
154
lib/applications/TopologyBrowser/TopologyBrowser.js
Executable file
154
lib/applications/TopologyBrowser/TopologyBrowser.js
Executable file
@@ -0,0 +1,154 @@
|
||||
const logAttributes = require('../../../util/logAttributes')
|
||||
const inputHandler = require('./inputHandler')
|
||||
const alarms = require('./commands/alarms')
|
||||
const sync = require('./commands/sync')
|
||||
const initialPrompt = require('./commands/initialPrompt')
|
||||
const nextObjects = require('./commands/nextObjects')
|
||||
const nextAttributes = require('./commands/nextAttributes')
|
||||
const setIdByCommand = require('./commands/setIdByCommand')
|
||||
const show = require('./commands/show')
|
||||
const up = require('./commands/up')
|
||||
const config = require('./commands/config')
|
||||
const end = require('./commands/end')
|
||||
const setAttribute = require('./commands/setAttribute')
|
||||
const description = require('./commands/description')
|
||||
const get = require('./commands/get')
|
||||
const set = require('./commands/set')
|
||||
const commit = require('./commands/commit')
|
||||
const home = require('./commands/home')
|
||||
const search = require('./commands/search')
|
||||
const goToFdn = require('./commands/goToFdn')
|
||||
const createNext = require('../../../util/createNext')
|
||||
const { mainHelp, configHelp } = require('./help')
|
||||
|
||||
const ENM = require('../../components/ENM')
|
||||
const chalk = require('chalk')
|
||||
|
||||
class TopologyBrowser extends ENM {
|
||||
constructor(username, password, url) {
|
||||
super(username, password, url)
|
||||
this.objectUrl = '/persistentObject/'
|
||||
this.alarmUrl = '/alarmcontroldisplayservice/alarmMonitoring/alarmoperations/'
|
||||
this.nodeTypesUrl = '/modelInfo/model/nodeTypes/'
|
||||
this.nodeSearchUrl = '/managedObjects/search/v2'
|
||||
this.nodePoIdsUrl = '/managedObjects/getPosByPoIds'
|
||||
|
||||
this.currentPoId = 0
|
||||
this.nextPoId = 1
|
||||
this.fdn = ''
|
||||
this.childrens = []
|
||||
this.poIds = []
|
||||
this.isConfig = false
|
||||
this.attributes = []
|
||||
this.nextVariants = null
|
||||
this.attributesData = []
|
||||
this.attribute = null
|
||||
this.networkDetails = null
|
||||
this.configSet = []
|
||||
this.includeNonPersistent = false
|
||||
this.configCommands = ['commit', 'check', 'end', 'exit']
|
||||
this.help = mainHelp
|
||||
}
|
||||
|
||||
async initialPrompt() {
|
||||
await initialPrompt.call(this)
|
||||
}
|
||||
|
||||
async next(input) {
|
||||
await this.nextVariants(input)
|
||||
return createNext.call(this, input ? input : '')
|
||||
}
|
||||
|
||||
async nextObjects(input) {
|
||||
return await nextObjects.call(this, input)
|
||||
}
|
||||
|
||||
async nextAttributes(input) {
|
||||
return await nextAttributes.call(this, input)
|
||||
}
|
||||
|
||||
setIdByCommand(command) {
|
||||
return setIdByCommand.call(this, command)
|
||||
}
|
||||
|
||||
async show(filter) {
|
||||
await show.call(this, filter)
|
||||
}
|
||||
|
||||
up() {
|
||||
return up.call(this)
|
||||
}
|
||||
|
||||
async config(fdn) {
|
||||
this.help = configHelp
|
||||
return await config.call(this, fdn)
|
||||
}
|
||||
|
||||
end() {
|
||||
this.help = mainHelp
|
||||
end.call(this)
|
||||
}
|
||||
|
||||
setAttribute(attribute) {
|
||||
return setAttribute.call(this, attribute)
|
||||
}
|
||||
|
||||
description() {
|
||||
description.call(this)
|
||||
}
|
||||
|
||||
get(fdn) {
|
||||
get.call(this, fdn)
|
||||
}
|
||||
|
||||
async set() {
|
||||
await set.call(this)
|
||||
}
|
||||
|
||||
async commit(fdn) {
|
||||
return await commit.call(this, fdn)
|
||||
}
|
||||
|
||||
check() {
|
||||
logAttributes(this.fdn.replace(/\((\w+)\)/g, ''), this.configSet)
|
||||
}
|
||||
|
||||
home() {
|
||||
home.call(this)
|
||||
}
|
||||
|
||||
async search() {
|
||||
await search.call(this)
|
||||
}
|
||||
|
||||
async goToFdn(fromFdn, targetFdn) {
|
||||
return await goToFdn.call(this, fromFdn, targetFdn)
|
||||
}
|
||||
|
||||
persistent() {
|
||||
this.includeNonPersistent = !this.includeNonPersistent
|
||||
console.log(chalk.yellow(`Include Non Persistent Atrributes Set to: ${this.includeNonPersistent}`))
|
||||
}
|
||||
|
||||
async alarms(fdn) {
|
||||
await alarms.call(this, fdn)
|
||||
}
|
||||
|
||||
async sync(fdn) {
|
||||
await sync.call(this, fdn)
|
||||
}
|
||||
|
||||
async inputHandler() {
|
||||
await inputHandler.call(this)
|
||||
}
|
||||
|
||||
getPrompt() {
|
||||
if (this.fdn.length >= 67) {
|
||||
return `...${this.fdn.slice(-65)}`
|
||||
}
|
||||
return this.fdn
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = TopologyBrowser
|
||||
34
lib/components/TopologyBrowser/commands/alarms.js → lib/applications/TopologyBrowser/commands/alarms.js
Normal file → Executable file
34
lib/components/TopologyBrowser/commands/alarms.js → lib/applications/TopologyBrowser/commands/alarms.js
Normal file → Executable file
@@ -1,19 +1,18 @@
|
||||
const colors = require('colors')
|
||||
const chalk = require('chalk')
|
||||
const inquirer = require('inquirer')
|
||||
|
||||
const requestWrapper = require('../../util/requestWrapper')
|
||||
const logAlarm = require('../../util/logAlarm')
|
||||
const eventTimeToString = require('../../util/eventTimeToString')
|
||||
const logAlarm = require('../../../../util/logAlarm')
|
||||
const eventTimeToString = require('../../../../util/eventTimeToString')
|
||||
|
||||
const closeAlarms = { name: 'Close Alarms'.yellow, value: -1}
|
||||
const closeAlarms = { name: chalk.yellow('Close Alarms'), value: -1}
|
||||
|
||||
|
||||
function logTotal(total) {
|
||||
if (total === 0) {
|
||||
console.log(`Total Alarms: ${total}`.green)
|
||||
console.log(chalk.green(`Total Alarms: ${total}`))
|
||||
return
|
||||
}
|
||||
console.log(`Total Alarms: ${total}`.yellow)
|
||||
console.log(chalk.yellow(`Total Alarms: ${total}`))
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +35,7 @@ function parsePoIdResponse(response) {
|
||||
|
||||
async function getPoIds(url, nodes) {
|
||||
const axiosConfig = {
|
||||
text: 'Getting Alarms...',
|
||||
method: 'post',
|
||||
url,
|
||||
data: {
|
||||
@@ -54,7 +54,7 @@ async function getPoIds(url, nodes) {
|
||||
advFilters: ''
|
||||
}
|
||||
}
|
||||
const response = await requestWrapper(axiosConfig, 'Getting Alarms...')
|
||||
const response = await this.httpClient.request(axiosConfig)
|
||||
if (!Array.isArray(response.data)) return
|
||||
const [total, eventPoIds] = parsePoIdResponse(response)
|
||||
logTotal(total)
|
||||
@@ -64,6 +64,7 @@ async function getPoIds(url, nodes) {
|
||||
|
||||
async function getFields(url, eventPoIds) {
|
||||
const axiosConfig = {
|
||||
text: 'Getting Alarms Data...',
|
||||
method: 'post',
|
||||
url,
|
||||
data: {
|
||||
@@ -74,12 +75,12 @@ async function getFields(url, eventPoIds) {
|
||||
category: 'All'
|
||||
}
|
||||
}
|
||||
const response = await requestWrapper(axiosConfig, 'Getting Alarms Data...')
|
||||
const response = await this.httpClient.request(axiosConfig)
|
||||
return response.data
|
||||
}
|
||||
|
||||
|
||||
async function alarmChoices(alarmList, input) {
|
||||
function alarmChoices(alarmList, input) {
|
||||
const filter = input ? input : ''
|
||||
return alarmList
|
||||
.map(al => {
|
||||
@@ -102,7 +103,7 @@ async function alarmsLoop(alarmList) {
|
||||
name: 'alarm',
|
||||
message: 'Select Alarm:',
|
||||
pageSize: 10,
|
||||
source: async (answers, input) => await alarmChoices(alarmList, input)
|
||||
source: async (answers, input) => alarmChoices(alarmList, input)
|
||||
}
|
||||
])
|
||||
if (input.alarm === closeAlarms.value) break
|
||||
@@ -111,15 +112,14 @@ async function alarmsLoop(alarmList) {
|
||||
}
|
||||
|
||||
|
||||
async function alarms(fdn) {
|
||||
const meContextFind = fdn.match(/(NetworkElement|MeContext)=([\w-]+),?/)
|
||||
async function alarms() {
|
||||
const meContextFind = this.fdn.match(/(NetworkElement|MeContext)=([\w-]+),?/)
|
||||
if (!meContextFind) {
|
||||
console.log('No alarming object in FDN!'.yellow)
|
||||
return
|
||||
throw new Error('No alarming object in FDN!')
|
||||
}
|
||||
const eventPoIds = await getPoIds(`${this.alarmUrl}eventpoids`, meContextFind[2])
|
||||
const eventPoIds = await getPoIds.call(this, `${this.alarmUrl}eventpoids`, meContextFind[2])
|
||||
if (!eventPoIds) return
|
||||
const alarmList = await getFields(`${this.alarmUrl}getalarmlist/fields`, eventPoIds)
|
||||
const alarmList = await getFields.call(this, `${this.alarmUrl}getalarmlist/fields`, eventPoIds)
|
||||
await alarmsLoop(alarmList)
|
||||
}
|
||||
|
||||
35
lib/applications/TopologyBrowser/commands/commit.js
Executable file
35
lib/applications/TopologyBrowser/commands/commit.js
Executable file
@@ -0,0 +1,35 @@
|
||||
const logAttributes = require('../../../../util/logAttributes')
|
||||
const logCommit = require('../../../../util/logCommit')
|
||||
|
||||
|
||||
async function commit() {
|
||||
if (!this.configSet.length) {
|
||||
throw new Error('Configuration is empty❗')
|
||||
}
|
||||
this.fdn = this.fdn.replace(/\((\w+)\)/g, '')
|
||||
logAttributes(this.fdn, this.configSet)
|
||||
const axiosConfig = {
|
||||
text: 'Commiting Config...',
|
||||
method: 'put',
|
||||
url: `${this.objectUrl}${this.currentPoId}`,
|
||||
data: {
|
||||
poId: this.currentPoId,
|
||||
fdn: this.fdn,
|
||||
attributes: this.configSet,
|
||||
},
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
const response = await this.httpClient.request(axiosConfig)
|
||||
if (response.data) {
|
||||
logCommit(response.data)
|
||||
} else {
|
||||
throw new Error('No data or response❗')
|
||||
}
|
||||
this.configSet.length = 0
|
||||
this.end()
|
||||
}
|
||||
|
||||
|
||||
module.exports = commit
|
||||
19
lib/components/TopologyBrowser/commands/config.js → lib/applications/TopologyBrowser/commands/config.js
Normal file → Executable file
19
lib/components/TopologyBrowser/commands/config.js → lib/applications/TopologyBrowser/commands/config.js
Normal file → Executable file
@@ -1,10 +1,10 @@
|
||||
const requestWrapper = require('../../util/requestWrapper')
|
||||
const logDetails = require('../../util/logDetails')
|
||||
const logDetails = require('../../../../util/logDetails')
|
||||
|
||||
|
||||
async function config(fdn) {
|
||||
async function config() {
|
||||
this.isConfig = true
|
||||
const axiosConfig = {
|
||||
text: 'Reading Attributes...',
|
||||
method: 'get',
|
||||
url: `${this.objectUrl}${this.currentPoId}`,
|
||||
params: {
|
||||
@@ -12,27 +12,26 @@ async function config(fdn) {
|
||||
stringifyLong: true
|
||||
}
|
||||
}
|
||||
const responseA = await requestWrapper(axiosConfig, 'Reading Attributes...')
|
||||
const responseA = await this.httpClient.request(axiosConfig)
|
||||
if (!responseA.data.attributes) {
|
||||
console.log('Can\'t read attributes'.red)
|
||||
return fdn
|
||||
throw new Error('Can\'t read attributes')
|
||||
}
|
||||
const { attributes, namespace, namespaceVersion, neType, neVersion, networkDetails, type} = responseA.data
|
||||
axiosConfig.text = 'Reading Attributes Data...'
|
||||
axiosConfig.url = `${this.objectUrl}model/${neType}/${neVersion}/${namespace}/${type}/${namespaceVersion}/attributes`
|
||||
axiosConfig.params = {
|
||||
includeNonPersistent: this.includeNonPersistent
|
||||
}
|
||||
const responseD = await requestWrapper(axiosConfig, 'Reading Attributes Data...')
|
||||
const responseD = await this.httpClient.request(axiosConfig)
|
||||
if (!responseD.data.attributes) {
|
||||
console.log('Can\'t read attributes data'.red)
|
||||
return fdn
|
||||
throw new Error('Can\'t read attributes data')
|
||||
}
|
||||
this.networkDetails = networkDetails
|
||||
logDetails(networkDetails)
|
||||
this.attributes = attributes
|
||||
this.nextVariants = async (input) => await this.nextAttributes(input)
|
||||
this.attributesData = responseD.data.attributes
|
||||
return `${fdn}(config)`
|
||||
this.fdn = `${this.fdn}(config)`
|
||||
}
|
||||
|
||||
|
||||
21
lib/applications/TopologyBrowser/commands/description.js
Executable file
21
lib/applications/TopologyBrowser/commands/description.js
Executable file
@@ -0,0 +1,21 @@
|
||||
const chalk = require('chalk')
|
||||
const logAttributeData = require('../../../../util/logAttributeData')
|
||||
|
||||
|
||||
function description() {
|
||||
const attributeData = this.attributesData.find(item => item.key === this.attribute)
|
||||
if (attributeData) {
|
||||
logAttributeData(attributeData)
|
||||
if (attributeData.complexRef) {
|
||||
console.log(`${chalk.magenta(attributeData.type)}
|
||||
${chalk.cyan(attributeData.complexRef.key)}: ${chalk.grey(attributeData.complexRef.description)}
|
||||
`)
|
||||
attributeData.complexRef.attributes.forEach(attr => logAttributeData(attr))
|
||||
}
|
||||
} else {
|
||||
throw new Error('Attribute Not Found❗')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = description
|
||||
2
lib/components/TopologyBrowser/commands/end.js → lib/applications/TopologyBrowser/commands/end.js
Normal file → Executable file
2
lib/components/TopologyBrowser/commands/end.js → lib/applications/TopologyBrowser/commands/end.js
Normal file → Executable file
@@ -1,7 +1,9 @@
|
||||
function end() {
|
||||
this.fdn = this.fdn.replace(/\((\w+)\)/g, '')
|
||||
this.isConfig = false
|
||||
this.attribute = null
|
||||
this.configSet.length = 0
|
||||
this.configCommands = this.configCommands.filter(cmd => !['get', 'set', 'description'].includes(cmd) )
|
||||
this.nextVariants = async (input) => await this.nextObjects(input)
|
||||
}
|
||||
|
||||
23
lib/applications/TopologyBrowser/commands/get.js
Executable file
23
lib/applications/TopologyBrowser/commands/get.js
Executable file
@@ -0,0 +1,23 @@
|
||||
const logAttributes = require('../../../../util/logAttributes')
|
||||
const banner = require('../../../../util/banner')
|
||||
const chalk = require('chalk')
|
||||
|
||||
|
||||
function get() {
|
||||
const syncStatus = this.networkDetails.find(item => item.key === 'syncStatus')
|
||||
if (syncStatus && syncStatus.value === 'UNSYNCHRONIZED') {
|
||||
console.log(chalk.yellow(`
|
||||
❗ ${syncStatus.key}: ${syncStatus.value} ❗`))
|
||||
}
|
||||
const attribute = this.attributes.find(item => item.key === this.attribute)
|
||||
if (!attribute) {
|
||||
throw new Error(`Attribute not Found: ${this.attribute}`)
|
||||
}
|
||||
const attributeData = this.attributesData.find(item => item.key === this.attribute)
|
||||
logAttributes(this.fdn, [attribute])
|
||||
console.log(` ${chalk.green('Type: ') + attributeData['type']} ${attributeData['defaultValue'] ? chalk.yellow('Default: ') + attributeData['defaultValue'] : ''}
|
||||
`)
|
||||
if (attributeData.constraints && attributeData.constraints.orderingConstraint) banner(attributeData)
|
||||
}
|
||||
|
||||
module.exports = get
|
||||
21
lib/components/TopologyBrowser/commands/fdn.js → lib/applications/TopologyBrowser/commands/goToFdn.js
Normal file → Executable file
21
lib/components/TopologyBrowser/commands/fdn.js → lib/applications/TopologyBrowser/commands/goToFdn.js
Normal file → Executable file
@@ -1,28 +1,29 @@
|
||||
const requestWrapper = require('../../util/requestWrapper')
|
||||
|
||||
|
||||
async function fdn(fromFdn, targetFdn) {
|
||||
async function goToFdn(targetFdn) {
|
||||
if (!targetFdn) {
|
||||
throw new Error('Valid FDN must be supplied❗')
|
||||
}
|
||||
const axiosConfig = {
|
||||
text: 'Browsing to FDN...',
|
||||
method: 'get',
|
||||
url: `${this.objectUrl}fdn/${targetFdn}`,
|
||||
}
|
||||
const response1 = await requestWrapper(axiosConfig, 'Browsing to FDN...')
|
||||
if (!response1.data.fdn) return fromFdn
|
||||
const response1 = await this.httpClient.request(axiosConfig)
|
||||
this.poIds.length = 0
|
||||
const { fdn, poId } = response1.data
|
||||
this.currentPoId = poId
|
||||
this.nextPoId = poId
|
||||
this.nextVariants = async (input) => await this.nextObjects(input)
|
||||
axiosConfig.text = 'Building FDN path...'
|
||||
axiosConfig.url = `${this.objectUrl}network/${this.currentPoId}/subTrees`
|
||||
const response2 = await requestWrapper(axiosConfig, 'Building FDN path...')
|
||||
const response2 = await this.httpClient.request(axiosConfig)
|
||||
if (response2.data) {
|
||||
if (response2.data.treeNodes.length > 1) {
|
||||
response2.data.treeNodes.slice(0, -1).forEach((node) => {
|
||||
this.poIds.push(node.poId)
|
||||
})
|
||||
}
|
||||
this.childrens = null
|
||||
this.childrens = []
|
||||
}
|
||||
return fdn
|
||||
this.fdn = fdn
|
||||
}
|
||||
module.exports = fdn
|
||||
module.exports = goToFdn
|
||||
1
lib/components/TopologyBrowser/commands/home.js → lib/applications/TopologyBrowser/commands/home.js
Normal file → Executable file
1
lib/components/TopologyBrowser/commands/home.js → lib/applications/TopologyBrowser/commands/home.js
Normal file → Executable file
@@ -1,4 +1,5 @@
|
||||
function home() {
|
||||
this.fdn = this.fdn.split(',', 1)[0]
|
||||
this.nextPoId = this.poIds.shift()
|
||||
this.poIds.length = 0
|
||||
this.nextVariants = async (input) => await this.nextObjects(input)
|
||||
11
lib/components/TopologyBrowser/commands/initialPrompt.js → lib/applications/TopologyBrowser/commands/initialPrompt.js
Normal file → Executable file
11
lib/components/TopologyBrowser/commands/initialPrompt.js → lib/applications/TopologyBrowser/commands/initialPrompt.js
Normal file → Executable file
@@ -1,22 +1,21 @@
|
||||
const colors = require('colors')
|
||||
const requestWrapper = require('../../util/requestWrapper')
|
||||
const chalk = require("chalk")
|
||||
|
||||
|
||||
async function initialPrompt() {
|
||||
const axiosConfig = {
|
||||
text: 'Starting Topology Browser...',
|
||||
method: 'get',
|
||||
url: `${this.objectUrl}network/-1?relativeDepth=0:-2&childDepth=1`
|
||||
}
|
||||
const response = await requestWrapper(axiosConfig, 'Starting Topology Browser...')
|
||||
const response = await this.httpClient.request(axiosConfig)
|
||||
if (!response.data.treeNodes) {
|
||||
console.log('Nothing in initial promt!'.red)
|
||||
return
|
||||
throw new Error('Nothing in initial promt‼')
|
||||
}
|
||||
const { moType, moName, poId } = response.data.treeNodes[0]
|
||||
this.currentPoId = poId
|
||||
this.nextPoId = poId
|
||||
this.nextVariants = async (input) => await this.nextObjects(input)
|
||||
return `${moType}=${moName}`
|
||||
this.fdn = `${moType}=${moName}`
|
||||
}
|
||||
|
||||
|
||||
14
lib/applications/TopologyBrowser/commands/nextAttributes.js
Executable file
14
lib/applications/TopologyBrowser/commands/nextAttributes.js
Executable file
@@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
async function nextAttributes(input) {
|
||||
const filter = input ? input : ''
|
||||
this.commands = this.configCommands
|
||||
.filter(item => item.toLowerCase().includes(filter.toLowerCase()))
|
||||
this.choices = this.attributes
|
||||
.map(item => item.key)
|
||||
.filter(item => item.toLowerCase().includes(filter.toLowerCase()))
|
||||
.sort((a, b) => a > b ? 1 : -1)
|
||||
}
|
||||
|
||||
|
||||
module.exports = nextAttributes
|
||||
57
lib/applications/TopologyBrowser/commands/nextObjects.js
Executable file
57
lib/applications/TopologyBrowser/commands/nextObjects.js
Executable file
@@ -0,0 +1,57 @@
|
||||
const chalk = require("chalk")
|
||||
const logError = require('../../../../util/logError')
|
||||
|
||||
const otherCommands = ['show', 'config', 'up', 'home', 'fdn', 'search', 'persistent', 'alarms', 'sync', 'exit']
|
||||
|
||||
|
||||
function getSyncStatus(child) {
|
||||
if (child.syncStatus === 'SYNCHRONIZED') return '\t\t✅'
|
||||
if (child.syncStatus === 'UNSYNCHRONIZED') return '\t\t⏳'
|
||||
return child.syncStatus ? '\t\t❓' : ''
|
||||
}
|
||||
|
||||
|
||||
function getRadioAccessTechnology(child) {
|
||||
return child.radioAccessTechnology ? ' ' + chalk.bold.cyan(child.radioAccessTechnology.join(' ')) : ''
|
||||
}
|
||||
|
||||
|
||||
async function networkRequest() {
|
||||
try {
|
||||
const axiosConfig = {
|
||||
text: 'Loading network data...',
|
||||
method: 'get',
|
||||
url: `${this.objectUrl}network/${this.currentPoId}`
|
||||
}
|
||||
const { data: { treeNodes } } = await this.httpClient.request(axiosConfig)
|
||||
if (treeNodes) {
|
||||
this.childrens = treeNodes[0].childrens
|
||||
}
|
||||
} catch (error) {
|
||||
logError(error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function nextObjects(input){
|
||||
const filter = input ? input : ''
|
||||
if (this.currentPoId !== this.nextPoId || this.childrens.length === 0) {
|
||||
this.currentPoId = this.nextPoId
|
||||
this.poIds.push(this.currentPoId)
|
||||
await networkRequest.call(this)
|
||||
}
|
||||
this.commands = otherCommands.filter(cmd => cmd.toLowerCase().includes(filter.toLowerCase()))
|
||||
this.choices = this.childrens
|
||||
.map(child => {
|
||||
const st = getSyncStatus(child)
|
||||
const rt = getRadioAccessTechnology(child)
|
||||
const ne = child.neType ? ' ' + chalk.dim.gray(child.neType) : ''
|
||||
return `${child.moType}=${child.moName}${st}${rt}${ne}`
|
||||
})
|
||||
.filter(child => child.toLowerCase().includes(filter.toLowerCase()))
|
||||
.concat(filter.startsWith('show') ? [filter] : [])
|
||||
.concat(filter.startsWith('fdn') ? [filter] : [])
|
||||
}
|
||||
|
||||
|
||||
module.exports = nextObjects
|
||||
127
lib/applications/TopologyBrowser/commands/search.js
Executable file
127
lib/applications/TopologyBrowser/commands/search.js
Executable file
@@ -0,0 +1,127 @@
|
||||
const chalk = require('chalk')
|
||||
const inquirer = require('inquirer')
|
||||
const { isValidNodeName } = require('../../../../util/validation')
|
||||
|
||||
|
||||
async function getNodeTypes() {
|
||||
const axiosConfig = {
|
||||
text: 'Getting Node Types...',
|
||||
method: 'get',
|
||||
url: this.nodeTypesUrl,
|
||||
}
|
||||
const response = await this.httpClient.request(axiosConfig)
|
||||
return response.data
|
||||
}
|
||||
|
||||
|
||||
async function getPoIds(query) {
|
||||
const axiosConfig = {
|
||||
text: 'Searching Nodes...',
|
||||
method: 'get',
|
||||
url: this.nodeSearchUrl,
|
||||
headers: {
|
||||
'X-Netex-Scoping-Panel': true,
|
||||
},
|
||||
params: {
|
||||
query,
|
||||
orderby: 'moName',
|
||||
orderdirection: 'asc',
|
||||
}
|
||||
}
|
||||
const { data: { objects } } = await this.httpClient.request(axiosConfig)
|
||||
return objects.map(item => item.id)
|
||||
}
|
||||
|
||||
|
||||
async function getNodesData(poList) {
|
||||
const axiosConfig = {
|
||||
text: 'Getting Nodes Data...',
|
||||
method: 'post',
|
||||
url: this.nodePoIdsUrl,
|
||||
data: {
|
||||
poList,
|
||||
defaultMappings: ["syncStatus","managementState","radioAccessTechnology","parentNeType"],
|
||||
attributeMappings:[{"moType":"MeContext","attributeNames":["neType"]}]
|
||||
}
|
||||
}
|
||||
const response = await this.httpClient.request(axiosConfig)
|
||||
return response.data
|
||||
}
|
||||
|
||||
|
||||
function resultOutput(result) {
|
||||
console.log('')
|
||||
result.forEach(item => {
|
||||
const {
|
||||
fdn,
|
||||
attributes,
|
||||
cmSyncStatus,
|
||||
radioAccessTechnology,
|
||||
} = item
|
||||
console.log(`${cmSyncStatus === 'SYNCHRONIZED' ? '✅' : '⏳'} ${fdn} ${chalk.dim.grey(attributes.neType)} ${chalk.bold.cyan(radioAccessTechnology.join(' '))}`)
|
||||
})
|
||||
console.log('')
|
||||
}
|
||||
|
||||
|
||||
function filterTypes(input, nodeTypes){
|
||||
const filter = input ? input : ''
|
||||
return nodeTypes.filter(
|
||||
item => item
|
||||
.toLowerCase()
|
||||
.includes(filter.toLowerCase())
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
function buildQuery(nodeName, nodeType, rat) {
|
||||
const ratFilter = rat.length !== 0
|
||||
? ` filter by radioAccessTechnology ${rat.length === 1 ? 'containing ' : 'contains any of '}${rat.join(',')}`
|
||||
: ''
|
||||
const typeFilter = nodeType === 'ALL'
|
||||
? `with name = ${nodeName}`
|
||||
: `of type ${nodeType} where name = ${nodeName}`
|
||||
return `select all nodes ${nodeName && typeFilter}${ratFilter}`
|
||||
}
|
||||
|
||||
|
||||
async function search() {
|
||||
const nodeTypes = await getNodeTypes.call(this)
|
||||
nodeTypes.push('ALL')
|
||||
const { nodeName, nodeType, rat } = await inquirer.prompt([
|
||||
{
|
||||
type: 'autocomplete',
|
||||
name: 'nodeType',
|
||||
message: 'Select Node Type (default ALL):',
|
||||
pageSize: 10,
|
||||
default: 'ALL',
|
||||
source: async (answers, input) => filterTypes(input, nodeTypes)
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
name: 'rat',
|
||||
message: 'Select Radio Access Technologies (default all):',
|
||||
choices: [
|
||||
{name: '2G'},
|
||||
{name: '3G'},
|
||||
{name: '4G'},
|
||||
{name: '5G'},
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'nodeName',
|
||||
message: 'Type a Node Name:',
|
||||
validate: isValidNodeName
|
||||
}
|
||||
])
|
||||
const poList = await getPoIds.call(this, buildQuery(nodeName, nodeType, rat))
|
||||
if (poList.length === 0) {
|
||||
throw new Error('Nodes not found❗')
|
||||
}
|
||||
const result = await getNodesData.call(this, poList)
|
||||
resultOutput(result)
|
||||
}
|
||||
|
||||
|
||||
module.exports = search
|
||||
8
lib/components/TopologyBrowser/commands/set.js → lib/applications/TopologyBrowser/commands/set.js
Normal file → Executable file
8
lib/components/TopologyBrowser/commands/set.js → lib/applications/TopologyBrowser/commands/set.js
Normal file → Executable file
@@ -1,16 +1,14 @@
|
||||
const colors = require('colors')
|
||||
const inputByType = require('../inputValue')
|
||||
|
||||
|
||||
async function set() {
|
||||
const attributeData = this.attributesData.filter(item => item.key === this.attribute)[0]
|
||||
const attributeData = this.attributesData.find(item => item.key === this.attribute)
|
||||
if (!attributeData) return
|
||||
if (attributeData.writeBehavior === 'NOT_ALLOWED' || attributeData.immutable) {
|
||||
console.log('Attribute Is ReadOnly'.yellow)
|
||||
return
|
||||
throw new Error('Attribute Is ReadOnly')
|
||||
}
|
||||
if (this.isConfig) {
|
||||
const found = this.configSet.filter(item => item.key === this.attribute)[0]
|
||||
const found = this.configSet.find(item => item.key === this.attribute)
|
||||
const { value } = await inputByType(attributeData)
|
||||
if (found) {
|
||||
found.value = value
|
||||
12
lib/applications/TopologyBrowser/commands/setAttribute.js
Executable file
12
lib/applications/TopologyBrowser/commands/setAttribute.js
Executable file
@@ -0,0 +1,12 @@
|
||||
function setAttribute(attribute) {
|
||||
if (!this.attributes) return false
|
||||
if (!this.attributes.find(item => item.key === attribute)) return false
|
||||
if (!this.attribute) {
|
||||
['get', 'set', 'description'].forEach(cmd => this.configCommands.push(cmd))
|
||||
}
|
||||
this.attribute = attribute
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
module.exports = setAttribute
|
||||
2
lib/components/TopologyBrowser/commands/setIdByCommand.js → lib/applications/TopologyBrowser/commands/setIdByCommand.js
Normal file → Executable file
2
lib/components/TopologyBrowser/commands/setIdByCommand.js → lib/applications/TopologyBrowser/commands/setIdByCommand.js
Normal file → Executable file
@@ -1,5 +1,5 @@
|
||||
function setIdByCommand(command) {
|
||||
const nextChild = this.childrens.filter(child => `${child.moType}=${child.moName}` === command)[0]
|
||||
const nextChild = this.childrens.find(child => `${child.moType}=${child.moName}` === command)
|
||||
if (nextChild) {
|
||||
this.nextPoId = nextChild.poId
|
||||
return true
|
||||
6
lib/components/TopologyBrowser/commands/show.js → lib/applications/TopologyBrowser/commands/show.js
Normal file → Executable file
6
lib/components/TopologyBrowser/commands/show.js → lib/applications/TopologyBrowser/commands/show.js
Normal file → Executable file
@@ -1,9 +1,9 @@
|
||||
const requestWrapper = require('../../util/requestWrapper')
|
||||
const logAttributes = require('../../util/logAttributes')
|
||||
const logAttributes = require('../../../../util/logAttributes')
|
||||
|
||||
|
||||
async function show(filter) {
|
||||
const axiosConfig = {
|
||||
text: 'Getting Atrributes...',
|
||||
method: 'get',
|
||||
url: `${this.objectUrl}${this.currentPoId}`,
|
||||
params: {
|
||||
@@ -11,7 +11,7 @@ async function show(filter) {
|
||||
stringifyLong: true
|
||||
}
|
||||
}
|
||||
const response = await requestWrapper(axiosConfig)
|
||||
const response = await this.httpClient.request(axiosConfig)
|
||||
if (!response.data.fdn || !response.data.attributes) return
|
||||
logAttributes(response.data.fdn, response.data.attributes.filter(item => item.key.match(filter)))
|
||||
}
|
||||
26
lib/applications/TopologyBrowser/commands/sync.js
Executable file
26
lib/applications/TopologyBrowser/commands/sync.js
Executable file
@@ -0,0 +1,26 @@
|
||||
const chalk = require("chalk")
|
||||
|
||||
|
||||
async function sync() {
|
||||
const meContextFind = this.fdn.match(/(NetworkElement|MeContext)=([\w-]+),?/)
|
||||
if (!meContextFind) {
|
||||
throw new Error('No sync object in FDN!')
|
||||
}
|
||||
const actionUrl = `${this.objectUrl}v1/perform-mo-action/NetworkElement=${meContextFind[2]},CmFunction=1?actionName=sync`
|
||||
const axiosConfig = {
|
||||
text: 'Initiate Node Sync...',
|
||||
method: 'post',
|
||||
url: actionUrl,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
}
|
||||
const response = await this.httpClient.request(axiosConfig)
|
||||
console.log(`
|
||||
${chalk.bold(response.data.body)}
|
||||
${chalk.green(response.data.title)}
|
||||
`)
|
||||
}
|
||||
|
||||
|
||||
module.exports = sync
|
||||
5
lib/components/TopologyBrowser/commands/up.js → lib/applications/TopologyBrowser/commands/up.js
Normal file → Executable file
5
lib/components/TopologyBrowser/commands/up.js → lib/applications/TopologyBrowser/commands/up.js
Normal file → Executable file
@@ -3,9 +3,10 @@ function up() {
|
||||
this.poIds.pop()
|
||||
this.nextPoId = this.poIds.pop()
|
||||
this.currentPoId = this.poIds[this.poIds.length - 1]
|
||||
return true
|
||||
this.fdn = this.fdn.split(',').slice(0, -1).join(',')
|
||||
return
|
||||
}
|
||||
return false
|
||||
throw new Error('There\'s no way up!')
|
||||
}
|
||||
|
||||
|
||||
25
lib/applications/TopologyBrowser/help.js
Executable file
25
lib/applications/TopologyBrowser/help.js
Executable file
@@ -0,0 +1,25 @@
|
||||
const mainHelp = [
|
||||
'',
|
||||
'show [<valid regex>] - shows current object\'s attributes filtered with regex',
|
||||
'config - enters config mode',
|
||||
'up - navigate up one level',
|
||||
'fdn [<valid FDN>] - navigate to FDN',
|
||||
'home - navigate to root folder',
|
||||
'alarms - show alarms',
|
||||
'sync - initiate node CM synchronization',
|
||||
'persistent - toggle persistent attributes inclusion',
|
||||
'exit - logout and exit application',
|
||||
].join('\n')
|
||||
|
||||
const configHelp = [
|
||||
'',
|
||||
'set - set attribute\'s value',
|
||||
'get - get attribute\'s value',
|
||||
'commit - commiting changes to the network',
|
||||
'check - view configuration changes',
|
||||
'end - exit config mode without commiting',
|
||||
'exit - logout and exit application',
|
||||
].join('\n')
|
||||
|
||||
|
||||
module.exports = { mainHelp, configHelp }
|
||||
109
lib/applications/TopologyBrowser/inputHandler.js
Executable file
109
lib/applications/TopologyBrowser/inputHandler.js
Executable file
@@ -0,0 +1,109 @@
|
||||
const inquirer = require('inquirer')
|
||||
const chalk = require('chalk')
|
||||
|
||||
const logError = require('../../../util/logError')
|
||||
const { isEmpty } = require('../../../util/validation')
|
||||
|
||||
|
||||
inquirer.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt'))
|
||||
|
||||
|
||||
function commandOther(tplg, command) {
|
||||
const spl = command.split(/\s+/).find(item => item)
|
||||
if (tplg.setIdByCommand(spl)) {
|
||||
tplg.fdn = `${tplg.fdn},${spl}`
|
||||
} else if (tplg.setAttribute(command)) {
|
||||
tplg.fdn = tplg.fdn.replace(/\((\w+)\)/g, `(${command})`)
|
||||
} else {
|
||||
throw new Error('Command Unrecognized❗')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function handleCommand(tplg, command) {
|
||||
const [cmd, param] = command.split(/\s+/)
|
||||
const cmdMatch = cmd.match(/\[(\w+)\]/)
|
||||
const cmdName = cmdMatch ? cmdMatch[1] : cmd
|
||||
switch (cmdName) {
|
||||
case 'exit':
|
||||
tplg.fdn = ''
|
||||
break
|
||||
case 'show':
|
||||
await tplg.show(param ? param.trim() : '')
|
||||
break
|
||||
case 'config':
|
||||
await tplg.config()
|
||||
break
|
||||
case 'set':
|
||||
await tplg.set()
|
||||
break
|
||||
case 'commit':
|
||||
await tplg.commit()
|
||||
break
|
||||
case 'up':
|
||||
tplg.up()
|
||||
break
|
||||
case 'get':
|
||||
tplg.get()
|
||||
break
|
||||
case 'check':
|
||||
tplg.check()
|
||||
break
|
||||
case 'end':
|
||||
tplg.end()
|
||||
break
|
||||
case 'home':
|
||||
tplg.home()
|
||||
break
|
||||
case 'search':
|
||||
await tplg.search()
|
||||
break
|
||||
case 'description':
|
||||
tplg.description()
|
||||
break
|
||||
case 'persistent':
|
||||
tplg.persistent()
|
||||
break
|
||||
case 'fdn':
|
||||
await tplg.goToFdn(param ? param.trim() : '')
|
||||
break
|
||||
case 'alarms':
|
||||
await tplg.alarms()
|
||||
break
|
||||
case 'sync':
|
||||
await tplg.sync()
|
||||
break
|
||||
|
||||
default:
|
||||
commandOther(tplg, command)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function inputHandler() {
|
||||
await this.initialPrompt()
|
||||
while (true) {
|
||||
try {
|
||||
const input = await inquirer.prompt([
|
||||
{
|
||||
type: 'autocomplete',
|
||||
name: 'command',
|
||||
message: chalk.blue(this.getPrompt()),
|
||||
pageSize: 10,
|
||||
prefix: '',
|
||||
suffix: this.isConfig ? chalk.blue('#') : chalk.blue('>'),
|
||||
validate: isEmpty,
|
||||
source: async (answers, input) => await this.next(input),
|
||||
emptyText: this.help,
|
||||
}
|
||||
])
|
||||
await handleCommand(this, input.command)
|
||||
if (!this.fdn) break
|
||||
} catch (error) {
|
||||
logError(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = inputHandler
|
||||
29
lib/components/TopologyBrowser/inputValue.js → lib/applications/TopologyBrowser/inputValue.js
Normal file → Executable file
29
lib/components/TopologyBrowser/inputValue.js → lib/applications/TopologyBrowser/inputValue.js
Normal file → Executable file
@@ -1,16 +1,16 @@
|
||||
const colors = require('colors')
|
||||
const chalk = require('chalk')
|
||||
const inquirer = require('inquirer')
|
||||
const banner = require('../util/banner')
|
||||
const { isValidNumber, isValidString, checkValueRangeConstraints } = require('../util/validation')
|
||||
const banner = require('../../../util/banner')
|
||||
const { isValidNumber, isValidString, checkValueRangeConstraints } = require('../../../util/validation')
|
||||
|
||||
|
||||
async function inputInteger(attributeData) {
|
||||
const message = `${attributeData.key.yellow} { ${attributeData.unit ? attributeData.unit : 'parrots'.gray} } (${attributeData.type}): `
|
||||
const message = `${chalk.yellow(attributeData.key)} { ${attributeData.unit ? attributeData.unit : chalk.gray('parrots')} } (${attributeData.type}): `
|
||||
const input = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'value',
|
||||
suffix: '?'.green,
|
||||
suffix: chalk.green('?'),
|
||||
message,
|
||||
default: attributeData.defaultValue,
|
||||
validate: input => isValidNumber(input, attributeData.constraints),
|
||||
@@ -21,12 +21,12 @@ async function inputInteger(attributeData) {
|
||||
|
||||
|
||||
async function inputEnumRef(attributeData) {
|
||||
const message = `Select Value For ${attributeData.key.yellow}: `
|
||||
const message = `Select Value For ${chalk.yellow(attributeData.key)}: `
|
||||
const input = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'value',
|
||||
suffix: '?'.green,
|
||||
suffix: chalk.green('?'),
|
||||
message,
|
||||
choices: attributeData.enumeration.enumMembers.map(item => ({ name: `${item.key} (${item.description})`, value: item.key, short: item.key })),
|
||||
default: attributeData.defaultValue,
|
||||
@@ -39,12 +39,12 @@ async function inputEnumRef(attributeData) {
|
||||
async function inputBoolean(attributeData) {
|
||||
const variants = ['true', 'false']
|
||||
if (attributeData.constraints.nullable) variants.push('null')
|
||||
const message = `Select Value For ${attributeData.key.yellow}:`
|
||||
const message = `Select Value For ${chalk.yellow(attributeData.key)}:`
|
||||
const input = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'value',
|
||||
suffix: '?'.green,
|
||||
suffix: chalk.green('?'),
|
||||
message,
|
||||
choices: variants,
|
||||
default: String(attributeData.defaultValue),
|
||||
@@ -59,12 +59,12 @@ async function inputBoolean(attributeData) {
|
||||
|
||||
|
||||
async function inputString(attributeData) {
|
||||
const message = `${attributeData.key.yellow} (${attributeData.type}): `
|
||||
const message = `${chalk.yellow(attributeData.key)} (${attributeData.type}): `
|
||||
const input = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'value',
|
||||
suffix: '?'.green,
|
||||
suffix: chalk.green('?'),
|
||||
message,
|
||||
default: attributeData.defaultValue,
|
||||
validate: input => isValidString(input, attributeData.constraints),
|
||||
@@ -75,13 +75,13 @@ async function inputString(attributeData) {
|
||||
|
||||
|
||||
async function inputList(attributeData) {
|
||||
const message = `${attributeData.key.yellow} List Of (${attributeData.listReference.type}) Size: `
|
||||
const message = `${chalk.yellow(attributeData.key)} List Of (${attributeData.listReference.type}) Size: `
|
||||
const result = []
|
||||
const { value } = await inquirer.prompt([
|
||||
{
|
||||
type: 'number',
|
||||
name: 'value',
|
||||
suffix: '?'.green,
|
||||
suffix: chalk.green('?'),
|
||||
message,
|
||||
default: 'null',
|
||||
validate: input => +input > 0 || input === 'null',
|
||||
@@ -108,7 +108,7 @@ async function inputListValues(attributeData, listSize, result) {
|
||||
}
|
||||
if (attributeData.constraints.uniqueMembers) {
|
||||
if (result.indexOf(input.value) !== -1) {
|
||||
console.log('>>Array Values Should Be Unique'.red)
|
||||
console.log(chalk.red('>>Array Values Should Be Unique'))
|
||||
i--
|
||||
continue
|
||||
}
|
||||
@@ -138,6 +138,7 @@ async function inputByType(typeReference) {
|
||||
const inputs = {
|
||||
INTEGER: inputInteger,
|
||||
SHORT: inputInteger,
|
||||
LONG: inputInteger,
|
||||
ENUM_REF: inputEnumRef,
|
||||
BOOLEAN: inputBoolean,
|
||||
STRING: inputString,
|
||||
8
lib/components/AxiosHttpClient/AxiosHttpClient.js → lib/components/AxiosHttpClient.js
Normal file → Executable file
8
lib/components/AxiosHttpClient/AxiosHttpClient.js → lib/components/AxiosHttpClient.js
Normal file → Executable file
@@ -1,9 +1,9 @@
|
||||
const axios = require('axios')
|
||||
const chalk = require('chalk')
|
||||
const https = require('https')
|
||||
const axiosCookieJarSupport = require('axios-cookiejar-support').default
|
||||
const tough = require('tough-cookie')
|
||||
const SpinnerWithCounter = require('../../../util/SpinnerWithCounter')
|
||||
const logError = require('../../util/logError')
|
||||
const SpinnerWithCounter = require('./SpinnerWithCounter')
|
||||
|
||||
|
||||
axiosCookieJarSupport(axios)
|
||||
@@ -20,6 +20,10 @@ function beforeRequest(config) {
|
||||
|
||||
function errorRequest(error) {
|
||||
spinner.fail()
|
||||
if (401 === error.response.status) {
|
||||
logError(error)
|
||||
process.exit(1)
|
||||
}
|
||||
return Promise.reject(error)
|
||||
}
|
||||
|
||||
5
lib/components/ENM/ENM.js → lib/components/ENM.js
Normal file → Executable file
5
lib/components/ENM/ENM.js → lib/components/ENM.js
Normal file → Executable file
@@ -1,10 +1,11 @@
|
||||
const chalk = require('chalk')
|
||||
const axiosHttpClient = require('../AxiosHttpClient/AxiosHttpClient')
|
||||
const axiosHttpClient = require('./AxiosHttpClient')
|
||||
|
||||
class ENM {
|
||||
constructor(username, password, url) {
|
||||
this.logoutUrl = '/logout'
|
||||
this.loginUrl = `/login?IDToken1=${username}&IDToken2=${password}`
|
||||
this.commands = null
|
||||
this.choices = null
|
||||
this.httpClient = axiosHttpClient(url)
|
||||
}
|
||||
|
||||
0
util/SpinnerWithCounter.js → lib/components/SpinnerWithCounter.js
Normal file → Executable file
0
util/SpinnerWithCounter.js → lib/components/SpinnerWithCounter.js
Normal file → Executable file
@@ -1,132 +0,0 @@
|
||||
const logAttributes = require('../util/logAttributes')
|
||||
const inputHandler = require('./inputHandler')
|
||||
const alarms = require('../commands/alarms')
|
||||
const sync = require('../commands/sync')
|
||||
const initialPrompt = require('../commands/initialPrompt')
|
||||
const nextObjects = require('../commands/nextObjects')
|
||||
const nextAttributes = require('../commands/nextAttributes')
|
||||
const setIdByCommand = require('../commands/setIdByCommand')
|
||||
const show = require('../commands/show')
|
||||
const up = require('../commands/up')
|
||||
const config = require('../commands/config')
|
||||
const end = require('../commands/end')
|
||||
const setAttribute = require('../commands/setAttribute')
|
||||
const description = require('../commands/description')
|
||||
const get = require('../commands/get')
|
||||
const set = require('../commands/set')
|
||||
const commit = require('../commands/commit')
|
||||
const home = require('../commands/home')
|
||||
const fdn = require('../commands/fdn')
|
||||
|
||||
const ENM = require('../ENM/ENM')
|
||||
|
||||
class TopologyBrowser extends ENM {
|
||||
constructor(username, password, url) {
|
||||
super(username, password, url)
|
||||
this.objectUrl = '/persistentObject/'
|
||||
this.alarmUrl = '/alarmcontroldisplayservice/alarmMonitoring/alarmoperations/'
|
||||
|
||||
this.currentPoId = 0
|
||||
this.nextPoId = 1
|
||||
this.childrens = null
|
||||
this.poIds = []
|
||||
this.isConfig = false
|
||||
this.attributes = null
|
||||
this.nextVariants = null
|
||||
this.attributesData = null
|
||||
this.attribute = null
|
||||
this.networkDetails = null
|
||||
this.configSet = []
|
||||
this.includeNonPersistent = false
|
||||
this.configCommands = ['commit', 'check', 'end', 'persistent', 'exit']
|
||||
this.help = 'No results...'
|
||||
}
|
||||
|
||||
async initialPrompt() {
|
||||
return await initialPrompt.call(this)
|
||||
}
|
||||
|
||||
async next(input) {
|
||||
return await this.nextVariants(input)
|
||||
}
|
||||
|
||||
async nextObjects(input) {
|
||||
return await nextObjects.call(this, input)
|
||||
}
|
||||
|
||||
async nextAttributes(input) {
|
||||
return await nextAttributes.call(this, input)
|
||||
}
|
||||
|
||||
setIdByCommand(command) {
|
||||
return setIdByCommand.call(this, command)
|
||||
}
|
||||
|
||||
async show(filter) {
|
||||
await show.call(this, filter)
|
||||
}
|
||||
|
||||
up() {
|
||||
return up.call(this)
|
||||
}
|
||||
|
||||
async config(fdn) {
|
||||
return await config.call(this, fdn)
|
||||
}
|
||||
|
||||
end() {
|
||||
end.call(this)
|
||||
}
|
||||
|
||||
setAttribute(attribute) {
|
||||
return setAttribute.call(this, attribute)
|
||||
}
|
||||
|
||||
description() {
|
||||
description.call(this)
|
||||
}
|
||||
|
||||
get(fdn) {
|
||||
get.call(this, fdn)
|
||||
}
|
||||
|
||||
async set() {
|
||||
await set.call(this)
|
||||
}
|
||||
|
||||
async commit(fdn) {
|
||||
return await commit.call(this, fdn)
|
||||
}
|
||||
|
||||
check(fdn) {
|
||||
logAttributes(fdn, this.configSet)
|
||||
}
|
||||
|
||||
home() {
|
||||
home.call(this)
|
||||
}
|
||||
|
||||
async fdn(fromFdn, targetFdn) {
|
||||
return await fdn.call(this, fromFdn, targetFdn)
|
||||
}
|
||||
|
||||
persistent() {
|
||||
this.includeNonPersistent = !this.includeNonPersistent
|
||||
console.log(`Include Non Persistent Atrributes Set to: ${this.includeNonPersistent}`.yellow)
|
||||
}
|
||||
|
||||
async alarms(fdn) {
|
||||
await alarms.call(this, fdn)
|
||||
}
|
||||
|
||||
async sync(fdn) {
|
||||
await sync.call(this, fdn)
|
||||
}
|
||||
|
||||
async inputHandler() {
|
||||
await inputHandler.call(this)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = TopologyBrowser
|
||||
@@ -1,34 +0,0 @@
|
||||
const colors = require('colors')
|
||||
const logAttributes = require('../../util/logAttributes')
|
||||
const requestWrapper = require('../../util/requestWrapper')
|
||||
const logCommit = require('../../util/logCommit')
|
||||
|
||||
|
||||
async function commit(fdn) {
|
||||
logAttributes(fdn, this.configSet)
|
||||
this.configSet.forEach(item => delete item.from)
|
||||
const axiosConfig = {
|
||||
method: 'put',
|
||||
url: `${this.objectUrl}${this.currentPoId}`,
|
||||
data: {
|
||||
poId: this.currentPoId,
|
||||
fdn,
|
||||
attributes: this.configSet,
|
||||
},
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
const response = await requestWrapper(axiosConfig, 'Commiting Config...')
|
||||
if (response.data) {
|
||||
logCommit(response.data)
|
||||
} else {
|
||||
console.log('No data or response!'.red)
|
||||
}
|
||||
this.configSet.length = 0
|
||||
this.end()
|
||||
return fdn
|
||||
}
|
||||
|
||||
|
||||
module.exports = commit
|
||||
@@ -1,21 +0,0 @@
|
||||
const colors = require('colors')
|
||||
const logAttributeData = require('../../util/logAttributeData')
|
||||
|
||||
|
||||
function description() {
|
||||
const attributeData = this.attributesData.filter(item => item.key === this.attribute)[0]
|
||||
if (attributeData) {
|
||||
logAttributeData(attributeData)
|
||||
if (attributeData.complexRef) {
|
||||
console.log(`${attributeData.type.magenta}
|
||||
${attributeData.complexRef.key.cyan}: ${attributeData.complexRef.description.grey}
|
||||
`)
|
||||
attributeData.complexRef.attributes.forEach(attr => logAttributeData(attr))
|
||||
}
|
||||
} else {
|
||||
console.log('Attribute Not Found!'.yellow)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = description
|
||||
@@ -1,20 +0,0 @@
|
||||
const colors = require('colors')
|
||||
const logAttributes = require('../../util/logAttributes')
|
||||
const banner = require('../../util/banner')
|
||||
|
||||
|
||||
function get(fdn) {
|
||||
const syncStatus = this.networkDetails.filter(item => item.key === 'syncStatus')[0]
|
||||
if (syncStatus && syncStatus.value === 'UNSYNCHRONIZED') {
|
||||
console.log(`
|
||||
❗ ${syncStatus.key}: ${syncStatus.value} ❗`.yellow)
|
||||
}
|
||||
const attribute = this.attributes.filter(item => item.key === this.attribute)[0]
|
||||
const attributeData = this.attributesData.filter(item => item.key === this.attribute)[0]
|
||||
logAttributes(fdn, [attribute])
|
||||
console.log(` ${'Type: '.green + attributeData['type']} ${attributeData['defaultValue'] ? 'Default: '.yellow + attributeData['defaultValue'] : ''}
|
||||
`)
|
||||
if (attributeData.constraints && attributeData.constraints.orderingConstraint) banner(attributeData)
|
||||
}
|
||||
|
||||
module.exports = get
|
||||
@@ -1,14 +0,0 @@
|
||||
async function nextAttributes(input) {
|
||||
const filter = input ? input : ''
|
||||
let result = this.attributes.map(item => item.key).sort((a, b) => a > b ? 1 : -1)
|
||||
.concat(this.configCommands)
|
||||
.filter(item => item.toLowerCase().includes(filter.toLowerCase()))
|
||||
if (result.includes(filter)) {
|
||||
result = result.filter(item => item !== filter)
|
||||
result.unshift(filter)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
module.exports = nextAttributes
|
||||
@@ -1,34 +0,0 @@
|
||||
const requestWrapper = require('../../util/requestWrapper')
|
||||
|
||||
const otherCommands = ['show', 'config', 'up', 'home', 'fdn', 'persistent', 'alarms', 'sync', 'exit']
|
||||
|
||||
|
||||
async function nextObjects(input){
|
||||
const filter = input ? input : ''
|
||||
if (this.currentPoId !== this.nextPoId || !this.childrens) {
|
||||
this.currentPoId = this.nextPoId
|
||||
this.poIds.push(this.currentPoId)
|
||||
const axiosConfig = {
|
||||
method: 'get',
|
||||
url: `${this.objectUrl}network/${this.currentPoId}`
|
||||
}
|
||||
const response = await requestWrapper(axiosConfig)
|
||||
if (response.data.treeNodes) {
|
||||
this.childrens = response.data.treeNodes[0].childrens
|
||||
}
|
||||
}
|
||||
let result = this.childrens
|
||||
.map(child => `${child.moType}=${child.moName}`)
|
||||
.concat(otherCommands)
|
||||
.filter(child => child.toLowerCase().includes(filter.toLowerCase()))
|
||||
.concat(filter.startsWith('show') ? [filter] : [])
|
||||
.concat(filter.startsWith('fdn') ? [filter] : [])
|
||||
if (result.includes(filter)) {
|
||||
result = result.filter(item => item !== filter)
|
||||
result.unshift(filter)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
module.exports = nextObjects
|
||||
@@ -1,14 +0,0 @@
|
||||
function setAttribute(attribute) {
|
||||
if (!this.attributes) return false
|
||||
if (!this.attributes.filter(item => item.key === attribute)[0]) return false
|
||||
if (!this.attribute) {
|
||||
this.configCommands.push('get')
|
||||
this.configCommands.push('set')
|
||||
this.configCommands.push('description')
|
||||
}
|
||||
this.attribute = attribute
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
module.exports = setAttribute
|
||||
@@ -1,30 +0,0 @@
|
||||
const colors = require('colors')
|
||||
|
||||
const requestWrapper = require('../../util/requestWrapper')
|
||||
|
||||
|
||||
async function sync(fdn) {
|
||||
const meContextFind = fdn.match(/(NetworkElement|MeContext)=([\w-]+),?/)
|
||||
if (!meContextFind) {
|
||||
console.log('No sync object in FDN!'.yellow)
|
||||
return
|
||||
}
|
||||
const actionUrl = `${this.objectUrl}v1/perform-mo-action/NetworkElement=${meContextFind[2]},CmFunction=1?actionName=sync`
|
||||
const axiosConfig = {
|
||||
method: 'post',
|
||||
url: actionUrl,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
}
|
||||
const response = await requestWrapper(axiosConfig, 'Initiate Node Sync...')
|
||||
if (response.status === 200) {
|
||||
console.log(`
|
||||
${response.data.body.bold}
|
||||
${response.data.title.green}
|
||||
`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = sync
|
||||
@@ -1,136 +0,0 @@
|
||||
const inquirer = require('inquirer')
|
||||
const colors = require('colors')
|
||||
|
||||
const logError = require('../util/logError')
|
||||
const { isEmpty } = require('../util/validation')
|
||||
|
||||
|
||||
inquirer.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt'))
|
||||
|
||||
|
||||
function buildPrompt(fdn) {
|
||||
if (fdn.length >= 67) {
|
||||
return { prefix: '...', prompt: fdn.slice(-65) }
|
||||
}
|
||||
return { prefix: '', prompt: fdn }
|
||||
}
|
||||
|
||||
|
||||
function commndUp(tplg, fdn) {
|
||||
if (tplg.up()) {
|
||||
fdn = fdn.split(',').slice(0, -1).join(',')
|
||||
} else {
|
||||
console.log('There\'s no way up!'.yellow)
|
||||
}
|
||||
return fdn
|
||||
}
|
||||
|
||||
|
||||
function commandOther(tplg, fdn, command) {
|
||||
if (tplg.setIdByCommand(command)) {
|
||||
fdn = `${fdn},${command}`
|
||||
} else if (tplg.setAttribute(command)) {
|
||||
fdn = fdn.replace(/\((\w+)\)/g, `(${command})`)
|
||||
} else {
|
||||
console.log('Command Unrecognized❗'.red)
|
||||
}
|
||||
return fdn
|
||||
}
|
||||
|
||||
|
||||
async function handleCommand(tplg, fdn, command) {
|
||||
const [cmd, param] = command.split(/\s+/)
|
||||
switch (cmd) {
|
||||
case 'exit':
|
||||
return
|
||||
case 'show':
|
||||
await tplg.show(param ? param.trim() : '')
|
||||
break
|
||||
case 'config':
|
||||
fdn = await tplg.config(fdn)
|
||||
break
|
||||
case 'set':
|
||||
await tplg.set()
|
||||
break
|
||||
case 'commit':
|
||||
fdn = await tplg.commit(fdn.replace(/\((\w+)\)/g, ''))
|
||||
break
|
||||
case 'up':
|
||||
fdn = commndUp(tplg, fdn)
|
||||
break
|
||||
case 'get':
|
||||
tplg.get(fdn)
|
||||
break
|
||||
case 'check':
|
||||
tplg.check(fdn.replace(/\((\w+)\)/g, ''))
|
||||
break
|
||||
case 'end':
|
||||
tplg.end()
|
||||
fdn = fdn.replace(/\((\w+)\)/g, '')
|
||||
break
|
||||
case 'home':
|
||||
tplg.home()
|
||||
fdn = fdn.split(',', 1)[0]
|
||||
break
|
||||
case 'description':
|
||||
tplg.description()
|
||||
break
|
||||
case 'persistent':
|
||||
tplg.persistent()
|
||||
break
|
||||
case 'fdn':
|
||||
fdn = await tplg.fdn(fdn, param ? param.trim() : '')
|
||||
break
|
||||
case 'alarms':
|
||||
await tplg.alarms(fdn)
|
||||
break
|
||||
case 'sync':
|
||||
await tplg.sync(fdn)
|
||||
break
|
||||
|
||||
default:
|
||||
fdn = commandOther(tplg, fdn, command)
|
||||
}
|
||||
return fdn
|
||||
}
|
||||
|
||||
|
||||
async function inputHandlerLoop(tplg) {
|
||||
let prompt = await tplg.initialPrompt()
|
||||
let fdn = prompt
|
||||
let prefix = ''
|
||||
while (true) {
|
||||
try {
|
||||
const input = await inquirer.prompt([
|
||||
{
|
||||
type: 'autocomplete',
|
||||
name: 'command',
|
||||
message: tplg.isConfig ? prompt.blue.underline : prompt.blue,
|
||||
pageSize: 10,
|
||||
prefix: prefix.gray,
|
||||
suffix: tplg.isConfig ? '#'.blue : '>'.blue,
|
||||
validate: isEmpty,
|
||||
source: async (answers, input) => await tplg.next(input),
|
||||
emptyText: prvn.help,
|
||||
}
|
||||
])
|
||||
fdn = await handleCommand(tplg, fdn, input.command)
|
||||
if (!fdn) break
|
||||
({ prefix, prompt } = buildPrompt(fdn))
|
||||
} catch (error) {
|
||||
logError(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function inputHandler() {
|
||||
try {
|
||||
await inputHandlerLoop(this)
|
||||
} catch (error) {
|
||||
logError(error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = inputHandler
|
||||
0
package.json
Normal file → Executable file
0
package.json
Normal file → Executable file
11
util/banner.js
Executable file
11
util/banner.js
Executable file
@@ -0,0 +1,11 @@
|
||||
|
||||
function banner(params) {
|
||||
console.log(`
|
||||
If you see this, pls, send me this message:
|
||||
${JSON.stringify(params, null, 2)}
|
||||
If you see this, pls, send me this message:
|
||||
`)
|
||||
}
|
||||
|
||||
|
||||
module.exports = banner
|
||||
2
util/createNext.js
Normal file → Executable file
2
util/createNext.js
Normal file → Executable file
@@ -6,10 +6,10 @@ function createNext(filter) {
|
||||
const commands = this.commands.filter(cmd => cmd.toLowerCase().includes(filter.toLowerCase()))
|
||||
const choices = this.choices.filter(choice => choice.toLowerCase().includes(filter.toLowerCase()))
|
||||
return [
|
||||
...choices,
|
||||
separator,
|
||||
...commands.map(cmd => `[${cmd}]`),
|
||||
separator,
|
||||
...choices,
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
10
util/eventTimeToString.js
Executable file
10
util/eventTimeToString.js
Executable file
@@ -0,0 +1,10 @@
|
||||
|
||||
|
||||
function eventTimeToString(eventTime) {
|
||||
if (!eventTime) return ''
|
||||
return new Date(eventTime).toISOString().slice(0, -1).split('T').join(' ')
|
||||
// return `${eventDateTime.toLocaleDateString()} ${eventDateTime.toLocaleTimeString()}`
|
||||
}
|
||||
|
||||
|
||||
module.exports = eventTimeToString
|
||||
26
util/logAlarm.js
Executable file
26
util/logAlarm.js
Executable file
@@ -0,0 +1,26 @@
|
||||
const chalk = require('chalk')
|
||||
const eventTimeToString = require('./eventTimeToString')
|
||||
|
||||
|
||||
|
||||
const timeValues = [
|
||||
'eventTime',
|
||||
'insertTime',
|
||||
'ceaseTime',
|
||||
'ackTime',
|
||||
]
|
||||
|
||||
|
||||
function logAlarm(alarmList, eventPoId) {
|
||||
const alarm = alarmList.filter(item => item.eventPoIdAsLong === eventPoId)[0]
|
||||
timeValues.forEach(value => alarm[value] = eventTimeToString(alarm[value]))
|
||||
console.log(
|
||||
JSON.stringify(alarm, null, 2)
|
||||
.replace(/["(){}\[\]]/mg, '')
|
||||
.replace(/,$/mg, '')
|
||||
.replace(/^(\s{2}\w+):/mg, chalk.green('$1:'))
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
module.exports = logAlarm
|
||||
84
util/logAttributeData.js
Executable file
84
util/logAttributeData.js
Executable file
@@ -0,0 +1,84 @@
|
||||
const chalk = require('chalk')
|
||||
|
||||
|
||||
function logDefaultValue(value) {
|
||||
return value ? ` default: ${value}` : ''
|
||||
}
|
||||
|
||||
|
||||
function logAttribute(key, attribute, output) {
|
||||
let attrName = key.replace(/([A-Z])/g, ' $1')
|
||||
if (attribute !== undefined && attribute !== '') {
|
||||
output.push(`${chalk.blue(attrName.toLocaleUpperCase())}
|
||||
${attribute}
|
||||
`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function logConstraints(constraints, output) {
|
||||
output.push(`${chalk.blue(Object.keys({constraints}).pop().toLocaleUpperCase())}`)
|
||||
if (constraints.valueRangeConstraints) {
|
||||
constraints.valueRangeConstraints.forEach(item => {
|
||||
output.push(` ${chalk.yellow('Range')}: ${item.minValue}..${item.maxValue}`)
|
||||
})
|
||||
}
|
||||
['nullable', 'validContentRegex', 'valueResolution'].forEach(key => {
|
||||
if (Object.keys(constraints).includes(key)) {
|
||||
output.push(` ${chalk.yellow(key.replace(/([A-Z])/g, ' $1').replace(/^([a-z])/g, (l) => l.toUpperCase()))}: ${constraints[key]}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function logEnumeration(enumeration, output) {
|
||||
output.push(`${chalk.blue(Object.keys({enumeration}).pop().toLocaleUpperCase())}
|
||||
${chalk.cyan(enumeration.key)}
|
||||
${enumeration.description}`)
|
||||
enumeration.enumMembers.forEach(item => output.push(` ${chalk.yellow(item.key)} (${item.value}): -- ${chalk.gray(item.description)}`))
|
||||
}
|
||||
|
||||
|
||||
function logList(listReference, output) {
|
||||
output.push(`${chalk.blue(Object.keys({listReference}).pop().toLocaleUpperCase())}
|
||||
${listReference.type}`)
|
||||
if (listReference.constraints){
|
||||
logConstraints(listReference.constraints, output)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function logAttributeData(attributeData) {
|
||||
const attributeDataKeys = [
|
||||
'key',
|
||||
'type',
|
||||
'defaultValue',
|
||||
'description',
|
||||
'trafficDisturbances',
|
||||
'unit',
|
||||
'multiplicationFactor',
|
||||
'immutable',
|
||||
'precondition',
|
||||
'dependencies',
|
||||
'sideEffects',
|
||||
'activeChoiceCase',
|
||||
]
|
||||
|
||||
const output = [`
|
||||
${chalk.yellow.bold(attributeData['key'])}: ${chalk.green(attributeData['type'])} ${logDefaultValue(attributeData['defaultValue'])}
|
||||
`]
|
||||
attributeDataKeys.slice(3).forEach((key) => logAttribute(key, attributeData[key], output))
|
||||
if (attributeData.constraints) {
|
||||
logConstraints(attributeData.constraints, output)
|
||||
}
|
||||
if (attributeData.enumeration) {
|
||||
logEnumeration(attributeData.enumeration, output)
|
||||
}
|
||||
if (attributeData.listReference) {
|
||||
logList(attributeData.listReference, output)
|
||||
}
|
||||
console.log(output.join('\n') + '\n')
|
||||
}
|
||||
|
||||
|
||||
module.exports = logAttributeData
|
||||
34
util/logAttributes.js
Executable file
34
util/logAttributes.js
Executable file
@@ -0,0 +1,34 @@
|
||||
const chalk = require('chalk')
|
||||
|
||||
|
||||
function transformAttributes(element) {
|
||||
if (Array.isArray(element)) {
|
||||
return element.map(item => transformAttributes(item))
|
||||
}
|
||||
if (Array.isArray(element.value)) {
|
||||
return { [element.key]: transformAttributes(element.value) }
|
||||
}
|
||||
return element.key ? { [element.key]: element.value } : element
|
||||
}
|
||||
|
||||
|
||||
function colorize(attributes) {
|
||||
const sorted = attributes.sort ? attributes.sort((a, b) => a.key < b.key ? -1 : 1) : attributes
|
||||
return JSON.stringify(transformAttributes(sorted), null, 1)
|
||||
.replace(/["(){}\[\]]/mg, '')
|
||||
.replace(/^\s*,*\n/mg, '')
|
||||
.replace(/,$/mg, '')
|
||||
.replace(/^(\s{2}\w+):/mg, chalk.green('$1:'))
|
||||
.replace(/^(\s{4}\w+):/mg, chalk.yellow('$1:'))
|
||||
.replace(/^(\s{5}\w+):/mg, chalk.cyan('$1:'))
|
||||
}
|
||||
|
||||
|
||||
function logAttributes(fdn, attributes) {
|
||||
const output = `
|
||||
${chalk.yellow.bold('FDN')}: ${chalk.bold(fdn)}
|
||||
${colorize(attributes)}`
|
||||
console.log(output)
|
||||
}
|
||||
|
||||
module.exports = logAttributes
|
||||
10
util/logCommit.js
Executable file
10
util/logCommit.js
Executable file
@@ -0,0 +1,10 @@
|
||||
const chalk = require('chalk')
|
||||
|
||||
|
||||
function logCommit(commitResult) {
|
||||
if (commitResult.title === 'Success') {
|
||||
console.log(chalk.green(commitResult.title))
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = logCommit
|
||||
11
util/logDetails.js
Executable file
11
util/logDetails.js
Executable file
@@ -0,0 +1,11 @@
|
||||
const chalk = require('chalk')
|
||||
|
||||
|
||||
function logDetails(networkDetails) {
|
||||
const output = networkDetails.map(details => ` ${chalk.gray(details.key)}: ${details.value === 'UNSYNCHRONIZED' ? '⌛ ' + chalk.yellow(details.value): chalk.gray(details.value)}`)
|
||||
console.log(`
|
||||
${output.join('\n')}
|
||||
`)
|
||||
}
|
||||
|
||||
module.exports = logDetails
|
||||
66
util/logError.js
Normal file → Executable file
66
util/logError.js
Normal file → Executable file
@@ -1,27 +1,51 @@
|
||||
const chalk = require('chalk')
|
||||
|
||||
function logError(err) {
|
||||
if (err.response && err.response.data && err.response.data.errorTitle) {
|
||||
const {
|
||||
errorTitle = 'Error',
|
||||
errorBody = 'No error body',
|
||||
errorDetails = null
|
||||
} = err.response.data
|
||||
console.log(`
|
||||
⚠️ ${chalk.bold.bgRed(errorTitle)}
|
||||
${chalk.yellow(errorBody || '')}${errorDetails ? '\n' + errorDetails.toString() : ''}
|
||||
`)
|
||||
} else {
|
||||
const {
|
||||
name = 'Error',
|
||||
message = 'No error message',
|
||||
stack = null,
|
||||
} = err
|
||||
console.log(`
|
||||
⛔ ${chalk.bold.bgRed(name)}
|
||||
${chalk.yellow(message)}
|
||||
${chalk.dim(stack && process.env.NODE_ENV === 'development' ? stack : '')}
|
||||
`)
|
||||
try {
|
||||
if (!err.response) {
|
||||
const {
|
||||
name = 'Error',
|
||||
message = 'No error message',
|
||||
stack = null,
|
||||
} = err
|
||||
console.log(`
|
||||
⛔ ${chalk.bold.bgRed(name)}
|
||||
${chalk.yellow(message)}${chalk.dim(stack && process.env.NODE_ENV === 'development' ? '\n' + stack : '')}
|
||||
`)
|
||||
return
|
||||
}
|
||||
if (err.response.data) {
|
||||
const { data } = err.response
|
||||
// other http error
|
||||
let errorTitle = `${err.response.status}: ${err.response.statusText}`
|
||||
let errorBody = data.code
|
||||
let errorDetails = data.message
|
||||
if (typeof data !== 'object') {
|
||||
errorBody = data
|
||||
}
|
||||
if (data.errorCode) {
|
||||
errorBody = `${data.errorCode}: ${data.userMessage.title}`
|
||||
errorDetails = data.userMessage.body
|
||||
}
|
||||
// prvn error
|
||||
if (data.errorTitle) {
|
||||
errorTitle = data.errorTitle
|
||||
errorBody = data.errorBody
|
||||
errorDetails = data.errorDetails
|
||||
}
|
||||
// tplg error
|
||||
if (data.title) {
|
||||
errorTitle = `${data.errorCode}: ${data.title}`
|
||||
errorBody = data.body
|
||||
errorDetails = data.detail
|
||||
}
|
||||
console.log(`
|
||||
⚠️ ${chalk.bold.bgRed(errorTitle)}
|
||||
${chalk.yellow(errorBody)}${errorDetails ? '\n' + errorDetails.toString() : ''}
|
||||
`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
6
util/logNode.js
Normal file → Executable file
6
util/logNode.js
Normal file → Executable file
@@ -3,7 +3,7 @@ const chalk = require('chalk')
|
||||
|
||||
function logNodeStatus(statusEntries, indent = 4) {
|
||||
if (!statusEntries) {
|
||||
throw new Error('No node status entries!')
|
||||
throw new Error('No node status entries❗')
|
||||
}
|
||||
console.log('')
|
||||
statusEntries.forEach(entry => {
|
||||
@@ -21,7 +21,7 @@ function logNodeStatus(statusEntries, indent = 4) {
|
||||
|
||||
function logNodeProperties(attributes, attributeGroups, indent = 4) {
|
||||
if (!attributeGroups) {
|
||||
throw new Error('No node attribute groups!')
|
||||
throw new Error('No node attribute groups❗')
|
||||
}
|
||||
console.log('')
|
||||
logAttributes(attributes)
|
||||
@@ -37,7 +37,7 @@ function logNodeProperties(attributes, attributeGroups, indent = 4) {
|
||||
|
||||
function logAttributes(attributes, indent = 4) {
|
||||
if (!attributes) {
|
||||
throw new Error('No node attributes!')
|
||||
throw new Error('No node attributes❗')
|
||||
}
|
||||
attributes.forEach(attribute => {
|
||||
const { name, value } = attribute
|
||||
|
||||
0
util/logProject.js
Normal file → Executable file
0
util/logProject.js
Normal file → Executable file
55
util/validation.js
Normal file → Executable file
55
util/validation.js
Normal file → Executable file
@@ -6,5 +6,58 @@ const isEmpty = input => (input === '' ? chalk.bgRed('Empty Inputs not Allowed')
|
||||
const isValidHardwareId = input => (input.match(/[A-HJ-NP-Z0-9]{13}/) ? true : chalk.bgRed(`The Ericsson Hardware Serial Number frame consists of 13 alphanumeric characters.
|
||||
Character set is the letters A-Z with the exception of O and I, and digits 0-9.`))
|
||||
|
||||
const isValidNumber = (input, constraints) => {
|
||||
if (constraints) {
|
||||
const test = input ? input : ''
|
||||
if (!constraints.nullable && test === 'null') return chalk.red('Value Can\'t Be a null')
|
||||
if (constraints.nullable && test === 'null') return true
|
||||
if (!test.toString().match(/-?[0-9]+/)) return chalk.red('Input Is Not a Number')
|
||||
const checkResult = checkValueRangeConstraints(+test, constraints)
|
||||
if (checkResult) return checkResult
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
module.exports = { isEmpty, isValidHardwareId }
|
||||
const isValidString = (input, constraints) => {
|
||||
if (constraints) {
|
||||
const test = input ? input : ''
|
||||
if (!constraints.nullable && test === 'null') return chalk.red('Value Can\'t Be a null')
|
||||
if (constraints.nullable && test === 'null') return true
|
||||
if (constraints.validContentRegex && !test.match(constraints.validContentRegex)) return chalk.red('Input Doesn\'t Match RegEx')
|
||||
const checkResult = checkValueRangeConstraints(test.length, constraints)
|
||||
if (checkResult) return checkResult
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const checkValueRangeConstraints = (value, constraints) => {
|
||||
let min
|
||||
let max
|
||||
if (constraints.valueRangeConstraints) {
|
||||
const inRange = constraints.valueRangeConstraints.some(item => {
|
||||
min = item.minValue
|
||||
max = item.maxValue
|
||||
return min <= value && max >= value
|
||||
})
|
||||
errStrArr = constraints.valueRangeConstraints.map(item => `${item.minValue}..${item.maxValue}`)
|
||||
if (!inRange) return chalk.red(`Input is Outside Allowed Range: ${errStrArr.join(', ')}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const isValidNodeName = (input) => {
|
||||
if (input.match('[a-zA-Z0-9-_.\\/:$]+') || input === '') {
|
||||
return true
|
||||
}
|
||||
return chalk.red('Node Name is Invalid')
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
isEmpty,
|
||||
isValidHardwareId,
|
||||
isValidNumber,
|
||||
isValidString,
|
||||
checkValueRangeConstraints,
|
||||
isValidNodeName,
|
||||
}
|
||||
Reference in New Issue
Block a user