Skip to content

Commit cfe0158

Browse files
committed
CCDB: improved support for CI Security Proxy
* Fix support for multiurl CCDB backends * Add ability to specify Gate Token also for DELETE / PUT operations * Fix hardcoded URL in test
1 parent 9cda446 commit cfe0158

2 files changed

Lines changed: 48 additions & 7 deletions

File tree

CCDB/src/CcdbApi.cxx

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,16 +1300,21 @@ void CcdbApi::deleteObject(std::string const& path, long timestamp) const
13001300
{
13011301
CURL* curl;
13021302
CURLcode res;
1303-
stringstream fullUrl;
13041303
long timestampLocal = timestamp == -1 ? getCurrentTimestamp() : timestamp;
13051304

13061305
curl = curl_easy_init();
13071306
if (curl != nullptr) {
13081307
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
13091308
curl_easy_setopt(curl, CURLOPT_USERAGENT, mUniqueAgentID.c_str());
1309+
// A DELETE is a write, so it needs the gate token as storing does.
1310+
struct curl_slist* list = appendGateToken(nullptr);
1311+
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
13101312
curlSetSSLOptions(curl);
13111313

13121314
for (size_t hostIndex = 0; hostIndex < hostsPool.size(); hostIndex++) {
1315+
// Inside the loop: hoisted out, the stream accumulates and the second
1316+
// host's URL is the first with the second appended.
1317+
stringstream fullUrl;
13131318
fullUrl << getHostUrl(hostIndex) << "/" << path << "/" << timestampLocal;
13141319
curl_easy_setopt(curl, CURLOPT_URL, fullUrl.str().c_str());
13151320

@@ -1318,17 +1323,23 @@ void CcdbApi::deleteObject(std::string const& path, long timestamp) const
13181323
if (res != CURLE_OK) {
13191324
LOGP(alarm, "CURL_perform() failed: {}", curl_easy_strerror(res));
13201325
}
1321-
curl_easy_cleanup(curl);
13221326
}
1327+
// After the loop, not inside it: cleaning up per host left every later
1328+
// iteration using a freed handle.
1329+
curl_easy_cleanup(curl);
1330+
curl_slist_free_all(list);
13231331
}
13241332
}
13251333

