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.
......
Supports Markdown
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