diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-02-20 22:33:00 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-02-20 22:42:46 +0200 |
commit | 46130027d8e6e91951226456174e6ad471ddc50f (patch) | |
tree | f88ce6edd9b078b5f331497bc452525f3c4c9c94 /src/ctl.c | |
parent | e6902abfddb4d7b16dc9a4231a3781f354a08cd5 (diff) | |
download | pies-46130027d8e6e91951226456174e6ad471ddc50f.tar.gz pies-46130027d8e6e91951226456174e6ad471ddc50f.tar.bz2 |
Improve control interface
This commit implements the following operations on the new /conf endpoints:
GET /conf/runtime - List configuration
PUT /conf/runtime - Reload configuration
POST /conf/runtime - Post new configuration
GET /conf/files - List configuration files
DELETE /conf/files - Delete some or all configuration files
from the list
POST /conf/files - Install new configuration file
Piesctl supports the following new commands:
piesctl config reload
piesctl config file clear
piesctl config file add SYNTAX NAME
piesctl config file del[ete] NAME [NAME...]
piesctl config file list
* src/ctl.c (res_conf): New function.
(restab): New endpoint /conf
* src/pies.c (config_file_add): Set free_entry.
(config_file_remove, config_file_remove_all)
(config_file_list_serialize): New functions.
(pies_config_parse): Bail out if tree processing fails.
(pies_reload): Remove unused function.
(main): Redo ACTION_RELOAD handling.
Handle ACTION_COMMIT.
* src/pies.h (ACTION_COMMIT): New action.
(config_file_remove, config_file_remove_all)
(config_file_list_serialize)
(pies_read_config, progman_gc): New protos.
* src/piesctl.c (cmdline_parser_state): New struct
(next_token, peek_token): Take ptr to cmdline_parser_state as argument.
(parse_error, require_token, assert_eol)
(piesctl_format): New functions.
(parse_condition_to_uri): Rewrite using piesctl_format.
New subcommand: config.
Improve help output.
Diffstat (limited to 'src/ctl.c')
-rw-r--r-- | src/ctl.c | 246 |
1 files changed, 246 insertions, 0 deletions
@@ -910,6 +910,8 @@ static void res_programs (struct ctlio *, enum http_method, char const *, struct json_value *); static void res_runlevel (struct ctlio *, enum http_method, char const *, struct json_value *); +static void res_conf (struct ctlio *, enum http_method, char const *, + struct json_value *); static int pred_sysvinit (void); @@ -926,6 +928,7 @@ struct ctlio_resource static struct ctlio_resource restab[] = { #define S(s) #s, (sizeof (#s)-1) { S(/instance), CTL_ADMIN_STATE, NULL, res_instance }, + { S(/conf), CTL_ADMIN_STATE, NULL, res_conf }, { S(/programs), CTL_ADMIN_STATE|CTL_USER_STATE, NULL, res_programs }, { S(/runlevel), CTL_ADMIN_STATE, pred_sysvinit, res_runlevel }, @@ -2107,4 +2110,247 @@ res_runlevel (struct ctlio *io, enum http_method meth, else ctlio_reply (io, 405, NULL); } + +/* GET /conf/runtime - List configuration + * PUT /conf/runtime - Reload configuration + * POST /conf/runtime - Post new configuration + * + * GET /conf/files - List configuration files + * DELETE /conf/files - Delete some or all configuration files + * from the list + * POST /conf/files - Install new list configuration file + */ + +static void +conf_list_files (struct ctlio *io) +{ + io->output.reply = json_new_array (); + io->code = 200; + config_file_list_serialize (io->output.reply); +} +static void +conf_add_file (struct ctlio *io, struct json_value *json) +{ + struct json_value *v; + struct config_syntax *synt; + + if (json->type != json_object) + { + ctlio_reply (io, 400, NULL); + return; + } + if (json_object_get (json, "syntax", &v) || v->type != json_string) + { + ctlio_reply (io, 400, NULL); + return; + } + synt = str_to_config_syntax (v->v.s); + if (!synt) + { + ctlio_reply (io, 400, NULL); + return; + } + if (json_object_get (json, "file", &v) || v->type != json_string) + { + ctlio_reply (io, 400, NULL); + return; + } + + config_file_add (synt, v->v.s); + ctlio_reply (io, 201, NULL); +} + +static void +conf_delete_files (struct ctlio *io, struct json_value *json) +{ + io->code = 200; + io->output.reply = json_reply_create (); + + if ((json->type == json_bool && json->v.b == 1) + || (json->type == json_arr && json_array_size (json) == 0)) + { + config_file_remove_all (); + json_object_set_string (io->output.reply, "status", "OK"); + json_object_set_string (io->output.reply, "message", + "file list cleared"); + } + else if (json->type == json_arr) + { + size_t i, n, fails = 0; + struct json_value *reply; + + n = json_array_size (json); + + /* Check request */ + for (i = 0; i < n; i++) + { + struct json_value *val; + json_array_get (json, i, &val); + if (val->type != json_string) + { + json_object_set_string (io->output.reply, "status", "ER"); + json_object_set_string (io->output.reply, "error_message", + "malformed request"); + return; + } + } + + reply = json_new_array (); + /* Process request */ + for (i = 0; i < n; i++) + { + struct json_value *val; + int rc; + + json_array_get (json, i, &val); + + rc = config_file_remove (val->v.s); + if (rc) + ++fails; + json_array_append (reply, json_new_bool (!rc)); + } + + if (fails == n) + { + json_object_set_string (io->output.reply, "status", "ER"); + json_object_set_string (io->output.reply, "error_message", + "no matching files found"); + json_value_free (reply); + } + else + { + json_object_set_string (io->output.reply, "status", "OK"); + if (fails) + { + json_object_set_string (io->output.reply, "error_message", + "some files not removed"); + json_object_set (io->output.reply, "result", reply); + } + else + json_value_free (reply); + } + } +} + +static void (*saved_diag_fun)(grecs_locus_t const *, int, int, + const char *msg); +static struct json_value *messages; + +static void +reload_diag_fun (grecs_locus_t const *locus, int err, int errcode, + const char *text) +{ + struct json_value *msg = json_new_object (); + + if (locus) + { + struct json_value *ar = json_new_array (); + json_array_append (ar, json_new_string (locus->beg.file)); + json_array_append (ar, json_new_string (locus->end.file)); + json_object_set (msg, "file", ar); + + ar = json_new_array (); + json_array_append (ar, json_new_number (locus->beg.line)); + json_array_append (ar, json_new_number (locus->end.line)); + json_object_set (msg, "line", ar); + + ar = json_new_array (); + json_array_append (ar, json_new_number (locus->beg.col)); + json_array_append (ar, json_new_number (locus->end.col)); + json_object_set (msg, "col", ar); + + json_object_set (msg, "error", json_new_bool (err)); + + if (errcode) + { + json_object_set (msg, "syserrno", + json_new_number (errno)); + json_object_set (msg, "syserrstr", + json_new_string (strerror (errno))); + } + + json_object_set (msg, "message", json_new_string (text)); + json_array_append (messages, msg); + } + + saved_diag_fun (locus, err, errcode, text); +} + +static void +conf_reload (struct ctlio *io) +{ + io->code = 200; + io->output.reply = json_reply_create (); + + saved_diag_fun = grecs_print_diag_fun; + grecs_print_diag_fun = reload_diag_fun; + messages = json_new_array (); + if (pies_read_config ()) + { + json_object_set_string (io->output.reply, "status", "ER"); + json_object_set_string (io->output.reply, "error_message", + "configuration syntax error"); + } + else + { + pies_schedule_action (ACTION_COMMIT); + json_object_set_string (io->output.reply, "status", "OK"); + json_object_set_string (io->output.reply, "message", + "reload successful"); + } + json_object_set (io->output.reply, "parser_messages", messages); + grecs_print_diag_fun = saved_diag_fun; +} + +static void +res_conf (struct ctlio *io, enum http_method meth, + char const *uri, struct json_value *json) +{ + if (!uri) + { + ctlio_reply (io, 404, NULL); + return; + } + + ++uri; /* skip leading / */ + if (strcmp (uri, "files") == 0) + { + switch (meth) + { + case METH_GET: + conf_list_files (io); + break; + + case METH_POST: + conf_add_file (io, json); + break; + + case METH_DELETE: + conf_delete_files (io, json); + break; + + default: + ctlio_reply (io, 405, NULL); + } + } + else if (strcmp (uri, "runtime") == 0) + { + switch (meth) + { + case METH_GET: + case METH_POST: + ctlio_reply (io, 501, NULL); + break; + + case METH_PUT: + conf_reload (io); + break; + + default: + ctlio_reply (io, 405, NULL); + } + } + else + ctlio_reply (io, 404, NULL); +} |