Starting from 2021-07-01, all LRZ GitLab users will be required to explicitly accept the GitLab Terms of Service. Please see the detailed information at https://doku.lrz.de/display/PUBLIC/GitLab and make sure that your projects conform to the requirements.

Commit 81aa7087 authored by Alessio Netti's avatar Alessio Netti
Browse files

Code streamlining pt.II

- Removed dependencies from data analytics framework to dcdbpusher
- Checks for correctness of MQTT topics moved to the mqttChecker shared class
parent 9b468ff6
......@@ -34,6 +34,8 @@ bool AnalyticsManager::load(const string& path, const string& globalFile, const
return true;
}
MQTTChecker& mqttCheck = MQTTChecker::getInstance();
//Reading plugins
BOOST_FOREACH(boost::property_tree::iptree::value_type &plugin, cfg.get_child("analyzerPlugins")) {
if (boost::iequals(plugin.first, "analyzerPlugin")) {
if (!plugin.second.empty()) {
......@@ -106,6 +108,15 @@ bool AnalyticsManager::load(const string& path, const string& globalFile, const
// Returning an empty vector may indicate problems with the config file
if(dynLib.configurator->getAnalyzers().size() == 0) {
LOG(warning) << "Plugin \"" << dynLib.id << "\" created no analyzers!";
} else {
for(const auto& a : dynLib.configurator->getAnalyzers())
if( a->getStreaming() )
for(const auto& u : a->getUnits())
for(const auto& o: u->getBaseOutputs())
if(!mqttCheck.check(o->getMqtt())) {
LOG(error) << "Problematic MQTT-Topics, please check your config files!";
return false;
}
}
//save dl-struct
_plugins.push_back(dynLib);
......@@ -120,45 +131,6 @@ bool AnalyticsManager::load(const string& path, const string& globalFile, const
return true;
}
//TODO: when textual MQTT topics are in place, implement check method that ensures all sensors, groups, analyzers and entities have distinct names
bool AnalyticsManager::mqttCheck(pluginVector_t& pushers) {
if(_status != LOADED) {
LOG(error) << "Cannot perform MQTT check, AnalyticsManager is not loaded!";
return false;
}
std::set<std::string> _mqttTopics;
// Initializing set with topics from pusher sensors
for(const auto& p : pushers)
for(const auto& g : p.configurator->getSensorGroups())
for(const auto& s : g->getSensors())
_mqttTopics.insert(s->getMqtt());
// Check if an MQTT-suffix was assigned twice and if it is correctly formatted
for(const auto& p : _plugins)
for(const auto& a : p.configurator->getAnalyzers())
if( a->getStreaming() )
for(const auto& u : a->getUnits())
for(const auto& o: u->getBaseOutputs()) {
std::string str(o->getMqtt());
str.erase(std::remove(str.begin(), str.end(), '/'), str.end());
if (str.length() != 28) {
LOG(error) << "MQTT-Topic \"" << o->getMqtt() << "\" contains " << str.length() << " hex characters, not 28 as required!";
return false;
}
auto returnIt = _mqttTopics.insert(str);
if (!returnIt.second) {
LOG(error) << "MQTT-Topic \"" << o->getMqtt() << "\" used twice!";
return false;
}
}
_mqttTopics.clear();
return true;
}
bool AnalyticsManager::init(boost::asio::io_service& io, const string& plugin) {
if(_status != LOADED) {
LOG(error) << "Cannot init, AnalyticsManager is not loaded!";
......
......@@ -13,15 +13,13 @@
#include <boost/algorithm/string.hpp>
#include <boost/asio.hpp>
#include <dlfcn.h>
#include "logging.h"
#include "mqttchecker.h"
#include "includes/UnitInterface.h"
#include "includes/AnalyzerConfiguratorInterface.h"
#include "logging.h"
#include "../dcdbpusher/includes/PluginDefinitions.h"
using namespace std;
// Struct of values required to load analyzer dynamic libraries.
typedef struct {
std::string id;
......@@ -149,17 +147,6 @@ public:
*/
std::vector<an_dl_t>& getPlugins() { return _plugins; }
/**
* @brief Ensures that the MQTT topics of ths analyzer's sensors are consistent
*
* The method verifies that no two sensors from analyzer plugins overlap, and that this does not
* happen for sensors (as supplied with the pluginVector input argument) as well.
*
* @param pushers Vector of pusher plugins represented as dl_t structures
* @return True if check was successful, False otherwise
*/
bool mqttCheck(pluginVector_t& pushers);
// String used as a response for the REST GET /help command
const string restCheatSheet = "dcdbpusher analytics RESTful API cheatsheet:\n"
" -GET: /analytics/plugins List of currently loaded plugins (Discovery)\n"
......
......@@ -24,7 +24,7 @@ debug: all
clean:
rm -f $(ANALYZER_LIBS) $(shell find . -name "*.o")
rm -f "../common/src/sensornavigator.o"
rm -f ../common/src/sensornavigator.o
$(OBJS) : %.o : %.cpp
......
......@@ -10,7 +10,7 @@
#include "QueryEngine.h"
#include "AnalyzerInterface.h"
#include "../../dcdbpusher/includes/ConfiguratorInterface.h"
#include "pluginsettings.h"
/**
* Interface to configurators for data analyzer plugins
......@@ -59,7 +59,7 @@ public:
* method must be implemented in derived classes.
*
*
* @param pluginSettings A structure of plugin settings (see ConfiguratorInterface.h)
* @param pluginSettings A structure of plugin settings (see pluginsettings.h)
*/
virtual void setGlobalSettings(const pluginSettings_t& pluginSettings) = 0;
......
//
// Created by Netti, Alessio on 07.03.19.
//
#ifndef PROJECT_MQTTCHECKER_H
#define PROJECT_MQTTCHECKER_H
#include <set>
#include "logging.h"
/**
* Class that manages constraint for MQTT topic formatting
*
* This class is implemented as a singleton. It maintains an internal set containing the currently used MQTT topics.
* Each used sensor topic should be checked with the "check" method.
*/
class MQTTChecker {
public:
/**
* @brief Returns an instance to a MQTTChecker object
*
* The MQTTChecker class is implemented as a singleton: therefore, all entities calling the
* getInstance method will share the same instance of the MQTTChecker class.
*
* @returns Reference to a MQTTChecker object
*/
static MQTTChecker& getInstance() {
static MQTTChecker m;
return m;
}
/**
* @brief Resets the internal topics set
*/
void reset() { _topics.clear(); }
//TODO: when textual MQTT topics are in place, implement check method that ensures all sensors, groups, analyzers and entities have distinct names
/**
* @brief Performs a check on a certain MQTT topic
*
* The check is passed if the topic is not present already in the internal set (to prevent duplicate
* topics) and if all other internal checks are cleared.
*
* @param topic An arbitrary MQTT topic to check
* @return True if the topic is valid, False otherwise
*/
bool check(const std::string& topic) {
//MQTT topic must have 112 bit = 14 bytes = 28 hex chars
//but can have more with some extra '/', therefore remove all '/'
std::string str(topic);
str.erase(std::remove(str.begin(), str.end(), '/'), str.end());
if (str.length() != 28) {
LOG(error) << "MQTT-Topic \"" << topic << "\" contains " << str.length() << " hex characters, not 28 as required!";
return false;
}
auto returnIt = _topics.insert(str);
if (!returnIt.second) {
LOG(error) << "MQTT-Topic \"" << topic << "\" used twice!";
return false;
}
return true;
}
private:
/**
* @brief Private class constructor
*/
MQTTChecker() {}
/**
* @brief Copy constructor is not available
*/
MQTTChecker(MQTTChecker const&) = delete;
/**
* @brief Assignment operator is not available
*/
void operator=(MQTTChecker const&) = delete;
// Set used to keep track of topics
std::set<std::string> _topics;
// Logger object to notify MQTT check outcome
logger_t lg;
};
#endif //PROJECT_MQTTCHECKER_H
//
// Created by Netti, Alessio on 07.03.19.
//
#ifndef PROJECT_PLUGINSETTINGS_H
#define PROJECT_PLUGINSETTINGS_H
typedef struct {
std::string sensorPattern;
std::string mqttPrefix;
std::string tempdir;
unsigned int cacheInterval;
} pluginSettings_t;
#endif //PROJECT_PLUGINSETTINGS_H
......@@ -212,6 +212,7 @@ bool Configuration::readPlugins() {
return false;
}
MQTTChecker& mqttCheck = MQTTChecker::getInstance();
//read plugins
BOOST_FOREACH(boost::property_tree::iptree::value_type &plugin, cfg.get_child("plugins")) {
if (boost::iequals(plugin.first, "plugin")) {
......@@ -297,9 +298,9 @@ bool Configuration::readPlugins() {
//check if an MQTT-suffix was assigned twice
for(const auto& g : dynLib.configurator->getSensorGroups()) {
for(const auto& s : g->getSensors()) {
bool ok = checkMqtt(s->getMqtt());
bool ok = mqttCheck.check(s->getMqtt());
if(!ok) {
LOG(error) << "Problematic MQTT-Topics! Please check your config files";
LOG(error) << "Problematic MQTT-Topics, please check your config files!";
return false;
}
}
......@@ -343,25 +344,6 @@ boost::log::trivial::severity_level Configuration::translateLogLevel(int logLeve
}
}
bool Configuration::checkMqtt(const std::string& mqtt) {
//MQTT topic must have 112 bit = 14 bytes = 28 hex chars
//but can have more with some extra '/', therefore remove all '/'
std::string str(mqtt);
str.erase(std::remove(str.begin(), str.end(), '/'), str.end());
if (str.length() != 28) {
LOG(error) << "MQTT-Topic \"" << mqtt << "\" contains " << str.length() << " hex characters, not 28 as required!";
return false;
}
auto returnIt = _mqttTopics.insert(str);
if (!returnIt.second) {
LOG(error) << "MQTT-Topic \"" << mqtt << "\" used twice!";
return false;
}
return true;
}
global_t& Configuration::getGlobal() {
return _global;
}
......
......@@ -14,6 +14,7 @@
#include <boost/property_tree/ptree.hpp>
#include <boost/log/trivial.hpp>
#include "includes/PluginDefinitions.h"
#include "mqttchecker.h"
typedef struct {
bool validateConfig;
......@@ -89,14 +90,6 @@ public:
*/
boost::log::trivial::severity_level translateLogLevel(int logLevel);
/**
* Check if the mqtt-suffix is already in use.
* @param mqtt The MQTT-suffix to check
* @return True if the suffix is still available, false if already used
*/
bool checkMqtt(const std::string& mqtt);
/*
* Return global settings
*/
......
......@@ -391,8 +391,7 @@ int main(int argc, char** argv) {
_queryEngine.triggerUpdate();
_queryEngine.setQueryCallback(sensorQueryCallback);
if(!_analyticsManager->load(argv[argc-1], "global.conf", pluginSettings) ||
!_analyticsManager->mqttCheck(_configuration->getPlugins())) {
if(!_analyticsManager->load(argv[argc-1], "global.conf", pluginSettings)) {
LOG(fatal) << "Failed to load data analytics manager!";
return 1;
}
......
......@@ -11,15 +11,9 @@
#include <string>
#include <vector>
#include "pluginsettings.h"
#include "SensorGroupTemplate.h"
typedef struct {
std::string sensorPattern;
std::string mqttPrefix;
std::string tempdir;
unsigned int cacheInterval;
} pluginSettings_t;
/**
* Abstract interface which defines the functionality of a configurator
*/
......
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