Currently job artifacts in CI/CD pipelines on LRZ GitLab never expire. Starting from Wed 26.1.2022 the default expiration time will be 30 days (GitLab default). Currently existing artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

Commit 6cd50299 authored by Micha Mueller's avatar Micha Mueller
Browse files

New feature for REST API: one can trigger reload of a plugin configuration via PUT request

parent aac7502a
......@@ -129,7 +129,7 @@ Tables with allowed ressources sorted by REST methods can be found below. A quer
| Ressource | Explanation |
|:--------- |:----------- |
| /[plugin]/[action] | One can request to do a action on the specified plugin. Currently supported actions are `start` and `stop` which start or stop the polling of the sensors of the plugin.
| /[plugin]/[action] | One can request to do a action on the specified plugin. Currently supported actions are `start`, `stop` and `reload` which start or stop the polling of the sensors of the plugin respectively triggers a reload of the plugin configuration. If a configuration reload is requested, all sensors of the plugin are stopped first. Then new sensors are created and started according to the configuration.
### Examples
......
......@@ -20,19 +20,42 @@ typedef struct {
} pluginSettings_t;
/**
* Abstract base class, which defines the interface for the configurators in the shared dynamic libraries.
* Base class, which defines the interface for the configurators in the shared dynamic libraries.
* This base class shall not be constructed on itw own.
*/
class Configurator {
public:
Configurator() : _cacheInterval(900000) {}
virtual ~Configurator() {}
virtual ~Configurator() {
for (auto s : _sensors) {
delete s;
}
}
/**
* Read in the given configuration
* @param cfgPath Path to the config-file
* @return true on success, false otherwise
*/
virtual bool readConfig(std::string cfgPath) = 0;
virtual bool readConfig(std::string cfgPath) {
_cfgPath = cfgPath;
return true;
}
/**
* Clear internal storage and read in the configuration again.
*/
virtual bool reReadConfig() {
for (auto s : _sensors) {
s->stopPolling();
}
for (auto s : _sensors) {
delete s;
}
_sensors.clear();
return this->readConfig(_cfgPath);
}
virtual void setGlobalSettings(const pluginSettings_t& pluginSettings) {
_mqttPrefix = pluginSettings.mqttPrefix;
......@@ -44,6 +67,7 @@ public:
}
protected:
std::string _cfgPath;
std::string _mqttPrefix;
unsigned int _cacheInterval;
std::vector<Sensor*> _sensors;
......
......@@ -227,36 +227,68 @@ void HttpsServer::requestHandler::operator()(server::request const &request, ser
goto error;
}
//check if query and action are valid values
if (pathStrs[1] != "start" && pathStrs[1] != "stop") {
LOGH(warning) << "Unknown action " << pathStrs[1] << " requested";
connection->set_status(server::connection::not_supported);
goto error;
}
std::string action = pathStrs[1];
//process actual request
response = "Plugin not found!";
connection->set_status(server::connection::not_found);
for(auto& p : _httpsServer._plugins) {
if (p.id == pathStrs[0]) {
if (action == "start") {
//switch code depending on selected action
if (action == "start") {
for(auto& p : _httpsServer._plugins) {
if (p.id == pathStrs[0]) {
for(auto s : p.configurator->getSensors()) {
s->startPolling();
}
response = "Plugin " + pathStrs[0] + ": Sensors started";
connection->set_status(server::connection::ok);
} else if (action == "stop") {
break;
}
}
} else if (action == "stop") {
for(auto& p : _httpsServer._plugins) {
if (p.id == pathStrs[0]) {
for(auto s : p.configurator->getSensors()) {
s->stopPolling();
}
response = "Plugin " + pathStrs[0] + ": Sensors stopped";
connection->set_status(server::connection::ok);
break;
}
break;
}
} else if (action == "reload") {
for(auto& p : _httpsServer._plugins) {
if (p.id == pathStrs[0]) {
//before modifying the plugin we need to ensure that we have exclusive access
//therefore pause the only other concurrent user (MQTTPusher)
_httpsServer._mqttPusher->halt();
//wait until MQTTPusher is paused
while (!_httpsServer._mqttPusher->isHalted()) {
sleep(1);
}
if (p.configurator->reReadConfig()) {
response = "Plugin " + pathStrs[0] + ": Configuration reloaded";
connection->set_status(server::connection::ok);
} else {
response = "Plugin " + pathStrs[0] + ": Could not reload configuration";
connection->set_status(server::connection::internal_server_error);
}
for(auto s : p.configurator->getSensors()) {
s->init(_httpsServer._io);
s->startPolling();
}
//continue MQTTPusher
_httpsServer._mqttPusher->cont();
break;
}
}
} else {
LOGH(warning) << "Unknown action " << pathStrs[1] << " requested";
connection->set_status(server::connection::not_supported);
goto error;
}
}
......@@ -275,8 +307,8 @@ void HttpsServer::requestHandler::log(const server::string_type& message) {
LOGH(error) << message;
}
HttpsServer::HttpsServer(restAPISettings_t restAPISettings, pluginVector_t& plugins) :
_plugins(plugins), _handler(*this) {
HttpsServer::HttpsServer(restAPISettings_t restAPISettings, pluginVector_t& plugins, MQTTPusher* mqttPusher, boost::asio::io_service& io) :
_plugins(plugins), _mqttPusher(mqttPusher), _io(io), _handler(*this) {
std::shared_ptr<asio::ssl::context> ctx = std::make_shared<asio::ssl::context>(asio::ssl::context::sslv23);
ctx->set_options(asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv3 | asio::ssl::context::single_dh_use);
......
......@@ -20,8 +20,11 @@
#include <asio.hpp>
#include <asio/ssl.hpp>
#include <boost/asio.hpp>
#include "Logging.h"
#include "PluginDefinitions.h"
#include "MQTTPusher.h"
typedef struct {
std::string restHost;
......@@ -44,7 +47,7 @@ typedef std::map<std::string, std::bitset<NUM_PERMISSIONS>> authkeyMap_t;
class HttpsServer {
public:
HttpsServer(restAPISettings_t restAPISettings, pluginVector_t& plugins);
HttpsServer(restAPISettings_t restAPISettings, pluginVector_t& plugins, MQTTPusher* mqttPusher, boost::asio::io_service& io);
virtual ~HttpsServer();
bool addAuthkey(authkeyMap_t::value_type authkey) {
......@@ -75,7 +78,7 @@ private:
void log(const server::string_type& message);
private:
HttpsServer& _httpsServer; //to remember who is our parent. We need access to its _plugins
HttpsServer& _httpsServer; //to remember who is our parent. We need access to its member variables (like _plugins)
boost::log::sources::severity_logger<boost::log::trivial::severity_level> lg;
};
......@@ -94,6 +97,8 @@ private:
pluginVector_t& _plugins;
authkeyMap_t _authkeys;
MQTTPusher* _mqttPusher;
boost::asio::io_service& _io;
server* _server;
requestHandler _handler;
......
......@@ -18,7 +18,9 @@ MQTTPusher::MQTTPusher(int brokerPort, const std::string& brokerHost,
_brokerHost(brokerHost),
_plugins(plugins),
_connected(false),
_keepRunning(true) {
_keepRunning(true),
_doHalt(false),
_halted(false) {
//first print some info
int mosqMajor, mosqMinor, mosqRevision;
......@@ -73,6 +75,12 @@ void MQTTPusher::push() {
reading_t* reads = new reading_t[1024];
std::size_t totalCount = 0;
while (_keepRunning || totalCount) {
if (_doHalt) {
_halted = true;
sleep(2);
continue;
}
_halted = false;
totalCount = 0;
for(auto& p : _plugins) {
for(auto s : p.configurator->getSensors()) {
......@@ -117,6 +125,10 @@ void MQTTPusher::push() {
}
}
}
if(_doHalt) {
//for faster response
continue;
}
}
}
sleep(1);
......
......@@ -8,7 +8,7 @@
#ifndef MQTTPUSHER_H_
#define MQTTPUSHER_H_
#include "Configuration.h"
#include "PluginDefinitions.h"
#include <mosquitto.h>
/**
......@@ -30,6 +30,18 @@ public:
_keepRunning = false;
}
void halt() {
_doHalt = true;
}
void cont() {
_doHalt = false;
}
bool isHalted() const {
return _halted;
}
private:
int _brokerPort;
std::string _brokerHost;
......@@ -37,6 +49,8 @@ private:
struct mosquitto* _mosq;
bool _connected;
bool _keepRunning;
bool _doHalt;
bool _halted;
boost::log::sources::severity_logger<boost::log::trivial::severity_level> lg;
};
......
......@@ -349,7 +349,7 @@ int main(int argc, char** argv) {
//MQTTPusher and Https server get their own threads
_mqttPusher = new MQTTPusher(globalSettings.brokerPort, globalSettings.brokerHost, pluginSettings.mqttPrefix, _configuration->getPlugins());
_httpsServer = new HttpsServer(restAPISettings, _configuration->getPlugins());
_httpsServer = new HttpsServer(restAPISettings, _configuration->getPlugins(), _mqttPusher, io);
_configuration->readAuthkeys(_httpsServer);
boost::thread mqttThread(bind(&MQTTPusher::push, _mqttPusher));
......
......@@ -18,13 +18,11 @@ BACnetConfigurator::BACnetConfigurator() {
}
BACnetConfigurator::~BACnetConfigurator() {
for(auto s : _sensors) {
delete s;
}
delete _bacClient;
}
bool BACnetConfigurator::readConfig(std::string cfgPath) {
Configurator::readConfig(cfgPath);
boost::property_tree::iptree cfg;
boost::property_tree::read_info(cfgPath, cfg);
......
......@@ -34,6 +34,17 @@ public:
*/
bool readConfig(std::string cfgPath);
//Overwrite from Configurator
bool reReadConfig() {
for (auto s : _sensors) {
s->stopPolling();
}
delete _bacClient;
_bacClient = NULL;
_templateSensors.clear();
return Configurator::reReadConfig();
}
private:
/**
* Set the variables of sensor according to the values specified in config.
......
......@@ -22,13 +22,11 @@ IPMIConfigurator::IPMIConfigurator() {
_globalHost.retransmissionTimeout = 0;
}
IPMIConfigurator::~IPMIConfigurator() {
for (auto s : _sensors) {
delete s;
}
}
IPMIConfigurator::~IPMIConfigurator() {}
bool IPMIConfigurator::readConfig(std::string cfgPath) {
Configurator::readConfig(cfgPath);
boost::property_tree::iptree cfg;
boost::property_tree::read_info(cfgPath, cfg);
......
......@@ -36,11 +36,21 @@ namespace DCDB {
bool readConfig(std::string cfgPath);
//Overwrite from Configurator
virtual void setGlobalSettings(const pluginSettings_t& pluginSettings) {
void setGlobalSettings(const pluginSettings_t& pluginSettings) {
Configurator::setGlobalSettings(pluginSettings);
_tempdir = pluginSettings.tempdir;
}
//Overwrite from Configurator
bool reReadConfig() {
for (auto s : _sensors) {
s->stopPolling();
}
_hosts.clear();
_templateSensors.clear();
return Configurator::reReadConfig();
}
private:
/**
* Set the variables of sensor according to the values specified in config.
......
......@@ -41,8 +41,7 @@ IPMIHost::IPMIHost(const std::string& hostName, uint32_t retransmissionTimeout,
_delayNextReadUntil = 0;
}
IPMIHost::~IPMIHost() {
}
IPMIHost::~IPMIHost() {}
int IPMIHost::connect() {
if (!(_ipmiCtx = ipmi_ctx_create())) {
......
......@@ -18,16 +18,13 @@ using namespace std;
PDUConfigurator::PDUConfigurator() {
// TODO Auto-generated constructor stub
}
PDUConfigurator::~PDUConfigurator() {
for (auto s : _sensors) {
delete s;
}
}
PDUConfigurator::~PDUConfigurator() {}
bool PDUConfigurator::readConfig(std::string cfgPath) {
Configurator::readConfig(cfgPath);
boost::property_tree::iptree cfg;
boost::property_tree::read_info(cfgPath, cfg);
......
......@@ -34,6 +34,16 @@ public:
*/
bool readConfig(std::string cfgPath);
//Overwrite from Configurator
bool reReadConfig() {
for (auto s : _sensors) {
s->stopPolling();
}
_pdus.clear();
_templateSensors.clear();
return Configurator::reReadConfig();
}
private:
/**
* Set the variables of sensor according to the values specified in config.
......
......@@ -56,14 +56,10 @@ PerfeventConfigurator::PerfeventConfigurator() {
//TODO set up map for rest of config enum
}
PerfeventConfigurator::~PerfeventConfigurator() {
for(auto s : _sensors) {
delete s;
}
}
PerfeventConfigurator::~PerfeventConfigurator() {}
bool PerfeventConfigurator::readConfig(std::string cfgPath) {
//read template counters
Configurator::readConfig(cfgPath);
boost::property_tree::iptree cfg;
boost::property_tree::read_info(cfgPath, cfg);
......@@ -88,6 +84,7 @@ bool PerfeventConfigurator::readConfig(std::string cfgPath) {
}
}
//read template counters
BOOST_FOREACH(boost::property_tree::iptree::value_type &counter, cfg.get_child("CounterTemplate")) {
if (boost::iequals(counter.first, "counter")) {
LOG(debug) << "Template Counter \"" << counter.second.data() << "\"";
......
......@@ -34,6 +34,13 @@ public:
*/
bool readConfig(std::string cfgPath);
//Overwrite from Configurator
bool reReadConfig() {
_templateCounters.clear();
_templateCpus.clear();
return Configurator::reReadConfig();
}
private:
/**
* Set the variables of counter according to the values specified in config.
......
......@@ -14,17 +14,13 @@
using namespace std;
SysfsConfigurator::SysfsConfigurator() {
SysfsConfigurator::SysfsConfigurator() {}
}
SysfsConfigurator::~SysfsConfigurator() {
for(auto s : _sensors) {
delete s;
}
}
SysfsConfigurator::~SysfsConfigurator() {}
bool SysfsConfigurator::readConfig(std::string cfgPath) {
Configurator::readConfig(cfgPath);
boost::property_tree::iptree cfg;
boost::property_tree::read_info(cfgPath, cfg);
......
......@@ -31,6 +31,12 @@ public:
*/
bool readConfig(std::string cfgPath);
//Overwrite from Configurator
bool reReadConfig() {
_templateSensors.clear();
return Configurator::reReadConfig();
}
private:
/**
* Set the variables of sensor according to the values specified in config.
......
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