root/src/noit_check_rest.c

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

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