#!/bin/bash # Evernode host setup tool to manage Sashimono installation and host registration. # This script is also used as the 'evernode' cli alias after the installation. # usage: ./setup.sh install evernode="Evernode beta" maxmind_creds="687058:FtcQjM0emHFMEfgI" cgrulesengd_default="cgrulesengd" alloc_ratio=80 ramKB_per_instance=524288 instances_per_core=3 evernode_alias=/usr/bin/evernode log_dir=/tmp/evernode-beta cloud_storage="https://stevernode.blob.core.windows.net/evernode-dev" setup_script_url="$cloud_storage/setup.sh" installer_url="$cloud_storage/installer.tar.gz" licence_url="$cloud_storage/licence.txt" installer_version_timestamp_file="installer.version.timestamp" setup_version_timestamp_file="setup.version.timestamp" # export vars used by Sashimono installer. export USER_BIN=/usr/bin export SASHIMONO_BIN=/usr/bin/sashimono export MB_XRPL_BIN=$SASHIMONO_BIN/mb-xrpl export DOCKER_BIN=$SASHIMONO_BIN/dockerbin export SASHIMONO_DATA=/etc/sashimono export MB_XRPL_DATA=$SASHIMONO_DATA/mb-xrpl export SASHIMONO_SERVICE="sashimono-agent" export CGCREATE_SERVICE="sashimono-cgcreate" export MB_XRPL_SERVICE="sashimono-mb-xrpl" export SASHIADMIN_GROUP="sashiadmin" export SASHIUSER_GROUP="sashiuser" export SASHIUSER_PREFIX="sashi" export MB_XRPL_USER="sashimbxrpl" export CG_SUFFIX="-cg" export EVERNODE_REGISTRY_ADDRESS="raaFre81618XegCrzTzVotAmarBcqNSAvK" export EVERNODE_AUTO_UPDATE_SERVICE="evernode-auto-update" # 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 # Helper to print multi line text. # (When passed as a parameter, bash auto strips spaces and indentation which is what we want) function echomult() { echo -e $1 } # The set of commands supported differs based on whether Sashimono is installed or not. if ! $sashimono_installed ; then # If sashimono is not installed but there's a sashimono binary directory, The previous installation is a failed attempt. # So, user can reinstall or uninstall the previous partial failed attempt. if [ ! -d $SASHIMONO_BIN ] ; then [ "$1" != "install" ] \ && echomult "$evernode host management tool \nYour system is not registered on $evernode. \nSupported commands: \ninstall - Install Sashimono and register on $evernode"\ && exit 1 else [ "$1" != "install" ] && [ "$1" != "uninstall" ] \ && echomult "$evernode host management tool \nYour system has a previous failed partial $evernode installation. \nSupported commands: \ninstall - Re-install Sashimono and register on $evernode \nuninstall - Uninstall previous $evernode installations"\ && exit 1 fi else [ "$1" == "install" ] \ && echo "$evernode is already installed on your host. Use the 'evernode' command to manage your host." \ && exit 1 [ "$1" != "install" ] && [ "$1" != "uninstall" ] && [ "$1" != "status" ] && [ "$1" != "list" ] && [ "$1" != "update" ] && [ "$1" != "log" ] \ && echomult "$evernode host management tool \nYour host is registered on $evernode. \nSupported commands: \nstatus - View $evernode registration info \nlist - View contract instances running on this system \nlog - Generate evernode log file. \nupdate - Check and install $evernode software updates \nuninstall - Uninstall and deregister from $evernode" \ && exit 1 fi mode=$1 if [ "$mode" == "install" ] || [ "$mode" == "uninstall" ] || [ "$mode" == "update" ] || [ "$mode" == "log" ] ; then [ -n "$2" ] && [ "$2" != "-q" ] && [ "$2" != "-i" ] && echo "Second arg must be -q (Quiet) or -i (Interactive)" && exit 1 [ "$2" == "-q" ] && interactive=false || interactive=true [ "$EUID" -ne 0 ] && echo "Please run with root privileges (sudo)." && exit 1 fi function confirm() { echo -en $1" [Y/n] " local yn="" read yn &1 \ | tee -a $logfile | stdbuf --output=L grep "STAGE" | cut -d ' ' -f 2- && install_failure fi # Create evernode cli alias at the begining. # So, if the installation attempt failed user can uninstall the failed installation using evernode commands. ! create_evernode_alias && install_failure # 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. ! UPGRADE=$upgrade ./sashimono-install.sh $inetaddr $init_peer_port $init_user_port $countrycode $alloc_instcount \ $alloc_cpu $alloc_ramKB $alloc_swapKB $alloc_diskKB $description $lease_amount 2>&1 \ | tee -a $logfile | stdbuf --output=L grep "STAGE" \ | while read line ; do [[ $line =~ ^STAGE[[:space:]]-p(.*)$ ]] && echo -e \\e[1A\\e[K"${line:9}" || echo ${line:6} ; done \ && remove_evernode_alias && install_failure set +o pipefail rm -r $tmp # Write the verison timestamp to a file for later updated version comparison. echo $installer_version_timestamp > $SASHIMONO_DATA/$installer_version_timestamp_file echo $setup_version_timestamp > $SASHIMONO_DATA/$setup_version_timestamp_file } function uninstall_evernode() { local upgrade=$1 # Check for existing contract instances. local users=$(cut -d: -f1 /etc/passwd | grep "^$SASHIUSER_PREFIX" | sort) readarray -t userarr <<<"$users" local sashiusers=() for user in "${userarr[@]}"; do [ ${#user} -lt 24 ] || [ ${#user} -gt 32 ] || [[ ! "$user" =~ ^$SASHIUSER_PREFIX[0-9]+$ ]] && continue sashiusers+=("$user") done local ucount=${#sashiusers[@]} if [ "$upgrade" == "0" ] ; then $interactive && [ $ucount -gt 0 ] && ! confirm "This will delete $ucount contract instances. \n\nDo you still want to uninstall?" && exit 1 ! $interactive && echo "$ucount contract instances will be deleted." fi [ "$upgrade" == "0" ] && echo "Uninstalling..." || echo "Uninstalling for upgrade..." ! UPGRADE=$upgrade $SASHIMONO_BIN/sashimono-uninstall.sh $2 && uninstall_failure # Remove the evernode alias at the end. # So, if the uninstallation failed user can try uninstall again with evernode commands. remove_evernode_alias } function update_evernode() { echo "Checking for updates..." local latest_installer_script_version=$(online_version_timestamp $installer_url) local latest_setup_script_version=$(online_version_timestamp $setup_script_url) [ -z "$latest_installer_script_version" ] && echo "Could not check for updates. Online installer not found." && exit 1 local current_installer_script_version=$(cat $SASHIMONO_DATA/$installer_version_timestamp_file) local current_setup_script_version=$(cat $SASHIMONO_DATA/$setup_version_timestamp_file) [ "$latest_installer_script_version" == "$current_installer_script_version" ] && [ "$latest_setup_script_version" == "$current_setup_script_version" ] && echo "Your $evernode installation is up to date." && exit 0 echo "New $evernode update available. Setup will re-install $evernode with updated software. Your account and contract instances will be preserved." $interactive && ! confirm "\nDo you want to install the update?" && exit 1 echo "Starting upgrade..." # Alias for setup.sh is created during 'install_evernode' too. # If only the setup.sh is updated but not the installer, then the alias should be created again. if [ "$latest_installer_script_version" != "$current_installer_script_version" ] ; then uninstall_evernode 1 install_evernode 1 elif [ "$latest_setup_script_version" != "$current_setup_script_version" ] ; then [ -d $log_dir ] || mkdir -p $log_dir logfile="$log_dir/installer-$(date +%s).log" ! create_evernode_alias && echo "Alias creation failed." echo $latest_setup_script_version > $SASHIMONO_DATA/$setup_version_timestamp_file fi echo "Upgrade complete." } function create_log() { tempfile=$(mktemp /tmp/evernode.XXXXXXXXX.log) { echo "System:" uname -r lsb_release -a echo "" echo "sa.cfg:" cat "$SASHIMONO_DATA/sa.cfg" echo "" echo "mb-xrpl.cfg:" cat "$MB_XRPL_DATA/mb-xrpl.cfg" echo "" echo "Sashimono log:" journalctl -u sashimono-agent.service | tail -n 200 echo "" echo "Message board log:" sudo -u sashimbxrpl bash -c journalctl --user -u sashimono-mb-xrpl | tail -n 200 echo "" echo "Auto updater service log:" journalctl -u evernode-auto-update | tail -n 200 } > "$tempfile" 2>&1 echo "Evernode log saved to $tempfile" } # Create a copy of this same script as a command. function create_evernode_alias() { ! curl -fsSL $setup_script_url --output $evernode_alias >> $logfile 2>&1 && echo "Error in creating alias." && return 1 ! chmod +x $evernode_alias >> $logfile 2>&1 && echo "Error in changing permission for the alias." && return 1 return 0 } function remove_evernode_alias() { rm $evernode_alias } function check_installer_pending_finish() { if [ -f /run/reboot-required.pkgs ] && [ -n "$(grep sashimono /run/reboot-required.pkgs)" ]; then echo "Your system needs to be rebooted in order to complete Sashimono installation." $interactive && confirm "Reboot now?" && reboot ! $interactive && echo "Rebooting..." && reboot return 0 else # If reboot not required, check whether re-login is required in case the setup was run with sudo. # This is because the user account gets added to sashiadmin group and re-login is needed for group permission to apply. # without this, user cannot run "sashi" cli commands without sudo. if [ "$mode" == "install" ] && [ -n "$SUDO_USER" ] ; then echo "You need to logout and log back in, to complete Sashimono installation." return 0 else return 1 fi fi } function reg_info() { echo "" if MB_DATA_DIR=$MB_XRPL_DATA node $MB_XRPL_BIN reginfo ; then echo -e "\nYour account details are stored in $MB_XRPL_DATA/mb-xrpl.cfg and $MB_XRPL_DATA/secret.cfg." fi } # Begin setup execution flow -------------------- echo "Thank you for trying out $evernode!" if [ "$mode" == "install" ]; then if ! $interactive ; then inetaddr=${3} # IP or DNS address. init_peer_port=${4} # Starting peer port for instances. init_user_port=${5} # Starting user port for instances. countrycode=${6} # 2-letter country code. alloc_cpu=${7} # CPU microsec to allocate for contract instances (max 1000000). alloc_ramKB=${8} # RAM to allocate for contract instances. alloc_swapKB=${9} # Swap to allocate for contract instances. alloc_diskKB=${10} # Disk space to allocate for contract instances. alloc_instcount=${11} # Total contract instance count. lease_amount=${12} # Contract instance lease amount in EVRs. fi $interactive && ! confirm "This will install Sashimono, Evernode's contract instance management software, and register your system as an $evernode host.\n \nThe setup will go through the following steps:\n - Check your system compatibility for $evernode.\n - Collect information about your system to be published to users.\n - Generate a testnet XRPL account to receive $evernode hosting rewards.\n \nContinue?" && exit 1 check_sys_req # Check bc command is installed. if ! command -v bc &>/dev/null; then echo "bc command not found. Installing.." apt-get -y install bc >/dev/null fi # Display licence file and ask for concent. printf "\n*****************************************************************************************************\n\n" curl --silent $licence_url | cat printf "\n\n*****************************************************************************************************\n" $interactive && ! confirm "\nDo you accept the terms of the licence agreement?" && exit 1 $interactive && ! confirm "Make sure your system does not currently contain any other workloads important to you since we will be making modifications to your system configuration. \nThis is beta software, so there's a chance things can go wrong. \n\nContinue?" && exit 1 set_inet_addr echo -e "Using '$inetaddr' as host internet address.\n" set_country_code echo -e "Using '$countrycode' as country code.\n" set_cgrules_svc echo -e "Using '$cgrulesengd_service' as cgroups rules engine service.\n" set_instance_alloc echo -e "Using allocation $(GB $alloc_ramKB) RAM, $(GB $alloc_swapKB) Swap, $(GB $alloc_diskKB) disk space, $alloc_instcount contract instances.\n" set_init_ports echo -e "Using port ranges (Peer: $init_peer_port-$((init_peer_port + alloc_instcount)), User: $init_user_port-$((init_user_port + alloc_instcount))).\n" set_lease_amount # Commented for future consideration. # (( $(echo "$lease_amount > 0" |bc -l) )) && echo -e "Using lease amount $lease_amount EVRs.\n" || echo -e "Using anchor tenant target price as lease amount.\n" (( $(echo "$lease_amount > 0" |bc -l) )) && echo -e "Using lease amount $lease_amount EVRs.\n" echo "Starting installation..." install_evernode 0 echomult "Installation successful! Installation log can be found at $logfile \n\nYour system is now registered on $evernode. You can check your system status with 'evernode status' command." elif [ "$mode" == "uninstall" ]; then # echomult "\nWARNING! Uninstalling will deregister your host from $evernode and you will LOSE YOUR XRPL ACCOUNT credentials # stored in '$MB_XRPL_DATA/mb-xrpl.cfg' and '$MB_XRPL_DATA/secret.cfg'. This is irreversible. Make sure you have your account address and # secret elsewhere before proceeding.\n" # $interactive && ! confirm "\nHave you read above warning and backed up your account credentials?" && exit 1 $interactive && ! confirm "\nAre you sure you want to uninstall $evernode?" && exit 1 # Force uninstall on quiet mode. $interactive && uninstall_evernode 0 || uninstall_evernode 0 -f echo "Uninstallation complete!" elif [ "$mode" == "status" ]; then reg_info elif [ "$mode" == "list" ]; then sashi list elif [ "$mode" == "update" ]; then update_evernode elif [ "$mode" == "log" ]; then create_log fi [ "$mode" != "uninstall" ] && check_installer_pending_finish exit 0