13261334
void CcdbApi::truncate(std::string const& path) const
13271335
{
13281336
CURL* curl;
13291337
CURLcode res;
1330-
stringstream fullUrl;
13311338
for (size_t i = 0; i < hostsPool.size(); i++) {
1339+
// Declared inside the loop: a stringstream hoisted out of it accumulates,
1340+
// so the second host's URL would be the first one with the second appended
1341+
// to it. Latent until now -- every caller used a single-host pool.
1342+
stringstream fullUrl;
13321343
std::string url = getHostUrl(i);
13331344
fullUrl << url << "/truncate/" << path;
13341345

@@ -1337,6 +1348,13 @@ void CcdbApi::truncate(std::string const& path) const
13371348
if (curl != nullptr) {
13381349
curl_easy_setopt(curl, CURLOPT_URL, fullUrl.str().c_str());
13391350

1351+
// Truncating is a write, so it needs the gate token exactly as storing
1352+
// does. This was the one write path left without it, which a broker
1353+
// answers 401 -- failing every CCDB suite in their teardown, since each
1354+
// one truncates the path it just wrote.
1355+
struct curl_slist* list = appendGateToken(nullptr);
1356+
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
1357+
13401358
curlSetSSLOptions(curl);
13411359

13421360
// Perform the request, res will get the return code
@@ -1345,6 +1363,7 @@ void CcdbApi::truncate(std::string const& path) const
13451363
LOGP(alarm, "CURL_perform() failed: {}", curl_easy_strerror(res));
13461364
}
13471365
curl_easy_cleanup(curl);
1366+
curl_slist_free_all(list);
13481367
}
13491368
}
13501369
}
@@ -1363,8 +1382,15 @@ bool CcdbApi::isHostReachable() const
13631382
curl = curl_easy_init();
13641383
curl_easy_setopt(curl, CURLOPT_USERAGENT, mUniqueAgentID.c_str());
13651384
if (curl) {
1385+
// Each host in turn, not mUrl: mUrl holds whatever was passed to init(),
1386+
// which for a failover setup is the whole comma-separated list. curl
1387+
// rejects that as malformed (CURLE_URL_MALFORMAT), so every multi-host
1388+
// instance reported itself unreachable no matter how healthy its hosts
1389+
// were -- and testCcdbApiMultipleUrls, whose cases are gated on this,
1390+
// silently skipped instead of running.
13661391
for (size_t hostIndex = 0; hostIndex < hostsPool.size() && res != CURLE_OK; hostIndex++) {
1367-
curl_easy_setopt(curl, CURLOPT_URL, mUrl.data());
1392+
std::string url = getHostUrl(hostIndex);
1393+
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
13681394
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
13691395
curlSetSSLOptions(curl);
13701396
res = CURL_perform(curl);
@@ -1661,8 +1687,12 @@ int CcdbApi::updateMetadata(std::string const& path, std::map<std::string, std::
16611687
curl_easy_setopt(curl, CURLOPT_USERAGENT, mUniqueAgentID.c_str());
16621688
if (curl != nullptr) {
16631689
CURLcode res;
1664-
stringstream fullUrl;
1690+
// A PUT is a write, so it needs the gate token as storing does.
1691+
struct curl_slist* list = appendGateToken(nullptr);
16651692
for (size_t hostIndex = 0; hostIndex < hostsPool.size(); hostIndex++) {
1693+
// Inside the loop: hoisted out, the stream accumulates and the second
1694+
// host's URL is the first with the second appended.
1695+
stringstream fullUrl;
16661696
fullUrl << getHostUrl(hostIndex) << "/" << path << "/" << timestamp;
16671697
if (newEOV > 0) {
16681698
fullUrl << "/" << newEOV;
@@ -1689,6 +1719,7 @@ int CcdbApi::updateMetadata(std::string const& path, std::map<std::string, std::
16891719
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); // make sure we use PUT
16901720
curl_easy_setopt(curl, CURLOPT_USERAGENT, mUniqueAgentID.c_str());
16911721
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
1722+
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
16921723
curlSetSSLOptions(curl);
16931724

16941725
// Perform the request, res will get the return code
@@ -1699,9 +1730,12 @@ int CcdbApi::updateMetadata(std::string const& path, std::map<std::string, std::
16991730
} else {
17001731
ret = 0;
17011732
}
1702-
curl_easy_cleanup(curl);
17031733
}
17041734
}
1735+
// After the loop, not inside it: cleaning up per host left every later
1736+
// iteration using a freed handle.
1737+
curl_easy_cleanup(curl);
1738+
curl_slist_free_all(list);
17051739
}
17061740
return ret;
17071741
}

CCDB/test/testCcdbApiMultipleUrls.cxx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "CCDB/CCDBTimeStampUtils.h"
1818
#include <boost/test/unit_test.hpp>
1919
#include <cstdio>
20+
#include <cstdlib>
2021
#include <TH1F.h>
2122

2223
using namespace std;
@@ -35,7 +36,13 @@ struct Fixture {
3536
Fixture()
3637
{
3738
CcdbApi api;
38-
ccdbUrl = "https://localhost:22,https://localhost:8080,http://ccdb-test.cern.ch:8080";
39+
// This suite uploads, so it needs a WRITABLE instance -- ccdb-test by
40+
// default, not the official CCDB. Only the LAST entry is configurable:
41+
// what is under test here is the failover, so the two dead endpoints in
42+
// front of it are part of the fixture and stay hardcoded.
43+
const char* host = std::getenv("ALICEO2_CCDB_HOST");
44+
ccdbUrl = "https://localhost:22,https://localhost:8080,";
45+
ccdbUrl += host ? host : "http://ccdb-test.cern.ch:8080";
3946
api.init(ccdbUrl);
4047
cout << "ccdb url: " << ccdbUrl << endl;
4148
hostReachable = api.isHostReachable();

0 commit comments

Comments
 (0)