From d028a4d8c67656df19fb825fbc492deb0bdaa4ad Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 25 Apr 2025 18:54:31 +1200 Subject: [PATCH] . --- CMakeLists.txt | 2 + src/servers.cpp | 11 ++-- src/templates.cpp | 6 +- src/utils/directories.cpp | 16 ++++- src/utils/directories.hpp | 16 ++--- src/utils/utils.cpp | 32 ++++++++++ src/utils/utils.hpp | 2 + templates/dropshell-agent/README.txt | 23 +++++++ .../dropshell-agent/_allservicesstatus.sh | 60 +++++++++++++++++++ templates/dropshell-agent/example/service.env | 4 ++ templates/dropshell-agent/install.sh | 8 +++ templates/dropshell-agent/start.sh | 8 +++ templates/dropshell-agent/status.sh | 8 +++ templates/dropshell-agent/stop.sh | 7 +++ templates/dropshell-agent/uninstall.sh | 7 +++ 15 files changed, 195 insertions(+), 15 deletions(-) create mode 100644 templates/dropshell-agent/README.txt create mode 100644 templates/dropshell-agent/_allservicesstatus.sh create mode 100644 templates/dropshell-agent/example/service.env create mode 100644 templates/dropshell-agent/install.sh create mode 100644 templates/dropshell-agent/start.sh create mode 100644 templates/dropshell-agent/status.sh create mode 100644 templates/dropshell-agent/stop.sh create mode 100644 templates/dropshell-agent/uninstall.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index b4fcaa9..fdb7836 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,7 @@ configure_file( # Find required packages find_package(Boost REQUIRED COMPONENTS program_options filesystem system) find_package(Curses REQUIRED) +find_package(TBB REQUIRED) # Auto-detect source files file(GLOB_RECURSE SOURCES "src/*.cpp") @@ -42,6 +43,7 @@ target_link_libraries(dropshell PRIVATE Boost::filesystem Boost::system ${CURSES_LIBRARIES} + TBB::tbb ) # Install targets diff --git a/src/servers.cpp b/src/servers.cpp index 995206d..9565259 100644 --- a/src/servers.cpp +++ b/src/servers.cpp @@ -11,6 +11,7 @@ #include #include #include +#include namespace fs = boost::filesystem; @@ -55,18 +56,20 @@ void list_servers() { tableprint tp("All DropShell Servers"); tp.add_row({"Name", "Address", "Health", "Ports"}); - for (const auto& server : servers) { + + std::for_each(std::execution::par, servers.begin(), servers.end(), [&](const ServerInfo& server) { std::vector ports_used; std::string serviceticks = ""; std::vector services = get_server_services_info(server.name); - for (const auto& service : services) { + + std::for_each(std::execution::par, services.begin(), services.end(), [&](const ServiceInfo& service) { service_runner ss; if (ss.init(server.name, service.service_name)) serviceticks += ss.healthmark() + " "; else std::cout<<"Error: Failed to initialise service runner for server: ["< ports = ss.get_ports(); ports_used.insert(ports_used.end(), ports.begin(), ports.end()); - } + }); // convert ports_used to string std::string ports_used_str = ""; bool first = true; @@ -78,7 +81,7 @@ void list_servers() { first = false; } tp.add_row({server.name, server.ssh_host, serviceticks, ports_used_str}); - } + }); tp.print(); } diff --git a/src/templates.cpp b/src/templates.cpp index 9fe7b18..41c0144 100644 --- a/src/templates.cpp +++ b/src/templates.cpp @@ -1,6 +1,7 @@ #include "templates.hpp" #include "config.hpp" #include "utils/directories.hpp" +#include "utils/utils.hpp" #include #include #include @@ -155,7 +156,10 @@ void create_template(const std::string& template_name) { std::string replacement_line = "TEMPLATE=" + template_name; // replace the line in the example/service.env file with the replacement line std::string service_env_path = new_template_path + "/example/service.env"; - + if (!replace_line_in_file(service_env_path, search_string, replacement_line)) { + std::cerr << "Error: Failed to replace TEMPLATE= line in service.env file" << std::endl; + return; + } // 3. Print out the README.txt file and the path std::string readme_path = new_template_path + "/README.txt"; diff --git a/src/utils/directories.cpp b/src/utils/directories.cpp index afed437..e0a9886 100644 --- a/src/utils/directories.cpp +++ b/src/utils/directories.cpp @@ -134,14 +134,24 @@ std::string get_local_service_env_path(const std::string &server_name, const std return env.get_DROPSHELL_DIR(); } - std::string get_remote_service_path(const std::string &server_name, const std::string &service_name) + std::string get_remote_services_path(const std::string &server_name) { - if (server_name.empty() || service_name.empty()) + if (server_name.empty()) return std::string(); std::string dropshell_path = get_remote_DROPSHELL_path(server_name); if (dropshell_path.empty()) return std::string(); - return (fs::path(dropshell_path) / service_name).string(); + return (fs::path(dropshell_path) / "services").string(); + } + + std::string get_remote_service_path(const std::string &server_name, const std::string &service_name) + { + if (server_name.empty() || service_name.empty()) + return std::string(); + std::string services_path = get_remote_services_path(server_name); + if (services_path.empty()) + return std::string(); + return (fs::path(services_path) / service_name).string(); } std::string get_remote_service_config_path(const std::string &server_name, const std::string &service_name) diff --git a/src/utils/directories.hpp b/src/utils/directories.hpp index 4e2fada..55123bd 100644 --- a/src/utils/directories.hpp +++ b/src/utils/directories.hpp @@ -23,14 +23,16 @@ namespace dropshell { // remote paths // DROPSHELL_DIR - // |-- service name - // |-- config - // |-- service.env - // |-- (user config files) - // |-- template - // |-- (script files) - // |-- backups + // |-- backups + // |-- services + // |-- service name + // |-- config <-- this is passed as argument to all scripts + // |-- service.env + // |-- (user config files) + // |-- template + // |-- (script files) std::string get_remote_DROPSHELL_path(const std::string &server_name); + std::string get_remote_services_path(const std::string &server_name); std::string get_remote_service_path(const std::string &server_name, const std::string &service_name); std::string get_remote_service_config_path(const std::string &server_name, const std::string &service_name); std::string get_remote_service_template_path(const std::string &server_name, const std::string &service_name); diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 8e6a901..7080bc5 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -1,6 +1,8 @@ #include "utils.hpp" #include #include +#include +#include namespace dropshell { @@ -10,4 +12,34 @@ void maketitle(const std::string& title) { std::cout << std::string(title.length() + 4, '-') << std::endl; } +bool replace_line_in_file(const std::string& file_path, const std::string& search_string, const std::string& replacement_line) { + std::ifstream input_file(file_path); + std::vector file_lines; + std::string line; + + if (!input_file.is_open()) { + std::cerr << "Error: Unable to open file: " << file_path << std::endl; + return false; + } + + while (std::getline(input_file, line)) { + if (line.find(search_string) != std::string::npos) + file_lines.push_back(replacement_line); + else + file_lines.push_back(line); + } + input_file.close(); + + std::ofstream output_file(file_path); + if (!output_file.is_open()) + { + std::cerr << "Error: Unable to open file: " << file_path << std::endl; + return false; + } + for (const auto& modified_line : file_lines) + output_file << modified_line << "\n"; + output_file.close(); + return true; +} + } // namespace dropshell \ No newline at end of file diff --git a/src/utils/utils.hpp b/src/utils/utils.hpp index d355618..305c347 100644 --- a/src/utils/utils.hpp +++ b/src/utils/utils.hpp @@ -11,4 +11,6 @@ namespace dropshell { */ void maketitle(const std::string& title); +bool replace_line_in_file(const std::string& file_path, const std::string& search_string, const std::string& replacement_line); + } // namespace dropshell \ No newline at end of file diff --git a/templates/dropshell-agent/README.txt b/templates/dropshell-agent/README.txt new file mode 100644 index 0000000..03d2363 --- /dev/null +++ b/templates/dropshell-agent/README.txt @@ -0,0 +1,23 @@ +DropShell Template Example + +Shell scripts defined in this folder are run as DropShell commands on the remote server (not locally!). +All scripts are passed the directory containing the server-specific service environment (SSSE) as an argument +(the environment file, along with any other server and service-specific files, is then in $1/service.env) + +The default SSSE file included when a new service is created is in example/service.env. This must exist, +and must at minimum contain the TEMPLATE= variable. + +The optional backups script gets a second argument, which is the backup file to create (a single tgz file). + +Mandatory scripts are: +- install.sh +- uninstall.sh +- start.sh +- stop.sh + +Optional standard scripts are: +- backup.sh +- status.sh +- ports.sh +- logs.sh + diff --git a/templates/dropshell-agent/_allservicesstatus.sh b/templates/dropshell-agent/_allservicesstatus.sh new file mode 100644 index 0000000..a0c544a --- /dev/null +++ b/templates/dropshell-agent/_allservicesstatus.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +# This script checks ALL services on the server and returns a status for each. + +# Return format is simple ENV with the following format: +# SERVICE_NAME_HEALTH=healthy|unhealthy|unknown +# SERVICE_NAME_PORTS=port1,port2,port3 + +# Get all services on the server +SCRIPT_DIR="$(dirname "$0")" + +# // DROPSHELL_DIR +# // |-- backups +# // |-- services +# // |-- service name +# // |-- config <-- this is passed as argument to all scripts +# // |-- service.env +# // |-- (user config files) +# // |-- template +# // |-- (script files) + +# Get all services on the server +SERVICES_PATH="${SCRIPT_DIR}/../" + +# Get all service names +SERVICE_NAMES=$(ls "${SERVICES_PATH}") + +# Iterate over all service names +for SERVICE_NAME in ${SERVICE_NAMES}; do + # Get the service health + SERVICE_PATH="${SERVICES_PATH}/${SERVICE_NAME}" + STATUS_FILE="${SERVICE_PATH}/template/status.sh" + if [ -f "${STATUS_FILE}" ]; then + # suppress all output from the status script + if $(bash "${STATUS_FILE}" "${SERVICE_PATH}/config" > /dev/null 2>&1); then + SERVICE_HEALTH="healthy" + else + SERVICE_HEALTH="unhealthy" + fi + else + SERVICE_HEALTH="unknown" + fi + + # Get the service ports + PORTS_FILE="${SERVICE_PATH}/template/ports.sh" + if [ -f "${PORTS_FILE}" ]; then + # suppress all output from the ports script + SERVICE_PORTS=$(bash "${PORTS_FILE}" "${SERVICE_PATH}/config" > /dev/null 2>&1) + else + SERVICE_PORTS="unknown" + fi + + # return the health and ports + echo "${SERVICE_NAME}_HEALTH=${SERVICE_HEALTH}" + echo "${SERVICE_NAME}_PORTS=${SERVICE_PORTS}" +done + + + + diff --git a/templates/dropshell-agent/example/service.env b/templates/dropshell-agent/example/service.env new file mode 100644 index 0000000..0334f93 --- /dev/null +++ b/templates/dropshell-agent/example/service.env @@ -0,0 +1,4 @@ +# Template to use - always required! +TEMPLATE=dropshell-agent + + diff --git a/templates/dropshell-agent/install.sh b/templates/dropshell-agent/install.sh new file mode 100644 index 0000000..f69f185 --- /dev/null +++ b/templates/dropshell-agent/install.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# INSTALL SCRIPT +# The install script is required for all templates. +# It is used to install the service on the server. +# It is called with the path to the server specific env file as an argument. + +echo "Installation of ${CONTAINER_NAME} complete" diff --git a/templates/dropshell-agent/start.sh b/templates/dropshell-agent/start.sh new file mode 100644 index 0000000..deb0b12 --- /dev/null +++ b/templates/dropshell-agent/start.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# START SCRIPT +# The start script is required for all templates. +# It is used to start the service on the server. +# It is called with the path to the server specific env file as an argument. + + diff --git a/templates/dropshell-agent/status.sh b/templates/dropshell-agent/status.sh new file mode 100644 index 0000000..c65f41b --- /dev/null +++ b/templates/dropshell-agent/status.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# STATUS SCRIPT +# The status script is OPTIONAL. +# It is used to return the status of the service (0 is healthy, 1 is unhealthy). +# It is called with the path to the server specific env file as an argument. + +return 0 diff --git a/templates/dropshell-agent/stop.sh b/templates/dropshell-agent/stop.sh new file mode 100644 index 0000000..a735b58 --- /dev/null +++ b/templates/dropshell-agent/stop.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# STOP SCRIPT +# The stop script is required for all templates. +# It is used to stop the service on the server. +# It is called with the path to the server specific env file as an argument. + diff --git a/templates/dropshell-agent/uninstall.sh b/templates/dropshell-agent/uninstall.sh new file mode 100644 index 0000000..822d9a2 --- /dev/null +++ b/templates/dropshell-agent/uninstall.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# UNINSTALL SCRIPT +# The uninstall script is required for all templates. +# It is used to uninstall the service from the server. +# It is called with the path to the server specific env file as an argument. +