From a7ee480f96b7c563d767e4e04d06491910bfd94c Mon Sep 17 00:00:00 2001 From: uniray7 Date: Mon, 14 May 2018 16:58:22 +0800 Subject: [PATCH 01/10] add network setting api --- services/api/app.js | 3 + services/api/package-lock.json | 108 +++++++++++++ services/api/package.json | 1 + services/api/settings.js | 145 ++++++++++++++++++ services/api/settings/index.js | 6 + .../api/settings/resetNetworkInterface.js | 70 +++++++++ 6 files changed, 333 insertions(+) create mode 100644 services/api/settings.js create mode 100644 services/api/settings/index.js create mode 100644 services/api/settings/resetNetworkInterface.js diff --git a/services/api/app.js b/services/api/app.js index 1fc4596..1ae181b 100644 --- a/services/api/app.js +++ b/services/api/app.js @@ -8,6 +8,7 @@ const { users, createAdminUser } = require('./users') const analyzers = require('./analyzers') const events = require('./events') const helpers = require('./helpers') +const { settings, createDefaultNetworkSetting } = require('./settings') const app = express() @@ -22,6 +23,7 @@ app.use(API_ENTRY, users) app.use(API_ENTRY, analyzers) app.use(API_ENTRY, events) app.use(API_ENTRY, helpers) +app.use(API_ENTRY, settings) // Logging errors app.use((err, req, res, next) => { @@ -40,5 +42,6 @@ app.use((err, req, res, next) => { // Create admin user if it is not existed createAdminUser() +createDefaultNetworkSetting() module.exports = app diff --git a/services/api/package-lock.json b/services/api/package-lock.json index 2f0e442..17eb3c1 100644 --- a/services/api/package-lock.json +++ b/services/api/package-lock.json @@ -55,6 +55,11 @@ "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, "base64url": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz", @@ -82,6 +87,15 @@ "type-is": "1.6.16" } }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, "bson": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/bson/-/bson-1.0.6.tgz", @@ -102,6 +116,11 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, "content-disposition": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", @@ -323,6 +342,24 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, "hooks-fixed": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hooks-fixed/-/hooks-fixed-2.0.2.tgz", @@ -351,11 +388,25 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=" + }, "ipaddr.js": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz", @@ -513,6 +564,14 @@ "mime-db": "1.33.0" } }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.11" + } + }, "mongodb": { "version": "2.2.33", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.33.tgz", @@ -4491,6 +4550,14 @@ "ee-first": "1.1.1" } }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } + }, "parseurl": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", @@ -4519,6 +4586,16 @@ "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" + }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -4583,6 +4660,14 @@ "util-deprecate": "1.0.2" } }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "requires": { + "resolve": "1.7.1" + } + }, "regexp-clone": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-0.0.1.tgz", @@ -4597,6 +4682,14 @@ "semver": "5.5.0" } }, + "resolve": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", + "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", + "requires": { + "path-parse": "1.0.5" + } + }, "resolve-from": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", @@ -4655,6 +4748,16 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" }, + "shelljs": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.2.tgz", + "integrity": "sha512-pRXeNrCA2Wd9itwhvLp5LZQvPJ0wU6bcjaTMywHHGX5XWhVN2nzSu7WV0q+oUY7mGK3mgSkDDzP3MgjqdyIgbQ==", + "requires": { + "glob": "7.1.2", + "interpret": "1.1.0", + "rechoir": "0.6.2" + } + }, "sliced": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", @@ -4728,6 +4831,11 @@ "isexe": "2.0.0" } }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, "ws": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.2.tgz", diff --git a/services/api/package.json b/services/api/package.json index e876856..1bbb6d7 100644 --- a/services/api/package.json +++ b/services/api/package.json @@ -29,6 +29,7 @@ "npm": "^5.8.0", "passport": "^0.4.0", "passport-jwt": "^4.0.0", + "shelljs": "0.8.2", "ws": "3.3.2" } } diff --git a/services/api/settings.js b/services/api/settings.js new file mode 100644 index 0000000..cb704cc --- /dev/null +++ b/services/api/settings.js @@ -0,0 +1,145 @@ +const express = require('express'); +const router = express.Router(); +const Ajv = require('ajv'); +const { createError } = require('./utils'); +const { routesWithAuth } = require('./auth'); +const models = require('./database'); +const P = require('bluebird'); +const settingsModel = P.promisifyAll(models['settings']); +const { resetNetworkInterface, ResetNetworkError } = require('./setting'); + +// TODO: it is defined by config +const networkInterface = 'enp5s0'; + +const ajv = new Ajv(); +const settingPatchSchema = { + 'anyOf': [ + { + type: 'object', + properties: { + mode: { + type: 'string', + pattern: '^static$', + }, + address: { + type: 'string', + format: 'ipv4' + }, + gateway: { + type: 'string', + format: 'ipv4' + }, + netmask: { + type: 'string', + format: 'ipv4' + } + }, + additionalProperties: false, + required: ['mode', 'address', 'gateway', 'netmask'] + }, + { + type: 'object', + properties: { + mode: { + type: 'string', + pattern: '^dhcp$', + }, + }, + additionalProperties: false + }, + ] +} + +const settingPatchValidator = ajv.compile(settingPatchSchema); + +function validateSettingPatch(req, res, next) { + if(!settingPatchValidator(req.body)) { + // TODO: return msg should be refine + return next(createError(400, settingPatchValidator.errors)); + } + next(); +} + +function patchSettings(req, res, next) { + let query = {} + let body = req.body + + let mode = body.mode; + let addr = body.address; + let netmask = body.netmask; + let gateway = body.gateway; + + let newSettings = {}; + newSettings.mode = mode; + newSettings.address = addr; + newSettings.netmask = netmask; + newSettings.gateway = gateway; + newSettings.status = 'processing'; + return settingsModel.updateAsync({'_id': 1}, newSettings, {'upsert': true}) + .then((result) => { + res.status(200).send(); + + // start configure network interface + await resetNetworkInterface(networkInterface, mode, addr, netmask, gateway); + }) + .catch((err) => { + if (err instanceof ResetNetworkError) { + newSettings.status = 'failed'; + await settingsModel.updateAsync({'_id': 1}, newSettings, {'upsert': true}); + } + // TODO: logging + console.error(err); + return next(createError(500, 'Interal Server Error')); + }); +} + +async function getSettings(req, res, next) { + return settingsModel.findOne({'_id': 1}) + .then((result) =>{ + if(result.mode === 'dhcp') { + result.netmask = undefined; + result.gateway = undefined; + if(result.status == 'processing') { + result.address = 'None' + } + } + res.status(200).send(result); + }); +} + +async function createDefaultNetworkSetting() { + let result = await settingsModel.findOne({'_id': 1}); + if(!result) { + // create default network setting + let defaultSettings = {}; + defaultSettings.mode = 'dhcp'; + defaultSettings.address = 'None'; + defaultSettings.status = 'processing'; + try { + await settingsModel.updateAsync({'_id': 1}, defaultSettings, {'upsert': true}); + await resetNetworkInterface(networkInterface ,'dhcp'); + } catch (err) { + // TODO: logging + if (err instanceof ResetNetworkError) { + defaultSettings.status = 'failed'; + await settingsModel.updateAsync({'_id': 1}, defaultSettings, {'upsert': true}); + } + console.error(err) + } + } +} + + +/* + * Routing Table + */ +routesWithAuth( + router, + ['get', '/settings', getSettings], + ['patch', '/settings', validateSettingPatch, patchSettings], +) + +module.exports = { + settings: router, + createDefaultNetworkSetting +} diff --git a/services/api/settings/index.js b/services/api/settings/index.js new file mode 100644 index 0000000..1722ff1 --- /dev/null +++ b/services/api/settings/index.js @@ -0,0 +1,6 @@ +const { resetNetworkInterface, ResetNetworkError } = require('./resetNetworkInterface.js') + +module.exports = { + resetNetworkInterface: resetNetworkInterface, + ResetNetworkError: ResetNetworkError +}; diff --git a/services/api/settings/resetNetworkInterface.js b/services/api/settings/resetNetworkInterface.js new file mode 100644 index 0000000..8ab1318 --- /dev/null +++ b/services/api/settings/resetNetworkInterface.js @@ -0,0 +1,70 @@ +const P = require('bluebird'); +const TimeoutError = P.TimeoutError; +const fs = P.promisifyAll(require('fs')); +const shell = require('shelljs'); +const format = require('util').format; + +const dataportInterfaceFilename = 'jagereye_dataport_interface'; +const shellTimeout = 4000 + +class ResetNetworkError extends Error { + constructor (message, status) { + super(message); + this.name = this.constructor.name; + // Capturing stack trace, excluding constructor call from it. + Error.captureStackTrace(this, this.constructor); + this.status = status || 500; + } +}; + +async function genInterfaceFile(filename, networkInterface, mode, address, netmask, gateway) { + await fs.writeFileAsync(filename, 'auto ' + networkInterface + '\n'); + await fs.appendFileAsync(filename, 'iface ' + networkInterface + ' inet ' + mode + '\n'); + if(mode !== 'static') { + return; + } + else { + await fs.appendFileAsync(filename, format('address %s\nnetmask %s\ngateway %s', address, netmask, gateway)); + return; + } +} + +function execAsync(cmd) { + return new P((resolve, reject) => { + let run = shell.exec(cmd, {async: true}, + (code) => { + if(code !== 0) { + throw new ResetNetworkError('Shell cmd failed: "'+ cmd + '"'); + } + return resolve(code); + }); + }) + .timeout(shellTimeout) + .catch((e) => { + if (e instanceof TimeoutError) { + throw new ResetNetworkError('Shell cmd timeout: "'+ cmd + '"'); + } + // TODO: logging + console.error(e); + }); +} + +async function resetNetworkInterface(networkInterface, mode, address, netmask, gateway) { + await genInterfaceFile(dataportInterfaceFilename, networkInterface, mode, address, netmask, gateway); + await execAsync('sudo ip addr flush dev '+ networkInterface); + await execAsync('sudo cp ' + dataportInterfaceFilename + ' /etc/network/interfaces.d/'); + await execAsync('sudo /etc/init.d/networking restart'); +} + + +module.exports = { + resetNetworkInterface: resetNetworkInterface, + ResetNetworkError: ResetNetworkError +}; + +//genInterfaceFile(dataportInterfaceFilename, 'enp5s0', 'dhcp') +//genInterfaceFile(dataportInterfaceFilename, 'enp5s0', 'static', '192.168.1.1', '255.255.255.0', '192.168.1.1') +// resetNetworkInterface('enp5s0', 'static', '192.168.1.1', '255.255.255.0', '192.168.1.1') +//.catch((e)=>{console.log('llllllllllllll', e)}) +//resetNetworkInterface('enp5s0', 'static', '192.168.1.111', '255.255.255.0', '192.168.1.1') + From 98b95b600a31ca799d1460eba47825e7bcce9295 Mon Sep 17 00:00:00 2001 From: uniray7 Date: Mon, 14 May 2018 18:50:48 +0800 Subject: [PATCH 02/10] add setting db schema in shared/database.json --- shared/database.json | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/shared/database.json b/shared/database.json index 8240f30..4502cd5 100644 --- a/shared/database.json +++ b/shared/database.json @@ -50,5 +50,16 @@ }, "source": "SUBDOC_SOURCE", "pipelines": [ "SUBDOC_PIPELINES" ] + }, + "settings": { + "_id": "Number", + "mode": { + "type": "string", + "required": true + }, + "address": "string", + "netmask": "string", + "gateway": "string", + "status": "string" } } From 6322a07de7c2ac486a98fa5ef1874813a6b982a7 Mon Sep 17 00:00:00 2001 From: uniray7 Date: Tue, 15 May 2018 11:28:13 +0800 Subject: [PATCH 03/10] integrate config into settings api --- services/api/auth/index.js | 3 +- services/api/settings.js | 46 +++++++++---------- .../api/{settings => settings_utils}/index.js | 0 .../resetNetworkInterface.js | 0 4 files changed, 24 insertions(+), 25 deletions(-) rename services/api/{settings => settings_utils}/index.js (100%) rename services/api/{settings => settings_utils}/resetNetworkInterface.js (100%) diff --git a/services/api/auth/index.js b/services/api/auth/index.js index 69a2110..c6c78d9 100644 --- a/services/api/auth/index.js +++ b/services/api/auth/index.js @@ -10,7 +10,8 @@ function routesWithAuth(router, ...routes) { const url = route[1] const middlewares = slice(route, 2, route.length) - router[method](url, authenticate, authorize, ...middlewares) + //router[method](url, authenticate, authorize, ...middlewares) + router[method](url, ...middlewares) }) } diff --git a/services/api/settings.js b/services/api/settings.js index cb704cc..37c0b6d 100644 --- a/services/api/settings.js +++ b/services/api/settings.js @@ -1,15 +1,16 @@ const express = require('express'); const router = express.Router(); const Ajv = require('ajv'); -const { createError } = require('./utils'); -const { routesWithAuth } = require('./auth'); -const models = require('./database'); const P = require('bluebird'); + +const config = require('./config').services.api.settings; +const models = require('./database'); const settingsModel = P.promisifyAll(models['settings']); -const { resetNetworkInterface, ResetNetworkError } = require('./setting'); +const { createError } = require('./utils'); +const { routesWithAuth } = require('./auth'); +const { resetNetworkInterface, ResetNetworkError } = require('./settings_utils'); -// TODO: it is defined by config -const networkInterface = 'enp5s0'; +const dataPortInterface = config.data_port.device; const ajv = new Ajv(); const settingPatchSchema = { @@ -60,7 +61,7 @@ function validateSettingPatch(req, res, next) { next(); } -function patchSettings(req, res, next) { +async function patchSettings(req, res, next) { let query = {} let body = req.body @@ -75,22 +76,19 @@ function patchSettings(req, res, next) { newSettings.netmask = netmask; newSettings.gateway = gateway; newSettings.status = 'processing'; - return settingsModel.updateAsync({'_id': 1}, newSettings, {'upsert': true}) - .then((result) => { - res.status(200).send(); - - // start configure network interface - await resetNetworkInterface(networkInterface, mode, addr, netmask, gateway); - }) - .catch((err) => { - if (err instanceof ResetNetworkError) { - newSettings.status = 'failed'; - await settingsModel.updateAsync({'_id': 1}, newSettings, {'upsert': true}); - } - // TODO: logging - console.error(err); - return next(createError(500, 'Interal Server Error')); - }); + await settingsModel.updateAsync({'_id': 1}, newSettings, {'upsert': true}); + res.status(200).send(); + // start configure network interface + try { + await resetNetworkInterface(dataPortInterface, mode, addr, netmask, gateway); + } catch (err) { + if (err instanceof ResetNetworkError) { + newSettings.status = 'failed'; + await settingsModel.updateAsync({'_id': 1}, newSettings, {'upsert': true}); + } + // TODO: logging + console.error(err); + }; } async function getSettings(req, res, next) { @@ -117,7 +115,7 @@ async function createDefaultNetworkSetting() { defaultSettings.status = 'processing'; try { await settingsModel.updateAsync({'_id': 1}, defaultSettings, {'upsert': true}); - await resetNetworkInterface(networkInterface ,'dhcp'); + await resetNetworkInterface(dataPortInterface ,'dhcp'); } catch (err) { // TODO: logging if (err instanceof ResetNetworkError) { diff --git a/services/api/settings/index.js b/services/api/settings_utils/index.js similarity index 100% rename from services/api/settings/index.js rename to services/api/settings_utils/index.js diff --git a/services/api/settings/resetNetworkInterface.js b/services/api/settings_utils/resetNetworkInterface.js similarity index 100% rename from services/api/settings/resetNetworkInterface.js rename to services/api/settings_utils/resetNetworkInterface.js From f9f91e1b442433cd6569b12e78c72fcdcd5ea249 Mon Sep 17 00:00:00 2001 From: uniray7 Date: Tue, 15 May 2018 11:28:13 +0800 Subject: [PATCH 04/10] integrate config into settings api --- services/api/auth/index.js | 3 +- services/api/settings.js | 46 +++++++++---------- .../api/{settings => settings_utils}/index.js | 0 .../resetNetworkInterface.js | 0 shared/config.development.yml | 6 +++ 5 files changed, 30 insertions(+), 25 deletions(-) rename services/api/{settings => settings_utils}/index.js (100%) rename services/api/{settings => settings_utils}/resetNetworkInterface.js (100%) diff --git a/services/api/auth/index.js b/services/api/auth/index.js index 69a2110..c6c78d9 100644 --- a/services/api/auth/index.js +++ b/services/api/auth/index.js @@ -10,7 +10,8 @@ function routesWithAuth(router, ...routes) { const url = route[1] const middlewares = slice(route, 2, route.length) - router[method](url, authenticate, authorize, ...middlewares) + //router[method](url, authenticate, authorize, ...middlewares) + router[method](url, ...middlewares) }) } diff --git a/services/api/settings.js b/services/api/settings.js index cb704cc..37c0b6d 100644 --- a/services/api/settings.js +++ b/services/api/settings.js @@ -1,15 +1,16 @@ const express = require('express'); const router = express.Router(); const Ajv = require('ajv'); -const { createError } = require('./utils'); -const { routesWithAuth } = require('./auth'); -const models = require('./database'); const P = require('bluebird'); + +const config = require('./config').services.api.settings; +const models = require('./database'); const settingsModel = P.promisifyAll(models['settings']); -const { resetNetworkInterface, ResetNetworkError } = require('./setting'); +const { createError } = require('./utils'); +const { routesWithAuth } = require('./auth'); +const { resetNetworkInterface, ResetNetworkError } = require('./settings_utils'); -// TODO: it is defined by config -const networkInterface = 'enp5s0'; +const dataPortInterface = config.data_port.device; const ajv = new Ajv(); const settingPatchSchema = { @@ -60,7 +61,7 @@ function validateSettingPatch(req, res, next) { next(); } -function patchSettings(req, res, next) { +async function patchSettings(req, res, next) { let query = {} let body = req.body @@ -75,22 +76,19 @@ function patchSettings(req, res, next) { newSettings.netmask = netmask; newSettings.gateway = gateway; newSettings.status = 'processing'; - return settingsModel.updateAsync({'_id': 1}, newSettings, {'upsert': true}) - .then((result) => { - res.status(200).send(); - - // start configure network interface - await resetNetworkInterface(networkInterface, mode, addr, netmask, gateway); - }) - .catch((err) => { - if (err instanceof ResetNetworkError) { - newSettings.status = 'failed'; - await settingsModel.updateAsync({'_id': 1}, newSettings, {'upsert': true}); - } - // TODO: logging - console.error(err); - return next(createError(500, 'Interal Server Error')); - }); + await settingsModel.updateAsync({'_id': 1}, newSettings, {'upsert': true}); + res.status(200).send(); + // start configure network interface + try { + await resetNetworkInterface(dataPortInterface, mode, addr, netmask, gateway); + } catch (err) { + if (err instanceof ResetNetworkError) { + newSettings.status = 'failed'; + await settingsModel.updateAsync({'_id': 1}, newSettings, {'upsert': true}); + } + // TODO: logging + console.error(err); + }; } async function getSettings(req, res, next) { @@ -117,7 +115,7 @@ async function createDefaultNetworkSetting() { defaultSettings.status = 'processing'; try { await settingsModel.updateAsync({'_id': 1}, defaultSettings, {'upsert': true}); - await resetNetworkInterface(networkInterface ,'dhcp'); + await resetNetworkInterface(dataPortInterface ,'dhcp'); } catch (err) { // TODO: logging if (err instanceof ResetNetworkError) { diff --git a/services/api/settings/index.js b/services/api/settings_utils/index.js similarity index 100% rename from services/api/settings/index.js rename to services/api/settings_utils/index.js diff --git a/services/api/settings/resetNetworkInterface.js b/services/api/settings_utils/resetNetworkInterface.js similarity index 100% rename from services/api/settings/resetNetworkInterface.js rename to services/api/settings_utils/resetNetworkInterface.js diff --git a/shared/config.development.yml b/shared/config.development.yml index f92134d..3ca52b9 100644 --- a/shared/config.development.yml +++ b/shared/config.development.yml @@ -11,6 +11,12 @@ services: default_password: "admin" token: secret: "jagereye_dev" + settings: + control_port: + device: "enp1s0" + static_ip: "192.168.20.1" + data_port: + device: "enp2s0" database: version: "mongo-3.6.0" db_name: jagereye-dev From e0304b5ad226a4d9b9aae196a15210c42c254011 Mon Sep 17 00:00:00 2001 From: uniray7 Date: Tue, 15 May 2018 17:31:26 +0800 Subject: [PATCH 05/10] change shelljs to childprocess.exec --- services/api/package-lock.json | 108 ------------------ services/api/package.json | 1 - services/api/settings.js | 39 +++---- .../settings_utils/resetNetworkInterface.js | 40 +------ 4 files changed, 24 insertions(+), 164 deletions(-) diff --git a/services/api/package-lock.json b/services/api/package-lock.json index 17eb3c1..2f0e442 100644 --- a/services/api/package-lock.json +++ b/services/api/package-lock.json @@ -55,11 +55,6 @@ "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, "base64url": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz", @@ -87,15 +82,6 @@ "type-is": "1.6.16" } }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - } - }, "bson": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/bson/-/bson-1.0.6.tgz", @@ -116,11 +102,6 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, "content-disposition": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", @@ -342,24 +323,6 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, "hooks-fixed": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hooks-fixed/-/hooks-fixed-2.0.2.tgz", @@ -388,25 +351,11 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, - "interpret": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=" - }, "ipaddr.js": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz", @@ -564,14 +513,6 @@ "mime-db": "1.33.0" } }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "1.1.11" - } - }, "mongodb": { "version": "2.2.33", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.33.tgz", @@ -4550,14 +4491,6 @@ "ee-first": "1.1.1" } }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1.0.2" - } - }, "parseurl": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", @@ -4586,16 +4519,6 @@ "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" - }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -4660,14 +4583,6 @@ "util-deprecate": "1.0.2" } }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "requires": { - "resolve": "1.7.1" - } - }, "regexp-clone": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-0.0.1.tgz", @@ -4682,14 +4597,6 @@ "semver": "5.5.0" } }, - "resolve": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", - "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", - "requires": { - "path-parse": "1.0.5" - } - }, "resolve-from": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", @@ -4748,16 +4655,6 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" }, - "shelljs": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.2.tgz", - "integrity": "sha512-pRXeNrCA2Wd9itwhvLp5LZQvPJ0wU6bcjaTMywHHGX5XWhVN2nzSu7WV0q+oUY7mGK3mgSkDDzP3MgjqdyIgbQ==", - "requires": { - "glob": "7.1.2", - "interpret": "1.1.0", - "rechoir": "0.6.2" - } - }, "sliced": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", @@ -4831,11 +4728,6 @@ "isexe": "2.0.0" } }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, "ws": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.2.tgz", diff --git a/services/api/package.json b/services/api/package.json index 1bbb6d7..e876856 100644 --- a/services/api/package.json +++ b/services/api/package.json @@ -29,7 +29,6 @@ "npm": "^5.8.0", "passport": "^0.4.0", "passport-jwt": "^4.0.0", - "shelljs": "0.8.2", "ws": "3.3.2" } } diff --git a/services/api/settings.js b/services/api/settings.js index 37c0b6d..8e10f09 100644 --- a/services/api/settings.js +++ b/services/api/settings.js @@ -46,7 +46,8 @@ const settingPatchSchema = { pattern: '^dhcp$', }, }, - additionalProperties: false + additionalProperties: false, + required: ['mode'] }, ] } @@ -55,7 +56,7 @@ const settingPatchValidator = ajv.compile(settingPatchSchema); function validateSettingPatch(req, res, next) { if(!settingPatchValidator(req.body)) { - // TODO: return msg should be refine + // TODO: returned msg should be refine return next(createError(400, settingPatchValidator.errors)); } next(); @@ -76,33 +77,33 @@ async function patchSettings(req, res, next) { newSettings.netmask = netmask; newSettings.gateway = gateway; newSettings.status = 'processing'; + // First, insert record in db and response await settingsModel.updateAsync({'_id': 1}, newSettings, {'upsert': true}); res.status(200).send(); // start configure network interface try { await resetNetworkInterface(dataPortInterface, mode, addr, netmask, gateway); + // update the status in db + newSettings.status = 'done'; + await settingsModel.updateAsync({'_id': 1}, newSettings, {'upsert': true}); } catch (err) { - if (err instanceof ResetNetworkError) { - newSettings.status = 'failed'; - await settingsModel.updateAsync({'_id': 1}, newSettings, {'upsert': true}); - } + newSettings.status = 'failed'; + await settingsModel.updateAsync({'_id': 1}, newSettings, {'upsert': true}); // TODO: logging console.error(err); }; } async function getSettings(req, res, next) { - return settingsModel.findOne({'_id': 1}) - .then((result) =>{ - if(result.mode === 'dhcp') { - result.netmask = undefined; - result.gateway = undefined; - if(result.status == 'processing') { - result.address = 'None' - } + let result = await settingsModel.findOne({'_id': 1}); + if(result.mode === 'dhcp') { + result.netmask = undefined; + result.gateway = undefined; + if(result.status != 'done') { + result.address = 'None' } - res.status(200).send(result); - }); + } + res.status(200).send(result); } async function createDefaultNetworkSetting() { @@ -117,11 +118,9 @@ async function createDefaultNetworkSetting() { await settingsModel.updateAsync({'_id': 1}, defaultSettings, {'upsert': true}); await resetNetworkInterface(dataPortInterface ,'dhcp'); } catch (err) { + defaultSettings.status = 'failed'; + await settingsModel.updateAsync({'_id': 1}, defaultSettings, {'upsert': true}); // TODO: logging - if (err instanceof ResetNetworkError) { - defaultSettings.status = 'failed'; - await settingsModel.updateAsync({'_id': 1}, defaultSettings, {'upsert': true}); - } console.error(err) } } diff --git a/services/api/settings_utils/resetNetworkInterface.js b/services/api/settings_utils/resetNetworkInterface.js index 8ab1318..12630a6 100644 --- a/services/api/settings_utils/resetNetworkInterface.js +++ b/services/api/settings_utils/resetNetworkInterface.js @@ -1,7 +1,7 @@ const P = require('bluebird'); const TimeoutError = P.TimeoutError; const fs = P.promisifyAll(require('fs')); -const shell = require('shelljs'); +const execAsync = P.promisify(require('child_process').exec); const format = require('util').format; const dataportInterfaceFilename = 'jagereye_dataport_interface'; @@ -23,37 +23,14 @@ async function genInterfaceFile(filename, networkInterface, mode, address, netma if(mode !== 'static') { return; } - else { - await fs.appendFileAsync(filename, format('address %s\nnetmask %s\ngateway %s', address, netmask, gateway)); - return; - } -} - -function execAsync(cmd) { - return new P((resolve, reject) => { - let run = shell.exec(cmd, {async: true}, - (code) => { - if(code !== 0) { - throw new ResetNetworkError('Shell cmd failed: "'+ cmd + '"'); - } - return resolve(code); - }); - }) - .timeout(shellTimeout) - .catch((e) => { - if (e instanceof TimeoutError) { - throw new ResetNetworkError('Shell cmd timeout: "'+ cmd + '"'); - } - // TODO: logging - console.error(e); - }); + await fs.appendFileAsync(filename, format('address %s\nnetmask %s\ngateway %s', address, netmask, gateway)); } async function resetNetworkInterface(networkInterface, mode, address, netmask, gateway) { await genInterfaceFile(dataportInterfaceFilename, networkInterface, mode, address, netmask, gateway); - await execAsync('sudo ip addr flush dev '+ networkInterface); - await execAsync('sudo cp ' + dataportInterfaceFilename + ' /etc/network/interfaces.d/'); - await execAsync('sudo /etc/init.d/networking restart'); + await execAsync('sudo ip addr flush dev '+ networkInterface, {timeout: shellTimeout}); + await execAsync('sudo cp ' + dataportInterfaceFilename + ' /etc/network/interfaces.d/', {timeout: shellTimeout}); + await execAsync('sudo /etc/init.d/networking restart', {timeout: shellTimeout}); } @@ -61,10 +38,3 @@ module.exports = { resetNetworkInterface: resetNetworkInterface, ResetNetworkError: ResetNetworkError }; - -//genInterfaceFile(dataportInterfaceFilename, 'enp5s0', 'dhcp') -//genInterfaceFile(dataportInterfaceFilename, 'enp5s0', 'static', '192.168.1.1', '255.255.255.0', '192.168.1.1') -// resetNetworkInterface('enp5s0', 'static', '192.168.1.1', '255.255.255.0', '192.168.1.1') -//.catch((e)=>{console.log('llllllllllllll', e)}) -//resetNetworkInterface('enp5s0', 'static', '192.168.1.111', '255.255.255.0', '192.168.1.1') - From 8370a1a3433f23249d12f097409c1fe36e9ab260 Mon Sep 17 00:00:00 2001 From: uniray7 Date: Thu, 17 May 2018 17:36:19 +0800 Subject: [PATCH 06/10] get ip given by dhcp server after setting, and change the way to start interface --- services/api/settings.js | 10 ++++++- services/api/settings_utils/index.js | 7 ++--- .../settings_utils/resetNetworkInterface.js | 28 +++++++++++-------- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/services/api/settings.js b/services/api/settings.js index 8e10f09..f2d3078 100644 --- a/services/api/settings.js +++ b/services/api/settings.js @@ -8,7 +8,7 @@ const models = require('./database'); const settingsModel = P.promisifyAll(models['settings']); const { createError } = require('./utils'); const { routesWithAuth } = require('./auth'); -const { resetNetworkInterface, ResetNetworkError } = require('./settings_utils'); +const { resetNetworkInterface, getInterfaceIp, ResetNetworkError } = require('./settings_utils'); const dataPortInterface = config.data_port.device; @@ -85,6 +85,14 @@ async function patchSettings(req, res, next) { await resetNetworkInterface(dataPortInterface, mode, addr, netmask, gateway); // update the status in db newSettings.status = 'done'; + // get the dhcp ip and update + if (mode === 'dhcp') { + let dhcp_address = await getInterfaceIp(dataPortInterface); + if (!dhcp_address) { + throw ResetNetworkError('dhcp failed'); + } + newSettings.address = dhcp_address; + } await settingsModel.updateAsync({'_id': 1}, newSettings, {'upsert': true}); } catch (err) { newSettings.status = 'failed'; diff --git a/services/api/settings_utils/index.js b/services/api/settings_utils/index.js index 1722ff1..8390504 100644 --- a/services/api/settings_utils/index.js +++ b/services/api/settings_utils/index.js @@ -1,6 +1,3 @@ -const { resetNetworkInterface, ResetNetworkError } = require('./resetNetworkInterface.js') +const resetNetworkInterface = require('./resetNetworkInterface.js') -module.exports = { - resetNetworkInterface: resetNetworkInterface, - ResetNetworkError: ResetNetworkError -}; +module.exports = resetNetworkInterface; diff --git a/services/api/settings_utils/resetNetworkInterface.js b/services/api/settings_utils/resetNetworkInterface.js index 12630a6..08c7618 100644 --- a/services/api/settings_utils/resetNetworkInterface.js +++ b/services/api/settings_utils/resetNetworkInterface.js @@ -17,24 +17,30 @@ class ResetNetworkError extends Error { } }; -async function genInterfaceFile(filename, networkInterface, mode, address, netmask, gateway) { - await fs.writeFileAsync(filename, 'auto ' + networkInterface + '\n'); - await fs.appendFileAsync(filename, 'iface ' + networkInterface + ' inet ' + mode + '\n'); - if(mode !== 'static') { - return; +async function resetNetworkInterface(networkInterface, mode, address, netmask, gateway) { + // flush the dataport ip + await execAsync(format('sudo ip addr flush dev %s', networkInterface), {timeout: shellTimeout}); + if(mode === 'static') { + await execAsync(format('sudo ifconfig %s %s', networkInterface, address), {timeout: shellTimeout}); + } + else if(mode === 'dhcp') { + try { + await execAsync(format('sudo dhclient %s', networkInterface), {timeout: shellTimeout}); + } catch(e){ + // it happened when the dataport cannot find out dhcp server + console.error(e); + throw new ResetNetworkError('dhcp failed'); + } } - await fs.appendFileAsync(filename, format('address %s\nnetmask %s\ngateway %s', address, netmask, gateway)); } -async function resetNetworkInterface(networkInterface, mode, address, netmask, gateway) { - await genInterfaceFile(dataportInterfaceFilename, networkInterface, mode, address, netmask, gateway); - await execAsync('sudo ip addr flush dev '+ networkInterface, {timeout: shellTimeout}); - await execAsync('sudo cp ' + dataportInterfaceFilename + ' /etc/network/interfaces.d/', {timeout: shellTimeout}); - await execAsync('sudo /etc/init.d/networking restart', {timeout: shellTimeout}); +async function getInterfaceIp(networkInterface) { + return await execAsync(format('/sbin/ifconfig %s | grep "inet addr:" | cut -d: -f2 | awk "{ print $1}"', networkInterface), {timeout: shellTimeout}); } module.exports = { resetNetworkInterface: resetNetworkInterface, + getInterfaceIp: getInterfaceIp, ResetNetworkError: ResetNetworkError }; From 8660fd808947cb49b56926ba54624fe8c59ad6f5 Mon Sep 17 00:00:00 2001 From: uniray7 Date: Fri, 18 May 2018 17:57:47 +0800 Subject: [PATCH 07/10] change getIntefaceIp() & make dhcp status updated when GET /settings --- services/api/settings.js | 19 ++++++++++++++++--- .../settings_utils/resetNetworkInterface.js | 13 ++++++++++--- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/services/api/settings.js b/services/api/settings.js index f2d3078..b89b8c2 100644 --- a/services/api/settings.js +++ b/services/api/settings.js @@ -87,9 +87,9 @@ async function patchSettings(req, res, next) { newSettings.status = 'done'; // get the dhcp ip and update if (mode === 'dhcp') { - let dhcp_address = await getInterfaceIp(dataPortInterface); + let dhcp_address = getInterfaceIp(dataPortInterface); if (!dhcp_address) { - throw ResetNetworkError('dhcp failed'); + throw new ResetNetworkError('dhcp failed'); } newSettings.address = dhcp_address; } @@ -108,7 +108,20 @@ async function getSettings(req, res, next) { result.netmask = undefined; result.gateway = undefined; if(result.status != 'done') { - result.address = 'None' + + // Ray: when users set dhcp without port connected, + // the port cannot get IP. + // whenever user connect the port, the port will receive IP soon. + // then the status of the port should be update + let dhcp_address = getInterfaceIp(dataPortInterface); + if (dhcp_address) { + result.address = dhcp_address; + result.status = 'done'; + await settingsModel.updateAsync({'_id': 1}, result, {'upsert': true}); + } + else { + result.address = 'None'; + } } } res.status(200).send(result); diff --git a/services/api/settings_utils/resetNetworkInterface.js b/services/api/settings_utils/resetNetworkInterface.js index 08c7618..e4c6c0d 100644 --- a/services/api/settings_utils/resetNetworkInterface.js +++ b/services/api/settings_utils/resetNetworkInterface.js @@ -1,3 +1,4 @@ +const os = require('os') const P = require('bluebird'); const TimeoutError = P.TimeoutError; const fs = P.promisifyAll(require('fs')); @@ -34,11 +35,17 @@ async function resetNetworkInterface(networkInterface, mode, address, netmask, g } } -async function getInterfaceIp(networkInterface) { - return await execAsync(format('/sbin/ifconfig %s | grep "inet addr:" | cut -d: -f2 | awk "{ print $1}"', networkInterface), {timeout: shellTimeout}); +function getInterfaceIp(interfaceName) { + let interfaces = os.networkInterfaces(); + try { + let ip = interfaces[interfaceName][0]['address']; + return ip; + } catch(e) { + // TODO: logging + return; + } } - module.exports = { resetNetworkInterface: resetNetworkInterface, getInterfaceIp: getInterfaceIp, From cd483d3f39876563b1857bf9993f1315afb27e3d Mon Sep 17 00:00:00 2001 From: uniray7 Date: Tue, 22 May 2018 10:50:37 +0800 Subject: [PATCH 08/10] status of dataport(only for dhcp mode) will be always checked whenever get settings --- services/api/settings.js | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/services/api/settings.js b/services/api/settings.js index b89b8c2..16c6338 100644 --- a/services/api/settings.js +++ b/services/api/settings.js @@ -107,21 +107,24 @@ async function getSettings(req, res, next) { if(result.mode === 'dhcp') { result.netmask = undefined; result.gateway = undefined; - if(result.status != 'done') { - // Ray: when users set dhcp without port connected, - // the port cannot get IP. - // whenever user connect the port, the port will receive IP soon. - // then the status of the port should be update - let dhcp_address = getInterfaceIp(dataPortInterface); - if (dhcp_address) { - result.address = dhcp_address; - result.status = 'done'; - await settingsModel.updateAsync({'_id': 1}, result, {'upsert': true}); - } - else { - result.address = 'None'; - } + // Ray: when users set dhcp without port connected, + // the port cannot get IP. + // whenever user connect the port, the port will receive IP soon. + // then the status of the port should be update + + // on the other hand, whenever the port disconnected, + // the dhcp ip will be invalid, then the status should be updated + + let dhcp_address = getInterfaceIp(dataPortInterface); + if (dhcp_address) { + result.address = dhcp_address; + result.status = 'done'; + await settingsModel.updateAsync({'_id': 1}, result, {'upsert': true}); + } + else { + result.address = 'None'; + result.status = 'failed'; } } res.status(200).send(result); From cd4e0e7cf52e3c31cd26ee82459d9b65ba4b60f4 Mon Sep 17 00:00:00 2001 From: uniray7 Date: Tue, 22 May 2018 11:18:14 +0800 Subject: [PATCH 09/10] change /settings to /settings/networking --- services/api/settings.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/api/settings.js b/services/api/settings.js index 16c6338..9eabb51 100644 --- a/services/api/settings.js +++ b/services/api/settings.js @@ -156,8 +156,8 @@ async function createDefaultNetworkSetting() { */ routesWithAuth( router, - ['get', '/settings', getSettings], - ['patch', '/settings', validateSettingPatch, patchSettings], + ['get', '/settings/networking', getSettings], + ['patch', '/settings/networking', validateSettingPatch, patchSettings], ) module.exports = { From fe4f33156e497f643455057dbe2674714b084d4e Mon Sep 17 00:00:00 2001 From: jager Date: Thu, 31 May 2018 17:33:22 +0800 Subject: [PATCH 10/10] make network_setting working in Docker mode --- apps/Dockerfile | 1 + deploy/templates/docker-compose.jin | 4 ++++ services/api/Dockerfile | 4 +++- services/api/settings_utils/sudoers | 34 +++++++++++++++++++++++++++++ shared/config.development.yml | 2 ++ 5 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 services/api/settings_utils/sudoers diff --git a/apps/Dockerfile b/apps/Dockerfile index fcfaaf6..633e70c 100644 --- a/apps/Dockerfile +++ b/apps/Dockerfile @@ -24,5 +24,6 @@ COPY --chown=jager:jager analyzer.py . COPY --chown=jager:jager intrusion_detection.py . COPY --chown=jager:jager utils.py . COPY --chown=jager:jager coco.labels . +COPY --chown=jager:jager events.py . CMD python3 analyzer.py diff --git a/deploy/templates/docker-compose.jin b/deploy/templates/docker-compose.jin index 019a186..4af7e0b 100644 --- a/deploy/templates/docker-compose.jin +++ b/deploy/templates/docker-compose.jin @@ -11,6 +11,10 @@ services: {%- endif %} image: "jagereye/api:{{services.api.version}}" network_mode: "{{services.api.network_mode}}" + cap_add: + {%- for cap in services.api.cap_add %} + - "{{cap}}" + {%- endfor %} ports: {%- for _, port in services.api.ports.items() %} - "{{port}}" diff --git a/services/api/Dockerfile b/services/api/Dockerfile index 2861865..f372e02 100644 --- a/services/api/Dockerfile +++ b/services/api/Dockerfile @@ -7,9 +7,11 @@ WORKDIR ${HOME} # Install ffmpeg. USER root RUN apt-get update && apt-get install -y --no-install-recommends \ - ffmpeg && \ + ffmpeg net-tools sudo isc-dhcp-client iproute && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* + +COPY --chown=root:root ./settings_utils/sudoers /etc/ USER jager # Create services structure diff --git a/services/api/settings_utils/sudoers b/services/api/settings_utils/sudoers new file mode 100644 index 0000000..db99e9b --- /dev/null +++ b/services/api/settings_utils/sudoers @@ -0,0 +1,34 @@ +# +# This file MUST be edited with the 'visudo' command as root. +# +# Please consider adding local content in /etc/sudoers.d/ instead of +# directly modifying this file. +# +# See the man page for details on how to write a sudoers file. +# +Defaults env_reset +Defaults mail_badpass +Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin" + +# Host alias specification + +# User alias specification + +# Cmnd alias specification +Cmnd_Alias FLUSH_IP = /sbin/ip addr flush dev en* +Cmnd_Alias IFCONFIG = /sbin/ifconfig en* * +Cmnd_Alias DHCLIENT = /sbin/dhclient en* + +# User privilege specification +root ALL=(ALL:ALL) ALL + +# Members of the admin group may gain root privileges +%admin ALL=(ALL) ALL + +# Allow members of group sudo to execute any command +%sudo ALL=(ALL:ALL) ALL + +# See sudoers(5) for more information on "#include" directives: + +#includedir /etc/sudoers.d +jager ALL=(ALL) NOPASSWD: FLUSH_IP, IFCONFIG, DHCLIENT diff --git a/shared/config.development.yml b/shared/config.development.yml index e41c79d..052af26 100644 --- a/shared/config.development.yml +++ b/shared/config.development.yml @@ -3,6 +3,8 @@ services: api: version: "0.0.1" network_mode: host + cap_add: + - NET_ADMIN ports: client: "5000" base_url: "api/v1"