root/src/noit_check_rest.c

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

allow custom error codes, refs #171

  • 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 #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->children;
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->children;
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; 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   for(n = c; n; n = n->next) {
349     xmlNodePtr co = xmlNewNode(NULL, n->name);
350     xmlNodeAddContent(co, XML_GET_CONTENT(n));
351     xmlAddChild(config, co);
352   }
353   if(oldconfig) {
354     xmlReplaceNode(oldconfig, config);
355     xmlFreeNode(oldconfig);
356   }
357   else xmlAddChild(check, config);
358 }
359 static xmlNodePtr
360 make_conf_path(char *path) {
361   xmlNodePtr start, tmp;
362   char fullpath[1024], *tok, *brk;
363   if(!path || strlen(path) < 1) return NULL;
364   snprintf(fullpath, sizeof(fullpath), "%s", path+1);
365   fullpath[strlen(fullpath)-1] = '\0';
366   start = noit_conf_get_section(NULL, "/noit/checks");
367   if(!start) return NULL;
368   for (tok = strtok_r(fullpath, "/", &brk);
369        tok;
370        tok = strtok_r(NULL, "/", &brk)) {
371     if(!xmlValidateNameValue((xmlChar *)tok)) return NULL;
372     if(!strcmp(tok, "check")) return NULL;  /* These two paths */
373     if(!strcmp(tok, "config")) return NULL; /* are off limits. */
374     for (tmp = start->children; tmp; tmp = tmp->next) {
375       if(!strcmp((char *)tmp->name, tok)) break;
376     }
377     if(!tmp) {
378       tmp = xmlNewNode(NULL, (xmlChar *)tok);
379       xmlAddChild(start, tmp);
380     }
381     start = tmp;
382   }
383   return start;
384 }
385 static int
386 rest_delete_check(noit_http_rest_closure_t *restc,
387                   int npats, char **pats) {
388   noit_http_session_ctx *ctx = restc->http_ctx;
389   xmlXPathObjectPtr pobj = NULL;
390   xmlXPathContextPtr xpath_ctxt = NULL;
391   xmlNodePtr node;
392   uuid_t checkid;
393   noit_check_t *check;
394   const char *error;
395   char xpath[1024], *uuid_conf;
396   int rv, cnt, error_code = 500;
397   noit_boolean exists = noit_false;
398
399   if(npats != 2) goto error;
400
401   if(uuid_parse(pats[1], checkid)) goto error;
402   check = noit_poller_lookup(checkid);
403   if(check)
404     exists = noit_true;
405
406   rv = noit_check_xpath(xpath, sizeof(xpath), pats[0], pats[1]);
407   if(rv == 0) FAIL("uuid not valid");
408   if(rv < 0) FAIL("Tricky McTrickster... No");
409
410   noit_conf_xml_xpath(NULL, &xpath_ctxt);
411   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
412   if(!pobj || pobj->type != XPATH_NODESET ||
413      xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
414     if(exists) { error_code = 403; FAIL("uuid not yours"); }
415     goto not_found;
416   }
417   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
418   if(cnt != 1) FAIL("internal error, |checkid| > 1");
419   node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
420   uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid");
421   if(!uuid_conf || strcasecmp(uuid_conf, pats[1]))
422     FAIL("internal error uuid");
423
424   /* delete this here */
425   noit_poller_deschedule(check->checkid);
426   xmlUnlinkNode(node);
427   xmlFreeNode(node);
428   if(noit_conf_write_file(NULL) != 0)
429     noitL(noit_error, "local config write failed\n");
430   noit_conf_mark_changed();
431   noit_http_response_ok(ctx, "text/html");
432   noit_http_response_end(ctx);
433   goto cleanup;
434
435  not_found:
436   noit_http_response_not_found(ctx, "text/html");
437   noit_http_response_end(ctx);
438   goto cleanup;
439
440  error:
441   noit_http_response_standard(ctx, error_code, "ERROR", "text/html");
442   noit_http_response_end(ctx);
443   goto cleanup;
444
445  cleanup:
446   if(pobj) xmlXPathFreeObject(pobj);
447   return 0;
448 }
449
450 static int
451 rest_set_check(noit_http_rest_closure_t *restc,
452                int npats, char **pats) {
453   noit_http_session_ctx *ctx = restc->http_ctx;
454   xmlXPathObjectPtr pobj = NULL;
455   xmlXPathContextPtr xpath_ctxt = NULL;
456   xmlDocPtr doc = NULL, indoc = NULL;
457   xmlNodePtr node, root, attr, config, parent;
458   uuid_t checkid;
459   noit_check_t *check;
460   char xpath[1024], *uuid_conf;
461   int rv, cnt, error_code = 500;
462   const char *error = "internal error";
463   noit_boolean exists = noit_false;
464   struct rest_xml_payload *rxc;
465
466   if(npats != 2) goto error;
467
468   if(restc->call_closure == NULL) {
469     rxc = restc->call_closure = calloc(1, sizeof(*rxc));
470     restc->call_closure_free = rest_xml_payload_free;
471   }
472   rxc = restc->call_closure;
473   while(!rxc->complete) {
474     int len, mask;
475     if(rxc->len == rxc->allocd) {
476       char *b;
477       rxc->allocd += 32768;
478       b = rxc->buffer ? realloc(rxc->buffer, rxc->allocd) :
479                         malloc(rxc->allocd);
480       if(!b) FAIL("alloc failed");
481       rxc->buffer = b;
482     }
483     len = noit_http_session_req_consume(restc->http_ctx,
484                                         rxc->buffer + rxc->len,
485                                         rxc->allocd - rxc->len,
486                                         &mask);
487     if(len > 0) rxc->len += len;
488     if(len < 0 && errno == EAGAIN) return mask;
489     if(rxc->len == restc->http_ctx->req.content_length) rxc->complete = 1;
490   }
491
492   indoc = xmlParseMemory(rxc->buffer, rxc->len);
493   if(indoc == NULL) FAIL("xml parse error");
494   if(!validate_check_post(indoc, &attr, &config, &error)) goto error;
495
496   if(uuid_parse(pats[1], checkid)) goto error;
497   check = noit_poller_lookup(checkid);
498   if(check)
499     exists = noit_true;
500
501   rv = noit_check_xpath(xpath, sizeof(xpath), pats[0], pats[1]);
502   if(rv == 0) FAIL("uuid not valid");
503   if(rv < 0) FAIL("Tricky McTrickster... No");
504
505   noit_conf_xml_xpath(NULL, &xpath_ctxt);
506   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
507   if(!pobj || pobj->type != XPATH_NODESET ||
508      xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
509     if(exists) { error_code = 403; FAIL("uuid not yours"); }
510     else {
511       char *target = NULL, *name = NULL, *module = NULL;
512       noit_module_t *m;
513       xmlNodePtr newcheck, a;
514       /* make sure this isn't a dup */
515       for(a = attr; a; a = a->next) {
516         if(!strcmp((char *)a->name, "target"))
517           target = (char *)xmlNodeGetContent(a);
518         if(!strcmp((char *)a->name, "name"))
519           name = (char *)xmlNodeGetContent(a);
520         if(!strcmp((char *)a->name, "module"))
521           module = (char *)xmlNodeGetContent(a);
522       }
523       exists = (noit_poller_lookup_by_name(target, name) != NULL);
524       m = noit_module_lookup(module);
525       xmlFree(target);
526       xmlFree(name);
527       xmlFree(module);
528       if(exists) FAIL("target`name already registered");
529       if(!m) FAIL("module does not exist");
530       /* create a check here */
531       newcheck = xmlNewNode(NULL, (xmlChar *)"check");
532       xmlSetProp(newcheck, (xmlChar *)"uuid", (xmlChar *)pats[1]);
533       configure_xml_check(newcheck, attr, config);
534       parent = make_conf_path(pats[0]);
535       if(!parent) FAIL("invalid path");
536       xmlAddChild(parent, newcheck);
537     }
538   }
539   if(exists) {
540     int module_change;
541     char *target, *name, *module;
542     xmlNodePtr a;
543     noit_check_t *ocheck;
544
545     cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
546     if(cnt != 1) FAIL("internal error, |checkid| > 1");
547     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
548     uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid");
549     if(!uuid_conf || strcasecmp(uuid_conf, pats[1]))
550       FAIL("internal error uuid");
551
552     /* make sure this isn't a dup */
553     for(a = attr; a; a = a->next) {
554       if(!strcmp((char *)a->name, "target"))
555         target = (char *)xmlNodeGetContent(a);
556       if(!strcmp((char *)a->name, "name"))
557         name = (char *)xmlNodeGetContent(a);
558       if(!strcmp((char *)a->name, "module"))
559         module = (char *)xmlNodeGetContent(a);
560     }
561     ocheck = noit_poller_lookup_by_name(target, name);
562     module_change = strcmp(check->module, module);
563     xmlFree(target);
564     xmlFree(name);
565     xmlFree(module);
566     if(ocheck && ocheck != check) FAIL("new target`name would collide");
567     if(module_change) FAIL("cannot change module");
568     configure_xml_check(node, attr, config);
569     parent = make_conf_path(pats[0]);
570     if(!parent) FAIL("invalid path");
571     xmlUnlinkNode(node);
572     xmlAddChild(parent, node);
573   }
574
575   if(noit_conf_write_file(NULL) != 0)
576     noitL(noit_error, "local config write failed\n");
577   noit_conf_mark_changed();
578   noit_poller_reload(xpath);
579   if(restc->call_closure_free) restc->call_closure_free(restc->call_closure);
580   restc->call_closure_free = NULL;
581   restc->call_closure = NULL;
582   if(pobj) xmlXPathFreeObject(pobj);
583   if(doc) xmlFreeDoc(doc);
584   if(indoc) xmlFreeDoc(indoc);
585   restc->fastpath = rest_show_check;
586   return restc->fastpath(restc, restc->nparams, restc->params);
587
588  error:
589   noit_http_response_standard(ctx, error_code, "ERROR", "text/html");
590   doc = xmlNewDoc((xmlChar *)"1.0");
591   root = xmlNewDocNode(doc, NULL, (xmlChar *)"error", NULL);
592   xmlDocSetRootElement(doc, root);
593   xmlNodeAddContent(root, (xmlChar *)error);
594   noit_http_response_xml(ctx, doc);
595   noit_http_response_end(ctx);
596   goto cleanup;
597
598  cleanup:
599   if(pobj) xmlXPathFreeObject(pobj);
600   if(doc) xmlFreeDoc(doc);
601   if(indoc) xmlFreeDoc(indoc);
602   return 0;
603 }
604
605 void
606 noit_check_rest_init() {
607   assert(noit_http_rest_register(
608     "GET", "/checks/", "^show(/.*)(?<=/)(" UUID_REGEX ")$",
609     rest_show_check
610   ) == 0);
611   assert(noit_http_rest_register(
612     "PUT", "/checks/", "^set(/.*)(?<=/)(" UUID_REGEX ")$",
613     rest_set_check
614   ) == 0);
615   assert(noit_http_rest_register(
616     "DELETE", "/checks/", "^delete(/.*)(?<=/)(" UUID_REGEX ")$",
617     rest_delete_check
618   ) == 0);
619 }
620
Note: See TracBrowser for help on using the browser.