#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 "autocomplete.hpp" #include "utils/hash.hpp" #include #include #include #include #include #include #include namespace dropshell { extern const std::string VERSION; extern const std::string RELEASE_DATE; extern const std::string AUTHOR; extern const std::string LICENSE; bool 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 << " edit Edit the configuration of dropshell" << std::endl; if (gConfig().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 << " 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 << std::endl; std::cout << " install SERVER [SERVICE] Install/reinstall/update service(s). Safe/non-destructive." << std::endl; std::cout << " uninstall SERVER [SERVICE] Uninstalls the service on the remote server. Leaves data intact." << std::endl; std::cout << " nuke SERVER SERVICE Nuke the service on the remote server, deleting all remote data." << std::endl; std::cout << std::endl; std::cout << " COMMAND SERVER [SERVICE] Run a command on service(s), e.g." << std::endl; std::cout << " backup, restore, start, stop, logs" << 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)"< servicelist; }; bool getCLIServices(const std::string & arg2, const std::string & arg3, ServerAndServices & server_and_services) { if (arg2.empty()) return false; server_and_services.server_name = arg2; if (arg3.empty()) { server_and_services.servicelist = get_server_services_info(arg2); } else { server_and_services.servicelist.push_back(get_service_info(arg2, arg3)); } return true; } std::string safearg(int argc, char *argv[], int index) { if (index >= argc) return ""; return argv[index]; } void printversion() { maketitle("DropShell version " + VERSION); std::cout << "Release date: " << RELEASE_DATE << std::endl; std::cout << "Author: " << AUTHOR << std::endl; std::cout << "License: " << LICENSE << std::endl; } #define HAPPYEXIT(CMD, RUNCMD) {if (safearg(argc,argv,1) == CMD) {RUNCMD; return 0;}} #define BOOLEXIT(CMD, RUNCMD) {if (safearg(argc,argv,1) == CMD) {return (RUNCMD) ? 0 : 1;}} int main(int argc, char* argv[]) { HAPPYEXIT("hash", hash_demo_raw(safearg(argc,argv,2))) HAPPYEXIT("makesafecmd", std::cout< argvec; for (int i=0; i & server_definition_paths = gConfig().get_local_server_definition_paths(); if (server_definition_paths.size()>1) { // only show if there are multiple. std::cout << "Server definition paths: "; for (auto & dir : server_definition_paths) std::cout << "["<< dir << "] "; std::cout << std::endl; } if (gTemplateManager().is_loaded() && gTemplateManager().get_source_count() > 0) gTemplateManager().print_sources(); if (cmd == "server" || cmd == "servers" || cmd == "list" || cmd == "view") switch (argc) { case 2: list_servers(); return 0; case 3: show_server_details(argv[2]); return 0; case 4: cmd="logs"; break; default: return die("dropshell server: too many arguments"); } if (cmd == "templates") { gTemplateManager().list_templates(); return 0; } if (cmd == "create-template") { if (argc < 3) return die("Error: create-template requires a template name"); return (gTemplateManager().create_template(argv[2])) ? 0 : 1; } if (cmd == "create-server") { if (argc < 3) return die("Error: create-server requires a server name"); return (create_server(argv[2])) ? 0 : 1; } if (cmd == "create-service") { if (argc < 5) return die("Error: not enough arguments.\ndropshell create-service server template service"); return (create_service(argv[2], argv[3], argv[4])) ? 0 : 1; } if (cmd == "ssh" && argc < 4) { if (argc < 3) return die("Error: ssh requires a server name and optionally service name"); service_runner::interactive_ssh(argv[2], "bash"); return 0; } if (cmd == "edit" && argc < 4) { ASSERT(argc>=3, "Error: logic error!"); service_runner::edit_server(safearg(argc,argv,2)); return 0; } // handle running a command. std::set commands; get_all_used_commands(commands); commands.merge(std::set{"ssh","edit","_allservicesstatus","fullnuke"}); // handled by service_runner, but not in template_shell_commands. if (commands.count(cmd)) { std::set safe_commands = {"nuke", "fullnuke"}; if (safe_commands.count(cmd) && argc < 4) return die("Error: "+cmd+" requires a server name and service name. For safety, can't run on all services."); // get all the services to run the command on. ServerAndServices server_and_services; if (!getCLIServices(safearg(argc, argv, 2), safearg(argc, argv, 3), server_and_services)) return die("Error: "+cmd+" command requires server name and optionally service name"); // run the command on each service. for (const auto& service_info : server_and_services.servicelist) { if (!SIvalid(service_info)) std::cerr<<"Error: Unable to get service information."< additional_args; for (int i=4; i