root/src/noit_check_rest.c

Revision 6f0b2ab04b6e742c4bac93acdc575612ceabcae1, 20.9 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 5 years ago)

refs #171, supports inherit flags on config stanzas

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2009, 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 #include <assert.h>
35 #include <errno.h>
36 #include <libxml/parser.h>
37 #include <libxml/tree.h>
38 #include <libxml/xpath.h>
39 #include "noit_listener.h"
40 #include "noit_http.h"
41 #include "noit_rest.h"
42 #include "noit_check.h"
43 #include "noit_check_tools.h"
44 #include "noit_conf.h"
45 #include "noit_conf_private.h"
46
47 #define FAIL(a) do { error = (a); goto error; } while(0)
48 #define UUID_REGEX "[0-9a-fA-F]{4}(?:[0-9a-fA-F]{4}-){4}[0-9a-fA-F]{12}"
49
50 struct rest_xml_payload {
51   char *buffer;
52   int len;
53   int allocd;
54   int complete;
55 };
56
57 static int
58 rest_show_check(noit_http_rest_closure_t *restc,
59                 int npats, char **pats) {
60   noit_http_session_ctx *ctx = restc->http_ctx;
61   xmlXPathObjectPtr pobj = NULL;
62   xmlXPathContextPtr xpath_ctxt = NULL;
63   xmlDocPtr doc = NULL;
64   xmlNodePtr node, root, attr, config, state, tmp, anode, metrics;
65   uuid_t checkid;
66   noit_check_t *check;
67   char xpath[1024], *uuid_conf, *module, *value;
68   int rv, cnt, error_code = 500;
69   noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
70   const char *k;
71   int klen;
72   void *data;
73   noit_hash_table *configh;
74
75   if(npats != 2) goto error;
76
77   rv = noit_check_xpath(xpath, sizeof(xpath), pats[0], pats[1]);
78   if(rv == 0) goto not_found;
79   if(rv < 0) goto error;
80
81   noit_conf_xml_xpath(NULL, &xpath_ctxt);
82   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
83   if(!pobj || pobj->type != XPATH_NODESET ||
84      xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto not_found;
85   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
86   if(cnt != 1) goto error;
87
88   node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
89   uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid");
90   if(!uuid_conf || uuid_parse(uuid_conf, checkid)) goto error;
91
92   doc = xmlNewDoc((xmlChar *)"1.0");
93   root = xmlNewDocNode(doc, NULL, (xmlChar *)"check", NULL);
94   xmlDocSetRootElement(doc, root);
95
96 #define MYATTR(node,a,n,b) _noit_conf_get_string(node, &(n), "@" #a, &(b))
97 #define INHERIT(node,a,n,b) \
98   _noit_conf_get_string(node, &(n), "ancestor-or-self::node()/@" #a, &(b))
99 #define SHOW_ATTR(parent, node, a) do { \
100   xmlNodePtr anode = NULL; \
101   char *value = NULL; \
102   INHERIT(node, a, anode, value); \
103   if(value != NULL) { \
104     int clen, plen;\
105     const char *cpath, *apath; \
106     xmlNodePtr child; \
107     cpath = node ? (char *)xmlGetNodePath(node) : ""; \
108     apath = anode ? (char *)xmlGetNodePath(anode) : ""; \
109     clen = strlen(cpath); \
110     plen = strlen("/noit/checks"); \
111     child = xmlNewNode(NULL, (xmlChar *)#a); \
112     xmlNodeAddContent(child, (xmlChar *)value); \
113     if(!strncmp(cpath, apath, clen) && apath[clen] == '/') { \
114     } \
115     else { \
116       xmlSetProp(child, (xmlChar *)"inherited", (xmlChar *)apath+plen); \
117     } \
118     xmlAddChild(parent, child); \
119   } \
120 } while(0)
121 #define NODE_CONTENT(parent, k, v) do { \
122   xmlNodePtr tmp; \
123   if(v) { \
124     tmp = xmlNewNode(NULL, (xmlChar *)(k)); \
125     xmlNodeAddContent(tmp, (xmlChar *)(v)); \
126     xmlAddChild(parent, tmp); \
127   } \
128 } while(0)
129
130   attr = xmlNewNode(NULL, (xmlChar *)"attributes");
131   xmlAddChild(root, attr);
132
133   SHOW_ATTR(attr,node,uuid);
134
135   /* Name is odd, it falls back transparently to module */
136   if(!INHERIT(node, module, tmp, module)) module = NULL;
137   xmlAddChild(attr, (tmp = xmlNewNode(NULL, (xmlChar *)"name")));
138   if(MYATTR(node, name, anode, value))
139     xmlNodeAddContent(tmp, (xmlChar *)value);
140   else if(module)
141     xmlNodeAddContent(tmp, (xmlChar *)module);
142
143   SHOW_ATTR(attr,node,module);
144   SHOW_ATTR(attr,node,target);
145   SHOW_ATTR(attr,node,period);
146   SHOW_ATTR(attr,node,timeout);
147   SHOW_ATTR(attr,node,oncheck);
148   SHOW_ATTR(attr,node,filterset);
149   SHOW_ATTR(attr,node,disable);
150
151   /* Add the config */
152   config = xmlNewNode(NULL, (xmlChar *)"config");
153   configh = noit_conf_get_hash(node, "config");
154   while(noit_hash_next(configh, &iter, &k, &klen, &data))
155     NODE_CONTENT(config, k, data);
156   noit_hash_destroy(configh, free, free);
157   free(configh);
158   xmlAddChild(root, config);
159
160   /* Add the state */
161   xmlAddChild(root, (state = xmlNewNode(NULL, (xmlChar *)"state")));
162   check = noit_poller_lookup(checkid);
163   if(!check)
164     xmlSetProp(state, (xmlChar *)"error", (xmlChar *)"true");
165   else {
166     stats_t *c = &check->stats.current;
167     NODE_CONTENT(state, "running", NOIT_CHECK_RUNNING(check)?"true":"false");
168     NODE_CONTENT(state, "killed", NOIT_CHECK_KILLED(check)?"true":"false");
169     NODE_CONTENT(state, "configured",
170                  NOIT_CHECK_CONFIGURED(check)?"true":"false");
171     NODE_CONTENT(state, "disabled", NOIT_CHECK_DISABLED(check)?"true":"false");
172     xmlAddChild(state, (tmp = xmlNewNode(NULL, (xmlChar *)"last_run")));
173     if(check->stats.current.whence.tv_sec) {
174       struct timeval f = check->stats.current.whence;
175       struct timeval n;
176       char timestr[20];
177       gettimeofday(&n, NULL);
178       snprintf(timestr, sizeof(timestr), "%0.3f",
179                n.tv_sec + (n.tv_usec / 1000000.0));
180       xmlSetProp(tmp, (xmlChar *)"now", (xmlChar *)timestr);
181       snprintf(timestr, sizeof(timestr), "%0.3f",
182                f.tv_sec + (f.tv_usec / 1000000.0));
183       xmlNodeAddContent(tmp, (xmlChar *)timestr);
184     }
185     if(c->available) { /* truth here means the check has been run */
186       char buff[20];
187       snprintf(buff, sizeof(buff), "%0.3f", (float)c->duration/1000.0);
188       NODE_CONTENT(state, "runtime", buff);
189     }
190     NODE_CONTENT(state, "availability",
191                  noit_check_available_string(c->available));
192     NODE_CONTENT(state, "state", noit_check_state_string(c->state));
193     NODE_CONTENT(state, "status", c->status ? c->status : "");
194     memset(&iter, 0, sizeof(iter));
195     xmlAddChild(state, (metrics = xmlNewNode(NULL, (xmlChar *)"metrics")));
196     while(noit_hash_next(&c->metrics, &iter, &k, &klen, &data)) {
197       char buff[256];
198       metric_t *m = (metric_t *)data;
199       xmlAddChild(metrics, (tmp = xmlNewNode(NULL, (xmlChar *)m->metric_name)));
200       buff[0] = m->metric_type; buff[1] = '\0';
201       xmlSetProp(tmp, (xmlChar *)"type", (xmlChar *)buff);
202       if(m->metric_value.s) {
203         int rv;
204         rv = noit_stats_snprint_metric_value(buff, sizeof(buff), m);
205         if(rv < 0)
206           xmlSetProp(tmp, (xmlChar *)"error", (xmlChar *)"unknown type");
207         else
208           xmlNodeAddContent(tmp, (xmlChar *)buff);
209       }
210     }
211
212   }
213   noit_http_response_ok(ctx, "text/xml");
214   noit_http_response_xml(ctx, doc);
215   noit_http_response_end(ctx);
216   goto cleanup;
217
218  not_found:
219   noit_http_response_not_found(ctx, "text/html");
220   noit_http_response_end(ctx);
221   goto cleanup;
222
223  error:
224   noit_http_response_standard(ctx, error_code, "ERROR", "text/html");
225   noit_http_response_end(ctx);
226   goto cleanup;
227
228  cleanup:
229   if(pobj) xmlXPathFreeObject(pobj);
230   if(doc) xmlFreeDoc(doc);
231   return 0;
232 }
233
234 static void
235 rest_xml_payload_free(void *f) {
236   struct rest_xml_payload *xmlin = f;
237   if(xmlin->buffer) free(xmlin->buffer);
238 }
239
240 static int
241 validate_check_post(xmlDocPtr doc, xmlNodePtr *a, xmlNodePtr *c,
242                     const char **error) {
243   xmlNodePtr root, tl, an;
244   int name=0, module=0, target=0, period=0, timeout=0, filterset=0;
245   *a = *c = NULL;
246   root = xmlDocGetRootElement(doc);
247   if(!root || strcmp((char *)root->name, "check")) return 0;
248   for(tl = root->children; tl; tl = tl->next) {
249     if(!strcmp((char *)tl->name, "attributes")) {
250       *a = tl;
251       for(an = tl->children; an; an = an->next) {
252 #define CHECK_N_SET(a) if(!strcmp((char *)an->name, #a))
253         CHECK_N_SET(name) {
254           xmlChar *tmp;
255           pcre *valid_name = noit_conf_get_valid_name_checker();
256           int ovector[30], valid;
257           tmp = xmlNodeGetContent(an);
258           valid = (pcre_exec(valid_name, NULL,
259                              (char *)tmp, strlen((char *)tmp), 0, 0,
260                              ovector, sizeof(ovector)/sizeof(*ovector)) > 0);
261           xmlFree(tmp);
262           if(!valid) { *error = "invalid name"; return 0; }
263           name = 1;
264         }
265         else CHECK_N_SET(module) module = 1; /* This is validated by called */
266         else CHECK_N_SET(target) {
267           int valid;
268           xmlChar *tmp;
269           tmp = xmlNodeGetContent(an);
270           valid = noit_check_is_valid_target((char *)tmp);
271           xmlFree(tmp);
272           if(!valid) { *error = "invalid target"; return 0; }
273           target = 1;
274         }
275         else CHECK_N_SET(period) {
276           int pint;
277           xmlChar *tmp;
278           tmp = xmlNodeGetContent(an);
279           pint = noit_conf_string_to_int((char *)tmp);
280           xmlFree(tmp);
281           if(pint < 5000 || pint > 300000) {
282             *error = "invalid period";
283             return 0;
284           }
285           period = 1;
286         }
287         else CHECK_N_SET(timeout) {
288           int pint;
289           xmlChar *tmp;
290           tmp = xmlNodeGetContent(an);
291           pint = noit_conf_string_to_int((char *)tmp);
292           xmlFree(tmp);
293           if(pint < 0 || pint > 300000) {
294             *error = "invalid timeout";
295             return 0;
296           }
297           timeout = 1;
298         }
299         else CHECK_N_SET(filterset) filterset = 1;
300         else CHECK_N_SET(disable) { /* not required */
301           int valid;
302           xmlChar *tmp;
303           tmp = xmlNodeGetContent(an);
304           valid = (!strcasecmp((char *)tmp, "true") ||
305                    !strcasecmp((char *)tmp, "on") ||
306                    !strcasecmp((char *)tmp, "false") ||
307                    !strcasecmp((char *)tmp, "off"));
308           xmlFree(tmp);
309           if(!valid) { *error = "bad disable parameter"; return 0; }
310           target = 1;
311         }
312         else return 0;
313       }
314     }
315     else if(!strcmp((char *)tl->name, "config")) {
316       *c = tl;
317       /* Noop, anything goes */
318     }
319     else return 0;
320   }
321   if(name && module && target && period && timeout && filterset) return 1;
322   *error = "insufficient information";
323   return 0;
324 }
325 static void
326 configure_xml_check(xmlNodePtr check, xmlNodePtr a, xmlNodePtr c) {
327   xmlNodePtr n, config, oldconfig;
328   for(n = a->children; n; n = n->next) {
329 #define ATTR2PROP(attr) do { \
330   if(!strcmp((char *)n->name, #attr)) { \
331     xmlChar *v = xmlNodeGetContent(n); \
332     if(v) xmlSetProp(check, n->name, v); \
333     else xmlUnsetProp(check, n->name); \
334     if(v) xmlFree(v); \
335   } \
336 } while(0)
337     ATTR2PROP(name);
338     ATTR2PROP(target);
339     ATTR2PROP(module);
340     ATTR2PROP(period);
341     ATTR2PROP(timeout);
342     ATTR2PROP(disable);
343     ATTR2PROP(filter);
344   }
345   for(oldconfig = check->children; oldconfig; oldconfig = oldconfig->next)
346     if(!strcmp((char *)oldconfig->name, "config")) break;
347   config = xmlNewNode(NULL, (xmlChar *)"config");
348   if(c) {
349     xmlAttrPtr inherit;
350     if((inherit = xmlHasProp(c, (xmlChar *)"inherit")) != NULL &&
351         inherit->children && inherit->children->content)
352       xmlSetProp(config, (xmlChar *)"inherit", inherit->children->content);
353     for(n = c->children; n; n = n->next) {
354       xmlNodePtr co = xmlNewNode(NULL, n->name);
355       xmlNodeAddContent(co, XML_GET_CONTENT(n));
356       xmlAddChild(config, co);
357     }
358   }
359   if(oldconfig) {
360     xmlReplaceNode(oldconfig, config);
361     xmlFreeNode(oldconfig);
362   }
363   else xmlAddChild(check, config);
364 }
365 static xmlNodePtr
366 make_conf_path(char *path) {
367   xmlNodePtr start, tmp;
368   char fullpath[1024], *tok, *brk;
369   if(!path || strlen(path) < 1) return NULL;
370   snprintf(fullpath, sizeof(fullpath), "%s", path+1);
371   fullpath[strlen(fullpath)-1] = '\0';
372   start = noit_conf_get_section(NULL, "/noit/checks");
373   if(!start) return NULL;
374   for (tok = strtok_r(fullpath, "/", &brk);
375        tok;
376        tok = strtok_r(NULL, "/", &brk)) {
377     if(!xmlValidateNameValue((xmlChar *)tok)) return NULL;
378     if(!strcmp(tok, "check")) return NULL;  /* These two paths */
379     if(!strcmp(tok, "config")) return NULL; /* are off limits. */
380     for (tmp = start->children; tmp; tmp = tmp->next) {
381       if(!strcmp((char *)tmp->name, tok)) break;
382     }
383     if(!tmp) {
384       tmp = xmlNewNode(NULL, (xmlChar *)tok);
385       xmlAddChild(start, tmp);
386     }
387     start = tmp;
388   }
389   return start;
390 }
391 static int
392 rest_delete_check(noit_http_rest_closure_t *restc,
393                   int npats, char **pats) {
394   noit_http_session_ctx *ctx = restc->http_ctx;
395   xmlXPathObjectPtr pobj = NULL;
396   xmlXPathContextPtr xpath_ctxt = NULL;
397   xmlNodePtr node;
398   uuid_t checkid;
399   noit_check_t *check;
400   const char *error;
401   char xpath[1024], *uuid_conf;
402   int rv, cnt, error_code = 500;
403   noit_boolean exists = noit_false;
404
405   if(npats != 2) goto error;
406
407   if(uuid_parse(pats[1], checkid)) goto error;
408   check = noit_poller_lookup(checkid);
409   if(check)
410     exists = noit_true;
411
412   rv = noit_check_xpath(xpath, sizeof(xpath), pats[0], pats[1]);
413   if(rv == 0) FAIL("uuid not valid");
414   if(rv < 0) FAIL("Tricky McTrickster... No");
415
416   noit_conf_xml_xpath(NULL, &xpath_ctxt);
417   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
418   if(!pobj || pobj->type != XPATH_NODESET ||
419      xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
420     if(exists) { error_code = 403; FAIL("uuid not yours"); }
421     goto not_found;
422   }
423   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
424   if(cnt != 1) FAIL("internal error, |checkid| > 1");
425   node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
426   uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid");
427   if(!uuid_conf || strcasecmp(uuid_conf, pats[1]))
428     FAIL("internal error uuid");
429
430   /* delete this here */
431   noit_poller_deschedule(check->checkid);
432   xmlUnlinkNode(node);
433   xmlFreeNode(node);
434   if(noit_conf_write_file(NULL) != 0)
435     noitL(noit_error, "local config write failed\n");
436   noit_conf_mark_changed();
437   noit_http_response_ok(ctx, "text/html");
438   noit_http_response_end(ctx);
439   goto cleanup;
440
441  not_found:
442   noit_http_response_not_found(ctx, "text/html");
443   noit_http_response_end(ctx);
444   goto cleanup;
445
446  error:
447   noit_http_response_standard(ctx, error_code, "ERROR", "text/html");
448   noit_http_response_end(ctx);
449   goto cleanup;
450
451  cleanup:
452   if(pobj) xmlXPathFreeObject(pobj);
453   return 0;
454 }
455
456 static int
457 rest_set_check(noit_http_rest_closure_t *restc,
458                int npats, char **pats) {
459   noit_http_session_ctx *ctx = restc->http_ctx;
460   xmlXPathObjectPtr pobj = NULL;
461   xmlXPathContextPtr xpath_ctxt = NULL;
462   xmlDocPtr doc = NULL, indoc = NULL;
463   xmlNodePtr node, root, attr, config, parent;
464   uuid_t checkid;
465   noit_check_t *check;
466   char xpath[1024], *uuid_conf;
467   int rv, cnt, error_code = 500;
468   const char *error = "internal error";
469   noit_boolean exists = noit_false;
470   struct rest_xml_payload *rxc;
471
472   if(npats != 2) goto error;
473
474   if(restc->call_closure == NULL) {
475     rxc = restc->call_closure = calloc(1, sizeof(*rxc));
476     restc->call_closure_free = rest_xml_payload_free;
477   }
478   rxc = restc->call_closure;
479   while(!rxc->complete) {
480     int len, mask;
481     if(rxc->len == rxc->allocd) {
482       char *b;
483       rxc->allocd += 32768;
484       b = rxc->buffer ? realloc(rxc->buffer, rxc->allocd) :
485                         malloc(rxc->allocd);
486       if(!b) FAIL("alloc failed");
487       rxc->buffer = b;
488     }
489     len = noit_http_session_req_consume(restc->http_ctx,
490                                         rxc->buffer + rxc->len,
491                                         rxc->allocd - rxc->len,
492                                         &mask);
493     if(len > 0) rxc->len += len;
494     if(len < 0 && errno == EAGAIN) return mask;
495     if(rxc->len == restc->http_ctx->req.content_length) rxc->complete = 1;
496   }
497
498   indoc = xmlParseMemory(rxc->buffer, rxc->len);
499   if(indoc == NULL) FAIL("xml parse error");
500   if(!validate_check_post(indoc, &attr, &config, &error)) goto error;
501
502   if(uuid_parse(pats[1], checkid)) goto error;
503   check = noit_poller_lookup(checkid);
504   if(check)
505     exists = noit_true;
506
507   rv = noit_check_xpath(xpath, sizeof(xpath), pats[0], pats[1]);
508   if(rv == 0) FAIL("uuid not valid");
509   if(rv < 0) FAIL("Tricky McTrickster... No");
510
511   noit_conf_xml_xpath(NULL, &xpath_ctxt);
512   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
513   if(!pobj || pobj->type != XPATH_NODESET ||
514      xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
515     if(exists) { error_code = 403; FAIL("uuid not yours"); }
516     else {
517       char *target = NULL, *name = NULL, *module = NULL;
518       noit_module_t *m;
519       xmlNodePtr newcheck, a;
520       /* make sure this isn't a dup */
521       for(a = attr->children; a; a = a->next) {
522         if(!strcmp((char *)a->name, "target"))
523           target = (char *)xmlNodeGetContent(a);
524         if(!strcmp((char *)a->name, "name"))
525           name = (char *)xmlNodeGetContent(a);
526         if(!strcmp((char *)a->name, "module"))
527           module = (char *)xmlNodeGetContent(a);
528       }
529       exists = (noit_poller_lookup_by_name(target, name) != NULL);
530       m = noit_module_lookup(module);
531       xmlFree(target);
532       xmlFree(name);
533       xmlFree(module);
534       if(exists) FAIL("target`name already registered");
535       if(!m) FAIL("module does not exist");
536       /* create a check here */
537       newcheck = xmlNewNode(NULL, (xmlChar *)"check");
538       xmlSetProp(newcheck, (xmlChar *)"uuid", (xmlChar *)pats[1]);
539       configure_xml_check(newcheck, attr, config);
540       parent = make_conf_path(pats[0]);
541       if(!parent) FAIL("invalid path");
542       xmlAddChild(parent, newcheck);
543     }
544   }
545   if(exists) {
546     int module_change;
547     char *target, *name, *module;
548     xmlNodePtr a;
549     noit_check_t *ocheck;
550
551     cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
552     if(cnt != 1) FAIL("internal error, |checkid| > 1");
553     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
554     uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid");
555     if(!uuid_conf || strcasecmp(uuid_conf, pats[1]))
556       FAIL("internal error uuid");
557
558     /* make sure this isn't a dup */
559     for(a = attr->children; a; a = a->next) {
560       if(!strcmp((char *)a->name, "target"))
561         target = (char *)xmlNodeGetContent(a);
562       if(!strcmp((char *)a->name, "name"))
563         name = (char *)xmlNodeGetContent(a);
564       if(!strcmp((char *)a->name, "module"))
565         module = (char *)xmlNodeGetContent(a);
566     }
567     ocheck = noit_poller_lookup_by_name(target, name);
568     module_change = strcmp(check->module, module);
569     xmlFree(target);
570     xmlFree(name);
571     xmlFree(module);
572     if(ocheck && ocheck != check) FAIL("new target`name would collide");
573     if(module_change) FAIL("cannot change module");
574     configure_xml_check(node, attr, config);
575     parent = make_conf_path(pats[0]);
576     if(!parent) FAIL("invalid path");
577     xmlUnlinkNode(node);
578     xmlAddChild(parent, node);
579   }
580
581   if(noit_conf_write_file(NULL) != 0)
582     noitL(noit_error, "local config write failed\n");
583   noit_conf_mark_changed();
584   noit_poller_reload(xpath);
585   if(restc->call_closure_free) restc->call_closure_free(restc->call_closure);
586   restc->call_closure_free = NULL;
587   restc->call_closure = NULL;
588   if(pobj) xmlXPathFreeObject(pobj);
589   if(doc) xmlFreeDoc(doc);
590   if(indoc) xmlFreeDoc(indoc);
591   restc->fastpath = rest_show_check;
592   return restc->fastpath(restc, restc->nparams, restc->params);
593
594  error:
595   noit_http_response_standard(ctx, error_code, "ERROR", "text/html");
596   doc = xmlNewDoc((xmlChar *)"1.0");
597   root = xmlNewDocNode(doc, NULL, (xmlChar *)"error", NULL);
598   xmlDocSetRootElement(doc, root);
599   xmlNodeAddContent(root, (xmlChar *)error);
600   noit_http_response_xml(ctx, doc);
601   noit_http_response_end(ctx);
602   goto cleanup;
603
604  cleanup:
605   if(pobj) xmlXPathFreeObject(pobj);
606   if(doc) xmlFreeDoc(doc);
607   if(indoc) xmlFreeDoc(indoc);
608   return 0;
609 }
610
611 void
612 noit_check_rest_init() {
613   assert(noit_http_rest_register(
614     "GET", "/checks/", "^show(/.*)(?<=/)(" UUID_REGEX ")$",
615     rest_show_check
616   ) == 0);
617   assert(noit_http_rest_register(
618     "PUT", "/checks/", "^set(/.*)(?<=/)(" UUID_REGEX ")$",
619     rest_set_check
620   ) == 0);
621   assert(noit_http_rest_register(
622     "DELETE", "/checks/", "^delete(/.*)(?<=/)(" UUID_REGEX ")$",
623     rest_delete_check
624   ) == 0);
625 }
626
Note: See TracBrowser for help on using the browser.