root/src/noit_check_rest.c

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

programmatic configuration will have to suffice for now, closes #182

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