root/src/noit_check_rest.c

Revision c4fc37fcf1cb3f31782b792228a0b35e4cdf2acf, 23.1 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 3 years ago)

make the rest calls dirty the right bits for shatter output

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