root/src/modules/lua.c

Revision 9349d12fbdff88611b594e12e5a3025bf1e651de, 16.5 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 10 years ago)

forgot this file, refs #28

  • 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 "noit_conf.h"
9 #include "noit_module.h"
10 #include "noit_check.h"
11 #include "noit_check_tools.h"
12 #include "utils/noit_log.h"
13 #include "lua_noit.h"
14
15 #include <assert.h>
16
17 static noit_log_stream_t nlerr = NULL;
18 static noit_log_stream_t nldeb = NULL;
19
20 noit_lua_check_info_t *
21 get_ci(lua_State *L) {
22   noit_lua_check_info_t *v = NULL;
23   lua_getglobal(L, "noit_coros");
24   lua_pushthread(L);
25   lua_gettable(L, -2);
26   if(lua_isuserdata(L, -1)) v = lua_touserdata(L, -1);
27   lua_pop(L, 1);
28   return v;
29 }
30
31 static void
32 noit_event_dispose(void *ev) {
33   int mask;
34   eventer_t *value = ev;
35   eventer_t e = *value;
36   if(e->fd >= 0) e->opset->close(e->fd, &mask, e);
37   if(eventer_remove(e)) {
38     eventer_free(e);
39   }
40   free(ev);
41 }
42 void
43 noit_lua_check_register_event(noit_lua_check_info_t *ci, eventer_t e) {
44   eventer_t *eptr;
45   eptr = calloc(1, sizeof(*eptr));
46   memcpy(eptr, &e, sizeof(*eptr));
47   if(!ci->events) ci->events = calloc(1, sizeof(*ci->events));
48   noit_hash_store(ci->events, (const char *)eptr, sizeof(*eptr), eptr);
49 }
50 void
51 noit_lua_check_deregister_event(noit_lua_check_info_t *ci, eventer_t e) {
52   if(ci->events)
53     noit_hash_delete(ci->events, (const char *)&e, sizeof(*e),
54                      NULL, noit_event_dispose);
55 }
56 void
57 noit_lua_check_clean_events(noit_lua_check_info_t *ci) {
58   noit_hash_destroy(ci->events, NULL, noit_event_dispose);
59   free(ci->events);
60   ci->events = NULL;
61 }
62
63 static void
64 noit_lua_hash_to_table(lua_State *L,
65                        noit_hash_table *t) {
66   noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
67   const char *key, *value;
68   int klen;
69   lua_createtable(L, 0, t ? t->size : 0);
70   if(t) {
71     while(noit_hash_next(t, &iter, &key, &klen, (void **)&value)) {
72       lua_pushlstring(L, value, strlen(value));
73       lua_setfield(L, -2, key);
74     }
75   }
76   return;
77 }
78 static int
79 noit_module_index_func(lua_State *L) {
80   int n;
81   n = lua_gettop(L);    /* number of arguments */
82   assert(n == 2);
83   if(!luaL_checkudata(L, 1, "noit_module_t")) {
84     luaL_error(L, "metatable error, arg1 not a noit_module_t!");
85   }
86   return 0;
87 }
88 static int
89 noit_lua_set_available(lua_State *L) {
90   noit_check_t *check;
91   noit_lua_check_info_t *ci;
92   if(lua_gettop(L)) luaL_error(L, "wrong number of arguments");
93   check = lua_touserdata(L, lua_upvalueindex(1));
94   ci = check->closure;
95   ci->current.available = lua_tointeger(L, lua_upvalueindex(2));
96   return 0;
97 }
98 static int
99 noit_lua_set_state(lua_State *L) {
100   noit_check_t *check;
101   noit_lua_check_info_t *ci;
102   if(lua_gettop(L)) luaL_error(L, "wrong number of arguments");
103   check = lua_touserdata(L, lua_upvalueindex(1));
104   ci = check->closure;
105   ci->current.state = lua_tointeger(L, lua_upvalueindex(2));
106   return 0;
107 }
108 static int
109 noit_lua_set_status(lua_State *L) {
110   noit_check_t *check;
111   noit_lua_check_info_t *ci;
112   if(lua_gettop(L) != 1) luaL_error(L, "wrong number of arguments");
113   check = lua_touserdata(L, lua_upvalueindex(1));
114   ci = check->closure;
115   ci->current.status = strdup(lua_tostring(L, 1));
116   return 0;
117 }
118 static int
119 noit_lua_set_metric(lua_State *L) {
120   noit_check_t *check;
121   noit_lua_check_info_t *ci;
122   const char *metric_name;
123   metric_type_t metric_type;
124
125   double __n;
126   int32_t __i;
127   u_int32_t __I;
128   int64_t __l;
129   u_int64_t __L;
130
131   if(lua_gettop(L) != 2) luaL_error(L, "wrong number of arguments");
132   check = lua_touserdata(L, lua_upvalueindex(1));
133   ci = check->closure;
134   if(!lua_isstring(L, 1)) luaL_error(L, "argument #1 must be a string");
135   metric_name = lua_tostring(L, 1);
136   metric_type = lua_tointeger(L, lua_upvalueindex(2));
137   if(lua_isnil(L, 2)) {
138     noit_stats_set_metric(&ci->current, metric_name, metric_type, NULL);
139     return 0;
140   }
141   switch(metric_type) {
142     case METRIC_GUESS:
143     case METRIC_STRING:
144       noit_stats_set_metric(&ci->current, metric_name, metric_type,
145                             (void *)lua_tostring(L, 2));
146       break;
147     case METRIC_INT32:
148       __i = luaL_optinteger(L, 2, 0);
149       noit_stats_set_metric(&ci->current, metric_name, metric_type, &__i);
150       break;
151     case METRIC_UINT32:
152       __I = luaL_optinteger(L, 2, 0);
153       noit_stats_set_metric(&ci->current, metric_name, metric_type, &__I);
154       break;
155     case METRIC_INT64:
156       __l = luaL_optinteger(L, 2, 0);
157       noit_stats_set_metric(&ci->current, metric_name, metric_type, &__l);
158       break;
159     case METRIC_UINT64:
160       __L = luaL_optinteger(L, 2, 0);
161       noit_stats_set_metric(&ci->current, metric_name, metric_type, &__L);
162       break;
163     case METRIC_DOUBLE:
164       __n = luaL_optnumber(L, 2, 0);
165       noit_stats_set_metric(&ci->current, metric_name, metric_type, &__n);
166       break;
167   }
168   return 0;
169 }
170 static int
171 noit_check_index_func(lua_State *L) {
172   int n;
173   const char *k;
174   noit_check_t **udata, *check;
175   n = lua_gettop(L);    /* number of arguments */
176   assert(n == 2);
177   if(!luaL_checkudata(L, 1, "noit_check_t")) {
178     luaL_error(L, "metatable error, arg1 not a noit_check_t!");
179   }
180   udata = lua_touserdata(L, 1);
181   check = *udata;
182   if(!lua_isstring(L, 2)) {
183     luaL_error(L, "metatable error, arg2 not a string!");
184   }
185   k = lua_tostring(L, 2);
186   switch(*k) {
187     case 'a':
188       if(!strcmp(k, "available")) {
189         lua_pushlightuserdata(L, check);
190         lua_pushinteger(L, NP_AVAILABLE);
191         lua_pushcclosure(L, noit_lua_set_available, 2);
192       }
193       else break;
194       return 1;
195     case 'b':
196       if(!strcmp(k, "bad")) {
197         lua_pushlightuserdata(L, check);
198         lua_pushinteger(L, NP_BAD);
199         lua_pushcclosure(L, noit_lua_set_state, 2);
200       }
201       else break;
202       return 1;
203     case 'c':
204       if(!strcmp(k, "config")) noit_lua_hash_to_table(L, check->config);
205       else break;
206       return 1;
207     case 'g':
208       if(!strcmp(k, "good")) {
209         lua_pushlightuserdata(L, check);
210         lua_pushinteger(L, NP_GOOD);
211         lua_pushcclosure(L, noit_lua_set_state, 2);
212       }
213       else break;
214       return 1;
215     case 'm':
216       if(!strcmp(k, "module")) lua_pushstring(L, check->module);
217
218 #define IF_METRIC_BLOCK(name,type) \
219       if(!strcmp(k, name)) { \
220         lua_pushlightuserdata(L, check); \
221         lua_pushinteger(L, type); \
222         lua_pushcclosure(L, noit_lua_set_metric, 2); \
223       }
224
225       else IF_METRIC_BLOCK("metric", METRIC_GUESS)
226       else IF_METRIC_BLOCK("metric_string", METRIC_STRING)
227       else IF_METRIC_BLOCK("metric_int32", METRIC_INT32)
228       else IF_METRIC_BLOCK("metric_uint32", METRIC_UINT32)
229       else IF_METRIC_BLOCK("metric_int64", METRIC_INT64)
230       else IF_METRIC_BLOCK("metric_uint64", METRIC_UINT64)
231       else IF_METRIC_BLOCK("metric_double", METRIC_DOUBLE)
232       else break;
233       return 1;
234     case 'n':
235       if(!strcmp(k, "name")) lua_pushstring(L, check->name);
236       else break;
237       return 1;
238     case 'p':
239       if(!strcmp(k, "period")) lua_pushinteger(L, check->period);
240       else break;
241       return 1;
242     case 's':
243       if(!strcmp(k, "status")) {
244         lua_pushlightuserdata(L, check);
245         lua_pushcclosure(L, noit_lua_set_status, 1);
246       }
247       else break;
248       return 1;
249     case 't':
250       if(!strcmp(k, "target")) lua_pushstring(L, check->target);
251       else if(!strcmp(k, "timeout")) lua_pushinteger(L, check->timeout);
252       else break;
253       return 1;
254     case 'u':
255       if(!strcmp(k, "unavailable")) {
256         lua_pushlightuserdata(L, check);
257         lua_pushinteger(L, NP_UNAVAILABLE);
258         lua_pushcclosure(L, noit_lua_set_available, 2);
259       }
260       else break;
261       return 1;
262     default:
263       break;
264   }
265   luaL_error(L, "noit_check_t no such element: %s", k);
266   return 0;
267 }
268 static void
269 noit_lua_setup_module(lua_State *L,
270                       noit_module_t *mod) {
271   noit_module_t **addr;
272   addr = (noit_module_t **)lua_newuserdata(L, sizeof(mod));
273   *addr = mod;
274   if(luaL_newmetatable(L, "noit_module_t") == 1) {
275     lua_pushcclosure(L, noit_module_index_func, 0);
276     lua_setfield(L, -2, "__index");
277   }
278   lua_setmetatable(L, -2);
279 }
280 static void
281 noit_lua_setup_check(lua_State *L,
282                      noit_check_t *check) {
283   noit_check_t **addr;
284   addr = (noit_check_t **)lua_newuserdata(L, sizeof(check));
285   *addr = check;
286   if(luaL_newmetatable(L, "noit_check_t") == 1) {
287     lua_pushcclosure(L, noit_check_index_func, 0);
288     lua_setfield(L, -2, "__index");
289   }
290   lua_setmetatable(L, -2);
291 }
292 static int
293 noit_lua_module_onload(noit_image_t *i) {
294   lua_State *L;
295   lua_module_closure_t *lmc;
296   lmc = noit_image_get_userdata(i);
297   L = lmc->lua_state;
298   if(luaL_dofile(L, lmc->script)) {
299     int i;
300     noitL(nlerr, "lua: %s.onload failed\n", lmc->object);
301     i = lua_gettop(L);
302     if(i>0) {
303       if(lua_isstring(L, i)) {
304         const char *err;
305         size_t len;
306         err = lua_tolstring(L, i, &len);
307         noitL(nlerr, "lua: %s\n", err);
308       }
309     }
310     return -1;
311   }
312
313   lua_getfield(L, LUA_GLOBALSINDEX, lmc->object);
314   if(lua_isnil(L, -1)) {
315     lua_pop(L, 1);
316     noitL(nlerr, "lua: no such object %s\n", lmc->object);
317     return -1;
318   }
319   lua_getfield(L, -1, "onload");
320   lua_remove(L, -2);
321   if(!lua_isfunction(L, -1)) {
322     lua_pop(L, 1);
323     /* No onload */
324     return 0;
325   }
326   noit_lua_setup_module(L, (noit_module_t *)i);
327   lua_pcall(L, 1, 1, 0);
328   if(lua_isnumber(L, -1)) {
329     int rv;
330     rv = lua_tointeger(L, -1);
331     lua_pop(L, 1);
332     return rv;
333   } else {
334     lua_pop(L,1);
335     noitL(nlerr, "%s.onload must return a integer\n", lmc->object);
336     return -1;
337   }
338   return 0;
339 }
340 #define LMC_DECL(L, mod) \
341   lua_State *L; \
342   lua_module_closure_t *lmc; \
343   lmc = noit_module_get_userdata(mod); \
344   L = lmc->lua_state
345 #define SETUP_CALL(L, func, failure) do { \
346   lua_getfield(L, LUA_GLOBALSINDEX, lmc->object); \
347   lua_getfield(L, -1, func); \
348   lua_remove(L, -2); \
349   if(!lua_isfunction(L, -1)) { \
350     lua_pop(L, 1); \
351     failure; \
352   } \
353 } while(0)
354 #define RETURN_INT(L, func) do { \
355   if(lua_isnumber(L, -1)) { \
356     int rv; \
357     rv = lua_tointeger(L, -1); \
358     lua_pop(L, 1); \
359     return rv; \
360   } \
361   lua_pop(L,1); \
362   noitL(nlerr, "%s.%s must return a integer\n", lmc->object, func); \
363 } while(0)
364
365 static int
366 noit_lua_module_config(noit_module_t *mod,
367                        noit_hash_table *options) {
368   LMC_DECL(L, mod);
369   SETUP_CALL(L, "config", return 0);
370
371   noit_lua_setup_module(L, mod);
372   noit_lua_hash_to_table(L, options);
373   lua_pcall(L, 2, 1, 0);
374
375   RETURN_INT(L, "config");
376   return -1;
377 }
378 static int
379 noit_lua_module_init(noit_module_t *mod) {
380   LMC_DECL(L, mod);
381   SETUP_CALL(L, "init", return 0);
382
383   noit_lua_setup_module(L, mod);
384   lua_pcall(L, 1, 1, 0);
385
386   RETURN_INT(L, "init");
387   return -1;
388 }
389 static void
390 noit_lua_module_cleanup(noit_module_t *mod, noit_check_t *check) {
391   noit_lua_check_info_t *ci = check->closure;
392   LMC_DECL(L, mod);
393   SETUP_CALL(L, "cleanup", goto clean);
394
395   noit_lua_setup_module(L, mod);
396   noit_lua_setup_check(L, check);
397   lua_pcall(L, 2, 0, 0);
398
399  clean:
400   if(ci) {
401     noit_lua_check_clean_events(ci);
402     free(ci);
403     check->closure = NULL;
404   }
405 }
406
407 /* Here is where the magic starts */
408 static void
409 noit_lua_log_results(noit_module_t *self, noit_check_t *check) {
410   noit_lua_check_info_t *ci = check->closure;
411   struct timeval duration;
412   u_int32_t duration_ms;
413
414   gettimeofday(&ci->finish_time, NULL);
415   sub_timeval(ci->finish_time, check->last_fire_time, &duration);
416
417   memcpy(&ci->current.whence, &ci->finish_time, sizeof(ci->current.whence));
418   ci->current.duration = duration.tv_sec * 1000 + duration.tv_usec / 1000;
419   duration_ms = ci->current.duration;
420
421   noit_check_set_stats(self, check, &ci->current);
422 }
423 int
424 noit_lua_resume(noit_lua_check_info_t *ci, int nargs) {
425   int result, base;
426   noit_check_t *check;
427   check = ci->check;
428
429   result = lua_resume(ci->coro_state, nargs);
430   switch(result) {
431     case 0: /* success */
432       break;
433     case LUA_YIELD: /* The complicated case */
434       /* The person yielding had better setup an event
435        * to wake up the coro...
436        */
437       return 0;
438     default: /* Errors */
439       ci->current.status = "unknown error";
440       ci->current.available = NP_UNAVAILABLE;
441       ci->current.state = NP_BAD;
442       base = lua_gettop(ci->coro_state);
443       if(base>0) {
444         if(lua_isstring(ci->coro_state, base)) {
445           const char *err;
446           err = lua_tostring(ci->coro_state, base);
447           if(err) ci->current.status = (char *)err;
448         }
449       }
450       break;
451   }
452   noit_lua_log_results(ci->self, ci->check);
453   noit_lua_module_cleanup(ci->self, ci->check);
454   check->flags &= ~NP_RUNNING;
455   return 0;
456 }
457 static int
458 noit_lua_check_timeout(eventer_t e, int mask, void *closure,
459                        struct timeval *now) {
460   noit_check_t *check;
461   noit_lua_check_info_t *ci = closure;
462   check = ci->check;
463   noitL(nldeb, "lua: %p ->check_timeout\n", ci->coro_state);
464   ci->timed_out = 1;
465   noit_lua_check_deregister_event(ci, e);
466   if(ci->coro_state) {
467     lua_pushnil(ci->coro_state);
468     noit_lua_resume(ci, 1);
469   } else {
470     noit_lua_log_results(ci->self, ci->check);
471     noit_lua_module_cleanup(ci->self, ci->check);
472     check->flags &= ~NP_RUNNING;
473   }
474   return 0;
475 }
476 static int
477 noit_lua_initiate(noit_module_t *self, noit_check_t *check) {
478   LMC_DECL(L, self);
479   noit_lua_check_info_t *ci;
480   struct timeval p_int, __now;
481   eventer_t e;
482
483   if(!check->closure) check->closure = calloc(1, sizeof(noit_lua_check_info_t));
484   ci = check->closure;
485
486   /* We cannot be running */
487   assert(!(check->flags & NP_RUNNING));
488   check->flags |= NP_RUNNING;
489
490   ci->self = self;
491   ci->check = check;
492   noit_check_stats_clear(&ci->current);
493
494   gettimeofday(&__now, NULL);
495   memcpy(&check->last_fire_time, &__now, sizeof(__now));
496
497   e = eventer_alloc();
498   e->mask = EVENTER_TIMER;
499   e->callback = noit_lua_check_timeout;
500   e->closure = ci;
501   memcpy(&e->whence, &__now, sizeof(__now));
502   p_int.tv_sec = check->timeout / 1000;
503   p_int.tv_usec = (check->timeout % 1000) * 1000;
504   add_timeval(e->whence, p_int, &e->whence);
505   noit_lua_check_register_event(ci, e);
506   eventer_add(e);
507
508   lua_getglobal(L, "noit_coros");
509   ci->coro_state = lua_newthread(L);
510   lua_pushlightuserdata(L, ci);
511   lua_settable(L, -3);
512   lua_pop(L, 1);
513
514   SETUP_CALL(ci->coro_state, "initiate", goto fail);
515   noit_lua_setup_module(ci->coro_state, ci->self);
516   noit_lua_setup_check(ci->coro_state, ci->check);
517   noit_lua_resume(ci, 2);
518
519   return 0;
520
521  fail:
522   noit_lua_log_results(ci->self, ci->check);
523   noit_lua_module_cleanup(ci->self, ci->check);
524   check->flags &= ~NP_RUNNING;
525   return -1;
526 }
527 /* This is the standard wrapper */
528 static int
529 noit_lua_module_initiate_check(noit_module_t *self, noit_check_t *check,
530                                int once, noit_check_t *cause) {
531   if(!check->closure) check->closure = calloc(1, sizeof(noit_lua_check_info_t));
532   INITIATE_CHECK(noit_lua_initiate, self, check);
533   return 0;
534 }
535 static noit_module_t *
536 noit_lua_load(noit_module_loader_t *loader,
537               char *module_name,
538               noit_conf_section_t section) {
539   noit_module_t *m;
540   lua_State *L;
541   lua_module_closure_t *lmc;
542   char *script;
543   char *object;
544  
545   noitL(nldeb, "Loading lua module: %s\n", module_name);
546   if(noit_conf_get_string(section, "@object", &object) == 0) {
547     noitL(nlerr, "Lua module %s require object attribute.\n", module_name);
548     return NULL;
549   }
550   if(noit_conf_get_string(section, "@script", &script) == 0) {
551     noitL(nlerr, "Lua module %s require script attribute.\n", module_name);
552     free(object);
553     return NULL;
554   }
555
556   m = noit_blank_module();
557   m->hdr.magic = NOIT_MODULE_MAGIC;
558   m->hdr.version = NOIT_MODULE_ABI_VERSION;
559   m->hdr.name = strdup(module_name);
560   m->hdr.description = strdup("Lua module");
561   m->hdr.onload = noit_lua_module_onload;
562   lmc = calloc(1, sizeof(*lmc));
563   lmc->object = object;
564   lmc->script = script;
565
566   L = lmc->lua_state = lua_open();
567   lua_gc(L, LUA_GCSTOP, 0);  /* stop collector during initialization */
568   luaL_openlibs(L);  /* open libraries */
569   luaopen_noit(L);
570   lua_newtable(L);
571   lua_setglobal(L, "noit_coros");
572   lua_gc(L, LUA_GCRESTART, 0);
573
574   noit_image_set_userdata(&m->hdr, lmc);
575   if(m->hdr.onload(&m->hdr) == -1) {
576     free(m->hdr.name);
577     free(m->hdr.description);
578     free(lmc->object);
579     free(lmc->script);
580     free(lmc);
581     /* FIXME: We leak the opaque_handler in the module here... */
582     free(m);
583     return NULL;
584   }
585
586   m->config = noit_lua_module_config;
587   m->init = noit_lua_module_init;
588   m->initiate_check = noit_lua_module_initiate_check;
589   m->cleanup = noit_lua_module_cleanup;
590
591   noit_register_module(m);
592   return m;
593 }
594
595 static int
596 noit_lua_loader_onload(noit_image_t *self) {
597   nlerr = noit_log_stream_find("error/serf");
598   nldeb = noit_log_stream_find("debug/serf");
599   if(!nlerr) nlerr = noit_stderr;
600   if(!nldeb) nldeb = noit_debug;
601   return 0;
602 }
603
604 noit_module_loader_t lua = {
605   {
606     NOIT_LOADER_MAGIC,
607     NOIT_LOADER_ABI_VERSION,
608     "lua",
609     "Lua check loader",
610     noit_lua_loader_onload,
611   },
612   noit_lua_load
613 };
Note: See TracBrowser for help on using the browser.