source: nscp/modules/LUAScript/script_wrapper.hpp @ 04ef932

0.4.00.4.10.4.2
Last change on this file since 04ef932 was 04ef932, checked in by Michael Medin <michael@…>, 22 months ago

2011-08-10

  • Fixed so it builds and runs on linux (but parser had issues so disabled som grammar rules whichneeds to be enabled again)
  • Added a lot of freatures and cleand up the PythonScript module
  • Started to merge som features from PythonScript back to Lua script


2011-08-07

  • Fixed a lot of issues with PythonScript module adding suport for alias and "raw command processing"
  • Fixed issue with loading plugins and aliases as well as duplicate plugin detection


2011-08-01

  • Property mode set to 100644
File size: 12.0 KB
Line 
1#pragma once
2
3#include <map>
4
5extern "C" {
6#include <lua.h>
7#include "lauxlib.h"
8#include "lualib.h"
9}
10#include "luna.h"
11
12#include <scripts/functions.hpp>
13
14namespace script_wrapper {
15
16        class Lua_State {
17                lua_State *L;
18        public:
19                Lua_State() : L(lua_open()) { }
20
21                ~Lua_State() {
22                        lua_close(L);
23                }
24
25                // implicitly act as a lua_State pointer
26                inline operator lua_State*() {
27                        return L;
28                }
29        };
30
31        class LUAException {
32                std::wstring error_;
33        public:
34                LUAException(std::wstring error) : error_(error) {}
35
36                std::wstring getMessage() const {
37                        return error_;
38                }
39
40        };
41
42        inline std::string w2s(std::wstring s) {
43                return strEx::wstring_to_string(s);
44        }
45        inline std::wstring s2w(std::string s) {
46                return strEx::string_to_wstring(s);
47        }
48        typedef std::pair<std::wstring,int> where_type;
49        where_type where(lua_State *L, int level = 1) {
50                lua_Debug ar;
51                if (lua_getstack(L, level, &ar)) {  /* check function at level */
52                        lua_getinfo(L, "Sl", &ar);  /* get info about it */
53                        if (ar.currentline > 0) {  /* is there info? */
54                                return where_type(s2w(ar.short_src), ar.currentline);
55                        }
56                }
57                return where_type(_T("unknown"),0);
58        }
59        std::wstring extract_string(lua_State *L) {
60                int top = lua_gettop(L);
61                if (lua_isstring(L, top))
62                        return strEx::string_to_wstring(lua_tostring( L, lua_gettop( L ) ));
63                return _T("<NOT_A_STRING>");
64        }
65        std::wstring pop_string(lua_State *L) {
66                std::wstring ret;
67                int top = lua_gettop(L);
68                if (lua_isstring(L, top))
69                        ret = strEx::string_to_wstring(lua_tostring( L, top));
70                else if (lua_isnil(L, top))
71                        ret = _T("<NIL>");
72                else if (lua_istable(L, top))
73                        ret = _T("<TABLE>");
74                else if (lua_isnumber(L, top))
75                        ret = _T("<NUMBER>");
76                else if (lua_iscfunction(L, top))
77                        ret = _T("<C-FUNCTION>");
78                else
79                        ret = _T("<UNKNOWN>");
80                lua_pop(L, 1);
81                return ret;
82        }
83        NSCAPI::nagiosReturn extract_code(lua_State *L) {
84                std::string str;
85                switch (lua_type( L, lua_gettop( L ) )) {
86        case LUA_TNUMBER:
87                return static_cast<int>(lua_tonumber(L, lua_gettop(L)));
88        case LUA_TTABLE:
89                NSC_LOG_ERROR_STD(_T("Incorect return from script: should be error, ok, warning or unknown"));
90                return NSCAPI::returnUNKNOWN;
91        case LUA_TSTRING:
92                str = lua_tostring(L, lua_gettop(L));
93                if ((str == "critical")||(str == "crit")||(str == "error")) {
94                        return NSCAPI::returnCRIT;
95                } else if ((str == "warning")||(str == "warn")) {
96                        return NSCAPI::returnWARN;
97                } else if (str == "ok") {
98                        return NSCAPI::returnOK;
99                } else if (str == "unknown") {
100                        return NSCAPI::returnUNKNOWN;
101                } else {
102                        NSC_LOG_ERROR_STD(_T("Incorect return from script: should be ok, warning, critical or unknown not: ") + strEx::string_to_wstring(str) );
103                        return NSCAPI::returnUNKNOWN;
104                }
105        case LUA_TBOOLEAN:
106                return lua_toboolean( L, lua_gettop( L ) )?NSCAPI::returnOK:NSCAPI::returnCRIT;
107                }
108                NSC_LOG_ERROR_STD(_T("Incorect return from script: should be error, ok, warning or unknown"));
109                return NSCAPI::returnUNKNOWN;
110        }
111        void push_code(lua_State *L, NSCAPI::nagiosReturn  code) {
112                if (code == NSCAPI::returnOK)
113                        lua_pushstring(L, strEx::wstring_to_string(_T("ok")).c_str());
114                else if (code == NSCAPI::returnWARN)
115                        lua_pushstring(L, strEx::wstring_to_string(_T("warning")).c_str());
116                else if (code == NSCAPI::returnCRIT)
117                        lua_pushstring(L, strEx::wstring_to_string(_T("critical")).c_str());
118                else
119                lua_pushstring(L, strEx::wstring_to_string(_T("unknown")).c_str());
120        }
121        void push_string(lua_State *L, std::wstring s) {
122                lua_pushstring(L, strEx::wstring_to_string(s).c_str());
123        }
124        void push_array(lua_State *L, std::list<std::wstring> &arr) {
125                lua_createtable(L, 0, arr.size());
126                int i=0;
127                for (std::list<std::wstring>::const_iterator cit=arr.begin(); cit != arr.end(); ++cit) {
128                        lua_pushnumber(L,i++);
129                        lua_pushstring(L,strEx::wstring_to_string(*cit).c_str());
130                        lua_settable(L,-3);
131                }
132        }
133
134        class lua_script;
135        class lua_handler {
136        public:
137                virtual void register_command(lua_script* script, std::wstring command, std::wstring function) = 0;
138
139        };
140        class lua_manager {
141                typedef std::map<double,lua_handler*> handler_type;
142                typedef std::map<double,lua_script*> script_type;
143                static handler_type handlers;
144                static script_type scripts;
145                static double last_value;
146                static char handler_key[];
147                static char script_key[];
148        public:
149                static lua_handler* get_handler(lua_State *L) {
150                        handler_type::const_iterator cit = handlers.find(get_id(L, handler_key));
151                        if (cit == handlers.end())
152                                throw LUAException(_T("Could not find handler reference"));
153                        return (*cit).second;
154                }
155                static void set_handler(lua_State *L, lua_handler* handler) {
156                        double id = get_id(L, handler_key);
157                        handlers[id] = handler;
158                }
159                static lua_script* get_script(lua_State *L) {
160                        script_type::const_iterator cit = scripts.find(get_id(L, script_key));
161                        if (cit == scripts.end())
162                                throw LUAException(_T("Could not find script reference"));
163                        return (*cit).second;
164                }
165                static void set_script(lua_State *L, lua_script* script) {
166                        double id = get_id(L, script_key);
167                        scripts[id] = script;
168                }
169                static double get_id(lua_State *L, char *key) {
170                        /* retrieve a number */
171                        lua_pushstring(L, key);
172                        //lua_pushlightuserdata(L, (void*)&key);  /* push address */
173                        lua_gettable(L, LUA_REGISTRYINDEX);  /* retrieve value */
174                        double v = 0;
175                        v = lua_tonumber(L, -1);  /* convert to number */
176                        lua_pop(L,1);
177                        if (v <= 0) {
178                                v = ++last_value;
179                                lua_pushstring(L, key);
180                                //lua_pushlightuserdata(L, reinterpret_cast<void*>(&key));  /* push address */
181                                lua_pushnumber(L, v);  /* push value */
182                                /* registry[&Key] = myNumber */
183                                lua_settable(L, LUA_REGISTRYINDEX);
184                        }
185                        return v;
186
187                }
188
189        };
190        class nsclient_wrapper {
191        public:
192
193                static int execute (lua_State *L) {
194                        try {
195                                int nargs = lua_gettop( L );
196                                if (nargs == 0) {
197                                        return luaL_error(L, "nscp.execute requires at least 1 argument!");
198                                }
199                                unsigned int argLen = nargs-1;
200                                std::list<std::wstring> arguments;
201                                for (unsigned int i=argLen;i>0;i--) {
202                                        arguments.push_front(extract_string(L));
203                                        lua_pop(L, 1);
204                                }
205                                std::wstring command = extract_string(L);
206                                lua_pop(L, 1);
207                                std::wstring message;
208                                std::wstring perf;
209                                NSCAPI::nagiosReturn ret = GET_CORE()->InjectSimpleCommand(command, arguments, message, perf);
210                                push_code(L, ret);
211                                lua_pushstring(L, strEx::wstring_to_string(message).c_str());
212                                lua_pushstring(L, strEx::wstring_to_string(perf).c_str());
213                                return 3;
214                        } catch (...) {
215                                return luaL_error(L, "Unknown exception in: nscp.execute");
216                        }
217                }
218
219                static int register_command(lua_State *L) {
220                        try {
221                                lua_handler *handler = lua_manager::get_handler(L);
222                                lua_script *script = lua_manager::get_script(L);
223                                int nargs = lua_gettop( L );
224                                if (nargs != 2)
225                                        return luaL_error(L, "Incorrect syntax: nscp.register(<key>, <function>);");
226                                handler->register_command(script, pop_string(L), pop_string(L));
227                                return 0;
228                        } catch (LUAException e) {
229                                return luaL_error(L, std::string("Error in nscp.register: " + w2s(e.getMessage())).c_str());
230                        } catch (...) {
231                                return luaL_error(L, "Unknown exception in: nscp.register");
232                        }
233                }
234
235                static int getSetting (lua_State *L) {
236                        int nargs = lua_gettop( L );
237                        if (nargs < 2 || nargs > 3)
238                                return luaL_error(L, "Incorrect syntax: nscp.getSetting(<section>, <key>[, <default value>]);");
239                        std::wstring v;
240                        if (nargs > 2)
241                                v = pop_string(L);
242                        std::wstring k = pop_string(L);
243                        std::wstring s = pop_string(L);
244                        push_string(L, GET_CORE()->getSettingsString(s, k, v));
245                        return 1;
246                }
247                static int getSection (lua_State *L) {
248                        int nargs = lua_gettop( L );
249                        if (nargs > 1)
250                                return luaL_error(L, "Incorrect syntax: nscp.getSection([<section>]);");
251                        std::wstring v;
252                        if (nargs > 0)
253                                v = pop_string(L);
254                        try {
255                                std::list<std::wstring> list = GET_CORE()->getSettingsSection(v);
256                                push_array(L, list);
257                        } catch (...) {
258                                return luaL_error(L, "Unknown exception getting section");
259                        }
260                        return 1;
261                }
262                static int info (lua_State *L) {
263                        return log_any(L, NSCAPI::log);
264                }
265                static int error (lua_State *L) {
266                        return log_any(L, NSCAPI::error);
267                }
268                static int log_any(lua_State *L, int mode) {
269                        where_type w = where(L);
270                        int nargs = lua_gettop( L );
271                        std::wstring str;
272                        for (int i=0;i<nargs;i++) {
273                                str += pop_string(L);
274                        }
275                        GET_CORE()->Message(mode, utf8::cvt<std::string>(w.first), w.second, str);
276                        return 0;
277                }
278
279                static const luaL_Reg my_funcs[];
280
281                static int luaopen(lua_State *L) {
282                        luaL_register(L, "nscp", my_funcs);
283                        return 1;
284                }
285
286
287        };
288        const luaL_Reg nsclient_wrapper::my_funcs[] = {
289                {"execute", execute},
290                {"info", info},
291                {"print", info},
292                {"error", error},
293                {"register", register_command},
294                {"getSetting", getSetting},
295                {"getSection", getSection},
296                {NULL, NULL}
297        };
298
299        lua_manager::handler_type lua_manager::handlers;
300        lua_manager::script_type lua_manager::scripts;
301        double lua_manager::last_value = 0;
302        char lua_manager::handler_key[] = "registry.key.handler";
303        char lua_manager::script_key[] = "registry.key.script";
304
305        class lua_script {
306                Lua_State L;
307                std::string script_;
308                std::string alias_;
309        public:
310                lua_script(const script_container &script) : script_(utf8::cvt<std::string>(script.script.string())), alias_(utf8::cvt<std::string>(script.alias)) {
311                        load();
312                }
313                void load() {
314                        luaL_openlibs(L);
315                        nsclient_wrapper::luaopen(L);
316                        if (luaL_loadfile(L, script_.c_str()) != 0) {
317                                throw LUAException(_T("Failed to load script: ") + get_wscript() + _T(": ") + s2w(lua_tostring(L, -1)));
318                        }
319
320                }
321                std::wstring get_wscript() const {
322                        return utf8::cvt<std::wstring>(script_);
323                }
324                std::string get_script() const {
325                        return script_;
326                }
327                void unload() {}
328                void reload(lua_handler *handler) {
329                        unload();
330                        load();
331                        pre_load(handler);
332                }
333                void pre_load(lua_handler *handler) {
334                        lua_manager::set_handler(L, handler);
335                        lua_manager::set_script(L, this);
336                        if (lua_pcall(L, 0, 0, 0) != 0) {
337                                throw LUAException(_T("Failed to parse script: ") + get_wscript() + _T(": ") + s2w(lua_tostring(L, -1)));
338                        }
339                }
340
341
342                NSCAPI::nagiosReturn extract_return(Lua_State &L, int arg_count,  std::wstring &message, std::wstring &perf) {
343                        // code, message, performance data
344                        if (arg_count > 3) {
345                                NSC_LOG_ERROR_STD(_T("Too many arguments return from script (only using last 3)"));
346                                lua_pop(L, arg_count-3);
347                        }
348                        if (arg_count > 2) {
349                                perf = extract_string(L);
350                                lua_pop( L, 1 );
351                        }
352                        if (arg_count > 1) {
353                                message = extract_string(L);
354                                lua_pop( L, 1 );
355                        }
356                        if (arg_count > 0) {
357                                int ret = extract_code(L);
358                                lua_pop( L, 1 );
359                                return ret;
360                        }
361                        NSC_LOG_ERROR_STD(_T("No arguments returned from script."));
362                        return NSCAPI::returnUNKNOWN;
363                }
364
365                NSCAPI::nagiosReturn handleCommand(lua_handler *handler, std::wstring function, std::wstring cmd, std::list<std::wstring> arguments, std::wstring &msg, std::wstring &perf) {
366                        lua_manager::set_handler(L, handler);
367                        lua_manager::set_script(L, this);
368                        int nargs = lua_gettop( L );
369                        lua_getglobal(L, w2s(function).c_str());
370                        if (!lua_isfunction(L, -1)) {
371                                lua_pop(L, 1); // remove function from LUA stack
372                                throw LUAException(_T("Failed to run script: ") + get_wscript() + _T(": Function not found: handle"));
373                        }
374                        lua_pushstring(L, w2s(cmd).c_str());
375
376                        lua_createtable(L, 0, arguments.size());
377                        int i=0;
378                        BOOST_FOREACH(std::wstring arg, arguments) {
379                                lua_pushnumber(L,i++);
380                                lua_pushstring(L,strEx::wstring_to_string(arg).c_str());
381                                lua_settable(L,-3);
382                        }
383
384                        if (lua_pcall(L, 2, LUA_MULTRET, 0) != 0) {
385                                std::wstring err = strEx::string_to_wstring(lua_tostring(L, -1));
386                                NSC_LOG_ERROR_STD(_T("Failed to call main function in script: ") + get_wscript() + _T(": ") + err);
387                                lua_pop(L, 1); // remove error message
388                                return NSCAPI::returnUNKNOWN;
389                        }
390                        return extract_return(L, lua_gettop( L )-nargs, msg, perf);
391                }
392        };
393
394
395
396
397
398}
Note: See TracBrowser for help on using the repository browser.