nghttpx: Add configrevision API endpoint
This commit adds configuration revision, which is considered opaque string, and changes after reloading configuration with SIGHUP. This revision is returned as a response to configrevision API endpoint. This allows external application to know whether nghttpx has finished reloading new configuration or not. Note that this revision does not change on backendconfig API calls.
This commit is contained in:
parent
dc15832030
commit
450ffaa6f0
|
@ -2942,6 +2942,7 @@ void reload_config(WorkerProcess *wp) {
|
|||
new_config->daemon = cur_config->daemon;
|
||||
// loop is reused, and ev_loop_flags gets ignored
|
||||
new_config->ev_loop_flags = cur_config->ev_loop_flags;
|
||||
new_config->config_revision = cur_config->config_revision + 1;
|
||||
|
||||
rv = process_options(new_config.get(), suconfig.cmdcfgs);
|
||||
if (rv != 0) {
|
||||
|
|
|
@ -41,6 +41,10 @@ const APIEndpoint apis[] = {
|
|||
(1 << API_METHOD_POST) | (1 << API_METHOD_PUT),
|
||||
&APIDownstreamConnection::handle_backendconfig,
|
||||
},
|
||||
APIEndpoint{
|
||||
StringRef::from_lit("/api/v1beta1/configrevision"), true,
|
||||
(1 << API_METHOD_GET), &APIDownstreamConnection::handle_configrevision,
|
||||
},
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
@ -82,7 +86,7 @@ enum {
|
|||
};
|
||||
|
||||
int APIDownstreamConnection::send_reply(unsigned int http_status,
|
||||
int api_status) {
|
||||
int api_status, const StringRef &data) {
|
||||
shutdown_read_ = true;
|
||||
|
||||
auto upstream = downstream_->get_upstream();
|
||||
|
@ -112,7 +116,8 @@ int APIDownstreamConnection::send_reply(unsigned int http_status,
|
|||
|
||||
// 3 is the number of digits in http_status, assuming it is 3 digits
|
||||
// number.
|
||||
auto buflen = M1.size() + M2.size() + M3.size() + api_status_str.size() + 3;
|
||||
auto buflen = M1.size() + M2.size() + M3.size() + data.size() +
|
||||
api_status_str.size() + 3;
|
||||
|
||||
auto buf = make_byte_ref(balloc, buflen);
|
||||
auto p = buf.base;
|
||||
|
@ -121,6 +126,7 @@ int APIDownstreamConnection::send_reply(unsigned int http_status,
|
|||
p = std::copy(std::begin(api_status_str), std::end(api_status_str), p);
|
||||
p = std::copy(std::begin(M2), std::end(M2), p);
|
||||
p = util::utos(p, http_status);
|
||||
p = std::copy(std::begin(data), std::end(data), p);
|
||||
p = std::copy(std::begin(M3), std::end(M3), p);
|
||||
|
||||
buf.len = p - buf.base;
|
||||
|
@ -147,6 +153,32 @@ int APIDownstreamConnection::send_reply(unsigned int http_status,
|
|||
return 0;
|
||||
}
|
||||
|
||||
namespace {
|
||||
const APIEndpoint *lookup_api(const StringRef &path) {
|
||||
switch (path.size()) {
|
||||
case 26:
|
||||
switch (path[25]) {
|
||||
case 'g':
|
||||
if (util::streq_l("/api/v1beta1/backendconfi", std::begin(path), 25)) {
|
||||
return &apis[0];
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 27:
|
||||
switch (path[26]) {
|
||||
case 'n':
|
||||
if (util::streq_l("/api/v1beta1/configrevisio", std::begin(path), 26)) {
|
||||
return &apis[1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int APIDownstreamConnection::push_request_headers() {
|
||||
auto &req = downstream_->request();
|
||||
|
||||
|
@ -154,12 +186,7 @@ int APIDownstreamConnection::push_request_headers() {
|
|||
StringRef{std::begin(req.path),
|
||||
std::find(std::begin(req.path), std::end(req.path), '?')};
|
||||
|
||||
for (auto &p : apis) {
|
||||
if (p.path == path) {
|
||||
api_ = &p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
api_ = lookup_api(path);
|
||||
|
||||
if (!api_) {
|
||||
send_reply(404, API_FAILURE);
|
||||
|
@ -365,6 +392,25 @@ int APIDownstreamConnection::handle_backendconfig() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int APIDownstreamConnection::handle_configrevision() {
|
||||
auto config = get_config();
|
||||
auto &balloc = downstream_->get_block_allocator();
|
||||
|
||||
// Construct the following string:
|
||||
// ,
|
||||
// "data":{
|
||||
// "configRevision": N
|
||||
// }
|
||||
auto data = concat_string_ref(
|
||||
balloc, StringRef::from_lit(R"(,"data":{"configRevision":)"),
|
||||
util::make_string_ref_uint(balloc, config->config_revision),
|
||||
StringRef::from_lit("}"));
|
||||
|
||||
send_reply(200, API_SUCCESS, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void APIDownstreamConnection::pause_read(IOCtrlReason reason) {}
|
||||
|
||||
int APIDownstreamConnection::resume_read(IOCtrlReason reason, size_t consumed) {
|
||||
|
|
|
@ -83,11 +83,14 @@ public:
|
|||
get_downstream_addr_group() const;
|
||||
virtual DownstreamAddr *get_addr() const;
|
||||
|
||||
int send_reply(unsigned int http_status, int api_status);
|
||||
int send_reply(unsigned int http_status, int api_status,
|
||||
const StringRef &data = StringRef{});
|
||||
int error_method_not_allowed();
|
||||
|
||||
// Handles backendconfig API request.
|
||||
int handle_backendconfig();
|
||||
// Handles configrevision API request.
|
||||
int handle_configrevision();
|
||||
|
||||
private:
|
||||
Worker *worker_;
|
||||
|
|
|
@ -850,6 +850,7 @@ struct Config {
|
|||
conn{},
|
||||
api{},
|
||||
dns{},
|
||||
config_revision{0},
|
||||
num_worker{0},
|
||||
padding{0},
|
||||
rlimit_nofile{0},
|
||||
|
@ -883,6 +884,13 @@ struct Config {
|
|||
StringRef conf_path;
|
||||
StringRef user;
|
||||
StringRef mruby_file;
|
||||
// The revision of configuration which is opaque string, and changes
|
||||
// on each configuration reloading. This does not change on
|
||||
// backendconfig API call. This value is returned in health check
|
||||
// as "nghttpx-conf-rev" response header field. The external
|
||||
// program can check this value to know whether reloading has
|
||||
// completed or not.
|
||||
uint64_t config_revision;
|
||||
size_t num_worker;
|
||||
size_t padding;
|
||||
size_t rlimit_nofile;
|
||||
|
|
Loading…
Reference in New Issue