root/src/noit_check_rest.c

Revision a33aa52dc08eb296a042f396243bde78cf840b99, 22.1 kB (checked in by gdusbabek <gdusbabek@gmail.com>, 3 years ago)

validate resolve_rtype and show in xml

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