1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-22 18:50:08 +03:00

F #5631: vCenter import elements (#1772)

(cherry picked from commit e9f33231f56e4843db0993e1180d781ec358a21b)
This commit is contained in:
Jorge Miguel Lobo Escalona 2022-02-14 16:15:29 +01:00 committed by Tino Vazquez
parent 241d5c6e3a
commit 80fc9b2566
No known key found for this signature in database
GPG Key ID: 14201E424D02047E
20 changed files with 745 additions and 448 deletions

View File

@ -198,7 +198,8 @@ CommandParser::CmdParser.new(ARGV) do
command :list_all,
list_desc,
:options => [OBJECT, HOST, DATASTORE, VCENTER, USER, PASS] do
:options => [OBJECT, HOST, DATASTORE, VCENTER, USER, PASS,
CLIHelper::CSV_OPT] do
begin
args = helper.parse_opts(options)
args[:filter] = false

View File

@ -29,9 +29,9 @@ import {
entrypointApi,
entrypointApp,
} from './routes/entrypoints'
import { websockets } from './routes/websockets'
import { guacamole } from './routes/websockets/guacamole'
import { vmrc } from './routes/websockets/vmrc'
import opennebulaWebsockets from './routes/websockets/opennebula'
import guacamole from './routes/websockets/guacamole'
import vmrc from './routes/websockets/vmrc'
import { getFireedgeConfig } from './utils/yml'
import { messageTerminal } from './utils/general'
import {
@ -143,7 +143,7 @@ const appServer = validateServerIsSecure()
)
: unsecureServer(app)
const sockets = websockets(appServer) || []
const websockets = opennebulaWebsockets(appServer) || []
let config = {
color: 'red',
@ -167,7 +167,7 @@ guacamole(appServer)
* Handle sigterm and sigint.
*/
const handleBreak = () => {
sockets.forEach((socket) => {
websockets.forEach((socket) => {
if (socket && socket.close && typeof socket.close === 'function') {
socket.close()
}

View File

@ -24,6 +24,7 @@ const { sprintf } = require('sprintf-js')
const { Actions } = require('server/utils/constants/commands/document')
const { defaults, httpCodes } = require('server/utils/constants')
const { publish } = require('server/utils/server')
const {
httpResponse,
parsePostData,
@ -43,7 +44,6 @@ const {
renameFolder,
moveToFolder,
findRecursiveFolder,
publish,
getEndpoint,
addOptionalCreateCommand,
getSpecificConfig,
@ -55,6 +55,9 @@ const {
defaultCommandProvision,
defaultEmptyFunction,
defaultErrorTemplate,
defaultRegexpStartJSON,
defaultRegexpEndJSON,
defaultRegexpSplitLine,
} = defaults
const { ok, notFound, accepted, internalServerError } = httpCodes
const httpInternalError = httpResponse(internalServerError, '', '')
@ -68,9 +71,6 @@ const provisionFile = {
ext: 'yaml',
}
const regexp = /^ID: \d+/
const regexpStartJSON = /^{/
const regexpEndJSON = /}$/
const regexpSplitLine = /\r|\n/
const relName = 'provision-mapping'
const ext = 'yml'
const appendError = '.ERROR'
@ -143,21 +143,23 @@ const executeWithEmit = (command = [], actions = {}, dataForLog = {}) => {
message
.toString()
.split(regexpSplitLine)
.split(defaultRegexpSplitLine)
.forEach((line) => {
if (line) {
if (
(regexpStartJSON.test(line) && regexpEndJSON.test(line)) ||
(!regexpStartJSON.test(line) &&
!regexpEndJSON.test(line) &&
(defaultRegexpStartJSON.test(line) &&
defaultRegexpEndJSON.test(line)) ||
(!defaultRegexpStartJSON.test(line) &&
!defaultRegexpEndJSON.test(line) &&
pendingMessages.length === 0)
) {
lastLine = line
publisher(lastLine)
} else if (
(regexpStartJSON.test(line) && !regexpEndJSON.test(line)) ||
(!regexpStartJSON.test(line) &&
!regexpEndJSON.test(line) &&
(defaultRegexpStartJSON.test(line) &&
!defaultRegexpEndJSON.test(line)) ||
(!defaultRegexpStartJSON.test(line) &&
!defaultRegexpEndJSON.test(line) &&
pendingMessages.length > 0)
) {
pendingMessages += line
@ -225,7 +227,7 @@ const logData = (id, fullPath = false) => {
existsFile(
stringPath,
(filedata) => {
rtn = { uuid, log: filedata.split(regexpSplitLine) }
rtn = { uuid, log: filedata.split(defaultRegexpSplitLine) }
if (fullPath) {
rtn.fullPath = stringPath
}

View File

@ -18,7 +18,6 @@ const { v4 } = require('uuid')
const { dirname, basename } = require('path')
// eslint-disable-next-line node/no-deprecated-api
const { parse } = require('url')
const events = require('events')
const { Document, scalarOptions, stringify } = require('yaml')
const {
writeFileSync,
@ -33,39 +32,6 @@ const { getFireedgeConfig, getProvisionConfig } = require('server/utils/yml')
const { messageTerminal } = require('server/utils/general')
const { defaultError } = require('server/utils/server')
const eventsEmitter = new events.EventEmitter()
/**
* Create a event emiter.
*
* @param {string} eventName - name event
* @param {object} message - object message
*/
const publish = (eventName = '', message = {}) => {
if (eventName && message) {
eventsEmitter.emit(eventName, message)
}
}
/**
* Subscriber to event emitter.
*
* @param {string} eventName - event name
* @param {Function} callback - function executed when event is emited
*/
const subscriber = (eventName = '', callback = () => undefined) => {
if (
eventName &&
callback &&
typeof callback === 'function' &&
eventsEmitter.listenerCount(eventName) < 1
) {
eventsEmitter.on(eventName, (message) => {
callback(message)
})
}
}
/**
* Create folder with files.
*
@ -322,9 +288,7 @@ const functionRoutes = {
renameFolder,
moveToFolder,
findRecursiveFolder,
publish,
addOptionalCreateCommand,
subscriber,
getSpecificConfig,
}

View File

@ -19,6 +19,14 @@ const TEMPLATES = 'templates'
const NETWORKS = 'networks'
const IMAGES = 'images'
const LIST = 'list'
const IMPORT = 'import'
const resourceFromData = {
LIST,
IMPORT,
}
const resources = {
DATASTORES,
TEMPLATES,
@ -26,45 +34,55 @@ const resources = {
IMAGES,
}
const questions = {
[DATASTORES]: [],
const params = {
[DATASTORES]: [
{
param: 'host',
flag: '-h',
for: [LIST, IMPORT],
},
],
[TEMPLATES]: [
{
question: 'Type',
flag: '--type',
param: 'datastore',
flag: '--datastore',
for: [LIST, IMPORT],
},
{
question: 'Folder',
param: 'host',
flag: '-h',
for: [LIST, IMPORT],
},
{
param: 'folder',
flag: '--folder',
for: [IMPORT],
},
{
question: 'Linked Clone',
flag: '--linked-clone',
param: 'linked_clone',
flag: '--linked_clone',
for: [IMPORT],
},
],
[NETWORKS]: [
{
question: 'Size',
flag: '--size',
},
{
question: 'Type',
flag: '--type',
},
{
question: 'MAC',
flag: '--mac',
},
{
question: 'Cluster(s) to import',
flag: '--cluster-imports',
},
{
question: 'Unimported Cluster(s)',
flag: '--cluster-unimported',
param: 'host',
flag: '-h',
for: [LIST, IMPORT],
},
],
[IMAGES]: [
{
param: 'host',
flag: '-h',
for: [LIST, IMPORT],
},
{
param: 'datastore',
flag: '--datastore',
for: [LIST, IMPORT],
},
],
[IMAGES]: [],
}
module.exports = { resources, questions }
module.exports = { resourceFromData, resources, params }

View File

@ -14,83 +14,93 @@
* limitations under the License. *
* ------------------------------------------------------------------------- */
const { defaults, httpCodes } = require('server/utils/constants')
const { httpResponse, executeCommand } = require('server/utils/server')
const {
httpResponse,
executeCommand,
executeCommandAsync,
publish,
} = require('server/utils/server')
const {
consoleParseToString,
consoleParseToJSON,
} = require('server/utils/opennebula')
const { resources } = require('server/routes/api/vcenter/command-flags')
const {
resourceFromData,
resources,
params: commandParams,
} = require('server/routes/api/vcenter/command-flags')
const { getSunstoneConfig } = require('server/utils/yml')
const { defaultEmptyFunction, defaultCommandVcenter } = defaults
const { ok, internalServerError, badRequest } = httpCodes
const httpBadRequest = httpResponse(badRequest, '', '')
const {
defaultEmptyFunction,
defaultCommandVcenter,
defaultRegexpStartJSON,
defaultRegexpEndJSON,
defaultRegexpSplitLine,
} = defaults
const { ok, internalServerError, badRequest, accepted } = httpCodes
const { LIST, IMPORT } = resourceFromData
const appConfig = getSunstoneConfig()
const prependCommand = appConfig.vcenter_prepend_command || ''
const regexExclude = [
/^Connecting to.*/gi,
/^Exploring vCenter.*/gi,
/^Connecting to.*/i,
/^Exploring vCenter.*/i,
// eslint-disable-next-line no-control-regex
/^\u001b\[.*?m\u001b\[.*?m# vCenter.*/gi,
/^\u001b\[.*?m\u001b\[.*?m# vCenter.*/i,
]
const regexHeader = /^IMID,.*/i
const validObjects = Object.values(resources)
/**
* Import the the desired vCenter object.
* Show a list with unimported vCenter objects excluding all filters.
*
* @param {object} res - http response
* @param {Function} next - express stepper
* @param {object} params - params of http request
* @param {object} userData - user of http request
*/
const importVcenter = (
res = {},
next = defaultEmptyFunction,
params = {},
userData = {}
) => {
let rtn = httpBadRequest
// check params
if (
params &&
params.vobject &&
validObjects.includes(params.vobject) &&
params.host
) {
const vobject = `${params.vobject}`.toLowerCase()
const list = (res = {}, next = defaultEmptyFunction, params = {}) => {
const { vobject, host, datastore } = params
let paramsCommand = [params.answers ? 'import' : 'import_defaults']
const vobjectLowercase = vobject && `${vobject}`.toLowerCase()
if (!(vobjectLowercase && host && validObjects.includes(vobjectLowercase))) {
res.locals.httpCode = badRequest
next()
if (params.id) {
paramsCommand.push(`${params.id}`)
}
let vobjectAndHost = ['-o', `${vobject}`, '-h', `${params.host}`]
if (vobject === resources.IMAGES && params.datastore) {
const datastoreParameter = ['-d', params.datastore]
vobjectAndHost = [...vobjectAndHost, ...datastoreParameter]
}
// flags by questions import command
/* if (params.answers && questions[vobject]) {
const answers = params.answers.split(',')
} */
paramsCommand = [...paramsCommand, ...vobjectAndHost]
const executedCommand = executeCommand(
defaultCommandVcenter,
paramsCommand,
prependCommand
)
const response = executedCommand.success ? ok : internalServerError
let message = ''
if (executedCommand.data) {
message = consoleParseToString(executedCommand.data, regexExclude)
}
rtn = httpResponse(response, message)
return
}
res.locals.httpCode = rtn
let paramsCommand = [
'list',
'-o',
`${vobjectLowercase}`,
'-h',
`${host}`,
'--csv',
]
if (vobjectLowercase === resources.IMAGES && datastore) {
const newParameters = ['-d', datastore]
paramsCommand = [...paramsCommand, ...newParameters]
}
const executedCommand = executeCommand(
defaultCommandVcenter,
paramsCommand,
prependCommand
)
const response = executedCommand.success ? ok : internalServerError
let message = ''
if (executedCommand.data) {
message = consoleParseToJSON(
consoleParseToString(executedCommand.data, regexExclude),
regexHeader
)
}
res.locals.httpCode = httpResponse(response, message)
next()
}
@ -100,105 +110,46 @@ const importVcenter = (
* @param {object} res - http response
* @param {Function} next - express stepper
* @param {object} params - params of http request
* @param {object} userData - user of http request
*/
const list = (
res = {},
next = defaultEmptyFunction,
params = {},
userData = {}
) => {
let rtn = httpBadRequest
if (
params &&
params.vobject &&
validObjects.includes(params.vobject) &&
params.host
) {
const vobject = `${params.vobject}`.toLowerCase()
let paramsCommand = [
'list',
'-o',
`${vobject}`,
'-h',
`${params.host}`,
'--csv',
]
if (vobject === resources.IMAGES && params.datastore) {
const newParameters = ['-d', params.datastore]
paramsCommand = [...paramsCommand, ...newParameters]
}
const executedCommand = executeCommand(
defaultCommandVcenter,
paramsCommand,
prependCommand
)
const listAll = (res = {}, next = defaultEmptyFunction, params = {}) => {
const { vobject, host, datastore } = params
const response = executedCommand.success ? ok : internalServerError
let message = ''
if (executedCommand.data) {
message = consoleParseToJSON(
consoleParseToString(executedCommand.data, regexExclude),
/^IMID,.*/gi
)
}
rtn = httpResponse(response, message)
const vobjectLowercase = vobject && `${vobject}`.toLowerCase()
if (!(vobjectLowercase && host && validObjects.includes(vobjectLowercase))) {
res.locals.httpCode = badRequest
next()
return
}
res.locals.httpCode = rtn
next()
}
/**
* Show a list with unimported vCenter objects excluding all filters.
*
* @param {object} res - http response
* @param {Function} next - express stepper
* @param {object} params - params of http request
* @param {object} userData - user of http request
*/
const listAll = (
res = {},
next = defaultEmptyFunction,
params = {},
userData = {}
) => {
let rtn = httpBadRequest
if (
params &&
params.vobject &&
validObjects.includes(params.vobject) &&
params.host
) {
const vobject = `${params.vobject}`.toLowerCase()
let paramsCommand = [
'list_all',
'-o',
`${vobject}`,
'-h',
`${params.host}`,
'--csv',
]
if (vobject === resources.IMAGES && params.datastore) {
const newParameters = ['-d', params.datastore]
paramsCommand = [...paramsCommand, ...newParameters]
}
const executedCommand = executeCommand(
defaultCommandVcenter,
paramsCommand,
prependCommand
)
let paramsCommand = [
'list_all',
'-o',
`${vobjectLowercase}`,
'-h',
`${host}`,
'--csv',
]
const response = executedCommand.success ? ok : internalServerError
let message = ''
if (executedCommand.data) {
message = consoleParseToJSON(
consoleParseToString(executedCommand.data, regexExclude),
/^IMID,.*/gi
)
}
rtn = httpResponse(response, message)
if (vobjectLowercase === resources.IMAGES && datastore) {
const newParameters = ['-d', datastore]
paramsCommand = [...paramsCommand, ...newParameters]
}
res.locals.httpCode = rtn
const executedCommand = executeCommand(
defaultCommandVcenter,
paramsCommand,
prependCommand
)
const response = executedCommand.success ? ok : internalServerError
let message = ''
if (executedCommand.data) {
message = consoleParseToJSON(
consoleParseToString(executedCommand.data, regexExclude),
regexHeader
)
}
res.locals.httpCode = httpResponse(response, message)
next()
}
@ -208,31 +159,28 @@ const listAll = (
* @param {object} res - http response
* @param {Function} next - express stepper
* @param {object} params - params of http request
* @param {object} userData - user of http request
*/
const cleartags = (
res = {},
next = defaultEmptyFunction,
params = {},
userData = {}
) => {
let rtn = httpBadRequest
// check params
if (params && params.id) {
const paramsCommand = ['cleartags', `${params.id}`]
const executedCommand = executeCommand(
defaultCommandVcenter,
paramsCommand,
prependCommand
)
const response = executedCommand.success ? ok : internalServerError
let message = ''
if (executedCommand.data) {
message = consoleParseToString(executedCommand.data, regexExclude)
}
rtn = httpResponse(response, message)
const cleartags = (res = {}, next = defaultEmptyFunction, params = {}) => {
const { id } = params
if (!Number.isInteger(parseInt(id))) {
res.locals.httpCode = badRequest
next()
return
}
res.locals.httpCode = rtn
const paramsCommand = ['cleartags', id]
const executedCommand = executeCommand(
defaultCommandVcenter,
paramsCommand,
prependCommand
)
const response = executedCommand.success ? ok : internalServerError
let message = ''
if (executedCommand.data) {
message = consoleParseToString(executedCommand.data, regexExclude)
}
res.locals.httpCode = httpResponse(response, message)
next()
}
@ -242,48 +190,196 @@ const cleartags = (
* @param {object} res - http response
* @param {Function} next - express stepper
* @param {object} params - params of http request
* @param {object} userData - user of http request
*/
const hosts = (
res = {},
next = defaultEmptyFunction,
params = {},
userData = {}
) => {
let rtn = httpBadRequest
// check params
if (params && params.vcenter && params.user && params.pass) {
const paramsCommand = [
'hosts',
'--vcenter',
`${params.vcenter}`.toLowerCase(),
'--vuser',
`${params.user}`,
'--vpass',
`${params.pass}`,
'--use-defaults',
]
const executedCommand = executeCommand(
defaultCommandVcenter,
paramsCommand,
prependCommand
)
const response = executedCommand.success ? ok : internalServerError
let message = ''
if (executedCommand.data) {
message = consoleParseToString(executedCommand.data, regexExclude)
}
rtn = httpResponse(response, message)
const importHost = (res = {}, next = defaultEmptyFunction, params = {}) => {
/**
* PENDING IMPORT 1 HOST
*/
const { vcenter, user, pass } = params
if (!(vcenter && user && pass)) {
res.locals.httpCode = badRequest
next()
return
}
res.locals.httpCode = rtn
const vcenterLowercase = vcenter && `${vcenter}`.toLowerCase()
const paramsCommand = [
'hosts',
'--vcenter',
vcenterLowercase,
'--vuser',
`${user}`,
'--vpass',
`${pass}`,
'--use-defaults',
]
const executedCommand = executeCommand(
defaultCommandVcenter,
paramsCommand,
prependCommand
)
const response = executedCommand.success ? ok : internalServerError
let message = ''
if (executedCommand.data) {
message = consoleParseToString(executedCommand.data, regexExclude)
}
res.locals.httpCode = httpResponse(response, message)
next()
}
/**
* Import the desired vCenter object.
*
* @param {object} res - http response
* @param {Function} next - express stepper
* @param {object} params - params of http request
* @param {object} userData - user Data
* @param {Function} oneConnection - xmlrpc function
* @param {'template'|'images'|'datastores'|'networks'} type - type resource
*/
const importVobject = (
res = {},
next = defaultEmptyFunction,
params = {},
userData = {},
oneConnection = defaultEmptyFunction,
type
) => {
const httpReturn = (httpCode) => {
res.locals.httpCode = httpCode
next()
}
!(type && validObjects.includes(type)) && httpReturn(badRequest)
const paramsForCommand = commandParams[type]
let flagsImport = []
paramsForCommand
.filter((flag) => flag.for && flag.for.includes(IMPORT))
.forEach(({ param, flag }) => {
if (params[param]) {
flagsImport = [...flagsImport, flag, params[param]]
}
})
const publisher = (line = '') => {
publish(defaultCommandVcenter, {
resource: type,
data: line,
})
}
let pendingMessages = ''
const emit = (message) => {
if (message && typeof message.toString === 'function') {
message
.toString()
.split(defaultRegexpSplitLine)
.forEach((line) => {
if (line) {
if (
(defaultRegexpStartJSON.test(line) &&
defaultRegexpEndJSON.test(line)) ||
(!defaultRegexpStartJSON.test(line) &&
!defaultRegexpEndJSON.test(line) &&
pendingMessages.length === 0)
) {
publisher(line)
} else if (
(defaultRegexpStartJSON.test(line) &&
!defaultRegexpEndJSON.test(line)) ||
(!defaultRegexpStartJSON.test(line) &&
!defaultRegexpEndJSON.test(line) &&
pendingMessages.length > 0)
) {
pendingMessages += line
} else {
publisher(pendingMessages + line)
pendingMessages = ''
}
}
})
}
}
const executeImport = (ref) => {
executeCommandAsync(
defaultCommandVcenter,
['import_defaults', ref, '-o', type, ...flagsImport],
prependCommand,
{
err: (message) => emit(message),
out: (message) => emit(message),
close: defaultEmptyFunction,
}
)
}
const { id } = params
if (id) {
id.split(',').forEach((ref) => {
executeImport(ref)
})
httpReturn(accepted)
return
}
let flagsList = []
paramsForCommand
.filter((flag) => flag.for && flag.for.includes(LIST))
.forEach(({ param, flag }) => {
if (params[param]) {
flagsList = [...flagsList, flag, params[param]]
}
})
const iterateListAll = (message) => {
if (message && typeof message.toString === 'function') {
const messageString = message.toString()
const listData = consoleParseToJSON(
consoleParseToString(messageString, regexExclude),
regexHeader
)
if (listData.length) {
listData.forEach(({ REF }) => {
if (!REF) {
return
}
executeImport(REF)
})
} else {
publisher(messageString)
}
}
}
executeCommandAsync(
defaultCommandVcenter,
['list_all', '-o', type, '--csv', ...flagsList],
prependCommand,
{
err: iterateListAll,
out: iterateListAll,
close: defaultEmptyFunction,
}
)
httpReturn(accepted)
}
const functionRoutes = {
importVcenter,
list,
listAll,
cleartags,
hosts,
importHost,
importVobject,
}
module.exports = functionRoutes

View File

@ -16,36 +16,54 @@
const { Actions, Commands } = require('server/routes/api/vcenter/routes')
const {
importVcenter,
importVobject,
list,
listAll,
cleartags,
hosts,
importHost,
} = require('server/routes/api/vcenter/functions')
const { resources } = require('server/routes/api/vcenter/command-flags')
const { TEMPLATES, DATASTORES, NETWORKS, IMAGES } = resources
const {
VCENTER_CLEARTAGS,
VCENTER_HOSTS,
VCENTER_IMPORT,
VCENTER_LISTALL,
VCENTER_CLEAR_TAGS,
VCENTER_IMPORT_HOSTS,
VCENTER_IMPORT_DATASTORES,
VCENTER_IMPORT_TEMPLATES,
VCENTER_IMPORT_NETWORKS,
VCENTER_IMPORT_IMAGES,
VCENTER_LIST_ALL,
VCENTER_LIST,
} = Actions
module.exports = [
{
...Commands[VCENTER_CLEARTAGS],
...Commands[VCENTER_CLEAR_TAGS],
action: cleartags,
},
{
...Commands[VCENTER_HOSTS],
action: hosts,
...Commands[VCENTER_IMPORT_HOSTS],
action: importHost,
},
{
...Commands[VCENTER_IMPORT],
action: importVcenter,
...Commands[VCENTER_IMPORT_DATASTORES],
action: (...args) => importVobject(...args, DATASTORES),
},
{
...Commands[VCENTER_LISTALL],
...Commands[VCENTER_IMPORT_NETWORKS],
action: (...args) => importVobject(...args, NETWORKS),
},
{
...Commands[VCENTER_IMPORT_IMAGES],
action: (...args) => importVobject(...args, IMAGES),
},
{
...Commands[VCENTER_IMPORT_TEMPLATES],
action: (...args) => importVobject(...args, TEMPLATES),
},
{
...Commands[VCENTER_LIST_ALL],
action: listAll,
},
{

View File

@ -18,29 +18,34 @@ const {
httpMethod,
from: fromData,
} = require('server/utils/constants/defaults')
const VCENTER = require('server/routes/api/vcenter/basepath')
const basepath = `/${VCENTER}`
const basepath = '/vcenter'
const { POST, GET } = httpMethod
const { resource, postBody, query } = fromData
const VCENTER_CLEARTAGS = 'vcenter.cleartags'
const VCENTER_HOSTS = 'vcenter.hosts'
const VCENTER_IMPORT = 'vcenter.import'
const VCENTER_LISTALL = 'vcenter.listall'
const VCENTER_CLEAR_TAGS = 'vcenter.cleartags'
const VCENTER_IMPORT_HOSTS = 'vcenter.importhosts'
const VCENTER_IMPORT_DATASTORES = 'vcenter.importdatastores'
const VCENTER_IMPORT_TEMPLATES = 'vcenter.importtemplates'
const VCENTER_IMPORT_NETWORKS = 'vcenter.importnetworks'
const VCENTER_IMPORT_IMAGES = 'vcenter.importimages'
const VCENTER_LIST_ALL = 'vcenter.listall'
const VCENTER_LIST = 'vcenter.list'
const Actions = {
VCENTER_CLEARTAGS,
VCENTER_HOSTS,
VCENTER_IMPORT,
VCENTER_LISTALL,
VCENTER_CLEAR_TAGS,
VCENTER_IMPORT_HOSTS,
VCENTER_IMPORT_TEMPLATES,
VCENTER_IMPORT_DATASTORES,
VCENTER_IMPORT_NETWORKS,
VCENTER_IMPORT_IMAGES,
VCENTER_LIST_ALL,
VCENTER_LIST,
}
module.exports = {
Actions,
Commands: {
[VCENTER_CLEARTAGS]: {
[VCENTER_CLEAR_TAGS]: {
path: `${basepath}/cleartags/:id`,
httpMethod: POST,
auth: true,
@ -50,31 +55,79 @@ module.exports = {
},
},
},
[VCENTER_HOSTS]: {
path: `${basepath}/hosts`,
[VCENTER_IMPORT_HOSTS]: {
path: `${basepath}/hosts/:id?`,
httpMethod: POST,
auth: true,
params: {
id: {
from: resource,
},
vcenter: {
from: postBody,
name: 'vcenter',
},
user: {
from: postBody,
name: 'user',
},
pass: {
from: postBody,
name: 'pass',
},
},
},
[VCENTER_IMPORT]: {
path: `${basepath}/:vobject`,
[VCENTER_IMPORT_DATASTORES]: {
path: `${basepath}/datastores/:id?`,
httpMethod: POST,
auth: true,
params: {
vobject: {
id: {
from: resource,
},
host: {
from: postBody,
},
},
},
[VCENTER_IMPORT_TEMPLATES]: {
path: `${basepath}/templates/:id?`,
httpMethod: POST,
auth: true,
params: {
id: {
from: resource,
},
datastore: {
from: postBody,
},
host: {
from: postBody,
},
folder: {
from: postBody,
},
linked_clone: {
from: postBody,
},
},
},
[VCENTER_IMPORT_NETWORKS]: {
path: `${basepath}/networks/:id?`,
httpMethod: POST,
auth: true,
params: {
id: {
from: resource,
},
host: {
from: postBody,
},
},
},
[VCENTER_IMPORT_IMAGES]: {
path: `${basepath}/images/:id?`,
httpMethod: POST,
auth: true,
params: {
id: {
from: resource,
},
host: {
@ -83,16 +136,10 @@ module.exports = {
datastore: {
from: postBody,
},
id: {
from: postBody,
},
answers: {
from: postBody,
},
},
},
[VCENTER_LISTALL]: {
path: `${basepath}/listall/:vobject`,
[VCENTER_LIST_ALL]: {
path: `${basepath}/listall/:vobject/:host`,
httpMethod: GET,
auth: true,
params: {
@ -100,7 +147,7 @@ module.exports = {
from: resource,
},
host: {
from: query,
from: resource,
},
datastore: {
from: query,
@ -108,7 +155,7 @@ module.exports = {
},
},
[VCENTER_LIST]: {
path: `${basepath}/:vobject`,
path: `${basepath}/:vobject/:host`,
httpMethod: GET,
auth: true,
params: {
@ -116,7 +163,7 @@ module.exports = {
from: resource,
},
host: {
from: query,
from: resource,
},
datastore: {
from: query,

View File

@ -13,9 +13,6 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
const { resolve } = require('path')
const { env } = require('process')
const Worker = require('tiny-worker')
const upcast = require('upcast')
const {
defaults,
@ -30,15 +27,15 @@ const {
} = require('server/routes/entrypoints/Api/middlawares')
const { fillResourceforHookConnection } = require('server/utils/opennebula')
const { httpResponse, validateHttpMethod } = require('server/utils/server')
const { useWorker, parseReturnWorker } = require('server/utils/worker')
const { writeInLogger } = require('server/utils/logger')
const {
defaultWebpackMode,
defaultEmptyFunction,
defaultMessageInvalidZone,
from: fromData,
} = defaults
const { internalServerError, ok, notFound } = httpCodes
const { internalServerError } = httpCodes
const { resource: fromResource, query, postBody } = fromData
/**
@ -63,14 +60,7 @@ const executeWorker = ({
res,
}) => {
if (user && password && rpc && command && paramsCommand) {
let workerPath = [__dirname]
if (env && env.NODE_ENV === defaultWebpackMode) {
workerPath = ['src', 'server', 'utils']
} else {
require('server/utils/index.worker')
}
const worker = new Worker(resolve(...workerPath, 'index.worker.js'))
const worker = useWorker()
worker.onmessage = function (result) {
worker.terminate()
const err = result && result.data && result.data.err
@ -78,34 +68,21 @@ const executeWorker = ({
writeInLogger([command, JSON.stringify(value)], 'worker: %s : %s')
if (!err) {
fillResourceforHookConnection(user, command, paramsCommand)
switch (typeof value) {
case 'string':
try {
res.locals.httpCode = httpResponse(ok, JSON.parse(value))
} catch (error) {
res.locals.httpCode = httpResponse(notFound, value)
}
break
case 'object':
res.locals.httpCode = httpResponse(ok, value)
break
case 'number':
res.locals.httpCode = httpResponse(ok, value)
break
default:
break
}
res.locals.httpCode = parseReturnWorker(value)
}
next()
}
worker.postMessage({
globalState: (global && global.paths) || {},
user,
password,
rpc,
command,
paramsCommand,
type: 'xmlrpc',
config: {
globalState: (global && global.paths) || {},
user,
password,
rpc,
command,
paramsCommand,
},
})
}
}

View File

@ -104,7 +104,4 @@ const guacamole = (appServer) => {
}
}
module.exports = {
endpointGuacamole,
guacamole,
}
module.exports = guacamole

View File

@ -78,6 +78,4 @@ const main = (app = {}, type = '') => {
}
}
module.exports = {
main,
}
module.exports = main

View File

@ -51,10 +51,10 @@ const websockets = (appServer = {}) => {
}).listen(appServer)
try {
// eslint-disable-next-line global-require
const fileInfo = require(`./${filename}`)
if (fileInfo.main && typeof fileInfo.main === 'function') {
const file = require(`./${filename}`)
if (typeof file === 'function') {
sockets.push(io)
fileInfo.main(io, filename)
file(io, filename)
}
} catch (error) {
if (error instanceof Error) {
@ -72,6 +72,4 @@ const websockets = (appServer = {}) => {
return sockets
}
module.exports = {
websockets,
}
module.exports = websockets

View File

@ -14,4 +14,46 @@
* limitations under the License. *
* ------------------------------------------------------------------------- */
module.exports = 'vcenter'
const {
middlewareValidateAuthWebsocket,
subscriber,
} = require('server/utils/server')
const { messageTerminal } = require('server/utils/general')
const { defaults } = require('server/utils/constants')
const { defaultCommandProvision } = defaults
/**
* Object http error.
*
* @param {object} error - error message
* @returns {object} param of terminalMessage function
*/
const configErrorProvision = (error = '') => ({
color: 'red',
error,
message: '%s',
})
/**
* Route of websocket Provisions.
*
* @param {object} app - express app
* @param {string} type - type WS
*/
const main = (app = {}, type = '') => {
try {
app.use(middlewareValidateAuthWebsocket).on('connection', (server = {}) => {
server.on('disconnect', () => {
messageTerminal(configErrorProvision('disconnect'))
})
subscriber(defaultCommandProvision, (data) => {
app.emit(type, data)
})
})
} catch (error) {
messageTerminal(configErrorProvision(error))
}
}
module.exports = main

View File

@ -14,9 +14,14 @@
* limitations under the License. *
* ------------------------------------------------------------------------- */
const { middlewareValidateAuthWebsocket } = require('server/utils/server')
const {
middlewareValidateAuthWebsocket,
subscriber,
} = require('server/utils/server')
const { messageTerminal } = require('server/utils/general')
const { subscriber } = require('server/routes/api/oneprovision/utils')
const { defaults } = require('server/utils/constants')
const { defaultCommandVcenter } = defaults
/**
* Object http error.
@ -42,7 +47,7 @@ const main = (app = {}, type = '') => {
server.on('disconnect', () => {
messageTerminal(configErrorProvision('disconnect'))
})
subscriber('oneprovision', (data) => {
subscriber(defaultCommandVcenter, (data) => {
app.emit(type, data)
})
})
@ -51,6 +56,4 @@ const main = (app = {}, type = '') => {
}
}
module.exports = {
main,
}
module.exports = main

View File

@ -86,6 +86,4 @@ const vmrc = (appServer) => {
}
}
module.exports = {
vmrc,
}
module.exports = vmrc

View File

@ -52,6 +52,9 @@ const defaults = {
defaultSessionExpiration: 180,
defaultSessionLimitExpiration: 30,
defaultRememberSessionExpiration: 43200,
defaultRegexpStartJSON: /^{/,
defaultRegexpEndJSON: /}$/,
defaultRegexpSplitLine: /\r|\n/,
defaultAppName: appName,
defaultConfigErrorMessage: {
color: 'red',
@ -62,10 +65,14 @@ const defaults = {
path: `${baseUrl}${baseUrlWebsockets}hooks`,
methods: ['GET', 'POST'],
},
provision: {
[appNameProvision]: {
path: `${baseUrl}${baseUrlWebsockets}${appNameProvision}`,
methods: ['GET', 'POST'],
},
vcenter: {
path: `${baseUrl}${baseUrlWebsockets}vcenter`,
methods: ['GET', 'POST'],
},
},
defaultApps: apps,
httpMethod: {
@ -102,8 +109,8 @@ const defaults = {
parseAttributeValue: true,
trimValues: true,
},
defaultCommandProvision: 'oneprovision',
defaultCommandProvisionTemplate: 'oneprovision-template',
defaultCommandProvision: `one${appNameProvision}`,
defaultCommandProvisionTemplate: `one${appNameProvision}-template`,
defaultCommandProvider: 'oneprovider',
defaultCommandVcenter: 'onevcenter',
defaultCommandVM: 'onevm',

View File

@ -18,16 +18,27 @@ const { opennebulaConnect } = require('../../../src/server/utils/opennebula')
// eslint-disable-next-line no-undef
onmessage = function (ev = {}) {
const { data } = ev
let pass = true
const returnData = (data = '') => {
/**
* Return data worker.
*
* @param {any} rtnData - data for worker
*/
const returnDataWorker = (rtnData = '') => {
if (pass) {
// eslint-disable-next-line no-undef
postMessage(data)
postMessage(rtnData)
}
}
if (ev && ev.data) {
/**
* Function when the worker is XMLRPC.
*
* @param {object} config - config XMLRPC
*/
const xmlrpc = (config = {}) => {
const {
globalState = {},
user = '',
@ -35,16 +46,21 @@ onmessage = function (ev = {}) {
rpc = '',
command = '',
paramsCommand = [],
} = ev.data
} = config
if (globalState && user && password && rpc && command) {
pass = false
global.paths = globalState
const connect = opennebulaConnect(user, password, rpc)
connect(command, paramsCommand, (err, value) => {
pass = true
returnData({ err, value })
returnDataWorker({ err, value })
})
}
}
returnData()
if (data) {
const { type = '', config = '' } = data
type === 'xmlrpc' && xmlrpc(config)
}
returnDataWorker()
}

View File

@ -441,32 +441,30 @@ const generateNewResourceTemplate = (
* @returns {string} new console string
*/
const consoleParseToString = (stringConsole = '', excludeRegexs = []) => {
const rtn = []
if (stringConsole) {
const lines = stringConsole.split(regexLine)
lines.forEach((line) => {
let pass = true
if (Array.isArray(excludeRegexs)) {
excludeRegexs.forEach((rex) => {
if (rex.test(line)) {
pass = false
}
})
}
const cleanLine = line
.replace(regexRemoveBlanks, ' ')
.replace(regexANSIColor, '')
.trim()
if (cleanLine && pass) {
rtn.push(cleanLine)
}
})
if (!stringConsole) {
return
}
const rtn = []
stringConsole.split(regexLine).forEach((line) => {
let pass = true
if (Array.isArray(excludeRegexs)) {
excludeRegexs.forEach((rex) => {
if (rex.test(line)) {
pass = false
}
})
}
const cleanLine = line
.replace(regexRemoveBlanks, ' ')
.replace(regexANSIColor, '')
.trim()
if (cleanLine && pass) {
rtn.push(cleanLine)
}
})
return rtn
}
@ -475,32 +473,35 @@ const consoleParseToString = (stringConsole = '', excludeRegexs = []) => {
*
* @param {Array} arrayConsole - result of consoleParseToString function
* @param {string} regexHeader - regex for find header
* @returns {string} new console string
* @returns {any[]} console string JSON parsed
*/
const consoleParseToJSON = (arrayConsole = [], regexHeader = '') => {
let rtn = []
const rtn = []
if (
regexHeader &&
Array.isArray(arrayConsole) &&
arrayConsole[0] &&
regexHeader.test(arrayConsole[0])
!(
regexHeader &&
Array.isArray(arrayConsole) &&
arrayConsole[0] &&
regexHeader.test(arrayConsole[0])
)
) {
const header = arrayConsole[0].split(',')
arrayConsole.forEach((row = '', i = 0) => {
if (row && i > 0) {
const explodeRow = CSVtoArray(row)
rtn.push(
explodeRow.map((value, index) => ({
[header[index]]: stringWrappedBrakets.test(value)
? CSVtoArray(value.replace(brakets, ''))
: value,
}))
)
}
})
} else {
rtn = arrayConsole
return rtn
}
const header = arrayConsole[0].split(',')
arrayConsole.forEach((row = '', i = 0) => {
if (row && i > 0) {
const explodeRow = CSVtoArray(row)
if (Array.isArray(explodeRow)) {
const newLine = {}
explodeRow.forEach((value, index) => {
newLine[header[index]] = stringWrappedBrakets.test(value)
? CSVtoArray(value.replace(brakets, ''))
: value
})
rtn.push(newLine)
}
}
})
return rtn
}

View File

@ -35,11 +35,14 @@ const {
statSync,
removeSync,
} = require('fs-extra')
const { spawnSync, spawn } = require('child_process')
const events = require('events')
const { defaults, httpCodes } = require('server/utils/constants')
const { messageTerminal } = require('server/utils/general')
const { validateAuth } = require('server/utils/jwt')
const { writeInLogger } = require('server/utils/logger')
const { spawnSync, spawn } = require('child_process')
const eventsEmitter = new events.EventEmitter()
const {
httpMethod,
defaultApps,
@ -162,18 +165,15 @@ const getQueryData = (server = {}) => {
* Validate Authentication for websocket.
*
* @param {object} server - express app
* @returns {boolean} if token is valid
* @returns {undefined|boolean} if token is valid
*/
const validateAuthWebsocket = (server = {}) => {
let rtn
const { token } = getQueryData(server)
if (token) {
rtn = validateAuth({
return validateAuth({
headers: { authorization: token },
})
}
return rtn
}
/**
@ -387,7 +387,14 @@ const genFireedgeKey = () => {
createFile(
global.paths.FIREEDGE_KEY_PATH,
uuidv4.replace(/-/g, ''),
() => undefined,
() => {
writeInLogger(`file ${global.paths.FIREEDGE_KEY_PATH} created`)
messageTerminal({
color: 'green',
message: 'File %s created',
error: global.paths.FIREEDGE_KEY_PATH,
})
},
(err) => {
const errorData = (err && err.message) || ''
writeInLogger(errorData)
@ -885,6 +892,37 @@ const executeCommandAsync = (
}
}
/**
* Create a event emiter.
*
* @param {string} eventName - name event
* @param {object} message - object message
*/
const publish = (eventName = '', message = {}) => {
if (eventName && message) {
eventsEmitter.emit(eventName, message)
}
}
/**
* Subscriber to event emitter.
*
* @param {string} eventName - event name
* @param {Function} callback - function executed when event is emited
*/
const subscriber = (eventName = '', callback = () => undefined) => {
if (
eventName &&
callback &&
typeof callback === 'function' &&
eventsEmitter.listenerCount(eventName) < 1
) {
eventsEmitter.on(eventName, (message) => {
callback(message)
})
}
}
module.exports = {
encrypt,
decrypt,
@ -915,4 +953,6 @@ module.exports = {
checkValidApp,
removeFile,
validateHttpMethod,
publish,
subscriber,
}

View File

@ -0,0 +1,74 @@
/* ------------------------------------------------------------------------- *
* Copyright 2002-2021, OpenNebula Project, OpenNebula Systems *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may *
* not use this file except in compliance with the License. You may obtain *
* a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
const Worker = require('tiny-worker')
const { env } = require('process')
const { resolve } = require('path')
const { httpResponse } = require('server/utils/server')
const { defaults, httpCodes } = require('server/utils/constants')
const { internalServerError, ok, notFound } = httpCodes
const { defaultWebpackMode } = defaults
/**
* Use Tiny worker.
*
* @returns {object} - Worker
*/
const useWorker = () => {
let workerPath = [__dirname]
if (env && env.NODE_ENV === defaultWebpackMode) {
workerPath = ['src', 'server', 'utils']
} else {
require('server/utils/index.worker')
}
return new Worker(resolve(...workerPath, 'index.worker.js'))
}
/**
* Parse Return http worker.
*
* @param {any} value - data from worker.
* @returns {object} http response
*/
const parseReturnWorker = (value) => {
let rtn = httpResponse(internalServerError)
switch (typeof value) {
case 'string':
try {
rtn = httpResponse(ok, JSON.parse(value))
} catch (error) {
rtn = httpResponse(notFound, value)
}
break
case 'object':
rtn = httpResponse(ok, value)
break
case 'number':
rtn = httpResponse(ok, value)
break
default:
break
}
return rtn
}
module.exports = {
useWorker,
parseReturnWorker,
}