root/src/noit_check.c

Revision 57a327349609ef60a33dc6da15017c5d6642320a, 11.7 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

renaming something before it becomes crazy painful

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  */
5
6 #include "noit_defines.h"
7
8 #include <stdio.h>
9 #include <unistd.h>
10 #include <assert.h>
11 #include <netinet/in.h>
12 #include <arpa/inet.h>
13
14 #include "utils/noit_log.h"
15 #include "utils/noit_hash.h"
16 #include "utils/noit_skiplist.h"
17 #include "noit_conf.h"
18 #include "noit_check.h"
19 #include "noit_module.h"
20 #include "eventer/eventer.h"
21
22 static noit_hash_table polls = NOIT_HASH_EMPTY;
23 static noit_skiplist polls_by_name = { 0 };
24 static u_int32_t __config_load_generation = 0;
25 struct uuid_dummy {
26   uuid_t foo;
27 };
28
29 #define UUID_SIZE sizeof(struct uuid_dummy)
30
31 static const char *
32 __noit_check_available_string(int16_t available) {
33   switch(available) {
34     case NP_AVAILABLE:    return "available";
35     case NP_UNAVAILABLE:  return "unavailable";
36     case NP_UNKNOWN:      return "unknown";
37   }
38   return "???";
39 }
40 static const char *
41 __noit_check_state_string(int16_t state) {
42   switch(state) {
43     case NP_GOOD:         return "good";
44     case NP_BAD:          return "bad";
45     case NP_UNKNOWN:      return "unknown";
46   }
47   return "???";
48 }
49 static int __check_name_compare(void *a, void *b) {
50   noit_check_t *ac = a;
51   noit_check_t *bc = b;
52   int rv;
53   if((rv = strcmp(ac->target, bc->target)) != 0) return rv;
54   if((rv = strcmp(ac->name, bc->name)) != 0) return rv;
55   return 0;
56 }
57 void
58 noit_poller_load_checks() {
59   int i, cnt = 0;
60   noit_conf_section_t *sec;
61   __config_load_generation++;
62   sec = noit_conf_get_sections(NULL, "/noit/checks//check", &cnt);
63   for(i=0; i<cnt; i++) {
64     char uuid_str[37];
65     char target[256];
66     char module[256];
67     char name[256];
68     char oncheck[1024];
69     int no_period = 0;
70     int no_oncheck = 0;
71     int period = 0, timeout = 0;
72     uuid_t uuid, out_uuid;
73     noit_hash_table *options;
74
75     if(!noit_conf_get_stringbuf(sec[i], "@uuid",
76                                 uuid_str, sizeof(uuid_str))) {
77       noitL(noit_stderr, "check %d has no uuid\n", i+1);
78       continue;
79     }
80     if(uuid_parse(uuid_str, uuid)) {
81       noitL(noit_stderr, "check uuid: '%s' is invalid\n", uuid_str);
82       continue;
83     }
84     if(!noit_conf_get_stringbuf(sec[i], "ancestor-or-self::node()/target", target, sizeof(target))) {
85       noitL(noit_stderr, "check uuid: '%s' has no target\n",
86             uuid_str);
87       continue;
88     }
89     if(!noit_conf_get_stringbuf(sec[i], "ancestor-or-self::node()/module", module, sizeof(module))) {
90       noitL(noit_stderr, "check uuid: '%s' has no module\n",
91             uuid_str);
92       continue;
93     }
94     if(!noit_conf_get_stringbuf(sec[i], "name", name, sizeof(name))) {
95       strcpy(name, module);
96     }
97     if(!noit_conf_get_int(sec[i], "ancestor-or-self::node()/period", &period)) {
98       no_period = 1;
99     }
100     if(!noit_conf_get_stringbuf(sec[i], "ancestor-or-self::node()/oncheck", oncheck, sizeof(oncheck))) {
101       oncheck[0] = '\0';
102       no_oncheck = 1;
103     }
104     if(no_period && no_oncheck) {
105       noitL(noit_stderr, "check uuid: '%s' has neither period nor oncheck\n",
106             uuid_str);
107       continue;
108     }
109     if(!(no_period || no_oncheck)) {
110       noitL(noit_stderr, "check uuid: '%s' has has on check and period.\n",
111             uuid_str);
112       continue;
113     }
114     if(!noit_conf_get_int(sec[i], "ancestor-or-self::node()/timeout", &timeout)) {
115       noitL(noit_stderr, "check uuid: '%s' has no timeout\n", uuid_str);
116       continue;
117     }
118     if(!no_period && timeout >= period) {
119       noitL(noit_stderr, "check uuid: '%s' timeout > period\n", uuid_str);
120       timeout = period/2;
121     }
122     options = noit_conf_get_hash(sec[i], "ancestor-or-self::node()/config/*");
123     noit_poller_schedule(target, module, name, options,
124                          period, timeout, oncheck[0] ? oncheck : NULL,
125                          uuid, out_uuid);
126     noitL(noit_debug, "loaded uuid: %s\n", uuid_str);
127   }
128 }
129
130 void
131 noit_poller_initiate() {
132   noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
133   uuid_t key_id;
134   int klen;
135   noit_check_t *check;
136   while(noit_hash_next(&polls, &iter, (const char **)key_id, &klen,
137                        (void **)&check)) {
138     noit_module_t *mod;
139     mod = noit_module_lookup(check->module);
140     if(mod) {
141       if((check->flags & NP_DISABLED) == 0)
142         mod->initiate_check(mod, check, 0, NULL);
143     }
144     else {
145       noitL(noit_stderr, "Cannot find module '%s'\n", check->module);
146       check->flags |= NP_DISABLED;
147     }
148   }
149 }
150
151 void
152 noit_poller_make_causal_map() {
153   noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
154   uuid_t key_id;
155   int klen;
156   noit_check_t *check, *parent;
157   while(noit_hash_next(&polls, &iter, (const char **)key_id, &klen,
158                        (void **)&check)) {
159     if(check->oncheck) {
160       /* This service is causally triggered by another service */
161       char fullcheck[1024];
162       char *name = check->oncheck;
163       char *target = NULL;
164
165       if((target = strchr(check->oncheck, '`')) != NULL) {
166         strlcpy(fullcheck, check->oncheck, target - check->oncheck);
167         name = target + 1;
168         target = fullcheck;
169       }
170       else
171        target = check->target;
172
173       parent = noit_poller_lookup_by_name(target, name);
174       if(!parent) {
175         check->flags |= NP_DISABLED;
176         noitL(noit_stderr, "Disabling check %s/%s, can't find oncheck %s/%s\n",
177               check->target, check->name, target, name);
178       }
179       else {
180         dep_list_t *dep;
181         dep = malloc(sizeof(*dep));
182         dep->check = check;
183         dep->next = parent->causal_checks;
184         parent->causal_checks = dep;
185       }
186     }
187   }
188 }
189 void
190 noit_poller_init() {
191   noit_skiplist_init(&polls_by_name);
192   noit_skiplist_set_compare(&polls_by_name, __check_name_compare,
193                             __check_name_compare);
194   noit_poller_load_checks();
195   noit_poller_make_causal_map();
196   noit_poller_initiate();
197 }
198
199 int
200 noit_poller_schedule(const char *target,
201                      const char *module,
202                      const char *name,
203                      noit_hash_table *config,
204                      u_int32_t period,
205                      u_int32_t timeout,
206                      const char *oncheck,
207                      uuid_t in,
208                      uuid_t out) {
209   int8_t family;
210   int rv;
211   union {
212     struct in_addr addr4;
213     struct in6_addr addr6;
214   } a;
215   noit_check_t *new_check;
216
217
218   family = AF_INET;
219   rv = inet_pton(family, target, &a);
220   if(rv != 1) {
221     family = AF_INET6;
222     rv = inet_pton(family, target, &a);
223     if(rv != 1) {
224       noitL(noit_stderr, "Cannot translate '%s' to IP\n", target);
225       return -1;
226     }
227   }
228
229   new_check = calloc(1, sizeof(*new_check));
230   if(!new_check) return -1;
231   new_check->generation = __config_load_generation;
232   new_check->target_family = family;
233   memcpy(&new_check->target_addr, &a, sizeof(a));
234   new_check->target = strdup(target);
235   new_check->module = strdup(module);
236   new_check->name = name ? strdup(name): NULL;
237
238   if(config != NULL) {
239     noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
240     const char *k;
241     int klen;
242     void *data;
243     new_check->config = calloc(1, sizeof(*new_check->config));
244     while(noit_hash_next(config, &iter, &k, &klen, &data)) {
245       noit_hash_store(new_check->config, strdup(k), klen, strdup((char *)data));
246     }
247   }
248   new_check->oncheck = oncheck ? strdup(oncheck) : NULL;
249   new_check->period = period;
250   new_check->timeout = timeout;
251   new_check->flags = 0;
252   if(uuid_is_null(in))
253     uuid_generate(new_check->checkid);
254   else
255     uuid_copy(new_check->checkid, in);
256
257   assert(noit_hash_store(&polls,
258                          (char *)new_check->checkid, UUID_SIZE,
259                          new_check));
260   noit_skiplist_insert(&polls_by_name, new_check);
261   uuid_copy(out, new_check->checkid);
262   return 0;
263 }
264
265 int
266 noit_poller_deschedule(uuid_t in) {
267   noit_check_t *checker;
268   if(noit_hash_retrieve(&polls,
269                         (char *)in, UUID_SIZE,
270                         (void **)&checker) == 0) {
271     return -1;
272   }
273   if(checker->flags & NP_RUNNING) {
274     checker->flags |= NP_KILLED;
275     return 0;
276   }
277   if(checker->fire_event) {
278      eventer_remove(checker->fire_event);
279      eventer_free(checker->fire_event);
280      checker->fire_event = NULL;
281   }
282   noit_hash_delete(&polls, (char *)in, UUID_SIZE, free, free);
283
284   if(checker->target) free(checker->target);
285   if(checker->module) free(checker->module);
286   if(checker->name) free(checker->name);
287   if(checker->config) {
288     noit_hash_destroy(checker->config, free, free);
289     free(checker->config);
290     checker->config = NULL;
291   }
292   free(checker);
293   return 0;
294 }
295
296 noit_check_t *
297 noit_poller_lookup(uuid_t in) {
298   noit_check_t *check;
299   if(noit_hash_retrieve(&polls,
300                         (char *)in, UUID_SIZE,
301                         (void **)&check)) {
302     return check;
303   }
304   return NULL;
305 }
306 noit_check_t *
307 noit_poller_lookup_by_name(char *target, char *name) {
308   noit_check_t *check, *tmp_check;
309   tmp_check = calloc(1, sizeof(*tmp_check));
310   tmp_check->target = target;
311   tmp_check->name = name;
312   check = noit_skiplist_find(&polls_by_name, tmp_check, NULL);
313   free(tmp_check);
314   return check;
315 }
316
317 static void
318 __free_metric(void *vm) {
319   metric_t *m = vm;
320   free(m->metric_name);
321   if(m->metric_value.i) free(m->metric_value.i);
322 }
323
324 void
325 __stats_add_metric(stats_t *newstate, metric_t *m) {
326   noit_hash_replace(&newstate->metrics, m->metric_name, strlen(m->metric_name),
327                     m, NULL, __free_metric);
328 }
329
330 void
331 noit_stats_set_metric_int(stats_t *newstate, char *name, int *value) {
332   metric_t *m = calloc(1, sizeof(*m));
333   m->metric_name = strdup(name);
334   m->metric_type = METRIC_INT;
335   if(value) {
336     m->metric_value.i = malloc(sizeof(*value));
337     *(m->metric_value.i) = *value;
338   }
339   __stats_add_metric(newstate, m);
340 }
341
342 void
343 noit_stats_set_metric_float(stats_t *newstate, char *name, float *value) {
344   metric_t *m = calloc(1, sizeof(*m));
345   m->metric_name = strdup(name);
346   m->metric_type = METRIC_FLOAT;
347   if(value) {
348     m->metric_value.f = malloc(sizeof(*value));
349     *(m->metric_value.f) = *value;
350   }
351   __stats_add_metric(newstate, m);
352 }
353
354 void
355 noit_stats_set_metric_string(stats_t *newstate, char *name, char *value) {
356   metric_t *m = calloc(1, sizeof(*m));
357   m->metric_name = strdup(name);
358   m->metric_type = METRIC_STRING;
359   m->metric_value.s = value ? strdup(value) : NULL;
360   __stats_add_metric(newstate, m);
361 }
362
363 void
364 noit_check_set_stats(struct _noit_module *module,
365                      noit_check_t *check, stats_t *newstate) {
366   int report_change = 0;
367   dep_list_t *dep;
368   if(check->stats.previous.status)
369     free(check->stats.previous.status);
370   noit_hash_destroy(&check->stats.previous.metrics, NULL, __free_metric);
371   memcpy(&check->stats.previous, &check->stats.current, sizeof(stats_t));
372   memcpy(&check->stats.current, newstate, sizeof(stats_t));
373   if(check->stats.current.status)
374     check->stats.current.status = strdup(check->stats.current.status);
375
376   /* check for state changes */
377   if(check->stats.current.available != 0 &&
378      check->stats.previous.available != 0 &&
379      check->stats.current.available != check->stats.previous.available)
380     report_change = 1;
381   if(check->stats.current.state != 0 &&
382      check->stats.previous.state != 0 &&
383      check->stats.current.state != check->stats.previous.state)
384     report_change = 1;
385
386   noitL(noit_error, "%s/%s <- [%s]\n", check->target, check->module,
387         check->stats.current.status);
388   if(report_change) {
389     noitL(noit_error, "%s/%s -> [%s/%s]\n",
390           check->target, check->module,
391           __noit_check_available_string(check->stats.current.available),
392           __noit_check_state_string(check->stats.current.state));
393   }
394   for(dep = check->causal_checks; dep; dep = dep->next) {
395     noit_module_t *mod;
396     mod = noit_module_lookup(dep->check->module);
397     assert(mod);
398     noitL(noit_debug, "Firing %s/%s in response to %s/%s\n",
399           dep->check->target, dep->check->name,
400           check->target, check->name);
401     mod->initiate_check(mod, dep->check, 1, check);
402   }
403 }
Note: See TracBrowser for help on using the browser.