Skip to content

Commit 9b6e795

Browse files
committed
parse expiration time and reload config at time out
1 parent 786463b commit 9b6e795

1 file changed

Lines changed: 121 additions & 1 deletion

File tree

plugins/s3_auth/s3_auth.cc

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@
3737
#include <openssl/sha.h>
3838
#include <openssl/hmac.h>
3939

40+
#include <chrono>
41+
#include <atomic>
42+
#include <mutex>
43+
#include <shared_mutex>
44+
4045
#include <ts/ts.h>
4146
#include <ts/remap.h>
4247
#include "tscore/ink_config.h"
@@ -153,6 +158,7 @@ ConfigCache gConfCache;
153158
// One configuration setup
154159
//
155160
int event_handler(TSCont, TSEvent, void *); // Forward declaration
161+
int config_reloader(TSCont, TSEvent, void *);
156162

157163
class S3Config
158164
{
@@ -162,6 +168,9 @@ class S3Config
162168
if (get_cont) {
163169
_cont = TSContCreate(event_handler, nullptr);
164170
TSContDataSet(_cont, static_cast<void *>(this));
171+
172+
_conf_rld = TSContCreate(config_reloader, TSMutexCreate());
173+
TSContDataSet(_conf_rld, static_cast<void *>(this));
165174
}
166175
}
167176

@@ -171,9 +180,13 @@ class S3Config
171180
TSfree(_secret);
172181
TSfree(_keyid);
173182
TSfree(_token);
183+
TSfree(_conf_fname);
174184
if (_cont) {
175185
TSContDestroy(_cont);
176186
}
187+
if (_conf_rld) {
188+
TSContDestroy(_conf_rld);
189+
}
177190
}
178191

179192
// Is this configuration usable?
@@ -212,16 +225,19 @@ class S3Config
212225
copy_changes_from(const S3Config *src)
213226
{
214227
if (src->_secret) {
228+
TSfree(_secret);
215229
_secret = TSstrdup(src->_secret);
216230
_secret_len = src->_secret_len;
217231
}
218232

219233
if (src->_keyid) {
234+
TSfree(_keyid);
220235
_keyid = TSstrdup(src->_keyid);
221236
_keyid_len = src->_keyid_len;
222237
}
223238

224239
if (src->_token) {
240+
TSfree(_token);
225241
_token = TSstrdup(src->_token);
226242
_token_len = src->_token_len;
227243
}
@@ -250,6 +266,13 @@ class S3Config
250266
_region_map = src->_region_map;
251267
_region_map_modified = true;
252268
}
269+
270+
_expiration = src->_expiration;
271+
272+
if (src->_conf_fname) {
273+
TSfree(_conf_fname);
274+
_conf_fname = TSstrdup(src->_conf_fname);
275+
}
253276
}
254277

255278
// Getters
@@ -319,6 +342,18 @@ class S3Config
319342
return _region_map;
320343
}
321344

345+
long
346+
expiration() const
347+
{
348+
return _expiration;
349+
}
350+
351+
const char *
352+
conf_fname() const
353+
{
354+
return _conf_fname;
355+
}
356+
322357
// Setters
323358
void
324359
set_secret(const char *s)
@@ -380,6 +415,19 @@ class S3Config
380415
_region_map_modified = true;
381416
}
382417

418+
void
419+
set_expiration(const char *s)
420+
{
421+
_expiration = strtol(s, nullptr, 10);
422+
}
423+
424+
void
425+
set_conf_fname(const char *s)
426+
{
427+
TSfree(_conf_fname);
428+
_conf_fname = TSstrdup(s);
429+
}
430+
383431
// Parse configs from an external file
384432
bool parse_config(const std::string &filename);
385433

@@ -391,6 +439,15 @@ class S3Config
391439
TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_REQUEST_HDR_HOOK, _cont);
392440
}
393441

442+
void
443+
schedule_conf_reload(long delay) const
444+
{
445+
TSContScheduleOnPool(_conf_rld, delay * 1000, TS_THREAD_POOL_NET);
446+
}
447+
448+
std::shared_mutex reload_mutex;
449+
std::atomic_bool reload_waiting = false;
450+
394451
private:
395452
char *_secret = nullptr;
396453
size_t _secret_len = 0;
@@ -403,12 +460,15 @@ class S3Config
403460
bool _version_modified = false;
404461
bool _virt_host_modified = false;
405462
TSCont _cont = nullptr;
463+
TSCont _conf_rld = nullptr;
406464
StringSet _v4includeHeaders;
407465
bool _v4includeHeaders_modified = false;
408466
StringSet _v4excludeHeaders;
409467
bool _v4excludeHeaders_modified = false;
410468
StringMap _region_map;
411469
bool _region_map_modified = false;
470+
long _expiration = 0;
471+
char *_conf_fname = nullptr;
412472
};
413473

