root/src/noit_conf_checks.c

Revision 7865cee1d9b7182fb2f14d72c16f22b39abd7d99, 41.8 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 3 weeks ago)

If the current metrics in the stats are empty and the previous stats
are not, show the previous metrics (noting that they are old).

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  *       copyright notice, this list of conditions and the following
13  *       disclaimer in the documentation and/or other materials provided
14  *       with the distribution.
15  *     * Neither the name OmniTI Computer Consulting, Inc. nor the names
16  *       of its contributors may be used to endorse or promote products
17  *       derived from this software without specific prior written
18  *       permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "noit_defines.h"
34
35 #include <stdio.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <errno.h>
39 #include <assert.h>
40 #include <libxml/parser.h>
41 #include <libxml/tree.h>
42 #include <libxml/xpath.h>
43
44 #include "noit_conf.h"
45 #include "noit_conf_private.h"
46 #include "noit_conf_checks.h"
47 #include "noit_check.h"
48 #include "noit_check_tools.h"
49 #include "noit_filters.h"
50 #include "noit_console.h"
51 #include "utils/noit_hash.h"
52 #include "utils/noit_log.h"
53
54 static void register_console_config_check_commands();
55
56 static struct _valid_attr_t {
57   const char *scope;
58   const char *name;
59   const char *xpath;
60   int checks_fixate;
61 } valid_attrs[] = {
62   { "/checks", "name", "@name", 0 },
63   { "/checks", "target", "@target", 0 },
64   { "/checks", "period", "@period", 0 },
65   { "/checks", "timeout", "@timeout", 0 },
66   { "/checks", "oncheck", "@oncheck", 0 },
67   { "/checks", "disable", "@disable", 0 },
68   { "/checks", "resolve_rtype", "@resolve_rtype", 0 },
69   { "/checks", "filterset", "@filterset", 0 },
70   { "/checks", "module", "@module", 1 },
71   { "/filtersets", "target", "@target", 0 },
72   { "/filtersets", "module", "@module", 0 },
73   { "/filtersets", "name", "@name", 0 },
74   { "/filtersets", "metric", "@metric", 0 },
75 };
76
77 void
78 noit_console_state_add_check_attrs(noit_console_state_t *state,
79                                    console_cmd_func_t f,
80                                    const char *scope) {
81   int i;
82   for(i = 0;
83       i < sizeof(valid_attrs)/sizeof(valid_attrs[0]);
84       i++) {
85     if(strcmp(valid_attrs[i].scope, scope)) continue;
86     noit_console_state_add_cmd(state,
87       NCSCMD(valid_attrs[i].name, f, NULL,
88              NULL, &valid_attrs[i]));
89   }
90 }
91 static noit_hash_table check_attrs = NOIT_HASH_EMPTY;
92
93 void noit_console_conf_checks_init() {
94   int i;
95   for(i=0;i<sizeof(valid_attrs)/sizeof(*valid_attrs);i++) {
96     noit_hash_store(&check_attrs,
97                     valid_attrs[i].name, strlen(valid_attrs[i].name),
98                     &valid_attrs[i]);
99   }
100   register_console_config_check_commands();
101 }
102
103 static int
104 noit_console_mkcheck_xpath(char *xpath, int len,
105                            noit_conf_t_userdata_t *info,
106                            const char *arg) {
107   int rv;
108   rv = noit_check_xpath(xpath, len, "/", arg);
109   if(rv == -1) return -1;
110   if(rv == 0) {
111     char *path = (!info || !strcmp(info->path, "/")) ? "" : info->path;
112     snprintf(xpath, len, "/noit%s%s%s[@uuid]",
113              path, arg ? "/" : "", arg ? arg : "");
114   }
115   return 0;
116 }
117 static void
118 nc_attr_show(noit_console_closure_t ncct, const char *name, xmlNodePtr cnode,
119              xmlNodePtr anode, const char *value) {
120   char *cpath, *apath;
121   cpath = cnode ? (char *)xmlGetNodePath(cnode) : strdup("");
122   apath = anode ? (char *)xmlGetNodePath(anode) : strdup("");
123   nc_printf(ncct, " %s: %s", name, value ? value : "[undef]");
124   if(value && cpath && apath) {
125     int clen = strlen(cpath);
126     int plen = strlen("/noit/checks/");
127     if(!strncmp(cpath, apath, clen) && apath[clen] == '/') {
128       /* we have a match, which means it isn't inherited */
129     }
130     else {
131       nc_printf(ncct, " [inherited from %s]",
132                 strlen(apath) > plen ? apath + plen : apath);
133     }
134   }
135   nc_write(ncct, "\n", 1);
136   if(cpath) free(cpath);
137   if(apath) free(apath);
138 }
139 static void
140 refresh_subchecks(noit_console_closure_t ncct,
141                   noit_conf_t_userdata_t *info) {
142   char *path;
143   char xpath[1024];
144  
145   path = info->path;
146   if(!strcmp(path, "/")) path = "";
147
148   /* The first one is just a process_checks, the second is the reload.
149    * Reload does a lot of work and there is no need to do it twice.
150    */
151   snprintf(xpath, sizeof(xpath), "/noit/%s[@uuid]", path);
152   noit_poller_process_checks(xpath);
153   snprintf(xpath, sizeof(xpath), "/noit/%s//check[@uuid]", path);
154   noit_poller_reload(xpath);
155 }
156 static int
157 noit_config_check_update_attrs(xmlNodePtr node, int argc, char **argv) {
158   int i, error = 0;
159   if(argc % 2) return -1;
160
161   for(i=0; i<argc; i+=2) {
162     void *vattrinfo;
163     struct _valid_attr_t *attrinfo;
164     char *attr = argv[i], *val = NULL;
165     if(!strcasecmp(argv[i], "no")) attr = argv[i+1];
166     else val = argv[i+1];
167     if(!noit_hash_retrieve(&check_attrs, attr, strlen(attr),
168                            &vattrinfo)) {
169       error = 1;
170       break;
171     }
172     attrinfo = vattrinfo;
173     /* The fixation stuff doesn't matter here, this check is brand-new */
174     xmlUnsetProp(node, (xmlChar *)attrinfo->name);
175     if(val)
176       xmlSetProp(node, (xmlChar *)attrinfo->name, (xmlChar *)val);
177     CONF_DIRTY(node);
178     noit_conf_mark_changed();
179   }
180   return error;
181 }
182
183 static int
184 noit_conf_mkcheck_under(const char *ppath, int argc, char **argv, uuid_t out) {
185   int rv = -1;
186   const char *path;
187   char xpath[1024];
188   xmlXPathContextPtr xpath_ctxt = NULL;
189   xmlXPathObjectPtr pobj = NULL;
190   xmlNodePtr node = NULL, newnode;
191
192   /* attr val [or] no attr (sets of two) */
193   if(argc % 2) goto out;
194
195   noit_conf_xml_xpath(NULL, &xpath_ctxt);
196   path = strcmp(ppath, "/") ? ppath : "";
197   snprintf(xpath, sizeof(xpath), "/noit%s", path);
198   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
199   if(!pobj || pobj->type != XPATH_NODESET ||
200      xmlXPathNodeSetGetLength(pobj->nodesetval) != 1) {
201     goto out;
202   }
203   node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
204   if((newnode = xmlNewChild(node, NULL, (xmlChar *)"check", NULL)) != NULL) {
205     char outstr[37];
206     uuid_generate(out);
207     uuid_unparse_lower(out, outstr);
208     xmlSetProp(newnode, (xmlChar *)"uuid", (xmlChar *)outstr);
209     xmlSetProp(newnode, (xmlChar *)"disable", (xmlChar *)"true");
210
211     /* No risk of running off the end (we checked this above) */
212     if(noit_config_check_update_attrs(newnode, argc, argv)) {
213       /* Something went wrong, remove the node */
214       xmlUnlinkNode(newnode);
215     }
216     else {
217       CONF_DIRTY(newnode);
218       noit_conf_mark_changed();
219       rv = 0;
220     }
221   }
222  out:
223   if(pobj) xmlXPathFreeObject(pobj);
224   return rv;
225 }
226
227 static int
228 noit_console_check(noit_console_closure_t ncct,
229                    int argc, char **argv,
230                    noit_console_state_t *state, void *closure) {
231   int cnt;
232   noit_conf_t_userdata_t *info;
233   char xpath[1024], newuuid_str[37];
234   char *uuid_conf = NULL, *wanted;
235   uuid_t checkid;
236   xmlXPathContextPtr xpath_ctxt = NULL;
237   xmlXPathObjectPtr pobj = NULL;
238   xmlNodePtr node = NULL;
239   noit_boolean creating_new = noit_false;
240
241   if(closure) {
242     char *fake_argv[1] = { ".." };
243     noit_console_state_pop(ncct, 0, argv, NULL, NULL);
244     noit_console_config_cd(ncct, 1, fake_argv, NULL, NULL);
245   }
246
247   noit_conf_xml_xpath(NULL, &xpath_ctxt);
248   if(argc < 1) {
249     nc_printf(ncct, "requires at least one argument\n");
250     return -1;
251   }
252   if(argc % 2 == 0) {
253     nc_printf(ncct, "wrong number of arguments\n");
254     return -1;
255   }
256
257   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
258   wanted = strcmp(argv[0], "new") ? argv[0] : NULL;
259   if(info && !wanted) {
260     /* We are creating a new node */
261     uuid_t out;
262     creating_new = noit_true;
263     if(strncmp(info->path, "/checks/", strlen("/checks/")) &&
264        strcmp(info->path, "/checks")) {
265       nc_printf(ncct, "New checks must be under /checks/\n");
266       return -1;
267     }
268     if(noit_conf_mkcheck_under(info->path, argc - 1, argv + 1, out)) {
269       nc_printf(ncct, "Error creating new check\n");
270       return -1;
271     }
272     newuuid_str[0] = '\0';
273     uuid_unparse_lower(out, newuuid_str);
274     wanted = newuuid_str;
275   }
276   /* We many not be in conf-t mode -- that's fine */
277   if(noit_console_mkcheck_xpath(xpath, sizeof(xpath), info, wanted)) {
278     nc_printf(ncct, "could not find check '%s'\n", wanted);
279     return -1;
280   }
281
282   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
283   if(!pobj || pobj->type != XPATH_NODESET ||
284      xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
285     nc_printf(ncct, "no checks found for '%s'\n", wanted);
286     goto out;
287   }
288   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
289   if(info && cnt != 1) {
290     nc_printf(ncct, "Ambiguous check specified\n");
291     goto out;
292   }
293   node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
294   uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid");
295   if(!uuid_conf || uuid_parse(uuid_conf, checkid)) {
296     nc_printf(ncct, "%s has invalid or missing UUID!\n",
297               (char *)xmlGetNodePath(node) + strlen("/noit"));
298     goto out;
299   }
300   if(argc > 1 && !creating_new)
301     if(noit_config_check_update_attrs(node, argc - 1, argv + 1))
302       nc_printf(ncct, "Partially successful, error setting some attributes\n");
303
304   if(info) {
305     char *xmlpath;
306     if(info->path) free(info->path);
307     xmlpath = (char *)xmlGetNodePath(node);
308     info->path = strdup(xmlpath + strlen("/noit"));
309     free(xmlpath);
310     uuid_copy(info->current_check, checkid);
311     if(argc > 1) refresh_subchecks(ncct, info);
312     if(state) {
313       noit_console_state_push_state(ncct, state);
314       noit_console_state_init(ncct);
315     }
316     goto out;
317   }
318  out:
319   if(uuid_conf) free(uuid_conf);
320   if(pobj) xmlXPathFreeObject(pobj);
321   return 0;
322 }
323 static int
324 noit_console_watch_check(noit_console_closure_t ncct,
325                          int argc, char **argv,
326                          noit_console_state_t *state, void *closure) {
327   int i, cnt;
328   int adding = (int)(vpsized_int)closure;
329   int period = 0;
330   char xpath[1024];
331   xmlXPathObjectPtr pobj = NULL;
332   xmlXPathContextPtr xpath_ctxt = NULL;
333
334   noit_conf_xml_xpath(NULL, &xpath_ctxt);
335   if(argc < 1 || argc > 2) {
336     nc_printf(ncct, "requires one or two arguments\n");
337     return -1;
338   }
339   /* An alternate period */
340   if(argc == 2) period = atoi(argv[1]);
341
342   if(noit_console_mkcheck_xpath(xpath, sizeof(xpath), NULL,
343                                 argc ? argv[0] : NULL)) {
344     nc_printf(ncct, "ERROR: could not find check '%s'\n", argv[0]);
345     return -1;
346   }
347
348   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
349   if(!pobj || pobj->type != XPATH_NODESET ||
350      xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
351     nc_printf(ncct, "no checks found\n");
352     goto out;
353   }
354   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
355   for(i=0; i<cnt; i++) {
356     uuid_t checkid;
357     noit_check_t *check;
358     xmlNodePtr node;
359     char *uuid_conf;
360
361     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
362     uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid");
363     if(!uuid_conf || uuid_parse(uuid_conf, checkid)) {
364       nc_printf(ncct, "%s has invalid or missing UUID!\n",
365                 (char *)xmlGetNodePath(node) + strlen("/noit"));
366       continue;
367     }
368     if(period == 0) {
369       check = noit_poller_lookup(checkid);
370       if(!check) continue;
371       if(adding) noit_check_transient_add_feed(check, ncct->feed_path);
372       else noit_check_transient_remove_feed(check, ncct->feed_path);
373     }
374     else {
375       if(adding) {
376         check = noit_check_watch(checkid, period);
377         /* This check must be watched from the console */
378         noit_check_transient_add_feed(check, ncct->feed_path);
379         /* Note the check */
380         noit_check_log_check(check);
381         /* kick it off, if it isn't running already */
382         if(!NOIT_CHECK_LIVE(check)) noit_check_activate(check);
383       }
384       else {
385         check = noit_check_get_watch(checkid, period);
386         if(check) noit_check_transient_remove_feed(check, ncct->feed_path);
387       }
388     }
389   }
390  out:
391   if(pobj) xmlXPathFreeObject(pobj);
392   return 0;
393 }
394 static int
395 _qsort_string_compare(const void *i1, const void *i2) {
396         const char *s1 = ((const char **)i1)[0];
397         const char *s2 = ((const char **)i2)[0];
398         return strcasecmp(s1, s2);
399 }
400 static int
401 noit_console_show_check(noit_console_closure_t ncct,
402                         int argc, char **argv,
403                         noit_console_state_t *state, void *closure) {
404   int i, cnt;
405   noit_conf_t_userdata_t *info;
406   char xpath[1024];
407   xmlXPathObjectPtr pobj = NULL;
408   xmlXPathContextPtr xpath_ctxt = NULL;
409
410   noit_conf_xml_xpath(NULL, &xpath_ctxt);
411   if(argc > 1) {
412     nc_printf(ncct, "requires zero or one arguments\n");
413     return -1;
414   }
415
416   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
417   /* We many not be in conf-t mode -- that's fine */
418   if(noit_console_mkcheck_xpath(xpath, sizeof(xpath), info,
419                                 argc ? argv[0] : NULL)) {
420     nc_printf(ncct, "could not find check '%s'\n", argv[0]);
421     return -1;
422   }
423
424   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
425   if(!pobj || pobj->type != XPATH_NODESET ||
426      xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
427     nc_printf(ncct, "no checks found\n");
428     goto out;
429   }
430   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
431   if(info && cnt != 1) {
432     nc_printf(ncct, "Ambiguous check specified\n");
433     goto out;
434   }
435   for(i=0; i<cnt; i++) {
436     noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
437     const char *k;
438     int klen;
439     void *data;
440     uuid_t checkid;
441     noit_check_t *check;
442     noit_hash_table *config;
443     xmlNodePtr node, anode, mnode = NULL;
444     char *uuid_conf;
445     char *module, *value;
446
447     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
448     uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid");
449     if(!uuid_conf || uuid_parse(uuid_conf, checkid)) {
450       nc_printf(ncct, "%s has invalid or missing UUID!\n",
451                 (char *)xmlGetNodePath(node) + strlen("/noit"));
452       continue;
453     }
454     nc_printf(ncct, "==== %s ====\n", uuid_conf);
455     free(uuid_conf);
456
457 #define MYATTR(a,n,b) _noit_conf_get_string(node, &(n), "@" #a, &(b))
458 #define INHERIT(a,n,b) \
459   _noit_conf_get_string(node, &(n), "ancestor-or-self::node()/@" #a, &(b))
460 #define SHOW_ATTR(a) do { \
461   anode = NULL; \
462   value = NULL; \
463   INHERIT(a, anode, value); \
464   nc_attr_show(ncct, #a, node, anode, value); \
465   if(value != NULL) free(value); \
466 } while(0)
467
468     if(!INHERIT(module, mnode, module)) module = NULL;
469     if(MYATTR(name, anode, value)) {
470       nc_printf(ncct, " name: %s\n", value);
471       free(value);
472     }
473     else
474       nc_printf(ncct, " name: %s [from module]\n", module ? module : "[undef]");
475     nc_attr_show(ncct, "module", node, mnode, module);
476     if(module) free(module);
477     SHOW_ATTR(target);
478     SHOW_ATTR(resolve_rtype);
479     SHOW_ATTR(period);
480     SHOW_ATTR(timeout);
481     SHOW_ATTR(oncheck);
482     SHOW_ATTR(filterset);
483     SHOW_ATTR(disable);
484     /* Print out all the config settings */
485     config = noit_conf_get_hash(node, "config");
486     while(noit_hash_next(config, &iter, &k, &klen, &data)) {
487       nc_printf(ncct, " config::%s: %s\n", k, (const char *)data);
488     }
489     noit_hash_destroy(config, free, free);
490     free(config);
491
492     check = noit_poller_lookup(checkid);
493     if(!check) {
494       nc_printf(ncct, " ERROR: not in running system\n");
495     }
496     else {
497       int idx = 0;
498       nc_printf(ncct, " target_ip: %s\n", check->target_ip);
499       nc_printf(ncct, " currently: %08x ", check->flags);
500       if(NOIT_CHECK_RUNNING(check)) nc_printf(ncct, "%srunning", idx++?",":"");
501       if(NOIT_CHECK_KILLED(check)) nc_printf(ncct, "%skilled", idx++?",":"");
502       if(!NOIT_CHECK_CONFIGURED(check)) nc_printf(ncct, "%sunconfig", idx++?",":"");
503       if(NOIT_CHECK_DISABLED(check)) nc_printf(ncct, "%sdisabled", idx++?",":"");
504       if(!idx) nc_printf(ncct, "idle");
505       nc_write(ncct, "\n", 1);
506       if (check->fire_event != NULL) {
507         struct timeval now, diff;
508         gettimeofday(&now, NULL);
509         sub_timeval(check->fire_event->whence, now, &diff);
510         nc_printf(ncct, " next run: %0.3f seconds\n",
511                 diff.tv_sec + (diff.tv_usec / 1000000.0));
512       }
513       else {
514         nc_printf(ncct, " next run: unscheduled\n");
515       }
516
517       if(check->stats.current.whence.tv_sec == 0) {
518         nc_printf(ncct, " last run: never\n");
519       }
520       else {
521         stats_t *c = &check->stats.current;
522         int mcount=0;
523         const char **sorted_keys;
524         char buff[256];
525         struct timeval now, diff;
526         noit_boolean filtered;
527
528         gettimeofday(&now, NULL);
529         sub_timeval(now, c->whence, &diff);
530         nc_printf(ncct, " last run: %0.3f seconds ago\n",
531                   diff.tv_sec + (diff.tv_usec / 1000000.0));
532         nc_printf(ncct, " availability/state: %s/%s\n",
533                   noit_check_available_string(c->available),
534                   noit_check_state_string(c->state));
535         nc_printf(ncct, " status: %s\n", c->status ? c->status : "[[null]]");
536         nc_printf(ncct, " feeds: %d\n", check->feeds ? check->feeds->size : 0);
537         nc_printf(ncct, " metrics:\n");
538         if(c->metrics.size == 0 && check->stats.previous.metrics.size > 0) {
539           nc_printf(ncct, " metrics (previous):\n");
540           c = &check->stats.previous;
541         }
542         memset(&iter, 0, sizeof(iter));
543         sorted_keys = alloca(c->metrics.size * sizeof(*sorted_keys));
544         while(noit_hash_next(&c->metrics, &iter, &k, &klen, &data)) {
545           if(sorted_keys) sorted_keys[mcount++] = k;
546           else {
547             noit_stats_snprint_metric(buff, sizeof(buff), (metric_t *)data);
548             filtered = !noit_apply_filterset(check->filterset, check, (metric_t *)data);
549             nc_printf(ncct, "  %c%s\n", filtered ? '*' : ' ', buff);
550           }
551         }
552         if(sorted_keys) {
553           int j;
554           qsort(sorted_keys, mcount, sizeof(*sorted_keys),
555                 _qsort_string_compare);
556           for(j=0;j<mcount;j++) {
557             if(noit_hash_retrieve(&c->metrics,
558                                   sorted_keys[j], strlen(sorted_keys[j]),
559                                   &data)) {
560               noit_stats_snprint_metric(buff, sizeof(buff), (metric_t *)data);
561               filtered = !noit_apply_filterset(check->filterset, check, (metric_t *)data);
562               nc_printf(ncct, "  %c%s\n", filtered ? '*' : ' ', buff);
563             }
564           }
565         }
566       }
567     }
568   }
569  out:
570   if(pobj) xmlXPathFreeObject(pobj);
571   return 0;
572 }
573 static int
574 noit_console_config_nocheck(noit_console_closure_t ncct,
575                             int argc, char **argv,
576                             noit_console_state_t *state, void *closure) {
577   int i, cnt;
578   const char *err = "internal error";
579   noit_conf_t_userdata_t *info;
580   xmlXPathObjectPtr pobj = NULL;
581   xmlXPathContextPtr xpath_ctxt = NULL;
582   char xpath[1024];
583   uuid_t checkid;
584
585   noit_conf_xml_xpath(NULL, &xpath_ctxt);
586   if(argc < 1) {
587     nc_printf(ncct, "requires one argument\n");
588     return -1;
589   }
590
591   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
592   if(noit_console_mkcheck_xpath(xpath, sizeof(xpath), info, argv[0])) {
593     nc_printf(ncct, "could not find check '%s'\n", argv[0]);
594     return -1;
595   }
596   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
597   if(!pobj || pobj->type != XPATH_NODESET ||
598      xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
599     err = "no checks found";
600     goto bad;
601   }
602   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
603   for(i=0; i<cnt; i++) {
604     xmlNodePtr node;
605     char *uuid_conf;
606     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
607     uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid");
608     if(!uuid_conf || uuid_parse(uuid_conf, checkid)) {
609       nc_printf(ncct, "%s has invalid or missing UUID!\n",
610                 (char *)xmlGetNodePath(node) + strlen("/noit"));
611     }
612     else {
613       if(argc > 1) {
614         int j;
615         for(j=1;j<argc;j++)
616           xmlUnsetProp(node, (xmlChar *)argv[j]);
617         CONF_DIRTY(node);
618       } else {
619         nc_printf(ncct, "descheduling %s\n", uuid_conf);
620         noit_poller_deschedule(checkid);
621         CONF_REMOVE(node);
622         xmlUnlinkNode(node);
623       }
624       noit_conf_mark_changed();
625     }
626   }
627   if(argc > 1) {
628     noit_poller_process_checks(xpath);
629     noit_poller_reload(xpath);
630   }
631   nc_printf(ncct, "rebuilding causal map...\n");
632   noit_poller_make_causal_map();
633   if(pobj) xmlXPathFreeObject(pobj);
634   return 0;
635  bad:
636   if(pobj) xmlXPathFreeObject(pobj);
637   nc_printf(ncct, "%s\n", err);
638   return -1;
639 }
640 static int
641 noit_console_config_show(noit_console_closure_t ncct,
642                          int argc, char **argv,
643                          noit_console_state_t *state, void *closure) {
644   noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
645   const char *k;
646   int klen;
647   void *data;
648   int i, cnt, titled = 0, cliplen = 0;
649   const char *path = "", *basepath = NULL;
650   char xpath[1024];
651   noit_conf_t_userdata_t *info = NULL;
652   noit_hash_table *config;
653   xmlXPathObjectPtr pobj = NULL;
654   xmlXPathContextPtr xpath_ctxt = NULL, current_ctxt;
655   xmlDocPtr master_config = NULL;
656   xmlNodePtr node = NULL;
657
658   noit_conf_xml_xpath(&master_config, &xpath_ctxt);
659   if(argc > 1) {
660     nc_printf(ncct, "too many arguments\n");
661     return -1;
662   }
663
664   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
665   if(info && info->path) path = basepath = info->path;
666   if(!info && argc == 0) {
667     nc_printf(ncct, "argument required when not in configuration mode\n");
668     return -1;
669   }
670
671   if(argc == 1) path = argv[0];
672   if(!basepath) basepath = path;
673
674   /* { / } is a special case */
675   if(!strcmp(basepath, "/")) basepath = "";
676   if(!strcmp(path, "/")) path = "";
677
678   if(!master_config) {
679     nc_printf(ncct, "no config\n");
680     return -1;
681   }
682
683   /* { / } is the only path that will end with a /
684    * in XPath { / / * } means something _entirely different than { / * }
685    * Ever notice how it is hard to describe xpath in C comments?
686    */
687   /* We don't want to show the root node */
688   cliplen = strlen("/noit/");
689
690   /* If we are in configuration mode
691    * and we are without an argument or the argument is absolute,
692    * clip the current path off */
693   if(info && (argc == 0 || path[0] != '/')) cliplen += strlen(basepath);
694   if(!path[0] || path[0] == '/') /* base only, or absolute path requested */
695     snprintf(xpath, sizeof(xpath), "/noit%s/@*", path);
696   else
697     snprintf(xpath, sizeof(xpath), "/noit%s/%s/@*", basepath, path);
698
699   current_ctxt = xpath_ctxt;
700   pobj = xmlXPathEval((xmlChar *)xpath, current_ctxt);
701   if(!pobj || pobj->type != XPATH_NODESET) {
702     nc_printf(ncct, "no such object\n");
703     goto bad;
704   }
705   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
706   titled = 0;
707   for(i=0; i<cnt; i++) {
708     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
709     if(!strcmp((char *)node->name, "check")) continue;
710     if(node->children && node->children == xmlGetLastChild(node) &&
711       xmlNodeIsText(node->children)) {
712       char *node_str, *xmlpath;
713       node_str = (char *)xmlXPathCastNodeToString(node->children);
714       xmlpath = (char *)xmlGetNodePath(node);
715       if(!titled++) nc_printf(ncct, "== Section Settings ==\n");
716       nc_printf(ncct, "%s: %s\n", xmlpath + cliplen, node_str);
717       free(xmlpath);
718       free(node_str);
719     }
720   }
721   xmlXPathFreeObject(pobj);
722
723   /* Print out all the config settings */
724   if(!path[0] || path[0] == '/') /* base only, or absolute path requested */
725     snprintf(xpath, sizeof(xpath), "/noit%s", path);
726   else
727     snprintf(xpath, sizeof(xpath), "/noit%s/%s", basepath, path);
728   pobj = xmlXPathEval((xmlChar *)xpath, current_ctxt);
729   if(!pobj || pobj->type != XPATH_NODESET) {
730     nc_printf(ncct, "no such object\n");
731     goto bad;
732   }
733   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
734   if(cnt > 0) {
735     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
736     titled = 0;
737     config = noit_conf_get_hash(node, "config");
738     while(noit_hash_next(config, &iter, &k, &klen, &data)) {
739       if(!titled++) nc_printf(ncct, "== Section [Aggregated] Config ==\n");
740       nc_printf(ncct, "config::%s: %s\n", k, (const char *)data);
741     }
742     noit_hash_destroy(config, free, free);
743     free(config);
744   }
745   xmlXPathFreeObject(pobj);
746
747   /* _shorten string_ turning last { / @ * } to { / * } */
748   if(!path[0] || path[0] == '/') /* base only, or absolute path requested */
749     snprintf(xpath, sizeof(xpath), "/noit%s/*", path);
750   else
751     snprintf(xpath, sizeof(xpath), "/noit%s/%s/*", basepath, path);
752   pobj = xmlXPathEval((xmlChar *)xpath, current_ctxt);
753   if(!pobj || pobj->type != XPATH_NODESET) {
754     nc_printf(ncct, "no such object\n");
755     goto bad;
756   }
757   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
758   titled = 0;
759   for(i=0; i<cnt; i++) {
760     char *xmlpath;
761     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
762     if(!strcmp((char *)node->name, "check")) continue;
763     if(!strcmp((char *)node->name, "filterset")) continue;
764     xmlpath = (char *)xmlGetNodePath(node);
765     if(strcmp(xmlpath + cliplen, "config")) {
766       if(!(node->children && node->children == xmlGetLastChild(node) &&
767            xmlNodeIsText(node->children))) {
768         if(!titled++) nc_printf(ncct, "== Subsections ==\n");
769         nc_printf(ncct, "%s\n", xmlpath + cliplen);
770       }
771     }
772     free(xmlpath);
773   }
774
775   titled = 0;
776   for(i=0; i<cnt; i++) {
777     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
778     if(!strcmp((char *)node->name, "filterset")) {
779       xmlAttr *attr;
780       char *filter_name = NULL;
781       for(attr=node->properties; attr; attr = attr->next) {
782         if(!strcmp((char *)attr->name, "name"))
783           filter_name = (char *)xmlXPathCastNodeToString(attr->children);
784       }
785       if(filter_name) {
786         nc_printf(ncct, "filterset[@name=\"%s\"]\n", filter_name);
787         xmlFree(filter_name);
788       }
789       else nc_printf(ncct, "fitlerset\n");
790     }
791     else if(!strcmp((char *)node->name, "check")) {
792       int busted = 1;
793       xmlAttr *attr;
794       char *uuid_str = NULL;
795       uuid_t checkid;
796
797       if(!titled++) nc_printf(ncct, "== Checks ==\n");
798
799       for(attr=node->properties; attr; attr = attr->next) {
800         if(!strcmp((char *)attr->name, "uuid")) {
801           uuid_str = (char *)xmlXPathCastNodeToString(attr->children);
802           break;
803         }
804       }
805       nc_printf(ncct, "check[@uuid=\"%s\"] ", uuid_str ? uuid_str : "undefined");
806       if(uuid_str && uuid_parse(uuid_str, checkid) == 0) {
807         noit_check_t *check;
808         check = noit_poller_lookup(checkid);
809         if(check) {
810           busted = 0;
811           nc_printf(ncct, "%s`%s`%s", check->target, check->module, check->name);
812         }
813       }
814       if(uuid_str) free(uuid_str);
815       if(busted) nc_printf(ncct, "[check not in running system]");
816       nc_write(ncct, "\n", 1);
817     }
818   }
819   xmlXPathFreeObject(pobj);
820   return 0;
821  bad:
822   if(pobj) xmlXPathFreeObject(pobj);
823   return -1;
824 }
825
826 static char *
827 conf_t_check_prompt(EditLine *el) {
828   noit_console_closure_t ncct;
829   noit_conf_t_userdata_t *info;
830   noit_check_t *check;
831   static char *tl = "noit(conf)# ";
832   static char *pfmt = "noit(conf:%s%s%s)# ";
833
834   el_get(el, EL_USERDATA, (void *)&ncct);
835   if(!ncct) return tl;
836   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
837   if(!info) return tl;
838
839   check = noit_poller_lookup(info->current_check);
840   if(check &&
841      check->target && check->target[0] &&
842      check->name && check->name[0])
843     snprintf(info->prompt, sizeof(info->prompt),
844              pfmt, check->target, "`", check->name);
845   else {
846     char uuid_str[37];
847     uuid_unparse_lower(info->current_check, uuid_str);
848     snprintf(info->prompt, sizeof(info->prompt), pfmt, "[", uuid_str, "]");
849   }
850   return info->prompt;
851 }
852 static int
853 noit_conf_checks_reload(noit_console_closure_t ncct,
854                         int argc, char **argv,
855                         noit_console_state_t *state, void *closure) {
856   if(noit_conf_reload(ncct, argc, argv, state, closure)) return -1;
857   noit_poller_reload(NULL);
858   return 0;
859 }
860
861 static int
862 validate_attr_set_scope(noit_conf_t_userdata_t *info,
863                         struct _valid_attr_t *attrinfo) {
864   int len;
865   len = strlen(attrinfo->scope);
866   if(strncmp(info->path, attrinfo->scope, len) ||
867      (info->path[len] != '\0' && info->path[len] != '/')) {
868     return -1;
869   }
870   return 0;
871 }
872 static int
873 replace_config(noit_console_closure_t ncct,
874                noit_conf_t_userdata_t *info, const char *name,
875                const char *value) {
876   int i, cnt, rv = -1, active = 0;
877   xmlXPathObjectPtr pobj = NULL;
878   xmlXPathContextPtr xpath_ctxt = NULL;
879   xmlNodePtr node, confignode;
880   char xpath[1024], *path;
881
882   path = info->path;
883   if(!strcmp(path, "/")) path = "";
884
885   noit_conf_xml_xpath(NULL, &xpath_ctxt);
886
887   /* Only if checks will fixate this attribute shall we check for
888    * child <check> nodes.
889    * NOTE: this return nothing and "seems" okay if we are _in_
890    *       a <check> node.  That case is handled below.
891    */
892   snprintf(xpath, sizeof(xpath), "/noit/%s//check[@uuid]", path);
893   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
894   if(!pobj || pobj->type != XPATH_NODESET) goto out;
895   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
896   for(i=0; i<cnt; i++) {
897     uuid_t checkid;
898     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
899     if(noit_conf_get_uuid(node, "@uuid", checkid)) {
900       noit_check_t *check;
901       check = noit_poller_lookup(checkid);
902       if(check && NOIT_CHECK_LIVE(check)) active++;
903     }
904   }
905   if(pobj) xmlXPathFreeObject(pobj);
906
907 #ifdef UNSAFE_RECONFIG
908   snprintf(xpath, sizeof(xpath), "/noit/%s", path);
909   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
910   if(!pobj || pobj->type != XPATH_NODESET) goto out;
911   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
912   if(cnt != 1) {
913     nc_printf(ncct, "Internal error: context node disappeared\n");
914     goto out;
915   }
916   node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
917   if(strcmp((const char *)node->name, "check")) {
918     uuid_t checkid;
919     /* Detect if  we are actually a <check> node and attempting to
920      * change something we shouldn't.
921      * This is the counterpart noted above.
922      */
923     if(noit_conf_get_uuid(node, "@uuid", checkid)) {
924       noit_check_t *check;
925       check = noit_poller_lookup(checkid);
926       if(NOIT_CHECK_LIVE(check)) active++;
927     }
928   }
929   if(active) {
930     nc_printf(ncct, "Cannot set '%s', it would effect %d live check(s)\n",
931               name, active);
932     goto out;
933   }
934   if(pobj) xmlXPathFreeObject(pobj);
935 #endif
936
937   /* Here we want to remove /noit/path/config/name */
938   snprintf(xpath, sizeof(xpath), "/noit/%s/config/%s", path, name);
939   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
940   if(!pobj || pobj->type != XPATH_NODESET) goto out;
941   if(xmlXPathNodeSetGetLength(pobj->nodesetval) > 0) {
942     xmlNodePtr toremove;
943     toremove = xmlXPathNodeSetItem(pobj->nodesetval, 0);
944     CONF_REMOVE(toremove);
945     xmlUnlinkNode(toremove);
946   }
947   /* TODO: if there are no more children of config, remove config? */
948   if(value) {
949     if(pobj) xmlXPathFreeObject(pobj);
950     /* He we create config if needed and place a child node under it */
951     snprintf(xpath, sizeof(xpath), "/noit/%s/config", path);
952     pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
953     if(!pobj || pobj->type != XPATH_NODESET) goto out;
954     if(xmlXPathNodeSetGetLength(pobj->nodesetval) == 0) {
955       if(pobj) xmlXPathFreeObject(pobj);
956       snprintf(xpath, sizeof(xpath), "/noit/%s", path);
957       pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
958       if(!pobj || pobj->type != XPATH_NODESET) goto out;
959       if(xmlXPathNodeSetGetLength(pobj->nodesetval) != 1) {
960         nc_printf(ncct, "Node disappeared from under you!\n");
961         goto out;
962       }
963       confignode = xmlNewChild(xmlXPathNodeSetItem(pobj->nodesetval, 0),
964                                NULL, (xmlChar *)"config", NULL);
965       if(confignode == NULL) {
966         nc_printf(ncct, "Error creating config child node.\n");
967         goto out;
968       }
969     }
970     else confignode = xmlXPathNodeSetItem(pobj->nodesetval, 0);
971
972     assert(confignode);
973     /* Now we create a child */
974     xmlNewChild(confignode, NULL, (xmlChar *)name, (xmlChar *)value);
975     CONF_DIRTY(confignode);
976   }
977   noit_conf_mark_changed();
978   rv = 0;
979  out:
980   if(pobj) xmlXPathFreeObject(pobj);
981   return rv;
982 }
983 static int
984 replace_attr(noit_console_closure_t ncct,
985              noit_conf_t_userdata_t *info, struct _valid_attr_t *attrinfo,
986              const char *value) {
987   int i, cnt, rv = -1, active = 0;
988   xmlXPathObjectPtr pobj = NULL;
989   xmlXPathContextPtr xpath_ctxt = NULL;
990   xmlNodePtr node;
991   char xpath[1024], *path;
992
993   path = info->path;
994   if(!strcmp(path, "/")) path = "";
995
996   noit_conf_xml_xpath(NULL, &xpath_ctxt);
997   if(attrinfo->checks_fixate) {
998     /* Only if checks will fixate this attribute shall we check for
999      * child <check> nodes.
1000      * NOTE: this return nothing and "seems" okay if we are _in_
1001      *       a <check> node.  That case is handled below.
1002      */
1003     snprintf(xpath, sizeof(xpath), "/noit/%s//check[@uuid]", path);
1004     pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
1005     if(!pobj || pobj->type != XPATH_NODESET) goto out;
1006     cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
1007     for(i=0; i<cnt; i++) {
1008       uuid_t checkid;
1009       node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
1010       if(noit_conf_get_uuid(node, "@uuid", checkid)) {
1011         noit_check_t *check;
1012         check = noit_poller_lookup(checkid);
1013         if(check && NOIT_CHECK_LIVE(check)) active++;
1014       }
1015     }
1016     if(pobj) xmlXPathFreeObject(pobj);
1017   }
1018   snprintf(xpath, sizeof(xpath), "/noit/%s", path);
1019   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
1020   if(!pobj || pobj->type != XPATH_NODESET) goto out;
1021   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
1022   if(cnt != 1) {
1023     nc_printf(ncct, "Internal error: context node disappeared\n");
1024     goto out;
1025   }
1026   node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
1027   if(attrinfo->checks_fixate &&
1028      !strcmp((const char *)node->name, "check")) {
1029     uuid_t checkid;
1030     /* Detect if  we are actually a <check> node and attempting to
1031      * change something we shouldn't.
1032      * This is the counterpart noted above.
1033      */
1034     if(noit_conf_get_uuid(node, "@uuid", checkid)) {
1035       noit_check_t *check;
1036       check = noit_poller_lookup(checkid);
1037       if(check && NOIT_CHECK_LIVE(check)) active++;
1038     }
1039   }
1040   if(active) {
1041     nc_printf(ncct, "Cannot set '%s', it would effect %d live check(s)\n",
1042               attrinfo->name, active);
1043     goto out;
1044   }
1045   xmlUnsetProp(node, (xmlChar *)attrinfo->name);
1046   if(value)
1047     xmlSetProp(node, (xmlChar *)attrinfo->name, (xmlChar *)value);
1048   CONF_DIRTY(node);
1049   noit_conf_mark_changed();
1050   rv = 0;
1051  out:
1052   if(pobj) xmlXPathFreeObject(pobj);
1053   return rv;
1054 }
1055 int
1056 noit_conf_check_set_attr(noit_console_closure_t ncct,
1057                          int argc, char **argv,
1058                          noit_console_state_t *state, void *closure) {
1059   struct _valid_attr_t *attrinfo = closure;
1060   noit_conf_t_userdata_t *info;
1061
1062   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
1063   if(!info || validate_attr_set_scope(info, attrinfo)) {
1064     nc_printf(ncct, "'%s' attribute only valid in %s scope\n",
1065               attrinfo->name, attrinfo->scope);
1066     return -1;
1067   }
1068
1069   if(argc != 1) {
1070     nc_printf(ncct, "set requires exactly one value\n");
1071     return -1;
1072   }
1073   /* Okay, we have an attribute and it should be set/replaced on the
1074    * current path.
1075    */
1076   if(replace_attr(ncct, info, attrinfo, argv[0])) {
1077     return -1;
1078   }
1079
1080   /* So, we updated an attribute, so we need to reload all checks
1081    * that are descendent-or-self of this node.
1082    */
1083   if(!strncmp(info->path, "/checks", strlen("/checks")))
1084     refresh_subchecks(ncct, info);
1085   if(!strncmp(info->path, "/filtersets", strlen("/filtersets")))
1086     noit_refresh_filtersets(ncct, info);
1087   return 0;
1088 }
1089
1090 int
1091 noit_conf_check_unset_attr(noit_console_closure_t ncct,
1092                            int argc, char **argv,
1093                            noit_console_state_t *state, void *closure) {
1094   struct _valid_attr_t *attrinfo = closure;
1095   noit_conf_t_userdata_t *info;
1096
1097   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
1098   if(!info || validate_attr_set_scope(info, attrinfo)) {
1099     nc_printf(ncct, "'%s' attribute only valid in %s scope\n",
1100               attrinfo->name, attrinfo->scope);
1101     return -1;
1102   }
1103
1104   if(argc != 0) {
1105     nc_printf(ncct, "no arguments allowed to this command.\n");
1106     return -1;
1107   }
1108   /* Okay, we have an attribute and it should be set/replaced on the
1109    * current path.
1110    */
1111   if(replace_attr(ncct, info, attrinfo, NULL)) {
1112     return -1;
1113   }
1114
1115   /* So, we updated an attribute, so we need to reload all checks
1116    * that are descendent-or-self of this node.
1117    */
1118   if(!strncmp(info->path, "/checks", strlen("/checks")))
1119     refresh_subchecks(ncct, info);
1120   if(!strncmp(info->path, "/filterset", strlen("/filterest")))
1121     noit_refresh_filtersets(ncct, info);
1122   return 0;
1123 }
1124
1125 int
1126 noit_console_config_setconfig(noit_console_closure_t ncct,
1127                                 int argc, char **argv,
1128                                 noit_console_state_t *state, void *closure) {
1129   noit_conf_t_userdata_t *info;
1130
1131   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
1132
1133   if(argc != 2) {
1134     nc_printf(ncct, "two arguments required.\n");
1135     return -1;
1136   }
1137   /* Okay, we have an child name and it should be culled from
1138    * current path/config.
1139    */
1140   if(replace_config(ncct, info, argv[0], argv[1])) {
1141     return -1;
1142   }
1143
1144   /* So, we updated an attribute, so we need to reload all checks
1145    * that are descendent-or-self of this node.
1146    */
1147   refresh_subchecks(ncct, info);
1148   return 0;
1149 }
1150
1151 int
1152 noit_console_config_unsetconfig(noit_console_closure_t ncct,
1153                                 int argc, char **argv,
1154                                 noit_console_state_t *state, void *closure) {
1155   noit_conf_t_userdata_t *info;
1156
1157   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
1158
1159   if(argc != 1) {
1160     nc_printf(ncct, "one argument required.\n");
1161     return -1;
1162   }
1163   /* Okay, we have an child name and it should be culled from
1164    * current path/config.
1165    */
1166   if(replace_config(ncct, info, argv[0], NULL)) {
1167     return -1;
1168   }
1169
1170   /* So, we updated an attribute, so we need to reload all checks
1171    * that are descendent-or-self of this node.
1172    */
1173   refresh_subchecks(ncct, info);
1174   return 0;
1175 }
1176
1177
1178 #define NEW_STATE(a) (a) = noit_console_state_alloc()
1179 #define ADD_CMD(a,cmd,func,ac,ss,c) \
1180   noit_console_state_add_cmd((a), \
1181     NCSCMD(cmd, func, ac, ss, c))
1182 #define DELEGATE_CMD(a,cmd,ac,ss) \
1183   noit_console_state_add_cmd((a), \
1184     NCSCMD(cmd, noit_console_state_delegate, ac, ss, NULL))
1185
1186 static
1187 void register_console_config_check_commands() {
1188   cmd_info_t *showcmd, *nocmd, *confcmd, *conftcmd, *conftnocmd, *lscmd;
1189   noit_console_state_t *tl, *_conf_t_check_state, *_unset_state,
1190                        *_attr_state, *_uattr_state;
1191
1192   tl = noit_console_state_initial();
1193   showcmd = noit_console_state_get_cmd(tl, "show");
1194   nocmd = noit_console_state_get_cmd(tl, "no");
1195   confcmd = noit_console_state_get_cmd(tl, "configure");
1196   conftcmd = noit_console_state_get_cmd(confcmd->dstate, "terminal");
1197   conftnocmd = noit_console_state_get_cmd(conftcmd->dstate, "no");
1198   lscmd = noit_console_state_get_cmd(conftcmd->dstate, "ls");
1199   lscmd->func = noit_console_config_show;
1200   /* attribute <attrname> <value> */
1201   NEW_STATE(_attr_state);
1202   noit_console_state_add_check_attrs(_attr_state, noit_conf_check_set_attr,
1203                                      "/checks");
1204  
1205   /* no attribute <attrname> <value> */
1206   NEW_STATE(_uattr_state);
1207   noit_console_state_add_check_attrs(_uattr_state, noit_conf_check_unset_attr,
1208                                      "/checks");
1209   NEW_STATE(_unset_state);
1210   DELEGATE_CMD(_unset_state, "attribute",
1211                noit_console_opt_delegate, _uattr_state);
1212   ADD_CMD(_unset_state, "config",
1213           noit_console_config_unsetconfig, NULL, NULL, NULL);
1214
1215   DELEGATE_CMD(conftnocmd->dstate, "attribute",
1216                noit_console_opt_delegate, _uattr_state);
1217   ADD_CMD(conftnocmd->dstate, "config",
1218           noit_console_config_unsetconfig, NULL, NULL, NULL);
1219   ADD_CMD(conftnocmd->dstate, "check",
1220           noit_console_config_nocheck, NULL, NULL, NULL);
1221  
1222   NEW_STATE(_conf_t_check_state);
1223   _conf_t_check_state->console_prompt_function = conf_t_check_prompt;
1224   DELEGATE_CMD(_conf_t_check_state, "attribute",
1225                noit_console_opt_delegate, _attr_state);
1226   DELEGATE_CMD(_conf_t_check_state, "no",
1227                noit_console_opt_delegate, _unset_state);
1228   ADD_CMD(_conf_t_check_state, "config",
1229           noit_console_config_setconfig, NULL, NULL, NULL);
1230   ADD_CMD(_conf_t_check_state, "status",
1231           noit_console_show_check, NULL, NULL, NULL);
1232   ADD_CMD(_conf_t_check_state, "exit",
1233           noit_console_config_cd, NULL, NULL, "..");
1234   ADD_CMD(_conf_t_check_state, "check",
1235           noit_console_check, noit_console_conf_check_opts,
1236           _conf_t_check_state, "..");
1237
1238   ADD_CMD(conftcmd->dstate, "config",
1239           noit_console_config_setconfig, NULL, NULL, NULL);
1240   ADD_CMD(conftcmd->dstate, "check",
1241           noit_console_check, noit_console_conf_check_opts,
1242           _conf_t_check_state, NULL);
1243
1244   ADD_CMD(showcmd->dstate, "check",
1245           noit_console_show_check, noit_console_check_opts, NULL, NULL);
1246
1247   ADD_CMD(tl, "watch",
1248           noit_console_watch_check, noit_console_check_opts, NULL, (void *)1);
1249
1250   ADD_CMD(nocmd->dstate, "watch",
1251           noit_console_watch_check, noit_console_check_opts, NULL, (void *)0);
1252
1253   DELEGATE_CMD(conftcmd->dstate, "attribute",
1254                noit_console_opt_delegate, _attr_state);
1255
1256   ADD_CMD(tl, "reload", noit_conf_checks_reload, NULL, NULL, NULL);
1257 }
1258
Note: See TracBrowser for help on using the browser.