AnalyticsManager.cpp 8.84 KB
Newer Older
Alessio Netti's avatar
Alessio Netti committed
1
2
3
4
5
6
7
8
9
10
//
// Created by Netti, Alessio on 10.12.18.
//

#include "AnalyticsManager.h"

void AnalyticsManager::clear() {
    for(const auto& p : _plugins)
        p.destroy(p.configurator);
    _plugins.clear();
Alessio Netti's avatar
Alessio Netti committed
11
    _status = CLEAR;
Alessio Netti's avatar
Alessio Netti committed
12
13
14
15
16
17
18
}

bool AnalyticsManager::load(const string& path, const string& globalFile, const pluginSettings_t& pluginSettings) {
    //The load code is pretty much the same as in Configuration.cpp to load pusher plugins
    _configPath = path;
    _pluginSettings = pluginSettings;
    boost::property_tree::iptree cfg;
19
20
21
22

    if (_configPath != "" && _configPath[_configPath.length()-1] != '/')
        _configPath.append("/");

Alessio Netti's avatar
Alessio Netti committed
23
    try {
24
        boost::property_tree::read_info(_configPath + globalFile, cfg);
Alessio Netti's avatar
Alessio Netti committed
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
    } catch (boost::property_tree::info_parser_error& e) {
        LOG(error) << "Error when reading analyzer plugins from global.conf: " << e.what();
        return false;
    }

    BOOST_FOREACH(boost::property_tree::iptree::value_type &plugin, cfg.get_child("analyzerPlugins")) {
        if (boost::iequals(plugin.first, "analyzerPlugin")) {
            if (!plugin.second.empty()) {
                LOG(info) << "Loading analyzer plugin \"" << plugin.second.data() << "\"...";
                std::string pluginConfig; //path to config file for plugin
                std::string pluginLib = "libdcdbanalyzer_" + plugin.second.data();
#if __APPLE__
                pluginLib+= ".dylib";
#else
                pluginLib+= ".so";
#endif
                BOOST_FOREACH(boost::property_tree::iptree::value_type &val, plugin.second) {
                    if (boost::iequals(val.first, "path")) {
43
                        std::string iPath = val.second.data();
Alessio Netti's avatar
Alessio Netti committed
44
                        // If path not specified we will look up in the default lib-directories (usr/lib and friends)
45
46
47
48
                        if (iPath != "") {
                            if (iPath[iPath.length()-1] != '/')
                                iPath.append("/");
                            pluginLib = iPath + pluginLib;
Alessio Netti's avatar
Alessio Netti committed
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
                        }
                    } else if (boost::iequals(val.first, "config")) {
                        pluginConfig = val.second.data();
                        // If config-path not specified we will look for pluginName.conf in the global.conf directory
                        if (pluginConfig == "")
                            pluginConfig = _configPath + plugin.second.data() + ".conf";
                    } else {
                        LOG(warning) << "  Value \"" << val.first << "\" not recognized. Omitting";
                    }
                }
                // Open dl-code based on http://tldp.org/HOWTO/C++-dlopen/thesolution.html
                if (FILE *file = fopen(pluginConfig.c_str(), "r")) {
                    fclose(file);
                    an_dl_t dynLib;
                    dynLib.id = plugin.second.data();
                    dynLib.DL = NULL;
                    dynLib.configurator = NULL;

                    // If plugin.conf exists, open libdcdbanalyzer_pluginName.so and read config
                    LOG(info) << pluginConfig << " found";
                    dynLib.DL = dlopen(pluginLib.c_str(), RTLD_NOW);
                    if(!dynLib.DL) {
                        LOG(error) << "Cannot load " << dynLib.id << "-library: " << dlerror();
                        return false;
                    }
                    dlerror();

                    // Set dynLib an_dl_t struct, load create and destroy symbols
                    dynLib.create = (an_create_t*) dlsym(dynLib.DL, "create");
                    const char* dlsym_error = dlerror();
                    if (dlsym_error) {
                        LOG(error) << "Cannot load symbol create for " << dynLib.id << ": " << dlsym_error;
                        return false;
                    }

                    dynLib.destroy = (an_destroy_t*) dlsym(dynLib.DL, "destroy");
                    dlsym_error = dlerror();
                    if (dlsym_error) {
                        LOG(error) << "Cannot load symbol destroy for " << dynLib.id << ": " << dlsym_error;
                        return false;
                    }

                    dynLib.configurator = dynLib.create();
                    dynLib.configurator->setGlobalSettings(_pluginSettings);
                    // Read the analyzer plugin configuration
                    if (!(dynLib.configurator->readConfig(pluginConfig))) {
                        LOG(error) << "Plugin \"" << dynLib.id << "\" could not read configuration!";
                        return false;
                    }

                    // 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!";
                    }
                    //save dl-struct
                    _plugins.push_back(dynLib);
                    LOG(info) << "Plugin \"" << dynLib.id << "\" loaded!";
                } else {
                    LOG(info) << pluginConfig << " not found. Omitting";
                }
            }
        }
    }
