From 52241a795fe59d62454e74cb573456524cb75ce9 Mon Sep 17 00:00:00 2001 From: zeus Date: Sun, 12 Dec 2021 21:09:35 +0200 Subject: [PATCH] mongoexpress --- .../share/swarmlab.io/sec/config.default.js | 222 ++++ .../usr/share/swarmlab.io/sec/package.json | 105 ++ .../usr/share/swarmlab.io/sec/swarmlab-sec | 953 ++++++++++++++---- 3 files changed, 1058 insertions(+), 222 deletions(-) create mode 100644 install/usr/share/swarmlab.io/sec/config.default.js create mode 100644 install/usr/share/swarmlab.io/sec/package.json diff --git a/install/usr/share/swarmlab.io/sec/config.default.js b/install/usr/share/swarmlab.io/sec/config.default.js new file mode 100644 index 0000000..b73eb84 --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/config.default.js @@ -0,0 +1,222 @@ +'use strict'; + +let mongo = { + // Setting the connection string will only give access to that database + // to see more databases you need to set mongodb.admin to true or add databases to the mongodb.auth list + // It is RECOMMENDED to use connectionString instead of individual params, other options will be removed later. + // More info here: https://docs.mongodb.com/manual/reference/connection-string/ + connectionString: process.env.ME_CONFIG_MONGODB_SERVER ? '' : process.env.ME_CONFIG_MONGODB_URL, + host: '127.0.0.1', + port: '27017', + dbName: '', +}; + +// Accessing Bluemix variable to get MongoDB info +if (process.env.VCAP_SERVICES) { + const dbLabel = 'mongodb-2.4'; + const env = JSON.parse(process.env.VCAP_SERVICES); + if (env[dbLabel]) { + mongo = env[dbLabel][0].credentials; + } +} + +const basicAuthUsername = 'ME_CONFIG_BASICAUTH_USERNAME'; +const basicAuthPassword = 'ME_CONFIG_BASICAUTH_PASSWORD'; +const adminUsername = 'ME_CONFIG_MONGODB_ADMINUSERNAME'; +const adminPassword = 'ME_CONFIG_MONGODB_ADMINPASSWORD'; +const dbAuthUsername = 'ME_CONFIG_MONGODB_AUTH_USERNAME'; +const dbAuthPassword = 'ME_CONFIG_MONGODB_AUTH_PASSWORD'; + +function getFile(filePath) { + if (typeof filePath !== 'undefined' && filePath) { + const fs = require('fs'); + + try { + if (fs.existsSync(filePath)) { + return fs.readFileSync(filePath); + } + } catch (err) { + console.error('Failed to read file', filePath, err); + } + } + return null; +} + +function getFileEnv(envVariable) { + const origVar = process.env[envVariable]; + const fileVar = process.env[envVariable + '_FILE']; + if (fileVar) { + const file = getFile(fileVar); + if (file) { + return file.toString().split(/\r?\n/)[0].trim(); + } + } + return origVar; +} + +function getBinaryFileEnv(envVariable) { + const fileVar = process.env[envVariable]; + return getFile(fileVar); +} + +const meConfigMongodbServer = process.env.ME_CONFIG_MONGODB_SERVER + ? process.env.ME_CONFIG_MONGODB_SERVER.split(',') + : false; + +function getConnectionStringFromEnvVariables() { + const infos = { + // server: mongodb hostname or IP address + // for replica set, use array of string instead + server: ( + meConfigMongodbServer.length > 1 ? meConfigMongodbServer : meConfigMongodbServer[0] + ) || mongo.host, + port: process.env.ME_CONFIG_MONGODB_PORT || mongo.port, + dbName: process.env.ME_CONFIG_MONGODB_AUTH_DATABASE || mongo.dbName, + + // >>>> If you are using an admin mongodb account, or no admin account exists, fill out section below + // >>>> Using an admin account allows you to view and edit all databases, and view stats + // leave username and password empty if no admin account exists + username: getFileEnv(adminUsername) || getFileEnv(dbAuthUsername) || mongo.username, + password: getFileEnv(adminPassword) || getFileEnv(dbAuthPassword) || mongo.password, + }; + const login = infos.username ? `${infos.username}:${infos.password}@` : ''; + return `mongodb://${login}${infos.server}:${infos.port}/${infos.dbName}`; +} + +const sslCA = 'ME_CONFIG_MONGODB_CA_FILE'; +const sslCAFromEnv = getBinaryFileEnv(sslCA); + +module.exports = { + mongodb: { + // if a connection string options such as server/port/etc are ignored + connectionString: mongo.connectionString || getConnectionStringFromEnvVariables(), + + connectionOptions: { + // ssl: connect to the server using secure SSL + ssl: process.env.ME_CONFIG_MONGODB_SSL || mongo.ssl, + + // sslValidate: validate mongod server certificate against CA + sslValidate: process.env.ME_CONFIG_MONGODB_SSLVALIDATE || true, + + // sslCA: array of valid CA certificates + sslCA: sslCAFromEnv ? [sslCAFromEnv] : [], + + // autoReconnect: automatically reconnect if connection is lost + autoReconnect: true, + + // poolSize: size of connection pool (number of connections to use) + poolSize: 4, + }, + + // set admin to true if you want to turn on admin features + // if admin is true, the auth list below will be ignored + // if admin is true, you will need to enter an admin username/password below (if it is needed) + admin: process.env.ME_CONFIG_MONGODB_ENABLE_ADMIN + ? process.env.ME_CONFIG_MONGODB_ENABLE_ADMIN.toLowerCase() === 'true' + : false, + + // whitelist: hide all databases except the ones in this list (empty list for no whitelist) + whitelist: [], + + // blacklist: hide databases listed in the blacklist (empty list for no blacklist) + blacklist: [], + }, + + site: { + // baseUrl: the URL that mongo express will be located at - Remember to add the forward slash at the start and end! + baseUrl: process.env.ME_CONFIG_SITE_BASEURL || '/', + cookieKeyName: 'mongo-express', + cookieSecret: process.env.ME_CONFIG_SITE_COOKIESECRET || 'cookiesecret', + host: process.env.VCAP_APP_HOST || 'localhost', + port: process.env.VCAP_APP_PORT || 8081, + requestSizeLimit: process.env.ME_CONFIG_REQUEST_SIZE || '50mb', + sessionSecret: process.env.ME_CONFIG_SITE_SESSIONSECRET || 'sessionsecret', + sslCert: process.env.ME_CONFIG_SITE_SSL_CRT_PATH || '', + sslEnabled: process.env.ME_CONFIG_SITE_SSL_ENABLED || false, + sslKey: process.env.ME_CONFIG_SITE_SSL_KEY_PATH || '', + }, + + // set useBasicAuth to true if you want to authenticate mongo-express logins + // if admin is false, the basicAuthInfo list below will be ignored + // this will be true unless ME_CONFIG_BASICAUTH_USERNAME is set and is the empty string + useBasicAuth: getFileEnv(basicAuthUsername) !== '', + + basicAuth: { + username: getFileEnv(basicAuthUsername) || 'admin', + password: getFileEnv(basicAuthPassword) || 'pass', + }, + + options: { + // Display startup text on console + console: true, + + // documentsPerPage: how many documents you want to see at once in collection view + documentsPerPage: 10, + + // editorTheme: Name of the theme you want to use for displaying documents + // See http://codemirror.net/demo/theme.html for all examples + editorTheme: process.env.ME_CONFIG_OPTIONS_EDITORTHEME || 'rubyblue', + + // Maximum size of a single property & single row + // Reduces the risk of sending a huge amount of data when viewing collections + maxPropSize: (100 * 1000), // default 100KB + maxRowSize: (1000 * 1000), // default 1MB + + // The options below aren't being used yet + + // cmdType: the type of command line you want mongo express to run + // values: eval, subprocess + // eval - uses db.eval. commands block, so only use this if you have to + // subprocess - spawns a mongo command line as a subprocess and pipes output to mongo express + cmdType: 'eval', + + // subprocessTimeout: number of seconds of non-interaction before a subprocess is shut down + subprocessTimeout: 300, + + // readOnly: if readOnly is true, components of writing are not visible. + readOnly: process.env.ME_CONFIG_OPTIONS_READONLY + ? process.env.ME_CONFIG_OPTIONS_READONLY.toLowerCase() === 'true' + : false, + + // collapsibleJSON: if set to true, jsons will be displayed collapsible + collapsibleJSON: true, + + // collapsibleJSONDefaultUnfold: if collapsibleJSON is set to `true`, this defines default level + // to which JSONs are displayed unfolded; use number or "all" to unfold all levels + collapsibleJSONDefaultUnfold: 1, + + // gridFSEnabled: if gridFSEnabled is set to 'true', you will be able to manage uploaded files + // ( ak. grids, gridFS ) + gridFSEnabled: process.env.ME_CONFIG_SITE_GRIDFS_ENABLED + ? process.env.ME_CONFIG_SITE_GRIDFS_ENABLED.toLowerCase() === 'true' + : false, + + // logger: this object will be used to initialize router logger (morgan) + logger: {}, + + // confirmDelete: if confirmDelete is set to 'true', a modal for confirming deletion is + // displayed before deleting a document/collection + confirmDelete: false, + + // noExport: if noExport is set to true, we won't show export buttons + noExport: false, + + // noDelete: if noDelete is set to true, we won't show delete buttons + noDelete: process.env.ME_CONFIG_OPTIONS_NO_DELETE || false, + }, + + // Specify the default keyname that should be picked from a document to display in collections list. + // Keynames can be specified for every database and collection. + // If no keyname is specified, it defaults to '_id', which is a mandatory field. + // For Example : + // defaultKeyNames{ + // "world_db":{ //Database Name + // "continent":"cont_name", // collection:field + // "country":"country_name", + // "city":"name" + // } + // } + defaultKeyNames: { + + }, +}; diff --git a/install/usr/share/swarmlab.io/sec/package.json b/install/usr/share/swarmlab.io/sec/package.json new file mode 100644 index 0000000..e52551d --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/package.json @@ -0,0 +1,105 @@ +{ + "version": "1.0.0-alpha.4", + "author": "https://github.com/mongo-express", + "name": "mongo-express", + "description": "Web-based admin interface for MongoDB", + "keywords": [ + "admin", + "administration", + "collection", + "database", + "GUI", + "interface", + "manage", + "manage-mongo", + "mongo", + "mongodb", + "phpmyadmin", + "UI", + "web-based" + ], + "bin": { + "mongo-express": "./app.js" + }, + "repository": { + "type": "git", + "url": "git://github.com/mongo-express/mongo-express.git" + }, + "dependencies": { + "basic-auth-connect": "^1.0.0", + "bluebird": "^3.7.2", + "body-parser": "^1.18.3", + "bson": "^4.2.0", + "busboy": "^0.2.13", + "cli-color": "^2.0.0", + "commander": "^2.9.0", + "cookie-parser": "1.4.4", + "cross-env": "^7.0.3", + "csurf": "1.10.0", + "errorhandler": "1.5.1", + "express": "4.17.1", + "express-fileupload": "^0.4.0", + "express-session": "^1.15.6", + "flat": "^2.0.1", + "gridfs-stream": "^1.1.1", + "json2csv": "^3.7.1", + "lodash": "~4.17.4", + "method-override": "^2.3.10", + "mongodb": "^3.6.2", + "mongodb-query-parser": "^2.1.2", + "morgan": "^1.9.0", + "patch-package": "^6.4.7", + "serve-favicon": "^2.5.0", + "swig-templates": "2.0.3", + "update-notifier": "5.1.0" + }, + "devDependencies": { + "@babel/core": "^7.16.0", + "@babel/preset-env": "^7.16.0", + "assets-webpack-plugin": "^7.1.1", + "babel-loader": "^8.2.3", + "bootstrap": "^3.3.7", + "chai": "^4.3.4", + "clean-webpack-plugin": "^4.0.0", + "codemirror": "^5.23.0", + "concurrently": "^6.3.0", + "copy-webpack-plugin": "^9.0.1", + "eslint": "^7.11.0", + "eslint-config-airbnb-base": "^14.0.0", + "eslint-plugin-import": "^2.22.0", + "eslint-plugin-lodash": "^7.1.0", + "jquery": "^3.5.1", + "mocha": "^9.1.3", + "nodemon": "^2.0.14", + "pre-commit": "1.2.2", + "renderjson": "dozoisch/renderjson#cd0ef870c1298d53f09555da54e4bf57a0d21414", + "supertest": "^6.1.6", + "webpack": "^5.61.0", + "webpack-cli": "^4.9.1" + }, + "resolutions": { + "**/event-stream": "^4.0.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0", + "npm": ">=3.0.0" + }, + "license": "MIT", + "scripts": { + "postinstall": "patch-package", + "lint": "eslint .", + "start": "cross-env NODE_ENV=production node app", + "start-dev": "concurrently --kill-others \"nodemon app --watch lib\" \"npm run build-dev\"", + "build-dev": "webpack --watch", + "build": "cross-env NODE_ENV=production webpack", + "test": "npm run mocha && npm run lint", + "mocha": "cross-env NODE_ENV=test mocha", + "test-watch": "cross-env NODE_ENV=test mocha --watch --reporter spec", + "prepublish": "npm run build" + }, + "pre-commit": [ + "test" + ], + "main": "./middleware", + "browserslist": "defaults" +} diff --git a/install/usr/share/swarmlab.io/sec/swarmlab-sec b/install/usr/share/swarmlab.io/sec/swarmlab-sec index b73eb84..fa00a15 100644 --- a/install/usr/share/swarmlab.io/sec/swarmlab-sec +++ b/install/usr/share/swarmlab.io/sec/swarmlab-sec @@ -1,222 +1,731 @@ -'use strict'; - -let mongo = { - // Setting the connection string will only give access to that database - // to see more databases you need to set mongodb.admin to true or add databases to the mongodb.auth list - // It is RECOMMENDED to use connectionString instead of individual params, other options will be removed later. - // More info here: https://docs.mongodb.com/manual/reference/connection-string/ - connectionString: process.env.ME_CONFIG_MONGODB_SERVER ? '' : process.env.ME_CONFIG_MONGODB_URL, - host: '127.0.0.1', - port: '27017', - dbName: '', -}; - -// Accessing Bluemix variable to get MongoDB info -if (process.env.VCAP_SERVICES) { - const dbLabel = 'mongodb-2.4'; - const env = JSON.parse(process.env.VCAP_SERVICES); - if (env[dbLabel]) { - mongo = env[dbLabel][0].credentials; - } -} - -const basicAuthUsername = 'ME_CONFIG_BASICAUTH_USERNAME'; -const basicAuthPassword = 'ME_CONFIG_BASICAUTH_PASSWORD'; -const adminUsername = 'ME_CONFIG_MONGODB_ADMINUSERNAME'; -const adminPassword = 'ME_CONFIG_MONGODB_ADMINPASSWORD'; -const dbAuthUsername = 'ME_CONFIG_MONGODB_AUTH_USERNAME'; -const dbAuthPassword = 'ME_CONFIG_MONGODB_AUTH_PASSWORD'; - -function getFile(filePath) { - if (typeof filePath !== 'undefined' && filePath) { - const fs = require('fs'); - - try { - if (fs.existsSync(filePath)) { - return fs.readFileSync(filePath); - } - } catch (err) { - console.error('Failed to read file', filePath, err); - } - } - return null; -} - -function getFileEnv(envVariable) { - const origVar = process.env[envVariable]; - const fileVar = process.env[envVariable + '_FILE']; - if (fileVar) { - const file = getFile(fileVar); - if (file) { - return file.toString().split(/\r?\n/)[0].trim(); - } - } - return origVar; -} - -function getBinaryFileEnv(envVariable) { - const fileVar = process.env[envVariable]; - return getFile(fileVar); -} - -const meConfigMongodbServer = process.env.ME_CONFIG_MONGODB_SERVER - ? process.env.ME_CONFIG_MONGODB_SERVER.split(',') - : false; - -function getConnectionStringFromEnvVariables() { - const infos = { - // server: mongodb hostname or IP address - // for replica set, use array of string instead - server: ( - meConfigMongodbServer.length > 1 ? meConfigMongodbServer : meConfigMongodbServer[0] - ) || mongo.host, - port: process.env.ME_CONFIG_MONGODB_PORT || mongo.port, - dbName: process.env.ME_CONFIG_MONGODB_AUTH_DATABASE || mongo.dbName, - - // >>>> If you are using an admin mongodb account, or no admin account exists, fill out section below - // >>>> Using an admin account allows you to view and edit all databases, and view stats - // leave username and password empty if no admin account exists - username: getFileEnv(adminUsername) || getFileEnv(dbAuthUsername) || mongo.username, - password: getFileEnv(adminPassword) || getFileEnv(dbAuthPassword) || mongo.password, - }; - const login = infos.username ? `${infos.username}:${infos.password}@` : ''; - return `mongodb://${login}${infos.server}:${infos.port}/${infos.dbName}`; -} - -const sslCA = 'ME_CONFIG_MONGODB_CA_FILE'; -const sslCAFromEnv = getBinaryFileEnv(sslCA); - -module.exports = { - mongodb: { - // if a connection string options such as server/port/etc are ignored - connectionString: mongo.connectionString || getConnectionStringFromEnvVariables(), - - connectionOptions: { - // ssl: connect to the server using secure SSL - ssl: process.env.ME_CONFIG_MONGODB_SSL || mongo.ssl, - - // sslValidate: validate mongod server certificate against CA - sslValidate: process.env.ME_CONFIG_MONGODB_SSLVALIDATE || true, - - // sslCA: array of valid CA certificates - sslCA: sslCAFromEnv ? [sslCAFromEnv] : [], - - // autoReconnect: automatically reconnect if connection is lost - autoReconnect: true, - - // poolSize: size of connection pool (number of connections to use) - poolSize: 4, - }, - - // set admin to true if you want to turn on admin features - // if admin is true, the auth list below will be ignored - // if admin is true, you will need to enter an admin username/password below (if it is needed) - admin: process.env.ME_CONFIG_MONGODB_ENABLE_ADMIN - ? process.env.ME_CONFIG_MONGODB_ENABLE_ADMIN.toLowerCase() === 'true' - : false, - - // whitelist: hide all databases except the ones in this list (empty list for no whitelist) - whitelist: [], - - // blacklist: hide databases listed in the blacklist (empty list for no blacklist) - blacklist: [], - }, - - site: { - // baseUrl: the URL that mongo express will be located at - Remember to add the forward slash at the start and end! - baseUrl: process.env.ME_CONFIG_SITE_BASEURL || '/', - cookieKeyName: 'mongo-express', - cookieSecret: process.env.ME_CONFIG_SITE_COOKIESECRET || 'cookiesecret', - host: process.env.VCAP_APP_HOST || 'localhost', - port: process.env.VCAP_APP_PORT || 8081, - requestSizeLimit: process.env.ME_CONFIG_REQUEST_SIZE || '50mb', - sessionSecret: process.env.ME_CONFIG_SITE_SESSIONSECRET || 'sessionsecret', - sslCert: process.env.ME_CONFIG_SITE_SSL_CRT_PATH || '', - sslEnabled: process.env.ME_CONFIG_SITE_SSL_ENABLED || false, - sslKey: process.env.ME_CONFIG_SITE_SSL_KEY_PATH || '', - }, - - // set useBasicAuth to true if you want to authenticate mongo-express logins - // if admin is false, the basicAuthInfo list below will be ignored - // this will be true unless ME_CONFIG_BASICAUTH_USERNAME is set and is the empty string - useBasicAuth: getFileEnv(basicAuthUsername) !== '', - - basicAuth: { - username: getFileEnv(basicAuthUsername) || 'admin', - password: getFileEnv(basicAuthPassword) || 'pass', - }, - - options: { - // Display startup text on console - console: true, - - // documentsPerPage: how many documents you want to see at once in collection view - documentsPerPage: 10, - - // editorTheme: Name of the theme you want to use for displaying documents - // See http://codemirror.net/demo/theme.html for all examples - editorTheme: process.env.ME_CONFIG_OPTIONS_EDITORTHEME || 'rubyblue', - - // Maximum size of a single property & single row - // Reduces the risk of sending a huge amount of data when viewing collections - maxPropSize: (100 * 1000), // default 100KB - maxRowSize: (1000 * 1000), // default 1MB - - // The options below aren't being used yet - - // cmdType: the type of command line you want mongo express to run - // values: eval, subprocess - // eval - uses db.eval. commands block, so only use this if you have to - // subprocess - spawns a mongo command line as a subprocess and pipes output to mongo express - cmdType: 'eval', - - // subprocessTimeout: number of seconds of non-interaction before a subprocess is shut down - subprocessTimeout: 300, - - // readOnly: if readOnly is true, components of writing are not visible. - readOnly: process.env.ME_CONFIG_OPTIONS_READONLY - ? process.env.ME_CONFIG_OPTIONS_READONLY.toLowerCase() === 'true' - : false, - - // collapsibleJSON: if set to true, jsons will be displayed collapsible - collapsibleJSON: true, - - // collapsibleJSONDefaultUnfold: if collapsibleJSON is set to `true`, this defines default level - // to which JSONs are displayed unfolded; use number or "all" to unfold all levels - collapsibleJSONDefaultUnfold: 1, - - // gridFSEnabled: if gridFSEnabled is set to 'true', you will be able to manage uploaded files - // ( ak. grids, gridFS ) - gridFSEnabled: process.env.ME_CONFIG_SITE_GRIDFS_ENABLED - ? process.env.ME_CONFIG_SITE_GRIDFS_ENABLED.toLowerCase() === 'true' - : false, - - // logger: this object will be used to initialize router logger (morgan) - logger: {}, - - // confirmDelete: if confirmDelete is set to 'true', a modal for confirming deletion is - // displayed before deleting a document/collection - confirmDelete: false, - - // noExport: if noExport is set to true, we won't show export buttons - noExport: false, - - // noDelete: if noDelete is set to true, we won't show delete buttons - noDelete: process.env.ME_CONFIG_OPTIONS_NO_DELETE || false, - }, - - // Specify the default keyname that should be picked from a document to display in collections list. - // Keynames can be specified for every database and collection. - // If no keyname is specified, it defaults to '_id', which is a mandatory field. - // For Example : - // defaultKeyNames{ - // "world_db":{ //Database Name - // "continent":"cont_name", // collection:field - // "country":"country_name", - // "city":"name" - // } - // } - defaultKeyNames: { - - }, -}; +#!/bin/bash + +# The MIT License (MIT) +# +# rootApostolos@swarmlab.io +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# Origin: https://github.com/NLKNguyen/alpine-mpich + +set -e + +DOCKERuser="docker" +PACKAGES=$(cat </dev/null 2>&1 && pwd )" + SOURCE="$(readlink "$SOURCE")" + [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located +done +DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )" + + +# ----------------------------------------------- +# +# Load Default config swarmlab.io +# +# ---------------------------------------------- + + +#. $DIR/.env + + +# ----------------------------------------------- +# +# Find Working dir +# +# ---------------------------------------------- + +function EPHEMERAL_PORT() { + LOW_BOUND=49152 + RANGE=16384 + while true; do + CANDIDATE=$[$LOW_BOUND + ($RANDOM % $RANGE)] + (echo "" >/dev/tcp/127.0.0.1/${CANDIDATE}) >/dev/null 2>&1 + if [ $? -ne 0 ]; then + echo $CANDIDATE + break + fi + done +} + +servicesshport=$(EPHEMERAL_PORT) + +Wdir=$(pwd) + +if [ ! -f $Wdir/.env ]; then +cat << EOF > $Wdir/.env +REGISTRY_ADDR=localhost +REGISTRY_PORT=5000 +IMAGE_NAME=$HYBRID_NETWORK +SSH_PORT=$servicesshport +WEB_PORT=$(EPHEMERAL_PORT) +WEB_PORT1=$(EPHEMERAL_PORT) +WEB_PORT2=$(EPHEMERAL_PORT) +EOF +fi + +. $Wdir/.env + +create_dockerfile () +{ + docker pull $IMAGE_origin << ANSWERS +yes +yes +yes +ANSWERS + +. $Wdir/ROOT_PASSWORD +if [ -d "$Wdir/project" ]; then + # ----------------------------------------------- + # + # create Dockerfile + # + # ---------------------------------------------- + + search='ok' + + if [ $search == 'ok' ] + then + echo "" + echo ">>> Load Origin " + cat << EOF > $Wdir/Dockerfile + FROM $IMAGE_origin + # + USER root + + COPY $bootstrap /usr/bin + COPY $hostnames_get /usr/bin + COPY $hostnames /usr/bin + COPY install-vim-plugin.sh . + + ENV NOTVISIBLE "in users profile" + ENV USER1 docker + ENV USER_HOME /home/docker + ENV SSHDIR \${USER_HOME}/.ssh + COPY ssh/ \${SSHDIR}/ + + RUN export DEBIAN_FRONTEND=noninteractive \ + && rm -rf /usr/share/doc \ + && rm -rf /usr/share/man \ + && rm -rf /usr/share/locale \ + && mkdir -p /var/run/sshd \ + && echo 'root:pass' | chpasswd \ + && echo "export VISIBLE=now" >> /etc/profile \ + && mkdir -p /home/docker/project \ + && mkdir -p /etc/opt \ + && echo "docker:docker" | chpasswd \ + && echo "StrictHostKeyChecking no" > \${SSHDIR}/config \ + && cat \${SSHDIR}/*.pub >> \${SSHDIR}/authorized_keys \ + && chmod -R 600 \${SSHDIR}/* \ + && chown -R \${USER1}:\${USER1} \${SSHDIR} + + COPY .vimrc /home/docker + EXPOSE 8081 + USER docker +EOF + fi +else + echo "" + echo "Not in Project Directory" + echo "A project directory should look like this" + echo "" + +cat <>> Load Origin " + cat << EOF > $Wdir/Dockerfile + FROM $IMAGE_origin + # + USER root + COPY $bootstrap /usr/bin + COPY $hostnames_get /usr/bin + COPY $hostnames /usr/bin + COPY install-vim-plugin.sh . + + ENV NOTVISIBLE "in users profile" + ENV USER1 docker + ENV USER_HOME /home/docker + + RUN export DEBIAN_FRONTEND=noninteractive \ + && rm -rf /usr/share/doc \ + && rm -rf /usr/share/man \ + && rm -rf /usr/share/locale \ + && mkdir -p /var/run/sshd \ + && echo 'root:pass' | chpasswd \ + && echo "export VISIBLE=now" >> /etc/profile \ + && mkdir -p /home/docker/project \ + && mkdir -p /etc/opt \ + && echo "docker:docker" | chpasswd \ + && echo "StrictHostKeyChecking no" > \${SSHDIR}/config \ + && cat \${SSHDIR}/*.pub >> \${SSHDIR}/authorized_keys \ + && chmod -R 600 \${SSHDIR}/* \ + && chown -R \${USER1}:\${USER1} \${SSHDIR} + + COPY .vimrc /home/docker + EXPOSE 8081 + USER docker +EOF +fi + + +/bin/mkdir -p $Wdir/project +/bin/mkdir -p $Wdir/logs +/bin/cp -rf $DIR/project/bin $Wdir/project +/bin/cp -rf $DIR/project/courses $Wdir/project +/bin/cp -rf $DIR/project/config $Wdir/project +/bin/cp -rf $DIR/project/data-www $Wdir/project +/bin/cp -f $DIR/project/hello_world.sh $Wdir/project +/bin/cp -f $DIR/project/config.default.js $Wdir/project/config.default.js +/bin/cp -f $DIR/project/package.json $Wdir/project/package.json +/bin/cp -f $DIR/$bootstrap $Wdir/$bootstrap +/bin/cp -f $DIR/$hostnames $Wdir/$hostnames +/bin/cp -f $DIR/$hostnames_get $Wdir/$hostnames_get +/bin/cp -f $DIR/ROOT_PASSWORD $Wdir/ROOT_PASSWORD +/bin/cp -rf $DIR/.vimrc $Wdir/.vimrc +/bin/cp -rf $DIR/install-vim-plugin.sh $Wdir/install-vim-plugin.sh + + +cat << EOF > $Wdir/docker-compose.yml +version: "3" + +services: + + masterservice: + image: $IMAGE_NAME + privileged: true + environment: + - NODENAME=${NODENAME} + - NODENETWORK=${NODENETWORK} + - DISPLAY=\${DISPLAY} + cap_add: + - NET_ADMIN + user: root + entrypoint: ["sec_bootstrap", "role=masterservice", "sec_master_service_name=masterservice", "sec_worker_service_name=workerservice"] + ports: + - "\${R_PORT1}:8081" + # - "\${R_PORT2}:3080" + networks: + - ${HYBRID_NETWORK} + volumes: + - $Wdir/project:/home/docker/project + - $Wdir/project/package.json:/home/docker/project/package.json + - $Wdir/project/config.default.js:/home/docker/project/config.js + - $Wdir/$bootstrap:/usr/bin/$bootstrap + + +# workerservice: +# image: $IMAGE_NAME +# privileged: true +# environment: +# - NODENAME=${NODENAME} +# - NODENETWORK=${NODENETWORK} +# - DISPLAY=\${DISPLAY} +# cap_add: +# - NET_ADMIN +# user: root +# entrypoint: ["sec_bootstrap", "role=workerservice", "sec_master_service_name=masterservice", "sec_worker_service_name=workerservice"] +# #ports: +# # - "\${SSH_PORT}:22" +# networks: +# - ${HYBRID_NETWORK} +# volumes: +# - $Wdir/project:/home/docker/project +# - $Wdir/project/data-www:/data-www +# - $Wdir/project/config/nginx.conf:/etc/nginx/nginx.conf +# - $Wdir/project/config/default.conf:/etc/nginx/conf.d/default.conf +# - $Wdir/project/config/supervisord.conf:/etc/supervisor/supervisord.conf + +networks: + ${HYBRID_NETWORK}: +EOF + +#/bin/cp -rf $DIR/ssh $Wdir + +cat << EOF > $Wdir/stop.sh +../install/usr/share/swarmlab.io/sec/swarmlab-sec down +EOF + +cat << EOF > $Wdir/container-stop.sh +docker stop \$1 +docker container rm \$1 +EOF + +cat < CLEAN UP SWARMLAB" + + printf "\\n%s\\n" "$HEADER" + echo "$ docker-compose down" + printf "\\n" + + docker-compose down +} + +up_registry () +{ + printf "\\n\\n===> SPIN UP REGISTRY" + + printf "\\n%s\\n" "$HEADER" + echo "$ docker-compose up -d registry" + printf "\\n" + + #docker stop swarmlab-registry || true && docker rm swarmlab-registry || true # remove for microservices + docker container prune --force + docker-compose up --no-recreate -d registry +} + +generate_ssh_keys () +{ + if [ -f ssh/id_rsa ] && [ -f ssh/id_rsa.pub ]; then + return 0 + fi + + printf "\\n\\n===> GENERATE SSH KEYS \\n\\n" + + echo "$ mkdir -p ssh/ " + printf "\\n" + mkdir -p ssh/ + + echo "$ ssh-keygen -f ssh/id_rsa -t rsa -N ''" + printf "\\n" + ssh-keygen -f ssh/id_rsa -t rsa -N '' +} + +build_and_push_image () +{ + printf "\\n\\n===> BUILD IMAGE" + printf "\\n%s\\n" "$HEADER" + echo "$ docker build -t \"$IMAGE_NAME\" ." + printf "\\n" + #docker build -t "$REGISTRY_ADDR:$REGISTRY_PORT/$IMAGE_NAME" . + docker build --force-rm --pull -t "$IMAGE_NAME" . + +} + +up_master () +{ + printf "\\n\\n===> SPIN UP MASTER NODE" + printf "\\n%s\\n" "$HEADER" + echo "$ docker-compose up -d masterservice" + printf "\\n" + echo "$ $IMAGE_local -d $IMAGE_origin" + printf "\\n" + + docker-compose rm -f -s -v + docker-compose up --build --remove-orphans --force-recreate -d masterservice << ANSWERS +yes +yes +yes +ANSWERS + #docker-compose up --force-recreate -d masterservice +} + + +up_workers () +{ + printf "\\n\\n===> SPIN UP WORKER NODES" + printf "\\n%s\\n" "$HEADER" + echo "$ docker-compose up -d worker" + printf "\\n" + docker-compose rm -f -s -v + docker-compose up --build --force-recreate --renew-anon-volumes --remove-orphans -d workerservice + #docker-compose up --force-recreate -d workerservice + + printf "\\n" + printf "\\n%s\\n" "$HEADER" + + NUM_WORKER=$((SIZE - 1)) + echo "$ docker-compose scale workerservice=$NUM_WORKER" + printf "\\n" + docker-compose scale workerservice=${NUM_WORKER} +} + +down_master () +{ + printf "\\n\\n===> TORN DOWN MASTER NODE" + printf "\\n%s\\n" "$HEADER" + + echo "$ docker-compose stop masterservice && docker-compose rm -f masterservice" + printf "\\n" + docker-compose stop masterservice && docker-compose rm -f masterservice +} + +down_workers () +{ + printf "\\n\\n===> TORN DOWN WORKER NODES" + printf "\\n%s\\n" "$HEADER" + echo "$ docker-compose stop worker && docker-compose rm -f worker" + printf "\\n" + docker-compose stop workerservice && docker-compose rm -f workerservice +} + +list () +{ + printf "\\n\\n===> LIST CONTAINERS" + printf "\\n%s\\n" "$HEADER" + echo "$ docker-compose ps" + printf "\\n" + docker-compose ps +} + + +exec_on_mpi_master_container () +{ + # shellcheck disable=SC2046 + docker exec -it -u $DOCKERuser $(docker-compose ps | grep 'masterservice'| awk 'NR==1{print $1}') "$@" +} + +prompt_ready () +{ + printf "\\n\\n===> SWARMLAB READY \\n\\n" +} + +show_instruction () +{ + echo ' ## . ' + echo ' ## ## ## == ' + echo ' ## ## ## ## ## === ' + echo ' /"""""""""""""""""\___/ === ' + echo ' ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~ ' + echo ' \______ o __/ ' + echo ' \ \ __/ ' + echo ' \____\_______/ ' + echo ' ' + echo ' Swarmlab.io Hybrid ' + echo '' + echo '==============================================================' + echo '' + + echo "To run SEC programs in an interative shell:" + echo " 1. Login to masterservice node:" + echo " Using Container->connect Menou:" + echo " copy/paste and Run command" + echo "" + echo " Or using SSH with keys through exposed port:" + echo " $ ssh -o \"StrictHostKeyChecking no\" -i ssh/id_rsa -p $SSH_PORT docker@localhost" + echo ' where [localhost] could be changed to the host IP of masterservice node' + echo "" + echo " 2. Execute programs inside masterservice node, for example:" + echo " $ sudo su" + echo " # apk update" + echo " *----------------------------------------------------*" + echo " | Default hostfile of connected nodes in the swarmlab |" + echo " | To obtain hostfile manually: $ ./bin/swarmlab-nmap: > hosts |" + echo " * ---------------------------------------------------*" + echo "" + echo "" +} + + + +############################################# + +while [ "$1" != "" ]; +do + PARAM=$(echo "$1" | awk -F= '{print $1}') + VALUE=$(echo "$1" | awk -F= '{print $2}') + + case $PARAM in + help) + usage + exit + ;; + -i) + show_instruction + exit + ;; + + login) + COMMAND_LOGIN=1 + ;; + + exec) + COMMAND_EXEC=1 + shift # the rest is the shell command to run in the node + SHELL_COMMAND="$*" + break # end while loop + ;; + + up) + COMMAND_UP=1 + ;; + + create) + COMMAND_CREATE=1 + ;; + + down) + COMMAND_DOWN=1 + ;; + + reload) + COMMAND_RELOAD=1 + ;; + + scale) + COMMAND_SCALE=1 + ;; + + list) + COMMAND_LIST=1 + ;; + + clean) + COMMAND_CLEAN=1 + ;; + + size) + [ "$VALUE" ] && SIZE=$VALUE + ;; + + *) + echo "ERROR: unknown parameter \"$PARAM\"" + usage + exit 1 + ;; + esac + shift +done + + +if [ $COMMAND_UP -eq 1 ]; then + create_dockerfile + down_all + clear_all + #up_registry # remove for microservices + generate_ssh_keys + build_and_push_image # remove for microservices + up_master + #up_workers + + prompt_ready + show_instruction + +elif [ $COMMAND_CREATE -eq 1 ]; then + create_project + +elif [ $COMMAND_DOWN -eq 1 ]; then + down_all + clear_all + +elif [ $COMMAND_CLEAN -eq 1 ]; then + clear_all + + +elif [ $COMMAND_SCALE -eq 1 ]; then + create_dockerfile + down_master + down_workers + up_master + #up_workers + + prompt_ready + show_instruction + +elif [ $COMMAND_RELOAD -eq 1 ]; then + create_dockerfile + down_master + down_workers + build_and_push_image + up_master + #up_workers + + prompt_ready + show_instruction + +elif [ $COMMAND_LOGIN -eq 1 ]; then + exec_on_mpi_master_container /bin/bash + +elif [ $COMMAND_EXEC -eq 1 ]; then + create_dockerfile + exec_on_mpi_master_container ash -c "${SHELL_COMMAND}" + +elif [ $COMMAND_LIST -eq 1 ]; then + list +else + usage +fi +