dropshell release 2025.0519.0021
Some checks failed
Dropshell Test / Build_and_Test (push) Has been cancelled
Some checks failed
Dropshell Test / Build_and_Test (push) Has been cancelled
This commit is contained in:
parent
548ffea6f9
commit
6c3c35bf89
83
source/agent-local/agent-install.sh
Executable file
83
source/agent-local/agent-install.sh
Executable file
@ -0,0 +1,83 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR=$(dirname "$0")
|
||||
|
||||
echo "Installing dropshell host agent on this computer..."
|
||||
|
||||
|
||||
# Prints an error message in red and exits with status code 1.
|
||||
_die() {
|
||||
echo -e "Error: $1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
# Checks if listed environment variables are set; calls _die() if any are missing.
|
||||
_check_required_env_vars() {
|
||||
local required_vars=("$@")
|
||||
for var in "${required_vars[@]}"; do
|
||||
if [ -z "${!var}" ]; then
|
||||
_die "Required environment variable $var is not set"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Checks if Docker is installed, running, and user has permission. Returns 1 on failure.
|
||||
_check_docker_installed() {
|
||||
if ! command -v docker &> /dev/null; then
|
||||
echo "Docker is not installed"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# check if docker daemon is running
|
||||
if ! docker info &> /dev/null; then
|
||||
echo "Docker daemon is not running"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# check if user has permission to run docker
|
||||
if ! docker run --rm hello-world &> /dev/null; then
|
||||
echo "User does not have permission to run docker"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
function install_bb64() {
|
||||
# check curl installed
|
||||
if ! command -v curl &> /dev/null; then
|
||||
_die "Curl is not installed. Curl is required for agent installation."
|
||||
fi
|
||||
|
||||
curl -fsSL "https://gitea.jde.nz/public/bb64/releases/download/latest/install.sh" | bash -s -- "$AGENT_PATH" "$(id -u $USER):$(id -g $USER)"
|
||||
|
||||
# test result code from curl
|
||||
if [ $? -ne 0 ]; then
|
||||
_die "Failed to install bb64. Curl returned non-zero exit code."
|
||||
fi
|
||||
|
||||
# test if bb64 is installed
|
||||
"$AGENT_PATH/bb64" -v
|
||||
if [ $? -ne 0 ]; then
|
||||
_die "bb64 did not install correctly."
|
||||
fi
|
||||
|
||||
echo "bb64 installed successfully."
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
set -a
|
||||
AGENT_PATH="$SCRIPT_DIR"
|
||||
set +a
|
||||
|
||||
_check_required_env_vars "AGENT_PATH"
|
||||
echo "Installing host agent into $AGENT_PATH"
|
||||
|
||||
_check_docker_installed || _die "Docker is required."
|
||||
|
||||
install_bb64
|
||||
|
70
source/agent-remote/agent-install.sh
Executable file
70
source/agent-remote/agent-install.sh
Executable file
@ -0,0 +1,70 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script is used to install the dropshell agent on a remote server.
|
||||
|
||||
SCRIPT_DIR=$(dirname "$0")
|
||||
|
||||
set -a
|
||||
|
||||
AGENT_PATH="$SCRIPT_DIR"
|
||||
|
||||
set +a
|
||||
|
||||
|
||||
if [ -f "$SCRIPT_DIR/common.sh" ]; then
|
||||
source "$SCRIPT_DIR/common.sh"
|
||||
else
|
||||
echo "Error: common.sh not found in $SCRIPT_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
_check_required_env_vars "AGENT_PATH"
|
||||
|
||||
function install_bb64() {
|
||||
# check curl installed
|
||||
if ! command -v curl &> /dev/null; then
|
||||
_die "Curl is not installed. Curl is required for agent installation."
|
||||
fi
|
||||
|
||||
curl -fsSL "https://gitea.jde.nz/public/bb64/releases/download/latest/install.sh" | bash -s -- "$AGENT_PATH" "$(id -u $USER):$(id -g $USER)"
|
||||
|
||||
# test result code from curl
|
||||
if [ $? -ne 0 ]; then
|
||||
_die "Failed to install bb64. Curl returned non-zero exit code."
|
||||
fi
|
||||
|
||||
# test if bb64 is installed
|
||||
"$AGENT_PATH/bb64" -v
|
||||
if [ $? -ne 0 ]; then
|
||||
_die "bb64 did not install correctly."
|
||||
fi
|
||||
|
||||
echo "bb64 installed successfully."
|
||||
return 0;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
echo "Installing dropshell agent..."
|
||||
|
||||
install_bb64
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
echo "Running remote agent self-test..."
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
echo "Completed remote agent self-test."
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
echo "Completed dropshell agent installation."
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
exit 0
|
@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Running remote agent self-test..."
|
||||
|
||||
echo "Completed remote agent self-test."
|
||||
|
||||
exit 0
|
@ -14,6 +14,5 @@ if ! command -v dehydrate &> /dev/null; then
|
||||
curl -fsSL https://gitea.jde.nz/public/dehydrate/releases/download/latest/install.sh | bash
|
||||
fi
|
||||
|
||||
SCRIPT_DIR=$(dirname "$0")
|
||||
|
||||
dehydrate "${SCRIPT_DIR}/agent" "${SCRIPT_DIR}/src/autogen"
|
||||
dehydrate "${SCRIPT_DIR}/agent-remote" "${SCRIPT_DIR}/src/autogen"
|
||||
dehydrate "${SCRIPT_DIR}/agent-local" "${SCRIPT_DIR}/src/autogen"
|
||||
|
160
source/src/autogen/_agent-local.cpp
Normal file
160
source/src/autogen/_agent-local.cpp
Normal file
@ -0,0 +1,160 @@
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
/*
|
||||
|
||||
THIS FILE IS AUTO-GENERATED BY DEHYDRATE.
|
||||
DO NOT EDIT THIS FILE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "_agent-local.hpp"
|
||||
namespace recreate_agent_local {
|
||||
|
||||
|
||||
// Tiny dependency-free FNV-1a 64-bit hash
|
||||
static uint64_t fnv1a_64(const void* data, size_t len) {
|
||||
const uint8_t* p = static_cast<const uint8_t*>(data);
|
||||
uint64_t h = 0xcbf29ce484222325ULL;
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
h = (h ^ p[i]) * 0x100000001b3ULL;
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
// Base64 decoding function - no dependencies
|
||||
static void base64_decode(const char* encoded_data, size_t encoded_len, unsigned char* output, size_t* output_len) {
|
||||
const char* base64_chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
size_t out_pos = 0;
|
||||
int val = 0, valb = -8;
|
||||
|
||||
for (size_t i = 0; i < encoded_len; i++) {
|
||||
char c = encoded_data[i];
|
||||
if (c == '=') break;
|
||||
|
||||
// Find position in base64_chars
|
||||
const char* pos = strchr(base64_chars, c);
|
||||
if (pos == nullptr) continue; // Skip invalid characters
|
||||
|
||||
val = (val << 6) + static_cast<int>(pos - base64_chars);
|
||||
valb += 6;
|
||||
if (valb >= 0) {
|
||||
output[out_pos++] = static_cast<unsigned char>((val >> valb) & 0xFF);
|
||||
valb -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
*output_len = out_pos;
|
||||
}
|
||||
|
||||
// Utility function to recreate a file with proper permissions
|
||||
static bool _recreate_file_(const std::filesystem::path& outpath, uint64_t file_hash, std::filesystem::perms file_perms, const unsigned char* filedata, size_t filedata_len) {
|
||||
namespace fs = std::filesystem;
|
||||
bool needs_write = false;
|
||||
|
||||
// Check if file exists and has correct hash
|
||||
if (fs::exists(outpath)) {
|
||||
// Check content hash
|
||||
std::ifstream in(outpath, std::ios::binary);
|
||||
std::ostringstream oss;
|
||||
oss << in.rdbuf();
|
||||
std::string data = oss.str();
|
||||
uint64_t existing_hash = fnv1a_64(data.data(), data.size());
|
||||
needs_write = existing_hash != file_hash;
|
||||
} else {
|
||||
needs_write = true; // File doesn't exist, need to create it
|
||||
}
|
||||
|
||||
bool needs_permission_update = true;
|
||||
if (!needs_write) { // we always update permissions if the file is written or changed. Othewise we check.
|
||||
fs::perms current_perms = fs::status(outpath).permissions();
|
||||
needs_permission_update = current_perms != file_perms;
|
||||
}
|
||||
|
||||
if (needs_write) {
|
||||
fs::create_directories(outpath.parent_path());
|
||||
std::ofstream out(outpath, std::ios::binary);
|
||||
out.write(reinterpret_cast<const char*>(filedata), filedata_len);
|
||||
out.close();
|
||||
// Set the file permissions
|
||||
fs::permissions(outpath, file_perms);
|
||||
|
||||
if (!fs::exists(outpath)) {
|
||||
std::cout << "[dehydrate] " << outpath.filename() << ": created\n";
|
||||
} else {
|
||||
std::cout << "[dehydrate] " << outpath.filename() << ": updated (hash changed)\n";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (needs_permission_update) {
|
||||
// Update only permissions
|
||||
fs::permissions(outpath, file_perms);
|
||||
std::cout << "[dehydrate] " << outpath.filename() << ": updated (permissions changed)\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool recreate_tree(std::string destination_folder) {
|
||||
namespace fs = std::filesystem;
|
||||
bool any_written = false;
|
||||
{
|
||||
// File: agent-install.sh
|
||||
fs::path outpath = fs::path(destination_folder) / "agent-install.sh";
|
||||
static const char filedata_base64[] = "IyEvYmluL2Jhc2gKClNDUklQVF9ESVI9JChkaXJuYW1lICIkMCIpCgplY2hvICJJbnN0YWxsaW5n"\
|
||||
"IGRyb3BzaGVsbCBob3N0IGFnZW50IG9uIHRoaXMgY29tcHV0ZXIuLi4iCgoKIyBQcmludHMgYW4g"\
|
||||
"ZXJyb3IgbWVzc2FnZSBpbiByZWQgYW5kIGV4aXRzIHdpdGggc3RhdHVzIGNvZGUgMS4KX2RpZSgp"\
|
||||
"IHsKICAgIGVjaG8gLWUgIkVycm9yOiAkMSIKICAgIGV4aXQgMQp9CgoKIyBDaGVja3MgaWYgbGlz"\
|
||||
"dGVkIGVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgc2V0OyBjYWxscyBfZGllKCkgaWYgYW55IGFy"\
|
||||
"ZSBtaXNzaW5nLgpfY2hlY2tfcmVxdWlyZWRfZW52X3ZhcnMoKSB7CiAgICBsb2NhbCByZXF1aXJl"\
|
||||
"ZF92YXJzPSgiJEAiKQogICAgZm9yIHZhciBpbiAiJHtyZXF1aXJlZF92YXJzW0BdfSI7IGRvCiAg"\
|
||||
"ICAgICAgaWYgWyAteiAiJHshdmFyfSIgXTsgdGhlbgogICAgICAgICAgICBfZGllICJSZXF1aXJl"\
|
||||
"ZCBlbnZpcm9ubWVudCB2YXJpYWJsZSAkdmFyIGlzIG5vdCBzZXQiCiAgICAgICAgZmkKICAgIGRv"\
|
||||
"bmUKfQoKIyBDaGVja3MgaWYgRG9ja2VyIGlzIGluc3RhbGxlZCwgcnVubmluZywgYW5kIHVzZXIg"\
|
||||
"aGFzIHBlcm1pc3Npb24uIFJldHVybnMgMSBvbiBmYWlsdXJlLgpfY2hlY2tfZG9ja2VyX2luc3Rh"\
|
||||
"bGxlZCgpIHsKICAgIGlmICEgY29tbWFuZCAtdiBkb2NrZXIgJj4gL2Rldi9udWxsOyB0aGVuCiAg"\
|
||||
"ICAgICAgZWNobyAiRG9ja2VyIGlzIG5vdCBpbnN0YWxsZWQiCiAgICAgICAgcmV0dXJuIDEKICAg"\
|
||||
"IGZpCgogICAgIyBjaGVjayBpZiBkb2NrZXIgZGFlbW9uIGlzIHJ1bm5pbmcKICAgIGlmICEgZG9j"\
|
||||
"a2VyIGluZm8gJj4gL2Rldi9udWxsOyB0aGVuCiAgICAgICAgZWNobyAiRG9ja2VyIGRhZW1vbiBp"\
|
||||
"cyBub3QgcnVubmluZyIKICAgICAgICByZXR1cm4gMQogICAgZmkKCiAgICAjIGNoZWNrIGlmIHVz"\
|
||||
"ZXIgaGFzIHBlcm1pc3Npb24gdG8gcnVuIGRvY2tlcgogICAgaWYgISBkb2NrZXIgcnVuIC0tcm0g"\
|
||||
"aGVsbG8td29ybGQgJj4gL2Rldi9udWxsOyB0aGVuCiAgICAgICAgZWNobyAiVXNlciBkb2VzIG5v"\
|
||||
"dCBoYXZlIHBlcm1pc3Npb24gdG8gcnVuIGRvY2tlciIKICAgICAgICByZXR1cm4gMQogICAgZmkK"\
|
||||
"CiAgICByZXR1cm4gMAp9CgpmdW5jdGlvbiBpbnN0YWxsX2JiNjQoKSB7ICAgIAogICAgIyBjaGVj"\
|
||||
"ayBjdXJsIGluc3RhbGxlZAogICAgaWYgISBjb21tYW5kIC12IGN1cmwgJj4gL2Rldi9udWxsOyB0"\
|
||||
"aGVuCiAgICAgICAgX2RpZSAiQ3VybCBpcyBub3QgaW5zdGFsbGVkLiBDdXJsIGlzIHJlcXVpcmVk"\
|
||||
"IGZvciBhZ2VudCBpbnN0YWxsYXRpb24uIgogICAgZmkKCiAgICBjdXJsIC1mc1NMICJodHRwczov"\
|
||||
"L2dpdGVhLmpkZS5uei9wdWJsaWMvYmI2NC9yZWxlYXNlcy9kb3dubG9hZC9sYXRlc3QvaW5zdGFs"\
|
||||
"bC5zaCIgfCBiYXNoIC1zIC0tICIkQUdFTlRfUEFUSCIgIiQoaWQgLXUgJFVTRVIpOiQoaWQgLWcg"\
|
||||
"JFVTRVIpIgoKICAgICMgdGVzdCByZXN1bHQgY29kZSBmcm9tIGN1cmwKICAgIGlmIFsgJD8gLW5l"\
|
||||
"IDAgXTsgdGhlbgogICAgICAgIF9kaWUgIkZhaWxlZCB0byBpbnN0YWxsIGJiNjQuIEN1cmwgcmV0"\
|
||||
"dXJuZWQgbm9uLXplcm8gZXhpdCBjb2RlLiIKICAgIGZpCgogICAgIyB0ZXN0IGlmIGJiNjQgaXMg"\
|
||||
"aW5zdGFsbGVkCiAgICAiJEFHRU5UX1BBVEgvYmI2NCIgLXYKICAgIGlmIFsgJD8gLW5lIDAgXTsg"\
|
||||
"dGhlbgogICAgICAgIF9kaWUgImJiNjQgZGlkIG5vdCBpbnN0YWxsIGNvcnJlY3RseS4iCiAgICBm"\
|
||||
"aQoKICAgIGVjaG8gImJiNjQgaW5zdGFsbGVkIHN1Y2Nlc3NmdWxseS4iCiAgICByZXR1cm4gMDsK"\
|
||||
"fQoKCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t"\
|
||||
"LS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpzZXQgLWEKQUdFTlRfUEFUSD0iJFNDUklQVF9ESVIiCnNl"\
|
||||
"dCArYQoKX2NoZWNrX3JlcXVpcmVkX2Vudl92YXJzICJBR0VOVF9QQVRIIgplY2hvICJJbnN0YWxs"\
|
||||
"aW5nIGhvc3QgYWdlbnQgaW50byAkQUdFTlRfUEFUSCIKCl9jaGVja19kb2NrZXJfaW5zdGFsbGVk"\
|
||||
"IHx8IF9kaWUgIkRvY2tlciBpcyByZXF1aXJlZC4iCgppbnN0YWxsX2JiNjQKCg==";
|
||||
|
||||
// Decode Base64 data
|
||||
size_t decoded_size = (strlen(filedata_base64) * 3) / 4;
|
||||
unsigned char* decoded_data = new unsigned char[decoded_size];
|
||||
size_t actual_size;
|
||||
base64_decode(filedata_base64, strlen(filedata_base64), decoded_data, &actual_size);
|
||||
|
||||
bool file_written = _recreate_file_(outpath, 14766786204011647584ULL, std::filesystem::perms(493), decoded_data, actual_size);
|
||||
delete[] decoded_data;
|
||||
any_written = any_written || file_written;
|
||||
}
|
||||
return any_written;
|
||||
}
|
||||
}
|
@ -10,6 +10,6 @@
|
||||
|
||||
|
||||
#include <string>
|
||||
namespace recreate_agent {
|
||||
namespace recreate_agent_local {
|
||||
bool recreate_tree(std::string destination_folder);
|
||||
}
|
@ -12,8 +12,8 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "_agent.hpp"
|
||||
namespace recreate_agent {
|
||||
#include "_agent-remote.hpp"
|
||||
namespace recreate_agent_remote {
|
||||
|
||||
|
||||
// Tiny dependency-free FNV-1a 64-bit hash
|
||||
@ -105,22 +105,6 @@ static bool _recreate_file_(const std::filesystem::path& outpath, uint64_t file_
|
||||
bool recreate_tree(std::string destination_folder) {
|
||||
namespace fs = std::filesystem;
|
||||
bool any_written = false;
|
||||
{
|
||||
// File: selftest.sh
|
||||
fs::path outpath = fs::path(destination_folder) / "selftest.sh";
|
||||
static const char filedata_base64[] = "IyEvYmluL2Jhc2gKCmVjaG8gIlJ1bm5pbmcgcmVtb3RlIGFnZW50IHNlbGYtdGVzdC4uLiIKCmVj"\
|
||||
"aG8gIkNvbXBsZXRlZCByZW1vdGUgYWdlbnQgc2VsZi10ZXN0LiIKCmV4aXQgMAo=";
|
||||
|
||||
// Decode Base64 data
|
||||
size_t decoded_size = (strlen(filedata_base64) * 3) / 4;
|
||||
unsigned char* decoded_data = new unsigned char[decoded_size];
|
||||
size_t actual_size;
|
||||
base64_decode(filedata_base64, strlen(filedata_base64), decoded_data, &actual_size);
|
||||
|
||||
bool file_written = _recreate_file_(outpath, 11594895391899191874ULL, std::filesystem::perms(493), decoded_data, actual_size);
|
||||
delete[] decoded_data;
|
||||
any_written = any_written || file_written;
|
||||
}
|
||||
{
|
||||
// File: datacommands.sh
|
||||
fs::path outpath = fs::path(destination_folder) / "datacommands.sh";
|
||||
@ -248,6 +232,48 @@ bool recreate_tree(std::string destination_folder) {
|
||||
delete[] decoded_data;
|
||||
any_written = any_written || file_written;
|
||||
}
|
||||
{
|
||||
// File: agent-install.sh
|
||||
fs::path outpath = fs::path(destination_folder) / "agent-install.sh";
|
||||
static const char filedata_base64[] = "IyEvYmluL2Jhc2gKCiMgVGhpcyBzY3JpcHQgaXMgdXNlZCB0byBpbnN0YWxsIHRoZSBkcm9wc2hl"\
|
||||
"bGwgYWdlbnQgb24gYSByZW1vdGUgc2VydmVyLgoKU0NSSVBUX0RJUj0kKGRpcm5hbWUgIiQwIikK"\
|
||||
"CnNldCAtYQoKQUdFTlRfUEFUSD0iJFNDUklQVF9ESVIiCgpzZXQgK2EKCgppZiBbIC1mICIkU0NS"\
|
||||
"SVBUX0RJUi9jb21tb24uc2giIF07IHRoZW4KICAgIHNvdXJjZSAiJFNDUklQVF9ESVIvY29tbW9u"\
|
||||
"LnNoIgplbHNlCiAgICBlY2hvICJFcnJvcjogY29tbW9uLnNoIG5vdCBmb3VuZCBpbiAkU0NSSVBU"\
|
||||
"X0RJUiIKICAgIGV4aXQgMQpmaQoKX2NoZWNrX3JlcXVpcmVkX2Vudl92YXJzICJBR0VOVF9QQVRI"\
|
||||
"IgoKZnVuY3Rpb24gaW5zdGFsbF9iYjY0KCkgeyAgICAKICAgICMgY2hlY2sgY3VybCBpbnN0YWxs"\
|
||||
"ZWQKICAgIGlmICEgY29tbWFuZCAtdiBjdXJsICY+IC9kZXYvbnVsbDsgdGhlbgogICAgICAgIF9k"\
|
||||
"aWUgIkN1cmwgaXMgbm90IGluc3RhbGxlZC4gQ3VybCBpcyByZXF1aXJlZCBmb3IgYWdlbnQgaW5z"\
|
||||
"dGFsbGF0aW9uLiIKICAgIGZpCgogICAgY3VybCAtZnNTTCAiaHR0cHM6Ly9naXRlYS5qZGUubnov"\
|
||||
"cHVibGljL2JiNjQvcmVsZWFzZXMvZG93bmxvYWQvbGF0ZXN0L2luc3RhbGwuc2giIHwgYmFzaCAt"\
|
||||
"cyAtLSAiJEFHRU5UX1BBVEgiICIkKGlkIC11ICRVU0VSKTokKGlkIC1nICRVU0VSKSIKCiAgICAj"\
|
||||
"IHRlc3QgcmVzdWx0IGNvZGUgZnJvbSBjdXJsCiAgICBpZiBbICQ/IC1uZSAwIF07IHRoZW4KICAg"\
|
||||
"ICAgICBfZGllICJGYWlsZWQgdG8gaW5zdGFsbCBiYjY0LiBDdXJsIHJldHVybmVkIG5vbi16ZXJv"\
|
||||
"IGV4aXQgY29kZS4iCiAgICBmaQoKICAgICMgdGVzdCBpZiBiYjY0IGlzIGluc3RhbGxlZAogICAg"\
|
||||
"IiRBR0VOVF9QQVRIL2JiNjQiIC12CiAgICBpZiBbICQ/IC1uZSAwIF07IHRoZW4KICAgICAgICBf"\
|
||||
"ZGllICJiYjY0IGRpZCBub3QgaW5zdGFsbCBjb3JyZWN0bHkuIgogICAgZmkKCiAgICBlY2hvICJi"\
|
||||
"YjY0IGluc3RhbGxlZCBzdWNjZXNzZnVsbHkuIgogICAgcmV0dXJuIDA7Cn0KCiMtLS0tLS0tLS0t"\
|
||||
"LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t"\
|
||||
"LS0tLS0tCgplY2hvICJJbnN0YWxsaW5nIGRyb3BzaGVsbCBhZ2VudC4uLiIKCmluc3RhbGxfYmI2"\
|
||||
"NAoKCgojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t"\
|
||||
"LS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKZWNobyAiUnVubmluZyByZW1vdGUgYWdlbnQgc2VsZi10"\
|
||||
"ZXN0Li4uIgoKCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t"\
|
||||
"LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgplY2hvICJDb21wbGV0ZWQgcmVtb3RlIGFnZW50"\
|
||||
"IHNlbGYtdGVzdC4iCgoKIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t"\
|
||||
"LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCmVjaG8gIkNvbXBsZXRlZCBkcm9wc2hl"\
|
||||
"bGwgYWdlbnQgaW5zdGFsbGF0aW9uLiIKCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t"\
|
||||
"LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpleGl0IDAK";
|
||||
|
||||
// Decode Base64 data
|
||||
size_t decoded_size = (strlen(filedata_base64) * 3) / 4;
|
||||
unsigned char* decoded_data = new unsigned char[decoded_size];
|
||||
size_t actual_size;
|
||||
base64_decode(filedata_base64, strlen(filedata_base64), decoded_data, &actual_size);
|
||||
|
||||
bool file_written = _recreate_file_(outpath, 8417440848759774142ULL, std::filesystem::perms(493), decoded_data, actual_size);
|
||||
delete[] decoded_data;
|
||||
any_written = any_written || file_written;
|
||||
}
|
||||
{
|
||||
// File: _allservicesstatus.sh
|
||||
fs::path outpath = fs::path(destination_folder) / "_allservicesstatus.sh";
|
15
source/src/autogen/_agent-remote.hpp
Normal file
15
source/src/autogen/_agent-remote.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
|
||||
THIS FILE IS AUTO-GENERATED BY DEHYDRATE.
|
||||
DO NOT EDIT THIS FILE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <string>
|
||||
namespace recreate_agent_remote {
|
||||
bool recreate_tree(std::string destination_folder);
|
||||
}
|
@ -5,7 +5,8 @@
|
||||
#include "templates.hpp"
|
||||
#include "shared_commands.hpp"
|
||||
#include "utils/hash.hpp"
|
||||
#include "autogen/_agent.hpp"
|
||||
#include "autogen/_agent-local.hpp"
|
||||
#include "autogen/_agent-remote.hpp"
|
||||
#include "services.hpp"
|
||||
#include "utils/output.hpp"
|
||||
|
||||
@ -248,24 +249,15 @@ namespace dropshell
|
||||
std::filesystem::create_directories(p);
|
||||
}
|
||||
|
||||
// download bb64 for the host architecture.
|
||||
if (!std::filesystem::exists(localpath::agent() + "bb64"))
|
||||
{
|
||||
std::string cmd = "cd " + localpath::agent() + " && curl -fsSL -o bb64 https://gitea.jde.nz/public/bb64/releases/download/latest/bb64.amd64 && chmod a+x bb64";
|
||||
int ret = system(cmd.c_str());
|
||||
if (EXITSTATUSCHECK(ret))
|
||||
info << "Downloaded local bb64 to " << localpath::agent() << std::endl;
|
||||
else
|
||||
error << "Failed to download local bb64 to " << localpath::agent() << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
info << "Updating local bb64..." << std::endl;
|
||||
system((localpath::agent() + "bb64 -u").c_str()); // update.
|
||||
}
|
||||
// create the agent-local directory.
|
||||
recreate_agent_local::recreate_tree(localpath::agent());
|
||||
|
||||
// run the local agent installer.
|
||||
execute_local_command(localpath::agent(), "agent-install.sh",{}, nullptr, cMode::Defaults | cMode::NoBB64);
|
||||
|
||||
// create the agent-remote directory.
|
||||
info << "Creating local files to copy to remote agents..." << std::endl;
|
||||
recreate_agent::recreate_tree(localpath::files_for_remote_agent());
|
||||
recreate_agent_remote::recreate_tree(localpath::files_for_remote_agent());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -295,23 +287,9 @@ namespace dropshell
|
||||
shared_commands::rsync_tree_to_remote(localpath::files_for_remote_agent(), agent_path, server_env, false);
|
||||
info << "done." << std::endl;
|
||||
|
||||
// add in bb64. We can't use execute_remote_command() here, as that relies on bb64 which we're installing!
|
||||
info << "Installing bb64 on " << server << "..." << std::endl
|
||||
<< std::flush;
|
||||
// run the agent installer. Can't use BB64 yet, as we're installing it on the remote server.
|
||||
|
||||
std::string remote_cmd =
|
||||
"ssh -p " + server_env.get_SSH_INFO().port + " " + server_env.get_SSH_INFO().user + "@" + server_env.get_SSH_INFO().host +
|
||||
" 'mkdir -p " + quote(agent_path) + " && curl -fsSL \"https://gitea.jde.nz/public/bb64/releases/download/latest/install.sh\" | bash -s -- " +
|
||||
quote(agent_path) + " " + quote("$(id -u " + server_env.get_SSH_USER() + "):$(id -g " + server_env.get_SSH_USER() + ")") + "'";
|
||||
|
||||
// std::cout << "Executing: " << remote_cmd << std::endl;
|
||||
if (!execute_local_command("", remote_cmd, {}, nullptr, cMode::Silent))
|
||||
error << "Failed to download bb64 to " << agent_path << " on remote server." << std::endl;
|
||||
else
|
||||
debug << "Downloaded bb64 to " << agent_path << " on remote server." << std::endl;
|
||||
|
||||
// run the self-test.
|
||||
bool okay = execute_ssh_command(server_env.get_SSH_INFO(), sCommand(agent_path, "./selftest.sh", {}), cMode::Defaults, nullptr);
|
||||
bool okay = execute_ssh_command(server_env.get_SSH_INFO(), sCommand(agent_path, "agent-install.sh",{}), cMode::Defaults | cMode::NoBB64, nullptr);
|
||||
if (!okay)
|
||||
{
|
||||
error << "ERROR: Failed to install remote agent on " << server << std::endl;
|
||||
|
@ -127,6 +127,16 @@ namespace dropshell
|
||||
|
||||
ASSERT(backup_details.has_value() && backup_details->is_valid(), "Invalid backup file.");
|
||||
|
||||
debug << "Backup details: " << std::endl;
|
||||
debug << " Backup filename: " << backup_details->get_filename() << std::endl;
|
||||
debug << " Backup template: " << backup_details->get_template_name() << std::endl;
|
||||
debug << " Backup taken from server: " << backup_details->get_server() << std::endl;
|
||||
debug << " Backup taken from service: " << backup_details->get_service() << std::endl;
|
||||
debug << " " << std::endl;
|
||||
debug << "Restoring to:" << std::endl;
|
||||
debug << " Server: " << server << std::endl;
|
||||
debug << " Service: " << service << std::endl;
|
||||
|
||||
std::string local_backups_dir = gConfig().get_local_backup_path();
|
||||
if (local_backups_dir.empty() || !std::filesystem::exists(local_backups_dir))
|
||||
{
|
||||
@ -143,14 +153,11 @@ namespace dropshell
|
||||
if (backup_details->get_template_name() != service_info.template_name)
|
||||
{
|
||||
error << "Error: Backup template does not match service template. Can't restore." << std::endl;
|
||||
debug << "Backup template: " << backup_details->get_template_name() << std::endl;
|
||||
debug << "Service template: " << service_info.template_name << std::endl;
|
||||
debug << "Backup file: " << local_backup_file_path << std::endl;
|
||||
info << "Backup template: " << backup_details->get_template_name() << std::endl;
|
||||
info << "Service template: " << service_info.template_name << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
info << "Restoring " << backup_details->get_datetime() << " backup of " << backup_details->get_service() << " taken from " << backup_details->get_server() << ", onto " << server << "/" << service << std::endl;
|
||||
info << std::endl;
|
||||
warning << "*** ALL DATA FOR " << server << "/" << service << " WILL BE OVERWRITTEN! ***" << std::endl;
|
||||
|
||||
// run the restore script
|
||||
@ -160,9 +167,9 @@ namespace dropshell
|
||||
info << "1) Backing up old service... " << std::endl;
|
||||
if (!shared_commands::backupdata_service(server, service))
|
||||
{
|
||||
error << "Error: Backup failed, restore aborted." << std::endl;
|
||||
error << "You can try using dropshell install " << server << " " << service << " to install the service afresh." << std::endl;
|
||||
error << "Otherwise, stop the service, create and initialise a new one, then restore to that." << std::endl;
|
||||
error << "Backup failed, restore aborted." << std::endl;
|
||||
info << "You can try using dropshell install " << server << " " << service << " to install the service afresh." << std::endl;
|
||||
info << "Otherwise, stop the service, create and initialise a new one, then restore to that." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
info << "Backup complete." << std::endl;
|
||||
|
@ -121,7 +121,7 @@ namespace dropshell
|
||||
|
||||
std::string output;
|
||||
if (!execute_ssh_command(env.get_SSH_INFO(), sCommand(remotepath::agent(server_name), "./_allservicesstatus.sh", {{"HOST_NAME", server_name}, {"SERVER", server_name}, {"AGENT_PATH", remotepath::agent(server_name)}}),
|
||||
cMode::CaptureOutput | cMode::Silent,
|
||||
cMode::Silent,
|
||||
&output))
|
||||
return status;
|
||||
|
||||
|
@ -218,8 +218,7 @@ bool server_env_manager::run_remote_template_command_and_capture_output(const st
|
||||
for (const auto& [key, value] : extra_env_vars)
|
||||
scommand->add_env_var(key, value);
|
||||
|
||||
cMode mode = cMode::CaptureOutput;
|
||||
return execute_ssh_command(get_SSH_INFO(), scommand.value(), mode, &output);
|
||||
return execute_ssh_command(get_SSH_INFO(), scommand.value(), cMode::Defaults, &output);
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,7 +22,6 @@ namespace dropshell
|
||||
return (ret != -1 && WIFEXITED(ret) && (WEXITSTATUS(ret) == 0)); // ret is -1 if the command failed to execute.
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------------
|
||||
// execute_local_command_interactive
|
||||
// ----------------------------------------------------------------------------------------------------------
|
||||
@ -30,7 +29,7 @@ namespace dropshell
|
||||
{
|
||||
if (command.get_command_to_run().empty())
|
||||
return false;
|
||||
std::string full_command = command.construct_cmd(localpath::agent()); // Get the command string
|
||||
std::string full_command = command.construct_cmd(localpath::agent()+"/bb64"); // Get the command string
|
||||
|
||||
pid_t pid = fork();
|
||||
|
||||
@ -88,12 +87,16 @@ namespace dropshell
|
||||
newline_ = (chunk[chunk.size() - 1] == '\n');
|
||||
}
|
||||
|
||||
void print(const std::string& buffer) {
|
||||
void print(const std::string &buffer)
|
||||
{
|
||||
size_t start = 0;
|
||||
while (start < buffer.size()) {
|
||||
while (start < buffer.size())
|
||||
{
|
||||
size_t newline_pos = buffer.find('\n', start);
|
||||
if (newline_pos == std::string::npos) {
|
||||
if (start < buffer.size()) {
|
||||
if (newline_pos == std::string::npos)
|
||||
{
|
||||
if (start < buffer.size())
|
||||
{
|
||||
print_chunk(buffer.substr(start));
|
||||
}
|
||||
break;
|
||||
@ -109,26 +112,30 @@ namespace dropshell
|
||||
sColour currentColour_;
|
||||
};
|
||||
|
||||
|
||||
bool execute_local_command(std::string directory_to_run_in, std::string command_to_run, const std::map<std::string, std::string> &env_vars, std::string *output, cMode mode)
|
||||
{
|
||||
sCommand command(directory_to_run_in, command_to_run, env_vars);
|
||||
|
||||
if (hasFlag(mode, cMode::Interactive))
|
||||
{
|
||||
ASSERT(!hasFlag(mode, cMode::CaptureOutput), "Interactive mode and capture output mode cannot be used together");
|
||||
ASSERT(output == nullptr, "Interactive mode and an output string cannot be used together");
|
||||
|
||||
return execute_local_command_interactive(command);
|
||||
}
|
||||
|
||||
|
||||
if (command.get_command_to_run().empty())
|
||||
return false;
|
||||
|
||||
bool silent = hasFlag(mode, cMode::Silent);
|
||||
|
||||
std::string full_cmd = command.construct_cmd(localpath::agent()) + (hasFlag(mode, cMode::CaptureOutput) ? " 2>&1" : ""); // capture both stdout and stderr
|
||||
std::string full_cmd;
|
||||
if (!hasFlag(mode, cMode::NoBB64))
|
||||
full_cmd = command.construct_cmd(localpath::agent()+"/bb64");
|
||||
else
|
||||
full_cmd = command.construct_cmd("");
|
||||
|
||||
if (output != nullptr)
|
||||
full_cmd += " 2>&1"; // capture both stdout and stderr
|
||||
|
||||
FILE *pipe = popen(full_cmd.c_str(), "r");
|
||||
if (!pipe)
|
||||
@ -157,17 +164,18 @@ namespace dropshell
|
||||
if (remote_command.get_command_to_run().empty())
|
||||
return false;
|
||||
|
||||
ASSERT(!(hasFlag(mode, cMode::CaptureOutput) && output == nullptr), "Capture output mode must be used with an output string");
|
||||
|
||||
std::stringstream ssh_cmd;
|
||||
ssh_cmd << "ssh -p " << ssh_info.port << " " << (hasFlag(mode, cMode::Interactive) ? "-tt " : "")
|
||||
<< ssh_info.user << "@" << ssh_info.host;
|
||||
|
||||
std::string remote_agent_path = remotepath::agent(ssh_info.server_ID);
|
||||
std::string remote_bb64_path;
|
||||
|
||||
if (!hasFlag(mode, cMode::NoBB64))
|
||||
remote_bb64_path = remotepath::agent(ssh_info.server_ID) + "/bb64";
|
||||
|
||||
bool rval = execute_local_command(
|
||||
"", // directory to run in
|
||||
ssh_cmd.str() + " " + remote_command.construct_cmd(remote_agent_path), // local command to run
|
||||
"", // local directory to run in
|
||||
ssh_cmd.str() + " " + remote_command.construct_cmd(remote_bb64_path), // local command to run
|
||||
{}, // environment variables
|
||||
output, // output string
|
||||
mode // mode
|
||||
@ -175,12 +183,8 @@ namespace dropshell
|
||||
|
||||
if (!rval && !hasFlag(mode, cMode::Silent))
|
||||
{
|
||||
std::cerr << std::endl
|
||||
<< std::endl;
|
||||
std::cerr << "Error: Failed to execute ssh command:" << std::endl;
|
||||
std::cerr << "\033[90m" << ssh_cmd.str() + " " + remote_command.construct_cmd(remote_agent_path) << "\033[0m" << std::endl;
|
||||
std::cerr << std::endl
|
||||
<< std::endl;
|
||||
error << "Error: Failed to execute ssh command:" << std::endl;
|
||||
debug << ssh_cmd.str() + " " + remote_command.construct_cmd(remote_bb64_path) << std::endl;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
@ -188,19 +192,19 @@ namespace dropshell
|
||||
// ----------------------------------------------------------------------------------------------------------
|
||||
// makesafecmd
|
||||
// ----------------------------------------------------------------------------------------------------------
|
||||
std::string sCommand::makesafecmd(std::string agent_path, const std::string &command) const
|
||||
std::string sCommand::makesafecmd(std::string bb64path, const std::string &command) const
|
||||
{
|
||||
if (command.empty())
|
||||
return "";
|
||||
std::string encoded = base64_encode(dequote(trim(command)));
|
||||
std::string commandstr = agent_path + "/bb64 " + encoded;
|
||||
std::string commandstr = bb64path + " " + encoded;
|
||||
return commandstr;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------------
|
||||
// construct_cmd
|
||||
// ----------------------------------------------------------------------------------------------------------
|
||||
std::string sCommand::construct_cmd(std::string agent_path) const
|
||||
std::string sCommand::construct_cmd(std::string bb64path) const
|
||||
{
|
||||
if (mCmd.empty())
|
||||
return "";
|
||||
@ -208,6 +212,8 @@ namespace dropshell
|
||||
// need to construct to change directory and set environment variables
|
||||
std::string cmdstr;
|
||||
|
||||
if (!bb64path.empty())
|
||||
{
|
||||
if (!mDir.empty())
|
||||
cmdstr += "cd " + quote(mDir) + " && ";
|
||||
|
||||
@ -217,8 +223,16 @@ namespace dropshell
|
||||
|
||||
cmdstr += mCmd;
|
||||
|
||||
if (!agent_path.empty())
|
||||
cmdstr = makesafecmd(agent_path, cmdstr);
|
||||
cmdstr = makesafecmd(bb64path, cmdstr);
|
||||
}
|
||||
else
|
||||
{ // raw! bootstrapping only.
|
||||
ASSERT(mVars.empty(), "Bootstrapping command must not have environment variables");
|
||||
if (!mDir.empty())
|
||||
cmdstr += mDir + "/" + mCmd;
|
||||
else
|
||||
cmdstr += mCmd;
|
||||
}
|
||||
|
||||
return cmdstr;
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ enum class cMode {
|
||||
Defaults = 0,
|
||||
Interactive = 1,
|
||||
Silent = 2,
|
||||
CaptureOutput = 4
|
||||
NoBB64 = 4
|
||||
};
|
||||
|
||||
inline cMode operator&(cMode lhs, cMode rhs) {return static_cast<cMode>(static_cast<int>(lhs) & static_cast<int>(rhs));}
|
||||
@ -52,10 +52,10 @@ class sCommand {
|
||||
|
||||
bool empty() const { return mCmd.empty(); }
|
||||
|
||||
std::string construct_cmd(std::string agent_path) const;
|
||||
std::string construct_cmd(std::string bb64path) const;
|
||||
|
||||
private:
|
||||
std::string makesafecmd(std::string agent_path, const std::string& command) const;
|
||||
std::string makesafecmd(std::string bb64path, const std::string& command) const;
|
||||
|
||||
private:
|
||||
std::string mDir;
|
||||
|
Loading…
x
Reference in New Issue
Block a user