Alessio Netti's avatar
Alessio Netti committed
112
    _status = LOADED;
Alessio Netti's avatar
Alessio Netti committed
113
114
115
    return true;
}

116
bool AnalyticsManager::mqttCheck(pluginVector_t& pushers) {
Alessio Netti's avatar
Alessio Netti committed
117
118
119
120
121
    if(_status != LOADED) {
        LOG(error) << "Cannot perform MQTT check, AnalyticsManager is not loaded!";
        return false;
    }

122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
    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())
            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;
}

Alessio Netti's avatar
Alessio Netti committed
153
bool AnalyticsManager::init(boost::asio::io_service& io, const string& plugin) {
Alessio Netti's avatar
Alessio Netti committed
154
155
156
157
    if(_status != LOADED) {
        LOG(error) << "Cannot init, AnalyticsManager is not loaded!";
        return false;
    }
Alessio Netti's avatar
Alessio Netti committed
158
159
    for (const auto &p : _plugins)
        //Actions always affect either one or all plugins, and always all analyzers within said plugin
160
161
        if(plugin=="" || plugin==p.id) {
            LOG(info) << "Init \"" << p.id << "\" data analytics plugin";
Alessio Netti's avatar
Alessio Netti committed
162
163
            for (const auto &a : p.configurator->getAnalyzers())
                a->init(io);
164
        }
Alessio Netti's avatar
Alessio Netti committed
165
166
167
168
    return true;
}

bool AnalyticsManager::reload(boost::asio::io_service& io, const string& plugin) {
Alessio Netti's avatar
Alessio Netti committed
169
170
171
172
    if(_status != LOADED) {
        LOG(error) << "Cannot reload, AnalyticsManager is not loaded!";
        return false;
    }
Alessio Netti's avatar
Alessio Netti committed
173
174
    for (const auto &p : _plugins)
        if(plugin=="" || plugin==p.id) {
175
            LOG(info) << "Reload \"" << p.id << "\" data analytics plugin";
Alessio Netti's avatar
Alessio Netti committed
176
177
178
179
180
181
182
183
184
            if( !p.configurator->reReadConfig() )
                return false;
            for (const auto &a : p.configurator->getAnalyzers())
                a->init(io);
        }
    return true;
}

bool AnalyticsManager::start(const string& plugin) {
Alessio Netti's avatar
Alessio Netti committed
185
186
187
188
    if(_status != LOADED) {
        LOG(error) << "Cannot start, AnalyticsManager is not loaded!";
        return false;
    }
Alessio Netti's avatar
Alessio Netti committed
189
    for (const auto &p : _plugins)
190
191
        if(plugin=="" || plugin==p.id) {
            LOG(info) << "Start \"" << p.id << "\" data analytics plugin";
Alessio Netti's avatar
Alessio Netti committed
192
193
            for (const auto &a : p.configurator->getAnalyzers())
                a->start();
194
        }
Alessio Netti's avatar
Alessio Netti committed
195
196
197
198
    return true;
}

bool AnalyticsManager::stop(const string& plugin) {
Alessio Netti's avatar
Alessio Netti committed
199
200
201
202
    if(_status != LOADED) {
        LOG(error) << "Cannot stop, AnalyticsManager is not loaded!";
        return false;
    }
Alessio Netti's avatar
Alessio Netti committed
203
    for (const auto &p : _plugins)
204
205
        if(plugin=="" || plugin==p.id) {
            LOG(info) << "Stop \"" << p.id << "\" data analytics plugin";
Alessio Netti's avatar
Alessio Netti committed
206
207
            for (const auto &a : p.configurator->getAnalyzers())
                a->stop();
208
        }
Alessio Netti's avatar
Alessio Netti committed
209
210
211
212
    return true;
}

string AnalyticsManager::forwardREST(const string& command) {
Alessio Netti's avatar
Alessio Netti committed
213
214
215
216
    if(_status != LOADED) {
        LOG(error) << "Cannot forward REST command, AnalyticsManager is not loaded!";
        return "";
    }
Alessio Netti's avatar
Alessio Netti committed
217
218
219
    //TODO: implement REST interface integration
    return "";
}