aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2016-02-20 22:33:00 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2016-02-20 22:42:46 +0200
commit46130027d8e6e91951226456174e6ad471ddc50f (patch)
treef88ce6edd9b078b5f331497bc452525f3c4c9c94
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.
-rw-r--r--src/ctl.c246
-rw-r--r--src/pies.c88
-rw-r--r--src/pies.h10
-rw-r--r--src/piesctl.c612
4 files changed, 787 insertions, 169 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 *,
910 struct json_value *); 910 struct json_value *);
911static void res_runlevel (struct ctlio *, enum http_method, char const *, 911static void res_runlevel (struct ctlio *, enum http_method, char const *,
912 struct json_value *); 912 struct json_value *);
913static void res_conf (struct ctlio *, enum http_method, char const *,
914 struct json_value *);
913 915
914static int pred_sysvinit (void); 916static int pred_sysvinit (void);
915 917
@@ -926,6 +928,7 @@ struct ctlio_resource
926static struct ctlio_resource restab[] = { 928static struct ctlio_resource restab[] = {
927#define S(s) #s, (sizeof (#s)-1) 929#define S(s) #s, (sizeof (#s)-1)
928 { S(/instance), CTL_ADMIN_STATE, NULL, res_instance }, 930 { S(/instance), CTL_ADMIN_STATE, NULL, res_instance },
931 { S(/conf), CTL_ADMIN_STATE, NULL, res_conf },
929 { S(/programs), CTL_ADMIN_STATE|CTL_USER_STATE, NULL, 932 { S(/programs), CTL_ADMIN_STATE|CTL_USER_STATE, NULL,
930 res_programs }, 933 res_programs },
931 { S(/runlevel), CTL_ADMIN_STATE, pred_sysvinit, res_runlevel }, 934 { S(/runlevel), CTL_ADMIN_STATE, pred_sysvinit, res_runlevel },
@@ -2107,4 +2110,247 @@ res_runlevel (struct ctlio *io, enum http_method meth,
2107 else 2110 else
2108 ctlio_reply (io, 405, NULL); 2111 ctlio_reply (io, 405, NULL);
2109} 2112}
2113
2114/* GET /conf/runtime - List configuration
2115 * PUT /conf/runtime - Reload configuration
2116 * POST /conf/runtime - Post new configuration
2117 *
2118 * GET /conf/files - List configuration files
2119 * DELETE /conf/files - Delete some or all configuration files
2120 * from the list
2121 * POST /conf/files - Install new list configuration file
2122 */
2123
2124static void
2125conf_list_files (struct ctlio *io)
2126{
2127 io->output.reply = json_new_array ();
2128 io->code = 200;
2129 config_file_list_serialize (io->output.reply);
2130}
2110 2131
2132static void
2133conf_add_file (struct ctlio *io, struct json_value *json)
2134{
2135 struct json_value *v;
2136 struct config_syntax *synt;
2137
2138 if (json->type != json_object)
2139 {
2140 ctlio_reply (io, 400, NULL);
2141 return;
2142 }
2143 if (json_object_get (json, "syntax", &v) || v->type != json_string)
2144 {
2145 ctlio_reply (io, 400, NULL);
2146 return;
2147 }
2148 synt = str_to_config_syntax (v->v.s);
2149 if (!synt)
2150 {
2151 ctlio_reply (io, 400, NULL);
2152 return;
2153 }
2154 if (json_object_get (json, "file", &v) || v->type != json_string)
2155 {
2156 ctlio_reply (io, 400, NULL);
2157 return;
2158 }
2159
2160 config_file_add (synt, v->v.s);
2161 ctlio_reply (io, 201, NULL);
2162}
2163
2164static void
2165conf_delete_files (struct ctlio *io, struct json_value *json)
2166{
2167 io->code = 200;
2168 io->output.reply = json_reply_create ();
2169
2170 if ((json->type == json_bool && json->v.b == 1)
2171 || (json->type == json_arr && json_array_size (json) == 0))
2172 {
2173 config_file_remove_all ();
2174 json_object_set_string (io->output.reply, "status", "OK");
2175 json_object_set_string (io->output.reply, "message",
2176 "file list cleared");
2177 }
2178 else if (json->type == json_arr)
2179 {
2180 size_t i, n, fails = 0;
2181 struct json_value *reply;
2182
2183 n = json_array_size (json);
2184
2185 /* Check request */
2186 for (i = 0; i < n; i++)
2187 {
2188 struct json_value *val;
2189 json_array_get (json, i, &val);
2190 if (val->type != json_string)
2191 {
2192 json_object_set_string (io->output.reply, "status", "ER");
2193 json_object_set_string (io->output.reply, "error_message",
2194 "malformed request");
2195 return;
2196 }
2197 }
2198
2199 reply = json_new_array ();
2200 /* Process request */
2201 for (i = 0; i < n; i++)
2202 {
2203 struct json_value *val;
2204 int rc;
2205
2206 json_array_get (json, i, &val);
2207
2208 rc = config_file_remove (val->v.s);
2209 if (rc)
2210 ++fails;
2211 json_array_append (reply, json_new_bool (!rc));
2212 }
2213
2214 if (fails == n)
2215 {
2216 json_object_set_string (io->output.reply, "status", "ER");
2217 json_object_set_string (io->output.reply, "error_message",
2218 "no matching files found");
2219 json_value_free (reply);
2220 }
2221 else
2222 {
2223 json_object_set_string (io->output.reply, "status", "OK");
2224 if (fails)
2225 {
2226 json_object_set_string (io->output.reply, "error_message",
2227 "some files not removed");
2228 json_object_set (io->output.reply, "result", reply);
2229 }
2230 else
2231 json_value_free (reply);
2232 }
2233 }
2234}
2235
2236static void (*saved_diag_fun)(grecs_locus_t const *, int, int,
2237 const char *msg);
2238static struct json_value *messages;
2239
2240static void
2241reload_diag_fun (grecs_locus_t const *locus, int err, int errcode,
2242 const char *text)
2243{
2244 struct json_value *msg = json_new_object ();
2245
2246 if (locus)
2247 {
2248 struct json_value *ar = json_new_array ();
2249 json_array_append (ar, json_new_string (locus->beg.file));
2250 json_array_append (ar, json_new_string (locus->end.file));
2251 json_object_set (msg, "file", ar);
2252
2253 ar = json_new_array ();
2254 json_array_append (ar, json_new_number (locus->beg.line));
2255 json_array_append (ar, json_new_number (locus->end.line));
2256 json_object_set (msg, "line", ar);
2257
2258 ar = json_new_array ();
2259 json_array_append (ar, json_new_number (locus->beg.col));
2260 json_array_append (ar, json_new_number (locus->end.col));
2261 json_object_set (msg, "col", ar);
2262
2263 json_object_set (msg, "error", json_new_bool (err));
2264
2265 if (errcode)
2266 {
2267 json_object_set (msg, "syserrno",
2268 json_new_number (errno));
2269 json_object_set (msg, "syserrstr",
2270 json_new_string (strerror (errno)));
2271 }
2272
2273 json_object_set (msg, "message", json_new_string (text));
2274 json_array_append (messages, msg);
2275 }
2276
2277 saved_diag_fun (locus, err, errcode, text);
2278}
2279
2280static void
2281conf_reload (struct ctlio *io)
2282{
2283 io->code = 200;
2284 io->output.reply = json_reply_create ();
2285
2286 saved_diag_fun = grecs_print_diag_fun;
2287 grecs_print_diag_fun = reload_diag_fun;
2288 messages = json_new_array ();
2289 if (pies_read_config ())
2290 {
2291 json_object_set_string (io->output.reply, "status", "ER");
2292 json_object_set_string (io->output.reply, "error_message",
2293 "configuration syntax error");
2294 }
2295 else
2296 {
2297 pies_schedule_action (ACTION_COMMIT);
2298 json_object_set_string (io->output.reply, "status", "OK");
2299 json_object_set_string (io->output.reply, "message",
2300 "reload successful");
2301 }
2302 json_object_set (io->output.reply, "parser_messages", messages);
2303 grecs_print_diag_fun = saved_diag_fun;
2304}
2305
2306static void
2307res_conf (struct ctlio *io, enum http_method meth,
2308 char const *uri, struct json_value *json)
2309{
2310 if (!uri)
2311 {
2312 ctlio_reply (io, 404, NULL);
2313 return;
2314 }
2315
2316 ++uri; /* skip leading / */
2317 if (strcmp (uri, "files") == 0)
2318 {
2319 switch (meth)
2320 {