Skip to content
Snippets Groups Projects
TMSSBridge.cc 7.56 KiB
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 <Common/LofarLogger.h>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/algorithm/string.hpp>
#include <cstdlib>
#include <iostream>
#include <string>

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)
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);
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
//    httpQuery("/api/subtask/?start_time__lt=2020-03-04T12:03:00")
string TMSSBridge::httpQuery(const string& target, const string& query_method, const string& data)
Jorrit Schaap's avatar
Jorrit Schaap committed
    const std::string url(std::string("http://") + itsHost + std::string(":") + std::to_string(itsPort) + target);
    // 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;
    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;
//        }
    THROW(TMSSBridgeException, "Could not parse HTTP data as JSON. HTTP data was:\n" + httpResponse);
}