Notice to GitKraken users: A vulnerability has been found in the SSH key generation of GitKraken versions 7.6.0 to 8.0.0 (https://www.gitkraken.com/blog/weak-ssh-key-fix). If you use GitKraken and have generated a SSH key using one of these versions, please remove it both from your local workstation and from your LRZ GitLab profile.

21.10.2021, 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

Commit 2088e1d7 authored by Michael Ott's avatar Michael Ott
Browse files

Allow for actual configuration files to be specified on command line, not just...

Allow for actual configuration files to be specified on command line, not just configuration directories. Add exception handling to main of pusher, collectagent, grafanaserver
parent 66a9aac0
......@@ -46,14 +46,13 @@ void AnalyticsController::stop() {
_initialized = false;
}
bool AnalyticsController::initialize(Configuration& settings, const string& configPath) {
bool AnalyticsController::initialize(Configuration& settings) {
_settings = settings;
_configPath = configPath;
_navigator = make_shared<SensorNavigator>();
// A sensor navigator is only built if operator plugins are expected to be instantiated
QueryEngine &_queryEngine = QueryEngine::getInstance();
if(_manager->probe(_configPath, "collectagent.conf")) {
if(_manager->probe(settings.cfgFilePath, settings.cfgFileName)) {
vector<string> topics;
for(const auto& kv : _metadataStore->getMap())
if(kv.second.isValid())
......@@ -77,7 +76,7 @@ bool AnalyticsController::initialize(Configuration& settings, const string& conf
//TODO: find a better solution to disable the SensorBase default cache
_settings.pluginSettings.cacheInterval = 0;
if(!_manager->load(_configPath, "collectagent.conf", _settings.pluginSettings)) {
if(!_manager->load(_settings.cfgFilePath, _settings.cfgFileName, _settings.pluginSettings)) {
LOG(fatal) << "Failed to load data analytics manager!";
return false;
}
......
......@@ -108,7 +108,7 @@ public:
* @param configPath Path to the configuration files for the data analytics framework
* @return True if successful, false otherwise
*/
bool initialize(Configuration& settings, const string& configPath);
bool initialize(Configuration& settings);
/**
* @brief Sets the cache to be used for sensors
......@@ -222,7 +222,6 @@ private:
shared_ptr<OperatorManager> _manager;
// Misc configuration attributes
Configuration _settings;
string _configPath;
// Readings counter
uint64_t _readingCtr;
......
......@@ -529,7 +529,7 @@ void usage() {
012345678901234567890123456789012345678901234567890123456789012345678901234567890
*/
cout << "Usage:" << endl;
cout << " collectagent [-d] [-s] [-x] [-a] [-m<host>] [-c<host>] [-u<username>] [-p<password>] [-t<ttl>] [-v<verbosity>] <path/to/configfiles/>" << endl;
cout << " collectagent [-d] [-s] [-x] [-a] [-m<host>] [-c<host>] [-u<username>] [-p<password>] [-t<ttl>] [-v<verbosity>] <config>" << endl;
cout << " collectagent -h" << endl;
cout << endl;
......@@ -557,7 +557,7 @@ int main(int argc, char* const argv[]) {
// Checking if path to config is supplied
if (argc <= 1) {
cout << "Please specify a path to the config-directory" << endl << endl;
cout << "Please specify a path to the config-directory or a config-file" << endl << endl;
usage();
exit(EXIT_FAILURE);
}
......@@ -584,10 +584,7 @@ int main(int argc, char* const argv[]) {
auto cmdSink = setupCmdLogger();
Configuration config(argv[argc - 1], "collectagent.conf");
if( !config.readConfig() ) {
LOG(fatal) << "Failed to read global configuration!";
exit(EXIT_FAILURE);
}
config.readConfig();
// References to shorten access to config parameters
Configuration& settings = config;
......@@ -739,7 +736,7 @@ int main(int argc, char* const argv[]) {
queryEngine.setGroupQueryCallback(sensorGroupQueryCallback);
queryEngine.setMetadataQueryCallback(metadataQueryCallback);
queryEngine.setJobQueryCallback(jobQueryCallback);
if(!analyticsController->initialize(settings, argv[argc - 1]))
if(!analyticsController->initialize(settings))
return EXIT_FAILURE;
LOG_LEVEL vLogLevel = settings.validateConfig ? LOG_LEVEL::info : LOG_LEVEL::debug;
......@@ -876,6 +873,10 @@ int main(int argc, char* const argv[]) {
delete metadataStore;
LOG(info) << "Collect Agent closed. Bye bye...";
}
catch (const std::runtime_error& e) {
LOG(fatal) << e.what();
return EXIT_FAILURE;
}
catch (const exception& e) {
LOG(fatal) << "Exception: " << e.what();
abrt(EXIT_FAILURE, INTERR);
......
......@@ -171,7 +171,7 @@ public:
*
* @return True if successful, false otherwise
*/
bool readConfig();
void readConfig();
/**
* @brief Reads user credentials from the config file and accordingly adds
......@@ -192,7 +192,9 @@ public:
analyticsSettings_t analyticsSettings;
serverSettings_t restAPISettings;
pluginSettings_t pluginSettings;
std::string cfgFilePath;
std::string cfgFileName;
protected:
/**
* @brief Virtual method to integrate additional configuration blocks
......@@ -215,10 +217,6 @@ protected:
*/
virtual bool readAdditionalValues(boost::property_tree::iptree::value_type &global) { return false; }
// Path and name of the configuration file
std::string _cfgFilePath;
std::string _cfgFileName;
// Logger object
boost::log::sources::severity_logger<boost::log::trivial::severity_level> lg;
};
......
......@@ -27,25 +27,35 @@
#include "globalconfiguration.h"
#include "RESTHttpsServer.h"
#include "boost/filesystem.hpp"
GlobalConfiguration::GlobalConfiguration(const std::string& cfgFilePath, const std::string& cfgFileName) {
_cfgFileName = cfgFileName;
_cfgFilePath = cfgFilePath;
if (_cfgFilePath[_cfgFilePath.length()-1] != '/')
_cfgFilePath.append("/");
boost::filesystem::path p(cfgFilePath);
if (boost::filesystem::exists(p)) {
if (boost::filesystem::is_directory(p)) {
this->cfgFileName = cfgFileName;
this->cfgFilePath = cfgFilePath;
} else {
this->cfgFileName = p.filename().native();
this->cfgFilePath = p.parent_path().native();
}
if (this->cfgFilePath[this->cfgFilePath.length()-1] != '/')
this->cfgFilePath.append("/");
} else {
throw std::runtime_error(cfgFilePath + " does not exist");
}
}
bool GlobalConfiguration::readConfig() {
void GlobalConfiguration::readConfig() {
// Open file
std::string globalConfig = _cfgFilePath;
globalConfig.append(_cfgFileName);
std::string globalConfig = cfgFilePath;
globalConfig.append(cfgFileName);
boost::property_tree::iptree cfg;
// Parse to property_tree
try {
boost::property_tree::read_info(globalConfig, cfg);
} catch (boost::property_tree::info_parser_error& e) {
LOG(error) << "Error when reading " << _cfgFileName << ": " << e.what();
return false;
throw std::runtime_error("Error when parsing " + globalConfig + ": " + e.what());
}
BOOST_FOREACH(boost::property_tree::iptree::value_type &global, cfg.get_child("global")) {
......@@ -119,20 +129,19 @@ bool GlobalConfiguration::readConfig() {
}
readAdditionalBlocks(cfg);
return true;
}
bool GlobalConfiguration::readRestAPIUsers(RESTHttpsServer* server) {
//open file
std::string globalConfig = _cfgFilePath;
globalConfig.append(_cfgFileName);
std::string globalConfig = cfgFilePath;
globalConfig.append(cfgFileName);
boost::property_tree::iptree cfg;
//parse to property_tree
try {
boost::property_tree::read_info(globalConfig, cfg);
} catch (boost::property_tree::info_parser_error& e) {
LOG(error) << "Error when reading users from " << _cfgFileName << ":" << e.what();
LOG(error) << "Error when reading users from " << cfgFileName << ":" << e.what();
return false;
}
......
......@@ -53,18 +53,18 @@ bool Configuration::readAdditionalValues(boost::property_tree::iptree::value_typ
}
bool Configuration::readPlugins(PluginManager &pluginManager) {
std::string globalConfig = _cfgFilePath;
globalConfig.append(_cfgFileName);
std::string globalConfig = cfgFilePath;
globalConfig.append(cfgFileName);
boost::property_tree::iptree cfg;
try {
boost::property_tree::read_info(globalConfig, cfg);
} catch (boost::property_tree::info_parser_error &e) {
LOG(error) << "Error when reading plugins from " << _cfgFileName << ": " << e.what();
LOG(error) << "Error while parsing plugins from " << globalConfig << ": " << e.what();
return false;
}
pluginManager.setCfgFilePath(_cfgFilePath);
pluginManager.setCfgFilePath(cfgFilePath);
//read plugins
BOOST_FOREACH (boost::property_tree::iptree::value_type &plugin, cfg.get_child("plugins")) {
if (boost::iequals(plugin.first, "plugin")) {
......
This diff is collapsed.
......@@ -28,6 +28,7 @@
#include "RestAPI.h"
#include "version.h"
#include "dcdbdaemon.h"
#include "abrt.h"
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
......@@ -52,7 +53,7 @@ void printSyntax()
012345678901234567890123456789012345678901234567890123456789012345678901234567890
*/
std::cout << "Usage:" << std::endl;
std::cout << " grafanaserver [-d] [-c<host:port>] [-t<number>] [-v<level>] [-w<path>] <path/to/configfile/>" << std::endl;
std::cout << " grafanaserver [-d] [-c<host:port>] [-t<number>] [-v<level>] [-w<path>] <config>" << std::endl;
std::cout << " grafanaserver -h" << std::endl;
std::cout << std::endl;
......@@ -103,7 +104,7 @@ int main(int argc, char *argv[])
boost::thread_group threads;
if (argc <= 1) {
cout << "Please specify a path to the config-directory" << endl << endl;
cout << "Please specify a path to the config-directory or a config-file" << endl << endl;
printSyntax();
return 1;
}
......@@ -135,157 +136,164 @@ int main(int argc, char *argv[])
boost::log::sources::severity_logger<boost::log::trivial::severity_level> lg;
//finished logging startup for the moment (file log added later)
_configuration = new Configuration(argv[argc-1], "grafana.conf");
//Read global variables from config file
if(!_configuration->readConfig()) {
LOG(fatal) << "Failed to read global configuration!";
return 1;
try {
_configuration = new Configuration(argv[argc-1], "grafana.conf");
//Read global variables from config file
_configuration->readConfig();
//read global settings
Configuration& globalSettings = *_configuration;
cassandraSettings_t& cassandraSettings = _configuration->cassandraSettings;
serverSettings_t& restAPISettings = _configuration->restAPISettings;
hierarchySettings_t& hierarchySettings = _configuration->hierarchySettings;
//reset getopt()
optind = 1;
//read in options (overwrite dcdbpusher.conf settings if necessary)
while ((c = getopt(argc, argv, opts)) != -1) {
switch (c)
{
case 'c':
cassandraSettings.host = parseNetworkHost(optarg);
cassandraSettings.port = parseNetworkPort(optarg) == "" ? CASSANDRAPORT : parseNetworkPort(optarg);
break;
case 't':
globalSettings.threads = stoul(optarg);
case 'v':
globalSettings.logLevelCmd = stoi(optarg);
break;
case 'd':
globalSettings.daemonize = 1;
break;
case 'w':
globalSettings.tempdir = optarg;
if (globalSettings.tempdir[globalSettings.tempdir.length()-1] != '/') {
globalSettings.tempdir.append("/");
}
break;
case 'h':
printSyntax();
return 1;
default:
if (c != '?') cerr << "Unknown parameter: " << c << endl;
return 1;
}
}
//we now should know where the writable tempdir is
//set up logger to file
if (globalSettings.logLevelFile >= 0) {
auto fileSink = setupFileLogger(globalSettings.tempdir, std::string("grafanaserver"));
fileSink->set_filter(boost::log::trivial::severity >= translateLogLevel(globalSettings.logLevelFile));
}
//severity level may be overwritten (per option or config-file) --> set it according to globalSettings
if (globalSettings.logLevelCmd >= 0) {
cmdSink->set_filter(boost::log::trivial::severity >= translateLogLevel(globalSettings.logLevelCmd));
}
LOG(info) << "Logging setup complete";
//print configuration to give some feedback
//config of plugins is only printed if the config shall be validated or to debug level otherwise
LOG_LEVEL vLogLevel = LOG_LEVEL::debug;
LOG_VAR(vLogLevel) << "----- Configuration -----";
//print global settings in either case
LOG(info) << "Global Settings:";
LOG(info) << " Threads: " << globalSettings.threads;
LOG(info) << " Daemonize: " << (globalSettings.daemonize ? "Enabled" : "Disabled");
LOG(info) << " Write-Dir: " << globalSettings.tempdir;
LOG(info) << "Grafana Settings:";
LOG(info) << " Grafana Server: " << restAPISettings.host << ":" << restAPISettings.port;
LOG(info) << " Certificate: " << restAPISettings.certificate;
LOG(info) << " Private key file: " << restAPISettings.privateKey;
LOG(info) << " DH params from: " << restAPISettings.dhFile;
LOG(info) << "Cassandra Settings:";
LOG(info) << " Cassandra Server: " << cassandraSettings.host << ":" << cassandraSettings.port;
LOG(info) << "Hierarchy Settings:";
LOG(info) << " Regex: " << (hierarchySettings.regex != "" ? hierarchySettings.regex : "none");
LOG(info) << " Separator: " << (hierarchySettings.separator != "" ? hierarchySettings.separator : "none");
LOG_VAR(vLogLevel) << "----- End Configuration -----";
//Setting up the connection with the Cassandra DB
LOG(info) << "Connecting to the Cassandra database...";
_cassandraConnection = new DCDB::Connection();
_cassandraConnection->setHostname(cassandraSettings.host);
_cassandraConnection->setPort(atoi(cassandraSettings.port.c_str()));
if (!_cassandraConnection->connect()) {
LOG(fatal) << "Failed to connect to the Cassandra database!";
return 1;
}
_httpsServer = new RestAPI(restAPISettings, hierarchySettings, _cassandraConnection);
_configuration->readRestAPIUsers(_httpsServer);
if (globalSettings.daemonize) {
//boost.log does not support forking officially.
//however, just don't touch the sinks after daemonizing and it should work nonetheless
LOG(info) << "Detaching...";
cmdSink->flush();
boost::log::core::get()->remove_sink(cmdSink);
cmdSink.reset();
//daemonize
dcdbdaemon();
LOG(info) << "Now detached";
}
LOG(info) << "Creating threads...";
//dummy to keep io service alive even if no tasks remain (e.g. because all sensors have been stopped over REST API)
keepAliveWork = boost::make_shared<boost::asio::io_service::work>(io);
//Create pool of threads which handle the sensors
for(size_t i = 0; i < globalSettings.threads; i++) {
threads.create_thread(bind(static_cast< size_t (boost::asio::io_service::*) () >(&boost::asio::io_service::run), &io));
}
LOG(info) << "Threads created!";
LOG(info) << "Starting RestAPI Https Server...";
_httpsServer->start();
LOG(info) << "Registering signal handlers...";
signal(SIGINT, sigHandler); //Handle Strg+C
signal(SIGTERM, sigHandler); //Handle termination
LOG(info) << "Signal handlers registered!";
LOG(info) << "Cleaning up...";
delete _configuration;
LOG(info) << "Setup complete!";
LOG(trace) << "Running...";
//Run until Strg+C
threads.join_all();
//will only continue if interrupted by SIGINT and threads were stopped
LOG(info) << "Tearing down objects...";
delete _cassandraConnection;
delete _httpsServer;
}
//read global settings
Configuration& globalSettings = *_configuration;
cassandraSettings_t& cassandraSettings = _configuration->cassandraSettings;
serverSettings_t& restAPISettings = _configuration->restAPISettings;
hierarchySettings_t& hierarchySettings = _configuration->hierarchySettings;
//reset getopt()
optind = 1;
//read in options (overwrite dcdbpusher.conf settings if necessary)
while ((c = getopt(argc, argv, opts)) != -1) {
switch (c)
{
case 'c':
cassandraSettings.host = parseNetworkHost(optarg);
cassandraSettings.port = parseNetworkPort(optarg) == "" ? CASSANDRAPORT : parseNetworkPort(optarg);
break;
case 't':
globalSettings.threads = stoul(optarg);
case 'v':
globalSettings.logLevelCmd = stoi(optarg);
break;
case 'd':
globalSettings.daemonize = 1;
break;
case 'w':
globalSettings.tempdir = optarg;
if (globalSettings.tempdir[globalSettings.tempdir.length()-1] != '/') {
globalSettings.tempdir.append("/");
}
break;
case 'h':
printSyntax();
return 1;
default:
if (c != '?') cerr << "Unknown parameter: " << c << endl;
return 1;
}
}
//we now should know where the writable tempdir is
//set up logger to file
if (globalSettings.logLevelFile >= 0) {
auto fileSink = setupFileLogger(globalSettings.tempdir, std::string("grafanaserver"));
fileSink->set_filter(boost::log::trivial::severity >= translateLogLevel(globalSettings.logLevelFile));
catch (const std::runtime_error& e) {
LOG(fatal) << e.what();
return EXIT_FAILURE;
}
//severity level may be overwritten (per option or config-file) --> set it according to globalSettings
if (globalSettings.logLevelCmd >= 0) {
cmdSink->set_filter(boost::log::trivial::severity >= translateLogLevel(globalSettings.logLevelCmd));
catch (const exception& e) {
LOG(fatal) << "Exception: " << e.what();
abrt(EXIT_FAILURE, INTERR);
}
LOG(info) << "Logging setup complete";
//print configuration to give some feedback
//config of plugins is only printed if the config shall be validated or to debug level otherwise
LOG_LEVEL vLogLevel = LOG_LEVEL::debug;
LOG_VAR(vLogLevel) << "----- Configuration -----";
//print global settings in either case
LOG(info) << "Global Settings:";
LOG(info) << " Threads: " << globalSettings.threads;
LOG(info) << " Daemonize: " << (globalSettings.daemonize ? "Enabled" : "Disabled");
LOG(info) << " Write-Dir: " << globalSettings.tempdir;
LOG(info) << "Grafana Settings:";
LOG(info) << " Grafana Server: " << restAPISettings.host << ":" << restAPISettings.port;
LOG(info) << " Certificate: " << restAPISettings.certificate;
LOG(info) << " Private key file: " << restAPISettings.privateKey;
LOG(info) << " DH params from: " << restAPISettings.dhFile;
LOG(info) << "Cassandra Settings:";
LOG(info) << " Cassandra Server: " << cassandraSettings.host << ":" << cassandraSettings.port;
LOG(info) << "Hierarchy Settings:";
LOG(info) << " Regex: " << (hierarchySettings.regex != "" ? hierarchySettings.regex : "none");
LOG(info) << " Separator: " << (hierarchySettings.separator != "" ? hierarchySettings.separator : "none");
LOG_VAR(vLogLevel) << "----- End Configuration -----";
//Setting up the connection with the Cassandra DB
LOG(info) << "Connecting to the Cassandra database...";
_cassandraConnection = new DCDB::Connection();
_cassandraConnection->setHostname(cassandraSettings.host);
_cassandraConnection->setPort(atoi(cassandraSettings.port.c_str()));
if (!_cassandraConnection->connect()) {
LOG(fatal) << "Failed to connect to the Cassandra database!";
return 1;
}
_httpsServer = new RestAPI(restAPISettings, hierarchySettings, _cassandraConnection);
_configuration->readRestAPIUsers(_httpsServer);
if (globalSettings.daemonize) {
//boost.log does not support forking officially.
//however, just don't touch the sinks after daemonizing and it should work nonetheless
LOG(info) << "Detaching...";
cmdSink->flush();
boost::log::core::get()->remove_sink(cmdSink);
cmdSink.reset();
//daemonize
dcdbdaemon();
LOG(info) << "Now detached";
}
LOG(info) << "Creating threads...";
//dummy to keep io service alive even if no tasks remain (e.g. because all sensors have been stopped over REST API)
keepAliveWork = boost::make_shared<boost::asio::io_service::work>(io);
//Create pool of threads which handle the sensors
for(size_t i = 0; i < globalSettings.threads; i++) {
threads.create_thread(bind(static_cast< size_t (boost::asio::io_service::*) () >(&boost::asio::io_service::run), &io));
}
LOG(info) << "Threads created!";
LOG(info) << "Starting RestAPI Https Server...";
_httpsServer->start();
LOG(info) << "Registering signal handlers...";
signal(SIGINT, sigHandler); //Handle Strg+C
signal(SIGTERM, sigHandler); //Handle termination
LOG(info) << "Signal handlers registered!";
LOG(info) << "Cleaning up...";
delete _configuration;
LOG(info) << "Setup complete!";
LOG(trace) << "Running...";
//Run until Strg+C
threads.join_all();
//will only continue if interrupted by SIGINT and threads were stopped
LOG(info) << "Tearing down objects...";
delete _cassandraConnection;
delete _httpsServer;
LOG(info) << "Exiting...Goodbye!";
return 0;
}
......@@ -23,6 +23,7 @@ LIBS = -L../lib \
-lboost_log \
-lboost_regex \
-lboost_log_setup \
-lboost_filesystem \
-lcrypto \
-lssl
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment