Commit 1b2b109a authored by Micha Müller's avatar Micha Müller
Browse files

Pusher: Refactor ConfiguratorTemplate once again. Replace partial template...

Pusher: Refactor ConfiguratorTemplate once again. Replace partial template specialization with derived ConfiguratorTemplate for entities
parent 421dcf37
This diff is collapsed.
//================================================================================
// Name : ConfiguratorTemplateEntity.h
// Author : Micha Mueller
// Contact : info@dcdb.it
// Copyright : Leibniz Supercomputing Centre
// Description : Interface template for plugin configurators with entities.
//================================================================================
//================================================================================
// This file is part of DCDB (DataCenter DataBase)
// Copyright (C) 2019-2019 Leibniz Supercomputing Centre
//
// 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 DCDBPUSHER_INCLUDES_CONFIGURATORTEMPLATEENTITY_H_
#define DCDBPUSHER_INCLUDES_CONFIGURATORTEMPLATEENTITY_H_
#include "ConfiguratorTemplate.h"
#include "EntityInterface.h"
/**
* @brief Interface template for plugin configurator implementations with
* entities.
*
* @details Inherits from the ConfiguratorTemplate class and extends it for
* entity support
*
* @ingroup pusherplugins
*/
template <class SBase, class SGroup, class SEntity>
class ConfiguratorTemplateEntity : public ConfiguratorTemplate<SBase, SGroup> {
//the template shall only be instantiated for entities which derive from EntityInterface
static_assert(std::is_base_of<EntityInterface, SEntity>::value, "SEntity must derive from EntityInterface!");
protected:
//mention all required parent attributes and functions here to avoid compiler errors
using ConfiguratorInterface::_cfgPath;
using ConfiguratorInterface::_mqttPrefix;
using ConfiguratorInterface::lg;
using ConfiguratorInterface::readGlobal;
using ConfiguratorTemplate<SBase, SGroup>::_baseName;
using ConfiguratorTemplate<SBase, SGroup>::_groupName;
using ConfiguratorTemplate<SBase, SGroup>::_sensorGroups;
using ConfiguratorTemplate<SBase, SGroup>::_templateSensorBases;
using ConfiguratorTemplate<SBase, SGroup>::_templateSensorGroups;
using ConfiguratorTemplate<SBase, SGroup>::readSensorBase;
using ConfiguratorTemplate<SBase, SGroup>::readSensorGroup;
using ConfiguratorTemplate<SBase, SGroup>::storeSensorGroup;
//TODO use smart pointers
typedef std::map<std::string, SEntity *> sEntityMap_t;
using SB_Ptr = std::shared_ptr<SBase>;
using SG_Ptr = std::shared_ptr<SGroup>;
public:
ConfiguratorTemplateEntity()
: ConfiguratorTemplate<SBase, SGroup>(),
_entityName("INVALID") {}
virtual ~ConfiguratorTemplateEntity() {
for (auto e : _sensorEntitys) {
delete e;
}
for (auto te : _templateSensorEntitys) {
delete te.second;
}
// SensorGroups must be cleared before Entities
_sensorGroups.clear();
_sensorEntitys.clear();
_templateSensorEntitys.clear();
}
/**
* @brief Read in the given configuration
*
* @details Overwriting this method is only required if a custom logic is really necessary!
*
* @param cfgPath Path to the config-file
*
* @return True on success, false otherwise
*/
bool readConfig(std::string cfgPath) override {
_cfgPath = cfgPath;
boost::property_tree::iptree cfg;
boost::property_tree::read_info(cfgPath, cfg);
//read global variables (if present overwrite those from global.conf)
readGlobal(cfg);
//read groups and templates for groups. If present also entity/-template stuff
BOOST_FOREACH (boost::property_tree::iptree::value_type &val, cfg) {
//template entity
if (boost::iequals(val.first, "template_" + _entityName)) {
LOG(debug) << "Template " << _entityName << " \"" << val.second.data() << "\"";
if (!val.second.empty()) {
//name of an entity is only used to identify templates and is not stored otherwise
SEntity *entity = new SEntity(val.second.data());
if (readSensorEntity(*entity, val.second, true)) {
auto ret = _templateSensorEntitys.insert(std::pair<std::string, SEntity *>(val.second.data(), entity));
if (!ret.second) {
LOG(warning) << "Template " << _entityName << " "
<< val.second.data() << " already exists! Omitting...";
delete entity;
}
} else {
LOG(warning) << "Template " << _entityName << " \""
<< val.second.data() << "\" has bad values! Ignoring...";
delete entity;
}
}
//template group
} else if (boost::iequals(val.first, "template_" + _groupName)) {
LOG(debug) << "Template " << _groupName << " \"" << val.second.data() << "\"";
if (!val.second.empty()) {
SGroup *group = new SGroup(val.second.data());
if (readSensorGroup(*group, val.second, true)) {
auto ret = _templateSensorGroups.insert(std::pair<std::string, SGroup *>(val.second.data(), group));
if (!ret.second) {
LOG(warning) << "Template " << _groupName << " "
<< val.second.data() << " already exists! Omitting...";
delete group;
}
} else {
LOG(warning) << "Template " << _groupName << " \""
<< val.second.data() << "\" has bad values! Ignoring...";
delete group;
}
}
//template base
} else if (boost::iequals(val.first, "template_" + _baseName)) {
LOG(debug) << "Template " << _baseName << " \"" << val.second.data() << "\"";
if (!val.second.empty()) {
SBase *base = new SBase(val.second.data());
if (readSensorBase(*base, val.second, true)) {
auto ret = _templateSensorBases.insert(std::pair<std::string, SBase *>(val.second.data(), base));
if (!ret.second) {
LOG(warning) << "Template " << _baseName << " "
<< val.second.data() << " already exists! Omitting...";
delete base;
}
} else {
LOG(warning) << "Template " << _baseName << " \""
<< val.second.data() << "\" has bad values! Ignoring...";
delete base;
}
}
//template single sensor
} else if (boost::iequals(val.first, "template_single_" + _baseName)) {
LOG(debug) << "Template single " << _baseName << " \"" << val.second.data() << "\"";
if (!val.second.empty()) {
SGroup *group = new SGroup(val.second.data());
if (readSensorGroup(*group, val.second, true)) {
//group which consists of only one sensor
SB_Ptr sensor = std::make_shared<SBase>(val.second.data());
if (readSensorBase(*sensor, val.second, true)) {
group->pushBackSensor(sensor);
auto ret = _templateSensorGroups.insert(std::pair<std::string, SGroup *>(val.second.data(), group));
if (!ret.second) {
LOG(warning) << "Template single " << _baseName << " "
<< val.second.data() << " already exists! Omitting...";
delete group;
}
} else {
LOG(warning) << "Template single " << _baseName << " "
<< val.second.data() << " could not be read! Omitting";
delete group;
}
} else {
LOG(warning) << "Template single " << _baseName << " \""
<< val.second.data() << "\" has bad values! Ignoring...";
delete group;
}
}
//entity
} else if (boost::iequals(val.first, _entityName)) {
LOG(debug) << _entityName << " \"" << val.second.data() << "\"";
if (!val.second.empty()) {
SEntity *entity = new SEntity(val.second.data());
if (readSensorEntity(*entity, val.second)) {
_sensorEntitys.push_back(entity);
} else {
LOG(warning) << _entityName << " \""
<< val.second.data() << "\" has bad values! Ignoring...";
delete entity;
}
}
//group
} else if (boost::iequals(val.first, _groupName)) {
LOG(debug) << _groupName << " \"" << val.second.data() << "\"";
if (!val.second.empty()) {
SG_Ptr group = std::make_shared<SGroup>(val.second.data());
if (readSensorGroup(*group, val.second)) {
storeSensorGroup(group);
} else {
LOG(warning) << _groupName << " \""
<< val.second.data() << "\" has bad values! Ignoring...";
}
}
//single sensor
} else if (boost::iequals(val.first, "single_" + _baseName)) {
LOG(debug) << "Single " << _baseName << " \"" << val.second.data() << "\"";
if (!val.second.empty()) {
SG_Ptr group = std::make_shared<SGroup>(val.second.data());
if (readSensorGroup(*group, val.second)) {
//group which consists of only one sensor
SB_Ptr sensor;
//perhaps one sensor is already present because it was copied from the template group
if (group->acquireSensors().size() != 0) {
group->releaseSensors();
sensor = std::dynamic_pointer_cast<SBase>(group->acquireSensors()[0]);
group->releaseSensors();
//check if cast was successful (sensor != nullptr)
if (sensor) {
sensor->setName(val.second.data());
if (readSensorBase(*sensor, val.second)) {
storeSensorGroup(group);
} else {
LOG(warning) << "Single " << _baseName << " "
<< val.second.data() << " could not be read! Omitting";
}
} else {
LOG(warning) << "Single " << _baseName << " "
<< val.second.data() << " had a type mismatch when casting! Omitting";
}
} else {
group->releaseSensors();
sensor = std::make_shared<SBase>(val.second.data());
if (readSensorBase(*sensor, val.second)) {
group->pushBackSensor(sensor);
storeSensorGroup(group);
} else {
LOG(warning) << "Single " << _baseName << " "
<< val.second.data() << " could not be read! Omitting";
}
}
} else {
LOG(warning) << "Single " << _baseName << " \""
<< val.second.data() << "\" has bad values! Ignoring...";
}
}
} else if (!boost::iequals(val.first, "global")) {
LOG(error) << "\"" << val.first << "\": unknown construct!";
return false;
}
}
//read of config finished. Now we build the mqtt-topic for every sensor
return constructSensorTopics();
}
/**
* @brief Clear internal storage and return plugin in unconfigured state.
*/
void clearConfig() final override {
ConfiguratorTemplate<SBase, SGroup>::clearConfig();
//clean up remaining entity stuff
for (auto e : _sensorEntitys) {
delete e;
}
for (auto te : _templateSensorEntitys) {
delete te.second;
}
_sensorEntitys.clear();
_templateSensorEntitys.clear();
}
/**
* @brief Print configuration.
*
* @param ll Log severity level to be used from logger.
*/
void printConfig(LOG_LEVEL ll) final override {
ConfiguratorInterface::printConfig(ll);
//prints plugin specific configurator attributes and entities if present
this->printConfiguratorConfig(ll);
LOG_VAR(ll) << " " << _entityName << "s:";
if (_sensorEntitys.size() != 0) {
for (auto e : _sensorEntitys) {
e->printConfig(ll, 8);
LOG_VAR(ll) << " Sensor Groups:";
for (auto g : _sensorGroups) {
if (g->getEntity() == e) {
g->printConfig(ll, 16);
}
}
}
} else {
LOG_VAR(ll) << " No " << _entityName << "s present!";
}
}
protected:
///@name Template-internal use only
///@{
/**
* @brief Read common values of a sensor entity.
*
* @details Reads and sets the common base values of a sensor entity
* (currently none), then calls sensorEntity() to read plugin
* specific values.
*
* @param sEntity The aggregating entity for which to set the values.
* @param config A boost property (sub-)tree containing the values.
* @param isTemplate Indicate if sEntity is a template. If so, also store
* the corresponding sGroups in the template map.
*
* @return True on success, false otherwise
*/
bool readSensorEntity(SEntity &sEntity, CFG_VAL config, bool isTemplate = false) {
//first check if default entity is given
boost::optional<boost::property_tree::iptree &> def = config.get_child_optional("default");
if (def) {
//we copy all values from default
LOG(debug) << " Using \"" << def.get().data() << "\" as default.";
auto it = _templateSensorEntitys.find(def.get().data());
if (it != _templateSensorEntitys.end()) {
sEntity = *(it->second);
sEntity.setName(config.data());
for (auto g : _templateSensorGroups) {
if (it->second == g.second->getEntity()) {
SG_Ptr group = std::make_shared<SGroup>(*(g.second));
group->setEntity(&sEntity);
if (group->getGroupName().size() > 0) {
group->setGroupName(sEntity.getName() + "::" + group->getGroupName());
} else {
group->setGroupName(sEntity.getName());
}
storeSensorGroup(group);
}
}
} else {
LOG(warning) << "Template " << _entityName << "\""
<< def.get().data() << "\" not found! Using standard values.";
}
}
//read in values inherited from EntityInterface
BOOST_FOREACH (boost::property_tree::iptree::value_type &val, config) {
if (boost::iequals(val.first, "mqttPart")) {
sEntity.setMqttPart(val.second.data());
} else if (boost::iequals(val.first, "disabled")) {
sEntity.setDisabled(to_bool(val.second.data()));
}
}
sensorEntity(sEntity, config);
BOOST_FOREACH (boost::property_tree::iptree::value_type &val, config) {
if (boost::iequals(val.first, _groupName)) {
LOG(debug) << " " << _groupName << " " << val.second.data();
if (!val.second.empty()) {
if (isTemplate) {
SGroup *group = new SGroup(val.second.data());
if (readSensorGroup(*group, val.second)) {
group->setEntity(&sEntity);
auto ret = _templateSensorGroups.insert(std::pair<std::string, SGroup *>(sEntity.getName() + "::" + group->getGroupName(), group));
if (!ret.second) {
LOG(warning) << "Template " << _groupName << " "
<< sEntity.getName() + "::" + group->getGroupName() << " already exists! Omitting...";
delete group;
}
} else {
LOG(warning) << _groupName << " " << group->getGroupName()
<< " could not be read! Omitting";
delete group;
}
} else {
SG_Ptr group = std::make_shared<SGroup>(val.second.data());
if (readSensorGroup(*group, val.second)) {
group->setEntity(&sEntity);
if (group->getGroupName().size() > 0) {
group->setGroupName(sEntity.getName() + "::" + group->getGroupName());
} else {
group->setGroupName(sEntity.getName());
}
storeSensorGroup(group);
} else {
LOG(warning) << _groupName << " " << group->getGroupName()
<< " could not be read! Omitting";
}
}
}
} else if (boost::iequals(val.first, "single_" + _baseName)) {
LOG(debug) << "Single " << _baseName << " \"" << val.second.data() << "\"";
if (!val.second.empty()) {
if (isTemplate) {
SGroup *group = new SGroup(val.second.data());
//group which consists of only one sensor
if (readSensorGroup(*group, val.second)) {
group->setEntity(&sEntity);
SB_Ptr sensor = std::make_shared<SBase>(val.second.data());
if (readSensorBase(*sensor, val.second)) {
group->pushBackSensor(sensor);
auto ret = _templateSensorGroups.insert(std::pair<std::string, SGroup *>(val.second.data(), group));
if (!ret.second) {
LOG(warning) << "Template single " << _baseName << " "
<< val.second.data() << " already exists! Omitting...";
delete group;
}
} else {
LOG(warning) << "Template single " << _baseName << " "
<< val.second.data() << " could not be read! Omitting";
delete group;
}
} else {
LOG(warning) << "Single " << _baseName << " \""
<< val.second.data() << "\" has bad values! Ignoring...";
delete group;
}
} else {
SG_Ptr group = std::make_shared<SGroup>(val.second.data());
//group which consists of only one sensor
if (readSensorGroup(*group, val.second)) {
group->setEntity(&sEntity);
SB_Ptr sensor;
//perhaps one sensor is already present because it was copied from the template group
if (group->acquireSensors().size() != 0) {
group->releaseSensors();
sensor = std::dynamic_pointer_cast<SBase>(group->acquireSensors()[0]);
group->releaseSensors();
//check if cast was successful (sensor != nullptr)
if (sensor) {
sensor->setName(val.second.data());
if (readSensorBase(*sensor, val.second)) {
storeSensorGroup(group);
} else {
LOG(warning) << "Single " << _baseName << " "
<< val.second.data() << " could not be read! Omitting";
}
} else {
LOG(warning) << "Single " << _baseName << " "
<< val.second.data() << " had a type mismatch when casting! Omitting";
}
} else {
group->releaseSensors();
sensor = std::make_shared<SBase>(val.second.data());
if (readSensorBase(*sensor, val.second)) {
group->pushBackSensor(sensor);
storeSensorGroup(group);
} else {
LOG(warning) << "Single " << _baseName << " "
<< val.second.data() << " could not be read! Omitting";
}
}
} else {
LOG(warning) << "Single " << _baseName << " \""
<< val.second.data() << "\" has bad values! Ignoring...";
}
}
}
}
}
return true;
}
///@}
///@name Overwrite in plugin
///@{
/**
* Method responsible for reading plugin-specific sensor entity values.
*
* @param s The sensor entity for which to set the values
* @param config A boost property (sub-)tree containing the entity values
*/
virtual void sensorEntity(SEntity &s, CFG_VAL config) = 0;
///@}
///@name Utility
///@{
/**
* @brief Adjusts the names of the sensors in generated groups.
*
* @return True if successful, false otherwise.
*/
virtual bool constructSensorTopics() final override {
// Sensor names are adjusted according to the respective MQTT topics
for (auto &g : _sensorGroups) {
for (auto &s : g->acquireSensors()) {
s->setMqtt(MQTTChecker::formatTopic(_mqttPrefix) +
MQTTChecker::formatTopic(g->getEntity()->getMqttPart()) +
MQTTChecker::formatTopic(g->getMqttPart()) +
MQTTChecker::formatTopic(s->getMqtt()));
s->setName(s->getMqtt());
SensorMetadata *sm = s->getMetadata();
if (sm) {
sm->publicName = s->getMqtt();
sm->pattern = s->getMqtt();
sm->isVirtual = false;
if (sm->interval == 0)
sm->interval = (unsigned long long)g->getInterval() * 1000000;
}
}
g->releaseSensors();
}
return true;
}
///@}
std::string _entityName;
std::vector<SEntity *> _sensorEntitys;
sEntityMap_t _templateSensorEntitys;
};
#endif /* DCDBPUSHER_INCLUDES_CONFIGURATORTEMPLATEENTITY_H_ */
......@@ -33,9 +33,15 @@ cat << EOF > ${PLUGIN_NAME}Configurator.h
#ifndef ${PLUGIN_NAME_UPC}_${PLUGIN_NAME_UPC}CONFIGURATOR_H_
#define ${PLUGIN_NAME_UPC}_${PLUGIN_NAME_UPC}CONFIGURATOR_H_
#include "../../includes/ConfiguratorTemplate.h"
#include "${PLUGIN_NAME}SensorGroup.h"
EOF
if [ "$enableEntities" = true ]
then
echo "#include \"../../includes/ConfiguratorTemplateEntity.h\"" >> ${PLUGIN_NAME}Configurator.h
else
echo "#include \"../../includes/ConfiguratorTemplate.h\"" >> ${PLUGIN_NAME}Configurator.h
fi
echo "#include \"${PLUGIN_NAME}SensorGroup.h\"" >> ${PLUGIN_NAME}Configurator.h
if [ "$enableEntities" = true ]
then
......@@ -53,7 +59,7 @@ EOF
if [ "$enableEntities" = true ]
then
echo "class ${PLUGIN_NAME}Configurator : public ConfiguratorTemplate<${PLUGIN_NAME}SensorBase, ${PLUGIN_NAME}SensorGroup, ${PLUGIN_NAME}${ENTITY_NAME}> {" >> ${PLUGIN_NAME}Configurator.h
echo "class ${PLUGIN_NAME}Configurator : public ConfiguratorTemplateEntity<${PLUGIN_NAME}SensorBase, ${PLUGIN_NAME}SensorGroup, ${PLUGIN_NAME}${ENTITY_NAME}> {" >> ${PLUGIN_NAME}Configurator.h
else
echo "class ${PLUGIN_NAME}Configurator : public ConfiguratorTemplate<${PLUGIN_NAME}SensorBase, ${PLUGIN_NAME}SensorGroup> {" >> ${PLUGIN_NAME}Configurator.h
fi
......
......@@ -19,9 +19,9 @@ while getopts "hp:e:a:" opt; do
echo "Usage:"
echo "./generatePlugin.sh -p pluginName"
echo "Options:"
echo "-h\tPrint this help section"
echo "-e xx\tGenerate files for entity"
echo "-a xx\tSpecify name of the author which is to be mentioned in the"
echo "-h Print this help section"
echo "-e xx Generate files for entity"
echo "-a xx Specify name of the author which is to be mentioned in the"
echo "\tsource files"
exit 0
;;
......
......@@ -44,7 +44,7 @@ IPMIConfigurator::IPMIConfigurator() {
IPMIConfigurator::~IPMIConfigurator() {}
bool IPMIConfigurator::readConfig(std::string cfgPath) {
if (ConfiguratorTemplate<IPMISensorBase, IPMISensorGroup, IPMIHost>::readConfig(cfgPath)) {
if (ConfiguratorTemplateEntity<IPMISensorBase, IPMISensorGroup, IPMIHost>::readConfig(cfgPath)) {
for (auto &g : _sensorGroups) {
if (!g->checkConfig()) {
return false;
......
......@@ -28,7 +28,7 @@
#ifndef IPMICONFIGURATOR_H_
#define IPMICONFIGURATOR_H_