diff --git a/CMakeLists.txt b/CMakeLists.txt index 87552e4..7accb89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,7 +78,7 @@ target_precompile_headers(sagent PUBLIC src/pchheader.hpp) add_custom_target(installer COMMAND mkdir -p ./build/installer COMMAND bash -c "cp -r ./build/{sagent,sashi,hpfs,user-install.sh,user-uninstall.sh,contract_template} ./build/installer/" - COMMAND bash -c "cp -r ./installer/{docker-install.sh,registry-install.sh,registry-uninstall.sh,prereq.sh,sashimono-install.sh,sashimono-uninstall.sh} ./build/installer/" + COMMAND bash -c "cp -r ./installer/{docker-install.sh,docker-registry-install.sh,docker-registry-uninstall.sh,prereq.sh,sashimono-install.sh,sashimono-uninstall.sh} ./build/installer/" COMMAND bash -c "cp -r ./dependencies/{user-cgcreate.sh,libblake3.so,licence.txt} ./build/installer/" COMMAND bash -c "cp -r ./mb-xrpl/dist ./build/installer/mb-xrpl" COMMAND tar cfz ./build/installer.tar.gz --directory=./build/ installer diff --git a/dependencies/user-install.sh b/dependencies/user-install.sh index 109c5e3..13661bc 100755 --- a/dependencies/user-install.sh +++ b/dependencies/user-install.sh @@ -13,8 +13,10 @@ contract_gid=$7 peer_port=$8 user_port=$9 docker_image=${10} -if [ -z "$cpu" ] || [ -z "$memory" ] || [ -z "$swapmem" ] || [ -z "$disk" ] || [ -z "$contract_dir" ] || [ -z "$contract_uid" ] || [ -z "$contract_gid" ] || [ -z "$peer_port" ] || [ -z "$user_port" ]; then - echo "Expected: user-install.sh " +docker_registry=${11} +if [ -z "$cpu" ] || [ -z "$memory" ] || [ -z "$swapmem" ] || [ -z "$disk" ] || [ -z "$contract_dir" ] || + [ -z "$contract_uid" ] || [ -z "$contract_gid" ] || [ -z "$peer_port" ] || [ -z "$user_port" ] || + [ -z "$docker_image" ] || [ -z "$docker_registry" ]; then echo "INVALID_PARAMS,INST_ERR" && exit 1 fi @@ -160,6 +162,8 @@ echo "[Service] echo "Applying $docker_service extra args." exec_original="ExecStart=$docker_bin/dockerd-rootless.sh" exec_replace="$exec_original --max-concurrent-downloads 1" +# Add private docker registry information. +[ "$docker_registry" != "-" ] && exec_replace="$exec_replace --registry-mirror http://$docker_registry --insecure-registry $docker_registry" sed -i "s%$exec_original%$exec_replace%" $user_dir/.config/systemd/user/$docker_service # Reload the docker service. diff --git a/installer/registry-install.sh b/installer/docker-registry-install.sh similarity index 63% rename from installer/registry-install.sh rename to installer/docker-registry-install.sh index cc09a61..1a5b11b 100755 --- a/installer/registry-install.sh +++ b/installer/docker-registry-install.sh @@ -1,11 +1,10 @@ #!/bin/bash -# Sashimono docker registry installation script. +# Sashimono private docker registry installation script. +# This acts as a pull-through cache to the public docker hub registry. -docker_bin=$1 -user=$2 -port=$3 -hubacc="evernodedev" -images=("sashimono:hp.latest-ubt.20.04" "sashimono:hp.latest-ubt.20.04-njs.16") +user=$DOCKER_REGISTRY_USER +port=$DOCKER_REGISTRY_PORT +hubregistry="https://index.docker.io" user_dir=/home/$user # Waits until a service becomes ready up to 3 seconds. @@ -37,7 +36,7 @@ dockerd_socket="unix://$user_runtime_dir/docker.sock" # Setup env variables for the user. echo " export XDG_RUNTIME_DIR=$user_runtime_dir -export PATH=$docker_bin:\$PATH +export PATH=$DOCKER_BIN:\$PATH export DOCKER_HOST=$dockerd_socket" >>"$user_dir"/.bashrc echo "Updated user .bashrc." @@ -51,22 +50,13 @@ done [ "$user_systemd" != "running" ] && rollback "NO_SYSTEMD" echo "Installing rootless dockerd for user." -sudo -H -u "$user" PATH="$docker_bin":"$PATH" XDG_RUNTIME_DIR="$user_runtime_dir" "$docker_bin"/dockerd-rootless-setuptool.sh install +sudo -H -u "$user" PATH="$DOCKER_BIN":"$PATH" XDG_RUNTIME_DIR="$user_runtime_dir" "$DOCKER_BIN"/dockerd-rootless-setuptool.sh install service_ready "docker.service" || rollback "NO_DOCKERSVC" echo "Installed rootless dockerd for docker registry." -# Run the docker registry container on port 4444 -DOCKER_HOST=$dockerd_socket $docker_bin/docker run -d -p $port:5000 --restart=always --name registry registry:2 +# Run the docker registry container on specified port. +DOCKER_HOST=$dockerd_socket $DOCKER_BIN/docker run -d -p $port:5000 --restart=always --name registry -e REGISTRY_PROXY_REMOTEURL=$hubregistry registry:2 echo "Docker registry listening at $port" -# Prefetch the required docker images. -echo "Pulling Sashimono base contract images..." -for img in ${images[@]}; do - DOCKER_HOST=$dockerd_socket $docker_bin/docker pull $hubacc/$img - DOCKER_HOST=$dockerd_socket $docker_bin/docker tag $hubacc/$img localhost:$port/$img - DOCKER_HOST=$dockerd_socket $docker_bin/docker push localhost:$port/$img - DOCKER_HOST=$dockerd_socket $docker_bin/docker rmi $hubacc/$img -done - exit 0 \ No newline at end of file diff --git a/installer/registry-uninstall.sh b/installer/docker-registry-uninstall.sh similarity index 79% rename from installer/registry-uninstall.sh rename to installer/docker-registry-uninstall.sh index 2370c69..2d2e148 100755 --- a/installer/registry-uninstall.sh +++ b/installer/docker-registry-uninstall.sh @@ -1,15 +1,14 @@ #!/bin/bash # Sashimono docker registry installation script. -docker_bin=$1 -user=$2 +user=$DOCKER_REGISTRY_USER # Check if users exists. if [[ $(id -u "$user" 2>/dev/null || echo -1) -ge 0 ]]; then - : + : else - echo "$user does not exist." - exit 1 + echo "$user does not exist." + exit 0 fi user_dir=/home/$user @@ -18,8 +17,7 @@ user_runtime_dir="/run/user/$user_id" # Uninstall rootless dockerd. echo "Uninstalling rootless dockerd." -sudo -H -u "$user" PATH="$docker_bin":"$PATH" XDG_RUNTIME_DIR="$user_runtime_dir" "$docker_bin"/dockerd-rootless-setuptool.sh uninstall - +sudo -H -u "$user" PATH="$DOCKER_BIN":"$PATH" XDG_RUNTIME_DIR="$user_runtime_dir" "$DOCKER_BIN"/dockerd-rootless-setuptool.sh uninstall # Gracefully terminate user processes. echo "Terminating user processes." diff --git a/installer/sashimono-install.sh b/installer/sashimono-install.sh index 96d4aca..2e8aa69 100755 --- a/installer/sashimono-install.sh +++ b/installer/sashimono-install.sh @@ -21,6 +21,7 @@ function stage() { } function rollback() { + [ "$UPGRADE" == "1" ] && echo "Evernode update failed. You can try again later. If the problem persists, please uninstall and re-install Evernode." && exit 1 echo "Rolling back sashimono installation." "$script_dir"/sashimono-uninstall.sh -f echo "Rolled back the installation." @@ -36,6 +37,12 @@ function cgrulesengd_servicename() { fi } +function set_cpu_info() { + [ -z $cpu_model_name ] && cpu_model_name=$(lscpu | grep -i "^Model name:" | sed 's/Model name://g; s/[#$%*@;]//g' | xargs | tr ' ' '_') + [ -z $cpu_count ] && cpu_count=$(lscpu | grep -i "^CPU(s):" | sed 's/CPU(s)://g' | xargs) + [ -z $cpu_mhz ] && cpu_mhz=$(lscpu | grep -i "^CPU MHz:" | sed 's/CPU MHz://g' | sed 's/\.[0-9]*//g' | xargs) +} + # Check cgroup rule config exists. [ ! -f /etc/cgred.conf ] && echo "cgroups is not configured. Make sure you've installed and configured cgroup-tools." && exit 1 @@ -51,6 +58,8 @@ chmod +x $SASHIMONO_BIN/sashimono-uninstall.sh # Setting up Sashimono admin group. ! grep -q $SASHIADMIN_GROUP /etc/group && ! groupadd $SASHIADMIN_GROUP && echo "$SASHIADMIN_GROUP group creation failed." && rollback +! set_cpu_info && echo "Fetching CPU info failed" && rollback + # Register host only if NO_MB environment is not set. if [ "$NO_MB" == "" ]; then # Configure message board users and register host. @@ -89,7 +98,7 @@ if [ "$NO_MB" == "" ]; then # Append STAGE prefix to the lease offer creation logs, So they would get fetched from setup as stage logs. # Add -p to the progress logs so they would be printed overwriting the same line. ! sudo -u $MB_XRPL_USER MB_DATA_DIR=$MB_XRPL_DATA node $MB_XRPL_BIN register \ - $countrycode $cpuMicroSec $ramKB $swapKB $diskKB $inst_count $description | + $countrycode $cpuMicroSec $ramKB $swapKB $diskKB $inst_count $cpu_model_name $cpu_count $cpu_mhz $description | stdbuf --output=L sed -E '/^Creating lease offer/s/^/STAGE /;/^Created lease offer/s/^/STAGE -p /' && echo "REG_FAILURE" && rollback set +o pipefail @@ -104,7 +113,7 @@ rm -r "$SASHIMONO_DATA"/{contract_template,licence.txt} >/dev/null 2>&1 cp -r "$script_dir"/{contract_template,licence.txt} $SASHIMONO_DATA # Install Sashimono agent binaries into sashimono bin dir. -cp "$script_dir"/{sagent,hpfs,user-cgcreate.sh,user-install.sh,user-uninstall.sh} $SASHIMONO_BIN +cp "$script_dir"/{sagent,hpfs,user-cgcreate.sh,user-install.sh,user-uninstall.sh,docker-registry-uninstall.sh} $SASHIMONO_BIN chmod -R +x $SASHIMONO_BIN # Copy Blake3 and update linker library cache. @@ -123,11 +132,14 @@ mkdir -p $DOCKER_BIN [ -z "$(ls -A $DOCKER_BIN 2>/dev/null)" ] && echo "Rootless Docker installation failed." && rollback # Install private docker registry. -# stage "Installing private docker registry" -# (Disabled until secure registry configuration) -# ./registry-install.sh $DOCKER_BIN $DOCKER_REGISTRY_USER $DOCKER_REGISTRY_PORT -# [ "$?" == "1" ] && rollback -# registry_addr=$inetaddr:$DOCKER_REGISTRY_PORT +if [ "$DOCKER_REGISTRY_PORT" != "0" ]; then + stage "Installing private docker registry" + # TODO: secure registry configuration + "$script_dir"/docker-registry-install.sh + [ "$?" == "1" ] && echo "Private docker registry installation failed." && rollback +else + echo "Private docker registry installation skipped" +fi # If installing with sudo, add current logged-in user to Sashimono admin group. [ -n "$SUDO_USER" ] && usermod -a -G $SASHIADMIN_GROUP $SUDO_USER @@ -168,11 +180,11 @@ if [ -f $SASHIMONO_DATA/sa.cfg ]; then echo "Existing Sashimono data directory found. Updating..." ! $SASHIMONO_BIN/sagent upgrade $SASHIMONO_DATA && rollback else - ! $SASHIMONO_BIN/sagent new $SASHIMONO_DATA $inetaddr $inst_count $cpuMicroSec $ramKB $swapKB $diskKB && rollback + ! $SASHIMONO_BIN/sagent new $SASHIMONO_DATA $inetaddr $DOCKER_REGISTRY_PORT $inst_count $cpuMicroSec $ramKB $swapKB $diskKB && rollback fi if [[ "$NO_MB" == "" && -f $MB_XRPL_DATA/mb-xrpl.cfg ]]; then - ! sudo -u "$MB_XRPL_USER" MB_DATA_DIR="$MB_XRPL_DATA" node "$MB_XRPL_BIN" upgrade && rollback + ! sudo -u "$MB_XRPL_USER" MB_DATA_DIR="$MB_XRPL_DATA" node "$MB_XRPL_BIN" upgrade && rollback fi # Install Sashimono Agent systemd service. diff --git a/installer/sashimono-uninstall.sh b/installer/sashimono-uninstall.sh index 3df683e..27230fb 100755 --- a/installer/sashimono-uninstall.sh +++ b/installer/sashimono-uninstall.sh @@ -87,8 +87,8 @@ rm $service_path # Reload the systemd daemon after removing the service systemctl daemon-reload -# echo "Removing Sashimono private docker registry..." -# ./registry-uninstall.sh $DOCKER_BIN $DOCKER_REGISTRY_USER +echo "Removing Sashimono private docker registry..." +$SASHIMONO_BIN/docker-registry-uninstall.sh # Delete binaries except message board and sashimnono uninstall script. # We keep uninstall script so user can uninstall again if error occured at later steps. diff --git a/installer/setup.sh b/installer/setup.sh index c83f02a..26d8673 100755 --- a/installer/setup.sh +++ b/installer/setup.sh @@ -31,11 +31,13 @@ export SASHIADMIN_GROUP="sashiadmin" export SASHIUSER_GROUP="sashiuser" export SASHIUSER_PREFIX="sashi" export MB_XRPL_USER="sashimbxrpl" -export DOCKER_REGISTRY_USER="sashidockerreg" -export DOCKER_REGISTRY_PORT=4444 export CG_SUFFIX="-cg" export EVERNODE_REGISTRY_ADDRESS="rHQQq5aJ5kxFyNJXE36rAmuhxpDvpLHcWq" +# Private docker registry (not used for now) +export DOCKER_REGISTRY_USER="sashidockerreg" +export DOCKER_REGISTRY_PORT=0 + # Configuring the sashimono service is the last stage of the installation. # So if the service exists, Previous sashimono installation has been complete. [ -f /etc/systemd/system/$SASHIMONO_SERVICE.service ] && sashimono_installed=true || sashimono_installed=false @@ -375,6 +377,9 @@ function install_evernode() { # So, if the installation attempt failed user can uninstall the failed installation using evernode commands. create_evernode_alias + # Adding ip address as the host description. + description=$inetaddr + echo "Installing Sashimono..." # Filter logs with STAGE prefix and ommit the prefix when echoing. # If STAGE log contains -p arg, move the cursor to previous log line and overwrite the log. @@ -507,10 +512,7 @@ if [ "$mode" == "install" ]; then alloc_swapKB=${7} # Swap to allocate for contract instances. alloc_diskKB=${8} # Disk space to allocate for contract instances. alloc_instcount=${9} # Total contract instance count. - description=${10} # Registration description (underscore for spaces). - lease_amount=${11} # Contract instance lease amount in EVRs. - else - description="Evernode_host" + lease_amount=${10} # Contract instance lease amount in EVRs. fi $interactive && ! confirm "This will install Sashimono, Evernode's contract instance management software, diff --git a/mb-xrpl/app.js b/mb-xrpl/app.js index 1526787..babd4ce 100644 --- a/mb-xrpl/app.js +++ b/mb-xrpl/app.js @@ -23,9 +23,9 @@ async function main() { const acc = await setup.generateBetaHostAccount(registryAddress, domain); setup.newConfig(acc.address, acc.secret, registryAddress, parseFloat(leaseAmount)); } - else if (process.argv.length === 10 && process.argv[2] === 'register') { + else if (process.argv.length === 13 && process.argv[2] === 'register') { await new Setup().register(process.argv[3], parseInt(process.argv[4]), parseInt(process.argv[5]), - parseInt(process.argv[6]), parseInt(process.argv[7]), parseInt(process.argv[8]), process.argv[9]); + parseInt(process.argv[6]), parseInt(process.argv[7]), parseInt(process.argv[8]), process.argv[9], parseInt(process.argv[10]), parseInt(process.argv[11]), process.argv[12]); } else if (process.argv.length === 3 && process.argv[2] === 'deregister') { await new Setup().deregister(); diff --git a/mb-xrpl/lib/appenv.js b/mb-xrpl/lib/appenv.js index 48173e2..3605cdb 100644 --- a/mb-xrpl/lib/appenv.js +++ b/mb-xrpl/lib/appenv.js @@ -4,7 +4,8 @@ let appenv = { IS_DEV_MODE: process.env.MB_DEV === "1", FILE_LOG_ENABLED: process.env.MB_FILE_LOG === "1", DATA_DIR: process.env.MB_DATA_DIR || __dirname, - FAUCET_URL: process.env.MB_FAUCET_URL || "https://faucet-nft.ripple.com/accounts" + FAUCET_URL: process.env.MB_FAUCET_URL || "https://hooks-testnet-v2.xrpl-labs.com/newcreds", + DEFAULT_RIPPLED_SERVER: 'wss://hooks-testnet-v2.xrpl-labs.com' } appenv = { @@ -20,7 +21,7 @@ appenv = { ACQUIRE_LEASE_WAIT_TIMEOUT_THRESHOLD: 0.4, SASHI_CLI_PATH: appenv.IS_DEV_MODE ? "../build/sashi" : "/usr/bin/sashi", MB_VERSION: '0.5.0', - TOS_HASH: 'BECF974A2C48C21F39046C1121E5DF7BD55648E1005172868CD5738C23E3C073' + TOS_HASH: '757A0237B44D8B2BBB04AE2BAD5813858E0AECD2F0B217075E27E0630BA74314' // This is the sha256 hash of TOS text. } Object.freeze(appenv); diff --git a/mb-xrpl/lib/message-board.js b/mb-xrpl/lib/message-board.js index 0eb74eb..3e7374f 100644 --- a/mb-xrpl/lib/message-board.js +++ b/mb-xrpl/lib/message-board.js @@ -32,12 +32,14 @@ class MessageBoard { async init() { this.readConfig(); - if (!this.cfg.version || !this.cfg.xrpl.address || !this.cfg.xrpl.secret || !this.cfg.xrpl.registryAddress) + if (!this.cfg.version || !this.cfg.xrpl.address || !this.cfg.xrpl.secret || !this.cfg.xrpl.registryAddress || + !this.cfg.xrpl.registryAddress) throw "Required cfg fields cannot be empty."; console.log("Using registry " + this.cfg.xrpl.registryAddress); + console.log("Using rippled " + this.cfg.xrpl.rippledServer); - this.xrplApi = new evernode.XrplApi(); + this.xrplApi = new evernode.XrplApi(this.cfg.xrpl.rippledServer); evernode.Defaults.set({ registryAddress: this.cfg.xrpl.registryAddress, xrplApi: this.xrplApi diff --git a/mb-xrpl/lib/setup.js b/mb-xrpl/lib/setup.js index 71ca7bb..4ab2e1f 100644 --- a/mb-xrpl/lib/setup.js +++ b/mb-xrpl/lib/setup.js @@ -6,6 +6,12 @@ const fs = require('fs'); const { SqliteDatabase } = require('./sqlite-handler'); const { ConfigHelper } = require('./config-helper'); +function setEvernodeDefaults(registryAddress, rippledServer) { + evernode.Defaults.set({ + registryAddress: registryAddress, + rippledServer: rippledServer || appenv.DEFAULT_RIPPLED_SERVER + }); +} class Setup { @@ -32,14 +38,22 @@ class Setup { console.log("Generating faucet account..."); const resp = await this.#httpPost(appenv.FAUCET_URL); const json = JSON.parse(resp); + + // If Hooks TEST NET is used. return { - address: json.account.address, - secret: json.account.secret + address: json.address, + secret: json.secret }; + + // If NFT DEV NET is used. + // return { + // address: json.account.address, + // secret: json.account.secret + // }; } #getConfig(readSecret = true) { - return ConfigHelper.readConfig(appenv.CONFIG_PATH, readSecret? appenv.SECRET_CONFIG_PATH : null); + return ConfigHelper.readConfig(appenv.CONFIG_PATH, readSecret ? appenv.SECRET_CONFIG_PATH : null); } #saveConfig(cfg) { @@ -49,15 +63,19 @@ class Setup { newConfig(address = "", secret = "", registryAddress = "", leaseAmount = 0) { this.#saveConfig({ version: appenv.MB_VERSION, - xrpl: { address: address, secret: secret, registryAddress: registryAddress, leaseAmount: leaseAmount } + xrpl: { + address: address, + secret: secret, + registryAddress: registryAddress, + rippledServer: appenv.DEFAULT_RIPPLED_SERVER, + leaseAmount: leaseAmount + } }); } async generateBetaHostAccount(registryAddress, domain) { - evernode.Defaults.set({ - registryAddress: registryAddress - }); + setEvernodeDefaults(registryAddress); const acc = await this.#generateFaucetAccount(); @@ -117,12 +135,12 @@ class Setup { return acc; } - async register(countryCode, cpuMicroSec, ramKb, swapKb, diskKb, totalInstanceCount, description) { + async register(countryCode, cpuMicroSec, ramKb, swapKb, diskKb, totalInstanceCount, cpuModel, cpuCount, cpuSpeed, description) { console.log("Registering host..."); + + let cpuModelFormatted = cpuModel.replaceAll('_', ' '); const acc = this.#getConfig().xrpl; - evernode.Defaults.set({ - registryAddress: acc.registryAddress - }); + setEvernodeDefaults(acc.registryAddress, acc.rippledServer); const hostClient = new evernode.HostClient(acc.address, acc.secret); await hostClient.connect(); @@ -133,7 +151,7 @@ class Setup { while (attempts >= 0) { try { await hostClient.register(countryCode, cpuMicroSec, - Math.floor((ramKb + swapKb) / 1000), Math.floor(diskKb / 1000), totalInstanceCount, description.replace('_', ' ')); + Math.floor((ramKb + swapKb) / 1000), Math.floor(diskKb / 1000), totalInstanceCount, cpuModelFormatted.substring(0, 40), cpuCount, cpuSpeed, description.replaceAll('_', ' ')); // Create lease offers. console.log("Creating lease offers for the hosts..."); @@ -162,9 +180,7 @@ class Setup { async deregister() { console.log("Deregistering host..."); const acc = this.#getConfig().xrpl; - evernode.Defaults.set({ - registryAddress: acc.registryAddress - }); + setEvernodeDefaults(acc.registryAddress, acc.rippledServer); const hostClient = new evernode.HostClient(acc.address, acc.secret); await hostClient.connect(); @@ -179,9 +195,7 @@ class Setup { console.log(`Host account address: ${acc.address}`); if (!isBasic) { - evernode.Defaults.set({ - registryAddress: acc.registryAddress - }); + setEvernodeDefaults(acc.registryAddress, acc.rippledServer); try { const hostClient = new evernode.HostClient(acc.address); @@ -209,9 +223,13 @@ class Setup { async upgrade() { // Do a simple version change in the config. - // In the future we could have real upgrade/data migration logic here. const cfg = this.#getConfig(); cfg.version = appenv.MB_VERSION; + + // Fill missing fields. + if (!cfg.xrpl.rippledServer) + cfg.xrpl.rippledServer = appenv.DEFAULT_RIPPLED_SERVER + this.#saveConfig(cfg); await Promise.resolve(); // async placeholder. diff --git a/mb-xrpl/package-lock.json b/mb-xrpl/package-lock.json index 0415979..3316cd5 100644 --- a/mb-xrpl/package-lock.json +++ b/mb-xrpl/package-lock.json @@ -6,7 +6,7 @@ "": { "name": "mb-xrpl", "dependencies": { - "evernode-js-client": "0.4.36", + "evernode-js-client": "0.4.39", "sqlite3": "5.0.2" }, "devDependencies": { @@ -996,14 +996,15 @@ } }, "node_modules/evernode-js-client": { - "version": "0.4.36", - "resolved": "https://registry.npmjs.org/evernode-js-client/-/evernode-js-client-0.4.36.tgz", - "integrity": "sha512-mSo1ALOgPyQumYnwWL/JOBeyjBlb/wuwhRB/c56/MeHp+V+lwnYLrs/iGfNTzxjKMwYjrO5MYH/0M5ub9rIX5g==", + "version": "0.4.39", + "resolved": "https://registry.npmjs.org/evernode-js-client/-/evernode-js-client-0.4.39.tgz", + "integrity": "sha512-CLGTGUuBiPsocUpIt0WZKkBRtGcol80uBKbTlvfz9StdAU8H6zhfUMOCU5KmiPxjOWf4Bcx69z04FIwOmqmW1A==", "dependencies": { "elliptic": "6.5.4", "ripple-address-codec": "4.2.0", "ripple-keypairs": "1.1.0", - "xrpl": "2.2.1" + "xrpl": "2.2.1", + "xrpl-binary-codec": "1.4.2" } }, "node_modules/extend": { @@ -3056,6 +3057,34 @@ "node": ">=10.13.0" } }, + "node_modules/xrpl-binary-codec": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/xrpl-binary-codec/-/xrpl-binary-codec-1.4.2.tgz", + "integrity": "sha512-fYyyaiVgeCGUEplqebWl272NxOixLjb0xAIGjNUT17HytECPbUlc/0xUr9PvGLriqpZtQ3YEgpwpCPTEpFvL4A==", + "dependencies": { + "assert": "^2.0.0", + "big-integer": "^1.6.48", + "buffer": "5.6.0", + "create-hash": "^1.2.0", + "decimal.js": "^10.2.0", + "ripple-address-codec": "^4.2.3" + }, + "engines": { + "node": ">=10.22.0" + } + }, + "node_modules/xrpl-binary-codec/node_modules/ripple-address-codec": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/ripple-address-codec/-/ripple-address-codec-4.2.4.tgz", + "integrity": "sha512-roAOjKz94+FboTItey1XRh5qynwt4xvfBLvbbcx+FiR94Yw2x3LrKLF2GVCMCSAh5I6PkcpADg6AbYsUbGN3nA==", + "dependencies": { + "base-x": "3.0.9", + "create-hash": "^1.1.2" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/xrpl/node_modules/bn.js": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", @@ -3401,12 +3430,12 @@ "brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" }, "bs58": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", "requires": { "base-x": "^3.0.2" } @@ -3667,9 +3696,9 @@ } }, "es-abstract": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.0.tgz", - "integrity": "sha512-URbD8tgRthKD3YcC39vbvSDrX23upXnPcnGAjQfgxXF5ID75YcENawc9ZX/9iTP9ptUyfCLIxTTuMYoRfiOVKA==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", + "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", @@ -3690,7 +3719,7 @@ "object-inspect": "^1.12.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.4.1", + "regexp.prototype.flags": "^1.4.3", "string.prototype.trimend": "^1.0.5", "string.prototype.trimstart": "^1.0.5", "unbox-primitive": "^1.0.2" @@ -3870,14 +3899,15 @@ "dev": true }, "evernode-js-client": { - "version": "0.4.36", - "resolved": "https://registry.npmjs.org/evernode-js-client/-/evernode-js-client-0.4.36.tgz", - "integrity": "sha512-mSo1ALOgPyQumYnwWL/JOBeyjBlb/wuwhRB/c56/MeHp+V+lwnYLrs/iGfNTzxjKMwYjrO5MYH/0M5ub9rIX5g==", + "version": "0.4.39", + "resolved": "https://registry.npmjs.org/evernode-js-client/-/evernode-js-client-0.4.39.tgz", + "integrity": "sha512-CLGTGUuBiPsocUpIt0WZKkBRtGcol80uBKbTlvfz9StdAU8H6zhfUMOCU5KmiPxjOWf4Bcx69z04FIwOmqmW1A==", "requires": { "elliptic": "6.5.4", "ripple-address-codec": "4.2.0", "ripple-keypairs": "1.1.0", - "xrpl": "2.2.1" + "xrpl": "2.2.1", + "xrpl-binary-codec": "1.4.2" } }, "extend": { @@ -3951,10 +3981,13 @@ "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", "dev": true }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "requires": { + "is-callable": "^1.1.3" + } }, "forever-agent": { "version": "0.6.1", @@ -4413,14 +4446,14 @@ } }, "is-typed-array": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.8.tgz", - "integrity": "sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz", + "integrity": "sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==", "requires": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", + "es-abstract": "^1.20.0", + "for-each": "^0.3.3", "has-tostringtag": "^1.0.0" } }, @@ -4780,9 +4813,9 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==" + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.1.tgz", + "integrity": "sha512-Y/jF6vnvEtOPGiKD1+q+X0CiUYRQtEHp89MLLUJ7TUivtH8Ugn2+3A7Rynqk7BRsAoqeOQWnFnjpDrKSxDgIGA==" }, "object-is": { "version": "1.1.5", @@ -5379,16 +5412,16 @@ } }, "which-typed-array": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.7.tgz", - "integrity": "sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz", + "integrity": "sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==", "requires": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", + "es-abstract": "^1.20.0", + "for-each": "^0.3.3", "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.7" + "is-typed-array": "^1.1.9" } }, "wide-align": { @@ -5468,6 +5501,30 @@ } } }, + "xrpl-binary-codec": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/xrpl-binary-codec/-/xrpl-binary-codec-1.4.2.tgz", + "integrity": "sha512-fYyyaiVgeCGUEplqebWl272NxOixLjb0xAIGjNUT17HytECPbUlc/0xUr9PvGLriqpZtQ3YEgpwpCPTEpFvL4A==", + "requires": { + "assert": "^2.0.0", + "big-integer": "^1.6.48", + "buffer": "5.6.0", + "create-hash": "^1.2.0", + "decimal.js": "^10.2.0", + "ripple-address-codec": "^4.2.3" + }, + "dependencies": { + "ripple-address-codec": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/ripple-address-codec/-/ripple-address-codec-4.2.4.tgz", + "integrity": "sha512-roAOjKz94+FboTItey1XRh5qynwt4xvfBLvbbcx+FiR94Yw2x3LrKLF2GVCMCSAh5I6PkcpADg6AbYsUbGN3nA==", + "requires": { + "base-x": "3.0.9", + "create-hash": "^1.1.2" + } + } + } + }, "yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/mb-xrpl/package.json b/mb-xrpl/package.json index 999a421..593a111 100644 --- a/mb-xrpl/package.json +++ b/mb-xrpl/package.json @@ -5,7 +5,7 @@ "build": "npm run lint && ncc build app.js --minify -o dist" }, "dependencies": { - "evernode-js-client": "0.4.36", + "evernode-js-client": "0.4.39", "sqlite3": "5.0.2" }, "devDependencies": { diff --git a/src/conf.cpp b/src/conf.cpp index b9090b3..9988821 100644 --- a/src/conf.cpp +++ b/src/conf.cpp @@ -33,7 +33,7 @@ namespace conf * Create config here. * @return 0 for success. -1 for failure. */ - int create(std::string_view host_addr, std::string_view registry_addr, const size_t inst_count, + int create(std::string_view host_addr, const uint16_t docker_registry_port, const size_t inst_count, const size_t cpu_us, const size_t ram_kbytes, const size_t swap_kbytes, const size_t disk_kbytes) { if (util::is_file_exists(ctx.config_file)) @@ -69,9 +69,10 @@ namespace conf cfg.system.max_cpu_us = !cpu_us ? 900000 : cpu_us; // Total CPU allocation out of 1000000 microsec (1 sec). cfg.system.max_storage_kbytes = !disk_kbytes ? 5242880 : disk_kbytes; - const std::string img_prefix = registry_addr.empty() ? "evernodedev" : std::string(registry_addr); + const std::string img_prefix = "evernodedev"; cfg.docker.images["hp.latest-ubt.20.04"] = img_prefix + "/sashimono:hp.latest-ubt.20.04"; cfg.docker.images["hp.latest-ubt.20.04-njs.16"] = img_prefix + "/sashimono:hp.latest-ubt.20.04-njs.16"; + cfg.docker.registry_port = docker_registry_port; cfg.log.max_file_count = 50; cfg.log.max_mbytes_per_file = 10; @@ -269,6 +270,9 @@ namespace conf for (const auto &elem : docker["images"].object_range()) cfg.docker.images[elem.key()] = elem.value().as(); + + if (docker.contains("registry_port")) + cfg.docker.registry_port = docker["registry_port"].as(); } catch (const std::exception &e) { @@ -300,6 +304,10 @@ namespace conf } } + // If docker registry port is 0, we assume there's no private docker registry. + if (cfg.docker.registry_port > 0) + cfg.docker.registry_address = cfg.hp.host_address + ":" + std::to_string(cfg.docker.registry_port); + return 0; } @@ -346,6 +354,7 @@ namespace conf for (const auto &[key, name] : cfg.docker.images) images.insert_or_assign(key, name); docker_config.insert_or_assign("images", images); + docker_config.insert_or_assign("registry_port", cfg.docker.registry_port); d.insert_or_assign("docker", docker_config); } @@ -412,7 +421,7 @@ namespace conf * Convert string to Log Severity enum type. * @param severity log severity code. * @return log severity type. - */ + */ LOG_SEVERITY get_loglevel_type(std::string_view severity) { if (severity == "dbg") diff --git a/src/conf.hpp b/src/conf.hpp index d40bca8..8355d62 100644 --- a/src/conf.hpp +++ b/src/conf.hpp @@ -85,6 +85,8 @@ namespace conf struct docker_config { std::unordered_map images; + uint16_t registry_port = 0; // 0 means bypass private docker registry. + std::string registry_address; // This is dynamically constructed at load time. }; struct sa_config @@ -123,7 +125,7 @@ namespace conf int init(); - int create(std::string_view host_addr, std::string_view registry_addr, const size_t inst_count, + int create(std::string_view host_addr, const uint16_t docker_registry_port, const size_t inst_count, const size_t cpu_us, const size_t ram_kbytes, const size_t swap_kbytes, const size_t disk_kbytes); void set_dir_paths(std::string exepath, std::string datadir); diff --git a/src/hp_manager.cpp b/src/hp_manager.cpp index 6237098..1ff4abb 100644 --- a/src/hp_manager.cpp +++ b/src/hp_manager.cpp @@ -851,7 +851,8 @@ namespace hp std::to_string(contract_ugid.gid), std::to_string(instance_ports.peer_port), std::to_string(instance_ports.user_port), - docker_image}; + docker_image, + conf::cfg.docker.registry_address}; std::vector output_params; if (util::execute_bash_file(conf::ctx.user_install_sh, output_params, input_params) == -1) return -1; diff --git a/src/main.cpp b/src/main.cpp index 8255a18..b9c342e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -132,17 +132,20 @@ int main(int argc, char **argv) // This will create a new config. const std::string host_addr = (argc >= 4) ? argv[3] : ""; + uint16_t docker_registry_port = 0; size_t inst_count = 0, cpu_us = 0, ram_kbytes = 0, swap_kbytes = 0, disk_kbytes = 0; - if (((argc >= 5) && (util::stoull(argv[4], inst_count) != 0 || inst_count == 0)) || - ((argc >= 6) && (util::stoull(argv[5], cpu_us) != 0 || cpu_us == 0)) || - ((argc >= 7) && (util::stoull(argv[6], ram_kbytes) != 0 || ram_kbytes == 0)) || - ((argc >= 8) && (util::stoull(argv[7], swap_kbytes) != 0 || swap_kbytes == 0)) || - ((argc >= 9) && (util::stoull(argv[8], disk_kbytes) != 0 || disk_kbytes == 0)) || - conf::create(host_addr, "", inst_count, cpu_us, ram_kbytes, swap_kbytes, disk_kbytes) != 0) + if (((argc >= 5) && util::stoul(argv[4], docker_registry_port) != 0) || + ((argc >= 6) && (util::stoull(argv[5], inst_count) != 0 || inst_count == 0)) || + ((argc >= 7) && (util::stoull(argv[6], cpu_us) != 0 || cpu_us == 0)) || + ((argc >= 8) && (util::stoull(argv[7], ram_kbytes) != 0 || ram_kbytes == 0)) || + ((argc >= 9) && (util::stoull(argv[8], swap_kbytes) != 0 || swap_kbytes == 0)) || + ((argc >= 10) && (util::stoull(argv[9], disk_kbytes) != 0 || disk_kbytes == 0)) || + conf::create(host_addr, docker_registry_port, inst_count, cpu_us, ram_kbytes, swap_kbytes, disk_kbytes) != 0) { std::cerr << "Invalid Sashimono Agent config creation args.\n"; - std::cerr << inst_count << ", " << cpu_us << ", " << ram_kbytes << ", " << swap_kbytes << ", " << disk_kbytes << "\n"; + std::cerr << docker_registry_port << ", " << inst_count << ", " << cpu_us << ", " << ram_kbytes << ", " + << swap_kbytes << ", " << disk_kbytes << "\n"; return 1; } } @@ -195,8 +198,11 @@ int main(int argc, char **argv) salog::init(); // Do a simple version change in the config. - // In the future we could have real upgrade/data migration logic here. conf::cfg.version = version::AGENT_VERSION; + + if (conf::cfg.docker.registry_port == 0) + conf::cfg.docker.registry_port = 4444; + if (conf::write_config(conf::cfg) != 0) return -1; } diff --git a/src/util/util.cpp b/src/util/util.cpp index 4397996..4a187ab 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -39,7 +39,7 @@ namespace util } /** - * Check whether given directory exists. + * Check whether given directory exists. * @param path Directory path. * @return Returns true if given directory exists otherwise false. */ @@ -50,7 +50,7 @@ namespace util } /** - * Check whether given file exists. + * Check whether given file exists. * @param path File path. * @return Returns true if give file exists otherwise false. */ @@ -61,7 +61,7 @@ namespace util } /** - * Recursively creates directories and sub-directories if not exist. + * Recursively creates directories and sub-directories if not exist. * @param path Directory path. * @return Returns 0 operations succeeded otherwise -1. */ @@ -99,12 +99,12 @@ namespace util } /** - * Reads the entire file from given file discriptor. + * Reads the entire file from given file discriptor. * @param fd File descriptor to be read. * @param buf String buffer to be populated. * @param offset Begin offset of the file to read. * @return Returns number of bytes read in a successful read and -1 on error. - */ + */ int read_from_fd(const int fd, std::string &buf, const off_t offset) { struct stat st; @@ -123,7 +123,7 @@ namespace util * Provide a safe std::string overload for realpath. * @param path Path. * @returns Returns the realpath as string. - */ + */ const std::string realpath(std::string_view path) { std::array buffer; @@ -174,8 +174,8 @@ namespace util } /** - * Returns current time in UNIX epoch milliseconds. - */ + * Returns current time in UNIX epoch milliseconds. + */ uint64_t get_epoch_milliseconds() { return std::chrono::duration_cast>( @@ -218,7 +218,7 @@ namespace util * Split string by given delimeter. * @param collection Splitted strings params. * @param delimeter Delimeter to split string. - */ + */ void split_string(std::vector &collection, std::string_view str, std::string_view delimeter) { if (str.empty()) @@ -242,11 +242,11 @@ namespace util } /** - * Converts given string to a int. A wrapper function for std::stoi. + * Converts given string to a int. A wrapper function for std::stoi. * @param str String variable. * @param result Variable to store the answer from the conversion. * @return Returns 0 in a successful conversion and -1 on error. - */ + */ int stoi(const std::string &str, int &result) { try @@ -262,11 +262,11 @@ namespace util } /** - * Converts given string to a uint16_t. A wrapper function for std::stoul. + * Converts given string to a uint16_t. A wrapper function for std::stoul. * @param str String variable. * @param result Variable to store the answer from the conversion. * @return Returns 0 in a successful conversion and -1 on error. - */ + */ int stoul(const std::string &str, uint16_t &result) { try @@ -282,11 +282,11 @@ namespace util } /** - * Converts given string to a uint_64. A wrapper function for std::stoull. + * Converts given string to a uint_64. A wrapper function for std::stoull. * @param str String variable. * @param result Variable to store the answer from the conversion. * @return Returns 0 in a successful conversion and -1 on error. - */ + */ int stoull(const std::string &str, uint64_t &result) { try @@ -305,7 +305,7 @@ namespace util * Construct the user contract directory path when username is given. * @param username Username of the user. * @return Contract directory path. - */ + */ const std::string get_user_contract_dir(const std::string &username, std::string_view container_name) { return "/home/" + username + "/" + container_name.data(); @@ -316,7 +316,7 @@ namespace util * @param username Username of the user. * @param user_info User info struct to be populated. * @return -1 of error, 0 on success. - */ + */ int get_system_user_info(std::string_view username, user_info &user_info) { const struct passwd *pwd = getpwnam(username.data()); @@ -339,7 +339,7 @@ namespace util * @param str String to be modified. * @param find Substring to be searched. * @param replace Substring to be replaced. - */ + */ void find_and_replace(std::string &str, std::string_view find, std::string_view replace) { size_t pos = str.find(find); @@ -418,13 +418,15 @@ namespace util * @param file_name Name of the bash script. * @param output_params Final output of the bash script. * @param input_params Input parameters to the bash script (Optional). - */ + */ int execute_bash_file(std::string_view file_name, std::vector &output_params, const std::vector &input_params) { std::string params = ""; for (auto itr = input_params.begin(); itr != input_params.end(); itr++) { - params.append(*itr); + // Empty params are appended as '-' to preserve param order. + params.append(itr->empty() ? "-" : *itr); + if (std::next(itr) != input_params.end()) params.append(" "); } @@ -466,7 +468,7 @@ namespace util * @param output Pointer to populate output. * @param output_len Length of the output. * @return 0 on success and -1 on error. - */ + */ int execute_bash_cmd(const char *command, char *output, const int output_len) { FILE *fpipe = popen(command, "r");