mirror of
https://github.com/nginx/nginx.git
synced 2026-10-21 03:21:08 +00:00
Control API: reload support.
A new /control/config endpoint provides configuration reload function
with feedback returned to the user on the outcome.
Example:
$ curl 127.0.0.1:1234/1/control/config -X PATCH -v | jq
< HTTP/1.1 200 OK
< ...
<
{
"logs": []
}
$ curl 127.0.0.1:1234/1/control/config -X PATCH -v | jq
< HTTP/1.1 422 Unprocessable Entity
< ...
<
{
"logs": [
"...: invalid number of arguments in \"listen\" directive"
]
}
Co-authored-by: Pavel Pautov <p.pautov@f5.com>
This commit is contained in:
parent
4bc459a15c
commit
74133fba7c
2 changed files with 153 additions and 5 deletions
|
|
@ -36,6 +36,8 @@ typedef struct {
|
|||
|
||||
ngx_buf_t *in;
|
||||
ngx_chain_t *out;
|
||||
|
||||
ngx_uint_t reloaded;
|
||||
} ngx_control_request_t;
|
||||
|
||||
|
||||
|
|
@ -60,6 +62,9 @@ static ngx_int_t ngx_control_api_endpoints(ngx_control_request_t *r,
|
|||
const char **paths, ngx_int_t npaths);
|
||||
static ngx_int_t ngx_control_show_processes(ngx_control_request_t *r);
|
||||
static ngx_int_t ngx_control_show_version(ngx_control_request_t *r);
|
||||
static ngx_int_t ngx_control_reload_config(ngx_control_request_t *r);
|
||||
static void ngx_control_log_capture(ngx_log_t *log, ngx_uint_t l,
|
||||
u_char *buf, size_t len);
|
||||
|
||||
static ngx_int_t ngx_control_parse_request_line(ngx_control_request_t *r);
|
||||
static ngx_int_t ngx_control_send_json(ngx_control_request_t *r, ngx_int_t code,
|
||||
|
|
@ -288,7 +293,7 @@ ngx_int_t
|
|||
ngx_control_handle_events(void)
|
||||
{
|
||||
int ready, revents;
|
||||
ngx_uint_t i;
|
||||
ngx_uint_t i, reloaded;
|
||||
struct pollfd *pfd;
|
||||
ngx_control_request_t *r;
|
||||
|
||||
|
|
@ -307,6 +312,8 @@ ngx_control_handle_events(void)
|
|||
return NGX_OK;
|
||||
}
|
||||
|
||||
reloaded = 0;
|
||||
|
||||
for (i = 0; i < ngx_control_pollfd_n; /* void */) {
|
||||
|
||||
r = &ngx_control_requests[i];
|
||||
|
|
@ -317,6 +324,10 @@ ngx_control_handle_events(void)
|
|||
"control: i:%ui fd:%d e:%d re:%d",
|
||||
i, pfd->fd, pfd->events, pfd->revents);
|
||||
|
||||
if (i) {
|
||||
r->pool->log = ngx_cycle->log;
|
||||
}
|
||||
|
||||
if ((revents & (POLLERR|POLLHUP|POLLNVAL)) && i != 0) {
|
||||
ngx_control_close(r);
|
||||
continue;
|
||||
|
|
@ -330,9 +341,12 @@ ngx_control_handle_events(void)
|
|||
}
|
||||
|
||||
if (ngx_control_handle_read(r) != NGX_AGAIN) {
|
||||
reloaded |= r->reloaded;
|
||||
ngx_control_close(r);
|
||||
continue;
|
||||
}
|
||||
|
||||
reloaded |= r->reloaded;
|
||||
}
|
||||
|
||||
if (revents & POLLOUT) {
|
||||
|
|
@ -345,7 +359,7 @@ ngx_control_handle_events(void)
|
|||
i++;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
return reloaded ? NGX_DONE : NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -562,7 +576,7 @@ ngx_control_content(ngx_control_request_t *r)
|
|||
|
||||
static const char *root_endpoints[] = { "1" };
|
||||
static const char *api_endpoints[] = { "control", "nginx" };
|
||||
static const char *control_endpoints[] = { "processes" };
|
||||
static const char *control_endpoints[] = { "processes", "config" };
|
||||
|
||||
p = r->path.data;
|
||||
len = r->path.len;
|
||||
|
|
@ -609,7 +623,18 @@ ngx_control_content(ngx_control_request_t *r)
|
|||
return ngx_control_send_response(r, NGX_CTRL_NOT_ALLOWED, NULL);
|
||||
}
|
||||
|
||||
return ngx_control_api_endpoints(r, control_endpoints, 1);
|
||||
return ngx_control_api_endpoints(r, control_endpoints, 2);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 17:
|
||||
if (ngx_strncmp(p, "/1/control/config", len) == 0) {
|
||||
if (r->method != NGX_CTRL_PATCH) {
|
||||
return ngx_control_send_response(r, NGX_CTRL_NOT_ALLOWED, NULL);
|
||||
}
|
||||
|
||||
return ngx_control_reload_config(r);
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -836,6 +861,115 @@ ngx_control_show_version(ngx_control_request_t *r)
|
|||
}
|
||||
|
||||
|
||||
static ngx_data_item_t *
|
||||
ngx_control_json_logs(ngx_array_t *logs)
|
||||
{
|
||||
ngx_str_t *l;
|
||||
ngx_uint_t i;
|
||||
ngx_data_item_t *obj, *log_list, *log;
|
||||
|
||||
static ngx_str_t logs_field = ngx_string("logs");
|
||||
|
||||
obj = ngx_data_new_object(logs->pool);
|
||||
if (obj == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log_list = ngx_data_new_list(logs->pool);
|
||||
if (log_list == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
l = logs->elts;
|
||||
for (i = 0; i < logs->nelts; i++) {
|
||||
log = ngx_data_string_handler((uintptr_t) &l[i], logs->pool, NULL);
|
||||
if (log == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ngx_data_add_item(log_list, NULL, log);
|
||||
}
|
||||
|
||||
ngx_data_add_item(obj, &logs_field, log_list);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_control_reload_config(ngx_control_request_t *r)
|
||||
{
|
||||
ngx_int_t status;
|
||||
ngx_log_t log, *tmp;
|
||||
ngx_cycle_t *cycle;
|
||||
ngx_array_t log_store;
|
||||
ngx_data_item_t *obj;
|
||||
|
||||
status = NGX_CTRL_OK;
|
||||
|
||||
if (ngx_array_init(&log_store, r->pool, 3, sizeof(ngx_str_t)) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memzero(&log, sizeof(ngx_log_t));
|
||||
log.wdata = &log_store;
|
||||
log.writer = ngx_control_log_capture;
|
||||
log.log_level = NGX_LOG_DEBUG;
|
||||
|
||||
tmp = ngx_cycle->log;
|
||||
log.next = tmp;
|
||||
ngx_cycle->log = &log;
|
||||
cycle = ngx_init_cycle((ngx_cycle_t *) ngx_cycle);
|
||||
|
||||
if (cycle == NULL) {
|
||||
status = NGX_CTRL_UNPROCESSABLE;
|
||||
ngx_cycle->log = tmp;
|
||||
|
||||
} else {
|
||||
ngx_cycle = cycle;
|
||||
r->reloaded = 1;
|
||||
r->pool->log = ngx_cycle->log;
|
||||
}
|
||||
|
||||
obj = ngx_control_json_logs(&log_store);
|
||||
if (obj == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return ngx_control_send_json(r, status, obj);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_control_log_capture(ngx_log_t *log, ngx_uint_t lvl, u_char *buf, size_t len)
|
||||
{
|
||||
u_char *log_data;
|
||||
ngx_str_t *log_str;
|
||||
ngx_array_t *store;
|
||||
|
||||
if (lvl > NGX_LOG_WARN) {
|
||||
return;
|
||||
}
|
||||
|
||||
store = log->wdata;
|
||||
|
||||
log_data = ngx_pnalloc(store->pool, len);
|
||||
if (log_data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
log_str = ngx_array_push(store);
|
||||
if (log_str == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_memcpy(log_data, buf, len);
|
||||
|
||||
log_str->data = log_data;
|
||||
log_str->len = len;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_control_parse_request_line(ngx_control_request_t *r)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -178,7 +178,21 @@ ngx_master_process_cycle(ngx_cycle_t *cycle)
|
|||
if (ngx_sigio) {
|
||||
ngx_sigio = 0;
|
||||
|
||||
ngx_control_handle_events();
|
||||
if (ngx_control_handle_events() == NGX_DONE) {
|
||||
cycle = (ngx_cycle_t *) ngx_cycle;
|
||||
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx,
|
||||
ngx_core_module);
|
||||
ngx_start_worker_processes(cycle, ccf->worker_processes,
|
||||
NGX_PROCESS_JUST_RESPAWN);
|
||||
ngx_start_cache_manager_processes(cycle, 1);
|
||||
|
||||
/* allow new processes to start */
|
||||
ngx_msleep(100);
|
||||
|
||||
live = 1;
|
||||
ngx_signal_worker_processes(cycle,
|
||||
ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue