Commit 51c75916 authored by Michael Ott's avatar Michael Ott
Browse files

Allow for sensor and host templates

parent fc31a19d
......@@ -14,6 +14,8 @@
#include <boost/optional.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream>
#include <iomanip>
#include <sstream>
namespace DCDB {
......@@ -53,116 +55,173 @@ bool IPMIConfigurator::readConfig(std::string cfgPath) {
}
}
//read template sensors
BOOST_FOREACH(boost::property_tree::iptree::value_type &sensor, cfg.get_child("templateSensors")) {
if (boost::iequals(sensor.first, "sensor")) {
LOG(debug) << "Template Sensor \"" << sensor.second.data() << "\"";
if (!sensor.second.empty()) {
DCDB::IPMISensor ipmiSensor(sensor.second.data());
if(readSensor(ipmiSensor, sensor.second, true)) {
_templateSensors.insert(sensorMap_t::value_type(ipmiSensor.getName(), ipmiSensor));
} else {
LOG(warning) << "Template sensor \"" << sensor.second.data() << "\" has bad values! Ignoring...";
//read templates
boost::optional<boost::property_tree::iptree&> templates = cfg.get_child_optional("templates");
if (templates) {
BOOST_FOREACH(boost::property_tree::iptree::value_type &tmpl, templates.get()) {
if (boost::iequals(tmpl.first, "sensor")) {
LOG(debug) << "Template Sensor \"" << tmpl.second.data() << "\"";
if (!tmpl.second.empty()) {
DCDB::IPMISensor *ipmiSensor = new DCDB::IPMISensor(tmpl.second.data());
if(readSensor(ipmiSensor, tmpl.second)) {
_templateSensors.insert(sensorMap_t::value_type(ipmiSensor->getName(), ipmiSensor));
} else {
LOG(warning) << "Template sensor \"" << tmpl.second.data() << "\" has bad values! Ignoring...";
}
}
}
}
BOOST_FOREACH(boost::property_tree::iptree::value_type &tmpl, templates.get()) {
if (boost::iequals(tmpl.first, "host")) {
LOG(debug) << "Template Host \"" << tmpl.second.data() << "\"";
if (!tmpl.second.empty()) {
DCDB::IPMIHost *ipmiHost = new DCDB::IPMIHost(tmpl.second.data(), _globalHost.retransmissionTimeout, _globalHost.sessionTimeout);
if(readHost(ipmiHost, tmpl.second, true)) {
_templateHosts.insert(hostMap_t::value_type(ipmiHost->getHostName(), ipmiHost));
} else {
LOG(warning) << "Template host \"" << tmpl.second.data() << "\" has bad values! Ignoring...";
}
}
}
}
}
BOOST_FOREACH(boost::property_tree::iptree::value_type &host, cfg.get_child("hosts")) {
if (boost::iequals(host.first, ("host"))) {
LOG(debug) << "Host " << host.second.data();
_hosts.push_back(DCDB::IPMIHost(host.second.data(), _globalHost.retransmissionTimeout, _globalHost.sessionTimeout));
DCDB::IPMIHost &ipmiHost = _hosts.back();
ipmiHost.setMqttPrefix(_mqttPrefix);
ipmiHost.setCache(_tempdir);
if (!host.second.empty()) {
BOOST_FOREACH(boost::property_tree::iptree::value_type &h, host.second) {
if (boost::iequals(h.first, "username")) {
ipmiHost.setUserName(h.second.data());
LOG(debug) << " Username " << ipmiHost.getUserName();
} else if (boost::iequals(h.first, "password")) {
ipmiHost.setPassword(h.second.data());
LOG(debug) << " Password " << ipmiHost.getPassword();
} else if (boost::iequals(h.first, "mqttprefix")) {
ipmiHost.setMqttPrefix(h.second.data());
LOG(debug) << " MQTTPrefix " << ipmiHost.getMqttPrefix();
} else if (boost::iequals(h.first, "sensors")) {
BOOST_FOREACH(boost::property_tree::iptree::value_type &sensor, h.second) {
LOG(debug) << "Sensor \"" << sensor.second.data() << "\"";
sensorMap_t::iterator it = _templateSensors.find(sensor.second.data());
if (!sensor.second.empty() || (it != _templateSensors.end())) {
std::string name = host.second.data() + "_" + sensor.second.data();
DCDB::IPMISensor* ipmiSensor = new DCDB::IPMISensor(name);
//first check if default sensor is given
boost::optional<boost::property_tree::iptree&> defaultC = sensor.second.get_child_optional("default");
if(defaultC) {
LOG(debug) << " Using \"" << defaultC.get().data() << "\" as default.";
it = _templateSensors.find(defaultC.get().data());
} else if (it != _templateSensors.end()){
LOG(debug) << " Using \"" << sensor.second.data() << "\" as default.";
}
if(it != _templateSensors.end()) {
*ipmiSensor = it->second;
ipmiSensor->setName(name);
if (ipmiHost.getMqttPrefix() != "") {
ipmiSensor->setMqtt(ipmiHost.getMqttPrefix() + it->second.getMqtt());
} else {
ipmiSensor->setMqtt(_mqttPrefix + it->second.getMqtt());
}
} else {
LOG(warning) << " Template sensor \"" << defaultC.get().data() << "\" not found! Using standard values.";
}
//set pointer to corresponding host
ipmiSensor->setHost(&ipmiHost);
//read remaining values
if(readSensor(*ipmiSensor, sensor.second, false)) {
_sensors.push_back(ipmiSensor);
} else {
LOG(warning) << " Sensor \"" << sensor.second.data() << "\" has bad values! Ignoring..." << std::endl;
}
}
}
DCDB::IPMIHost *ipmiHost = NULL;
//first check if default host is given
boost::optional<boost::property_tree::iptree&> defaultHost = host.second.get_child_optional("default");
if(defaultHost) {
hostMap_t::iterator it = _templateHosts.find(defaultHost.get().data());
if (it != _templateHosts.end()) {
ipmiHost = new DCDB::IPMIHost(*(it->second));
ipmiHost->clearSensors();
ipmiHost->setHostName(host.second.data());
BOOST_FOREACH(DCDB::IPMISensor* tmpl, it->second->getSensors()) {
DCDB::IPMISensor *ipmiSensor = new DCDB::IPMISensor(*tmpl);
ipmiHost->addSensor(ipmiSensor);
_sensors.push_back(ipmiSensor);
}
} else {
LOG(warning) << " Template host \"" << defaultHost.get().data() << "\" not found! Using standard values.";
}
}
if (!ipmiHost) {
ipmiHost = new DCDB::IPMIHost(host.second.data(), _globalHost.retransmissionTimeout, _globalHost.sessionTimeout);
}
_hosts.push_back(ipmiHost);
ipmiHost->setMqttPrefix(_mqttPrefix);
ipmiHost->setCache(_tempdir);
readHost(ipmiHost, host.second, false);
}
}
return true;
}
bool IPMIConfigurator::readSensor(DCDB::IPMISensor& sensor, boost::property_tree::iptree& config, bool isTemplate) {
bool IPMIConfigurator::readHost(DCDB::IPMIHost *host, boost::property_tree::iptree& config, bool isTemplate) {
BOOST_FOREACH(boost::property_tree::iptree::value_type &val, config) {
if (boost::iequals(val.first, "interval")) {
sensor.setInterval(stoull(val.second.data()));
} else if (boost::iequals(val.first, "mqttsuffix")) {
if (isTemplate) {
sensor.setMqtt(val.second.data());
} else {
if (sensor.getHost() != NULL) {
// only workaround so that every host can define own prefix
// not guaranteed, but should actually work as long as prefix is defined before the sensors within a host
if (sensor.getHost()->getMqttPrefix() != "") {
sensor.setMqtt(sensor.getHost()->getMqttPrefix() + val.second.data());
if (boost::iequals(val.first, "username")) {
host->setUserName(val.second.data());
} else if (boost::iequals(val.first, "password")) {
host->setPassword(val.second.data());
} else if (boost::iequals(val.first, "mqttprefix")) {
host->setMqttPrefix(val.second.data());
} else if (boost::iequals(val.first, "sensors")) {
BOOST_FOREACH(boost::property_tree::iptree::value_type &sensor, val.second) {
sensorMap_t::iterator it = _templateSensors.find(sensor.second.data());
if (!sensor.second.empty() || (it != _templateSensors.end())) {
DCDB::IPMISensor* ipmiSensor;
//first check if default sensor is given
boost::optional<boost::property_tree::iptree&> defaultC = sensor.second.get_child_optional("default");
if(defaultC) {
it = _templateSensors.find(defaultC.get().data());
if (it == _templateSensors.end()) {
LOG(warning) << " Template sensor \"" << defaultC.get().data() << "\" not found! Using standard values.";
}
}
if(it != _templateSensors.end()) {
ipmiSensor = new DCDB::IPMISensor(*(it->second));
} else {
ipmiSensor = new DCDB::IPMISensor(sensor.second.data());
}
//set pointer to corresponding host
ipmiSensor->setHost(host);
//read remaining values
if(readSensor(ipmiSensor, sensor.second)) {
host->addSensor(ipmiSensor);;
if (!isTemplate) {
_sensors.push_back(ipmiSensor);
}
} else {
sensor.setMqtt(_mqttPrefix + val.second.data());
LOG(warning) << " Sensor \"" << sensor.second.data() << "\" has bad values! Ignoring..." << std::endl;
}
}
}
}
}
if (!isTemplate) {
LOG(debug) << " Hostname: " << host->getHostName();
LOG(debug) << " Username: " << host->getUserName();
LOG(debug) << " Password: " << host->getPassword();
LOG(debug) << " MQTTPrefix: " << host->getMqttPrefix();
LOG(debug) << " Sensors: ";
BOOST_FOREACH(DCDB::IPMISensor* ipmiSensor, host->getSensors()) {
LOG(debug) << " " << ipmiSensor->getName();
LOG(debug) << " MQTTSuffix: " << ipmiSensor->getMqtt();
LOG(debug) << " Interval: " << ipmiSensor->getInterval();
LOG(debug) << " minValues: " << ipmiSensor->getMinValues();
LOG(debug) << " factor: " << ipmiSensor->getFactor();
if (ipmiSensor->getRecordId() != 0) {
LOG(debug) << " RecordID: " << ipmiSensor->getRecordId();
} else {
std::stringstream ss;
ss << std::hex;
for (auto c: ipmiSensor->getRawCmd())
ss << " 0x" << std::setw(2) << std::setfill('0') << unsigned(c);
LOG(debug) << " Raw Command:" << ss.str();
LOG(debug) << " Start: " << unsigned(ipmiSensor->getStart());
LOG(debug) << " Stop: " << unsigned(ipmiSensor->getStop());
}
ipmiSensor->setHost(host);
ipmiSensor->setName(host->getHostName() + "_" + ipmiSensor->getName());
if (host->getMqttPrefix() != "") {
ipmiSensor->setMqtt(host->getMqttPrefix() + ipmiSensor->getMqtt());
} else {
ipmiSensor->setMqtt(_mqttPrefix + ipmiSensor->getMqtt());
}
}
}
return true;
}
bool IPMIConfigurator::readSensor(DCDB::IPMISensor *sensor, boost::property_tree::iptree& config) {
BOOST_FOREACH(boost::property_tree::iptree::value_type &val, config) {
if (boost::iequals(val.first, "interval")) {
sensor->setInterval(stoull(val.second.data()));
} else if (boost::iequals(val.first, "mqttsuffix")) {
sensor->setMqtt(val.second.data());
} else if (boost::iequals(val.first, "minValues")) {
sensor.setMinValues(stoull(val.second.data()));
sensor->setMinValues(stoull(val.second.data()));
} else if (boost::iequals(val.first, ("cmd"))) {
sensor.setRawCmd(val.second.data());
sensor->setRawCmd(val.second.data());
} else if (boost::iequals(val.first, "start")) {
sensor.setStart(stoi(val.second.data()));
sensor->setStart(stoi(val.second.data()));
} else if (boost::iequals(val.first, "stop")) {
sensor.setStop(stoi(val.second.data()));
sensor->setStop(stoi(val.second.data()));
} else if (boost::iequals(val.first, ("recordId"))) {
sensor.setRecordId(stoul(val.second.data()));
sensor->setRecordId(stoul(val.second.data()));
} else if (boost::iequals(val.first, ("factor"))) {
sensor.setFactor(std::stod(val.second.data()));
sensor->setFactor(std::stod(val.second.data()));
} else if (boost::iequals(val.first, "default")) {
//avoid unnecessary "Value not recognized" message
} else {
......@@ -170,20 +229,7 @@ bool IPMIConfigurator::readSensor(DCDB::IPMISensor& sensor, boost::property_tree
}
}
sensor.setCacheInterval(_cacheInterval);
if (!isTemplate) {
LOG(debug) << " MQTTSuffix:" << sensor.getMqtt();
LOG(debug) << " Interval : " << sensor.getInterval();
LOG(debug) << " minValues: " << sensor.getMinValues();
LOG(debug) << " factor : " << sensor.getFactor();
if (sensor.getRecordId() != 0) {
LOG(debug) << " RecordID : " << sensor.getRecordId();
} else {
LOG(debug) << " Using raw command";
LOG(debug) << " Start : " << unsigned(sensor.getStart());
LOG(debug) << " Stop : " << unsigned(sensor.getStop());
}
}
sensor->setCacheInterval(_cacheInterval);
return true;
}
......
......@@ -22,8 +22,9 @@ namespace DCDB {
class IPMIConfigurator : public Configurator {
typedef std::list<DCDB::IPMIHost> hostList_t;
typedef std::map<std::string, DCDB::IPMISensor> sensorMap_t;
typedef std::list<DCDB::IPMIHost*> hostList_t;
typedef std::map<std::string, DCDB::IPMISensor*> sensorMap_t;
typedef std::map<std::string, DCDB::IPMIHost*> hostMap_t;
typedef struct {
uint32_t sessionTimeout;
uint32_t retransmissionTimeout;
......@@ -57,14 +58,25 @@ namespace DCDB {
* Set the variables of sensor according to the values specified in config.
* @param sensor The sensor to be configured
* @param config A property(sub)tree containing the values
* @param isTemplate The property tree contains a sensor template
*
* @return True on success, false otherwise
*/
bool readSensor(IPMISensor& sensor, boost::property_tree::iptree& config, bool isTemplate);
bool readSensor(IPMISensor *sensor, boost::property_tree::iptree& config);
/**
* Set the variables of host according to the values specified in config.
* @param host The host to be configured
* @param config A property(sub)tree containing the values
* @param isTemplate The property tree contains a host template
*
* @return True on success, false otherwise
*/
bool readHost(DCDB::IPMIHost *host, boost::property_tree::iptree& config, bool isTemplate);
std::string _tempdir;
sensorMap_t _templateSensors;
hostMap_t _templateHosts;
hostList_t _hosts;
globalHost_t _globalHost;
};
......
......@@ -42,6 +42,10 @@ IPMIHost::IPMIHost(const std::string& hostName, uint32_t retransmissionTimeout,
_lastRead = 0;
}
IPMIHost::IPMIHost(const IPMIHost &ipmiHost) {
*this = ipmiHost;
}
IPMIHost::~IPMIHost() {
if (_strand) {
delete _strand;
......@@ -89,7 +93,7 @@ void IPMIHost::checkConnection() {
if (_ipmiCtx) {
uint64_t ts = getTimestamp();
if ((ts - _lastRead) > MS_TO_NS(_sessionTimeout)) {
LOG(debug) << "Last read was " << NS_TO_MS((ts - _lastRead)) << "ms ago, timeout is " << _sessionTimeout << "ms. Disconnecting.";
LOG(debug) << _hostName << ": Last read was " << NS_TO_MS((ts - _lastRead)) << "ms ago, timeout is " << _sessionTimeout << "ms. Disconnecting.";
disconnect();
}
}
......@@ -131,7 +135,7 @@ bool IPMIHost::openSdrCache() {
ipmi_sdr_cache_delete(_sdrCtx, _cache.c_str());
}
if (ipmi_sdr_cache_create(_sdrCtx, _ipmiCtx, _cache.c_str(), IPMI_SDR_CACHE_CREATE_FLAGS_DEFAULT, NULL, NULL) == 0) {
LOG(debug) << "Created new SDR cache " << _cache;
LOG(debug) << _hostName << ": Created new SDR cache " << _cache;
ipmi_sdr_cache_open(_sdrCtx, _ipmiCtx, _cache.c_str());
}
}
......@@ -265,10 +269,11 @@ double IPMIHost::readSensorRecord(std::vector<uint8_t>& record) {
if (reading) {
_errorCount = 0;
_lastRead = getTimestamp();
ret = *reading;
free(reading);
}
return ret;
}
void IPMIHost::increaseErrorCount() {
......
......@@ -9,6 +9,7 @@
#define IPMIHOST_H_
#include "../../Logging.h"
#include "IPMISensor.h"
#include <string>
#include <list>
......@@ -20,6 +21,7 @@ namespace DCDB {
class IPMIHost {
public:
IPMIHost(const std::string& hostName, uint32_t retransmissionTimeout, uint32_t sessionTimeout);
IPMIHost(const IPMIHost &ipmiHost);
virtual ~IPMIHost();
/* Send raw command to BMC. Returns sensor reading as responded by BMC. */
......@@ -107,6 +109,18 @@ namespace DCDB {
void setDelayNextReadUntil(uint64_t delayNextReadUntil) {
_delayNextReadUntil = delayNextReadUntil;
}
std::list<DCDB::IPMISensor*> getSensors() {
return _sensors;
}
void addSensor(DCDB::IPMISensor* ipmiSensor) {
_sensors.push_back(ipmiSensor);
}
void clearSensors() {
_sensors.clear();
}
private:
/* Open/close connection to BMC (sets/destroys _ipmiCtx) */
......@@ -137,6 +151,7 @@ namespace DCDB {
uint32_t _errorCount;
volatile uint64_t _delayNextReadUntil;
uint64_t _lastRead;
std::list<DCDB::IPMISensor*> _sensors;
};
} /* namespace DCDB */
......
......@@ -30,6 +30,12 @@ namespace DCDB {
_host = NULL;
}
IPMISensor::IPMISensor(const IPMISensor &ipmiSensor) :
Sensor(ipmiSensor.getName()) {
*this = ipmiSensor;
LOG(debug) << "IPMISensor::IPMISensor(): " << ipmiSensor.getName();
}
IPMISensor::~IPMISensor() {
// TODO Auto-generated destructor stub
}
......
......@@ -18,6 +18,8 @@ namespace DCDB {
class IPMISensor : public Sensor {
public:
IPMISensor(const std::string& name);
IPMISensor(const IPMISensor &ipmiSensor);
virtual ~IPMISensor();
void setRawCmd(std::string& rawCmd);
......
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