From b73f25e835cf5cf86a8a19b09d4ff39210d7f2e3 Mon Sep 17 00:00:00 2001 From: Fabian Posch Date: Mon, 8 Jan 2024 13:23:23 -0500 Subject: [PATCH] implement basic command line parsing --- include/cli_util.hpp | 68 ++++++++++++++++++++++ include/main.hpp | 37 ++++++++++++ src/cli_util.cpp | 99 ++++++++++++++++++++++++++++++++ src/main.cpp | 132 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 335 insertions(+), 1 deletion(-) create mode 100644 include/cli_util.hpp create mode 100644 include/main.hpp create mode 100644 src/cli_util.cpp diff --git a/include/cli_util.hpp b/include/cli_util.hpp new file mode 100644 index 0000000..defa143 --- /dev/null +++ b/include/cli_util.hpp @@ -0,0 +1,68 @@ + +/************************************************************************* + * + * Copyright (c) 2023 Fabian Posch + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + ************************************************************************** + */ + + +#ifndef __CLI_UTIL_H__ +#define __CLI_UTIL_H__ + +#include +#include +#include "db_client.hpp" + +#define POSTGRES_DEFAULT_PORT 5432 + +// environment variables used by the database module of the argument parser +#define SERVER_ADDR_ENV "ACT_DEPLOY_SERVER_ADDR" +#define SERVER_PORT_ENV "ACT_DEPLOY_SERVER_PORT" +#define SERVER_USER_ENV "ACT_DEPLOY_SERVER_USER" +#define SERVER_PWD_ENV "ACT_DEPLOY_SERVER_PWD" +#define SERVER_DBASE_ENV "ACT_DEPLOY_SERVER_DBASE" + + +/** + * @brief Parse database credentials from arguments or environment + * + * Parses the database options common between the different commands. No command line overrides were given, + * the data is loaded from environment variables given externally through macros. These macros are: + * + * - SERVER_ADDR_ENV: Environment variable containing the address of the Postgresql database server + * - SERVER_PORT_ENV: Variable containing the port of the Postgresql database server + * - SERVER_USER_ENV: Variable containing the database user + * - SERVER_PWD_ENV: Variable containing the database password + * - SERVER_DBASE_ENV: Variable containing the database name + * + * @param arguments Argument list given to the program + * @return db_credentials_t Structure containing the database credentials + * + * @throw std::invalid_argument Thrown if the server name was set by neither the environment nor an override argument + * @throw std::invalid_argument Thrown if the server port was set by neither the environment nor an override argument + * @throw std::invalid_argument Thrown if the given port is invalid + * @throw std::invalid_argument Thrown if the database user was set by neither the environment nor an override argument + * @throw std::invalid_argument Thrown if the database password was set by neither the environment nor an override argument + * @throw std::invalid_argument Thrown if the database name was set by neither the environment nor an override argument + */ +//db::db_credentials_t get_db_cred (arg_list& arguments); + +void get_db_cred_env (db::db_credentials_t& db_cred); + +#endif diff --git a/include/main.hpp b/include/main.hpp new file mode 100644 index 0000000..59effa3 --- /dev/null +++ b/include/main.hpp @@ -0,0 +1,37 @@ + +/************************************************************************* + * + * Copyright (c) 2023 Fabian Posch + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + ************************************************************************** + */ + + +#ifndef __ACTSIM_CLUSTER_AGENT__ +#define __ACTSIM_CLUSTER_AGENT__ + +// program version is defined by external variable +#ifndef PROG_VERSION +#define PROG_VERSION "unknown" +#endif +#define VERSION PROG_VERSION + +void print_usage(); +int main(int argc, char** argv); + +#endif diff --git a/src/cli_util.cpp b/src/cli_util.cpp new file mode 100644 index 0000000..ea8fe91 --- /dev/null +++ b/src/cli_util.cpp @@ -0,0 +1,99 @@ + +/************************************************************************* + * + * Copyright (c) 2023 Fabian Posch + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + ************************************************************************** + */ + +#include +#include +#include "db_client.hpp" +#include "util.h" +#include "cli_util.hpp" + + +void get_db_cred_env (db::db_credentials_t& db_cred) { + + // check if a server was given + if (!db_cred.server_override) { + if (std::getenv(SERVER_ADDR_ENV) == nullptr) { + throw new std::invalid_argument("No database server set in environment variable " SERVER_ADDR_ENV); + } + + db_cred.server = std::getenv(SERVER_ADDR_ENV); + db_cred.server_override = false; + } + + // check if a port was given + if (!db_cred.port_override) { + // if no env variable is set, we use postgresql's default port + if (std::getenv(SERVER_PORT_ENV) == nullptr) { + std::cerr << "Warning: No port given in environment variable " SERVER_PORT_ENV ". Using default Postgresql port." << std::endl; + db_cred.port = POSTGRES_DEFAULT_PORT; + db_cred.port_override = false; + + // otherwise we try to parse it from the environment variable + } else { + + std::string port_st = std::getenv(SERVER_PORT_ENV); + + DEBUG_PRINT("Parsing port " + port_st); + + try { + db_cred.port = std::atoi(port_st.c_str()); + } catch (std::invalid_argument& e) { + throw new std::invalid_argument("Could not parse port from environment variable " SERVER_PORT_ENV); + } + + // make sure the port is valid + if (db_cred.port <= 0) { + throw new std::invalid_argument("Port " SERVER_PORT_ENV " given in environment variable is not a valid port."); + } + + db_cred.port_override = false; + } + } + + // check if a user was given + if (!db_cred.uname_override) { + if (std::getenv(SERVER_USER_ENV) == nullptr) { + throw new std::invalid_argument("No database user set in environment variable " SERVER_USER_ENV); + } + db_cred.uname = std::getenv(SERVER_USER_ENV); + db_cred.uname_override = false; + } + + // check if a password was given + if (!db_cred.pwd_override) { + if (std::getenv(SERVER_PWD_ENV) == nullptr) { + throw new std::invalid_argument("No database password set in environment variable " SERVER_PWD_ENV); + } + db_cred.pwd = std::getenv(SERVER_PWD_ENV); + db_cred.pwd_override = false; + } + + // check if a database was given + if (!db_cred.dbase_override) { + if (std::getenv(SERVER_DBASE_ENV) == nullptr) { + throw new std::invalid_argument("No database set in environment variable " SERVER_DBASE_ENV); + } + db_cred.dbase = std::getenv(SERVER_DBASE_ENV); + db_cred.dbase_override = false; + } +} diff --git a/src/main.cpp b/src/main.cpp index aa10586..74c0efe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,9 +23,139 @@ */ #include +#include +#include +#include "cli_util.hpp" +#include "db_types.hpp" +#include "util.h" +#include "main.hpp" + +void print_usage() { + std::cout << "acstim-cluster-agent v" << VERSION << std::endl; +} int main (int argc, char **argv) { + static struct option long_options[] = { + {"dbase-server", required_argument, 0, 0}, + {"dbase-port", required_argument, 0, 0}, + {"dbase-user", required_argument, 0, 0}, + {"dbase-pwd", required_argument, 0, 0}, + {"dbase-dbase", required_argument, 0, 0}, + {"jobs", optional_argument, 0, 'j'}, + {0, 0, 0, 0} // null termination + }; + + int c; + int option_index = 0; + + // options to be set + int jobs = 1; + db::db_credentials_t db_cred; + + while ((c = getopt_long(argc, argv, "j::", long_options, &option_index)) != -1) { + switch (c) { + case 0: + + DEBUG_PRINT("Long argument found."); + + // switch through the options struct index + switch (option_index) { + case 0: + DEBUG_PRINT("Database server customized."); + db_cred.server = optarg; + db_cred.server_override = true; + break; + + case 1: + DEBUG_PRINT("Database port customized."); + try { + db_cred.port = std::atoi(optarg); + } catch (std::invalid_argument& e) { + std::cerr << "Error: Database port parameter must be a number!" << std::endl; + exit(1); + } + + if (db_cred.port < 1) { + std::cerr << "Error: Database port given is invalid. Aborting." << std::endl; + exit(1); + } + + db_cred.port_override = true; + + case 2: + DEBUG_PRINT("Database user customized."); + db_cred.uname = optarg; + db_cred.uname_override = true; + break; + + case 3: + DEBUG_PRINT("Database password customized."); + db_cred.pwd = optarg; + db_cred.pwd_override = true; + break; + + case 4: + DEBUG_PRINT("Database name customized."); + db_cred.dbase = optarg; + db_cred.dbase_override = true; + + default: + DEBUG_PRINT("Unexpected option index!"); + } + + std::cout << "Option " << long_options[option_index].name; + if (optarg) { + std::cout << " with arg " << optarg; + } + std::cout << std::endl; + break; + + case 'j': + + DEBUG_PRINT("Number of worker threads customized."); + + if (optarg) { + + try { + jobs = std::atoi(optarg); + } catch (std::invalid_argument& e) { + std::cerr << "Error: Worker threads parameter must be a number!" << std::endl; + exit(1); + } + + if (jobs < 1) { + std::cerr << "Error: Number of worker threads smaller than 1. Aborting." << std::endl; + exit(1); + } + } else { + const auto proc_count = std::thread::hardware_concurrency(); + if (proc_count == 0) { + std::cerr << "Error: Could not detect number of hardware threads. Defaulting to 1." << std::endl; + } else { + jobs = proc_count; + } + } + + std::cout << "Agent set to using " << jobs << " worker threads." << std::endl; + + break; + + case '?': + break; + + default: + break; + } + } + + try { + get_db_cred_env(db_cred); + } catch (std::invalid_argument& e) { + std::cerr << "Error: Could not load database configuration from environment. " << e.what() << std::endl; + exit(1); + } + std::cout << "Hello world!" << std::endl; -} \ No newline at end of file +}