Currently job artifacts in CI/CD pipelines on LRZ GitLab never expire. Starting from Wed 26.1.2022 the default expiration time will be 30 days (GitLab default). Currently existing artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

Commit 2bb121fc authored by Daniele Tafani's avatar Daniele Tafani
Browse files

Working HTTP server for Grafana. Still needs a lot of cleaning!

parent 256b712f
......@@ -13,6 +13,7 @@
#include "httpserver.h"
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/log/trivial.hpp>
......
......@@ -3,7 +3,9 @@ include ../config.mk
CXXFLAGS = -O2 -g --std=c++11 -Wall -Wno-unused-local-typedefs -Wno-deprecated-declarations -Wno-unknown-warning-option -fmessage-length=0 -I../include/ -I../lib/include -I$(DCDBDEPLOYPATH)/include -DBOOST_DATE_TIME_POSIX_TIME_STD_CONFIG -I$(DCDBDEPSPATH)/cpp-netlib-0.12.0-final/deps/asio/asio/include -I$(DCDBDEPSPATH)/cpp-netlib-0.12.0-final -I$(DCDBDEPSPATH)/cpp-netlib-0.12.0-final/deps/cxxopts/src -DASIO_HEADER_ONLY -DBOOST_TEST_DYN_LINK
OBJS = httpserver.o \
Configuration.o
Configuration.o \
Logging.o
LIBS = -L$(DCDBDEPLOYPATH)/lib/ -L../lib -ldcdb -lcassandra -lboost_system -lboost_thread -lboost_log_setup -lboost_log -lpthread -lcrypto -lssl -lcppnetlib-server-parsers -lcppnetlib-uri
TARGET = httpserver
......
//
// Server.cpp
// httpserver
//
// Created by Tafani, Daniele on 27.09.18.
// Copyright © 2018 LRZ. All rights reserved.
//
#include "Server.h"
#include <iostream>
using namespace std;
using namespace web;
using namespace http;
using namespace utility;
using namespace http::experimental::listener;
std::unique_ptr<handler> g_httpHandler;
Configuration* _configuration;
HttpsServer* _httpsServer;
DCDB::Connection* cassandraConnection;
handler::handler()
{
//ctor
}
handler::handler(utility::string_t url):m_listener(url)
{
m_listener.support(methods::GET, std::bind(&handler::handle_get, this, std::placeholders::_1));
m_listener.support(methods::PUT, std::bind(&handler::handle_put, this, std::placeholders::_1));
m_listener.support(methods::POST, std::bind(&handler::handle_post, this, std::placeholders::_1));
m_listener.support(methods::DEL, std::bind(&handler::handle_delete, this, std::placeholders::_1));
}
handler::~handler()
{
//dtor
}
void handler::handle_error(pplx::task<void>& t)
{
try
{
t.get();
}
catch(...)
{
// Ignore the error, Log it if a logger is available
}
}
//
// Get Request
// Primarily used for
//
void handler::handle_get(http_request message)
{
ucout << message.to_string() << endl;
auto paths = http::uri::split_path(http::uri::decode(message.relative_uri().path()));
message.relative_uri().path();
//Dbms* d = new Dbms();
//d->connect();
concurrency::streams::fstream::open_istream(U("static/index.html"), std::ios::in).then([=](concurrency::streams::istream is) {
message.reply(status_codes::OK, is, U("text/html")).then([](pplx::task<void> t) {
try{
t.get();
}
catch(...){
//
}
});
}).then([=](pplx::task<void>t) {
try{
t.get();
}
catch(...){
message.reply(status_codes::InternalError,U("INTERNAL ERROR "));
}
});
return;
};
//
// A POST request
//
void handler::handle_post(http_request message) {
ucout << message.to_string() << endl;
std::string response;
http_response resp;
if(message.relative_uri().to_string() == "/search") {
DCDB::SensorConfig sensorConfig(cassandraConnection);
std::list<std::string> publicSensors;
sensorConfig.getPublicSensorNames(publicSensors);
response = "[";
for (std::list<std::string>::iterator it=publicSensors.begin(); it != publicSensors.end(); it++) {
response = response + "\"" + (*it) + "\",";
}
response.pop_back();
response = response + "]";
message.reply(status_codes::OK, response);
}
else if(message.relative_uri().to_string() == "/query") {
//extract JSON from body
pplx::task<json::value> task = message.extract_json(true);
const json::value& jsonValue = task.get();
//get start time as string
std::string startStr = jsonValue.at("range").at("from").as_string();
startStr[startStr.find("T")] = ' ';
startStr.pop_back();
//get end time as string
std::string endStr = jsonValue.at("range").at("to").as_string();
endStr[endStr.find("T")] = ' ';
endStr.pop_back();
//get sensors
std::list<std::string> sensors;
for (int i = 0; i < jsonValue.at("targets").size(); i++)
sensors.push_back(jsonValue.at("targets").at(i).at("target").as_string());
//Prepare query
DCDB::TimeStamp start, end;
start = DCDB::TimeStamp(startStr, false);
end = DCDB::TimeStamp(endStr, false);
DCDB::SensorConfig sensorConfig(cassandraConnection);
json::value output;
uint64_t targetIdx = 0;
for (std::list<std::string>::iterator it = sensors.begin(); it != sensors.end(); it++) {
DCDB::Sensor sensor(cassandraConnection, *it);
//Shoot!
std::list<DCDB::SensorDataStoreReading> results;
sensor.query(results, start, end, DCDB::AGGREGATE_NONE);
//Format response for Grafana
output[targetIdx]["target"] = json::value::string(U(*it)) ;
uint64_t dataIdx = 0;
for (std::list<DCDB::SensorDataStoreReading>::iterator reading = results.begin(); reading != results.end(); reading++) {
std::vector<json::value> elements;
elements.push_back(boost::lexical_cast<double>((*reading).value)/3600000); //just to get Wh as a momentary example
elements.push_back((*reading).timeStamp.getRaw()/1000000); //The Grafana JSON data source plugin accepts only ms for timestamps
output[targetIdx]["datapoints"][dataIdx] = json::value::array(elements);
dataIdx++;
}
targetIdx++;
ucout << output.serialize() << endl;
}
resp.set_body(output);
resp.set_status_code(status_codes::OK);
message.reply(resp);
}
return ;
};
//
// A DELETE request
//
void handler::handle_delete(http_request message)
{
ucout << message.to_string() << endl;
string rep = U("WRITE YOUR OWN DELETE OPERATION");
message.reply(status_codes::OK,rep);
return;
};
//
// A PUT request
//
void handler::handle_put(http_request message)
{
ucout << message.to_string() << endl;
string rep = U("WRITE YOUR OWN PUT OPERATION");
message.reply(status_codes::OK,rep);
return;
};
void on_initialize(const string_t& address)
{
uri_builder uri(address);
auto addr = uri.to_uri().to_string();
g_httpHandler = std::unique_ptr<handler>(new handler(addr));
g_httpHandler->open().wait();
ucout << utility::string_t(U("Listening for requests at: ")) << addr << std::endl;
return;
}
void on_shutdown()
{
g_httpHandler->close().wait();
return;
}
#ifdef _WIN32
int wmain(int argc, wchar_t *argv[])
#else
int main(int argc, char *argv[])
#endif
{
_configuration = new Configuration(argv[argc-1]);
//Read global variables from config file
if(!_configuration->readGlobal()) {
//LOG(fatal) << "Failed to read global configuration!";
std::cerr << "Failed to read global configuration!";
return 1;
}
global_t& globalSettings = _configuration->getGlobal();
cassandraSettings_t& cassandraSettings = globalSettings.cassandraSettings;
restAPISettings_t& restAPISettings = globalSettings.restAPISettings;
/* Connect to the cassandra server */
cassandraConnection = new DCDB::Connection();
cassandraConnection->setHostname(cassandraSettings.cassandraHost);
cassandraConnection->setPort(cassandraSettings.cassandraPort);
if (!cassandraConnection->connect())
std::cerr << "Cannot connect to Cassandra database." << std::endl;
utility::string_t port = U(restAPISettings.restPort);
// if(argc == 2)
// {
// port = argv[1];
// }
utility::string_t address = U("http://" + restAPISettings.restHost + ":");
address.append(port);
on_initialize(address);
std::cout << "Press ENTER to exit." << std::endl;
std::string line;
std::getline(std::cin, line);
on_shutdown();
return 0;
}
//
// Server.h
// httpserver
//
// Created by Tafani, Daniele on 27.09.18.
// Copyright © 2018 LRZ. All rights reserved.
//
#include <stdio.h>
#include "Configuration.h"
#include "Logging.h"
#include "cassandra.h"
#ifndef Server_h
#define Server_h
#pragma once
#include <string>
#include <vector>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <fstream>
#include <random>
#ifdef _WIN32
#define NOMINMAX
#include <Windows.h>
#else
# include <sys/time.h>
#endif
#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"
#include "dcdb/connection.h"
#include "dcdb/timestamp.h"
#include "dcdb/sensorid.h"
#include "dcdb/sensordatastore.h"
#include "dcdb/sensorconfig.h"
#include "dcdb/sensor.h"
#pragma warning ( push )
#pragma warning ( disable : 4457 )
#pragma warning ( pop )
#include <locale>
#include <ctime>
using namespace std;
using namespace web;
using namespace http;
using namespace utility;
using namespace http::experimental::listener;
class handler
{
public:
handler();
handler(utility::string_t url);
virtual ~handler();
pplx::task<void>open(){return m_listener.open();}
pplx::task<void>close(){return m_listener.close();}
protected:
private:
void handle_get(http_request message);
void handle_put(http_request message);
void handle_post(http_request message);
void handle_delete(http_request message);
void handle_error(pplx::task<void>& t);
http_listener m_listener;
};
#endif /* Server_h */
......@@ -11,6 +11,7 @@ CPPDRV_VERSION = 2.0.1
LIBUV_VERSION = 0.10.36
CPPNET_VERSION = 0.12.0-final
CPPRESTSDK_VERSION = 2.10.6
JSONCPP_VERSION = 0.5.0
BOOST_VERSION_U = $(subst .,_,$(BOOST_VERSION))
DISTFILES = apache-cassandra-$(CASSANDRA_VERSION).tar.gz;http://archive.apache.org/dist/cassandra/$(CASSANDRA_VERSION)/apache-cassandra-$(CASSANDRA_VERSION)-bin.tar.gz \
......@@ -20,7 +21,7 @@ DISTFILES = apache-cassandra-$(CASSANDRA_VERSION).tar.gz;http://archive.apache.o
libuv-v$(LIBUV_VERSION).tar.gz;https://dist.libuv.org/dist/v$(LIBUV_VERSION)/libuv-v$(LIBUV_VERSION).tar.gz \
cpp-driver-$(CPPDRV_VERSION).tar.gz;https://github.com/datastax/cpp-driver/archive/$(CPPDRV_VERSION).tar.gz \
cpp-netlib-$(CPPNET_VERSION).tar.gz;http://downloads.cpp-netlib.org/0.12.0/cpp-netlib-$(CPPNET_VERSION).tar.gz \
cpprestsdk-$(CPPRESTSDK_VERSION).tar.gz;https://github.com/Microsoft/cpprestsdk/archive/v$(CPPRESTSDK_VERSION).tar.gz
cpprestsdk-$(CPPRESTSDK_VERSION).tar.gz;https://github.com/Microsoft/cpprestsdk/archive/v$(CPPRESTSDK_VERSION).tar.gz \
DISTFILES_HASHES = apache-cassandra-2.2.10.tar.gz|4c58cb7c6753ce26f7c4d650502feece;mosquitto-1.4.14.tar.gz|6b0966e93f118bc71ad7b61600a6c2d3;boost_1_58_0.tar.gz|5a5d5614d9a07672e1ab2a250b5defc5;openssl-1.0.2l.tar.gz|f85123cd390e864dfbe517e7616e6566;cpp-driver-2.0.1.tar.gz|70bf83e1cbd0d35b7e5ed66fc4dccbb1;libuv-v0.10.36.tar.gz|8eb77b4fee4f311c114a9fee06f5a2ab;cpp-netlib-0.12.0-final.tar.gz|29b87c0e8c1a9e7fbdea5afcec947d53;cpprestsdk-2.10.6.tar.gz|0a9b2424578fbeb1ac8465173ce8fc71
......@@ -230,7 +231,7 @@ $(DCDBDEPSPATH)/cpprestsdk-$(CPPRESTSDK_VERSION)/.built: $(DCDBDEPSPATH)/cpprest
$(DCDBDEPSPATH)/cpprestsdk-$(CPPRESTSDK_VERSION)/.installed: $(DCDBDEPSPATH)/cpprestsdk-$(CPPRESTSDK_VERSION)/.built
@echo "Installing cpprestsdk..."
cd $(DCDBDEPSPATH)/cpprestsdk_build && make install && touch $(@)
$(DCDBDEPSPATH)/apache-cassandra-$(CASSANDRA_VERSION)/.built: $(DCDBDEPSPATH)/apache-cassandra-$(CASSANDRA_VERSION)/.patched
@touch $(DCDBDEPSPATH)/apache-cassandra-$(CASSANDRA_VERSION)/.built
......
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