From 3df2fe4586beb03a2cecda538016ff1f053ec332 Mon Sep 17 00:00:00 2001 From: Kithmini Gunawardhana Date: Mon, 14 Oct 2024 09:16:09 +0530 Subject: [PATCH] Ubuntu 24 Support for Sashimono (#416) --- dependencies/user-cgcreate.sh | 101 +++++++++--------- dependencies/user-install.sh | 47 ++++++-- dependencies/user-uninstall.sh | 29 ++--- installer/docker-install.sh | 4 +- installer/prereq.sh | 178 ++++++++++++++----------------- installer/sashimono-install.sh | 33 +----- installer/sashimono-uninstall.sh | 20 +--- installer/setup.sh | 42 +++----- mb-xrpl/lib/appenv.js | 2 +- reputationd | 2 +- src/hp_manager.cpp | 52 +-------- src/version.hpp | 2 +- 12 files changed, 211 insertions(+), 301 deletions(-) diff --git a/dependencies/user-cgcreate.sh b/dependencies/user-cgcreate.sh index b214759..9e4924e 100755 --- a/dependencies/user-cgcreate.sh +++ b/dependencies/user-cgcreate.sh @@ -15,62 +15,67 @@ if [ ! -f "$saconfig" ]; then exit 1 fi -# Calculate resources +# Function to create or update cgroup limits based on user and process +apply_limits() { -# Read config values -max_mem_kbytes=$(jq '.system.max_mem_kbytes' $saconfig) -max_swap_kbytes=$(jq '.system.max_swap_kbytes' $saconfig) -max_cpu_us=$(jq '.system.max_cpu_us' $saconfig) -max_instance_count=$(jq '.system.max_instance_count' $saconfig) + echo "Apply limits $1" -([ "$max_instance_count" == "" ] || [ ${#max_instance_count} -eq 0 ] || [ "$max_instance_count" -le 0 ]) && echo "max_instance_count cannot be empty." && exit 1 + local user=$1 + local user_id=$(id -u $user) + local max_mem_kbytes=$(jq '.system.max_mem_kbytes' $saconfig) + local max_swap_kbytes=$(jq '.system.max_swap_kbytes' $saconfig) + local max_cpu_us=$(jq '.system.max_cpu_us' $saconfig) + local max_instance_count=$(jq '.system.max_instance_count' $saconfig) + local cores=$(grep -c ^processor /proc/cpuinfo) -instance_mem_kbytes=0 -if [ "$max_mem_kbytes" != "" ] && [ ! ${#max_mem_kbytes} -eq 0 ] && [ "$max_mem_kbytes" -gt 0 ]; then - ! instance_mem_kbytes=$(expr $max_mem_kbytes / $max_instance_count) && echo "Max memory limit calculation error." && exit 1 + ([ "$max_instance_count" == "" ] || [ ${#max_instance_count} -eq 0 ] || [ "$max_instance_count" -le 0 ]) && echo "max_instance_count cannot be empty." && exit 1 + + local instance_mem_kbytes=0 + if [ "$max_mem_kbytes" != "" ] && [ ! ${#max_mem_kbytes} -eq 0 ] && [ "$max_mem_kbytes" -gt 0 ]; then + ! instance_mem_kbytes=$(expr $max_mem_kbytes / $max_instance_count) && echo "Max memory limit calculation error." && exit 1 + fi + + local instance_swap_kbytes=0 + if [ "$max_swap_kbytes" != "" ] && [ ! ${#max_swap_kbytes} -eq 0 ] && [ "$max_swap_kbytes" -gt 0 ]; then + ! instance_swap_kbytes=$(expr $instance_mem_kbytes + $max_swap_kbytes / $max_instance_count) && echo "Max swap memory limit calculation error." && exit 1 + fi + + local instance_cpu_quota=0 + # In the Sashimono configuration, CPU time is 1000000us Sashimono is given max_cpu_us out of it. + # Instance allocation is multiplied by number of cores to determined the number of cores per instance and devided by 10 since cfs_period_us is set to 100000us + + local CPU_PERIOD="1000000" # in microseconds + if [ "$max_cpu_us" != "" ] && [ ! ${#max_cpu_us} -eq 0 ] && [ "$max_cpu_us" -gt 0 ]; then + cores=$(grep -c ^processor /proc/cpuinfo) + ! instance_cpu_quota=$(expr $(expr $cores \* $max_cpu_us \* 100) / $(expr $max_instance_count \* $CPU_PERIOD)) && echo "Max cpu limit calculation error." && exit 1 + fi + + echo "[Slice] +CPUQuota=${instance_cpu_quota}% +MemoryMax=${instance_mem_kbytes}K +MemorySwapMax=${instance_swap_kbytes}K" | sudo tee /etc/systemd/system/user-$user_id.slice.d/override.conf + + sudo systemctl daemon-reload + sudo systemctl restart user-$user_id.slice +} + +osversion=$(grep -ioP '^VERSION_ID="\K[^"]+' /etc/os-release) + +if [ "$osversion" == "24.04" ]; then + # Allow unpriviledged user namespaces (By Default restricted in Ubuntu 24.04) + sudo sysctl -w kernel.apparmor_restrict_unprivileged_unconfined=0 + sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 fi -instance_swap_kbytes=0 -if [ "$max_swap_kbytes" != "" ] && [ ! ${#max_swap_kbytes} -eq 0 ] && [ "$max_swap_kbytes" -gt 0 ]; then - ! instance_swap_kbytes=$(expr $instance_mem_kbytes + $max_swap_kbytes / $max_instance_count) && echo "Max swap memory limit calculation error." && exit 1 -fi - -instance_cpu_quota=0 -# In the Sashimono configuration, CPU time is 1000000us Sashimono is given max_cpu_us out of it. -# Instance allocation is multiplied by number of cores to determined the number of cores per instance and devided by 10 since cfs_period_us is set to 100000us -if [ "$max_cpu_us" != "" ] && [ ! ${#max_cpu_us} -eq 0 ] && [ "$max_cpu_us" -gt 0 ]; then - cores=$(grep -c ^processor /proc/cpuinfo) - ! instance_cpu_quota=$(expr $(expr $cores \* $max_cpu_us) / $(expr $max_instance_count \* 10)) && echo "Max cpu limit calculation error." && exit 1 -fi - -prefix="sashi" -cgroupsuffix="-cg" -users=$(cut -d: -f1 /etc/passwd | grep "^$prefix" | sort) +# Monitor processes and assign them to appropriate cgroups +# Get usernames matching the pattern +users=$(cut -d: -f1 /etc/passwd | grep "^sashi" | sort) readarray -t userarr <<<"$users" -validusers=() -for user in "${userarr[@]}"; do - [ ${#user} -lt 24 ] || [ ${#user} -gt 32 ] || [[ ! "$user" =~ ^$prefix[0-9]+$ ]] && continue - validusers+=("$user") -done has_err=0 -for user in "${validusers[@]}"; do - # Setup user cgroup. - if [ $instance_cpu_quota -gt 0 ] && - ! (cgcreate -g cpu:$user$cgroupsuffix && - echo "100000" >/sys/fs/cgroup/cpu/$user$cgroupsuffix/cpu.cfs_period_us && - echo "$instance_cpu_quota" >/sys/fs/cgroup/cpu/$user$cgroupsuffix/cpu.cfs_quota_us); then - echo "CPU cgroup creation for $user failed." - has_err=1 - fi - - if [ $instance_mem_kbytes -gt 0 ] && - ! (cgcreate -g memory:$user$cgroupsuffix && - echo "${instance_mem_kbytes}K" >/sys/fs/cgroup/memory/$user$cgroupsuffix/memory.limit_in_bytes && - echo "${instance_swap_kbytes}K" >/sys/fs/cgroup/memory/$user$cgroupsuffix/memory.memsw.limit_in_bytes); then - echo "Memory cgroup creation for $user failed." - has_err=1 - fi +for user in "${userarr[@]}"; do + [ ${#user} -lt 24 ] || [ ${#user} -gt 32 ] || [[ ! "$user" =~ ^sashi[0-9]+$ ]] && continue + ! apply_limits "$user" && has_err=1 done [ $has_err -eq 1 ] && exit 1 diff --git a/dependencies/user-install.sh b/dependencies/user-install.sh index 1285e8a..7cced5c 100755 --- a/dependencies/user-install.sh +++ b/dependencies/user-install.sh @@ -41,13 +41,11 @@ docker_pull_timeout_secs=120 cleanup_script=$user_dir/uninstall_cleanup.sh gp_udp_port_count=2 gp_tcp_port_count=2 +osversion=$(grep -ioP '^VERSION_ID=\K.+' /etc/os-release | tr -d '"') # Check if users already exists. [ "$(id -u "$user" 2>/dev/null || echo -1)" -ge 0 ] && echo "HAS_USER,INST_ERR" && exit 1 -# Check cgroup mounts exists. -{ [ ! -d /sys/fs/cgroup/cpu ] || [ ! -d /sys/fs/cgroup/memory ]; } && echo "CGROUP_ERR,INST_ERR" && exit 1 - function rollback() { echo "Rolling back user installation. $1" "$script_dir"/user-uninstall.sh "$user" @@ -199,6 +197,23 @@ for ((i = 0; i < $gp_tcp_port_count; i++)); do fi done +# Creating AppArmor Profile for unpriviledged user on Ubuntu 24.04 +if [ "$osversion" == "24.04" ]; then + filename=$(echo /home/$user/bin/rootlesskit | sed -e s@^/@@ -e s@/@.@g) + cat < /etc/apparmor.d/$filename +abi , +include + +"/home/$user/bin/rootlesskit" flags=(unconfined) { + userns, + + include if exists +} +EOF + chown $user:$user /etc/apparmor.d/$filename + systemctl restart apparmor.service +fi + 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 @@ -303,15 +318,25 @@ sudo -u "$user" XDG_RUNTIME_DIR="$user_runtime_dir" systemctl --user daemon-relo # In the Sashimono configuration, CPU time is 1000000us Sashimono is given max_cpu_us out of it. # Instance allocation is multiplied by number of cores to determined the number of cores per instance and devided by 10 since cfs_period_us is set to 100000us cores=$(grep -c ^processor /proc/cpuinfo) -cpu_quota=$(expr $(expr $cores \* $cpu) / 10) +cpu_period=1000000 +cpu_quota=$(expr $(expr $cores \* $cpu \* 100 \/ $cpu_period)) + echo "Setting up user cgroup resources." -! (cgcreate -g cpu:$user$cgroupsuffix && - echo "100000" >/sys/fs/cgroup/cpu/$user$cgroupsuffix/cpu.cfs_period_us && - echo "$cpu_quota" >/sys/fs/cgroup/cpu/$user$cgroupsuffix/cpu.cfs_quota_us) && rollback "CGROUP_CPU_CREAT" -! (cgcreate -g memory:$user$cgroupsuffix && - echo "${memory}K" >/sys/fs/cgroup/memory/$user$cgroupsuffix/memory.limit_in_bytes && - echo "${swapmem}K" >/sys/fs/cgroup/memory/$user$cgroupsuffix/memory.memsw.limit_in_bytes) && rollback "CGROUP_MEM_CREAT" -echo "Configured user cgroup resources." + +# Resource limiting for the unpriviledged user +mkdir /etc/systemd/system/user-$user_id.slice.d +touch /etc/systemd/system/user-$user_id.slice.d/override.conf + +echo "[Slice] +Slice=user.slice +MemoryMax=${memory}K +CPUQuota=${cpu_quota}% +MemorySwapMax=${swapmem}K" | sudo tee /etc/systemd/system/user-$user_id.slice.d/override.conf + +# Add all current members of the group to the cgroup +# apply_cgroups $user + +systemctl daemon-reload echo "$user_id,$user,$dockerd_socket,INST_SUC" exit 0 \ No newline at end of file diff --git a/dependencies/user-uninstall.sh b/dependencies/user-uninstall.sh index 532c057..3cb0e38 100755 --- a/dependencies/user-uninstall.sh +++ b/dependencies/user-uninstall.sh @@ -32,15 +32,7 @@ docker_bin=$script_dir/dockerbin cleanup_script=$user_dir/uninstall_cleanup.sh gp_udp_port_count=2 gp_tcp_port_count=2 - -function cgrulesengd_servicename() { - # Find the cgroups rules engine service. - local cgrulesengd_filepath=$(grep "ExecStart.*=.*/cgrulesengd$" /etc/systemd/system/*.service | head -1 | awk -F : ' { print $1 } ') - if [ -n "$cgrulesengd_filepath" ]; then - local cgrulesengd_filename=$(basename $cgrulesengd_filepath) - echo "${cgrulesengd_filename%.*}" - fi -} +osversion=$(grep -ioP '^VERSION_ID=\K.+' /etc/os-release | tr -d '"') echo "Uninstalling user '$user'." @@ -80,10 +72,8 @@ while true; do pkill -SIGKILL -u "$user" done -echo "Removing cgroups" -# Delete config values. -cgdelete -g cpu:$user$cgroupsuffix -cgdelete -g memory:$user$cgroupsuffix +echo "Removing cgroups user slice override configuration" +sudo rmdir /etc/systemd/system/user-$user_id.slice.d # Removing applied disk quota of the user before deleting. setquota -g -F vfsv0 "$user" 0 0 0 0 / @@ -151,17 +141,20 @@ if [ -f $cleanup_script ]; then /bin/bash -c $cleanup_script fi +# Removing AppArmor Profile +if [ "$osversion" == "24.04" ]; then + echo "Removing AppArmor Profile '$user'" + [ -f "/etc/apparmor.d/home.${user}.bin.rootlesskit" ] && sudo rm -r "/etc/apparmor.d/home.${user}.bin.rootlesskit" +fi + echo "Deleting user '$user'" userdel "$user" rm -r /home/"${user:?}" # Even though we are creating a group specifically, # It'll be automatically deleted when we delete the user. -cgrulesengd_service=$(cgrulesengd_servicename) -if [ ! -z "$cgrulesengd_service" ]; then - echo "Restarting the '$cgrulesengd_service' service..." - systemctl restart $cgrulesengd_service -fi +# Removing process and file desctiptor limitations for the user after user deletion. +sudo sed -i "/^$user/d" /etc/security/limits.conf # Removing process and file desctiptor limitations for the user after user deletion. sudo sed -i "/^$user/d" /etc/security/limits.conf diff --git a/installer/docker-install.sh b/installer/docker-install.sh index 2053944..c18e48a 100755 --- a/installer/docker-install.sh +++ b/installer/docker-install.sh @@ -13,8 +13,8 @@ if [ -z "$(ls -A $docker_bin 2>/dev/null)" ]; then tmp=$(mktemp -d) cd $tmp - curl -s https://download.docker.com/linux/static/stable/x86_64/docker-24.0.5.tgz --output docker.tgz - curl -s https://download.docker.com/linux/static/stable/x86_64/docker-rootless-extras-24.0.5.tgz --output rootless.tgz + curl -s https://download.docker.com/linux/static/stable/x86_64/docker-27.0.1.tgz --output docker.tgz + curl -s https://download.docker.com/linux/static/stable/x86_64/docker-rootless-extras-27.0.1.tgz --output rootless.tgz cd $docker_bin tar zxf $tmp/docker.tgz --strip-components=1 diff --git a/installer/prereq.sh b/installer/prereq.sh index c6defb0..736cc23 100755 --- a/installer/prereq.sh +++ b/installer/prereq.sh @@ -5,7 +5,6 @@ # Adding user disk quota limitation capability # Enable user quota in fstab for root mount. # Enable cgroup memory and swapaccount capability. -# Setup cgroups rules engine service. echo "---Sashimono prerequisites installer---" @@ -14,9 +13,6 @@ tmpfstab=$tmp.tmp originalfstab=/etc/fstab cp $originalfstab "$tmpfstab" backup=$originalfstab.sashi.bk -cgrulesengd_service=$1 # cgroups rules engine service name - -[ -z "$cgrulesengd_service" ] && cgrulesengd_service="cgrulesengd" function stage() { echo "STAGE $1" # This is picked up by the setup console output filter. @@ -82,6 +78,18 @@ if ! command -v snap &>/dev/null; then apt-get install -y snapd fi +# Install snap (required for letsencrypt certbot install) +if ! command -v dbus-user-session &>/dev/null; then + stage "Installing dbus-ser-session" + apt-get install -y dbus-user-session + +fi + +if ! command -v systemd-container &>/dev/null; then + stage "Installing systemd-container" + apt-get install -y systemd-container +fi + # ------------------------------- # fstab changes # We do not edit original file, instead we create a temp file with original and edit it. @@ -183,43 +191,6 @@ else echo "Fuse config already updated." fi -# ------------------------------- -stage "Configuring cgroup rules engine" - -# Copy cgred.conf from examples if not exists to setup control groups. -[ ! -f /etc/cgred.conf ] && cp /usr/share/doc/cgroup-tools/examples/cgred.conf /etc/ - -# Create new cgconfig.conf if not exists to setup control groups. -[ ! -f /etc/cgconfig.conf ] && : >/etc/cgconfig.conf - -# Create new cgrules.conf if not exists to setup control groups. -[ ! -f /etc/cgrules.conf ] && : >/etc/cgrules.conf - -# Setup a service if not exists to run cgroup rules generator. -cgrulesengd_file="/etc/systemd/system/$cgrulesengd_service.service" -if ! [ -f "$cgrulesengd_file" ]; then - echo "[Unit] - Description=cgroups rules generator - After=network.target - - [Service] - User=root - Group=root - Type=forking - EnvironmentFile=-/etc/cgred.conf - ExecStart=/usr/sbin/cgrulesengd - Restart=on-failure - - [Install] - WantedBy=multi-user.target" >$cgrulesengd_file - systemctl daemon-reload -fi -systemctl enable $cgrulesengd_service -systemctl start $cgrulesengd_service - -# ------------------------------- -stage "Configuring grub" - # Enable cgroup memory and swapaccount if not already configured # We create a temp of the grub file and replace with original file only if success. tmp=$(mktemp -d) @@ -227,72 +198,89 @@ tmpgrub=$tmp.tmp cp /etc/default/grub "$tmpgrub" updated=0 -# Check GRUB_CMDLINE_LINUX exists, create new if not exists. -# If exists check for cgroup_enable=memory and swapaccount=1 and configure them if not already configured. -sed -n -r -e "/^GRUB_CMDLINE_LINUX=/{q100}" "$tmpgrub" -res=$? -if [ $res -eq 100 ]; then - # Check cgroup_enable=memory exists, create new if not exists otherwise skip. - sed -n -r -e "/^GRUB_CMDLINE_LINUX=/{ /cgroup_enable=memory/{q100}; }" "$tmpgrub" - res=$? - if [ $res -eq 0 ]; then - sed -i -r -e "/^GRUB_CMDLINE_LINUX=/{ s/\"\s*\$/ cgroup_enable=memory\"/ }" "$tmpgrub" - res=$? - updated=1 - fi - # If there's no error. - if [ $res -eq 0 ] || [ $res -eq 100 ]; then - # Check swapaccount=1 exists, create new if not exists otherwise skip. - sed -n -r -e "/^GRUB_CMDLINE_LINUX=/{ /swapaccount=1/{q100}; }" "$tmpgrub" +if mount | grep "type cgroup2" | grep -q "/sys/fs/cgroup/unified"; then + stage "Configuring grub" + stage "Enabling Cgroups unified hierarchy" + + sed -n -r -e "/^GRUB_CMDLINE_LINUX=/{q100}" "$tmpgrub" + res=$? + if [ $res -eq 100 ]; then + + # Check systemd.unified_cgroup_hierarchy=1exists, create new if not exists otherwise skip. + sed -n -r -e "/^GRUB_CMDLINE_LINUX=/{ /systemd.unified_cgroup_hierarchy=1/{q100}; }" "$tmpgrub" res=$? if [ $res -eq 0 ]; then - # Check whether there's swapaccount value other than 1, If so replace value with 1. - # Otherwise add swapaccount=1 after cgroup_enable=memory. - sed -n -r -e "/^GRUB_CMDLINE_LINUX=/{ /swapaccount=/{q100}; }" "$tmpgrub" + sed -i -r -e "/^GRUB_CMDLINE_LINUX=/{ s/\"\s*\$/ systemd.unified_cgroup_hierarchy=1\"/ }" "$tmpgrub" res=$? - if [ $res -eq 100 ]; then - sed -i -r -e "/^GRUB_CMDLINE_LINUX=/{ s/swapaccount=[0-9]*/swapaccount=1/ }" "$tmpgrub" - res=$? - updated=1 - elif [ $res -eq 0 ]; then - sed -i -r -e "/^GRUB_CMDLINE_LINUX=/{ s/cgroup_enable=memory/cgroup_enable=memory swapaccount=1/ }" "$tmpgrub" + updated=1 + fi + + # If there's no error. + if [ $res -eq 0 ] || [ $res -eq 100 ]; then + # Check cgroup_enable=memory exists, create new if not exists otherwise skip. + sed -n -r -e "/^GRUB_CMDLINE_LINUX=/{ /cgroup_enable=memory/{q100}; }" "$tmpgrub" + res=$? + if [ $res -eq 0 ]; then + sed -i -r -e "/^GRUB_CMDLINE_LINUX=/{ s/\"\s*\$/ cgroup_enable=memory\"/ }" "$tmpgrub" res=$? updated=1 fi fi - fi -elif [ $res -eq 0 ]; then - echo "GRUB_CMDLINE_LINUX=\"cgroup_enable=memory swapaccount=1\"" >>"$tmpgrub" - res=$? - updated=1 -fi -# If the res is not success(0) or alredy exist(100). -[ ! $res -eq 0 ] && [ ! $res -eq 100 ] && echo "Grub GRUB_CMDLINE_LINUX update failed." && exit 1 - -# If updated we do update-grub and reboot. -if [ $updated -eq 1 ]; then - # Create a backup of original grub, So we can replace the backup with original if update-grub failed. - grub_backup=/etc/default/grub.sashi.bk - cp /etc/default/grub $grub_backup - mv "$tmpgrub" /etc/default/grub - rm -r "$tmp" - if ! update-grub >/dev/null 2>&1; then - mv $grub_backup /etc/default/grub - echo "Grub update failed." - exit 1 + # If there's no error. + if [ $res -eq 0 ] || [ $res -eq 100 ]; then + # Check swapaccount=1 exists, create new if not exists otherwise skip. + sed -n -r -e "/^GRUB_CMDLINE_LINUX=/{ /swapaccount=1/{q100}; }" "$tmpgrub" + res=$? + if [ $res -eq 0 ]; then + # Check whether there's swapaccount value other than 1, If so replace value with 1. + # Otherwise add swapaccount=1 after cgroup_enable=memory. + sed -n -r -e "/^GRUB_CMDLINE_LINUX=/{ /swapaccount=/{q100}; }" "$tmpgrub" + res=$? + if [ $res -eq 100 ]; then + sed -i -r -e "/^GRUB_CMDLINE_LINUX=/{ s/swapaccount=[0-9]*/swapaccount=1/ }" "$tmpgrub" + res=$? + updated=1 + elif [ $res -eq 0 ]; then + sed -i -r -e "/^GRUB_CMDLINE_LINUX=/{ s/cgroup_enable=memory/cgroup_enable=memory swapaccount=1/ }" "$tmpgrub" + res=$? + updated=1 + fi + fi + fi + elif [ $res -eq 0 ]; then + echo "GRUB_CMDLINE_LINUX=\"systemd.unified_cgroup_hierarchy=1 cgroup_enable=memory swapaccount=1\"" >>"$tmpgrub" + res=$? + updated=1 fi - # Indicate pending reboot in the standard reboot required file. - touch /run/reboot-required - rebootpkgs=/run/reboot-required.pkgs - (! [ -f $rebootpkgs ] || [ -z "$(grep sashimono $rebootpkgs)" ]) && echo "sashimono" >>$rebootpkgs + # If the res is not success(0) or alredy exist(100). + [ ! $res -eq 0 ] && [ ! $res -eq 100 ] && echo "Grub GRUB_CMDLINE_LINUX update failed." && exit 1 - echo "Updated grub. System needs to be rebooted to apply grub changes." -else - rm -r "$tmp" - echo "Grub already configured." + # If updated we do update-grub and reboot. + if [ $updated -eq 1 ]; then + # Create a backup of original grub, So we can replace the backup with original if update-grub failed. + grub_backup=/etc/default/grub.sashi.bk + cp /etc/default/grub $grub_backup + mv "$tmpgrub" /etc/default/grub + rm -r "$tmp" + if ! update-grub >/dev/null 2>&1; then + mv $grub_backup /etc/default/grub + echo "Grub update failed." + exit 1 + fi + + # Indicate pending reboot in the standard reboot required file. + touch /run/reboot-required + rebootpkgs=/run/reboot-required.pkgs + (! [ -f $rebootpkgs ] || [ -z "$(grep sashimono $rebootpkgs)" ]) && echo "sashimono" >>$rebootpkgs + + echo "Updated grub. System needs to be rebooted to apply grub changes." + else + rm -r "$tmp" + echo "Grub already configured." + fi fi exit 0 diff --git a/installer/sashimono-install.sh b/installer/sashimono-install.sh index a851262..eb5c8b6 100755 --- a/installer/sashimono-install.sh +++ b/installer/sashimono-install.sh @@ -175,19 +175,10 @@ function call_third_party() { return 1 } -function cgrulesengd_servicename() { - # Find the cgroups rules engine service. - local cgrulesengd_filepath=$(grep "ExecStart.*=.*/cgrulesengd$" /etc/systemd/system/*.service | head -1 | awk -F : ' { print $1 } ') - if [ -n "$cgrulesengd_filepath" ]; then - local cgrulesengd_filename=$(basename $cgrulesengd_filepath) - echo "${cgrulesengd_filename%.*}" - 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) + [ -z $cpu_model_name ] && cpu_model_name=$(cat /proc/cpuinfo | grep -m 1 "model name" | sed -n 's/model name\s*: //p' | sed 's/ /_/g') + [ -z $cpu_count ] && cpu_count=$(grep -c ^processor /proc/cpuinfo) + [ -z $cpu_mhz ] && cpu_mhz=$(cat /proc/cpuinfo | grep -m 1 "cpu MHz" | sed -n 's/cpu MHz\s*: //p') } function setup_certbot_renewal() { @@ -453,13 +444,10 @@ function upgrade() { return 0 } -# 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 # Stop services before start upgrade. if [[ "$UPGRADE" == "1" ]]; then systemctl stop $SASHIMONO_SERVICE - systemctl stop $CGCREATE_SERVICE sudo -u "$MB_XRPL_USER" XDG_RUNTIME_DIR="$mb_user_runtime_dir" systemctl --user stop $MB_XRPL_SERVICE fi @@ -492,7 +480,6 @@ rm -r "$tmp" # Install Sashimono agent binaries into sashimono bin dir. 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 - # Setup tls certs used for contract instance websockets. [ "$UPGRADE" == "0" ] && setup_tls_certs @@ -578,21 +565,10 @@ fi stage "Configuring Sashimono services" -cgrulesengd_service=$(cgrulesengd_servicename) -[ -z "$cgrulesengd_service" ] && echo "cgroups rules engine service does not exist." && abort - -# Setting up cgroup rules with sashiusers group (if not already setup). -echo "Creating cgroup rules..." ! grep -q $SASHIUSER_GROUP /etc/group && ! groupadd $SASHIUSER_GROUP && echo "$SASHIUSER_GROUP group creation failed." && abort -if ! grep -q $SASHIUSER_GROUP /etc/cgrules.conf; then - ! echo "@$SASHIUSER_GROUP cpu,memory %u$CG_SUFFIX" >>/etc/cgrules.conf && echo "Cgroup rule creation failed." && abort - # Restart the service to apply the cgrules config. - echo "Restarting the '$cgrulesengd_service' service." - systemctl restart $cgrulesengd_service || abort -fi # Install Sashimono Agent cgcreate service. -# This is a oneshot service which runs once at system startup. The intention is to run 'cgcreate' for +# This is a oneshot service which runs once at system startup. This update user slices # all sashimono users every time the system boots up. echo "[Unit] Description=Sashimono cgroup creation service. @@ -604,7 +580,6 @@ Type=oneshot ExecStart=$SASHIMONO_BIN/user-cgcreate.sh $SASHIMONO_DATA [Install] WantedBy=multi-user.target" >/etc/systemd/system/$CGCREATE_SERVICE.service - echo "Configuring sashimono agent service..." # Since gp ports are added as new feature we manually configure the default on upgrade mode if not exists. diff --git a/installer/sashimono-uninstall.sh b/installer/sashimono-uninstall.sh index 3829743..2e05edc 100755 --- a/installer/sashimono-uninstall.sh +++ b/installer/sashimono-uninstall.sh @@ -79,15 +79,6 @@ function exec_mb() { return $return_code } -function cgrulesengd_servicename() { - # Find the cgroups rules engine service. - local cgrulesengd_filepath=$(grep "ExecStart.*=.*/cgrulesengd$" /etc/systemd/system/*.service | head -1 | awk -F : ' { print $1 } ') - if [ -n "$cgrulesengd_filepath" ]; then - local cgrulesengd_filename=$(basename $cgrulesengd_filepath) - echo "${cgrulesengd_filename%.*}" - fi -} - function cleanup_certbot_ssl() { # revoke/delete certs if certbot is used. if command -v certbot &>/dev/null && [ -f "$SASHIMONO_DATA/sa.cfg" ]; then @@ -282,16 +273,7 @@ echo "Deleting Sashimono CLI..." rm $USER_BIN/sashi if [ "$UPGRADE" == "0" ]; then - # When removing the cgrules service, we first edit the config and restart the service to apply the config. - # Then we remove the attached group. - echo "Deleting cgroup rules..." - sed -i -r "/^@$SASHIUSER_GROUP\s+cpu,memory\s+%u$CG_SUFFIX/d" /etc/cgrules.conf - - cgrulesengd_service=$(cgrulesengd_servicename) - [ -z "$cgrulesengd_service" ] && echo "Warning: cgroups rules engine service does not exist." - - echo "Restarting the '$cgrulesengd_service' service..." - systemctl restart $cgrulesengd_service + # Remove the attached group. groupdel $SASHIUSER_GROUP fi diff --git a/installer/setup.sh b/installer/setup.sh index ba2af86..6202ba5 100755 --- a/installer/setup.sh +++ b/installer/setup.sh @@ -11,7 +11,6 @@ evernode="Evernode" maxmind_creds="687058:FtcQjM0emHFMEfgI" - cgrulesengd_default="cgrulesengd" alloc_ratio=80 ramKB_per_instance=524288 instances_per_core=3 @@ -28,9 +27,12 @@ root_user="root" repo_owner="EvernodeXRPL" - repo_name="evernode-resources" + repo_name="evernode-24-resources" desired_branch="main" + # Regular expression pattern to match "0.*.*" + older_version_pattern="^0\.[0-9]+\.[0-9]+$" + # Reputation modes : 0 - "none", 1 - "OneToOne", 2 - "OneToMany" is_fresh_reputation_acc=false reputation_account_mode=0 @@ -201,6 +203,12 @@ echo "$evernode is already installed on your host. You cannot deregister without uninstalling. Use the 'evernode' command to manage your host." && exit 1 + current_evernode_version=$(jq -r '.version' "$MB_XRPL_CONFIG") + if [[ "$1" == "update" && $current_evernode_version =~ $older_version_pattern ]]; then + echomult "Update not supported on this machine. + \nPlease back up your secrets, transfer your host, and perform a fresh installation instead of proceeding with the upgrade.." && exit 1 + fi + [ "$1" != "uninstall" ] && [ "$1" != "status" ] && [ "$1" != "list" ] && [ "$1" != "update" ] && [ "$1" != "log" ] && [ "$1" != "applyssl" ] && [ "$1" != "transfer" ] && [ "$1" != "config" ] && [ "$1" != "delete" ] && [ "$1" != "governance" ] && [ "$1" != "regkey" ] && [ "$1" != "offerlease" ] && [ "$1" != "reputationd" ] && echomult "$evernode host management tool \nYour have $evernode installed on your machine. @@ -321,7 +329,7 @@ local osversion=$(grep -ioP '^VERSION_ID=\K.+' /etc/os-release) local errors="" - ([ "$os" != "ubuntu" ] || [ "$osversion" != '"20.04"' ]) && errors=" OS: $os $osversion (required: Ubuntu 20.04)\n" + ([ "$os" != "ubuntu" ] || [ "$osversion" != '"24.04"' ]) && errors=" OS: $os $osversion (required: Ubuntu 24.04)\n" [ $ramKB -lt 2000000 ] && errors="$errors RAM: $(GB $ramKB) (required: 2 GB RAM)\n" [ $swapKB -lt 2000000 ] && errors="$errors Swap: $(GB $swapKB) (required: 2 GB Swap)\n" [ $diskKB -lt 4000000 ] && errors="$errors Disk space (/home): $(GB $diskKB) (required: 4 GB)\n" @@ -330,7 +338,7 @@ echo "System check complete. Your system is capable of becoming an $evernode host." else echomult "Your system does not meet following $evernode system requirements:\n $errors" - echomult "$evernode host registration requires Ubuntu 20.04 with minimum 2 GB RAM, + echomult "$evernode host registration requires Ubuntu 24.04 with minimum 2 GB RAM, 2 GB Swap and 4 GB free disk space for /home. Aborting setup." exit 1 fi @@ -682,16 +690,6 @@ done } - function check_ipv4_req() { - # Check for IPv4 addresses - local ipv4_addresses=$(ip -4 addr show | grep inet) - if [ -z "$ipv4_addresses" ]; then - echomult "Your system does not support IPv4." - echomult "$evernode host registration requires IPv4 support for dApp deployment." - exit 1 - fi - } - function set_ipv6_subnet() { ipv6_subnet="-" @@ -750,16 +748,6 @@ done } - function set_cgrules_svc() { - local filepath=$(grep "ExecStart.*=.*/cgrulesengd$" /etc/systemd/system/*.service | head -1 | awk -F : ' { print $1 } ') - if [ -n "$filepath" ]; then - local filename=$(basename $filepath) - cgrulesengd_service="${filename%.*}" - fi - # If service not detected, use the default name. - [ -z "$cgrulesengd_service" ] && cgrulesengd_service=$cgrulesengd_default || echo "cgroups rules engine service found: '$cgrulesengd_service'" - } - function set_instance_alloc() { [ -z $alloc_ramKB ] && alloc_ramKB=$(((ramKB / 100) * alloc_ratio)) [ -z $alloc_swapKB ] && alloc_swapKB=$(((swapKB / 100) * alloc_ratio)) @@ -1452,7 +1440,7 @@ WantedBy=timers.target" >/etc/systemd/system/$EVERNODE_AUTO_UPDATE_SERVICE.timer if [ "$upgrade" == "0" ]; then echo "Installing other prerequisites..." - ! ./prereq.sh $cgrulesengd_service 2>&1 | + ! ./prereq.sh 2>&1 | tee -a >(stdbuf --output=L awk '{ cmd="date -u +\"%Y-%m-%d %H:%M:%S\""; cmd | getline utc_time; close(cmd); print utc_time, $0 }' >>$logfile) | stdbuf --output=L grep -E 'STAGE' | while read -r line; do cleaned_line=$(echo "$line" | sed -E 's/STAGE//g' | awk '{sub(/^[ \t]+/, ""); print}') @@ -2329,7 +2317,6 @@ WantedBy=timers.target" >/etc/systemd/system/$EVERNODE_AUTO_UPDATE_SERVICE.timer to you since we will be making modifications to your system configuration. \n\nContinue?" && exit 1 - check_ipv4_req check_sys_req check_prereq @@ -2387,9 +2374,6 @@ WantedBy=timers.target" >/etc/systemd/system/$EVERNODE_AUTO_UPDATE_SERVICE.timer [ ! -f "$MB_XRPL_CONFIG" ] && set_ipv6_subnet [ "$ipv6_subnet" != "-" ] && [ "$ipv6_net_interface" != "-" ] && echo -e "Using $ipv6_subnet IPv6 subnet on $ipv6_net_interface for contract instances.\n" - set_cgrules_svc - echo -e "Using '$cgrulesengd_service' as cgroups rules engine service.\n" - [ ! -f "$SASHIMONO_CONFIG" ] && set_instance_alloc echo -e "Using allocation $(GB $alloc_ramKB) memory, $(GB $alloc_swapKB) Swap, $(GB $alloc_diskKB) disk space, distributed among $alloc_instcount contract instances.\n" diff --git a/mb-xrpl/lib/appenv.js b/mb-xrpl/lib/appenv.js index 8c65cd6..564ff77 100644 --- a/mb-xrpl/lib/appenv.js +++ b/mb-xrpl/lib/appenv.js @@ -45,7 +45,7 @@ appenv = { ORPHAN_PRUNE_SCHEDULER_INTERVAL_HOURS: 2, SASHIMONO_SCHEDULER_INTERVAL_SECONDS: 2, SASHI_CLI_PATH: appenv.IS_DEV_MODE ? "../build/sashi" : "/usr/bin/sashi", - MB_VERSION: '0.12.1', + MB_VERSION: '1.0.0', TOS_HASH: '0801677EBCB2F76EF97D531549D8B27DB2C7A4A8EE7F60032AE40184247F0810', // This is the sha256 hash of EVERNODE-HOSTING-PRINCIPLES.pdf. NETWORK: 'mainnet', REPUTATIOND_CONFIG_PATH: path.join(appenv.DATA_DIR, '../') + "reputationd/reputationd.cfg", diff --git a/reputationd b/reputationd index ed57e1b..989c98f 160000 --- a/reputationd +++ b/reputationd @@ -1 +1 @@ -Subproject commit ed57e1b0b977d1a77cc87306be9fb1c291bb9f4b +Subproject commit 989c98f9dc6d862161267ed8579d525d5589528d diff --git a/src/hp_manager.cpp b/src/hp_manager.cpp index 063ef9a..ab9ac00 100644 --- a/src/hp_manager.cpp +++ b/src/hp_manager.cpp @@ -32,7 +32,7 @@ namespace hp // We keep docker logs at size limit of 10mb, We only need these logs for docker instance failure debugging since all other logs are kept in files. // For the local log driver compression, minimum max-file should be 2. So we keep two logs each max-size is 5mb constexpr const char *DOCKER_CREATE = "DOCKER_HOST=unix:///run/user/$(id -u %s)/docker.sock timeout --foreground -v -s SIGINT %ss %s/dockerbin/docker create -t -i --stop-signal=SIGINT --log-driver local \ - --log-opt max-size=5m --log-opt max-file=2 --name=%s -p %s:%s -p %s:%s -p %s:%s/udp -p %s:%s -p %s:%s -p %s:%s/udp -p %s:%s/udp --restart unless-stopped --mount type=bind,source=%s,target=/contract %s run /contract"; + --log-opt max-size=5m --log-opt max-file=2 --name=%s -p %s:%s -p %s:%s -p %s:%s/udp -p %s:%s -p %s:%s -p %s:%s/udp -p %s:%s/udp --security-opt seccomp=unconfined --security-opt apparmor=unconfined --restart unless-stopped --mount type=bind,source=%s,target=/contract %s run /contract"; constexpr const char *DOCKER_START = "DOCKER_HOST=unix:///run/user/$(id -u %s)/docker.sock %s/dockerbin/docker start %s"; constexpr const char *DOCKER_STOP = "DOCKER_HOST=unix:///run/user/$(id -u %s)/docker.sock %s/dockerbin/docker stop %s"; constexpr const char *DOCKER_REMOVE = "DOCKER_HOST=unix:///run/user/$(id -u %s)/docker.sock %s/dockerbin/docker rm -f %s"; @@ -317,7 +317,7 @@ namespace hp const std::string gp_udp_port_1 = std::to_string(assigned_ports.gp_udp_port_start); const std::string gp_udp_port_2 = std::to_string(assigned_ports.gp_udp_port_start + 1); const std::string timeout = std::to_string(DOCKER_CREATE_TIMEOUT_SECS); - const int len = 376 + username.length() + timeout.length() + conf::ctx.exe_dir.length() + container_name.length() + (user_port.length() * 2) + (peer_port.length() * 4) + (gp_tcp_port_1.length() * 2) + (gp_tcp_port_2.length() * 2) + (gp_udp_port_1.length() * 2) + (gp_udp_port_2.length() * 2) + contract_dir.length() + image_name.length(); + const int len = 376 + 69 + username.length() + timeout.length() + conf::ctx.exe_dir.length() + container_name.length() + (user_port.length() * 2) + (peer_port.length() * 4) + (gp_tcp_port_1.length() * 2) + (gp_tcp_port_2.length() * 2) + (gp_udp_port_1.length() * 2) + (gp_udp_port_2.length() * 2) + contract_dir.length() + image_name.length(); char command[len]; sprintf(command, DOCKER_CREATE, username.data(), timeout.data(), conf::ctx.exe_dir.data(), container_name.data(), user_port.data(), user_port.data(), @@ -1094,58 +1094,16 @@ namespace hp } } /** - * Check whether there's a pending reboot and cgrules service is running and configured. + * Check whether there's a pending reboot * @return true if active and configured otherwise false. */ bool system_ready() { - char buffer[20]; - - if (util::execute_bash_cmd(CGRULE_ACTIVE, buffer, 20) == -1) - return false; - - // Check cgrules service status is active. - if (strncmp(buffer, "active", 6) != 0) - { - LOG_ERROR << "Cgrules service is inactive."; - return false; - } - - // Check cgrules cpu and memory mounts exist. - if (!util::is_dir_exists(CGRULE_CPU_DIR) || !util::is_dir_exists(CGRULE_MEM_DIR)) - { - LOG_ERROR << "Cgrules cpu or memory mounts does not exist."; - return false; - } - - // Check cgrules config exist and configured. - int fd = open(CGRULE_CONF, O_RDONLY); - if (fd == -1) - { - LOG_ERROR << errno << ": Error opening the cgrules config file."; - return false; - } - - std::string buf; - if (util::read_from_fd(fd, buf, 0) == -1) - { - LOG_ERROR << errno << ": Error reading the cgrules config file."; - close(fd); - return false; - } - - close(fd); - - if (!std::regex_search(buf, std::regex(CGRULE_REGEXP))) - { - LOG_ERROR << "Cgrules config entry does not exist."; - return false; - } - // Check there's a pending reboot. if (util::is_file_exists(REBOOT_FILE)) { - fd = open(REBOOT_FILE, O_RDONLY); + std::string buf; + int fd = open(REBOOT_FILE, O_RDONLY); if (fd == -1) { LOG_ERROR << errno << ": Error opening the reboot file."; diff --git a/src/version.hpp b/src/version.hpp index bb21579..19faa83 100644 --- a/src/version.hpp +++ b/src/version.hpp @@ -6,7 +6,7 @@ namespace version { // Sashimono agent version. Written to new configs. - constexpr const char *AGENT_VERSION = "0.12.1"; + constexpr const char *AGENT_VERSION = "1.0.0"; // Minimum compatible config version (this will be used to validate configs). constexpr const char *MIN_CONFIG_VERSION = "0.5.0";