Commit 954e4e3c authored by Daniele Tafani's avatar Daniele Tafani
Browse files

Manage custom sensor names, updated README accordingly, removed wrong header file.

parent f2dc11d6
......@@ -44,7 +44,6 @@ DCDB::Connection* _cassandraConnection;
boost::shared_ptr<boost::asio::io_service::work> keepAliveWork;
void printSyntax()
{
_configuration = new Configuration("", "grafana.conf");
......
//
// HTTPServer.h
//
// The header file of HTTPServer.cpp.
//
// Created by Tafani, Daniele on 27.09.18.
// Copyright © 2018 LRZ. All rights reserved.
//
#include <stdio.h>
#include "Configuration.h"
#include "globalconfiguration.h"
#include "logging.h"
#include "cassandra.h"
#include "dcdbdaemon.h"
#include "sensornavigator.h"
#ifndef HTTPServer_h
#define HTTPServer_h
#pragma once
#include <string>
#include <vector>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <fstream>
#include <random>
#include <locale>
#include <ctime>
#ifdef _WIN32
#define NOMINMAX
#include <Windows.h>
#else
# include <sys/time.h>
#endif
//Headers from Boost
#include <boost/thread/condition.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/regex.hpp>
#include <asio/ssl.hpp>
//Headers from cpprestsdk
#include "cpprest/json.h"
#include "cpprest/http_listener.h"
#include "cpprest/uri.h"
#include "cpprest/asyncrt_utils.h"
#include "cpprest/json.h"
#include "cpprest/filestream.h"
#include "cpprest/containerstream.h"
#include "cpprest/producerconsumerstream.h"
//Headers from dcdb
#include "dcdb/connection.h"
#include "dcdb/timestamp.h"
#include "dcdb/sensorid.h"
#include "dcdb/sensordatastore.h"
#include "dcdb/sensorconfig.h"
#include "dcdb/sensor.h"
using namespace std;
using namespace web;
using namespace http;
using namespace utility;
using namespace http::experimental::listener;
/**
* This class implements the behaviour of a request handler of the REST server.
*/
class handler
{
public:
/**
* The default constructor of the class.
*/
handler();
/**
* The constructor of the class with URL of the REST server.
* @param url
*/
handler(utility::string_t url);
/**
* The destructor of the class.
*/
virtual ~handler();
pplx::task<void>open(){return m_listener.open();}
pplx::task<void>close(){return m_listener.close();}
private:
/**
* This function handles HTTP GET requests.
* It is only used once to handle a Grafana request to define a data source.
*
* @param message: the HTTP message containing the GET request.
*/
void handle_get(http_request message);
/**
* This function handles HTTP POST requests.
* It is used to handle Grafana queries (for sensor names and data).
*
* @param message: the HTTP message containing the POST request.
*/
void handle_post(http_request message);
/**
* This function decodes base64 string for HTTP basic authentication.
*
* @param input: the base64 string to be decoded.
*/
std::string decode(std::string input);
/**
* The HTTP listener of the handler that supports different HTTP requests.
*
*/
http_listener m_listener;
};
/*
* Provides REST API services over configurable host and port.
*/
class HttpsServer {
public:
HttpsServer(restAPISettings_t restAPISettings, cassandraSettings_t cassandraSettings, hierarchySettings_t hierarchySettings, asio::io_service& io);
virtual ~HttpsServer();
/*
* Starts the handler of the server.
*/
void run() {
_handler->open().wait();
}
/*
* Stops the handler of the server.
*/
void stop() {
_handler->close().wait();
}
private:
std::unique_ptr<handler> _handler;
boost::log::sources::severity_logger<boost::log::trivial::severity_level> lg;
};
#endif /* HTTPServer_h */
......@@ -55,7 +55,7 @@ The configuration specifies various settings for grafanaserver in general. Pleas
| address | Define address and port of the Cassandra DB server which stores the timeserie data. Default is 127.0.0.1:9042.
| | |
| hierarchy | Wrapper for the definition of he hierarchical structure of the sensor tree.
| regex | Regular expression representing the full hierarchy of sensor names. If left empty, '/' are considered default separators of the different levels composing the name (e.g., /system/rack/chassis/node/sensor). See the documentation of the Sensor Navigator for more details.
| regex | Regular expression representing the full hierarchy of sensor names, where each level is separated by a provided "separator" character. If left empty, '/' are considered default separators of the different levels composing the name (e.g., /system/rack/chassis/node/sensor). If the published sensor names are different from their corresponding MQTT topics, the provided regex needs to reflect it. For example, the regex "mySystem.,rack\\d{2}.,chassis\\d{2}.,server\\d{2}" could represent a custom sensor name such as "mySystem.rack01.chassis03.server10" (see the documentation of the Sensor Navigator for more details). However, it is highly encouraged to leave the default configuration settings, whereas published sensor names exactly match their correspondant MQTT topics.
| separator | Specifies a custom separator for the different levels composing the sensor name. Default is emtpy.
| | |
| restAPI | Bundles all values related to the RestAPI. See the corresponding [section](#restApi) for more information on supported functionality.
......
......@@ -51,12 +51,13 @@ RestAPI::RestAPI(serverSettings_t settings,
LOG(info) << "Retrieving published sensor names and topics...";
//Get the list of all public sensors and topics.
std::vector<std::string> sensors;
std::vector<std::string> topics;
std::list<DCDB::PublicSensor> publicSensors;
_sensorConfig = new DCDB::SensorConfig(_connection);
_sensorConfig->getPublicSensorsVerbose(publicSensors);
std::vector<std::string> sensors;
std::vector<std::string> topics;
for(auto& s : publicSensors) {
sensors.push_back(s.name);
......@@ -67,7 +68,8 @@ RestAPI::RestAPI(serverSettings_t settings,
LOG(info) << "Building the sensor navigator...";
_navigator = new SensorNavigator();
_navigator->buildTree(hierarchySettings.regex, &sensors, &topics, hierarchySettings.separator);
_navigator->buildTree(hierarchySettings.regex, &sensors, &topics);
_separator = hierarchySettings.separator;
}
//Dummy GET request to create a datasource. All necessary checks that could be peformed here are
......@@ -95,7 +97,7 @@ void::RestAPI::POST_search(endpointArgs) {
res.body() = "[";
std::set<std::string> *treeOutput;
//Get the element from the sensor navigator
//Get the element from the sensor navigator.
std::string parentNode = getQuery("node", queries);
if(parentNode == "") {
try {
......@@ -114,10 +116,12 @@ void::RestAPI::POST_search(endpointArgs) {
}
}
}
else {
parentNode += "/";
parentNode += "/";
if(_separator != "")
boost::replace_all(parentNode, "/", _separator);
try {
treeOutput = _navigator->getNodes(parentNode,false);
}
......@@ -141,8 +145,7 @@ void::RestAPI::POST_search(endpointArgs) {
//Format the data for Grafana
boost::regex exp(parentNode);
std::string outputElement;
for (auto o : *treeOutput) {
for (auto& o : *treeOutput) {
if(getQuery("sensors", queries) != "true") {
outputElement = boost::regex_replace((o),exp,"");
outputElement.erase(std::remove(outputElement.begin(), outputElement.end(), '/'), outputElement.end());
......@@ -212,12 +215,11 @@ void::RestAPI::POST_query(endpointArgs) {
//Format the output for the response to Grafana.
std::string datapoints = "[";
for (auto& r : results)
datapoints += "[" + std::to_string(r.value * ps.scaling_factor) + ","
+ std::to_string(r.timeStamp.getRaw()/1000000) + "],";
datapoints.pop_back();
if(datapoints.back() == ',')
datapoints.pop_back();
datapoints += "]";
res.body() += "{\"target\":\"" + sensorName + "\",\"datapoints\":" + datapoints + "},";
}
......
......@@ -126,6 +126,7 @@ private:
SensorNavigator* _navigator;
DCDB::Connection* _connection;
DCDB::SensorConfig* _sensorConfig;
std::string _separator;
};
......
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