This commit is contained in:
Your Name 2025-04-21 11:47:07 +12:00
parent 0eacb838ce
commit a718f23375
11 changed files with 235 additions and 10 deletions

View File

@ -7,15 +7,15 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Find required packages
find_package(Boost REQUIRED COMPONENTS program_options filesystem system)
# Auto-detect source files
file(GLOB_RECURSE SOURCES "src/*.cpp")
file(GLOB_RECURSE HEADERS "src/*.hpp")
# Add executable
add_executable(dropshell
src/main.cpp
src/version.cpp
src/status.cpp
src/servers.cpp
src/help.cpp
src/config.cpp
)
add_executable(dropshell ${SOURCES})
# Set include directories
target_include_directories(dropshell PRIVATE src)
# Link libraries
target_link_libraries(dropshell PRIVATE

View File

@ -7,7 +7,7 @@ _dropshell_completions() {
prev="${COMP_WORDS[COMP_CWORD-1]}"
# List of main commands
opts="help version status servers"
opts="help version status servers templates"
# If we're completing the first argument, show all commands
if [[ ${COMP_CWORD} -eq 1 ]] ; then
@ -36,6 +36,10 @@ _dropshell_completions() {
COMPREPLY=( $(compgen -W "${servers[@]}" -- ${cur}) )
return 0
;;
templates)
# No additional completions for templates
COMPREPLY=()
;;
*)
;;
esac

27
src/dropshell.cpp Normal file
View File

@ -0,0 +1,27 @@
#include "dropshell.hpp"
#include "templates.hpp"
#include <iostream>
#include <iomanip>
void dropshell::list_templates() {
template_manager tm;
std::vector<template_info> templates;
if (!tm.get_templates(templates)) {
std::cerr << "Error: Failed to get templates" << std::endl;
return;
}
if (templates.empty()) {
std::cout << "No templates found." << std::endl;
return;
}
std::cout << "Available templates:" << std::endl;
std::cout << std::left << std::setw(20) << "Name" << "Path" << std::endl;
std::cout << std::string(60, '-') << std::endl;
for (const auto& t : templates) {
std::cout << std::left << std::setw(20) << t.name << t.path << std::endl;
}
}

View File

@ -24,6 +24,8 @@ void print_help(const boost::program_options::options_description& desc);
void print_version();
void check_status();
void list_servers();
void list_templates();
void show_server_details(const std::string& server_name);
// Utility functions
std::vector<ServerInfo> get_configured_servers();

View File

@ -15,10 +15,14 @@ void print_help(const boost::program_options::options_description& desc) {
std::cout << std::endl;
std::cout << " status Check system status" << std::endl;
std::cout << " servers List configured servers" << std::endl;
std::cout << " servers NAME Show details for specific server" << std::endl;
std::cout << " templates List available templates" << std::endl;
std::cout << std::endl;
std::cout << "Examples:" << std::endl;
std::cout << " dropshell servers" << std::endl;
std::cout << " dropshell servers myserver" << std::endl;
std::cout << " dropshell init /path/to/directory" << std::endl;
std::cout << " dropshell templates" << std::endl;
}
} // namespace dropshell

View File

