/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ const http = require('http'); const { join } = require('path'); const polka = require('polka'); const sirv = require('sirv'); const { json } = require('body-parser'); const sshClient = require('ssh2').Client; const { PORT=3000 } = process.env; const files = sirv('dist', {dev: true}); const server = http.createServer(); let sshConn; const sendJSON = (res, httpCode, message) => { res.writeHead(httpCode, { 'Content-Type': 'application/json' }); return JSON.stringify(message); }; const connect = (req, res) => { if (!req.body.address.length || !req.body.username.length || !req.body.port.length || !req.body.key.length) { res.end(sendJSON(res, 500, 'Erreur : un champ requis manque.')); } sshConn = new sshClient(); try { sshConn.on('ready', () => { console.log('Client :: ready'); res.end(sendJSON(res, 200, 'OK, connecté !')); }).connect({ host: req.body.address, port: req.body.port, username: req.body.username, privateKey: req.body.key, passphrase: req.body.password }); sshConn.on('error', (err) => { console.log(err); res.end(sendJSON(res, 403, err.message)); }); } catch(err) { console.log(err); res.end(sendJSON(res, 403, err.message)); } }; const disconnect = (req, res) => { if (sshConn) sshConn.end(); res.end(sendJSON(res, 200, 'OK, déconnecté !')); }; const execCommand = (cmd, res) => { if (sshConn) { sshConn.exec(cmd, (err, stream) => { if (err) throw err; let std = ''; stream.on('close', function(code, signal) { console.log('Stream :: close :: code: ' + code + ', signal: ' + signal); res.end(sendJSON(res, 200, std)); }).on('data', function(data) { console.log('STDOUT: ' + data); std += data; }).stderr.on('data', function(data) { console.log('STDERR: ' + data); std += data; }); }); } else { res.end(sendJSON(res, 500, 'Pas de connexion SSH !')); } }; const serverCommand = (req, res) => { let execCmd = 'cd ~/docker/hosts/*/ && '; switch (req.params.cmd) { case 'webstart': execCmd += 'docker-compose start nginx'; break; case 'webstop': execCmd += 'docker-compose stop nginx'; break; case 'webrestart': execCmd += 'docker-compose restart nginx'; break; case 'odoostart': execCmd += 'docker-compose start moka'; break; case 'odoostop': execCmd += 'docker-compose stop moka'; break; case 'odoorestart': execCmd += 'docker-compose restart moka'; break; case 'dbstart': execCmd += 'docker-compose start pgmoka'; break; case 'dbstop': execCmd += 'docker-compose stop pgmoka'; break; case 'dbrestart': execCmd += 'docker-compose restart pgmoka'; break; default: execCmd = '/bin/true'; } execCommand(execCmd, res); }; const odooAction = (req, res) => { console.log(req.body); if (!req.body.databases.length) { res.end(sendJSON(res, 500, 'Erreur : pas de base de données sélectionnée.\n')); } if (!req.body.modules.length) { res.end(sendJSON(res, 500, 'Erreur : aucun module fourni.\n')); } let execCmd = 'cd ~/docker/hosts/*/ && '; // Base command let odooCmd = 'OCB/odoo-bin -c odoo.conf --no-xmlrpc --stop-after-init '; // Install or update odooCmd += (req.body.action == 'install') ? '-i ' : '-u '; odooCmd += req.body.modules; const odooCmdCached = odooCmd; // Handle multi databases odooCmd = []; req.body.databases.forEach((dbname) => { odooCmd.push(odooCmdCached + ' -d ' + dbname); }); odooCmd = odooCmd.join(' && '); if (req.body.stop) { execCmd += 'docker-compose stop moka && ' execCmd += 'docker-compose run --rm moka bash -c \'bash genconf.sh && ' + odooCmd + '\' && '; execCmd += 'docker-compose start moka' } else { execCmd += 'docker-compose exec moka bash -c \'' + odooCmd + '\''; } console.log(execCmd); execCommand(execCmd, res); }; polka({ server }) .use(json(), files) .post('/connect', connect) .get('/disconnect', disconnect) .get('/cmd/:cmd', serverCommand) .post('/odooaction', odooAction) .listen(PORT, err => { if (err) throw err; console.log(`> Running on localhost:${PORT}`); });