Skip to content

Commit

Permalink
Implemented HTTPS-based Czar front-end
Browse files Browse the repository at this point in the history
Eliminated classes of the QHTTP-based version of the Czar frontend
  • Loading branch information
iagaponenko committed Jul 5, 2024
1 parent 5c13233 commit 54a4933
Show file tree
Hide file tree
Showing 13 changed files with 492 additions and 418 deletions.
8 changes: 7 additions & 1 deletion src/admin/python/lsst/qserv/admin/cli/entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,13 @@ class CommandInfo:
"--lua-cpath=/usr/local/lua/qserv/lib/czarProxy.so --defaults-file={{proxy_cfg_path}}",
)),
("czar-http", CommandInfo(
"qserv-czar-http http {{czar_cfg_path}} {{http_frontend_port}} {{http_frontend_threads}} ",
"qserv-czar-http "
"http "
"{{czar_cfg_path}} "
"{{http_frontend_port}} "
"{{http_frontend_threads}} "
"{{http_ssl_cert_file}} "
"{{http_ssl_private_key_file}}",
)),
("cmsd-manager", CommandInfo(
"cmsd -c {{cmsd_manager_cfg_path}} -n manager -I v4",
Expand Down
10 changes: 6 additions & 4 deletions src/czar/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
add_library(czar OBJECT)

target_sources(czar PRIVATE
ChttpCzarIngestModule.cc
ChttpCzarQueryModule.cc
ChttpCzarSvc.cc
ChttpModule.cc
Czar.cc
HttpCzarIngestModule.cc
HttpCzarSvc.cc
HttpCzarQueryModule.cc
HttpModule.cc
HttpMonitorModule.cc
HttpSvc.cc
Expand All @@ -23,6 +24,7 @@ target_link_libraries(czar PUBLIC
util
log
XrdSsiLib
cpp-httplib
)

function(CZAR_UTILS)
Expand Down Expand Up @@ -51,4 +53,4 @@ endfunction()

czar_utils(
qserv-czar-http
)
)
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
*/

// Class header
#include "czar/HttpCzarIngestModule.h"
#include "czar/ChttpCzarIngestModule.h"

// System headers
#include <algorithm>
Expand All @@ -38,7 +38,6 @@
#include "http/Exceptions.h"
#include "http/MetaModule.h"
#include "http/RequestBodyJSON.h"
#include "qhttp/Request.h"
#include "qhttp/Status.h"

using namespace std;
Expand Down Expand Up @@ -105,27 +104,25 @@ void setProtocolFields(json& data) {

namespace lsst::qserv::czar {

void HttpCzarIngestModule::process(asio::io_service& io_service, string const& context,
shared_ptr<qhttp::Request> const& req,
shared_ptr<qhttp::Response> const& resp, string const& subModuleName,
http::AuthType const authType) {
HttpCzarIngestModule module(io_service, context, req, resp);
void ChttpCzarIngestModule::process(asio::io_service& io_service, string const& context,
httplib::Request const& req, httplib::Response& resp,
string const& subModuleName, http::AuthType const authType) {
ChttpCzarIngestModule module(io_service, context, req, resp);
module.execute(subModuleName, authType);
}

HttpCzarIngestModule::HttpCzarIngestModule(asio::io_service& io_service, string const& context,
shared_ptr<qhttp::Request> const& req,
shared_ptr<qhttp::Response> const& resp)
: http::QhttpModule(cconfig::CzarConfig::instance()->replicationAuthKey(),
ChttpCzarIngestModule::ChttpCzarIngestModule(asio::io_service& io_service, string const& context,
httplib::Request const& req, httplib::Response& resp)
: http::ChttpModule(cconfig::CzarConfig::instance()->replicationAuthKey(),
cconfig::CzarConfig::instance()->replicationAdminAuthKey(), req, resp),
_io_service(io_service),
_context(context),
_registryBaseUrl("http://" + cconfig::CzarConfig::instance()->replicationRegistryHost() + ":" +
to_string(cconfig::CzarConfig::instance()->replicationRegistryPort())) {}

string HttpCzarIngestModule::context() const { return _context; }
string ChttpCzarIngestModule::context() const { return _context; }

json HttpCzarIngestModule::executeImpl(string const& subModuleName) {
json ChttpCzarIngestModule::executeImpl(string const& subModuleName) {
string const func = string(__func__) + "[sub-module='" + subModuleName + "']";
debug(func);
if (subModuleName == "INGEST-DATA")
Expand All @@ -137,7 +134,7 @@ json HttpCzarIngestModule::executeImpl(string const& subModuleName) {
throw invalid_argument(context() + func + " unsupported sub-module");
}

json HttpCzarIngestModule::_ingestData() {
json ChttpCzarIngestModule::_ingestData() {
debug(__func__);
checkApiVersion(__func__, 35);

Expand Down Expand Up @@ -262,7 +259,7 @@ json HttpCzarIngestModule::_ingestData() {
return json();
}

json HttpCzarIngestModule::_deleteDatabase() {
json ChttpCzarIngestModule::_deleteDatabase() {
debug(__func__);
checkApiVersion(__func__, 34);

Expand All @@ -277,7 +274,7 @@ json HttpCzarIngestModule::_deleteDatabase() {
return json();
}

json HttpCzarIngestModule::_deleteTable() {
json ChttpCzarIngestModule::_deleteTable() {
debug(__func__);
checkApiVersion(__func__, 34);

Expand All @@ -295,7 +292,7 @@ json HttpCzarIngestModule::_deleteTable() {
return json();
}

vector<string> HttpCzarIngestModule::_getWorkerIds() {
vector<string> ChttpCzarIngestModule::_getWorkerIds() {
vector<string> workerIds;
auto const workersJson = _requestController(http::Method::GET, "/replication/config");
for (auto const& worker : workersJson.at("config").at("workers")) {
Expand All @@ -311,7 +308,7 @@ vector<string> HttpCzarIngestModule::_getWorkerIds() {
return workerIds;
}

void HttpCzarIngestModule::_unpublishOrCreateDatabase(const string& databaseName) {
void ChttpCzarIngestModule::_unpublishOrCreateDatabase(const string& databaseName) {
json const config = _requestController(http::Method::GET, "/replication/config").at("config");
for (const auto& database : config.at("databases")) {
if (boost::iequals(database.at("database").get<string>(), databaseName)) {
Expand All @@ -324,37 +321,37 @@ void HttpCzarIngestModule::_unpublishOrCreateDatabase(const string& databaseName
_createDirectorTable(databaseName);
}

void HttpCzarIngestModule::_createDatabase(string const& databaseName) {
void ChttpCzarIngestModule::_createDatabase(string const& databaseName) {
json data = json::object({{"database", databaseName},
{"num_stripes", ::defaultNumStripes},
{"num_sub_stripes", ::defaultNumSubStripes},
{"overlap", ::defaultOverlap}});
_requestController(http::Method::POST, "/ingest/database", data);
}

void HttpCzarIngestModule::_deleteDatabase(string const& databaseName) {
void ChttpCzarIngestModule::_deleteDatabase(string const& databaseName) {
json data = json::object();
_requestController(http::Method::DELETE, "/ingest/database/" + databaseName, data);
}

void HttpCzarIngestModule::_unpublishDatabase(string const& databaseName) {
void ChttpCzarIngestModule::_unpublishDatabase(string const& databaseName) {
json data = json::object({{"publish", 0}});
_requestController(http::Method::PUT, "/replication/config/database/" + databaseName, data);
}

void HttpCzarIngestModule::_publishDatabase(string const& databaseName) {
void ChttpCzarIngestModule::_publishDatabase(string const& databaseName) {
json data = json::object();
_requestController(http::Method::PUT, "/ingest/database/" + databaseName, data);
}

void HttpCzarIngestModule::_createTable(string const& databaseName, string const& tableName,
json const& schema) {
void ChttpCzarIngestModule::_createTable(string const& databaseName, string const& tableName,
json const& schema) {
json data = json::object(
{{"database", databaseName}, {"table", tableName}, {"is_partitioned", 0}, {"schema", schema}});
_requestController(http::Method::POST, "/ingest/table/", data);
}

void HttpCzarIngestModule::_createDirectorTable(string const& databaseName) {
void ChttpCzarIngestModule::_createDirectorTable(string const& databaseName) {
json const schema = json::array({{{"name", "objectId"}, {"type", "BIGINT"}},
{{"name", "ra"}, {"type", "DOUBLE"}},
{{"name", "dec"}, {"type", "DOUBLE"}},
Expand All @@ -377,30 +374,30 @@ void HttpCzarIngestModule::_createDirectorTable(string const& databaseName) {
_allocateChunk(databaseName, ::defaultChunkId);
}

void HttpCzarIngestModule::_deleteTable(string const& databaseName, string const& tableName) {
void ChttpCzarIngestModule::_deleteTable(string const& databaseName, string const& tableName) {
json data = json::object();
_requestController(http::Method::DELETE, "/ingest/table/" + databaseName + "/" + tableName, data);
}

uint32_t HttpCzarIngestModule::_startTransaction(string const& databaseName) {
uint32_t ChttpCzarIngestModule::_startTransaction(string const& databaseName) {
json data = json::object({{"database", databaseName}});
auto const response = _requestController(http::Method::POST, "/ingest/trans", data);
return response.at("databases").at(databaseName).at("transactions")[0].at("id").get<uint32_t>();
}

void HttpCzarIngestModule::_abortOrCommitTransaction(uint32_t id, bool abort) {
void ChttpCzarIngestModule::_abortOrCommitTransaction(uint32_t id, bool abort) {
json data = json::object();
auto const service = "/ingest/trans/" + to_string(id) + "?abort=" + (abort ? "1" : "0");
_requestController(http::Method::PUT, service, data);
}

json HttpCzarIngestModule::_allocateChunk(string const& databaseName, unsigned int chunkId) {
json ChttpCzarIngestModule::_allocateChunk(string const& databaseName, unsigned int chunkId) {
json data = json::object({{"database", databaseName}, {"chunk", chunkId}});
return _requestController(http::Method::POST, "/ingest/chunk", data);
}

void HttpCzarIngestModule::_createIndexes(string const& func, string const& databaseName,
string const& tableName, json const& indexes) {
void ChttpCzarIngestModule::_createIndexes(string const& func, string const& databaseName,
string const& tableName, json const& indexes) {
for (auto const& indexDef : indexes) {
if (!indexDef.is_object()) throw http::Error(func, "index definition is not a JSON object");
try {
Expand All @@ -415,8 +412,8 @@ void HttpCzarIngestModule::_createIndexes(string const& func, string const& data
}
}

void HttpCzarIngestModule::_countRows(string const& func, string const& databaseName,
string const& tableName) {
void ChttpCzarIngestModule::_countRows(string const& func, string const& databaseName,
string const& tableName) {
json data = json::object({{"database", databaseName},
{"table", tableName},
{"row_counters_state_update_policy", "ENABLED"},
Expand All @@ -428,7 +425,7 @@ void HttpCzarIngestModule::_countRows(string const& func, string const& database
}
}

string HttpCzarIngestModule::_controller() {
string ChttpCzarIngestModule::_controller() {
if (_controllerBaseUrl.empty()) {
auto const response = _requestRegistry(http::Method::GET, "/services");
for (auto const& [id, controller] : response.at("services").at("controllers").items()) {
Expand All @@ -443,7 +440,7 @@ string HttpCzarIngestModule::_controller() {
return _controllerBaseUrl;
}

string HttpCzarIngestModule::_worker(string const& workerId) {
string ChttpCzarIngestModule::_worker(string const& workerId) {
if (_workerBaseUrls.empty()) {
auto const response = _requestRegistry(http::Method::GET, "/services");
for (auto const& [id, worker] : response.at("services").at("workers").items()) {
Expand All @@ -458,7 +455,7 @@ string HttpCzarIngestModule::_worker(string const& workerId) {
return _workerBaseUrls.at(workerId);
}

json HttpCzarIngestModule::_request(http::Method method, string const& url, json& data) {
json ChttpCzarIngestModule::_request(http::Method method, string const& url, json& data) {
json const errorExt = json::object(
{{"method", http::method2string(method)}, {"url", url}, {"timeout_sec", _timeoutSec}});
auto const request = _asyncRequest(method, url, data);
Expand All @@ -480,8 +477,8 @@ json HttpCzarIngestModule::_request(http::Method method, string const& url, json
return response;
}

shared_ptr<http::AsyncReq> HttpCzarIngestModule::_asyncRequest(http::Method method, string const& url,
json& data) {
shared_ptr<http::AsyncReq> ChttpCzarIngestModule::_asyncRequest(http::Method method, string const& url,
json& data) {
shared_ptr<http::AsyncReq> request;
if (method == http::Method::GET) {
string const url_ = url + "?version=" + to_string(http::MetaModule::version) +
Expand All @@ -496,7 +493,7 @@ shared_ptr<http::AsyncReq> HttpCzarIngestModule::_asyncRequest(http::Method meth
return request;
}

shared_ptr<http::AsyncReq> HttpCzarIngestModule::_asyncPostRequest(string const& url, string const& data) {
shared_ptr<http::AsyncReq> ChttpCzarIngestModule::_asyncPostRequest(string const& url, string const& data) {
unordered_map<string, string> const headers({{"Content-Type", "application/json"}});
auto const request = http::AsyncReq::create(_io_service, nullptr, http::Method::POST, url, data, headers);
request->setExpirationIval(_timeoutSec);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
* the GNU General Public License along with this program. If not,
* see <http://www.lsstcorp.org/LegalNotices/>.
*/
#ifndef LSST_QSERV_CZAR_HTTPCZARINGESTMODULE_H
#define LSST_QSERV_CZAR_HTTPCZARINGESTMODULE_H
#ifndef LSST_QSERV_CZAR_CHTTPCZARINGESTMODULE_H
#define LSST_QSERV_CZAR_CHTTPCZARINGESTMODULE_H

// System headers
#include <map>
Expand All @@ -32,28 +32,28 @@
#include "nlohmann/json.hpp"

// Qserv headers
#include "http/ChttpModule.h"
#include "http/Method.h"
#include "http/QhttpModule.h"

// Forward declarations

namespace lsst::qserv::http {
class AsyncReq;
} // namespace lsst::qserv::http

namespace lsst::qserv::qhttp {
namespace httplib {
class Request;
class Response;
} // namespace lsst::qserv::qhttp
} // namespace httplib

// This header declarations
namespace lsst::qserv::czar {

/**
* Class HttpCzarIngestModule implements a handler for processing requests for ingesting
* Class ChttpCzarIngestModule implements a handler for processing requests for ingesting
* user-generated data prodicts via the HTTP-based frontend.
*/
class HttpCzarIngestModule : public http::QhttpModule {
class ChttpCzarIngestModule : public http::ChttpModule {
public:
/**
* @note supported values for parameter 'subModuleName' are:
Expand All @@ -64,24 +64,23 @@ class HttpCzarIngestModule : public http::QhttpModule {
* @throws std::invalid_argument for unknown values of parameter 'subModuleName'
*/
static void process(boost::asio::io_service& io_service, std::string const& context,
std::shared_ptr<qhttp::Request> const& req,
std::shared_ptr<qhttp::Response> const& resp, std::string const& subModuleName,
httplib::Request const& req, httplib::Response& resp,
std::string const& subModuleName,
http::AuthType const authType = http::AuthType::NONE);

HttpCzarIngestModule() = delete;
HttpCzarIngestModule(HttpCzarIngestModule const&) = delete;
HttpCzarIngestModule& operator=(HttpCzarIngestModule const&) = delete;
ChttpCzarIngestModule() = delete;
ChttpCzarIngestModule(ChttpCzarIngestModule const&) = delete;
ChttpCzarIngestModule& operator=(ChttpCzarIngestModule const&) = delete;

virtual ~HttpCzarIngestModule() = default;
virtual ~ChttpCzarIngestModule() = default;

protected:
virtual std::string context() const final;
virtual nlohmann::json executeImpl(std::string const& subModuleName) final;

private:
HttpCzarIngestModule(boost::asio::io_service& io_service, std::string const& context,
std::shared_ptr<qhttp::Request> const& req,
std::shared_ptr<qhttp::Response> const& resp);
ChttpCzarIngestModule(boost::asio::io_service& io_service, std::string const& context,
httplib::Request const& req, httplib::Response& resp);

nlohmann::json _ingestData();
nlohmann::json _deleteDatabase();
Expand Down Expand Up @@ -233,4 +232,4 @@ class HttpCzarIngestModule : public http::QhttpModule {

} // namespace lsst::qserv::czar

#endif // LSST_QSERV_CZAR_HTTPCZARINGESTMODULE_H
#endif // LSST_QSERV_CZAR_CHTTPCZARINGESTMODULE_H
Loading

0 comments on commit 54a4933

Please sign in to comment.