diff --git a/bin/manager b/bin/manager index 57c8cd4..8b3c771 100755 --- a/bin/manager +++ b/bin/manager @@ -3,6 +3,8 @@ HOMEDIR="$(dirname "$(cd -- "$(dirname "$(readlink -f "$0")")" && (pwd -P 2>/dev usage() { echo "USAGE: ./manager [ --port 3012 ] [ --storage /path/to/storage.json ] [ --key secreKey ] [ --color ] " + echo " [ --reset ] # set current host as manager" + echo " [ --cluster "server1,server2" ] # add extra workers on setup" exit 1 } @@ -15,6 +17,8 @@ while (( "$#" )); do --key ) shift; key=$1 ;; --storage ) shift; storage=$1 ;; --sqlite ) shift; sqlite=$1 ;; + --reset ) shift; reset=1 ;; + --cluster ) shift; cluster=$1 ;; --help ) usage ;; -*) echo "invalid parameter: $1"; usage ;; esac @@ -44,12 +48,29 @@ if [[ $key ]]; then echo "Custom secret key set: *****" fi +if [[ $cluster ]]; then + export CRONICLE_cluster="$cluster" + echo "Following nodes will be added on setup: $cluster" +fi + # pull data from git if needed # if [ ! -d data/global ] && [ -v GIT_REPO ]; then # git clone $GIT_REPO $HOMEDIR/data # fi -$HOMEDIR/bin/control.sh setup +# check for custom nodejs binary +if [ -f $HOMEDIR/nodejs/bin/node ]; then + export PATH="$HOMEDIR/nodejs/bin:$PATH" + echo "using custom node version: $(node -v)" +fi + + +# setup storage OR make current host the primary manager if needed +if [ "$reset" = 1 ]; then + node $HOMEDIR/bin/storage-cli.js reset +else $HOMEDIR/bin/control.sh setup +fi + if [ -f "$HOMEDIR/logs/cronicled.pid" ]; then echo 'removing old pid file' @@ -63,12 +84,6 @@ if [ -f "$HOMEDIR/data/backup.json" ]; then rm "$HOMEDIR/data/backup.json" fi -# check for custom nodejs binary -if [ -f $HOMEDIR/nodejs/bin/node ]; then - export PATH="$HOMEDIR/nodejs/bin:$PATH" - echo "using custom node version: $(node -v)" -fi - BINARY="node $HOMEDIR/lib/main.js" # check if bundle exist if [ -f "$HOMEDIR/bin/cronicle.js" ]; then diff --git a/bin/manager.bat b/bin/manager.bat index 6e209a1..0f87258 100644 --- a/bin/manager.bat +++ b/bin/manager.bat @@ -43,8 +43,21 @@ if /I "%1"=="--port" ( echo Using sqlite as storage: %~f2 shift shift +) else if /I "%1"=="--cluster" ( + if "%2"=="" ( + echo Missing cluster value. Specify comma-separatd hostnames + exit + ) + set CRONICLE_cluster=%~f2 + echo These servers will be added on setup: %~f2 + shift + shift +) else if /I "%1"=="--reset" ( + set CRONICLE_RESET=1 ) else if /I "%1"=="--help" ( - echo Usage: .\manager [--port port] [ --storage /path/to/storage.json] + echo Usage: .\manager [--port port] [ --storage /path/to/storage.json] + echo [ --reset ] # make current host the manager + echo [ --cluster "server1,server2"] # add extra workers on setup shift ) else (exit) @@ -59,11 +72,11 @@ IF EXIST "%~dp0..\nodejs\node.exe" ( SET "PATH=%~dp0..\nodejs;%PATH%" ) -node .\storage-cli.js setup - -if not "%~1"=="" ( - set "CRONICLE_WebServer__http_port=%1" - echo CRONICLE_http_port is set to %1 +REM setup or reset manager +if "%CRONICLE_RESET%"=="1" ( + node .\storage-cli.js reset +) else ( + node .\storage-cli.js setup ) node .\cronicle.js --manager --echo --foreground --color diff --git a/bin/storage-cli.js b/bin/storage-cli.js index 6e7ed85..7e44a99 100755 --- a/bin/storage-cli.js +++ b/bin/storage-cli.js @@ -10,6 +10,7 @@ var os = require('os'); var fs = require('fs'); var async = require('async'); var bcrypt = require('bcrypt-node'); +var dns = require('dns') var Args = require('pixl-args'); var Tools = require('pixl-tools'); @@ -155,6 +156,27 @@ for (var env_key in process.env) { } } +// helper function to resolve IPs for CRONICLE_cluster +const getIPsForHostnames = async (hostnames) => { + const ipPromises = hostnames.map(hostname => { + return new Promise((resolve, reject) => { + dns.lookup(hostname.trim(), (err, ip) => { + if (err) resolve({ hostname: hostname.trim(), ip: null }); + else resolve({ hostname: hostname.trim(), ip }); + }); + }); + }); + + try { + // Wait for all DNS lookups to finish + const ips = await Promise.all(ipPromises); + return ips; + } catch (error) { + console.error("Error fetching IP addresses:", error); + return []; + } +}; + // construct standalone storage server var storage = new StandaloneStorage(config.Storage, function (err) { if (err) throw err; @@ -188,12 +210,19 @@ var storage = new StandaloneStorage(config.Storage, function (err) { // make sure this is only run once // changing exit code to 0, so it won't break docker entry point - storage.get('global/users', function (err) { + storage.get('global/users', async function (err) { if (!err) { print("Storage has already been set up. There is no need to run this command again.\n\n"); process.exit(0); } + if(process.env['CRONICLE_cluster']) { + let servers = await getIPsForHostnames(process.env['CRONICLE_cluster'].split(',')) + servers.forEach(server =>{ + setup.storage.push(["listPush", "global/servers", server]) + }) + } + async.eachSeries(setup.storage, function (params, callback) { verbose("Executing: " + JSON.stringify(params) + "\n"); @@ -230,6 +259,34 @@ var storage = new StandaloneStorage(config.Storage, function (err) { }); break; + case 'reset': + + let newGroup = { regexp: '^(' + Tools.escapeRegExp(hostname) + ')$' } + + storage.listFindUpdate('global/server_groups', { id: "maingrp" }, newGroup, function (err) { + if (err) throw err; + print(`Main group regex is set to [ ${newGroup.regexp} ]`); + print("\n"); + + storage.listFind("global/servers", { hostname: hostname }, function (err, item) { + // already exist? + if (item) { + print(`${hostname} already exist in server list\n`); + storage.shutdown(function () { process.exit(1); }); + } + else { + storage.listPush("global/servers", { hostname: hostname, ip: ip }, function (err) { + if (err) throw err; + print(`Added ${hostname} to server list (remove old servers from UI as needed)\n`); + storage.shutdown(function () { process.exit(0); }); + }) + } + + }) + + }); + break; + case 'admin': // create or replace admin account // Usage: ./storage-cli.js admin USERNAME PASSWORD [EMAIL]