// 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 // 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; Json::Value result = httpGET(queryStr); 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: // httpGET("/api/subtask/?start_time__lt=2020-03-04T12:03:00" // results in a json string output // Json::Value TMSSBridge::httpGET(const string& target) { Json::Value jsonData(""); const std::string url(std::string("http://") + itsHost + std::string(":") + std::to_string(itsPort) + target); CURL* curl = curl_easy_init(); // 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); // 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