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:
Tatsuhiro Tsujikawa 2017-02-15 23:23:48 +09:00
parent dc15832030
commit 450ffaa6f0
4 changed files with 67 additions and 9 deletions

View File

@ -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) {

View File

@ -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) {

View File

@ -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_;

View File

@ -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;