@ -51,7 +51,16 @@ int main(int argc, char* argv[]) {
dropshell::check_status();
return 0;
} else if (cmd == "servers") {
dropshell::list_servers();
if (argc > 2) {
// Show details for specific server
dropshell::show_server_details(argv[2]);
} else {
// List all servers
dropshell::list_servers();
}
return 0;
} else if (cmd == "templates") {
dropshell::list_templates();
return 0;
} else if (cmd == "init") {
if (!vm.count("directory")) {

74
src/server_env.cpp Normal file
View File

@ -0,0 +1,74 @@
#include "server_env.hpp"
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/filesystem.hpp>
#include <cstdlib>
namespace dropshell {
server_env::server_env(const std::string& path) {
// Construct the full path to _server.env
boost::filesystem::path env_path = boost::filesystem::path(path) / "_server.env";
// Check if file exists
if (!boost::filesystem::exists(env_path)) {
throw std::runtime_error("Server environment file not found: " + env_path.string());
}
try {
// Read the INI file
boost::property_tree::ptree pt;
boost::property_tree::ini_parser::read_ini(env_path.string(), pt);
// Store all variables
for (const auto& section : pt) {
for (const auto& key_value : section.second) {
variables[key_value.first] = key_value.second.get_value<std::string>();
}
}
// Verify required variables exist
if (variables.find("SSH_HOST") == variables.end() ||
variables.find("SSH_USER") == variables.end() ||
variables.find("SSH_PORT") == variables.end()) {
throw std::runtime_error("Missing required variables in server environment file");
}
} catch (const boost::property_tree::ini_parser_error& e) {
throw std::runtime_error("Failed to parse server environment file: " + std::string(e.what()));
}
}
std::string server_env::get_variable(const std::string& name) {
auto it = variables.find(name);
if (it == variables.end()) {
return "";
}
std::string value = it->second;
// Replace ${USER} with actual username
const char* username = std::getenv("USER");
if (username) {
std::string user_var = "${USER}";
size_t pos = value.find(user_var);
if (pos != std::string::npos) {
value.replace(pos, user_var.length(), username);
}
}
return value;
}
std::string server_env::get_SSH_HOST() {
return get_variable("SSH_HOST");
}
std::string server_env::get_SSH_USER() {
return get_variable("SSH_USER");
}
std::string server_env::get_SSH_PORT() {
return get_variable("SSH_PORT");
}
} // namespace dropshell

32
src/server_env.hpp Normal file
View File

@ -0,0 +1,32 @@
// server_env.hpp
//
// read the _server.env file and provide a class to access the variables
//
#include <string>
#include <map>
namespace dropshell {
// reads path / _server.env and provides a class to access the variables.
// each env file is required to have the following variables:
// SSH_HOST
// SSH_USER
// SSH_PORT
// the following replacements are made in the values:
// ${USER} -> the username of the user running dropshell
class server_env {
public:
server_env(const std::string& path);
std::string get_variable(const std::string& name);
std::string get_SSH_HOST();
std::string get_SSH_USER();
std::string get_SSH_PORT();
private:
std::map<std::string, std::string> variables;
};
} // namespace dropshell

View File

@ -86,4 +86,67 @@ void list_servers() {
}
}
void show_server_details(const std::string& server_name) {
std::string user_dir;
if (!get_user_directory(user_dir)) {
std::cerr << "Error: User directory not set" << std::endl;
return;
}
fs::path server_dir = fs::path(user_dir) / "servers" / server_name;
if (!fs::exists(server_dir)) {
std::cerr << "Error: Server '" << server_name << "' not found" << std::endl;
return;
}
fs::path env_file = server_dir / "_server.env";
if (!fs::exists(env_file)) {
std::cerr << "Error: Server configuration file not found" << std::endl;
return;
}
std::cout << "Server Details: " << server_name << std::endl;
std::cout << std::string(40, '-') << std::endl;
std::ifstream file(env_file.string());
std::string line;
while (std::getline(file, line)) {
if (!line.empty() && line[0] != '#') {
std::cout << line << std::endl;
}
}
// Check if server is reachable via SSH
std::string ssh_address;
file.clear();
file.seekg(0);
while (std::getline(file, line)) {
if (boost::starts_with(line, "SSH_ADDRESS=")) {
ssh_address = line.substr(12);
break;
}
}
if (!ssh_address.empty()) {
std::cout << std::endl << "Server Status:" << std::endl;
std::cout << std::string(40, '-') << std::endl;
// Try to connect to the server
std::string cmd = "ssh -o ConnectTimeout=5 " + ssh_address + " 'echo connected' 2>/dev/null";
int result = system(cmd.c_str());
if (result == 0) {
std::cout << "Status: Online" << std::endl;
// Get uptime if possible
cmd = "ssh " + ssh_address + " 'uptime' 2>/dev/null";
int rval = system(cmd.c_str());
if (rval != 0) {
std::cout << "Error: Failed to get uptime" << std::endl;
}
} else {
std::cout << "Status: Offline" << std::endl;
}
}
}
} // namespace dropshell

View File

@ -5,6 +5,8 @@
#include <string>
#include <algorithm>
namespace dropshell {
template_manager::template_manager() {
// Constructor implementation
}
@ -74,3 +76,4 @@ bool template_manager::get_template_info(const std::string& name, template_info&
return false;
}
} // namespace dropshell

View File

@ -1,4 +1,9 @@
#include <string>
#include <vector>
namespace dropshell {
class template_info {
public:
std::string name;
@ -20,3 +25,5 @@ class template_manager {
bool get_templates(std::vector<template_info>& templates);
bool get_template_info(const std::string& name, template_info& info);
};
} // namespace dropshell