414474
bool
@@ -465,6 +525,8 @@ S3Config::parse_config(const std::string &config_fname)
465525
set_exclude_headers(pos2 + 19);
466526
} else if (0 == strncasecmp(pos2, "v4-region-map=", 14)) {
467527
set_region_map(pos2 + 14);
528+
} else if (0 == strncasecmp(pos2, "expiration=", 11)) {
529+
set_expiration(pos2 + 11);
468530
} else {
469531
// ToDo: warnings?
470532
}
@@ -499,6 +561,7 @@ ConfigCache::get(const char *fname)
499561
if (tv.tv_sec > (it->second.second + _ttl)) {
500562
// Update the cached configuration file.
501563
S3Config *s3 = new S3Config(false); // false == this config does not get the continuation
564+
s3->set_conf_fname(fname);
502565

503566
TSDebug(PLUGIN_NAME, "Configuration from %s is stale, reloading", config_fname.c_str());
504567
it->second.second = tv.tv_sec;
@@ -516,6 +579,7 @@ ConfigCache::get(const char *fname)
516579
} else {
517580
// Create a new cached file.
518581
S3Config *s3 = new S3Config(false); // false == this config does not get the continuation
582+
s3->set_conf_fname(fname);
519583

520584
if (s3->parse_config(config_fname)) {
521585
_cache[config_fname] = std::make_pair(s3, tv.tv_sec);
@@ -876,7 +940,13 @@ event_handler(TSCont cont, TSEvent event, void *edata)
876940
switch (event) {
877941
case TS_EVENT_HTTP_SEND_REQUEST_HDR:
878942
if (request.initialize()) {
879-
status = request.authorize(s3);
943+
while (true) {
944+
if (!s3->reload_waiting) {
945+
std::shared_lock lock(s3->reload_mutex);
946+
status = request.authorize(s3);
947+
break;
948+
}
949+
}
880950
}
881951

882952
if (TS_HTTP_STATUS_OK == status) {
@@ -897,6 +967,42 @@ event_handler(TSCont cont, TSEvent event, void *edata)
897967
return 0;
898968
}
899969

970+
int
971+
config_reloader(TSCont cont, TSEvent event, void *edata)
972+
{
973+
TSDebug(PLUGIN_NAME, "reloading configs");
974+
S3Config *s3 = static_cast<S3Config *>(TSContDataGet(cont));
975+
S3Config *file_config = gConfCache.get(s3->conf_fname());
976+
977+
if (!file_config->valid()) {
978+
TSError("[%s] requires both shared and AWS secret configuration", PLUGIN_NAME);
979+
return TS_ERROR;
980+
}
981+
982+
s3->reload_waiting = true;
983+
{
984+
std::unique_lock lock(s3->reload_mutex);
985+
s3->copy_changes_from(file_config);
986+
}
987+
s3->reload_waiting = false;
988+
989+
if (s3->expiration() == 0) {
990+
TSDebug(PLUGIN_NAME, "disabling auto config reload");
991+
} else {
992+
long delay = s3->expiration() -
993+
std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
994+
if (delay > 0) {
995+
TSDebug(PLUGIN_NAME, "scheduling config reload with %ld seconds delay", delay);
996+
s3->schedule_conf_reload(delay);
997+
} else {
998+
TSDebug(PLUGIN_NAME, "expiration time is in the past, re-checking in 10 seconds");
999+
s3->schedule_conf_reload(10);
1000+
}
1001+
}
1002+
1003+
return TS_SUCCESS;
1004+
}
1005+
9001006
///////////////////////////////////////////////////////////////////////////////
9011007
// Initialize the plugin.
9021008
//
@@ -1000,6 +1106,20 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char * /* errbuf ATS_UNUSE
10001106
return TS_ERROR;
10011107
}
10021108

1109+
if (s3->expiration() == 0) {
1110+
TSDebug(PLUGIN_NAME, "disabling auto config reload");
1111+
} else {
1112+
long delay = s3->expiration() -
1113+
std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
1114+
if (delay > 0) {
1115+
TSDebug(PLUGIN_NAME, "scheduling config reload with %ld seconds delay", delay);
1116+
s3->schedule_conf_reload(delay);
1117+
} else {
1118+
TSDebug(PLUGIN_NAME, "expiration time is in the past, re-checking in 10 seconds");
1119+
s3->schedule_conf_reload(10);
1120+
}
1121+
}
1122+
10031123
*ih = static_cast<void *>(s3);
10041124
TSDebug(PLUGIN_NAME, "New rule: access_key=%s, virtual_host=%s, version=%d", s3->keyid(), s3->virt_host() ? "yes" : "no",
10051125
s3->version());

0 commit comments

Comments
 (0)