source: nscp/modules/PythonScript/PythonScript.cpp @ a44cb15

0.4.00.4.10.4.2
Last change on this file since a44cb15 was a44cb15, checked in by Michael Medin <michael@…>, 21 months ago
  • Implemented registration of channels (so no longer faked)
  • Added settings key to change the NSCAAgent channel name
  • Addded proper channel handling to PythonScript module
  • Improved error handling in channels API
  • Rewrote wrapper API to use templates and classes instead of macros (ish)
  • Improved the internal plugin wrapping API to support multiple plugin load
  • Fixed so PythonScript module supports multiple plugin load (with new argument for plugin_id)
  • Added API for registrying routers and handling routing (almost there now)
  • Fixed issue with messages due to new API
  • Property mode set to 100644
File size: 12.9 KB
Line 
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 <strEx.h>
24#include <time.h>
25#include <error.hpp>
26#include <file_helpers.hpp>
27
28#include <boost/python.hpp>
29
30#include <settings/client/settings_client.hpp>
31#include <nscapi/functions.hpp>
32
33#include "script_wrapper.hpp"
34
35PythonScript::PythonScript() {
36}
37PythonScript::~PythonScript() {
38}
39
40namespace sh = nscapi::settings_helper;
41
42bool PythonScript::loadModule() {
43        return false;
44}
45using namespace boost::python;
46
47
48
49BOOST_PYTHON_MODULE(NSCP)
50{
51        class_<script_wrapper::settings_wrapper, boost::shared_ptr<script_wrapper::settings_wrapper> >("Settings", no_init)
52                .def("get",&script_wrapper::settings_wrapper::create)
53                .staticmethod("get")
54                .def("create",&script_wrapper::settings_wrapper::create)
55                .staticmethod("create")
56                .def("get_section", &script_wrapper::settings_wrapper::get_section)
57                .def("get_string", &script_wrapper::settings_wrapper::get_string)
58                .def("set_string", &script_wrapper::settings_wrapper::set_string)
59                .def("get_bool", &script_wrapper::settings_wrapper::get_bool)
60                .def("set_bool", &script_wrapper::settings_wrapper::set_bool)
61                .def("get_int", &script_wrapper::settings_wrapper::get_int)
62                .def("set_int", &script_wrapper::settings_wrapper::set_int)
63                .def("save", &script_wrapper::settings_wrapper::save)
64                .def("register_path", &script_wrapper::settings_wrapper::settings_register_path)
65                .def("register_key", &script_wrapper::settings_wrapper::settings_register_key)
66                ;
67        class_<script_wrapper::function_wrapper, boost::shared_ptr<script_wrapper::function_wrapper> >("Registry", no_init)
68                .def("get",&script_wrapper::function_wrapper::create)
69                .staticmethod("get")
70                .def("create",&script_wrapper::function_wrapper::create)
71                .staticmethod("create")
72                .def("function", &script_wrapper::function_wrapper::register_function)
73                .def("simple_function", &script_wrapper::function_wrapper::register_simple_function)
74                .def("cmdline", &script_wrapper::function_wrapper::register_cmdline)
75                .def("simple_cmdline", &script_wrapper::function_wrapper::register_simple_cmdline)
76                .def("subscription", &script_wrapper::function_wrapper::subscribe_function)
77                .def("simple_subscription", &script_wrapper::function_wrapper::subscribe_simple_function)
78                ;
79        class_<script_wrapper::command_wrapper, boost::shared_ptr<script_wrapper::command_wrapper> >("Core", no_init)
80                .def("get",&script_wrapper::command_wrapper::create)
81                .staticmethod("get")
82                .def("create",&script_wrapper::command_wrapper::create)
83                .staticmethod("create")
84                .def("simple_query", &script_wrapper::command_wrapper::simple_query)
85                .def("query", &script_wrapper::command_wrapper::query)
86                .def("simple_exec", &script_wrapper::command_wrapper::simple_exec)
87                .def("exec", &script_wrapper::command_wrapper::exec)
88                .def("simple_submit", &script_wrapper::command_wrapper::simple_submit)
89                .def("submit", &script_wrapper::command_wrapper::submit)
90                ;
91
92        enum_<script_wrapper::status>("status")
93                .value("CRITICAL", script_wrapper::CRIT)
94                .value("WARNING", script_wrapper::WARN)
95                .value("UNKNOWN", script_wrapper::UNKNOWN)
96                .value("OK", script_wrapper::OK)
97                ;
98        def("log", script_wrapper::log_msg);
99//      def("get_module_alias", script_wrapper::get_module_alias);
100//      def("get_script_alias", script_wrapper::get_script_alias);
101}
102
103python_script::python_script(unsigned int plugin_id, const std::string alias, const script_container& script) : alias(alias), plugin_id(plugin_id) {
104        _exec(utf8::cvt<std::string>(script.script.string()));
105        callFunction("init", plugin_id, alias, utf8::cvt<std::string>(script.alias));
106}
107python_script::~python_script(){
108        callFunction("shutdown");
109}
110void python_script::callFunction(const std::string& functionName) {
111        try     {
112                object scriptFunction = extract<object>(localDict[functionName]);
113                if( scriptFunction )
114                        scriptFunction();
115        } catch( error_already_set e) {
116                script_wrapper::log_exception();
117        }
118}
119void python_script::callFunction(const std::string& functionName, unsigned int i1, const std::string &s1, const std::string &s2){
120        try     {
121                object scriptFunction = extract<object>(localDict[functionName]);
122                if(scriptFunction)
123                        scriptFunction(i1, s1, s2);
124        } catch(error_already_set e) {
125                script_wrapper::log_exception();
126        }
127}
128void python_script::_exec(const std::string &scriptfile){
129        try     {
130                object main_module = import("__main__");
131                dict globalDict = extract<dict>(main_module.attr("__dict__"));
132                localDict = globalDict.copy();
133                //localDict.attr("plugin_id") = plugin_id;
134                //localDict.attr("plugin_alias") = alias;
135
136                PyRun_SimpleString("import cStringIO");
137                PyRun_SimpleString("import sys");
138                PyRun_SimpleString("sys.stderr = cStringIO.StringIO()");
139                boost::filesystem::wpath path = GET_CORE()->getBasePath();
140                path /= _T("scripts");
141                path /= _T("python");
142                path /= _T("lib");
143                PyRun_SimpleString(("sys.path.append('" + utf8::cvt<std::string>(path.string()) + "')").c_str());
144                object ignored = exec_file(scriptfile.c_str(), localDict, localDict);   
145        } catch( error_already_set e) {
146                script_wrapper::log_exception();
147        }
148}
149
150bool PythonScript::loadModuleEx(std::wstring alias, NSCAPI::moduleLoadMode mode) {
151        alias_ = alias;
152        NSC_DEBUG_MSG_STD(_T("LoadEx in PythonScript as ") + alias);
153        try {
154                root_ = get_core()->getBasePath();
155
156                sh::settings_registry settings(get_settings_proxy());
157                settings.set_alias(alias, _T("python"));
158
159                settings.alias().add_path_to_settings()
160                        (_T("LUA SCRIPT SECTION"), _T("Section for the PythonScripts module."))
161
162                        (_T("scripts"), sh::fun_values_path(boost::bind(&PythonScript::loadScript, this, _1, _2)),
163                        _T("LUA SCRIPTS SECTION"), _T("A list of scripts available to run from the PythonScript module."))
164                        ;
165
166                settings.register_all();
167                settings.notify();
168
169                Py_Initialize();
170                try {
171
172                        PyRun_SimpleString("import cStringIO");
173                        PyRun_SimpleString("import sys");
174                        PyRun_SimpleString("sys.stderr = cStringIO.StringIO()");
175
176                        initNSCP();
177
178                        BOOST_FOREACH(script_container &script, scripts_) {
179                                instances_.push_back(boost::shared_ptr<python_script>(new python_script(get_id(), utf8::cvt<std::string>(alias), script)));
180                        }
181
182                } catch( error_already_set e) {
183                        script_wrapper::log_exception();
184                } catch (std::exception &e) {
185                        NSC_LOG_ERROR_STD(_T("Exception: Failed to load python scripts: ") + utf8::cvt<std::wstring>(e.what()));
186                }
187        } catch (...) {
188                NSC_LOG_ERROR_STD(_T("Exception caught: <UNKNOWN EXCEPTION>"));
189                return false;
190        }
191        return true;
192}
193
194boost::optional<boost::filesystem::wpath> PythonScript::find_file(std::wstring file) {
195        std::list<boost::filesystem::wpath> checks;
196        checks.push_back(file);
197        checks.push_back(root_ / _T("scripts") / _T("python") / file);
198        checks.push_back(root_ / _T("scripts") / file);
199        checks.push_back(root_ / _T("python") / file);
200        checks.push_back(root_ / file);
201        BOOST_FOREACH(boost::filesystem::wpath c, checks) {
202                NSC_DEBUG_MSG_STD(_T("Looking for: ") + c.string());
203                if (boost::filesystem::exists(c))
204                        return boost::optional<boost::filesystem::wpath>(c);
205        }
206        NSC_LOG_ERROR(_T("Script not found: ") + file);
207        return boost::optional<boost::filesystem::wpath>();
208}
209
210bool PythonScript::loadScript(std::wstring alias, std::wstring file) {
211        try {
212                if (file.empty()) {
213                        file = alias;
214                        alias = _T("");
215                }
216                boost::optional<boost::filesystem::wpath> ofile = find_file(file);
217                if (!ofile)
218                        return false;
219                script_container::push(scripts_, alias, *ofile);
220                NSC_DEBUG_MSG_STD(_T("Adding script: ") + alias + _T(" (") + ofile->string() + _T(")"));
221                return true;
222        } catch (...) {
223                NSC_LOG_ERROR_STD(_T("Could not find script: (Unknown exception) ") + file);
224        }
225        return false;
226}
227
228
229bool PythonScript::unloadModule() {
230        instances_.clear();
231        //Py_Finalize();
232        return true;
233}
234
235bool PythonScript::hasCommandHandler() {
236        return true;
237}
238bool PythonScript::hasMessageHandler() {
239        return true;
240}
241bool PythonScript::hasNotificationHandler() {
242        return true;
243}
244
245bool PythonScript::reload(std::wstring &message) {
246        /*
247        bool error = false;
248        commands_.clear();
249        for (script_list::const_iterator cit = scripts_.begin(); cit != scripts_.end() ; ++cit) {
250                try {
251                        (*cit)->reload(this);
252                } catch (script_wrapper::LUAException e) {
253                        error = true;
254                        message += _T("Exception when reloading script: ") + (*cit)->get_script() + _T(": ") + e.getMessage();
255                        NSC_LOG_ERROR_STD(_T("Exception when reloading script: ") + (*cit)->get_script() + _T(": ") + e.getMessage());
256                } catch (...) {
257                        error = true;
258                        message += _T("Unhandeled Exception when reloading script: ") + (*cit)->get_script();
259                        NSC_LOG_ERROR_STD(_T("Unhandeled Exception when reloading script: ") + (*cit)->get_script());
260                }
261        }
262        if (!error)
263                message = _T("LUA scripts Reloaded...");
264        return !error;
265        */
266        return false;
267}
268
269NSCAPI::nagiosReturn PythonScript::commandRAWLineExec(const wchar_t* char_command, const std::string &request, std::string &response) {
270        boost::shared_ptr<script_wrapper::function_wrapper> inst = script_wrapper::function_wrapper::create(get_id());
271        std::string cmd = utf8::cvt<std::string>(char_command);
272        if (inst->has_cmdline(cmd)) {
273                return inst->handle_exec(cmd, request, response);
274        }
275        if (inst->has_simple_cmdline(cmd)) {
276                nscapi::functions::decoded_simple_command_data data = nscapi::functions::parse_simple_exec_request(char_command, request);
277                std::wstring result;
278                NSCAPI::nagiosReturn ret = inst->handle_simple_exec(cmd, data.args, result);
279                nscapi::functions::create_simple_exec_response(data.command, ret, result, response);
280                return ret;
281        }
282        return NSCAPI::returnIgnored;
283}
284
285
286NSCAPI::nagiosReturn PythonScript::handleRAWCommand(const wchar_t* command, const std::string &request, std::string &response) {
287        boost::shared_ptr<script_wrapper::function_wrapper> inst = script_wrapper::function_wrapper::create(get_id());
288        std::string cmd = utf8::cvt<std::string>(command);
289        if (inst->has_function(cmd)) {
290                return inst->exec(cmd, request, response);
291        }
292        if (inst->has_simple(cmd)) {
293                nscapi::functions::decoded_simple_command_data data = nscapi::functions::parse_simple_query_request(command, request);
294                std::wstring msg, perf;
295                NSCAPI::nagiosReturn ret = inst->exec_simple(cmd, data.args, msg, perf);
296                nscapi::functions::create_simple_query_response(data.command, ret, msg, perf, response);
297                return ret;
298        }
299        NSC_LOG_ERROR_STD(_T("Could not find python commands for: ") + command + _T(" (avalible python commands are: ") + inst->get_commands() + _T(")"));
300        /*
301        if (command == _T("luareload")) {
302                return reload(message)?NSCAPI::returnOK:NSCAPI::returnCRIT;
303        }
304        */
305        return NSCAPI::returnIgnored;
306}
307
308
309NSCAPI::nagiosReturn PythonScript::handleRAWNotification(const std::wstring &channel, const std::wstring &command, std::string &request) {
310        boost::shared_ptr<script_wrapper::function_wrapper> inst = script_wrapper::function_wrapper::create(get_id());
311        std::string cmd = utf8::cvt<std::string>(command);
312        std::string chnl = utf8::cvt<std::string>(channel);
313        if (inst->has_message_handler(chnl)) {
314                return inst->handle_message(chnl, cmd, request);
315        }
316        if (inst->has_simple_message_handler(chnl)) {
317                std::wstring msg, perf;
318                int code = nscapi::functions::parse_simple_query_response(request, msg, perf);
319                return inst->handle_simple_message(chnl, cmd, code, msg, perf);
320        }
321        return NSCAPI::returnIgnored;
322}
323
324NSC_WRAP_DLL();
325NSC_WRAPPERS_MAIN_DEF(PythonScript);
326NSC_WRAPPERS_IGNORE_MSG_DEF();
327NSC_WRAPPERS_HANDLE_CMD_DEF();
328NSC_WRAPPERS_CLI_DEF();
329NSC_WRAPPERS_HANDLE_NOTIFICATION_DEF();
Note: See TracBrowser for help on using the repository browser.