implement basic command line parsing

This commit is contained in:
Fabian Posch 2024-01-08 13:23:23 -05:00
parent 1f4c020df9
commit b73f25e835
4 changed files with 335 additions and 1 deletions

68
include/cli_util.hpp Normal file
View file

@ -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 <map>
#include <list>
#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

37
include/main.hpp Normal file
View file

@ -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

99
src/cli_util.cpp Normal file
View file

@ -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 <iostream>
#include <sstream>
#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;
}
}

View file

@ -23,9 +23,139 @@
*/
#include <iostream>
#include <getopt.h>
#include <thread>
#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;
}
}