253 lines
9.1 KiB
C++
253 lines
9.1 KiB
C++
#include "version.hpp"
|
|
#include "config.hpp"
|
|
#include "service_runner.hpp"
|
|
#include "services.hpp"
|
|
#include "servers.hpp"
|
|
#include "utils/directories.hpp"
|
|
#include "templates.hpp"
|
|
#include "utils/utils.hpp"
|
|
#include "utils/readmes.hpp"
|
|
#include "autocomplete.hpp"
|
|
#include "main_commands.hpp"
|
|
|
|
#include <filesystem>
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <iomanip>
|
|
|
|
namespace dropshell {
|
|
|
|
void print_help() {
|
|
std::cout << std::endl;
|
|
maketitle("DropShell version " + VERSION);
|
|
std::cout << std::endl;
|
|
std::cout << "A tool for managing server configurations" << std::endl;
|
|
std::cout << std::endl;
|
|
std::cout << "dropshell ..." << std::endl;
|
|
std::cout << " help Show this help message" << std::endl;
|
|
std::cout << " init DIR Add DIR as a local server config directory (can add several)" << std::endl;
|
|
|
|
if (get_global_config()->is_config_set()) {
|
|
std::cout << " server NAME Show details for specific server" << std::endl;
|
|
std::cout << " templates List all available templates" << std::endl;
|
|
std::cout << std::endl;
|
|
std::cout << std::endl;
|
|
std::cout << "Service commands: (if no service is specified, all services for the server are affected)" << std::endl;
|
|
std::cout << " install SERVER [SERVICE] Install/reinstall/update service(s). Non-destructive." << std::endl;
|
|
std::cout << " list [SERVER] [SERVICE] List status/details of all servers/server/service." << std::endl;
|
|
std::cout << " edit [SERVER] [SERVICE] Edit the configuration of dropshell/server/service." << std::endl;
|
|
std::cout << " COMMAND SERVER [SERVICE] Run a command on service(s)." << std::endl;
|
|
std::cout << std::endl;
|
|
std::cout << "Standard commands: install, uninstall, backup, restore, start, stop" << std::endl;
|
|
std::cout << std::endl;
|
|
std::cout << " ssh SERVER [SERVICE] Launch an interactive shell on a server or service" << std::endl;
|
|
std::cout << std::endl;
|
|
std::cout << "Creation commands: (apply to the first local config directory)"<<std::endl;
|
|
std::cout << " create-template TEMPLATE" << std::endl;
|
|
std::cout << " create-server SERVER" << std::endl;
|
|
std::cout << " create-service SERVER TEMPLATE SERVICE" << std::endl;
|
|
}
|
|
else {
|
|
std::cout << " edit Edit the configuration of dropshell" << std::endl;
|
|
std::cout << std::endl;
|
|
std::cout << "Other commands available once initialised." << std::endl;
|
|
}
|
|
}
|
|
|
|
} // namespace dropshell
|
|
|
|
|
|
bool parseargs(std::string arg2, std::string arg3, std::string & server_name, std::vector<dropshell::ServiceInfo>& servicelist)
|
|
{
|
|
if (arg2.empty()) return false;
|
|
server_name = arg2;
|
|
|
|
if (arg3.empty()) {
|
|
servicelist = dropshell::get_server_services_info(server_name);
|
|
} else {
|
|
servicelist.push_back(dropshell::get_service_info(server_name, arg3));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
std::string safearg(int argc, char *argv[], int index)
|
|
{
|
|
if (index >= argc) return "";
|
|
return argv[index];
|
|
}
|
|
|
|
int main(int argc, char* argv[]) {
|
|
try {
|
|
dropshell::config *cfg = dropshell::get_global_config();
|
|
// silently attempt to load the config file.
|
|
cfg->load_config();
|
|
|
|
if (argc < 2) {
|
|
dropshell::print_help();
|
|
return 0;
|
|
}
|
|
std::string cmd = argv[1];
|
|
std::vector<std::string> argvec;
|
|
for (int i=0; i<argc; i++)
|
|
argvec.push_back(argv[i]);
|
|
|
|
|
|
if (cmd == "autocomplete") {
|
|
dropshell::autocomplete(argvec);
|
|
return 0;
|
|
}
|
|
|
|
if (cmd == "init") {
|
|
return dropshell::main_commands::init(argvec);
|
|
}
|
|
|
|
if (cmd == "help" || cmd == "-h" || cmd == "--help" || cmd== "h" || cmd=="halp") {
|
|
dropshell::print_help();
|
|
return 0;
|
|
}
|
|
|
|
if (cmd == "edit" && argc < 3) {
|
|
std::filesystem::create_directories(dropshell::get_local_dropshell_config_parent_path());
|
|
dropshell::edit_file(dropshell::get_local_dropshell_config_file(), "Please ensure any directories you have introduced in the config file exist.");
|
|
return 0;
|
|
}
|
|
|
|
// ------------------------------------------------------------
|
|
// from here we require the config file to be loaded.
|
|
if (!cfg->is_config_set()) {
|
|
std::cerr << "Please run 'dropshell init <path>' to initialise the user directory and create a configuration file." << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
const std::vector<std::string> & local_config_directories = cfg->get_local_config_directories();
|
|
std::cout << "Config directories: ";
|
|
for (auto & dir : local_config_directories)
|
|
std::cout << "["<< dir << "] ";
|
|
std::cout << std::endl;
|
|
|
|
if (cmd == "server" || cmd == "servers" || cmd == "list" || cmd == "view")
|
|
switch (argc)
|
|
{
|
|
case 2:
|
|
dropshell::list_servers();
|
|
return 0;
|
|
case 3:
|
|
dropshell::show_server_details(argv[2]);
|
|
return 0;
|
|
case 4:
|
|
cmd="logs";
|
|
break;
|
|
default:
|
|
std::cerr << "dropshell server: too many arguments" << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
if (cmd == "templates") {
|
|
dropshell::list_templates();
|
|
return 0;
|
|
}
|
|
|
|
if (cmd == "create-template") {
|
|
if (argc < 3) {
|
|
std::cerr << "Error: create-template requires a template name" << std::endl;
|
|
return 1;
|
|
}
|
|
dropshell::create_template(argv[2]);
|
|
return 0;
|
|
}
|
|
|
|
if (cmd == "create-server") {
|
|
if (argc < 3) {
|
|
std::cerr << "Error: create-server requires a server name" << std::endl;
|
|
return 1;
|
|
}
|
|
dropshell::create_server(argv[2]);
|
|
return 0;
|
|
}
|
|
|
|
if (cmd == "create-service") {
|
|
if (argc < 5) {
|
|
std::cerr << "Error: not enough arguments." << std::endl;
|
|
std::cerr << "dropshell create-service server template service" << std::endl;
|
|
return 1;
|
|
}
|
|
dropshell::create_service(argv[2], argv[3], argv[4]);
|
|
return 0;
|
|
}
|
|
|
|
if (cmd == "ssh" && argc < 4) {
|
|
if (argc < 3)
|
|
{
|
|
std::cerr << "Error: ssh requires a server name and optionally service name" << std::endl;
|
|
return 1;
|
|
}
|
|
dropshell::interactive_ssh(argv[2], "bash");
|
|
return 0;
|
|
}
|
|
|
|
if (cmd == "edit" && argc < 4) {
|
|
ASSERT_ALWAYS(argc>=3);
|
|
dropshell::edit_server(argv[2]);
|
|
return 0;
|
|
}
|
|
|
|
if (cmd == "backup" || cmd=="backups") {
|
|
if (argc < 4) {
|
|
std::cerr << "Error: backup requires a target server and target service to back up" << std::endl;
|
|
return 1;
|
|
}
|
|
return dropshell::main_commands::backup(argvec);
|
|
}
|
|
|
|
if (cmd == "restore") {
|
|
if (argc < 4) {
|
|
std::cerr << "Error: restore requires a target server, target service the backup file to restore" << std::endl;
|
|
return 1;
|
|
}
|
|
return dropshell::main_commands::restore(argvec);
|
|
}
|
|
|
|
// handle running a command.
|
|
std::set<std::string> commands;
|
|
dropshell::get_all_used_commands(commands);
|
|
commands.merge(std::set<std::string>{"ssh","edit"}); // handled by service_runner, but not in template_shell_commands.
|
|
for (const auto& command : commands) {
|
|
if (cmd == command) {
|
|
std::string server_name;
|
|
std::vector<dropshell::ServiceInfo> servicelist;
|
|
if (!parseargs(safearg(argc, argv, 2), safearg(argc, argv, 3), server_name, servicelist)) {
|
|
std::cerr << "Error: " << command << " command requires server name and optionally service name" << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
for (const auto& service_info : servicelist) {
|
|
dropshell::service_runner runner(server_name, service_info.service_name);
|
|
if (!runner.isValid()) {
|
|
std::cerr << "Error: Failed to initialize service" << std::endl;
|
|
return 1;
|
|
}
|
|
if (!runner.run_command(command)) {
|
|
std::cerr << command +" failed." << std::endl;
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Unknown command
|
|
std::cerr << "Error: Unknown command '" << cmd << "'" << std::endl;
|
|
std::cerr << "Valid commands: ";
|
|
for (const auto& command : commands) {
|
|
std::cerr << command << " ";
|
|
}
|
|
std::cerr << std::endl;
|
|
return 1;
|
|
|
|
} catch (const std::exception& e) {
|
|
std::cerr << "Error: " << e.what() << std::endl;
|
|
return 1;
|
|
}
|
|
}
|