root/src/noit_check_rest.c

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

refactor this and expose some of the bits as helpful utility functions, refs #171

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