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..286c880 100755 --- a/installer/sashimono-install.sh +++ b/installer/sashimono-install.sh @@ -104,7 +104,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 +123,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,7 +171,7 @@ 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 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 8512325..bb473c5 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="rDsg8R6MYfEB7Da861ThTRzVUWBa3xJgWL" +# 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 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");