// 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 <Common/LofarLogger.h> #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() { } Json::Value TMSSBridge::getSubTask(int subtask_id) { string queryStr = "/api/subtask/" + to_string(subtask_id) + "/"; Json::Value result = httpGETAsJson(queryStr); cout << std::endl << result.toStyledString() << std::endl << std::endl; return result; } // // get all subTaskIDS that should run within three minutes (ordered in time if multiple are found) // for given cluster // Json::Value TMSSBridge::getSubTasksStartingInThreeMinutes() { time_t now = time(0); ptime lower_limit = from_time_t(now); ptime upper_limit = from_time_t(now+3*60); //TODO: make exact query as in SAS/OTDB/sql/getTreeGroup_func.sql with OR'd states and exact timewindow string queryStr = "/api/subtask/?state__value=scheduled&start_time__gt=" + to_iso_extended_string(lower_limit) + "&start_time__lt=" + to_iso_extended_string(upper_limit) + "&ordering=start_time"; Json::Value result = httpGETAsJson(queryStr); return result["results"]; } Json::Value TMSSBridge::getActiveSubTasks() { ptime now = from_time_t(time(0)); //TODO: make exact query as in SAS/OTDB/sql/getTreeGroup_func.sql with OR'd states and exact timewindow string queryStr = "/api/subtask/?state__value=started&start_time__lt=" + to_iso_extended_string(now) + "&stop_time__gt=" + to_iso_extended_string(now) + "&ordering=start_time"; Json::Value result = httpGETAsJson(queryStr); return result["results"]; } Json::Value TMSSBridge::getFinishingSubTasks() { ptime justnow = from_time_t(time(0)-3*60); //TODO: make exact query as in SAS/OTDB/sql/getTreeGroup_func.sql with OR'd states and exact timewindow string queryStr = "/api/subtask/?state__value=finishing&stop_time__gt=" + to_iso_extended_string(justnow) + "&ordering=start_time"; Json::Value result = httpGETAsJson(queryStr); return result["results"]; } std::string TMSSBridge::getParsetAsText(int subtask_id) { string queryStr = "/api/subtask/" + to_string(subtask_id) + "/parset"; return httpQuery(queryStr); } std::string TMSSBridge::setSubtaskState(int subtask_id, const string& state) { string queryStr = "/api/subtask/" + to_string(subtask_id) + "/"; return httpQuery(queryStr, "PATCH", "{ \"state\": \"/api/subtask_state/" + state +"/\" }"); } 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 query and return the response body // Need to check response status code of http (200) // Inspired by https://gist.github.com/connormanning/41efa6075515019e499c // Example: // httpQuery("/api/subtask/?start_time__lt=2020-03-04T12:03:00") // results in a json string output // string TMSSBridge::httpQuery(const string& target, const string& query_method, const string& data) { 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()); // Set HTTP method if (query_method == "GET") { curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L); } else if (query_method == "POST") { curl_easy_setopt(curl, CURLOPT_POST, 1L); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str()); } else if (query_method == "PUT" || query_method == "PATCH" ) { curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, query_method.c_str()); curl_easy_setopt(curl, CURLOPT_USERAGENT, "TMSSBridge using libcurl"); struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "Expect:"); headers = curl_slist_append(headers, "Content-Type: application/json"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str()); curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1L); } // 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); cout << "[" << query_method << "] code=" << httpCode << " " << url << std::endl; if (httpCode == 200) return string(*httpData.get()); THROW(TMSSBridgeException, "Couldn't " + query_method + " from " + url + " exiting with http code " + to_string(httpCode)); } Json::Value TMSSBridge::httpGETAsJson(const string& target) { std::string httpResponse = this->httpQuery(target); Json::Value jsonData(""); Json::Reader jsonReader; if (jsonReader.parse(httpResponse, jsonData)) { // if(jsonData["count"] != 0) { // cout << "JSON data for " << target << std::endl << jsonData.toStyledString() << std::endl; // } return jsonData; } THROW(TMSSBridgeException, "Could not parse HTTP data as JSON. HTTP data was:\n" + httpResponse); } };//MainCU };//LOFAR