Compare commits
5 Commits
DEV
...
2025.0517.
Author | SHA1 | Date | |
---|---|---|---|
038d08e638 | |||
27f86e95e7 | |||
891f0d023f | |||
91f706ffcd | |||
0e1ac9ddd8 |
@ -8,6 +8,8 @@ A system management tool for server operations, written in C++.
|
|||||||
curl -fsSL https://gitea.jde.nz/public/dropshell/releases/download/latest/install.sh | sudo bash
|
curl -fsSL https://gitea.jde.nz/public/dropshell/releases/download/latest/install.sh | sudo bash
|
||||||
```
|
```
|
||||||
|
|
||||||
|
This installs as dropshell, with a symlink ds if the ds command does not already exist.
|
||||||
|
|
||||||
## Installation of Agent
|
## Installation of Agent
|
||||||
|
|
||||||
Install the Agent on each server you wish to manage. Supports amd64 (x86_64) and arm64 (aarch64) architectures.
|
Install the Agent on each server you wish to manage. Supports amd64 (x86_64) and arm64 (aarch64) architectures.
|
||||||
@ -24,3 +26,7 @@ Manual steps:
|
|||||||
1. Test ssh'ing into the server.
|
1. Test ssh'ing into the server.
|
||||||
|
|
||||||
|
|
||||||
|
## Install Services
|
||||||
|
|
||||||
|
Set up a server and install a service:
|
||||||
|
1. `ds create-server SERVERNAME`
|
||||||
|
@ -51,7 +51,7 @@ add_dependencies(dropshell run_createagent)
|
|||||||
# Set include directories
|
# Set include directories
|
||||||
# build dir goes first so that we can use the generated version.hpp
|
# build dir goes first so that we can use the generated version.hpp
|
||||||
target_include_directories(dropshell PRIVATE
|
target_include_directories(dropshell PRIVATE
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/src>
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/src/autogen>
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/utils
|
${CMAKE_CURRENT_SOURCE_DIR}/src/utils
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/contrib
|
${CMAKE_CURRENT_SOURCE_DIR}/src/contrib
|
||||||
|
7
source/agent/selftest.sh
Executable file
7
source/agent/selftest.sh
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Running remote agent self-test..."
|
||||||
|
|
||||||
|
echo "Completed remote agent self-test."
|
||||||
|
|
||||||
|
exit 0
|
@ -6,7 +6,9 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
rm -f build_amd64/dropshell build_arm64/dropshell build/dropshell.amd64 build/dropshell.arm64
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
rm -f $SCRIPT_DIR/build_amd64/dropshell $SCRIPT_DIR/build_arm64/dropshell $SCRIPT_DIR/output/dropshell.amd64 $SCRIPT_DIR/output/dropshell.arm64
|
||||||
|
|
||||||
# Determine number of CPU cores for parallel build
|
# Determine number of CPU cores for parallel build
|
||||||
if command -v nproc >/dev/null 2>&1; then
|
if command -v nproc >/dev/null 2>&1; then
|
||||||
@ -15,6 +17,9 @@ else
|
|||||||
JOBS=4 # fallback default
|
JOBS=4 # fallback default
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
PREV_PWD=$PWD
|
||||||
|
cd $SCRIPT_DIR
|
||||||
|
|
||||||
# Build for amd64 (musl)
|
# Build for amd64 (musl)
|
||||||
echo "Building for amd64 (musl)..."
|
echo "Building for amd64 (musl)..."
|
||||||
cmake -B build_amd64 -DCMAKE_BUILD_TYPE=Release \
|
cmake -B build_amd64 -DCMAKE_BUILD_TYPE=Release \
|
||||||
@ -23,8 +28,8 @@ cmake -B build_amd64 -DCMAKE_BUILD_TYPE=Release \
|
|||||||
-DCMAKE_EXE_LINKER_FLAGS="-static" \
|
-DCMAKE_EXE_LINKER_FLAGS="-static" \
|
||||||
-DCMAKE_CXX_FLAGS="-march=x86-64" .
|
-DCMAKE_CXX_FLAGS="-march=x86-64" .
|
||||||
cmake --build build_amd64 --target dropshell --config Release -j"$JOBS"
|
cmake --build build_amd64 --target dropshell --config Release -j"$JOBS"
|
||||||
mkdir -p build
|
mkdir -p output
|
||||||
cp build_amd64/dropshell build/dropshell.amd64
|
cp build_amd64/dropshell output/dropshell.amd64
|
||||||
|
|
||||||
# Build for arm64 (musl)
|
# Build for arm64 (musl)
|
||||||
echo "Building for arm64 (musl)..."
|
echo "Building for arm64 (musl)..."
|
||||||
@ -35,18 +40,20 @@ cmake -B build_arm64 -DCMAKE_BUILD_TYPE=Release \
|
|||||||
-DCMAKE_CXX_FLAGS="-march=armv8-a" \
|
-DCMAKE_CXX_FLAGS="-march=armv8-a" \
|
||||||
-DCMAKE_SYSTEM_PROCESSOR=aarch64 .
|
-DCMAKE_SYSTEM_PROCESSOR=aarch64 .
|
||||||
cmake --build build_arm64 --target dropshell --config Release -j"$JOBS"
|
cmake --build build_arm64 --target dropshell --config Release -j"$JOBS"
|
||||||
mkdir -p build
|
mkdir -p output
|
||||||
cp build_arm64/dropshell build/dropshell.arm64
|
cp build_arm64/dropshell output/dropshell.arm64
|
||||||
|
|
||||||
if [ ! -f build/dropshell.amd64 ]; then
|
if [ ! -f output/dropshell.amd64 ]; then
|
||||||
echo "build/dropshell.amd64 not found!" >&2
|
echo "output/dropshell.amd64 not found!" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f build/dropshell.arm64 ]; then
|
if [ ! -f output/dropshell.arm64 ]; then
|
||||||
echo "build/dropshell.arm64 not found!" >&2
|
echo "output/dropshell.arm64 not found!" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Builds complete:"
|
echo "Builds complete:"
|
||||||
ls -lh build/dropshell.*
|
ls -lh output/dropshell.*
|
||||||
|
|
||||||
|
cd $PREV_PWD
|
@ -1,6 +1,10 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
# directory of this script
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
echo "Script directory: $SCRIPT_DIR"
|
||||||
|
|
||||||
# Check for GITEA_TOKEN_DEPLOY or GITEA_TOKEN
|
# Check for GITEA_TOKEN_DEPLOY or GITEA_TOKEN
|
||||||
if [ -n "$GITEA_TOKEN_DEPLOY" ]; then
|
if [ -n "$GITEA_TOKEN_DEPLOY" ]; then
|
||||||
TOKEN="$GITEA_TOKEN_DEPLOY"
|
TOKEN="$GITEA_TOKEN_DEPLOY"
|
||||||
@ -11,27 +15,32 @@ else
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
$SCRIPT_DIR/multibuild.sh
|
||||||
|
BUILD_DIR=$SCRIPT_DIR/build
|
||||||
|
|
||||||
./multibuild.sh
|
OLD_PWD=$PWD
|
||||||
|
cd $SCRIPT_DIR
|
||||||
|
|
||||||
if [ ! -f "build/dropshell.amd64" ]; then
|
|
||||||
echo "build/dropshell.amd64 not found!" >&2
|
if [ ! -f "output/dropshell.amd64" ]; then
|
||||||
|
echo "output/dropshell.amd64 not found!" >&2
|
||||||
echo "Please run multibuild.sh first." >&2
|
echo "Please run multibuild.sh first." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f "build/dropshell.arm64" ]; then
|
if [ ! -f "output/dropshell.arm64" ]; then
|
||||||
echo "build/dropshell.arm64 not found!" >&2
|
echo "output/dropshell.arm64 not found!" >&2
|
||||||
echo "Please run multibuild.sh first." >&2
|
echo "Please run multibuild.sh first." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
TAG=$(./build/dropshell.amd64 --version)
|
TAG=$("$SCRIPT_DIR/output/dropshell.amd64" --version)
|
||||||
|
[ -z "$TAG" ] && echo "Failed to get version from dropshell.amd64" >&2 && exit 1
|
||||||
|
|
||||||
echo "Publishing dropshell version $TAG"
|
echo "Publishing dropshell version $TAG"
|
||||||
|
|
||||||
# make sure we've commited.
|
# make sure we've commited.
|
||||||
git add . && git commit -m "dropshell release $TAG" && git push
|
git add "$SCRIPT_DIR/../" && git commit -m "dropshell release $TAG" && git push
|
||||||
|
|
||||||
|
|
||||||
# Find repo info from .git/config
|
# Find repo info from .git/config
|
||||||
@ -73,8 +82,10 @@ fi
|
|||||||
|
|
||||||
# Upload binaries and install.sh
|
# Upload binaries and install.sh
|
||||||
for FILE in dropshell.amd64 dropshell.arm64 install.sh server_autosetup.sh; do
|
for FILE in dropshell.amd64 dropshell.arm64 install.sh server_autosetup.sh; do
|
||||||
if [ -f "build/$FILE" ]; then
|
if [ -f "output/$FILE" ]; then
|
||||||
filetoupload="build/$FILE"
|
filetoupload="output/$FILE"
|
||||||
|
elif [ -f "../$FILE" ]; then
|
||||||
|
filetoupload="../$FILE"
|
||||||
elif [ -f "$FILE" ]; then
|
elif [ -f "$FILE" ]; then
|
||||||
filetoupload="$FILE"
|
filetoupload="$FILE"
|
||||||
else
|
else
|
||||||
@ -93,3 +104,5 @@ for FILE in dropshell.amd64 dropshell.arm64 install.sh server_autosetup.sh; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
echo "Published dropshell version $TAG to $REPO_URL (tag $TAG) with binaries."
|
echo "Published dropshell version $TAG to $REPO_URL (tag $TAG) with binaries."
|
||||||
|
|
||||||
|
cd $OLD_PWD
|
@ -105,6 +105,22 @@ static bool _recreate_file_(const std::filesystem::path& outpath, uint64_t file_
|
|||||||
bool recreate_tree(std::string destination_folder) {
|
bool recreate_tree(std::string destination_folder) {
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
bool any_written = false;
|
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
|
// File: datacommands.sh
|
||||||
fs::path outpath = fs::path(destination_folder) / "datacommands.sh";
|
fs::path outpath = fs::path(destination_folder) / "datacommands.sh";
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
|
// version.hpp (dummy for linter/IntelliSense)
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// DUMMY VERSION - replaced by build process.
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace dropshell {
|
namespace dropshell {
|
||||||
|
extern const std::string VERSION;
|
||||||
// Version information
|
extern const std::string RELEASE_DATE;
|
||||||
const std::string VERSION = "DEV";
|
extern const std::string AUTHOR;
|
||||||
const std::string RELEASE_DATE = "NEVER";
|
extern const std::string LICENSE;
|
||||||
const std::string AUTHOR = "j842";
|
}
|
||||||
const std::string LICENSE = "MIT";
|
|
||||||
|
|
||||||
} // namespace dropshell
|
|
@ -17,9 +17,9 @@ namespace dropshell
|
|||||||
static std::vector<std::string> create_service_name_list = {"create-service"};
|
static std::vector<std::string> create_service_name_list = {"create-service"};
|
||||||
|
|
||||||
// Static registration
|
// Static registration
|
||||||
struct UninstallCommandRegister
|
struct CreateServiceCommandRegister
|
||||||
{
|
{
|
||||||
UninstallCommandRegister()
|
CreateServiceCommandRegister()
|
||||||
{
|
{
|
||||||
CommandRegistry::instance().register_command({create_service_name_list,
|
CommandRegistry::instance().register_command({create_service_name_list,
|
||||||
create_service_handler,
|
create_service_handler,
|
||||||
|
@ -57,7 +57,10 @@ void help_autocomplete(const CommandContext& ctx) {
|
|||||||
void show_command(const std::string& cmd) {
|
void show_command(const std::string& cmd) {
|
||||||
const auto& cmd_info = CommandRegistry::instance().find_command(cmd);
|
const auto& cmd_info = CommandRegistry::instance().find_command(cmd);
|
||||||
if (!cmd_info)
|
if (!cmd_info)
|
||||||
|
{
|
||||||
std::cout << "Unknown command: " << cmd << std::endl;
|
std::cout << "Unknown command: " << cmd << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::cout << " ";
|
std::cout << " ";
|
||||||
print_left_aligned(cmd_info->help_usage, 30);
|
print_left_aligned(cmd_info->help_usage, 30);
|
||||||
@ -119,6 +122,13 @@ int help_handler(const CommandContext& ctx) {
|
|||||||
{
|
{
|
||||||
// show more!
|
// show more!
|
||||||
show_command("list");
|
show_command("list");
|
||||||
|
std::cout << std::endl;
|
||||||
|
show_command("install");
|
||||||
|
show_command("uninstall");
|
||||||
|
show_command("nuke");
|
||||||
|
std::cout << std::endl;
|
||||||
|
show_command("start");
|
||||||
|
show_command("stop");
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -121,6 +121,7 @@ namespace dropshell
|
|||||||
|
|
||||||
// Run install script
|
// Run install script
|
||||||
{
|
{
|
||||||
|
std::cout << "Running " << service_info.template_name << " install script on " << server << "..." << std::endl;
|
||||||
server_env.run_remote_template_command(service, "install", {}, silent, {});
|
server_env.run_remote_template_command(service, "install", {}, silent, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,10 +299,12 @@ namespace dropshell
|
|||||||
|
|
||||||
// now create the agent.
|
// now create the agent.
|
||||||
// copy across from the local agent files.
|
// copy across from the local agent files.
|
||||||
|
std::cout << "Copying local agent files to remote server... " << std::flush;
|
||||||
shared_commands::rsync_tree_to_remote(localpath::files_for_remote_agent(), agent_path, server_env, false);
|
shared_commands::rsync_tree_to_remote(localpath::files_for_remote_agent(), agent_path, server_env, false);
|
||||||
|
std::cout << "done." << std::endl;
|
||||||
|
|
||||||
// add in bb64. We can't use execute_remote_command() here, as that relies on bb64 which we're installing!
|
// add in bb64. We can't use execute_remote_command() here, as that relies on bb64 which we're installing!
|
||||||
std::cout << "Installing bb64 on " << server << std::endl << std::flush;
|
std::cout << "Installing bb64 on " << server << "..." << std::endl << std::flush;
|
||||||
|
|
||||||
std::string remote_cmd =
|
std::string remote_cmd =
|
||||||
"ssh -p " + server_env.get_SSH_INFO().port + " " + server_env.get_SSH_INFO().user + "@" + server_env.get_SSH_INFO().host +
|
"ssh -p " + server_env.get_SSH_INFO().port + " " + server_env.get_SSH_INFO().user + "@" + server_env.get_SSH_INFO().host +
|
||||||
@ -315,11 +318,14 @@ namespace dropshell
|
|||||||
std::cout << "Downloaded bb64 to " << agent_path << " on remote server." << std::endl;
|
std::cout << "Downloaded bb64 to " << agent_path << " on remote server." << std::endl;
|
||||||
|
|
||||||
// just test all is ok
|
// just test all is ok
|
||||||
|
|
||||||
|
// run the self-test.
|
||||||
std::string output;
|
std::string output;
|
||||||
bool okay = execute_ssh_command(server_env.get_SSH_INFO(), sCommand(agent_path, "./bb64 -i VGhlIGRyb3BzaGVsbCByZW1vdGUgYWdlbnQgaXMgY29ycmVjdGx5IGluc3RhbGxlZC4=", {}), cMode::CaptureOutput, &output);
|
bool okay = execute_ssh_command(server_env.get_SSH_INFO(), sCommand(agent_path, "./selftest.sh", {}), cMode::Defaults, &output);
|
||||||
if (!okay)
|
if (!okay)
|
||||||
{
|
{
|
||||||
std::cerr << "Failed to install bb64 on " << server << std::endl;
|
std::cerr << "ERROR: Failed to install remote agent on " << server << std::endl;
|
||||||
|
std::cerr << "ERROR: Output: " << output << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,9 +33,16 @@ struct NukeCommandRegister {
|
|||||||
"Nuke a service on a server. Destroys everything, both local and remote!",
|
"Nuke a service on a server. Destroys everything, both local and remote!",
|
||||||
// heredoc
|
// heredoc
|
||||||
R"(
|
R"(
|
||||||
Nuke a service on a server. Destroys everything, both local and remote!
|
Nuke a service.
|
||||||
|
|
||||||
|
Examples:
|
||||||
nuke SERVER SERVICE nuke the given service on the given server.
|
nuke SERVER SERVICE nuke the given service on the given server.
|
||||||
nuke SERVER all nuke all services on the given server.
|
nuke SERVER all nuke all services on the given server.
|
||||||
|
|
||||||
|
Note: This command is destructive and will destroy all data and all configuration,
|
||||||
|
both on the dropshell host and on the remote server.
|
||||||
|
|
||||||
|
Use with caution!
|
||||||
)"
|
)"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
91
source/src/commands/start.cpp
Normal file
91
source/src/commands/start.cpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#include "command_registry.hpp"
|
||||||
|
#include "config.hpp"
|
||||||
|
#include "utils/utils.hpp"
|
||||||
|
#include "utils/directories.hpp"
|
||||||
|
#include "shared_commands.hpp"
|
||||||
|
#include "server_env_manager.hpp"
|
||||||
|
#include "services.hpp"
|
||||||
|
#include "servers.hpp"
|
||||||
|
|
||||||
|
namespace dropshell
|
||||||
|
{
|
||||||
|
|
||||||
|
int start_handler(const CommandContext &ctx);
|
||||||
|
|
||||||
|
static std::vector<std::string> start_name_list = {"start", "start-service"};
|
||||||
|
|
||||||
|
// Static registration
|
||||||
|
struct StartCommandRegister
|
||||||
|
{
|
||||||
|
StartCommandRegister()
|
||||||
|
{
|
||||||
|
CommandRegistry::instance().register_command({start_name_list,
|
||||||
|
start_handler,
|
||||||
|
shared_commands::std_autocomplete_allowall,
|
||||||
|
false, // hidden
|
||||||
|
true, // requires_config
|
||||||
|
true, // requires_install
|
||||||
|
1, // min_args (after command)
|
||||||
|
2, // max_args (after command)
|
||||||
|
"start SERVER SERVICE|all",
|
||||||
|
"Start a service or all services on a server.",
|
||||||
|
R"(
|
||||||
|
|
||||||
|
start SERVER SERVICE Starts the given service on the given server.
|
||||||
|
start SERVER all Starts all services on the given server.
|
||||||
|
|
||||||
|
Note: This command will not create any data or configuration.
|
||||||
|
It will simply start the service on the remote server.
|
||||||
|
Stop the service with stop, or uninstall with uninstall.
|
||||||
|
)"});
|
||||||
|
}
|
||||||
|
} start_command_register;
|
||||||
|
|
||||||
|
bool start_service(const std::string &server, const std::string &service)
|
||||||
|
{
|
||||||
|
server_env_manager server_env(server);
|
||||||
|
if (!server_env.is_valid())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: Server " << server << " is not valid" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// run the start script.
|
||||||
|
bool started = server_env.run_remote_template_command(service, "start", {}, false, {});
|
||||||
|
|
||||||
|
if (started)
|
||||||
|
{
|
||||||
|
std::cout << "Service " << service << " on server " << server << " started." << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
std::cerr << "Error: Failed to start service " << service << " on server " << server << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int start_handler(const CommandContext &ctx)
|
||||||
|
{
|
||||||
|
if (ctx.args.size() < 2)
|
||||||
|
{
|
||||||
|
std::cerr << "Error: Server name and service name are both required" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string server = safearg(ctx.args, 0);
|
||||||
|
std::string service = safearg(ctx.args, 1);
|
||||||
|
|
||||||
|
if (service == "all")
|
||||||
|
{
|
||||||
|
// install all services on the server
|
||||||
|
maketitle("Stopping all services on " + server);
|
||||||
|
bool okay = true;
|
||||||
|
std::vector<LocalServiceInfo> services = get_server_services_info(server);
|
||||||
|
for (const auto &service : services)
|
||||||
|
okay &= start_service(server, service.service_name);
|
||||||
|
return okay ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start the specific service.
|
||||||
|
return start_service(server, service) ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace dropshell
|
91
source/src/commands/stop.cpp
Normal file
91
source/src/commands/stop.cpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#include "command_registry.hpp"
|
||||||
|
#include "config.hpp"
|
||||||
|
#include "utils/utils.hpp"
|
||||||
|
#include "utils/directories.hpp"
|
||||||
|
#include "shared_commands.hpp"
|
||||||
|
#include "server_env_manager.hpp"
|
||||||
|
#include "services.hpp"
|
||||||
|
#include "servers.hpp"
|
||||||
|
|
||||||
|
namespace dropshell
|
||||||
|
{
|
||||||
|
|
||||||
|
int stop_handler(const CommandContext &ctx);
|
||||||
|
|
||||||
|
static std::vector<std::string> stop_name_list = {"stop", "stop-service"};
|
||||||
|
|
||||||
|
// Static registration
|
||||||
|
struct StopCommandRegister
|
||||||
|
{
|
||||||
|
StopCommandRegister()
|
||||||
|
{
|
||||||
|
CommandRegistry::instance().register_command({stop_name_list,
|
||||||
|
stop_handler,
|
||||||
|
shared_commands::std_autocomplete_allowall,
|
||||||
|
false, // hidden
|
||||||
|
true, // requires_config
|
||||||
|
true, // requires_install
|
||||||
|
1, // min_args (after command)
|
||||||
|
2, // max_args (after command)
|
||||||
|
"stop SERVER SERVICE|all",
|
||||||
|
"Stop a service or all services on a server.",
|
||||||
|
R"(
|
||||||
|
|
||||||
|
stop SERVER SERVICE Stops the given service on the given server.
|
||||||
|
stop SERVER all Stops all services on the given server.
|
||||||
|
|
||||||
|
Note: This command will not destroy any data or configuration.
|
||||||
|
It will simply stop the service on the remote server.
|
||||||
|
Restart the service with start, or update and start it with install.
|
||||||
|
)"});
|
||||||
|
}
|
||||||
|
} stop_command_register;
|
||||||
|
|
||||||
|
bool stop_service(const std::string &server, const std::string &service)
|
||||||
|
{
|
||||||
|
server_env_manager server_env(server);
|
||||||
|
if (!server_env.is_valid())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: Server " << server << " is not valid" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// run the stop script.
|
||||||
|
bool stopped = server_env.run_remote_template_command(service, "stop", {}, false, {});
|
||||||
|
|
||||||
|
if (stopped)
|
||||||
|
{
|
||||||
|
std::cout << "Service " << service << " on server " << server << " stopped." << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
std::cerr << "Error: Failed to stop service " << service << " on server " << server << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int stop_handler(const CommandContext &ctx)
|
||||||
|
{
|
||||||
|
if (ctx.args.size() < 2)
|
||||||
|
{
|
||||||
|
std::cerr << "Error: Server name and service name are both required" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string server = safearg(ctx.args, 0);
|
||||||
|
std::string service = safearg(ctx.args, 1);
|
||||||
|
|
||||||
|
if (service == "all")
|
||||||
|
{
|
||||||
|
// install all services on the server
|
||||||
|
maketitle("Stopping all services on " + server);
|
||||||
|
bool okay = true;
|
||||||
|
std::vector<LocalServiceInfo> services = get_server_services_info(server);
|
||||||
|
for (const auto &service : services)
|
||||||
|
okay &= stop_service(server, service.service_name);
|
||||||
|
return okay ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop the specific service.
|
||||||
|
return stop_service(server, service) ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace dropshell
|
@ -23,25 +23,25 @@ namespace dropshell
|
|||||||
uninstall_handler,
|
uninstall_handler,
|
||||||
shared_commands::std_autocomplete_allowall,
|
shared_commands::std_autocomplete_allowall,
|
||||||
false, // hidden
|
false, // hidden
|
||||||
true, // requires_config
|
true, // requires_config
|
||||||
true, // requires_install
|
true, // requires_install
|
||||||
2, // min_args (after command)
|
2, // min_args (after command)
|
||||||
2, // max_args (after command)
|
2, // max_args (after command)
|
||||||
"uninstall SERVER SERVICE|all",
|
"uninstall SERVER SERVICE|all",
|
||||||
"Uninstall a service on a server. Does not remove configuration or user data.",
|
"Uninstall a service on a server. Does not remove configuration or user data.",
|
||||||
// heredoc
|
// heredoc
|
||||||
R"(
|
R"(
|
||||||
Uninstall a service on a server. Does not remove configuration or user data.
|
Uninstall a service, leaving all configuration and data intact.
|
||||||
uninstall SERVER SERVICE uninstall the given service on the given server.
|
|
||||||
uninstall SERVER all uninstall all services on the given server.
|
uninstall SERVER SERVICE Uninstall the given service on the given server.
|
||||||
|
uninstall SERVER all Uninstall all services on the given server.
|
||||||
|
|
||||||
|
Update and reinstall the service with install, or delete all configuration and data with nuke.
|
||||||
)"});
|
)"});
|
||||||
}
|
}
|
||||||
} uninstall_command_register;
|
} uninstall_command_register;
|
||||||
|
|
||||||
|
bool uninstall_service(const std::string &server, const std::string &service, bool silent = false)
|
||||||
|
|
||||||
|
|
||||||
bool uninstall_service(const std::string &server, const std::string &service, bool silent=false)
|
|
||||||
{
|
{
|
||||||
if (!silent)
|
if (!silent)
|
||||||
maketitle("Uninstalling " + service + " on " + server);
|
maketitle("Uninstalling " + service + " on " + server);
|
||||||
@ -81,7 +81,6 @@ namespace dropshell
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int uninstall_handler(const CommandContext &ctx)
|
int uninstall_handler(const CommandContext &ctx)
|
||||||
{
|
{
|
||||||
if (ctx.args.size() < 1)
|
if (ctx.args.size() < 1)
|
||||||
@ -109,5 +108,4 @@ namespace dropshell
|
|||||||
return uninstall_service(server, service) ? 0 : 1;
|
return uninstall_service(server, service) ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace dropshell
|
} // namespace dropshell
|
Reference in New Issue
Block a user