summaryrefslogtreecommitdiffabout
path: root/src/ctl.c
authorSergey Poznyakoff <gray@gnu.org.ua>2016-02-20 20:33:00 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2016-02-20 20:42:46 (GMT)
commit46130027d8e6e91951226456174e6ad471ddc50f (patch) (side-by-side diff)
treef88ce6edd9b078b5f331497bc452525f3c4c9c94 /src/ctl.c
parente6902abfddb4d7b16dc9a4231a3781f354a08cd5 (diff)
downloadpies-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') (more/less context) (ignore whitespace changes)
-rw-r--r--src/ctl.c246
1 files changed, 246 insertions, 0 deletions
diff --git a/src/ctl.c b/src/ctl.c
index 54282a2..3cbe459 100644
--- a/src/ctl.c
+++ b/src/ctl.c
@@ -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);
+}

Return to:

Send suggestions and report system problems to the System administrator.