source: nscp/modules/PythonScript/PythonScript.cpp @ 98113da

0.4.00.4.10.4.2
Last change on this file since 98113da was 98113da, checked in by Michael Medin <michael@…>, 20 months ago
  • Real-time CheckEventLog working (still only for one, and I think application log)
  • Added python tests to validfate that Real-time eventlog is working.
  • Fixed som defects here and there (now builds on Linux again)
  • Fixed so it builds in "debug mode"
  • Fixed issue in grammar which caused infiniate loop in som cases
  • Fixed so error rendering in eventlog works with "infininate number of argumnets"
  • Added support for targeting execs (in API)
  • Fixed some invalid return messages
  • Streamlined submissions wrappers to be more inline with "other wrappers"
  • Fixed a myrriad of minor python script bugs
  • Added sleep command (which sometimes causes issues so use with care)
  • Property mode set to 100644
File size: 15.2 KB
RevLine 
[b8c44b4]1/**************************************************************************
2*   Copyright (C) 2004-2007 by Michael Medin <michael@medin.name>         *
3*                                                                         *
4*   This code is part of NSClient++ - http://trac.nakednuns.org/nscp      *
5*                                                                         *
6*   This program is free software; you can redistribute it and/or modify  *
7*   it under the terms of the GNU General Public License as published by  *
8*   the Free Software Foundation; either version 2 of the License, or     *
9*   (at your option) any later version.                                   *
10*                                                                         *
11*   This program is distributed in the hope that it will be useful,       *
12*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14*   GNU General Public License for more details.                          *
15*                                                                         *
16*   You should have received a copy of the GNU General Public License     *
17*   along with this program; if not, write to the                         *
18*   Free Software Foundation, Inc.,                                       *
19*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
20***************************************************************************/
21#include "stdafx.h"
22#include "PythonScript.h"
23#include <time.h>
24#include <error.hpp>
25
26#include <boost/python.hpp>
[fb7e36a]27#include <boost/program_options.hpp>
[b8c44b4]28
[fb7e36a]29#include <strEx.h>
30#include <file_helpers.hpp>
[b8c44b4]31#include <settings/client/settings_client.hpp>
32#include <nscapi/functions.hpp>
33
34#include "script_wrapper.hpp"
35
36PythonScript::PythonScript() {
37}
38PythonScript::~PythonScript() {
39}
40
41namespace sh = nscapi::settings_helper;
[fb7e36a]42namespace po = boost::program_options;
[b8c44b4]43
44bool PythonScript::loadModule() {
45        return false;
46}
47using namespace boost::python;
48
49BOOST_PYTHON_MODULE(NSCP)
50{
[9b9be81]51        PyEval_InitThreads();
[b8c44b4]52        class_<script_wrapper::settings_wrapper, boost::shared_ptr<script_wrapper::settings_wrapper> >("Settings", no_init)
53                .def("get",&script_wrapper::settings_wrapper::create)
54                .staticmethod("get")
55                .def("create",&script_wrapper::settings_wrapper::create)
56                .staticmethod("create")
57                .def("get_section", &script_wrapper::settings_wrapper::get_section)
58                .def("get_string", &script_wrapper::settings_wrapper::get_string)
59                .def("set_string", &script_wrapper::settings_wrapper::set_string)
60                .def("get_bool", &script_wrapper::settings_wrapper::get_bool)
61                .def("set_bool", &script_wrapper::settings_wrapper::set_bool)
62                .def("get_int", &script_wrapper::settings_wrapper::get_int)
63                .def("set_int", &script_wrapper::settings_wrapper::set_int)
64                .def("save", &script_wrapper::settings_wrapper::save)
65                .def("register_path", &script_wrapper::settings_wrapper::settings_register_path)
66                .def("register_key", &script_wrapper::settings_wrapper::settings_register_key)
67                ;
[2c95d22]68        class_<script_wrapper::function_wrapper, boost::shared_ptr<script_wrapper::function_wrapper> >("Registry", no_init)
[b8c44b4]69                .def("get",&script_wrapper::function_wrapper::create)
70                .staticmethod("get")
71                .def("create",&script_wrapper::function_wrapper::create)
72                .staticmethod("create")
[2c95d22]73                .def("function", &script_wrapper::function_wrapper::register_function)
74                .def("simple_function", &script_wrapper::function_wrapper::register_simple_function)
[39c73cd]75                .def("cmdline", &script_wrapper::function_wrapper::register_cmdline)
76                .def("simple_cmdline", &script_wrapper::function_wrapper::register_simple_cmdline)
[2c95d22]77                .def("subscription", &script_wrapper::function_wrapper::subscribe_function)
78                .def("simple_subscription", &script_wrapper::function_wrapper::subscribe_simple_function)
[b8c44b4]79                ;
[a14aa07]80        class_<script_wrapper::command_wrapper, boost::shared_ptr<script_wrapper::command_wrapper> >("Core", init<>())
[b8c44b4]81                .def("get",&script_wrapper::command_wrapper::create)
82                .staticmethod("get")
83                .def("create",&script_wrapper::command_wrapper::create)
84                .staticmethod("create")
85                .def("simple_query", &script_wrapper::command_wrapper::simple_query)
86                .def("query", &script_wrapper::command_wrapper::query)
87                .def("simple_exec", &script_wrapper::command_wrapper::simple_exec)
88                .def("exec", &script_wrapper::command_wrapper::exec)
89                .def("simple_submit", &script_wrapper::command_wrapper::simple_submit)
90                .def("submit", &script_wrapper::command_wrapper::submit)
[9b9be81]91                .def("reload", &script_wrapper::command_wrapper::reload)
[b8c44b4]92                ;
93
94        enum_<script_wrapper::status>("status")
95                .value("CRITICAL", script_wrapper::CRIT)
96                .value("WARNING", script_wrapper::WARN)
97                .value("UNKNOWN", script_wrapper::UNKNOWN)
98                .value("OK", script_wrapper::OK)
99                ;
100        def("log", script_wrapper::log_msg);
[9b9be81]101        def("log_err", script_wrapper::log_error);
102        def("log_deb", script_wrapper::log_debug);
103        def("log_error", script_wrapper::log_error);
104        def("log_debug", script_wrapper::log_debug);
[98113da]105        def("sleep", script_wrapper::sleep);
[81e420c]106//      def("get_module_alias", script_wrapper::get_module_alias);
107//      def("get_script_alias", script_wrapper::get_script_alias);
[b8c44b4]108}
109
[a44cb15]110python_script::python_script(unsigned int plugin_id, const std::string alias, const script_container& script) : alias(alias), plugin_id(plugin_id) {
[fb7e36a]111        NSC_DEBUG_MSG_STD(_T("Loading python script: ") + script.script.string());
112        std::wcout << script.script.string() << std::endl;;
[b8c44b4]113        _exec(utf8::cvt<std::string>(script.script.string()));
[a44cb15]114        callFunction("init", plugin_id, alias, utf8::cvt<std::string>(script.alias));
[b8c44b4]115}
116python_script::~python_script(){
117        callFunction("shutdown");
118}
119void python_script::callFunction(const std::string& functionName) {
120        try     {
121                object scriptFunction = extract<object>(localDict[functionName]);
122                if( scriptFunction )
123                        scriptFunction();
124        } catch( error_already_set e) {
125                script_wrapper::log_exception();
126        }
127}
[a44cb15]128void python_script::callFunction(const std::string& functionName, unsigned int i1, const std::string &s1, const std::string &s2){
[b8c44b4]129        try     {
130                object scriptFunction = extract<object>(localDict[functionName]);
131                if(scriptFunction)
[a44cb15]132                        scriptFunction(i1, s1, s2);
[b8c44b4]133        } catch(error_already_set e) {
134                script_wrapper::log_exception();
135        }
136}
137void python_script::_exec(const std::string &scriptfile){
138        try     {
139                object main_module = import("__main__");
140                dict globalDict = extract<dict>(main_module.attr("__dict__"));
141                localDict = globalDict.copy();
[a44cb15]142                //localDict.attr("plugin_id") = plugin_id;
143                //localDict.attr("plugin_alias") = alias;
[39c73cd]144
145                PyRun_SimpleString("import cStringIO");
146                PyRun_SimpleString("import sys");
147                PyRun_SimpleString("sys.stderr = cStringIO.StringIO()");
[4b1e6fe]148                boost::filesystem::wpath path = GET_CORE()->getBasePath();
149                path /= _T("scripts");
150                path /= _T("python");
151                path /= _T("lib");
152                PyRun_SimpleString(("sys.path.append('" + utf8::cvt<std::string>(path.string()) + "')").c_str());
[b8c44b4]153                object ignored = exec_file(scriptfile.c_str(), localDict, localDict);   
154        } catch( error_already_set e) {
155                script_wrapper::log_exception();
156        }
157}
[a14aa07]158static bool has_init = false;
[b8c44b4]159bool PythonScript::loadModuleEx(std::wstring alias, NSCAPI::moduleLoadMode mode) {
[2c95d22]160        alias_ = alias;
[39c73cd]161        NSC_DEBUG_MSG_STD(_T("LoadEx in PythonScript as ") + alias);
[b8c44b4]162        try {
163                root_ = get_core()->getBasePath();
164
165                sh::settings_registry settings(get_settings_proxy());
166                settings.set_alias(alias, _T("python"));
167
168                settings.alias().add_path_to_settings()
169                        (_T("LUA SCRIPT SECTION"), _T("Section for the PythonScripts module."))
170
171                        (_T("scripts"), sh::fun_values_path(boost::bind(&PythonScript::loadScript, this, _1, _2)),
172                        _T("LUA SCRIPTS SECTION"), _T("A list of scripts available to run from the PythonScript module."))
173                        ;
174
175                settings.register_all();
176                settings.notify();
177
[a14aa07]178                bool do_init = false;
179                if (!has_init) {
180                        has_init = true;
181                        Py_Initialize();
182                        do_init = true;
183                }
184
[b8c44b4]185                try {
186
187                        PyRun_SimpleString("import cStringIO");
188                        PyRun_SimpleString("import sys");
189                        PyRun_SimpleString("sys.stderr = cStringIO.StringIO()");
190
[a14aa07]191                        if (do_init)
192                                initNSCP();
[b8c44b4]193
194                        BOOST_FOREACH(script_container &script, scripts_) {
[a44cb15]195                                instances_.push_back(boost::shared_ptr<python_script>(new python_script(get_id(), utf8::cvt<std::string>(alias), script)));
[b8c44b4]196                        }
197
198                } catch( error_already_set e) {
199                        script_wrapper::log_exception();
200                } catch (std::exception &e) {
201                        NSC_LOG_ERROR_STD(_T("Exception: Failed to load python scripts: ") + utf8::cvt<std::wstring>(e.what()));
202                }
203        } catch (...) {
204                NSC_LOG_ERROR_STD(_T("Exception caught: <UNKNOWN EXCEPTION>"));
205                return false;
206        }
207        return true;
208}
209
210boost::optional<boost::filesystem::wpath> PythonScript::find_file(std::wstring file) {
211        std::list<boost::filesystem::wpath> checks;
212        checks.push_back(file);
[9b9be81]213        checks.push_back((file + _T(".py")));
[b8c44b4]214        checks.push_back(root_ / _T("scripts") / _T("python") / file);
[9b9be81]215        checks.push_back(root_ / _T("scripts") / _T("python") / (file + _T(".py")));
[b8c44b4]216        checks.push_back(root_ / _T("scripts") / file);
[9b9be81]217        checks.push_back(root_ / _T("scripts") / (file + _T(".py")));
[b8c44b4]218        checks.push_back(root_ / file);
219        BOOST_FOREACH(boost::filesystem::wpath c, checks) {
220                NSC_DEBUG_MSG_STD(_T("Looking for: ") + c.string());
221                if (boost::filesystem::exists(c))
222                        return boost::optional<boost::filesystem::wpath>(c);
223        }
224        NSC_LOG_ERROR(_T("Script not found: ") + file);
225        return boost::optional<boost::filesystem::wpath>();
226}
227
[fb7e36a]228NSCAPI::nagiosReturn PythonScript::execute_and_load_python(std::list<std::wstring> args) {
229        try {
230                po::options_description desc;
231                boost::program_options::variables_map vm;
232                std::wstring file;
233                desc.add_options()
234                        ("script", po::wvalue<std::wstring>(&file), "The script to run")
235                        ("file", po::wvalue<std::wstring>(&file), "The script to run")
236                        ;
237
238                std::vector<std::wstring> vargs(args.begin(), args.end());
239                po::wparsed_options parsed = po::basic_command_line_parser<wchar_t>(vargs).options(desc).run();
240                po::store(parsed, vm);
241                po::notify(vm);
242
243                boost::optional<boost::filesystem::wpath> ofile = find_file(file);
244                if (!ofile)
245                        return false;
246                script_container sc(*ofile);
247                python_script script(get_id(), "", sc);
248                script.callFunction("__main__");
249        } catch (const std::exception &e) {
250                NSC_LOG_ERROR_STD(_T("Failed to execute script ") + utf8::cvt<std::wstring>(e.what()));
251        } catch (...) {
252                NSC_LOG_ERROR_STD(_T("Failed to execute script..."));
253        }
254}
255
[b8c44b4]256bool PythonScript::loadScript(std::wstring alias, std::wstring file) {
257        try {
258                if (file.empty()) {
259                        file = alias;
260                        alias = _T("");
261                }
262                boost::optional<boost::filesystem::wpath> ofile = find_file(file);
263                if (!ofile)
264                        return false;
265                script_container::push(scripts_, alias, *ofile);
266                NSC_DEBUG_MSG_STD(_T("Adding script: ") + alias + _T(" (") + ofile->string() + _T(")"));
267                return true;
268        } catch (...) {
269                NSC_LOG_ERROR_STD(_T("Could not find script: (Unknown exception) ") + file);
270        }
271        return false;
272}
273
274
275bool PythonScript::unloadModule() {
276        instances_.clear();
[39c73cd]277        //Py_Finalize();
[b8c44b4]278        return true;
279}
280
281bool PythonScript::hasCommandHandler() {
282        return true;
283}
284bool PythonScript::hasMessageHandler() {
[2c95d22]285        return true;
286}
287bool PythonScript::hasNotificationHandler() {
288        return true;
[b8c44b4]289}
290
291bool PythonScript::reload(std::wstring &message) {
292        /*
293        bool error = false;
294        commands_.clear();
295        for (script_list::const_iterator cit = scripts_.begin(); cit != scripts_.end() ; ++cit) {
296                try {
297                        (*cit)->reload(this);
298                } catch (script_wrapper::LUAException e) {
299                        error = true;
300                        message += _T("Exception when reloading script: ") + (*cit)->get_script() + _T(": ") + e.getMessage();
301                        NSC_LOG_ERROR_STD(_T("Exception when reloading script: ") + (*cit)->get_script() + _T(": ") + e.getMessage());
302                } catch (...) {
303                        error = true;
304                        message += _T("Unhandeled Exception when reloading script: ") + (*cit)->get_script();
305                        NSC_LOG_ERROR_STD(_T("Unhandeled Exception when reloading script: ") + (*cit)->get_script());
306                }
307        }
308        if (!error)
309                message = _T("LUA scripts Reloaded...");
310        return !error;
311        */
312        return false;
313}
314
[39c73cd]315NSCAPI::nagiosReturn PythonScript::commandRAWLineExec(const wchar_t* char_command, const std::string &request, std::string &response) {
[fb7e36a]316        std::wstring command = char_command;
[9b9be81]317        if (command == _T("execute-and-load-python") || command == _T("execute-python") || command == _T("run")) {
[fb7e36a]318                nscapi::functions::decoded_simple_command_data data = nscapi::functions::parse_simple_exec_request(char_command, request);
319                return execute_and_load_python(data.args);
320        }
[a44cb15]321        boost::shared_ptr<script_wrapper::function_wrapper> inst = script_wrapper::function_wrapper::create(get_id());
[39c73cd]322        std::string cmd = utf8::cvt<std::string>(char_command);
323        if (inst->has_cmdline(cmd)) {
[2c95d22]324                return inst->handle_exec(cmd, request, response);
[39c73cd]325        }
326        if (inst->has_simple_cmdline(cmd)) {
[2c95d22]327                nscapi::functions::decoded_simple_command_data data = nscapi::functions::parse_simple_exec_request(char_command, request);
[39c73cd]328                std::wstring result;
[2c95d22]329                NSCAPI::nagiosReturn ret = inst->handle_simple_exec(cmd, data.args, result);
[b38e845]330                nscapi::functions::create_simple_exec_response(data.command, ret, result, response);
331                return ret;
[39c73cd]332        }
333        return NSCAPI::returnIgnored;
334}
335
[b8c44b4]336
337NSCAPI::nagiosReturn PythonScript::handleRAWCommand(const wchar_t* command, const std::string &request, std::string &response) {
[a44cb15]338        boost::shared_ptr<script_wrapper::function_wrapper> inst = script_wrapper::function_wrapper::create(get_id());
[b8c44b4]339        std::string cmd = utf8::cvt<std::string>(command);
340        if (inst->has_function(cmd)) {
[a14aa07]341                return inst->handle_query(cmd, request, response);
[b8c44b4]342        }
343        if (inst->has_simple(cmd)) {
[b38e845]344                nscapi::functions::decoded_simple_command_data data = nscapi::functions::parse_simple_query_request(command, request);
[b8c44b4]345                std::wstring msg, perf;
[a14aa07]346                NSCAPI::nagiosReturn ret = inst->handle_simple_query(cmd, data.args, msg, perf);
[d7e265d]347                nscapi::functions::create_simple_query_response(data.command, ret, msg, perf, response);
[b38e845]348                return ret;
[b8c44b4]349        }
350        NSC_LOG_ERROR_STD(_T("Could not find python commands for: ") + command + _T(" (avalible python commands are: ") + inst->get_commands() + _T(")"));
351        /*
352        if (command == _T("luareload")) {
353                return reload(message)?NSCAPI::returnOK:NSCAPI::returnCRIT;
354        }
355        */
356        return NSCAPI::returnIgnored;
357}
358
[2c95d22]359
[a629015]360NSCAPI::nagiosReturn PythonScript::handleRAWNotification(const std::wstring &channel, std::string &request, std::string &response) {
[a44cb15]361        boost::shared_ptr<script_wrapper::function_wrapper> inst = script_wrapper::function_wrapper::create(get_id());
[2c95d22]362        std::string chnl = utf8::cvt<std::string>(channel);
363        if (inst->has_message_handler(chnl)) {
[9b9be81]364                NSCAPI::nagiosReturn ret = inst->handle_message(chnl, request, response);
365                if (ret != NSCAPI::returnIgnored)
366                        return ret;
[2c95d22]367        }
368        if (inst->has_simple_message_handler(chnl)) {
[9b9be81]369                std::wstring src, cmd, msg, perf;
370                int code = nscapi::functions::parse_simple_submit_request(request, src, cmd, msg, perf);
371                int ret = inst->handle_simple_message(chnl, to_string(src), to_string(cmd), code, msg, perf);
372                nscapi::functions::create_simple_submit_response(channel, cmd, ret, _T(""), response);
[a629015]373                return ret;
[2c95d22]374        }
375        return NSCAPI::returnIgnored;
376}
377
[b8c44b4]378NSC_WRAP_DLL();
[81e420c]379NSC_WRAPPERS_MAIN_DEF(PythonScript);
[b8c44b4]380NSC_WRAPPERS_IGNORE_MSG_DEF();
[81e420c]381NSC_WRAPPERS_HANDLE_CMD_DEF();
382NSC_WRAPPERS_CLI_DEF();
383NSC_WRAPPERS_HANDLE_NOTIFICATION_DEF();
Note: See TracBrowser for help on using the repository browser.