This commit is contained in:
parent
ec5f4ad38d
commit
35c97728c9
28
runner/.gitignore
vendored
28
runner/.gitignore
vendored
@ -1,28 +0,0 @@
|
||||
# Build directory
|
||||
build/
|
||||
cmake-build-*/
|
||||
|
||||
# IDE files
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*~
|
||||
|
||||
# Compiled object files
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Compiled dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
runner
|
||||
|
||||
# CMake generated files
|
||||
CMakeCache.txt
|
||||
CMakeFiles/
|
||||
cmake_install.cmake
|
||||
Makefile
|
@ -1,17 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(runner_demo)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(LIBSSH REQUIRED libssh)
|
||||
include_directories(${LIBSSH_INCLUDE_DIRS})
|
||||
link_directories(${LIBSSH_LIBRARY_DIRS})
|
||||
|
||||
add_library(runner_lib runner.cpp)
|
||||
target_include_directories(runner_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(runner_lib ${LIBSSH_LIBRARIES})
|
||||
|
||||
add_executable(runner runner_demo.cpp)
|
||||
target_link_libraries(runner runner_lib OpenSSL::SSL OpenSSL::Crypto ${LIBSSH_LIBRARIES})
|
@ -1,42 +0,0 @@
|
||||
# Runner
|
||||
|
||||
Simple c++ demonstration program of the dropshell runner library.
|
||||
|
||||
use:
|
||||
runner
|
||||
|
||||
|
||||
The exit code is that of the command run, or -1 if the command couldn't be run.
|
||||
|
||||
|
||||
|
||||
The c++ library used, which is contained in this codebase, has one simple function:
|
||||
|
||||
typedef struct sSSHInfo {
|
||||
std::string host;
|
||||
std::string user;
|
||||
std::string port;
|
||||
} sSSHInfo;
|
||||
|
||||
|
||||
static int execute_cmd(
|
||||
const std::string& command,
|
||||
const std::vector<std::string>& args,
|
||||
const std::string& working_dir,
|
||||
const std::map<std::string, std::string>& env,
|
||||
bool silent,
|
||||
bool interactive,
|
||||
sSSHInfo * sshinfo = nullptr,
|
||||
std::string* output = nullptr,
|
||||
);
|
||||
|
||||
|
||||
If SSH information is provided, the command will be executed on the remote server. Otherwise on the local machine.
|
||||
|
||||
If output is provided, the output of the command is captured.
|
||||
|
||||
If interactive is true, then an interactive session is created - e.g. for running nano to remotely edit a file, or sshing into a docker container from the remote host.
|
||||
|
||||
If silent is true, then all output is suppressed.
|
||||
|
||||
Before the command is run, the current directory is changed to working_dir on the remote host (or local host if no ssh info provided).
|
@ -1,34 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Check for cmake
|
||||
if ! command -v cmake &> /dev/null; then
|
||||
echo "Error: cmake is not installed. Please install cmake." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for g++
|
||||
if ! command -v g++ &> /dev/null; then
|
||||
echo "Error: g++ is not installed. Please install g++." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for OpenSSL
|
||||
if ! pkg-config --exists openssl; then
|
||||
echo "Error: OpenSSL development libraries not found. Please install libssl-dev." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BUILD_DIR=build
|
||||
mkdir -p "$BUILD_DIR"
|
||||
cd "$BUILD_DIR"
|
||||
|
||||
cmake ..
|
||||
make -j$(nproc)
|
||||
|
||||
if [ -f runner ]; then
|
||||
echo "Build successful. Run ./build/runner"
|
||||
else
|
||||
echo "Build failed. Check the output above for errors."
|
||||
exit 1
|
||||
fi
|
25578
runner/nlohmann/json.hpp
25578
runner/nlohmann/json.hpp
File diff suppressed because it is too large
Load Diff
@ -1,187 +0,0 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||
#define INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||
|
||||
#include <cstdint> // int64_t, uint64_t
|
||||
#include <map> // map
|
||||
#include <memory> // allocator
|
||||
#include <string> // string
|
||||
#include <vector> // vector
|
||||
|
||||
// #include <nlohmann/detail/abi_macros.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
|
||||
// This file contains all macro definitions affecting or depending on the ABI
|
||||
|
||||
#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK
|
||||
#if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH)
|
||||
#if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 12 || NLOHMANN_JSON_VERSION_PATCH != 0
|
||||
#warning "Already included a different version of the library!"
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum)
|
||||
#define NLOHMANN_JSON_VERSION_MINOR 12 // NOLINT(modernize-macro-to-enum)
|
||||
#define NLOHMANN_JSON_VERSION_PATCH 0 // NOLINT(modernize-macro-to-enum)
|
||||
|
||||
#ifndef JSON_DIAGNOSTICS
|
||||
#define JSON_DIAGNOSTICS 0
|
||||
#endif
|
||||
|
||||
#ifndef JSON_DIAGNOSTIC_POSITIONS
|
||||
#define JSON_DIAGNOSTIC_POSITIONS 0
|
||||
#endif
|
||||
|
||||
#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0
|
||||
#endif
|
||||
|
||||
#if JSON_DIAGNOSTICS
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag
|
||||
#else
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS
|
||||
#endif
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS _dp
|
||||
#else
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS
|
||||
#endif
|
||||
|
||||
#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp
|
||||
#else
|
||||
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#endif
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
|
||||
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
|
||||
#endif
|
||||
|
||||
// Construct the namespace ABI tags component
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) json_abi ## a ## b ## c
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c) \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c)
|
||||
|
||||
#define NLOHMANN_JSON_ABI_TAGS \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
|
||||
NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \
|
||||
NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON, \
|
||||
NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS)
|
||||
|
||||
// Construct the namespace version component
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
|
||||
_v ## major ## _ ## minor ## _ ## patch
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \
|
||||
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch)
|
||||
|
||||
#if NLOHMANN_JSON_NAMESPACE_NO_VERSION
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION
|
||||
#else
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION \
|
||||
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \
|
||||
NLOHMANN_JSON_VERSION_MINOR, \
|
||||
NLOHMANN_JSON_VERSION_PATCH)
|
||||
#endif
|
||||
|
||||
// Combine namespace components
|
||||
#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b
|
||||
#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \
|
||||
NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b)
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE
|
||||
#define NLOHMANN_JSON_NAMESPACE \
|
||||
nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \
|
||||
NLOHMANN_JSON_ABI_TAGS, \
|
||||
NLOHMANN_JSON_NAMESPACE_VERSION)
|
||||
#endif
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
#define NLOHMANN_JSON_NAMESPACE_BEGIN \
|
||||
namespace nlohmann \
|
||||
{ \
|
||||
inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \
|
||||
NLOHMANN_JSON_ABI_TAGS, \
|
||||
NLOHMANN_JSON_NAMESPACE_VERSION) \
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE_END
|
||||
#define NLOHMANN_JSON_NAMESPACE_END \
|
||||
} /* namespace (inline namespace) NOLINT(readability/namespace) */ \
|
||||
} // namespace nlohmann
|
||||
#endif
|
||||
|
||||
|
||||
/*!
|
||||
@brief namespace for Niels Lohmann
|
||||
@see https://github.com/nlohmann
|
||||
@since version 1.0.0
|
||||
*/
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
|
||||
/*!
|
||||
@brief default JSONSerializer template argument
|
||||
|
||||
This serializer ignores the template arguments and uses ADL
|
||||
([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))
|
||||
for serialization.
|
||||
*/
|
||||
template<typename T = void, typename SFINAE = void>
|
||||
struct adl_serializer;
|
||||
|
||||
/// a class to store JSON values
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/
|
||||
template<template<typename U, typename V, typename... Args> class ObjectType =
|
||||
std::map,
|
||||
template<typename U, typename... Args> class ArrayType = std::vector,
|
||||
class StringType = std::string, class BooleanType = bool,
|
||||
class NumberIntegerType = std::int64_t,
|
||||
class NumberUnsignedType = std::uint64_t,
|
||||
class NumberFloatType = double,
|
||||
template<typename U> class AllocatorType = std::allocator,
|
||||
template<typename T, typename SFINAE = void> class JSONSerializer =
|
||||
adl_serializer,
|
||||
class BinaryType = std::vector<std::uint8_t>, // cppcheck-suppress syntaxError
|
||||
class CustomBaseClass = void>
|
||||
class basic_json;
|
||||
|
||||
/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document
|
||||
/// @sa https://json.nlohmann.me/api/json_pointer/
|
||||
template<typename RefStringType>
|
||||
class json_pointer;
|
||||
|
||||
/*!
|
||||
@brief default specialization
|
||||
@sa https://json.nlohmann.me/api/json/
|
||||
*/
|
||||
using json = basic_json<>;
|
||||
|
||||
/// @brief a minimal map-like container that preserves insertion order
|
||||
/// @sa https://json.nlohmann.me/api/ordered_map/
|
||||
template<class Key, class T, class IgnoredLess, class Allocator>
|
||||
struct ordered_map;
|
||||
|
||||
/// @brief specialization that maintains the insertion order of object keys
|
||||
/// @sa https://json.nlohmann.me/api/ordered_json/
|
||||
using ordered_json = basic_json<nlohmann::ordered_map>;
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
@ -1,132 +0,0 @@
|
||||
#include "runner.h"
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
// Simple testing framework
|
||||
#define TESTRESULT(condition, description) \
|
||||
do { \
|
||||
std::cout << (condition ? "\033[32m[PASS]\033[0m " : "\033[31m[FAIL]\033[0m ") << description; \
|
||||
if (!(condition)) { \
|
||||
std::cout << " - Expected condition to be true"; \
|
||||
} \
|
||||
std::cout << std::endl; \
|
||||
} while(0)
|
||||
|
||||
// using json = nlohmann::json;
|
||||
|
||||
// std::string base64_decode(const std::string& encoded) {
|
||||
// BIO* bio, *b64;
|
||||
// int decodeLen = (encoded.length() * 3) / 4;
|
||||
// std::string decoded(decodeLen, '\0');
|
||||
// bio = BIO_new_mem_buf(encoded.data(), encoded.length());
|
||||
// b64 = BIO_new(BIO_f_base64());
|
||||
// bio = BIO_push(b64, bio);
|
||||
// BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
|
||||
// int len = BIO_read(bio, &decoded[0], encoded.length());
|
||||
// decoded.resize(len > 0 ? len : 0);
|
||||
// BIO_free_all(bio);
|
||||
// return decoded;
|
||||
// }
|
||||
|
||||
// int main(int argc, char* argv[]) {
|
||||
// if (argc != 2) {
|
||||
// std::cerr << "Usage: runner BASE64COMMAND\n";
|
||||
// return -1;
|
||||
// }
|
||||
// std::string decoded = base64_decode(argv[1]);
|
||||
// json j;
|
||||
// try {
|
||||
// j = json::parse(decoded);
|
||||
// } catch (...) {
|
||||
// std::cerr << "Invalid JSON in decoded command\n";
|
||||
// return -1;
|
||||
// }
|
||||
// std::string command = j.value("command", "");
|
||||
// std::vector<std::string> args = j.value("args", std::vector<std::string>{});
|
||||
// std::string working_dir = j.value("working_dir", "");
|
||||
// std::map<std::string, std::string> env = j.value("env", std::map<std::string, std::string>{});
|
||||
// bool silent = j.value("silent", false);
|
||||
// bool interactive = j.value("interactive", false);
|
||||
// sSSHInfo* sshinfo = nullptr;
|
||||
// sSSHInfo ssh;
|
||||
// if (j.contains("sshinfo")) {
|
||||
// ssh.host = j["sshinfo"].value("host", "");
|
||||
// ssh.user = j["sshinfo"].value("user", "");
|
||||
// ssh.port = j["sshinfo"].value("port", "");
|
||||
// sshinfo = &ssh;
|
||||
// }
|
||||
// std::string output;
|
||||
// int ret = execute_cmd(command, args, working_dir, env, silent, interactive, sshinfo, &output);
|
||||
// if (!silent && !output.empty()) {
|
||||
// std::cout << output;
|
||||
// }
|
||||
// return ret;
|
||||
// }
|
||||
|
||||
void test_docker() {
|
||||
std::string command = "docker";
|
||||
std::vector<std::string> args = {"exec", "-it", "squashkiwi", "/bin/bash"};
|
||||
std::string working_dir = ".";
|
||||
std::map<std::string, std::string> env = {};
|
||||
bool silent = false;
|
||||
bool interactive = true;
|
||||
runner::sSSHInfo ssh;
|
||||
ssh.host = "10.10.10.13";
|
||||
ssh.user = "katie";
|
||||
ssh.port = "22";
|
||||
|
||||
runner::execute_cmd(command, args, working_dir, env, silent, interactive, &ssh);
|
||||
}
|
||||
|
||||
void test_ssh() {
|
||||
std::string command = "bash";
|
||||
std::vector<std::string> args = {"-c", "ls -l && echo \"$WHATSUP\""};
|
||||
std::string working_dir = "/home";
|
||||
std::map<std::string, std::string> env = {{"WHATSUP", "Waaaaattttsssuuuppppp!"}};
|
||||
bool silent = true;
|
||||
bool interactive = false;
|
||||
runner::sSSHInfo ssh;
|
||||
ssh.host = "10.10.10.13";
|
||||
ssh.user = "katie";
|
||||
ssh.port = "22";
|
||||
|
||||
std::string output;
|
||||
int ret = runner::execute_cmd(command, args, working_dir, env, silent, interactive, &ssh, &output);
|
||||
TESTRESULT(ret == 0, "SSH test (ls and echo).");
|
||||
}
|
||||
|
||||
void test_env() {
|
||||
std::string command = "bash";
|
||||
// Simplify the command to avoid nested quoting issues
|
||||
std::vector<std::string> args = {"-c", "echo $WHATSUP"};
|
||||
std::string working_dir = "/home";
|
||||
std::map<std::string, std::string> env = {{"WHATSUP", "Waaaaattttsssuuuppppp!"}};
|
||||
bool silent = false;
|
||||
bool interactive = false;
|
||||
runner::sSSHInfo ssh;
|
||||
ssh.host = "10.10.10.13";
|
||||
ssh.user = "katie";
|
||||
ssh.port = "22";
|
||||
|
||||
// Capture output explicitly
|
||||
std::string output;
|
||||
int ret = runner::execute_cmd(command, args, working_dir, env, silent, interactive, &ssh, &output);
|
||||
|
||||
TESTRESULT(output == "Waaaaattttsssuuuppppp!","Whatsupppp test (remote env).");
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
test_ssh();
|
||||
test_env();
|
||||
}
|
||||
|
@ -5,7 +5,9 @@
|
||||
#include "templates.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
#include "utils/json.hpp"
|
||||
#include "utils/execute.hpp"
|
||||
#include "utils/runner.hpp"
|
||||
|
||||
#include <libassert/assert.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
@ -102,94 +104,82 @@ std::string server_env_manager::get_variable(const std::string& name) const {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
sCommand server_env_manager::construct_standard_template_run_cmd(const std::string &service_name, const std::string &command, std::vector<std::string> args, bool silent) const
|
||||
{
|
||||
if (command.empty())
|
||||
return sCommand();
|
||||
// sCommand server_env_manager::construct_standard_template_run_cmd(const std::string &service_name, const std::string &command, std::vector<std::string> args, bool silent) const
|
||||
// {
|
||||
// if (command.empty())
|
||||
// return sCommand();
|
||||
|
||||
std::string remote_service_template_path = remotepath::service_template(mServerName,service_name);
|
||||
std::string script_path = remote_service_template_path + "/" + command + ".sh";
|
||||
// std::string remote_service_template_path = remotepath::service_template(mServerName,service_name);
|
||||
// std::string script_path = remote_service_template_path + "/" + command + ".sh";
|
||||
|
||||
std::map<std::string, std::string> env_vars;
|
||||
if (!get_all_service_env_vars(mServerName, service_name, env_vars)) {
|
||||
std::cerr << "Error: Failed to get all service env vars for " << service_name << std::endl;
|
||||
return sCommand();
|
||||
}
|
||||
// std::map<std::string, std::string> env_vars;
|
||||
// if (!get_all_service_env_vars(mServerName, service_name, env_vars)) {
|
||||
// std::cerr << "Error: Failed to get all service env vars for " << service_name << std::endl;
|
||||
// return sCommand();
|
||||
// }
|
||||
|
||||
std::string argstr = "";
|
||||
for (const auto& arg : args) {
|
||||
argstr += " " + quote(dequote(trim(arg)));
|
||||
}
|
||||
// std::string argstr = "";
|
||||
// for (const auto& arg : args) {
|
||||
// argstr += " " + quote(dequote(trim(arg)));
|
||||
// }
|
||||
|
||||
sCommand scommand(remote_service_template_path, "bash " + quote(script_path) + argstr + (silent ? " > /dev/null 2>&1" : ""), env_vars);
|
||||
// sCommand scommand(remote_service_template_path, "bash " + quote(script_path) + argstr + (silent ? " > /dev/null 2>&1" : ""), env_vars);
|
||||
|
||||
if (scommand.empty())
|
||||
std::cerr << "Error: Failed to construct command for " << service_name << " " << command << std::endl;
|
||||
// if (scommand.empty())
|
||||
// std::cerr << "Error: Failed to construct command for " << service_name << " " << command << std::endl;
|
||||
|
||||
return scommand;
|
||||
}
|
||||
// return scommand;
|
||||
// }
|
||||
|
||||
|
||||
bool server_env_manager::check_remote_dir_exists(const std::string &dir_path) const
|
||||
{
|
||||
sCommand scommand("test -d " + quote(dir_path));
|
||||
return execute_ssh_command(get_SSH_INFO(), scommand, cMode::Silent);
|
||||
return 0==runner::execute_cmd("test",{"-d", quote(dir_path)}, {}, {}, true, false, &get_SSH_INFO());
|
||||
}
|
||||
|
||||
bool server_env_manager::check_remote_file_exists(const std::string& file_path) const {
|
||||
sCommand scommand("test -f " + quote(file_path));
|
||||
return execute_ssh_command(get_SSH_INFO(), scommand, cMode::Silent);
|
||||
return 0==runner::execute_cmd("test",{"-f",quote(file_path)}, {}, {}, true, false, &get_SSH_INFO());
|
||||
}
|
||||
|
||||
bool server_env_manager::check_remote_items_exist(const std::vector<std::string> &file_paths) const
|
||||
{
|
||||
// convert file_paths to a single string, separated by spaces
|
||||
std::string file_paths_str;
|
||||
std::string file_names_str;
|
||||
for (const auto& file_path : file_paths) {
|
||||
file_paths_str += quote(file_path) + " ";
|
||||
file_names_str += std::filesystem::path(file_path).filename().string() + " ";
|
||||
}
|
||||
// check if all items in the vector exist on the remote server, in a single command.
|
||||
sCommand scommand("for item in " + file_paths_str + "; do test -f $item; done");
|
||||
|
||||
bool okay = execute_ssh_command(get_SSH_INFO(), scommand, cMode::Silent);
|
||||
if (!okay) {
|
||||
std::cerr << "Error: Required items not found on remote server: " << file_names_str << std::endl;
|
||||
return 0==runner::execute_cmd("bash",{"-c","for item in " + file_paths_str + "; do test -f $item; done"}, {}, {}, true, false, &get_SSH_INFO());
|
||||
}
|
||||
|
||||
bool server_env_manager::run_remote_template_command(const std::string &service_name, const std::string &command, std::vector<std::string> args, bool silent, std::map<std::string, std::string> extra_env_vars, std::string * output) const
|
||||
{
|
||||
std::string working_dir = remotepath::service_template(mServerName,service_name);
|
||||
std::string script_path = working_dir + "/" + command + ".sh";
|
||||
std::string argstr = "";
|
||||
for (const auto& arg : args) {
|
||||
argstr += " " + quote(dequote(trim(arg)));
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> env_vars;
|
||||
if (!get_all_service_env_vars(mServerName, service_name, env_vars)) {
|
||||
std::cerr << "Error: Failed to get all service env vars for " << service_name << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool server_env_manager::run_remote_template_command(const std::string &service_name, const std::string &command, std::vector<std::string> args, bool silent, std::map<std::string, std::string> extra_env_vars) const
|
||||
{
|
||||
sCommand scommand = construct_standard_template_run_cmd(service_name, command, args, silent);
|
||||
|
||||
|
||||
// add the extra env vars to the command
|
||||
for (const auto& [key, value] : extra_env_vars)
|
||||
scommand.add_env_var(key, value);
|
||||
env_vars[key] = value;
|
||||
|
||||
if (scommand.get_command_to_run().empty())
|
||||
return false;
|
||||
cMode mode = (command=="ssh") ? (cMode::Interactive | cMode::RawCommand) : cMode::Silent;
|
||||
return execute_ssh_command(get_SSH_INFO(), scommand, mode);
|
||||
bool interactive = (command=="ssh");
|
||||
|
||||
ASSERT(!output || !silent); // if output is captured, silent must be false
|
||||
ASSERT(!interactive || !silent); // if command is ssh, silent must be false
|
||||
|
||||
return 0==runner::execute_cmd("bash",{"-c", quote(script_path) + argstr}, working_dir, env_vars, silent, interactive, &get_SSH_INFO(), output);
|
||||
}
|
||||
|
||||
bool server_env_manager::run_remote_template_command_and_capture_output(const std::string &service_name, const std::string &command, std::vector<std::string> args, std::string &output, bool silent, std::map<std::string, std::string> extra_env_vars) const
|
||||
{
|
||||
sCommand scommand = construct_standard_template_run_cmd(service_name, command, args, false);
|
||||
if (scommand.get_command_to_run().empty())
|
||||
return false;
|
||||
|
||||
// add the extra env vars to the command
|
||||
for (const auto& [key, value] : extra_env_vars)
|
||||
scommand.add_env_var(key, value);
|
||||
|
||||
cMode mode = cMode::CaptureOutput | cMode::RawCommand;
|
||||
return execute_ssh_command(get_SSH_INFO(), scommand, mode, &output);
|
||||
}
|
||||
|
||||
|
||||
// base64 <<< "FOO=BAR WHEE=YAY bash ./test.sh"
|
||||
// echo YmFzaCAtYyAnRk9PPUJBUiBXSEVFPVlBWSBiYXNoIC4vdGVzdC5zaCcK | base64 -d | bash
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "utils/execute.hpp"
|
||||
|
||||
namespace dropshell {
|
||||
|
||||
@ -43,7 +42,7 @@ class server_env_manager {
|
||||
std::string get_SSH_USER() const { return get_variable("SSH_USER"); }
|
||||
std::string get_SSH_PORT() const { return get_variable("SSH_PORT"); }
|
||||
std::string get_DROPSHELL_DIR() const { return get_variable("DROPSHELL_DIR"); }
|
||||
sSSHInfo get_SSH_INFO() const { return sSSHInfo{get_SSH_HOST(), get_SSH_USER(), get_SSH_PORT()}; }
|
||||
runner::sSSHInfo get_SSH_INFO() const { return runner::sSSHInfo{get_SSH_HOST(), get_SSH_USER(), get_SSH_PORT()}; }
|
||||
bool is_valid() const { return mValid; }
|
||||
std::string get_server_name() const { return mServerName; }
|
||||
|
||||
@ -54,12 +53,10 @@ class server_env_manager {
|
||||
bool check_remote_items_exist(const std::vector<std::string>& file_paths) const;
|
||||
|
||||
bool run_remote_template_command(const std::string& service_name, const std::string& command,
|
||||
std::vector<std::string> args, bool silent, std::map<std::string, std::string> extra_env_vars) const;
|
||||
bool run_remote_template_command_and_capture_output(const std::string& service_name, const std::string& command,
|
||||
std::vector<std::string> args, std::string & output, bool silent, std::map<std::string, std::string> extra_env_vars) const;
|
||||
std::vector<std::string> args = {}, bool silent = false, std::map<std::string, std::string> extra_env_vars = {}, std::string * output = nullptr) const;
|
||||
|
||||
private:
|
||||
sCommand construct_standard_template_run_cmd(const std::string& service_name, const std::string& command, std::vector<std::string> args, bool silent) const;
|
||||
//sCommand construct_standard_template_run_cmd(const std::string& service_name, const std::string& command, std::vector<std::string> args, bool silent) const;
|
||||
|
||||
private:
|
||||
std::string mServerName;
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
@ -16,7 +15,7 @@
|
||||
#include "services.hpp"
|
||||
#include "utils/directories.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
#include "utils/runner.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
@ -54,17 +53,14 @@ bool service_runner::install(bool silent) {
|
||||
return false;
|
||||
|
||||
// Create service directory
|
||||
std::string remote_service_path = remotepath::service(mServer, mService);
|
||||
std::string mkdir_cmd = "mkdir -p " + quote(remote_service_path);
|
||||
if (!execute_ssh_command(mServerEnv.get_SSH_INFO(), sCommand(mkdir_cmd), cMode::Silent))
|
||||
if (0!=runner::execute_cmd("mkdir -p " + remotepath::service(mServer, mService),{},"",{},true,false,&mServerEnv.get_SSH_INFO()))
|
||||
{
|
||||
std::cerr << "Failed to create service directory " << remote_service_path << std::endl;
|
||||
std::cerr << "Failed to create service directory " << remotepath::service(mServer, mService) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if rsync is installed on remote host
|
||||
std::string check_rsync_cmd = "which rsync > /dev/null 2>&1";
|
||||
if (!execute_ssh_command(mServerEnv.get_SSH_INFO(), sCommand(check_rsync_cmd), cMode::Silent))
|
||||
if (0!=runner::execute_cmd("which rsync",{},"",{},true,false,&mServerEnv.get_SSH_INFO()))
|
||||
{
|
||||
std::cerr << "rsync is not installed on the remote host" << std::endl;
|
||||
return false;
|
||||
@ -72,16 +68,7 @@ bool service_runner::install(bool silent) {
|
||||
|
||||
// Copy template files
|
||||
{
|
||||
std::cout << "Copying: [LOCAL] " << tinfo.local_template_path() << std::endl << std::string(8,' ')<<"[REMOTE] " << remotepath::service_template(mServer, mService) << "/" << std::endl;
|
||||
std::string rsync_cmd = "rsync --delete -zrpc -e 'ssh -p " + mServerEnv.get_SSH_PORT() + "' " +
|
||||
quote(tinfo.local_template_path().string()+"/") + " "+
|
||||
mServerEnv.get_SSH_USER() + "@" + mServerEnv.get_SSH_HOST() + ":" +
|
||||
quote(remotepath::service_template(mServer, mService)+"/");
|
||||
//std::cout << std::endl << rsync_cmd << std::endl << std::endl;
|
||||
if (!execute_local_command(rsync_cmd, silent ? cMode::Silent : cMode::None))
|
||||
{
|
||||
std::cerr << "Failed to copy template files using rsync" << std::endl;
|
||||
std::cerr << "Is rsync installed on the remote host?" << std::endl;
|
||||
if (!rsync_copy(tinfo.local_template_path().string()+"/", remotepath::service_template(mServer, mService)+"/", silent)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -93,14 +80,8 @@ bool service_runner::install(bool silent) {
|
||||
std::cerr << "Error: Service directory not found: " << local_service_path << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::cout << "Copying: [LOCAL] " << local_service_path << std::endl <<std::string(8,' ')<<"[REMOTE] " << remotepath::service_config(mServer,mService) << std::endl;
|
||||
std::string rsync_cmd = "rsync --delete -zrpc -e 'ssh -p " + mServerEnv.get_SSH_PORT() + "' " +
|
||||
quote(local_service_path + "/") + " "+
|
||||
mServerEnv.get_SSH_USER() + "@" + mServerEnv.get_SSH_HOST() + ":" +
|
||||
quote(remotepath::service_config(mServer,mService) + "/");
|
||||
if (!execute_local_command(rsync_cmd, silent ? cMode::Silent : cMode::None))
|
||||
{
|
||||
std::cerr << "Failed to copy service files using rsync" << std::endl;
|
||||
|
||||
if (!rsync_copy(local_service_path + "/", remotepath::service_config(mServer,mService) + "/", silent)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -141,12 +122,9 @@ bool service_runner::uninstall(bool silent) {
|
||||
}
|
||||
|
||||
// 4. Remove the service directory from the server
|
||||
std::string rm_cmd = "rm -rf " + quote(remotepath::service(mServer, mService));
|
||||
if (!execute_ssh_command(mServerEnv.get_SSH_INFO(), sCommand(rm_cmd), cMode::Silent)) {
|
||||
std::cerr << "Failed to remove service directory" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0!=runner::execute_cmd("rm -rf " + quote(remotepath::service(mServer, mService)), {}, "", {}, true, false, &mServerEnv.get_SSH_INFO()))
|
||||
std::cerr << "Failed to remove remote service directory at " << remotepath::service(mServer, mService) << std::endl;
|
||||
|
||||
std::cout << "Service " << mService << " successfully uninstalled from " << mServer << std::endl;
|
||||
return true;
|
||||
}
|
||||
@ -189,12 +167,10 @@ bool service_runner::fullnuke()
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string rm_cmd = "rm -rf " + quote(local_service_path);
|
||||
if (!execute_local_command(rm_cmd, cMode::Silent)) {
|
||||
std::cerr << "Failed to remove service directory" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0!=runner::execute_cmd("rm -rf " + quote(local_service_path), {}, "", {}, true, false, &mServerEnv.get_SSH_INFO()))
|
||||
std::cerr << "Failed to remove local service directory at " << local_service_path << std::endl;
|
||||
|
||||
std::cout << "Service " << mService << " successfully fully nuked from " << mServer << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -296,15 +272,13 @@ std::map<std::string, ServiceStatus> service_runner::get_all_services_status(std
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
std::string remote_service_template_path = remotepath::service_template(server_name,service_name);
|
||||
std::string script_path = remote_service_template_path + "/shared/" + command + ".sh";
|
||||
sCommand scommand(remote_service_template_path, "bash " + quote(script_path), {});
|
||||
|
||||
std::string cmd_path = remotepath::service_template(server_name,service_name) + "/shared/";
|
||||
std::string output;
|
||||
cMode mode = cMode::CaptureOutput | cMode::RawCommand;
|
||||
if (!execute_ssh_command(env.get_SSH_INFO(), scommand, mode, &output))
|
||||
if (0!=runner::execute_cmd("bash",{cmd_path+command+".sh"}, cmd_path, {}, true, false, &env.get_SSH_INFO(), &output))
|
||||
{
|
||||
std::cerr << "Error: Failed to run command script at " << cmd_path << std::endl;
|
||||
return status;
|
||||
}
|
||||
|
||||
std::stringstream ss(output);
|
||||
std::string line;
|
||||
@ -772,4 +746,20 @@ std::string service_runner::get_latest_backup_file(const std::string& server, co
|
||||
return latest_file;
|
||||
}
|
||||
|
||||
bool service_runner::rsync_copy(const std::string& local_path, const std::string& remote_path, bool silent) {
|
||||
std::cout << "Copying: [LOCAL] " << local_path << std::endl << std::string(8,' ')<<"[REMOTE] " << remote_path << std::endl;
|
||||
|
||||
std::string rsync_cmd = "rsync --delete -zrpc -e 'ssh -p " + mServerEnv.get_SSH_PORT() + "' " +
|
||||
quote(local_path) + " " +
|
||||
mServerEnv.get_SSH_USER() + "@" + mServerEnv.get_SSH_HOST() + ":" +
|
||||
quote(remote_path);
|
||||
|
||||
if (0 != runner::execute_cmd(rsync_cmd, {}, "", {}, true, false, &mServerEnv.get_SSH_INFO())) {
|
||||
std::cerr << "Failed to copy files using rsync" << std::endl;
|
||||
std::cerr << "Is rsync installed on the remote host?" << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace dropshell
|
@ -87,6 +87,8 @@ class service_runner {
|
||||
// edit the service configuration file
|
||||
void edit_service_config();
|
||||
|
||||
// Helper methods
|
||||
bool rsync_copy(const std::string& local_path, const std::string& remote_path, bool silent);
|
||||
|
||||
public:
|
||||
// utility functions
|
||||
|
@ -1,182 +0,0 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <libassert/assert.hpp>
|
||||
|
||||
#include "execute.hpp"
|
||||
#include "contrib/base64.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
|
||||
bool EXITSTATUSCHECK(int ret) {
|
||||
return (ret != -1 && WIFEXITED(ret) && (WEXITSTATUS(ret) == 0)); // ret is -1 if the command failed to execute.
|
||||
}
|
||||
|
||||
namespace dropshell {
|
||||
bool execute_local_command_interactive(const sCommand &command, bool silent)
|
||||
{
|
||||
if (command.get_command_to_run().empty())
|
||||
return false;
|
||||
std::string full_command = command.construct_cmd(cStyle::Raw); // Get the command string
|
||||
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid == -1) {
|
||||
// Fork failed
|
||||
perror("fork failed");
|
||||
return false;
|
||||
} else if (pid == 0) {
|
||||
// Child process
|
||||
std::vector<const char *> commandvec = {"bash", "-c", full_command.c_str(),NULL};
|
||||
|
||||
if (!silent) {
|
||||
std::cout << "Executing command: ";
|
||||
for (auto & x : commandvec) std::cout << x << " ";
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
execvp(commandvec[0], const_cast<char* const*>(commandvec.data()));
|
||||
// If execvp returns, it means an error occurred
|
||||
perror("execvp failed");
|
||||
exit(EXIT_FAILURE); // Exit child process on error
|
||||
} else {
|
||||
// Parent process
|
||||
int ret;
|
||||
// Wait for the child process to complete
|
||||
waitpid(pid, &ret, 0);
|
||||
|
||||
return EXITSTATUSCHECK(ret);
|
||||
}
|
||||
}
|
||||
|
||||
bool execute_local_command_and_capture_output(const sCommand& command, std::string * output, cMode mode)
|
||||
{
|
||||
ASSERT(output != nullptr, "Output string must be provided");
|
||||
ASSERT(is_raw(mode), "Capture output mode requires raw command mode");
|
||||
ASSERT(!hasFlag(mode, cMode::Silent), "Silent mode is not allowed with capture output mode");
|
||||
if (command.get_command_to_run().empty())
|
||||
return false;
|
||||
cStyle style = getStyle(mode);
|
||||
std::string full_cmd = command.construct_cmd(style) + " 2>&1";
|
||||
FILE *pipe = popen(full_cmd.c_str(), "r");
|
||||
if (!pipe) {
|
||||
return false;
|
||||
}
|
||||
char buffer[128];
|
||||
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
|
||||
(*output) += buffer;
|
||||
}
|
||||
int ret = pclose(pipe);
|
||||
return EXITSTATUSCHECK(ret);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool execute_local_command(const sCommand & command, cMode mode, std::string * output /* = nullptr */)
|
||||
{
|
||||
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");
|
||||
ASSERT(is_raw(mode), "Interactive mode requires raw command mode");
|
||||
|
||||
return execute_local_command_interactive(command, hasFlag(mode, cMode::Silent));
|
||||
}
|
||||
|
||||
if (hasFlag(mode, cMode::CaptureOutput)) {
|
||||
ASSERT(output != nullptr, "Capture output mode requires an output string to be provided");
|
||||
ASSERT(is_raw(mode), "Capture output mode requires raw command mode");
|
||||
ASSERT(!hasFlag(mode, cMode::Silent), "Silent mode is not allowed with capture output mode");
|
||||
|
||||
return execute_local_command_and_capture_output(command, output, mode);
|
||||
}
|
||||
|
||||
if (command.get_command_to_run().empty())
|
||||
return false;
|
||||
cStyle style = getStyle(mode);
|
||||
std::string full_cmd = command.construct_cmd(style) + " 2>&1" + (hasFlag(mode, cMode::Silent) ? " > /dev/null" : "");
|
||||
int ret = system(full_cmd.c_str());
|
||||
|
||||
bool ok = EXITSTATUSCHECK(ret);
|
||||
if (!ok) {
|
||||
std::cerr << "Error: Failed to execute command: " << std::endl;
|
||||
std::cerr << full_cmd << std::endl;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool execute_ssh_command(const sSSHInfo &ssh_info, const sCommand &command, cMode mode, std::string *output)
|
||||
{
|
||||
if (command.get_command_to_run().empty())
|
||||
return false;
|
||||
|
||||
ASSERT(!(hasFlag(mode, cMode::Interactive) && !is_raw(mode)), "Interactive mode requires raw command mode");
|
||||
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 cmdstr;
|
||||
if (!is_raw(mode))
|
||||
cmdstr = quote("bash -c " + command.construct_cmd(cStyle::Safe));
|
||||
else
|
||||
{
|
||||
std::string raw_cmd = command.construct_cmd(cStyle::Raw);
|
||||
ASSERT(raw_cmd.find("'") == std::string::npos, "Raw command must not contain single quotes");
|
||||
cmdstr = "bash -c "+ halfquote(raw_cmd);
|
||||
}
|
||||
|
||||
sCommand ssh_command(ssh_cmd.str() + " " + cmdstr);
|
||||
|
||||
bool rval = execute_local_command(ssh_command, mode, output);
|
||||
|
||||
if (!rval) {
|
||||
std::cerr <<std::endl<<std::endl;
|
||||
std::cerr << "Error: Failed to execute ssh command: { [" << ssh_command.get_directory_to_run_in() << "], [";
|
||||
std::cerr << ssh_command.get_command_to_run() << "], [";
|
||||
for (const auto& env_var : ssh_command.get_env_vars()) {
|
||||
std::cerr << env_var.first << "=" << env_var.second << ", ";
|
||||
}
|
||||
std::cerr << "] }" << std::endl;
|
||||
std::cerr <<std::endl<<std::endl;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
std::string makesafecmd(const std::string &command)
|
||||
{
|
||||
if (command.empty())
|
||||
return "";
|
||||
std::string encoded = base64_encode(dequote(trim(command)));
|
||||
std::string commandstr = "echo " + encoded + " | base64 -d | bash";
|
||||
return commandstr;
|
||||
}
|
||||
|
||||
std::string sCommand::construct_cmd(cStyle style) const
|
||||
{
|
||||
if (mCmd.empty())
|
||||
return "";
|
||||
|
||||
std::string cdcmd;
|
||||
if (!mDir.empty())
|
||||
cdcmd = "cd " + quote(mDir) + " && ";
|
||||
|
||||
std::string cmdstr;
|
||||
for (const auto& env_var : mVars) {
|
||||
cmdstr += env_var.first + "=" + quote(dequote(trim(env_var.second))) + " ";
|
||||
}
|
||||
|
||||
cmdstr += mCmd;
|
||||
|
||||
if (is_safe(style))
|
||||
cmdstr = makesafecmd(cmdstr);
|
||||
|
||||
return cdcmd + cmdstr;
|
||||
}
|
||||
|
||||
} // namespace dropshell
|
@ -1,83 +0,0 @@
|
||||
#ifndef EXECUTE_HPP
|
||||
#define EXECUTE_HPP
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace dropshell {
|
||||
|
||||
class sCommand;
|
||||
|
||||
// mode bitset
|
||||
enum class cMode {
|
||||
None = 0,
|
||||
Interactive = 1,
|
||||
Silent = 2,
|
||||
CaptureOutput = 4,
|
||||
RawCommand = 8
|
||||
};
|
||||
enum class cStyle {
|
||||
Safe = 0,
|
||||
Raw = 1
|
||||
};
|
||||
|
||||
inline cMode operator&(cMode lhs, cMode rhs) {return static_cast<cMode>(static_cast<int>(lhs) & static_cast<int>(rhs));}
|
||||
inline cMode operator+(cMode lhs, cMode rhs) {return static_cast<cMode>(static_cast<int>(lhs) | static_cast<int>(rhs));}
|
||||
inline cMode operator-(cMode lhs, cMode rhs) {return static_cast<cMode>(static_cast<int>(lhs) & ~static_cast<int>(rhs));}
|
||||
inline cMode operator|(cMode lhs, cMode rhs) {return static_cast<cMode>(static_cast<int>(lhs) | static_cast<int>(rhs));}
|
||||
inline cMode operator|=(cMode & lhs, cMode rhs) {return lhs = lhs | rhs;}
|
||||
inline bool hasFlag(cMode mode, cMode flag) {return (mode & flag) == flag;}
|
||||
inline bool is_safe(cStyle style) { return style == cStyle::Safe; }
|
||||
inline bool is_raw(cStyle style) { return style == cStyle::Raw; }
|
||||
inline bool is_raw(cMode mode) { return hasFlag(mode, cMode::RawCommand); }
|
||||
inline cStyle getStyle(cMode mode) { return is_raw(mode) ? cStyle::Raw : cStyle::Safe; }
|
||||
|
||||
|
||||
typedef struct sSSHInfo {
|
||||
std::string host;
|
||||
std::string user;
|
||||
std::string port;
|
||||
} sSSHInfo;
|
||||
|
||||
bool execute_local_command(const sCommand & command, cMode mode = cMode::None, std::string * output = nullptr);
|
||||
bool execute_ssh_command(const sSSHInfo & ssh_info, const sCommand & command, cMode mode = cMode::None, std::string * output = nullptr);
|
||||
|
||||
std::string makesafecmd(const std::string& command);
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// class to hold a command to run on the remote server.
|
||||
class sCommand {
|
||||
public:
|
||||
sCommand(std::string directory_to_run_in, std::string command_to_run, const std::map<std::string, std::string> & env_vars) :
|
||||
mDir(directory_to_run_in), mCmd(command_to_run), mVars(env_vars) {}
|
||||
sCommand(std::string command_to_run) :
|
||||
mDir(""), mCmd(command_to_run), mVars({}) {}
|
||||
sCommand() : mDir(""), mCmd(""), mVars({}) {}
|
||||
|
||||
std::string get_directory_to_run_in() const { return mDir; }
|
||||
std::string get_command_to_run() const { return mCmd; }
|
||||
const std::map<std::string, std::string>& get_env_vars() const { return mVars; }
|
||||
|
||||
void add_env_var(const std::string& key, const std::string& value) { mVars[key] = value; }
|
||||
|
||||
|
||||
std::string construct_cmd(cStyle style) const;
|
||||
|
||||
bool empty() const { return mCmd.empty(); }
|
||||
|
||||
private:
|
||||
std::string mDir;
|
||||
std::string mCmd;
|
||||
std::map<std::string, std::string> mVars;
|
||||
};
|
||||
|
||||
|
||||
} // namespace dropshell
|
||||
|
||||
|
||||
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
#include "runner.h"
|
||||
#include "runner.hpp"
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
@ -41,14 +41,6 @@ void trim(std::string* s) {
|
||||
}
|
||||
}
|
||||
|
||||
// Add working_dir to the forward declaration
|
||||
ssh_session ssh_connect_and_auth(const sSSHInfo* sshinfo, const std::map<std::string, std::string>& env, std::string* error);
|
||||
std::string ssh_build_remote_command(const std::string& command, const std::vector<std::string>& args, const std::string& working_dir, const std::map<std::string, std::string>& env);
|
||||
std::string escape_shell_arg(const std::string& arg);
|
||||
int ssh_interactive_shell_session(ssh_session session, ssh_channel channel, const std::string& remote_cmd_str, const std::string& command, std::string* output);
|
||||
int ssh_exec_command(ssh_session session, ssh_channel channel, const std::string& remote_cmd_str, bool silent, std::string* output, const std::map<std::string, std::string>& env, const std::string& working_dir);
|
||||
int local_execute_cmd(const std::string& command, const std::vector<std::string>& args, const std::string& working_dir, const std::map<std::string, std::string>& env, bool silent, bool interactive, std::string* output);
|
||||
|
||||
ssh_session ssh_connect_and_auth(const sSSHInfo* sshinfo, const std::map<std::string, std::string>& env, std::string* error) {
|
||||
ssh_session session = ssh_new();
|
||||
if (!session) {
|
@ -1,4 +1,7 @@
|
||||
#pragma once
|
||||
#ifndef RUNNER_HPP
|
||||
#define RUNNER_HPP
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
@ -22,4 +25,6 @@ int execute_cmd(
|
||||
std::string* output = nullptr
|
||||
);
|
||||
|
||||
} // namespace runner
|
||||
} // namespace runner
|
||||
|
||||
#endif // RUNNER_HPP
|
Loading…
x
Reference in New Issue
Block a user