root/src/modules/httptrap.c

Revision 304ec80b8cf842fc0abe5f9029790908b6455957, 20.4 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 4 days ago)

Convert to libmtev.

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2011, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  * Copyright (c) 2011-2015, Circonus, Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above
13  *       copyright notice, this list of conditions and the following
14  *       disclaimer in the documentation and/or other materials provided
15  *       with the distribution.
16  *     * Neither the name OmniTI Computer Consulting, Inc. nor the names
17  *       of its contributors may be used to endorse or promote products
18  *       derived from this software without specific prior written
19  *       permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
32
33 #include <mtev_defines.h>
34
35 #include <stdio.h>
36 #include <unistd.h>
37 #include <errno.h>
38 #include <assert.h>
39 #include <math.h>
40 #include <ctype.h>
41 #include <yajl/yajl_parse.h>
42
43 #include <mtev_rest.h>
44 #include <mtev_hash.h>
45
46 #include "noit_module.h"
47 #include "noit_check.h"
48 #include "noit_check_tools.h"
49 #include "noit_mtev_bridge.h"
50
51 #define DEFAULT_HTTPTRAP_DELIMITER '`'
52 #define MAX_DEPTH 32
53
54 static mtev_log_stream_t nlerr = NULL;
55 static mtev_log_stream_t nldeb = NULL;
56
57 typedef struct _mod_config {
58   mtev_hash_table *options;
59   mtev_boolean asynch_metrics;
60 } httptrap_mod_config_t;
61
62 typedef struct httptrap_closure_s {
63   noit_module_t *self;
64   int stats_count;
65 } httptrap_closure_t;
66
67 struct value_list {
68   char *v;
69   struct value_list *next;
70 };
71 struct rest_json_payload {
72   noit_check_t *check;
73   stats_t *stats;
74   yajl_handle parser;
75   int len;
76   int complete;
77   char delimiter;
78   char *error;
79   int depth;
80   char *keys[MAX_DEPTH];
81   char array_depth[MAX_DEPTH];
82   unsigned char last_special_key;
83   unsigned char saw_complex_type;
84   metric_type_t last_type;
85   struct value_list *last_value;
86   int cnt;
87   mtev_boolean immediate;
88 };
89
90 #define NEW_LV(json,a) do { \
91   struct value_list *nlv = malloc(sizeof(*nlv)); \
92   nlv->v = a; \
93   nlv->next = json->last_value; \
94   json->last_value = nlv; \
95 } while(0)
96
97 static mtev_boolean
98 mtev_httptrap_check_aynsch(noit_module_t *self,
99                            noit_check_t *check) {
100   const char *config_val;
101   httptrap_mod_config_t *conf;
102   if(!self) return mtev_true;
103   conf = noit_module_get_userdata(self);
104   if(!conf) return mtev_true;
105   mtev_boolean is_asynch = conf->asynch_metrics;
106   if(mtev_hash_retr_str(check->config,
107                         "asynch_metrics", strlen("asynch_metrics"),
108                         (const char **)&config_val)) {
109     if(!strcasecmp(config_val, "false") || !strcasecmp(config_val, "off"))
110       is_asynch = mtev_false;
111     else if(!strcasecmp(config_val, "true") || !strcasecmp(config_val, "on"))
112       is_asynch = mtev_true;
113   }
114
115   if(is_asynch) check->flags |= NP_SUPPRESS_METRICS;
116   else check->flags &= ~NP_SUPPRESS_METRICS;
117   return is_asynch;
118 }
119
120 static void
121 set_array_key(struct rest_json_payload *json) {
122   if(json->array_depth[json->depth] > 0) {
123     char str[256];
124     int strLen;
125     snprintf(str, sizeof(str), "%d", json->array_depth[json->depth] - 1);
126     json->array_depth[json->depth]++;
127     strLen = strlen(str);
128     if(json->keys[json->depth]) free(json->keys[json->depth]);
129     json->keys[json->depth] = NULL;
130     if(json->depth == 0) {
131       json->keys[json->depth] = malloc(strLen+1);
132       memcpy(json->keys[json->depth], str, strLen);
133       json->keys[json->depth][strLen] = '\0';
134     }
135     else {
136       int uplen = strlen(json->keys[json->depth-1]);
137       if(uplen + 1 + strLen > 255) return;
138       json->keys[json->depth] = malloc(uplen + 1 + strLen + 1);
139       memcpy(json->keys[json->depth], json->keys[json->depth-1], uplen);
140       json->keys[json->depth][uplen] = json->delimiter;
141       memcpy(json->keys[json->depth] + uplen + 1, str, strLen);
142       json->keys[json->depth][uplen + 1 + strLen] = '\0';
143     }
144   }
145 }
146 static int
147 httptrap_yajl_cb_null(void *ctx) {
148   struct rest_json_payload *json = ctx;
149   if(json->depth<0) return 0;
150   set_array_key(json);
151   if(json->last_special_key == 0x2) {
152     NEW_LV(json, NULL);
153     return 1;
154   }
155   if(json->last_special_key) return 0;
156   noit_stats_set_metric(json->check, json->stats,
157       json->keys[json->depth], METRIC_INT32, NULL);
158   if(json->immediate)
159     noit_stats_log_immediate_metric(json->check,
160         json->keys[json->depth], METRIC_INT32, NULL);
161   json->cnt++;
162   return 1;
163 }
164 static int
165 httptrap_yajl_cb_boolean(void *ctx, int boolVal) {
166   int ival;
167   struct rest_json_payload *json = ctx;
168   if(json->depth<0) return 0;
169   set_array_key(json);
170   if(json->last_special_key == 0x2) {
171     NEW_LV(json, strdup(boolVal ? "1" : "0"));
172     return 1;
173   }
174   if(json->last_special_key) return 0;
175   ival = boolVal ? 1 : 0;
176   noit_stats_set_metric(json->check, json->stats,
177       json->keys[json->depth], METRIC_INT32, &ival);
178   if(json->immediate)
179     noit_stats_log_immediate_metric(json->check,
180         json->keys[json->depth], METRIC_INT32, &ival);
181   json->cnt++;
182   return 1;
183 }
184 static int
185 httptrap_yajl_cb_number(void *ctx, const char * numberVal,
186                         size_t numberLen) {
187   char val[128];
188   struct rest_json_payload *json = ctx;
189   if(json->depth<0) return 0;
190   set_array_key(json);
191   if(json->last_special_key == 0x2) {
192     char *str;
193     str = malloc(numberLen+1);
194     memcpy(str, numberVal, numberLen);
195     str[numberLen] = '\0';
196     NEW_LV(json, str);
197     return 1;
198   }
199   if(json->last_special_key) return 0;
200   if(numberLen > sizeof(val)-1) numberLen = sizeof(val)-1;
201   memcpy(val, numberVal, numberLen);
202   val[numberLen] = '\0';
203   noit_stats_set_metric(json->check, json->stats,
204       json->keys[json->depth], METRIC_GUESS, val);
205   if(json->immediate)
206     noit_stats_log_immediate_metric(json->check,
207         json->keys[json->depth], METRIC_GUESS, val);
208   json->cnt++;
209   return 1;
210 }
211 static int
212 httptrap_yajl_cb_string(void *ctx, const unsigned char * stringVal,
213                         size_t stringLen) {
214   struct rest_json_payload *json = ctx;
215   char val[4096];
216   if(json->depth<0) return 0;
217   set_array_key(json);
218   if(json->last_special_key == 0x1) {
219     if(stringLen != 1) return 0;
220     if(*stringVal == 'L' || *stringVal == 'l' ||
221         *stringVal == 'I' || *stringVal == 'i' ||
222         *stringVal == 'n' || *stringVal == 's') {
223       json->last_type = *stringVal;
224       json->saw_complex_type |= 0x1;
225       return 1;
226     }
227     return 0;
228   }
229   else if(json->last_special_key == 0x2) {
230     char *str;
231     str = malloc(stringLen+1);
232     memcpy(str, stringVal, stringLen);
233     str[stringLen] = '\0';
234     NEW_LV(json, str);
235     json->saw_complex_type |= 0x2;
236     return 1;
237   }
238   if(stringLen > sizeof(val)-1) stringLen = sizeof(val)-1;
239   memcpy(val, stringVal, stringLen);
240   val[stringLen] = '\0';
241   noit_stats_set_metric(json->check, json->stats,
242       json->keys[json->depth], METRIC_GUESS, val);
243   if(json->immediate)
244     noit_stats_log_immediate_metric(json->check,
245         json->keys[json->depth], METRIC_GUESS, val);
246   json->cnt++;
247   return 1;
248 }
249 static int
250 httptrap_yajl_cb_start_map(void *ctx) {
251   struct rest_json_payload *json = ctx;
252   set_array_key(json);
253   json->depth++;
254   if(json->depth >= MAX_DEPTH) return 0;
255   return 1;
256 }
257 static int
258 httptrap_yajl_cb_end_map(void *ctx) {
259   struct value_list *p, *last_p = NULL;
260   struct rest_json_payload *json = ctx;
261   json->depth--;
262   if(json->saw_complex_type == 0x3) {
263     long double total = 0, cnt = 0;
264     mtev_boolean use_avg = mtev_false;
265     for(p=json->last_value;p;p=p->next) {
266       noit_stats_set_metric_coerce(json->check, json->stats,
267           json->keys[json->depth], json->last_type, p->v);
268       last_p = p;
269       if(p->v != NULL &&
270          (json->last_type == 'L' || json->last_type == 'l' ||
271           json->last_type == 'I' || json->last_type == 'i' ||
272           json->last_type == 'n')) {
273         total += strtold(p->v, NULL);
274         cnt = cnt + 1;
275         use_avg = mtev_true;
276       }
277       json->cnt++;
278     }
279     if(json->immediate && last_p != NULL) {
280       if(use_avg) {
281         double avg = total / cnt;
282         noit_stats_log_immediate_metric(json->check,
283             json->keys[json->depth], 'n', &avg);
284       }
285       else {
286         noit_stats_log_immediate_metric(json->check,
287             json->keys[json->depth], json->last_type, last_p->v);
288       }
289     }
290   }
291   json->saw_complex_type = 0;
292   for(p=json->last_value;p;) {
293     struct value_list *savenext;
294     savenext = p->next;
295     if(p->v) free(p->v);
296     savenext = p->next;
297     free(p);
298     p = savenext;
299   }
300   json->last_value = NULL;
301   return 1;
302 }
303 static int
304 httptrap_yajl_cb_start_array(void *ctx) {
305   struct rest_json_payload *json = ctx;
306   json->depth++;
307   json->array_depth[json->depth]++;
308   return 1;
309 }
310 static int
311 httptrap_yajl_cb_end_array(void *ctx) {
312   struct rest_json_payload *json = ctx;
313   json->array_depth[json->depth] = 0;
314   json->depth--;
315   return 1;
316 }
317 static int
318 httptrap_yajl_cb_map_key(void *ctx, const unsigned char * key,
319                          size_t stringLen) {
320   struct rest_json_payload *json = ctx;
321   if(stringLen > 255) return 0;
322   if(json->keys[json->depth]) free(json->keys[json->depth]);
323   json->keys[json->depth] = NULL;
324   if(stringLen == 5 && memcmp(key, "_type", 5) == 0) {
325     json->last_special_key = 0x1;
326     if(json->depth > 0) json->keys[json->depth] = strdup(json->keys[json->depth-1]);
327     return 1;
328   }
329   if(stringLen == 6 && memcmp(key, "_value", 6) == 0) {
330     if(json->depth > 0) json->keys[json->depth] = strdup(json->keys[json->depth-1]);
331     json->last_special_key = 0x2;
332     json->saw_complex_type |= 0x2;
333     return 1;
334   }
335   json->last_special_key = 0;
336   if(json->depth == 0) {
337     json->keys[json->depth] = malloc(stringLen+1);
338     memcpy(json->keys[json->depth], key, stringLen);
339     json->keys[json->depth][stringLen] = '\0';
340   }
341   else {
342     int uplen = strlen(json->keys[json->depth-1]);
343     if(uplen + 1 + stringLen > 255) return 0;
344     json->keys[json->depth] = malloc(uplen + 1 + stringLen + 1);
345     memcpy(json->keys[json->depth], json->keys[json->depth-1], uplen);
346     json->keys[json->depth][uplen] = json->delimiter;
347     memcpy(json->keys[json->depth] + uplen + 1, key, stringLen);
348     json->keys[json->depth][uplen + 1 + stringLen] = '\0';
349   }
350   return 1;
351 }
352 static yajl_callbacks httptrap_yajl_callbacks = {
353   .yajl_null = httptrap_yajl_cb_null,
354   .yajl_boolean = httptrap_yajl_cb_boolean,
355   .yajl_number = httptrap_yajl_cb_number,
356   .yajl_string = httptrap_yajl_cb_string,
357   .yajl_start_map = httptrap_yajl_cb_start_map,
358   .yajl_map_key = httptrap_yajl_cb_map_key,
359   .yajl_end_map = httptrap_yajl_cb_end_map,
360   .yajl_start_array = httptrap_yajl_cb_start_array,
361   .yajl_end_array = httptrap_yajl_cb_end_array
362 };
363
364 static void
365 rest_json_payload_free(void *f) {
366   int i;
367   struct rest_json_payload *json = f;
368   if(json->parser) yajl_free(json->parser);
369   if(json->error) free(json->error);
370   for(i=0;i<MAX_DEPTH;i++)
371     if(json->keys[i]) free(json->keys[i]);
372   if(json->last_value) free(json->last_value);
373   free(json);
374 }
375
376 static struct rest_json_payload *
377 rest_get_json_upload(mtev_http_rest_closure_t *restc,
378                     int *mask, int *complete) {
379   struct rest_json_payload *rxc;
380   mtev_http_request *req = mtev_http_session_request(restc->http_ctx);
381   httptrap_closure_t *ccl;
382   int content_length;
383   char buffer[32768];
384
385   content_length = mtev_http_request_content_length(req);
386   rxc = restc->call_closure;
387   ccl = rxc->check->closure;
388   rxc->immediate = mtev_httptrap_check_aynsch(ccl->self, rxc->check);
389   while(!rxc->complete) {
390     int len;
391     len = mtev_http_session_req_consume(
392             restc->http_ctx, buffer,
393             MIN(content_length - rxc->len, sizeof(buffer)),
394             sizeof(buffer),
395             mask);
396     if(len > 0) {
397       yajl_status status;
398       status = yajl_parse(rxc->parser, (unsigned char *)buffer, len);
399       if(status != yajl_status_ok) {
400         unsigned char *err;
401         *complete = 1;
402         err = yajl_get_error(rxc->parser, 0, (unsigned char *)buffer, len);
403         rxc->error = strdup((char *)err);
404         yajl_free_error(rxc->parser, err);
405         return rxc;
406       }
407       rxc->len += len;
408     }
409     if(len < 0 && errno == EAGAIN) return NULL;
410     else if(len < 0) {
411       *complete = 1;
412       return NULL;
413     }
414     content_length = mtev_http_request_content_length(req);
415     if((mtev_http_request_payload_chunked(req) && len == 0) ||
416        (rxc->len == content_length)) {
417       rxc->complete = 1;
418       yajl_complete_parse(rxc->parser);
419     }
420   }
421
422   *complete = 1;
423   return rxc;
424 }
425
426 static int httptrap_submit(noit_module_t *self, noit_check_t *check,
427                            noit_check_t *cause) {
428   httptrap_closure_t *ccl;
429   struct timeval duration;
430   /* We are passive, so we don't do anything for transient checks */
431   if(check->flags & NP_TRANSIENT) return 0;
432
433   mtev_httptrap_check_aynsch(self, check);
434   if(!check->closure) {
435     ccl = check->closure = (void *)calloc(1, sizeof(httptrap_closure_t));
436     memset(ccl, 0, sizeof(httptrap_closure_t));
437     ccl->self = self;
438   } else {
439     // Don't count the first run
440     char human_buffer[256];
441     ccl = (httptrap_closure_t*)check->closure;
442     gettimeofday(&check->stats.inprogress.whence, NULL);
443     sub_timeval(check->stats.inprogress.whence, check->last_fire_time, &duration);
444     check->stats.inprogress.duration = duration.tv_sec * 1000 + duration.tv_usec / 1000;
445
446     snprintf(human_buffer, sizeof(human_buffer),
447              "dur=%d,run=%d,stats=%d", check->stats.inprogress.duration,
448              check->generation, ccl->stats_count);
449     mtevL(nldeb, "httptrap(%s) [%s]\n", check->target, human_buffer);
450
451     // Not sure what to do here
452     check->stats.inprogress.available = (ccl->stats_count > 0) ?
453         NP_AVAILABLE : NP_UNAVAILABLE;
454     check->stats.inprogress.state = (ccl->stats_count > 0) ?
455         NP_GOOD : NP_BAD;
456     check->stats.inprogress.status = human_buffer;
457     if(check->last_fire_time.tv_sec)
458       noit_check_passive_set_stats(check, &check->stats.inprogress);
459
460     memcpy(&check->last_fire_time, &check->stats.inprogress.whence, sizeof(duration));
461   }
462   ccl->stats_count = 0;
463   noit_check_stats_clear(check, &check->stats.inprogress);
464   return 0;
465 }
466
467 static int
468 push_payload_at_check(struct rest_json_payload *rxc) {
469   httptrap_closure_t *ccl;
470   mtev_boolean immediate;
471   char key[256];
472
473   if (!rxc->check || strcmp(rxc->check->module, "httptrap")) return 0;
474   if (rxc->check->closure == NULL) return 0;
475   ccl = rxc->check->closure;
476   immediate = mtev_httptrap_check_aynsch(ccl->self,rxc->check);
477
478   /* do it here */
479   ccl->stats_count = rxc->cnt;
480   return rxc->cnt;
481 }
482
483 static int
484 rest_httptrap_handler(mtev_http_rest_closure_t *restc,
485                       int npats, char **pats) {
486   int mask, complete = 0, cnt;
487   struct rest_json_payload *rxc = NULL;
488   const char *error = "internal error", *secret = NULL;
489   mtev_http_session_ctx *ctx = restc->http_ctx;
490   char json_out[128];
491   noit_check_t *check;
492   uuid_t check_id;
493
494   if(npats != 2) {
495     error = "bad uri";
496     goto error;
497   }
498   if(uuid_parse(pats[0], check_id)) {
499     error = "uuid parse error";
500     goto error;
501   }
502
503   if(restc->call_closure == NULL) {
504     httptrap_closure_t *ccl;
505     const char *delimiter = NULL;
506     rxc = restc->call_closure = calloc(1, sizeof(*rxc));
507     rxc->delimiter = DEFAULT_HTTPTRAP_DELIMITER;
508     check = noit_poller_lookup(check_id);
509     if(!check || strcmp(check->module, "httptrap")) {
510       error = "no such httptrap check";
511       goto error;
512     }
513     (void)mtev_hash_retr_str(check->config, "secret", strlen("secret"), &secret);
514     if(!secret) secret = "";
515     if(strcmp(pats[1], secret)) {
516       error = "secret mismatch";
517       goto error;
518     }
519     (void)mtev_hash_retr_str(check->config, "delimiter", strlen("delimiter"), &delimiter);
520     if(delimiter && *delimiter) rxc->delimiter = *delimiter;
521     rxc->check = check;
522     ccl = check->closure;
523     if(!ccl) {
524       error = "noitd is booting, try again in a bit";
525       goto error;
526     }
527     rxc->stats = &rxc->check->stats.inprogress;
528     rxc->parser = yajl_alloc(&httptrap_yajl_callbacks, NULL, rxc);
529     rxc->depth = -1;
530     yajl_config(rxc->parser, yajl_allow_comments, 1);
531     yajl_config(rxc->parser, yajl_dont_validate_strings, 1);
532     yajl_config(rxc->parser, yajl_allow_trailing_garbage, 1);
533     yajl_config(rxc->parser, yajl_allow_partial_values, 1);
534     restc->call_closure_free = rest_json_payload_free;
535   }
536   else rxc = restc->call_closure;
537
538   /* flip threads */
539   {
540     mtev_http_connection *conn = mtev_http_session_connection(ctx);
541     eventer_t e = mtev_http_connection_event(conn);
542     if(e) {
543       pthread_t tgt = CHOOSE_EVENTER_THREAD_FOR_CHECK(rxc->check);
544       if(!pthread_equal(e->thr_owner, tgt)) {
545         e->thr_owner = tgt;
546         return EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION;
547       }
548     }
549   }
550
551   rxc = rest_get_json_upload(restc, &mask, &complete);
552   if(rxc == NULL && !complete) return mask;
553
554   if(!rxc) goto error;
555   if(rxc->error) goto error;
556
557   cnt = push_payload_at_check(rxc);
558
559   mtev_http_response_ok(ctx, "application/json");
560   snprintf(json_out, sizeof(json_out),
561            "{ \"stats\": %d }", cnt);
562   mtev_http_response_append(ctx, json_out, strlen(json_out));
563   mtev_http_response_end(ctx);
564   return 0;
565
566  error:
567   mtev_http_response_server_error(ctx, "application/json");
568   mtev_http_response_append(ctx, "{ error: \"", 10);
569   if(rxc && rxc->error) error = rxc->error;
570   mtev_http_response_append(ctx, error, strlen(error));
571   mtev_http_response_append(ctx, "\" }", 3);
572   mtev_http_response_end(ctx);
573   return 0;
574 }
575
576 static int mtev_httptrap_initiate_check(noit_module_t *self,
577                                         noit_check_t *check,
578                                         int once, noit_check_t *cause) {
579   check->flags |= NP_PASSIVE_COLLECTION;
580   if (check->closure == NULL) {
581     httptrap_closure_t *ccl;
582     ccl = check->closure = (void *)calloc(1, sizeof(httptrap_closure_t));
583     ccl->self = self;
584   }
585   INITIATE_CHECK(httptrap_submit, self, check, cause);
586   return 0;
587 }
588
589 static int mtev_httptrap_config(noit_module_t *self, mtev_hash_table *options) {
590   httptrap_mod_config_t *conf;
591   conf = noit_module_get_userdata(self);
592   if(conf) {
593     if(conf->options) {
594       mtev_hash_destroy(conf->options, free, free);
595       free(conf->options);
596     }
597   }
598   else
599     conf = calloc(1, sizeof(*conf));
600   conf->options = options;
601   noit_module_set_userdata(self, conf);
602   return 1;
603 }
604
605 static int mtev_httptrap_onload(mtev_image_t *self) {
606   if(!nlerr) nlerr = mtev_log_stream_find("error/httptrap");
607   if(!nldeb) nldeb = mtev_log_stream_find("debug/httptrap");
608   if(!nlerr) nlerr = noit_error;
609   if(!nldeb) nldeb = noit_debug;
610   return 0;
611 }
612
613 static int mtev_httptrap_init(noit_module_t *self) {
614   const char *config_val;
615   httptrap_mod_config_t *conf;
616   conf = noit_module_get_userdata(self);
617
618   conf->asynch_metrics = mtev_true;
619   if(mtev_hash_retr_str(conf->options,
620                         "asynch_metrics", strlen("asynch_metrics"),
621                         (const char **)&config_val)) {
622     if(!strcasecmp(config_val, "false") || !strcasecmp(config_val, "off"))
623       conf->asynch_metrics = mtev_false;
624   }
625
626   noit_module_set_userdata(self, conf);
627
628   /* register rest handler */
629   mtev_http_rest_register("PUT", "/module/httptrap/",
630                           "^(" UUID_REGEX ")/([^/]*).*$",
631                           rest_httptrap_handler);
632   mtev_http_rest_register("POST", "/module/httptrap/",
633                           "^(" UUID_REGEX ")/([^/]*).*$",
634                           rest_httptrap_handler);
635   return 0;
636 }
637
638 #include "httptrap.xmlh"
639 noit_module_t httptrap = {
640   {
641     .magic = NOIT_MODULE_MAGIC,
642     .version = NOIT_MODULE_ABI_VERSION,
643     .name = "httptrap",
644     .description = "httptrap collection",
645     .xml_description = httptrap_xml_description,
646     .onload = mtev_httptrap_onload
647   },
648   mtev_httptrap_config,
649   mtev_httptrap_init,
650   mtev_httptrap_initiate_check,
651   NULL
652 };
Note: See TracBrowser for help on using the browser.