Newer
Older
// TMSSBridge.cc: Implementation of the TMSS Bridge, interface between MAC Scheduler and TMSS
//
// Copyright (C) 2020
// ASTRON (Netherlands Foundation for Research in Astronomy)
// P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, softwaresupport@astron.nl
//
// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// $Id$
#include "TMSSBridge.h"
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/algorithm/string.hpp>
#include <cstdlib>
#include <iostream>
#include <string>
#include <curl/curl.h>
#include <jsoncpp/json/json.h>
using namespace std;
namespace LOFAR {
namespace MainCU {
//
// TMSSBridge Constructor
//

Jorrit Schaap
committed
TMSSBridge::TMSSBridge(const std::string &hostname, int port, const std::string &username, const std::string &password):
itsUser(username),
itsPassword(password),
itsHost(hostname),
itsPort(port)
{
}
//
// TMSSBridge Destructor
//
TMSSBridge::~TMSSBridge()
{
}
//
// get all subTaskIDS that should run within three minutes (ordered in time if multiple are found)
// for given cluster
//
vector<int> TMSSBridge::getSubTaskIDStartingInThreeMinutes(ptime currentTime, string clusterName)
{
string currentTimeStr = to_iso_extended_string(currentTime);
string queryStr = "/api/?start_time__lt=" + currentTimeStr + "&cluster__name==" + clusterName;
vector<string> urlList = translateHttpResultToSortedUrlList(result);
}
//
// Translate the HTTP result to json format and parse the json format
// How to handle json structure in C++?
// Get the number of taskIDs like python
// json_response = response.json()
// json_response.get('count'))
// ... and results[idx].items('url)
// if multiple found sort on startTime !
vector<string> TMSSBridge::translateHttpResultToSortedUrlList(Json::Value jsonRoot)
vector<string> urlList{};
// Read values
const int nbrTasksFound(jsonRoot["count"].asInt());
const Json::Value results = jsonRoot["results"];
for(int idx=0; idx<results.size(); ++idx) {
string urlStr = results[idx]["url"].asString();
string startTimeStr = results[idx]["start_time"].asString();
// Only interested in the subTaskID
vector<string>tmp;
boost::split(tmp, urlStr, boost::is_any_of("/subtask/"));
urlList.push_back(tmp.at(1).c_str());
// TODO: I am lazy now....sort on ascending starttime
}
return urlList;
std::size_t callback(const char* in,
std::size_t size,
std::size_t num,
std::string* out)
{
const std::size_t totalBytes(size * num);
out->append(in, totalBytes);
return totalBytes;
}
//
// Performs an HTTP GET and return the response body
// Need to check respons status code of http (200)
// Inspired by https://gist.github.com/connormanning/41efa6075515019e499c
// Example:

Jorrit Schaap
committed
// httpGET("/api/subtask/?start_time__lt=2020-03-04T12:03:00"
// results in a json string output
//

Jorrit Schaap
committed
Json::Value TMSSBridge::httpGET(const string& target)
{
Json::Value jsonData("");

Jorrit Schaap
committed
const std::string url(std::string("http://") + itsHost + std::string(":") + std::to_string(itsPort) + target);
CURL* curl = curl_easy_init();

Jorrit Schaap
committed
// setup authentication
curl_easy_setopt(curl, CURLOPT_USERNAME, itsUser.c_str());
curl_easy_setopt(curl, CURLOPT_PASSWORD, itsPassword.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// Set remote URL.
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
// Don't bother trying IPv6, which would increase DNS resolution time.
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
// Don't wait forever, time out after 10 seconds.
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
// Follow HTTP redirects if necessary.
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
// Response information.
long httpCode(0);
std::unique_ptr<std::string> httpData(new std::string());
// Hook up data handling function.
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);
// Hook up data container (will be passed as the last parameter to the
// callback handling function). Can be any pointer type, since it will
// internally be passed as a void pointer.
curl_easy_setopt(curl, CURLOPT_WRITEDATA, httpData.get());
// Run our HTTP GET command, capture the HTTP response code, and clean up.
curl_easy_perform(curl);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
curl_easy_cleanup(curl);
if (httpCode == 200)
{
std::cout << "\nGot successful response from " << url << std::endl;
// Response looks good - done using Curl now. Try to parse the results
// and print them out.
Json::Reader jsonReader;
std::string httpResponse(*httpData.get());
if (jsonReader.parse(httpResponse, jsonData))
{
// TODO:
// How we deal with logging in Lofar C++ ?
// for now just do a stdout...
std::cout << "Successfully parsed JSON data" << std::endl;
std::cout << "\nJSON data received:" << std::endl;
std::cout << jsonData.toStyledString() << std::endl;
}
else
{
THROW(TMSSBridgeException, "Could not parse HTTP data as JSON. HTTP data was:\n" + httpResponse);
}
}
else
{
THROW(TMSSBridgeException, "Couldn't GET from " + url + " exiting with http code " + to_string(httpCode));
}
return jsonData;
}
};//MainCU
};//LOFAR