mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-23 22:50:09 +03:00
F#3951: oneflow fireedge (#130)
* get and delete oneflow fireedge * POST oneflow fireedge * schemas oneflow fireedge * http code accepted * fix login with 2FA * fix oneflow connection with 2fa * separate service and service_template * add dev mode front * fix package json Signed-off-by: Jorge Lobo <jlobo@opennebula.io>
This commit is contained in:
parent
d5e3ba08bc
commit
b4aa12c441
@ -1,6 +1,6 @@
|
||||
# Sunstone React
|
||||
# Fire Edge
|
||||
|
||||
New Sunstone incarnation in React.
|
||||
Fire Edge server and client
|
||||
|
||||
## Build & Run
|
||||
|
||||
@ -18,7 +18,7 @@ New Sunstone incarnation in React.
|
||||
REST Interface. Usually Returns OpenNebula resource info. Login returns a JSON Web Token (`JWT`).
|
||||
|
||||
- Login: POST: `http://localhost:3000/api/auth` with params: `user` and `pass`.
|
||||
- Other: check file `src/config/command-params.js`
|
||||
- Other: check file `src/config/command-params.js`. if requires it to be in a specific zone you must put it at the end but before the query /feredation=ZONE_ID (replace ZONE_ID for the zone id)
|
||||
|
||||
- **zeroMQ**
|
||||
Websocket connection call to: `ws://127.0.0.1:3000/?token=JWT`
|
||||
@ -32,25 +32,4 @@ for this error run `sudo sysctl fs.inotify.max_user_watches=582222 && sudo sysct
|
||||
for this error run `killall -9 node` and start app again
|
||||
|
||||
## Project description
|
||||
|
||||
- `disk`: this folder content the transpiled code.
|
||||
- `disk/public`: content the transpiled code valid for the HTML.
|
||||
- `node_modules`: dependencies for backend (NODE).
|
||||
- `src`: non-transpiled code.
|
||||
- `src/config`: configuration files (please do not modify if you do not know how it works).
|
||||
- `src/config/command-params.js`: it contains the different commands with the possible opennebula parameters.
|
||||
- `src/config/defaults.js`: it contains default string parameters.
|
||||
- `src/config/function-routes.js`: it contains routes that are not opennebula commands.
|
||||
- `src/config/http-codes.js`: it contains all http codes for routes.
|
||||
- `src/config/params.js`: it contains the parameters used by the paths, example: `http://localhost:3000/api/template/id=0/action=info`.
|
||||
- `src/config/routes-api.js`: gather the different routes used by the API.
|
||||
- `src/public`: contains the sunstone in react.
|
||||
- `src/routes`: contains the routes for node (API and WEB).
|
||||
- `src/utils`: utilities used by the application.
|
||||
- `src/index.js`: entrypoint node.
|
||||
- `config.yml`: enviroment config for user
|
||||
- `.eslintignore`: files ignored by the eslint
|
||||
- `copyStaticAssets.js`: copy the html resourses to dist/public path (.ico, .css, fonts, etc).
|
||||
- `packaje.json`: contains the name of the packages used by the application.
|
||||
- `webpack.config.js`: contains the JS transpiler configurations.
|
||||
- `yarn.lock`: contains the dependencies using the yarn command.
|
||||
...
|
||||
|
@ -16,6 +16,12 @@ MODE: production
|
||||
# JWT user password encryption key (AUTH)
|
||||
TOKEN_SECRET: token_secreto
|
||||
|
||||
# Flow Server
|
||||
# ONE_FLOW_SERVER:
|
||||
# PROTOCOL: 'https'
|
||||
# HOST: '0.0.0.0'
|
||||
# POST: 2474
|
||||
|
||||
# JWT life time
|
||||
LIMIT_TOKEN:
|
||||
MIN: 14
|
||||
|
@ -5,10 +5,11 @@
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"build": "webpack --mode=production && concurrently \"npm run copy_static_assets\" \"npm run build:css\"",
|
||||
"build-node": "webpack --mode=production --env=node",
|
||||
"build-front": "webpack --mode=production --env=front && concurrently \"npm run copy_static_assets\" \"npm run build:css\"",
|
||||
"build-node": "webpack --mode=production --env=node",
|
||||
"build-front": "webpack --mode=production --env=front && concurrently \"npm run copy_static_assets\" \"npm run build:css\"",
|
||||
"build:css": "node-sass src/public/scss/main.scss dist/public/app.css --output-style compressed",
|
||||
"dev": "webpack --mode=development && npm run copy_static_assets && concurrently \"webpack --watch\" \"npm run build:css\" \"nodemon --inspect dist\"",
|
||||
"dev:front": "webpack --mode=development --env=front && npm run copy_static_assets && concurrently \"webpack --watch\" \"npm run build:css\" \"nodemon --inspect dist\"",
|
||||
"start": "node dist/index",
|
||||
"cypress:open": "cypress open",
|
||||
"cypress:run": "cypress run --headless --browser chrome --spec \"cypress/integration/**/*.spec.js\"",
|
||||
@ -31,8 +32,8 @@
|
||||
"ace-builds": "^1.4.11",
|
||||
"atob": "^2.1.2",
|
||||
"axios": "^0.19.2",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"body-parser": "^1.19.0",
|
||||
"btoa": "^1.2.1",
|
||||
"classnames": "^2.2.6",
|
||||
"colors": "^1.4.0",
|
||||
"compression": "^1.7.4",
|
||||
@ -43,6 +44,7 @@
|
||||
"helmet": "^3.23.3",
|
||||
"http": "0.0.1-security",
|
||||
"immutable": "^4.0.0-rc.12",
|
||||
"jsonschema": "^1.2.6",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"jwt-simple": "^0.5.6",
|
||||
"moment": "^2.27.0",
|
||||
@ -61,11 +63,12 @@
|
||||
"redux": "^4.0.4",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"remove": "^0.1.5",
|
||||
"socket.io": "^2.3.0",
|
||||
"socket.io-client": "^2.3.0",
|
||||
"speakeasy": "^2.0.0",
|
||||
"sprintf-js": "^1.1.2",
|
||||
"upcast": "^4.0.0",
|
||||
"url": "^0.11.0",
|
||||
"websocket": "^1.0.31",
|
||||
"window-or-global": "^1.0.1",
|
||||
"xml2js": "^0.4.23",
|
||||
"xmlrpc": "^1.3.2",
|
||||
|
@ -19,6 +19,7 @@ const helmet = require('helmet');
|
||||
const express = require('express');
|
||||
const morgan = require('morgan');
|
||||
const path = require('path');
|
||||
const socketIO = require('socket.io');
|
||||
const cors = require('cors');
|
||||
const {
|
||||
existsSync,
|
||||
@ -106,8 +107,9 @@ const appServer =
|
||||
)
|
||||
: unsecureServer(app);
|
||||
|
||||
// connect to zeromq websocket
|
||||
addWsServer(appServer);
|
||||
// connect to websocket
|
||||
const io = socketIO.listen(appServer);
|
||||
addWsServer(io);
|
||||
|
||||
appServer.listen(port, () => {
|
||||
const config = {
|
||||
|
74
src/fireedge/src/public/components/router/endpoints.js
Normal file
74
src/fireedge/src/public/components/router/endpoints.js
Normal file
@ -0,0 +1,74 @@
|
||||
/* Copyright 2002-2019, 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. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
import React from 'react';
|
||||
import Login from './login';
|
||||
import Settings from '../containers/Settings';
|
||||
import TestApi from '../containers/TestApi';
|
||||
import Dashboard from '../containers/Dashboard';
|
||||
import { Clusters, Hosts, Zones } from '../containers/Infrastructure';
|
||||
|
||||
const endpoints = {
|
||||
login: {
|
||||
path: '/',
|
||||
authenticated: false,
|
||||
menu: false,
|
||||
component: Login
|
||||
},
|
||||
dashboard: {
|
||||
path: '/dashboard',
|
||||
component: () => <Dashboard />
|
||||
},
|
||||
settings: {
|
||||
path: '/settings',
|
||||
component: () => <Settings />
|
||||
},
|
||||
test_api: {
|
||||
path: '/test-api',
|
||||
component: () => <TestApi />
|
||||
},
|
||||
// infrastructure
|
||||
infrastructure: {
|
||||
clusters: {
|
||||
path: '/clusters',
|
||||
component: () => <Clusters />
|
||||
},
|
||||
hosts: {
|
||||
path: '/hosts',
|
||||
component: () => <Hosts />
|
||||
},
|
||||
zones: {
|
||||
path: '/zones',
|
||||
component: () => <Zones />
|
||||
}
|
||||
},
|
||||
// networks
|
||||
networks: {
|
||||
vnets: {
|
||||
path: '/vnets'
|
||||
},
|
||||
vnets_templates: {
|
||||
path: '/vnets-templates'
|
||||
},
|
||||
vnets_topology: {
|
||||
path: '/vnets-topology'
|
||||
},
|
||||
vnets_secgroup: {
|
||||
path: '/secgroup'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default endpoints;
|
@ -33,7 +33,7 @@ const TestApi = () => {
|
||||
fullWidth
|
||||
select
|
||||
variant="outlined"
|
||||
label={<Translate word="Select resquest" />}
|
||||
label={<Translate word="Select request" />}
|
||||
value={name}
|
||||
onChange={handleChangeCommand}
|
||||
>
|
||||
|
@ -13,6 +13,30 @@
|
||||
/* limitations under the License. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
import WSConsole from './WSConsole';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import io from 'socket.io-client';
|
||||
import { findStorageData } from '../../../utils';
|
||||
import constants from '../../../constants';
|
||||
|
||||
export default { WSConsole };
|
||||
const { jwtName } = constants;
|
||||
|
||||
const ENDPOINT = 'http://127.0.0.1:3000';
|
||||
|
||||
function Webconsole() {
|
||||
const [response, setResponse] = useState({});
|
||||
|
||||
useEffect(() => {
|
||||
const socket = io(ENDPOINT, {
|
||||
query: {
|
||||
token: findStorageData(jwtName)
|
||||
}
|
||||
});
|
||||
socket.on('zeroMQ', data => {
|
||||
setResponse(data);
|
||||
});
|
||||
}, []);
|
||||
console.log('-->', response);
|
||||
return <p />;
|
||||
}
|
||||
|
||||
export default Webconsole;
|
||||
|
@ -34,8 +34,10 @@ const { from: fromData } = require('../../../../utils/constants/defaults');
|
||||
const {
|
||||
responseOpennebula,
|
||||
checkOpennebulaCommand,
|
||||
generateNewTemplate
|
||||
generateNewTemplate,
|
||||
check2Fa
|
||||
} = require('../../../../utils/opennebula');
|
||||
const { httpResponse } = require('../../../../utils/server');
|
||||
|
||||
// user config
|
||||
const appConfig = getConfig();
|
||||
@ -101,7 +103,7 @@ const privateRoutes = {
|
||||
const { otpauth_url: otpURL, base32 } = secret;
|
||||
qrcode.toDataURL(otpURL, (err, dataURL) => {
|
||||
if (err) {
|
||||
res.locals.httpCode = Map(internalServerError).toObject();
|
||||
res.locals.httpCode = httpResponse(internalServerError);
|
||||
next();
|
||||
} else {
|
||||
const connectOpennebula = connect();
|
||||
@ -115,7 +117,9 @@ const privateRoutes = {
|
||||
emptyTemplate[default2FAOpennebulaTmpVar] = base32;
|
||||
|
||||
dataUser[fromData.resource].id = userId;
|
||||
dataUser[fromData.postBody].template = generateNewTemplate(
|
||||
dataUser[
|
||||
fromData.postBody
|
||||
].template = generateNewTemplate(
|
||||
info.USER.TEMPLATE.SUNSTONE || {},
|
||||
emptyTemplate,
|
||||
[default2FAOpennebulaVar]
|
||||
@ -134,11 +138,9 @@ const privateRoutes = {
|
||||
value,
|
||||
pass => {
|
||||
if (pass !== undefined && pass !== null) {
|
||||
const codeOK = Map(ok).toObject();
|
||||
codeOK.data = {
|
||||
res.locals.httpCode = httpResponse(ok, {
|
||||
img: dataURL
|
||||
};
|
||||
res.locals.httpCode = codeOK;
|
||||
});
|
||||
next();
|
||||
} else {
|
||||
next();
|
||||
@ -184,22 +186,17 @@ const privateRoutes = {
|
||||
const sunstone = info.USER.TEMPLATE.SUNSTONE;
|
||||
const token = req[fromData.postBody].token;
|
||||
const secret = sunstone[default2FAOpennebulaTmpVar];
|
||||
const verified = speakeasy.totp.verify({
|
||||
secret,
|
||||
encoding: 'base32',
|
||||
token
|
||||
});
|
||||
if (verified) {
|
||||
if (check2Fa(secret, token)) {
|
||||
const emptyTemplate = {};
|
||||
emptyTemplate[default2FAOpennebulaVar] = secret;
|
||||
|
||||
const dataUser = Map(req).toObject();
|
||||
dataUser[fromData.resource].id = userId;
|
||||
dataUser[fromData.postBody].template = generateNewTemplate(
|
||||
sunstone || {},
|
||||
emptyTemplate,
|
||||
[default2FAOpennebulaTmpVar]
|
||||
);
|
||||
dataUser[
|
||||
fromData.postBody
|
||||
].template = generateNewTemplate(sunstone || {}, emptyTemplate, [
|
||||
default2FAOpennebulaTmpVar
|
||||
]);
|
||||
const getOpennebulaMethodUpdate = checkOpennebulaCommand(
|
||||
defaultMethodUserUpdate,
|
||||
POST
|
||||
@ -214,8 +211,7 @@ const privateRoutes = {
|
||||
value,
|
||||
pass => {
|
||||
if (pass !== undefined && pass !== null) {
|
||||
const codeOK = Map(ok).toObject();
|
||||
res.locals.httpCode = codeOK;
|
||||
res.locals.httpCode = httpResponse(ok);
|
||||
}
|
||||
next();
|
||||
},
|
||||
@ -224,7 +220,7 @@ const privateRoutes = {
|
||||
}
|
||||
);
|
||||
} else {
|
||||
res.locals.httpCode = Map(unauthorized).toObject();
|
||||
res.locals.httpCode = httpResponse(unauthorized);
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
@ -271,8 +267,7 @@ const privateRoutes = {
|
||||
value,
|
||||
pass => {
|
||||
if (pass !== undefined && pass !== null) {
|
||||
const codeOK = Map(ok).toObject();
|
||||
res.locals.httpCode = codeOK;
|
||||
res.locals.httpCode = httpResponse(ok);
|
||||
}
|
||||
next();
|
||||
},
|
||||
|
@ -12,26 +12,30 @@
|
||||
/* See the License for the specific language governing permissions and */
|
||||
/* limitations under the License. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
const speakeasy = require('speakeasy');
|
||||
const moment = require('moment');
|
||||
const { Map } = require('immutable');
|
||||
const {
|
||||
httpMethod,
|
||||
defaultMethodLogin,
|
||||
defaultMethodZones,
|
||||
defaultMethodConfig,
|
||||
defaultMethodUserInfo,
|
||||
default2FAOpennebulaVar,
|
||||
defaultNamespace,
|
||||
from: fromData
|
||||
} = require('../../../../utils/constants/defaults');
|
||||
const { getConfig } = require('../../../../utils/yml');
|
||||
const { ok, unauthorized } = require('../../../../utils/constants/http-codes');
|
||||
const {
|
||||
ok,
|
||||
unauthorized,
|
||||
accepted
|
||||
} = require('../../../../utils/constants/http-codes');
|
||||
const { createToken } = require('../../../../utils/jwt');
|
||||
const { httpResponse } = require('../../../../utils/server');
|
||||
const {
|
||||
responseOpennebula,
|
||||
paramsDefaultByCommandOpennebula,
|
||||
checkOpennebulaCommand
|
||||
checkOpennebulaCommand,
|
||||
check2Fa
|
||||
} = require('../../../../utils/opennebula');
|
||||
|
||||
const appConfig = getConfig();
|
||||
@ -127,30 +131,31 @@ const validate2faAuthentication = informationUser => {
|
||||
informationUser.TEMPLATE.SUNSTONE &&
|
||||
informationUser.TEMPLATE.SUNSTONE[default2FAOpennebulaVar]
|
||||
) {
|
||||
if (tfatoken.length <= 0) {
|
||||
updaterResponse(httpResponse(accepted));
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
const secret = informationUser.TEMPLATE.SUNSTONE[default2FAOpennebulaVar];
|
||||
const verified = speakeasy.totp.verify({
|
||||
secret,
|
||||
encoding: 'base32',
|
||||
tfatoken
|
||||
});
|
||||
if (!verified) {
|
||||
const codeUnauthorized = Map(unauthorized).toObject();
|
||||
codeUnauthorized.data = { message: 'invalid 2fa token' };
|
||||
updaterResponse(codeUnauthorized);
|
||||
if (!check2Fa(secret, tfatoken)) {
|
||||
updaterResponse(httpResponse(unauthorized, '', 'invalid 2fa token'));
|
||||
next();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const genJWT = informationUser => {
|
||||
if (informationUser && informationUser.ID) {
|
||||
if (informationUser && informationUser.ID && informationUser.PASSWORD) {
|
||||
const { ID: id } = informationUser;
|
||||
const dataJWT = { id, user, token: opennebulaToken };
|
||||
const jwt = createToken(dataJWT, nowUnix, nowWithDays.format('X'));
|
||||
if (jwt) {
|
||||
const codeOK = Map(ok).toObject();
|
||||
codeOK.data = { token: jwt };
|
||||
updaterResponse(codeOK);
|
||||
if (!global.users) {
|
||||
global.users = {};
|
||||
}
|
||||
global.users[user] = opennebulaToken;
|
||||
updaterResponse(httpResponse(ok, { token: jwt, id: informationUser.ID }));
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -221,15 +226,13 @@ const userInfo = userData => {
|
||||
defaultMethodLogin,
|
||||
getOpennebulaMethod(dataSource),
|
||||
(err, value) => {
|
||||
// res, err, value, response, next
|
||||
responseOpennebula(
|
||||
() => undefined,
|
||||
err,
|
||||
value,
|
||||
() => {
|
||||
setZones();
|
||||
setOneConfig();
|
||||
// aca se tiene que hacer la llamada a las zonas y a system.config
|
||||
setOneConfig(); // esto debe de estar antes de hacer el JWT
|
||||
},
|
||||
next
|
||||
);
|
||||
@ -250,8 +253,7 @@ const authenticate = val => {
|
||||
const findTextError = `[${namespace + defaultMethodLogin}]`;
|
||||
if (val) {
|
||||
if (val.indexOf(findTextError) >= 0) {
|
||||
const codeUnauthorized = Map(unauthorized).toObject();
|
||||
updaterResponse(codeUnauthorized);
|
||||
updaterResponse(httpResponse(unauthorized));
|
||||
next();
|
||||
} else {
|
||||
const oneConnect = connectOpennebula();
|
||||
|
@ -19,7 +19,6 @@ const {
|
||||
defaultMethodLogin
|
||||
} = require('../../../../utils/constants/defaults');
|
||||
const {
|
||||
unauthorized,
|
||||
internalServerError
|
||||
} = require('../../../../utils/constants/http-codes');
|
||||
const { from: fromData } = require('../../../../utils/constants/defaults');
|
||||
@ -97,6 +96,7 @@ const publicRoutes = {
|
||||
const dataSourceWithExpirateDate = Map(req).toObject();
|
||||
// add expire time unix for opennebula creation token
|
||||
dataSourceWithExpirateDate[fromData.postBody].expire = relativeTime;
|
||||
dataSourceWithExpirateDate[fromData.postBody].token = '';
|
||||
oneConnect(
|
||||
defaultMethodLogin,
|
||||
getOpennebulaMethod(dataSourceWithExpirateDate),
|
||||
|
133
src/fireedge/src/routes/api/routes/oneflow/functions.js
Normal file
133
src/fireedge/src/routes/api/routes/oneflow/functions.js
Normal file
@ -0,0 +1,133 @@
|
||||
/* Copyright 2002-2019, 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 { request } = require('axios');
|
||||
const btoa = require('btoa');
|
||||
const { Map } = require('immutable');
|
||||
|
||||
const {
|
||||
defaultOneFlowServer
|
||||
} = require('../../../../utils/constants/defaults');
|
||||
const { getConfig } = require('../../../../utils/yml');
|
||||
const { httpMethod } = require('../../../../utils/constants/defaults');
|
||||
const { addPrintf } = require('../../../../utils/general');
|
||||
const { httpResponse } = require('../../../../utils/server');
|
||||
const {
|
||||
ok,
|
||||
internalServerError
|
||||
} = require('../../../../utils/constants/http-codes');
|
||||
|
||||
const { GET, DELETE } = httpMethod;
|
||||
|
||||
const appConfig = getConfig();
|
||||
const oneFlowServiceDataConection =
|
||||
appConfig.ONE_FLOW_SERVER || defaultOneFlowServer;
|
||||
|
||||
const parsePostData = (postData = {}) => {
|
||||
const rtn = {};
|
||||
Object.entries(postData).forEach(([key, value]) => {
|
||||
try {
|
||||
rtn[key] = JSON.parse(value, (k, val) => {
|
||||
try {
|
||||
return JSON.parse(val);
|
||||
} catch (error) {
|
||||
return val;
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
rtn[key] = value;
|
||||
}
|
||||
});
|
||||
return rtn;
|
||||
};
|
||||
|
||||
const returnSchemaError = (error = []) =>
|
||||
error
|
||||
.map(element => (element && element.stack ? element.stack : ''))
|
||||
.toString();
|
||||
|
||||
const conectionOneFlow = (
|
||||
res,
|
||||
next = () => undefined,
|
||||
method = GET,
|
||||
user = '',
|
||||
path = '/',
|
||||
requestData = '',
|
||||
postData = ''
|
||||
) => {
|
||||
if (res && next && method && user) {
|
||||
const options = {
|
||||
method,
|
||||
baseURL: `${oneFlowServiceDataConection.PROTOCOL}://${oneFlowServiceDataConection.HOST}:${oneFlowServiceDataConection.PORT}`,
|
||||
url: path,
|
||||
headers: {
|
||||
Authorization: `Basic ${btoa(user)}`
|
||||
},
|
||||
validateStatus: status => status
|
||||
};
|
||||
|
||||
if (requestData) {
|
||||
options.url = addPrintf(path, requestData);
|
||||
}
|
||||
|
||||
if (postData) {
|
||||
options.data = postData;
|
||||
}
|
||||
request(options)
|
||||
.then(response => {
|
||||
if (response && response.statusText) {
|
||||
if (response.status >= 200 && response.status < 400) {
|
||||
if (response.data) {
|
||||
return response.data;
|
||||
}
|
||||
if (
|
||||
response.config.method &&
|
||||
response.config.method.toUpperCase() === DELETE
|
||||
) {
|
||||
const parseToNumber = validate =>
|
||||
isNaN(parseInt(validate, 10))
|
||||
? validate
|
||||
: parseInt(validate, 10);
|
||||
return Array.isArray(requestData)
|
||||
? parseToNumber(requestData[0])
|
||||
: parseToNumber(requestData);
|
||||
}
|
||||
} else if (response.data) {
|
||||
throw Error(response.data);
|
||||
}
|
||||
}
|
||||
throw Error(response.statusText);
|
||||
})
|
||||
.then(data => {
|
||||
res.locals.httpCode = httpResponse(ok, data);
|
||||
next();
|
||||
})
|
||||
.catch(e => {
|
||||
const codeInternalServerError = Map(internalServerError).toObject();
|
||||
if (e && e.message) {
|
||||
codeInternalServerError.data = e.message;
|
||||
}
|
||||
res.locals.httpCode = httpResponse(internalServerError, e && e.message);
|
||||
next();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const functionRoutes = {
|
||||
conectionOneFlow,
|
||||
parsePostData,
|
||||
returnSchemaError
|
||||
};
|
||||
|
||||
module.exports = functionRoutes;
|
@ -12,8 +12,76 @@
|
||||
/* See the License for the specific language governing permissions and */
|
||||
/* limitations under the License. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
const {
|
||||
serviceAll,
|
||||
service,
|
||||
serviceDelete,
|
||||
serviceAddAction,
|
||||
serviceAddScale,
|
||||
serviceAddRoleAction
|
||||
} = require('./service');
|
||||
const {
|
||||
serviceTemplateAll,
|
||||
serviceTemplate,
|
||||
serviceTemplateDelete,
|
||||
serviceTemplateCreate,
|
||||
serviceTemplateUpdate,
|
||||
serviceTemplateAction
|
||||
} = require('./service_template');
|
||||
const { httpMethod } = require('../../../../utils/constants/defaults');
|
||||
|
||||
const privateRoutes = {};
|
||||
const { GET, POST, DELETE, PUT } = httpMethod;
|
||||
|
||||
const privateRoutes = {
|
||||
'service-all': {
|
||||
httpMethod: GET,
|
||||
action: serviceAll
|
||||
},
|
||||
service: {
|
||||
httpMethod: GET,
|
||||
action: service
|
||||
},
|
||||
'service-delete': {
|
||||
httpMethod: DELETE,
|
||||
action: serviceDelete
|
||||
},
|
||||
'service-add-action': {
|
||||
httpMethod: POST,
|
||||
action: serviceAddAction
|
||||
},
|
||||
'service-add-scale': {
|
||||
httpMethod: POST,
|
||||
action: serviceAddScale
|
||||
},
|
||||
'service-add-role-action': {
|
||||
httpMethod: POST,
|
||||
action: serviceAddRoleAction
|
||||
},
|
||||
'service_template-all': {
|
||||
httpMethod: GET,
|
||||
action: serviceTemplateAll
|
||||
},
|
||||
service_template: {
|
||||
httpMethod: GET,
|
||||
action: serviceTemplate
|
||||
},
|
||||
'service_template-delete': {
|
||||
httpMethod: DELETE,
|
||||
action: serviceTemplateDelete
|
||||
},
|
||||
'service_template-create': {
|
||||
httpMethod: POST,
|
||||
action: serviceTemplateCreate
|
||||
},
|
||||
'service_template-update': {
|
||||
httpMethod: PUT,
|
||||
action: serviceTemplateUpdate
|
||||
},
|
||||
'service_template-action': {
|
||||
httpMethod: POST,
|
||||
action: serviceTemplateAction
|
||||
}
|
||||
};
|
||||
|
||||
const publicRoutes = {};
|
||||
|
||||
|
218
src/fireedge/src/routes/api/routes/oneflow/schemas.js
Normal file
218
src/fireedge/src/routes/api/routes/oneflow/schemas.js
Normal file
@ -0,0 +1,218 @@
|
||||
/* Copyright 2002-2019, 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 action = {
|
||||
id: '/Action',
|
||||
type: 'object',
|
||||
properties: {
|
||||
action: {
|
||||
perform: {
|
||||
type: 'string',
|
||||
required: true
|
||||
},
|
||||
params: {
|
||||
merge_template: {
|
||||
type: 'object',
|
||||
required: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const role = {
|
||||
id: '/Role',
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string',
|
||||
required: true
|
||||
},
|
||||
cardinality: {
|
||||
type: 'integer',
|
||||
default: 1,
|
||||
minimum: 0
|
||||
},
|
||||
vm_template: {
|
||||
type: 'integer',
|
||||
required: true
|
||||
},
|
||||
vm_template_contents: {
|
||||
type: 'string',
|
||||
required: false
|
||||
},
|
||||
parents: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
shutdown_action: {
|
||||
type: 'string',
|
||||
enum: ['shutdown', 'shutdown-hard'],
|
||||
required: false
|
||||
},
|
||||
min_vms: {
|
||||
type: 'integer',
|
||||
required: false,
|
||||
minimum: 0
|
||||
},
|
||||
max_vms: {
|
||||
type: 'integer',
|
||||
required: false,
|
||||
minimum: 0
|
||||
},
|
||||
cooldown: {
|
||||
type: 'integer',
|
||||
required: false,
|
||||
minimum: 0
|
||||
},
|
||||
elasticity_policies: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
type: {
|
||||
type: 'string',
|
||||
enum: ['CHANGE', 'CARDINALITY', 'PERCENTAGE_CHANGE'],
|
||||
required: true
|
||||
},
|
||||
adjust: {
|
||||
type: 'integer',
|
||||
required: true
|
||||
},
|
||||
min_adjust_step: {
|
||||
type: 'integer',
|
||||
required: false,
|
||||
minimum: 1
|
||||
},
|
||||
period_number: {
|
||||
type: 'integer',
|
||||
required: false,
|
||||
minimum: 0
|
||||
},
|
||||
period: {
|
||||
type: 'integer',
|
||||
required: false,
|
||||
minimum: 0
|
||||
},
|
||||
expression: {
|
||||
type: 'string',
|
||||
required: true
|
||||
},
|
||||
cooldown: {
|
||||
type: 'integer',
|
||||
required: false,
|
||||
minimum: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
scheduled_policies: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
type: {
|
||||
type: 'string',
|
||||
enum: ['CHANGE', 'CARDINALITY', 'PERCENTAGE_CHANGE'],
|
||||
required: true
|
||||
},
|
||||
adjust: {
|
||||
type: 'integer',
|
||||
required: true
|
||||
},
|
||||
min_adjust_step: {
|
||||
type: 'integer',
|
||||
required: false,
|
||||
minimum: 1
|
||||
},
|
||||
start_time: {
|
||||
type: 'string',
|
||||
required: false
|
||||
},
|
||||
recurrence: {
|
||||
type: 'string',
|
||||
required: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const service = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string',
|
||||
required: true
|
||||
},
|
||||
deployment: {
|
||||
type: 'string',
|
||||
enum: ['none', 'straight'],
|
||||
default: 'none'
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
required: false
|
||||
},
|
||||
shutdown_action: {
|
||||
type: 'string',
|
||||
enum: ['terminate', 'terminate-hard', 'shutdown', 'shutdown-hard'],
|
||||
required: false
|
||||
},
|
||||
roles: {
|
||||
type: 'array',
|
||||
items: { $ref: '/Role' },
|
||||
required: true
|
||||
},
|
||||
custom_attrs: {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
required: false
|
||||
},
|
||||
custom_attrs_values: {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
required: false
|
||||
},
|
||||
networks: {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
required: false
|
||||
},
|
||||
networks_values: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {}
|
||||
},
|
||||
required: false
|
||||
},
|
||||
ready_status_gate: {
|
||||
type: 'boolean',
|
||||
required: false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const functionRoutes = {
|
||||
action,
|
||||
role,
|
||||
service
|
||||
};
|
||||
|
||||
module.exports = functionRoutes;
|
239
src/fireedge/src/routes/api/routes/oneflow/service.js
Normal file
239
src/fireedge/src/routes/api/routes/oneflow/service.js
Normal file
@ -0,0 +1,239 @@
|
||||
/* Copyright 2002-2019, 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 { Validator } = require('jsonschema');
|
||||
const { action } = require('./schemas');
|
||||
const { conectionOneFlow } = require('./functions');
|
||||
const { httpMethod } = require('../../../../utils/constants/defaults');
|
||||
const { from: fromData } = require('../../../../utils/constants/defaults');
|
||||
const { httpResponse } = require('../../../../utils/server');
|
||||
const {
|
||||
methodNotAllowed,
|
||||
internalServerError
|
||||
} = require('../../../../utils/constants/http-codes');
|
||||
const { parsePostData, returnSchemaError } = require('./functions');
|
||||
|
||||
const { GET, POST, DELETE } = httpMethod;
|
||||
|
||||
const serviceAll = (req, res, next, connect, zone, user) => {
|
||||
if (req && res && user && next) {
|
||||
conectionOneFlow(res, next, GET, user, '/service');
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
const service = (req, res, next, connect, zone, user) => {
|
||||
if (req && res && user && next) {
|
||||
if (
|
||||
req &&
|
||||
fromData &&
|
||||
fromData.resource &&
|
||||
req[fromData.resource] &&
|
||||
req[fromData.resource].method
|
||||
) {
|
||||
conectionOneFlow(
|
||||
res,
|
||||
next,
|
||||
GET,
|
||||
user,
|
||||
`/service/{0}`,
|
||||
req[fromData.resource].method
|
||||
);
|
||||
} else {
|
||||
res.locals.httpCode = httpResponse(
|
||||
methodNotAllowed,
|
||||
'',
|
||||
'invalid id service'
|
||||
);
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
const serviceDelete = (req, res, next, connect, zone, user) => {
|
||||
if (req && res && user && next) {
|
||||
if (
|
||||
req &&
|
||||
fromData &&
|
||||
fromData.resource &&
|
||||
req[fromData.resource] &&
|
||||
req[fromData.resource].method
|
||||
) {
|
||||
conectionOneFlow(res, next, DELETE, user, `/service/{0}`, [
|
||||
req[fromData.resource].method
|
||||
]);
|
||||
} else {
|
||||
res.locals.httpCode = httpResponse(
|
||||
methodNotAllowed,
|
||||
'',
|
||||
'invalid id service'
|
||||
);
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
// PROBAR oneflow-server.rb
|
||||
const serviceAddAction = (req, res, next, connect, zone, user) => {
|
||||
if (req && res && user && next) {
|
||||
if (
|
||||
req &&
|
||||
fromData &&
|
||||
fromData.resource &&
|
||||
fromData.postBody &&
|
||||
req[fromData.resource] &&
|
||||
req[fromData.postBody] &&
|
||||
req[fromData.resource].method
|
||||
) {
|
||||
const postAction = parsePostData(req[fromData.postBody]);
|
||||
const v = new Validator();
|
||||
const valSchema = v.validate(postAction, action);
|
||||
if (valSchema.valid) {
|
||||
conectionOneFlow(
|
||||
res,
|
||||
next,
|
||||
POST,
|
||||
user,
|
||||
`/service/{0}/action`,
|
||||
req[fromData.resource].method,
|
||||
postAction
|
||||
);
|
||||
} else {
|
||||
res.locals.httpCode = httpResponse(
|
||||
internalServerError,
|
||||
'',
|
||||
`invalid schema ${returnSchemaError(valSchema.errors)}`
|
||||
);
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
res.locals.httpCode = httpResponse(
|
||||
methodNotAllowed,
|
||||
'',
|
||||
'invalid action or id'
|
||||
);
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
// PROBAR
|
||||
const serviceAddScale = (req, res, next, connect, zone, user) => {
|
||||
if (req && res && user && next) {
|
||||
if (
|
||||
req &&
|
||||
fromData &&
|
||||
fromData.resource &&
|
||||
fromData.postBody &&
|
||||
req[fromData.resource] &&
|
||||
req[fromData.postBody] &&
|
||||
req[fromData.resource].method
|
||||
) {
|
||||
const postAction = parsePostData(req[fromData.postBody]);
|
||||
const v = new Validator();
|
||||
const valSchema = v.validate(postAction, action);
|
||||
if (valSchema.valid) {
|
||||
conectionOneFlow(
|
||||
res,
|
||||
next,
|
||||
POST,
|
||||
user,
|
||||
`/service/{0}/action`,
|
||||
req[fromData.resource].method,
|
||||
postAction
|
||||
);
|
||||
} else {
|
||||
res.locals.httpCode = httpResponse(
|
||||
internalServerError,
|
||||
'',
|
||||
`invalid schema ${returnSchemaError(valSchema.errors)}`
|
||||
);
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
res.locals.httpCode = httpResponse(
|
||||
methodNotAllowed,
|
||||
'',
|
||||
'invalid action or id'
|
||||
);
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
// PROBAR oneflow-server.rb
|
||||
const serviceAddRoleAction = (req, res, next, connect, zone, user) => {
|
||||
if (req && res && user && next) {
|
||||
if (
|
||||
req &&
|
||||
fromData &&
|
||||
fromData.resource &&
|
||||
fromData.postBody &&
|
||||
req[fromData.resource] &&
|
||||
req[fromData.postBody] &&
|
||||
req[fromData.resource].method &&
|
||||
req[fromData.resource].id
|
||||
) {
|
||||
const postAction = parsePostData(req[fromData.postBody]);
|
||||
const v = new Validator();
|
||||
const valSchema = v.validate(postAction, action);
|
||||
if (valSchema.valid) {
|
||||
conectionOneFlow(
|
||||
res,
|
||||
next,
|
||||
POST,
|
||||
user,
|
||||
`/service/{0}/role/{1}`,
|
||||
[req[fromData.resource].method, req[fromData.resource].id],
|
||||
postAction
|
||||
);
|
||||
} else {
|
||||
res.locals.httpCode = httpResponse(
|
||||
internalServerError,
|
||||
'',
|
||||
`invalid schema ${returnSchemaError(valSchema.errors)}`
|
||||
);
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
res.locals.httpCode = httpResponse(
|
||||
methodNotAllowed,
|
||||
'',
|
||||
'invalid action or id'
|
||||
);
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
const serviceApi = {
|
||||
serviceAll,
|
||||
service,
|
||||
serviceDelete,
|
||||
serviceAddAction,
|
||||
serviceAddScale,
|
||||
serviceAddRoleAction
|
||||
};
|
||||
module.exports = serviceApi;
|
226
src/fireedge/src/routes/api/routes/oneflow/service_template.js
Normal file
226
src/fireedge/src/routes/api/routes/oneflow/service_template.js
Normal file
@ -0,0 +1,226 @@
|
||||
/* Copyright 2002-2019, 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 { Validator } = require('jsonschema');
|
||||
const { conectionOneFlow } = require('./functions');
|
||||
const { role, service, action } = require('./schemas');
|
||||
const { httpMethod } = require('../../../../utils/constants/defaults');
|
||||
const { from: fromData } = require('../../../../utils/constants/defaults');
|
||||
const { httpResponse } = require('../../../../utils/server');
|
||||
const {
|
||||
methodNotAllowed,
|
||||
internalServerError
|
||||
} = require('../../../../utils/constants/http-codes');
|
||||
const { parsePostData, returnSchemaError } = require('./functions');
|
||||
|
||||
const { GET, POST, DELETE, PUT } = httpMethod;
|
||||
|
||||
const serviceTemplateAll = (req, res, next, connect, zone, user) => {
|
||||
if (req && res && user && next) {
|
||||
conectionOneFlow(res, next, GET, user, '/service_template');
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
const serviceTemplate = (req, res, next, connect, zone, user) => {
|
||||
if (req && res && user && next) {
|
||||
if (
|
||||
req &&
|
||||
fromData &&
|
||||
fromData.resource &&
|
||||
req[fromData.resource] &&
|
||||
req[fromData.resource].method
|
||||
) {
|
||||
conectionOneFlow(res, next, GET, user, `/service_template/{0}`, [
|
||||
req[fromData.resource].method
|
||||
]);
|
||||
} else {
|
||||
res.locals.httpCode = httpResponse(
|
||||
methodNotAllowed,
|
||||
'',
|
||||
'invalid id service template'
|
||||
);
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
const serviceTemplateDelete = (req, res, next, connect, zone, user) => {
|
||||
if (req && res && user && next) {
|
||||
if (
|
||||
req &&
|
||||
fromData &&
|
||||
fromData.resource &&
|
||||
req[fromData.resource] &&
|
||||
req[fromData.resource].method
|
||||
) {
|
||||
conectionOneFlow(res, next, DELETE, user, `/service_template/{0}`, [
|
||||
req[fromData.resource].method
|
||||
]);
|
||||
} else {
|
||||
res.locals.httpCode = httpResponse(
|
||||
methodNotAllowed,
|
||||
'',
|
||||
'invalid id service'
|
||||
);
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
const serviceTemplateCreate = (req, res, next, connect, zone, user) => {
|
||||
if (req && res && user && next) {
|
||||
if (req && fromData && fromData.postBody && req[fromData.postBody]) {
|
||||
const postService = parsePostData(req[fromData.postBody]);
|
||||
const v = new Validator();
|
||||
v.addSchema(role, '/Role');
|
||||
const valSchema = v.validate(postService, service);
|
||||
if (valSchema.valid) {
|
||||
conectionOneFlow(
|
||||
res,
|
||||
next,
|
||||
POST,
|
||||
user,
|
||||
`/service_template`,
|
||||
'',
|
||||
postService
|
||||
);
|
||||
} else {
|
||||
res.locals.httpCode = httpResponse(
|
||||
internalServerError,
|
||||
'',
|
||||
`invalid schema ${returnSchemaError(valSchema.errors)}`
|
||||
);
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
res.locals.httpCode = httpResponse(
|
||||
methodNotAllowed,
|
||||
'',
|
||||
'invalid service json'
|
||||
);
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
// PROBAR
|
||||
const serviceTemplateUpdate = (req, res, next, connect, zone, user) => {
|
||||
if (req && res && user && next) {
|
||||
if (
|
||||
req &&
|
||||
fromData &&
|
||||
fromData.postBody &&
|
||||
fromData.resource &&
|
||||
req[fromData.postBody] &&
|
||||
req[fromData.resource] &&
|
||||
req[fromData.resource].method
|
||||
) {
|
||||
const postService = parsePostData(req[fromData.postBody]);
|
||||
const v = new Validator();
|
||||
v.addSchema(role, '/Role');
|
||||
const valSchema = v.validate(postService, service);
|
||||
if (valSchema.valid) {
|
||||
conectionOneFlow(
|
||||
res,
|
||||
next,
|
||||
PUT,
|
||||
user,
|
||||
`/service_template/{0}`,
|
||||
[req[fromData.resource].method],
|
||||
postService
|
||||
);
|
||||
} else {
|
||||
res.locals.httpCode = httpResponse(
|
||||
internalServerError,
|
||||
'',
|
||||
`invalid schema ${returnSchemaError(valSchema.errors)}`
|
||||
);
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
res.locals.httpCode = httpResponse(
|
||||
methodNotAllowed,
|
||||
'',
|
||||
'invalid service json or id'
|
||||
);
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
// PROBAR oneflow-server.rb
|
||||
const serviceTemplateAction = (req, res, next, connect, zone, user) => {
|
||||
if (req && res && user && next) {
|
||||
if (
|
||||
req &&
|
||||
fromData &&
|
||||
fromData.postBody &&
|
||||
fromData.resource &&
|
||||
req[fromData.postBody] &&
|
||||
req[fromData.resource] &&
|
||||
req[fromData.resource].method
|
||||
) {
|
||||
const postAction = parsePostData(req[fromData.postBody]);
|
||||
const v = new Validator();
|
||||
const valSchema = v.validate(postAction, action);
|
||||
if (valSchema.valid) {
|
||||
conectionOneFlow(
|
||||
res,
|
||||
next,
|
||||
POST,
|
||||
user,
|
||||
`/service_template/{0}/action`,
|
||||
[req[fromData.resource].method],
|
||||
postAction
|
||||
);
|
||||
} else {
|
||||
res.locals.httpCode = httpResponse(
|
||||
internalServerError,
|
||||
'',
|
||||
`invalid schema ${returnSchemaError(valSchema.errors)}`
|
||||
);
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
res.locals.httpCode = httpResponse(
|
||||
methodNotAllowed,
|
||||
'',
|
||||
'invalid action or id'
|
||||
);
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
const serviceTemplateApi = {
|
||||
serviceTemplateAll,
|
||||
serviceTemplate,
|
||||
serviceTemplateDelete,
|
||||
serviceTemplateCreate,
|
||||
serviceTemplateUpdate,
|
||||
serviceTemplateAction
|
||||
};
|
||||
module.exports = serviceTemplateApi;
|
@ -14,16 +14,15 @@
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
const express = require('express');
|
||||
const { Map } = require('immutable');
|
||||
const { defaults, httpCodes, params } = require('../../utils/constants');
|
||||
const { getConfig } = require('../../utils/yml');
|
||||
const {
|
||||
opennebulaConnect,
|
||||
checkRouteFunction,
|
||||
commandXML,
|
||||
checkOpennebulaCommand,
|
||||
validateRouteFunction,
|
||||
responseOpennebula
|
||||
responseOpennebula,
|
||||
httpResponse
|
||||
} = require('../../utils');
|
||||
|
||||
const {
|
||||
@ -77,7 +76,7 @@ router.all(
|
||||
(req, res, next) => {
|
||||
const { internalServerError, ok, methodNotAllowed } = httpCodes;
|
||||
const { method: httpMethod } = req;
|
||||
res.locals.httpCode = Map(internalServerError).toObject();
|
||||
res.locals.httpCode = httpResponse(internalServerError);
|
||||
const zone = getDataZone();
|
||||
if (zone) {
|
||||
const { RPC } = zone;
|
||||
@ -87,7 +86,7 @@ router.all(
|
||||
) => opennebulaConnect(user, pass, RPC);
|
||||
const { resource } = req.params;
|
||||
const routeFunction = checkRouteFunction(resource);
|
||||
res.locals.httpCode = Map(methodNotAllowed).toObject();
|
||||
res.locals.httpCode = httpResponse(methodNotAllowed);
|
||||
const dataSources = {
|
||||
[fromData.resource]: getParamsState(),
|
||||
[fromData.query]: getQueriesState(),
|
||||
@ -104,7 +103,8 @@ router.all(
|
||||
res,
|
||||
next,
|
||||
connectOpennebula,
|
||||
getIdUserOpennebula()
|
||||
getIdUserOpennebula(),
|
||||
`${getUserOpennebula()}:${getPassOpennebula()}`
|
||||
);
|
||||
} else {
|
||||
next();
|
||||
@ -118,12 +118,10 @@ router.all(
|
||||
);
|
||||
const getOpennebulaMethod = checkOpennebulaCommand(command, httpMethod);
|
||||
if (getOpennebulaMethod) {
|
||||
const response = val => {
|
||||
res.locals.httpCode = Map(ok).toObject();
|
||||
res.locals.httpCode.data = val || {};
|
||||
const response = (val = {}) => {
|
||||
res.locals.httpCode = httpResponse(ok, val || val === 0 ? val : {});
|
||||
if (typeof val === 'string') {
|
||||
res.locals.httpCode.data = {};
|
||||
res.locals.httpCode.message = val;
|
||||
res.locals.httpCode = httpResponse(ok, undefined, val);
|
||||
}
|
||||
next();
|
||||
};
|
||||
@ -138,11 +136,8 @@ router.all(
|
||||
getPassOpennebula(),
|
||||
RPC
|
||||
);
|
||||
connect(
|
||||
command,
|
||||
getOpennebulaMethod(dataSources),
|
||||
(err, value) =>
|
||||
responseOpennebula(updaterResponse, err, value, response, next)
|
||||
connect(command, getOpennebulaMethod(dataSources), (err, value) =>
|
||||
responseOpennebula(updaterResponse, err, value, response, next)
|
||||
);
|
||||
} else {
|
||||
next();
|
||||
|
@ -59,8 +59,16 @@ const validateResource = (req, res, next) => {
|
||||
idUserOpennebula = session.iss;
|
||||
userOpennebula = session.aud;
|
||||
passOpennebula = session.jti;
|
||||
next();
|
||||
return;
|
||||
// deberia estar condicionado por la variable de entorno dev
|
||||
if (
|
||||
global &&
|
||||
global.users &&
|
||||
global.users[userOpennebula] &&
|
||||
global.users[userOpennebula] === passOpennebula
|
||||
) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
}
|
||||
status = unauthorized;
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ module.exports = (
|
||||
},
|
||||
group: {
|
||||
from: postBody,
|
||||
default: ''
|
||||
default: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -14,7 +14,8 @@
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
const default2FAOpennebulaVar = 'TWO_FACTOR_AUTH_SECRET';
|
||||
const defaultIp = 'http://127.0.0.1';
|
||||
const defaultIp = '127.0.0.1';
|
||||
const protocol = 'http';
|
||||
const defaults = {
|
||||
httpMethod: {
|
||||
GET: 'GET',
|
||||
@ -31,10 +32,15 @@ const defaults = {
|
||||
{
|
||||
ID: 0,
|
||||
NAME: 'OpenNebula',
|
||||
RPC: `${defaultIp}:2633/RPC2`,
|
||||
RPC: `${protocol}://${defaultIp}:2633/RPC2`,
|
||||
VNC: ''
|
||||
}
|
||||
],
|
||||
defaultOneFlowServer: {
|
||||
PROTOCOL: protocol,
|
||||
HOST: defaultIp,
|
||||
PORT: 2474
|
||||
},
|
||||
defaultConfigFile: `${__dirname}/../config.yml`,
|
||||
defaultTypeLog: 'prod',
|
||||
defaultWebpackMode: 'development',
|
||||
|
@ -34,6 +34,10 @@ const httpCodes = {
|
||||
id: 503,
|
||||
message: 'Service Unavailable'
|
||||
},
|
||||
accepted: {
|
||||
id: 202,
|
||||
message: 'Accepted'
|
||||
},
|
||||
ok: {
|
||||
id: 200,
|
||||
message: 'OK'
|
||||
|
@ -27,6 +27,18 @@ const messageTerminal = ({ color, type, error, message }) => {
|
||||
console.log(consoleColor, typeConsole, errorConsole);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
messageTerminal
|
||||
const addPrintf = (string = '', args = '') => {
|
||||
let rtn = string;
|
||||
if (string && args) {
|
||||
const replacers = Array.isArray(args) ? args : [args];
|
||||
rtn = string.replace(/{(\d+)}/g, (match, number) =>
|
||||
typeof replacers[number] !== 'undefined' ? replacers[number] : match
|
||||
);
|
||||
}
|
||||
return rtn;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
messageTerminal,
|
||||
addPrintf
|
||||
};
|
||||
|
@ -18,7 +18,8 @@ const params = require('./constants/params');
|
||||
const { defaultTypeLog } = require('./constants/defaults');
|
||||
const functionRoutes = require('../routes/api');
|
||||
const { validateAuth } = require('./jwt');
|
||||
const { messageTerminal } = require('./general');
|
||||
const { httpResponse } = require('./server');
|
||||
const { messageTerminal, addPrintf } = require('./general');
|
||||
const { addWsServer } = require('./ws-zeromq');
|
||||
const { getConfig } = require('./yml');
|
||||
|
||||
@ -125,6 +126,7 @@ module.exports = {
|
||||
includeJSbyHTML,
|
||||
includeCSSbyHTML,
|
||||
messageTerminal,
|
||||
addPrintf,
|
||||
getRouteForOpennebulaCommand,
|
||||
getMethodForOpennebulaCommand,
|
||||
commandXML,
|
||||
@ -132,5 +134,6 @@ module.exports = {
|
||||
checkOpennebulaCommand,
|
||||
validateRouteFunction,
|
||||
responseOpennebula,
|
||||
getConfig
|
||||
getConfig,
|
||||
httpResponse
|
||||
};
|
||||
|
@ -19,6 +19,7 @@ const rpc = require('xmlrpc');
|
||||
const xml2js = require('xml2js');
|
||||
const { Map } = require('immutable');
|
||||
const { sprintf } = require('sprintf-js');
|
||||
const speakeasy = require('speakeasy');
|
||||
const httpCodes = require('./constants/http-codes');
|
||||
const commandsParams = require('./constants/commands');
|
||||
const {
|
||||
@ -263,13 +264,30 @@ const generateNewTemplate = (
|
||||
wrapper = 'SUNSTONE=[%1$s]'
|
||||
) => {
|
||||
const positions = Object.entries({ ...current, ...addPositions })
|
||||
.filter(position => position && !removedPositions.includes(position))
|
||||
.filter(position => {
|
||||
let element = position;
|
||||
if (Array.isArray(position)) {
|
||||
element = position[0];
|
||||
}
|
||||
return element && !removedPositions.includes(element);
|
||||
})
|
||||
.map(([position, value]) => `${position}=${value}`)
|
||||
.join(', ');
|
||||
|
||||
return sprintf(wrapper, positions);
|
||||
};
|
||||
|
||||
const check2Fa = (secret = '', token = '') => {
|
||||
let rtn = false;
|
||||
if (secret && token) {
|
||||
rtn = speakeasy.totp.verify({
|
||||
secret,
|
||||
encoding: 'base32',
|
||||
token
|
||||
});
|
||||
}
|
||||
return rtn;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
opennebulaConnect,
|
||||
responseOpennebula,
|
||||
@ -280,5 +298,6 @@ module.exports = {
|
||||
checkPositionInDataSource,
|
||||
checkOpennebulaCommand,
|
||||
paramsDefaultByCommandOpennebula,
|
||||
generateNewTemplate
|
||||
generateNewTemplate,
|
||||
check2Fa
|
||||
};
|
||||
|
35
src/fireedge/src/utils/server.js
Normal file
35
src/fireedge/src/utils/server.js
Normal file
@ -0,0 +1,35 @@
|
||||
/* Copyright 2002-2019, 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 { Map } = require('immutable');
|
||||
const { internalServerError } = require('./constants/http-codes');
|
||||
|
||||
const httpResponse = (response, data, message) => {
|
||||
let rtn = Map(internalServerError).toObject();
|
||||
rtn.data = data;
|
||||
if (response) {
|
||||
rtn = Map(response).toObject();
|
||||
}
|
||||
if (data || data === 0) {
|
||||
rtn.data = data;
|
||||
}
|
||||
if (message) {
|
||||
rtn.message = message;
|
||||
}
|
||||
return rtn;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
httpResponse
|
||||
};
|
@ -15,14 +15,13 @@
|
||||
|
||||
const atob = require('atob');
|
||||
|
||||
const { server: Server } = require('websocket');
|
||||
const { socket } = require('zeromq');
|
||||
const { socket: socketZeroMQ } = require('zeromq');
|
||||
const xml2js = require('xml2js');
|
||||
|
||||
const { messageTerminal } = require('./general');
|
||||
const { getConfig } = require('./yml');
|
||||
const { validateAuth } = require('./jwt');
|
||||
const { unauthorized } = require('./constants/http-codes');
|
||||
// const { unauthorized } = require('./constants/http-codes');
|
||||
|
||||
// user config
|
||||
const appConfig = getConfig();
|
||||
@ -32,92 +31,74 @@ const zeromqPort = appConfig.ZEROPORT || 2101;
|
||||
const zeromqHost = appConfig.ZEROHOST || '127.0.0.1';
|
||||
|
||||
const addWsServer = appServer => {
|
||||
if (
|
||||
appServer &&
|
||||
appServer.constructor &&
|
||||
appServer.constructor.name &&
|
||||
appServer.constructor.name === 'Server'
|
||||
) {
|
||||
// create the server
|
||||
const wsServer = new Server({
|
||||
httpServer: appServer
|
||||
});
|
||||
// connect to zeromq
|
||||
const zeromqSock = socketZeroMQ('sub');
|
||||
const address = `${zeromqType}://${zeromqHost}:${zeromqPort}`;
|
||||
try {
|
||||
zeromqSock.connect(address);
|
||||
zeromqSock.subscribe('');
|
||||
|
||||
// connect to zeromq
|
||||
const zeromqSock = socket('sub');
|
||||
const address = `${zeromqType}://${zeromqHost}:${zeromqPort}`;
|
||||
|
||||
try {
|
||||
zeromqSock.connect(address);
|
||||
let clients = [];
|
||||
|
||||
wsServer.on('request', request => {
|
||||
appServer
|
||||
.use((socketServer, next) => {
|
||||
if (
|
||||
request &&
|
||||
request.resourceURL &&
|
||||
request.resourceURL.query &&
|
||||
request.resourceURL.query.token &&
|
||||
socketServer.handshake.query &&
|
||||
socketServer.handshake.query.token &&
|
||||
validateAuth({
|
||||
headers: { authorization: request.resourceURL.query.token }
|
||||
headers: { authorization: socketServer.handshake.query.token }
|
||||
})
|
||||
) {
|
||||
const clientConnection = request.accept(null, request.origin);
|
||||
clients.push(clientConnection);
|
||||
zeromqSock.subscribe('');
|
||||
zeromqSock.on('message', (...args) => {
|
||||
const mssgs = [];
|
||||
// broadcast
|
||||
clients.forEach(client => {
|
||||
Array.prototype.slice.call(args).forEach(arg => {
|
||||
mssgs.push(arg.toString());
|
||||
});
|
||||
|
||||
if (mssgs[0] && mssgs[1]) {
|
||||
xml2js.parseString(
|
||||
atob(mssgs[1]),
|
||||
{
|
||||
explicitArray: false,
|
||||
trim: true,
|
||||
normalize: true,
|
||||
includeWhiteChars: true,
|
||||
strict: false
|
||||
},
|
||||
(error, result) => {
|
||||
if (error) {
|
||||
const configErrorParser = {
|
||||
color: 'red',
|
||||
type: error,
|
||||
message: 'Error parser: %s'
|
||||
};
|
||||
messageTerminal(configErrorParser);
|
||||
return;
|
||||
}
|
||||
client.send(
|
||||
JSON.stringify({ command: mssgs[0], data: result })
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
next();
|
||||
} else {
|
||||
const { id, message } = unauthorized;
|
||||
request.reject(id, message);
|
||||
next(new Error('Authentication error'));
|
||||
}
|
||||
});
|
||||
})
|
||||
.on('connection', socketServer => {
|
||||
zeromqSock.on('message', (...args) => {
|
||||
const mssgs = [];
|
||||
Array.prototype.slice.call(args).forEach(arg => {
|
||||
mssgs.push(arg.toString());
|
||||
});
|
||||
if (mssgs[0] && mssgs[1]) {
|
||||
xml2js.parseString(
|
||||
atob(mssgs[1]),
|
||||
{
|
||||
explicitArray: false,
|
||||
trim: true,
|
||||
normalize: true,
|
||||
includeWhiteChars: true,
|
||||
strict: false
|
||||
},
|
||||
(error, result) => {
|
||||
if (error) {
|
||||
const configErrorParser = {
|
||||
color: 'red',
|
||||
type: error,
|
||||
message: 'Error parser: %s'
|
||||
};
|
||||
messageTerminal(configErrorParser);
|
||||
} else {
|
||||
socketServer.emit('zeroMQ', {
|
||||
command: mssgs[0],
|
||||
data: result
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
wsServer.on('close', request => {
|
||||
// clear connection to broadcast
|
||||
clients = clients.filter(client => client !== request);
|
||||
/* socketServer.on('disconnect', () => {
|
||||
console.log('Client disconnected');
|
||||
clearInterval(interval);
|
||||
}); */
|
||||
});
|
||||
} catch (error) {
|
||||
const configErrorZeroMQ = {
|
||||
color: 'red',
|
||||
type: error,
|
||||
message: '%s'
|
||||
};
|
||||
messageTerminal(configErrorZeroMQ);
|
||||
}
|
||||
} catch (error) {
|
||||
const configErrorZeroMQ = {
|
||||
color: 'red',
|
||||
type: error,
|
||||
message: '%s'
|
||||
};
|
||||
messageTerminal(configErrorZeroMQ);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -236,6 +236,8 @@ delete '/service/:id' do
|
||||
end
|
||||
|
||||
post '/service/:id/action' do
|
||||
#require 'pry-byebug'
|
||||
#binding.pry
|
||||
action = JSON.parse(request.body.read)['action']
|
||||
opts = action['params']
|
||||
|
||||
@ -458,6 +460,8 @@ post '/service_template' do
|
||||
s_template = OpenNebula::ServiceTemplate.new(xml, @client)
|
||||
|
||||
begin
|
||||
# require 'pry-byebug'
|
||||
# binding.pry
|
||||
rc = s_template.allocate(request.body.read)
|
||||
rescue Validator::ParseException, JSON::ParserError => e
|
||||
return internal_error(e.message, VALIDATION_EC)
|
||||
|
Loading…
x
Reference in New Issue
Block a user