Remove support for external scripting languages.

Fixes #5920
This commit is contained in:
Gunnar Beutner 2014-04-02 09:03:19 +02:00
parent a05c31cda2
commit ebf8ed3019
12 changed files with 3 additions and 1067 deletions

View File

@ -19,7 +19,6 @@ mkclass_target(application.ti application.th)
mkclass_target(dynamicobject.ti dynamicobject.th) mkclass_target(dynamicobject.ti dynamicobject.th)
mkclass_target(filelogger.ti filelogger.th) mkclass_target(filelogger.ti filelogger.th)
mkclass_target(logger.ti logger.th) mkclass_target(logger.ti logger.th)
mkclass_target(script.ti script.th)
mkclass_target(streamlogger.ti streamlogger.th) mkclass_target(streamlogger.ti streamlogger.th)
mkclass_target(sysloglogger.ti sysloglogger.th) mkclass_target(sysloglogger.ti sysloglogger.th)
@ -28,9 +27,9 @@ add_library(base SHARED
convert.cpp dictionary.cpp dynamicobject.cpp dynamicobject.th dynamictype.cpp convert.cpp dictionary.cpp dynamicobject.cpp dynamicobject.th dynamictype.cpp
exception.cpp fifo.cpp filelogger.cpp filelogger.th logger.cpp logger.th exception.cpp fifo.cpp filelogger.cpp filelogger.th logger.cpp logger.th
netstring.cpp networkstream.cpp object.cpp objectlock.cpp process.cpp netstring.cpp networkstream.cpp object.cpp objectlock.cpp process.cpp
process-unix.cpp process-windows.cpp qstring.cpp ringbuffer.cpp script.cpp process-unix.cpp process-windows.cpp qstring.cpp ringbuffer.cpp
script.th scriptfunction.cpp scriptfunctionwrapper.cpp scriptinterpreter.cpp scriptfunction.cpp scriptfunctionwrapper.cpp scriptutils.cpp
scriptlanguage.cpp scriptutils.cpp scriptvariable.cpp serializer.cpp socket.cpp stacktrace.cpp scriptvariable.cpp serializer.cpp socket.cpp stacktrace.cpp
statsfunction.cpp stdiostream.cpp stream_bio.cpp stream.cpp streamlogger.cpp streamlogger.th statsfunction.cpp stdiostream.cpp stream_bio.cpp stream.cpp streamlogger.cpp streamlogger.th
sysloglogger.cpp sysloglogger.th tcpsocket.cpp threadpool.cpp timer.cpp sysloglogger.cpp sysloglogger.th tcpsocket.cpp threadpool.cpp timer.cpp
tlsstream.cpp tlsutility.cpp type.cpp unixsocket.cpp utility.cpp value.cpp tlsstream.cpp tlsutility.cpp type.cpp unixsocket.cpp utility.cpp value.cpp

View File

@ -1,46 +0,0 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#include "base/script.h"
#include "base/scriptlanguage.h"
#include "base/dynamictype.h"
#include "base/logger_fwd.h"
#include "base/objectlock.h"
#include "base/debug.h"
using namespace icinga;
REGISTER_TYPE(Script);
void Script::Start(void)
{
DynamicObject::Start();
ASSERT(OwnsLock());
SpawnInterpreter();
}
void Script::SpawnInterpreter(void)
{
Log(LogInformation, "base", "Reloading script '" + GetName() + "'");
ScriptLanguage::Ptr language = ScriptLanguage::GetByName(GetLanguage());
m_Interpreter = language->CreateInterpreter(GetSelf());
}

View File

@ -1,51 +0,0 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#ifndef SCRIPT_H
#define SCRIPT_H
#include "base/i2-base.h"
#include "base/script.th"
namespace icinga
{
class ScriptInterpreter;
/**
* A script.
*
* @ingroup base
*/
class I2_BASE_API Script : public ObjectImpl<Script>
{
public:
DECLARE_PTR_TYPEDEFS(Script);
virtual void Start(void);
private:
shared_ptr<ScriptInterpreter> m_Interpreter;
void SpawnInterpreter(void);
};
}
#endif /* SCRIPT_H */

View File

@ -1,12 +0,0 @@
#include "base/dynamicobject.h"
namespace icinga
{
class Script : DynamicObject
{
[config] String language;
[config] String "code";
};
}

View File

@ -1,52 +0,0 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#include "base/scriptinterpreter.h"
#include "base/scriptfunction.h"
#include "base/objectlock.h"
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
using namespace icinga;
ScriptInterpreter::ScriptInterpreter(const Script::Ptr&)
{ }
ScriptInterpreter::~ScriptInterpreter(void)
{
BOOST_FOREACH(const String& function, m_SubscribedFunctions) {
ScriptFunction::Unregister(function);
}
}
void ScriptInterpreter::SubscribeFunction(const String& name)
{
ObjectLock olock(this);
m_SubscribedFunctions.insert(name);
ScriptFunction::Register(name, boost::bind(&ScriptInterpreter::ProcessCall, this, name, _1));
}
void ScriptInterpreter::UnsubscribeFunction(const String& name)
{
ObjectLock olock(this);
m_SubscribedFunctions.erase(name);
ScriptFunction::Unregister(name);
}

View File

@ -1,57 +0,0 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#ifndef SCRIPTINTERPRETER_H
#define SCRIPTINTERPRETER_H
#include "base/i2-base.h"
#include "base/script.h"
#include <vector>
#include <set>
namespace icinga
{
/**
* A script interpreter.
*
* @ingroup base
*/
class I2_BASE_API ScriptInterpreter : public Object
{
public:
DECLARE_PTR_TYPEDEFS(ScriptInterpreter);
~ScriptInterpreter(void);
protected:
ScriptInterpreter(const Script::Ptr& script);
virtual Value ProcessCall(const String& function, const std::vector<Value>& arguments) = 0;
void SubscribeFunction(const String& name);
void UnsubscribeFunction(const String& name);
private:
std::set<String> m_SubscribedFunctions;
};
}
#endif /* SCRIPTINTERPRETER_H */

View File

@ -1,65 +0,0 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#include "base/scriptlanguage.h"
using namespace icinga;
ScriptLanguage::ScriptLanguage(void)
{ }
void ScriptLanguage::Register(const String& name, const ScriptLanguage::Ptr& language)
{
boost::mutex::scoped_lock lock(GetMutex());
GetLanguages()[name] = language;
}
void ScriptLanguage::Unregister(const String& name)
{
boost::mutex::scoped_lock lock(GetMutex());
GetLanguages().erase(name);
}
ScriptLanguage::Ptr ScriptLanguage::GetByName(const String& name)
{
boost::mutex::scoped_lock lock(GetMutex());
std::map<String, ScriptLanguage::Ptr>::iterator it;
it = GetLanguages().find(name);
if (it == GetLanguages().end())
return ScriptLanguage::Ptr();
return it->second;
}
boost::mutex& ScriptLanguage::GetMutex(void)
{
static boost::mutex mutex;
return mutex;
}
std::map<String, ScriptLanguage::Ptr>& ScriptLanguage::GetLanguages(void)
{
static std::map<String, ScriptLanguage::Ptr> languages;
return languages;
}

View File

@ -1,77 +0,0 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#ifndef SCRIPTLANGUAGE_H
#define SCRIPTLANGUAGE_H
#include "base/i2-base.h"
#include "base/scriptinterpreter.h"
#include <map>
namespace icinga
{
/**
* A scripting language.
*
* @ingroup base
*/
class I2_BASE_API ScriptLanguage : public Object
{
public:
DECLARE_PTR_TYPEDEFS(ScriptLanguage);
static void Register(const String& name, const ScriptLanguage::Ptr& language);
static void Unregister(const String& name);
static ScriptLanguage::Ptr GetByName(const String& name);
virtual ScriptInterpreter::Ptr CreateInterpreter(const Script::Ptr& script) = 0;
void SubscribeFunction(const String& name);
void UnsubscribeFunction(const String& name);
protected:
ScriptLanguage(void);
private:
static boost::mutex& GetMutex(void);
static std::map<String, ScriptLanguage::Ptr>& GetLanguages(void);
};
/**
* Helper class for registering ScriptLanguage implementation classes.
*
* @ingroup base
*/
class RegisterLanguageHelper
{
public:
RegisterLanguageHelper(const String& name, const ScriptLanguage::Ptr& language)
{
if (!ScriptLanguage::GetByName(name))
ScriptLanguage::Register(name, language);
}
};
#define REGISTER_SCRIPTLANGUAGE(name, klass) \
static RegisterLanguageHelper g_RegisterSL_ ## type(name, make_shared<klass>())
}
#endif /* SCRIPTLANGUAGE_H */

View File

@ -1,132 +0,0 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#include "python/pythoninterpreter.h"
#include "base/objectlock.h"
#include "base/utility.h"
#include <boost/foreach.hpp>
using namespace icinga;
PythonInterpreter::PythonInterpreter(const PythonLanguage::Ptr& language,
const Script::Ptr& script)
: ScriptInterpreter(script), m_Language(language), m_ThreadState(NULL)
{
PyEval_AcquireLock();
PythonInterpreter *interp = m_Language->GetCurrentInterpreter();
m_Language->SetCurrentInterpreter(this);
PyInterpreterState *pinterp = m_Language->GetMainThreadState()->interp;
m_ThreadState = PyThreadState_New(pinterp);
(void) PyThreadState_Swap(m_ThreadState);
PyRun_SimpleString(script->GetCode().CStr());
(void) PyThreadState_Swap(NULL);
m_Language->SetCurrentInterpreter(interp);
PyEval_ReleaseLock();
}
PythonInterpreter::~PythonInterpreter(void)
{
PyEval_AcquireLock();
(void) PyThreadState_Swap(NULL);
PyThreadState_Clear(m_ThreadState);
PyThreadState_Delete(m_ThreadState);
PyEval_ReleaseLock();
}
void PythonInterpreter::RegisterPythonFunction(const String& name, PyObject *function)
{
ObjectLock olock(this);
SubscribeFunction(name);
Py_INCREF(function);
m_Functions[name] = function;
}
void PythonInterpreter::UnregisterPythonFunction(const String& name)
{
ObjectLock olock(this);
UnsubscribeFunction(name);
m_Functions.erase(name);
}
Value PythonInterpreter::ProcessCall(const String& function, const std::vector<Value>& arguments)
{
ObjectLock olock(this);
PyEval_AcquireThread(m_ThreadState);
PythonInterpreter *interp = m_Language->GetCurrentInterpreter();
m_Language->SetCurrentInterpreter(this);
try {
std::map<String, PyObject *>::iterator it = m_Functions.find(function);
if (it == m_Functions.end())
BOOST_THROW_EXCEPTION(std::invalid_argument("Function '" + function + "' does not exist."));
PyObject *func = it->second;
PyObject *args = PyTuple_New(arguments.size());
int i = 0;
BOOST_FOREACH(const Value& argument, arguments) {
PyObject *arg = PythonLanguage::MarshalToPython(argument);
PyTuple_SetItem(args, i, arg);
}
PyObject *result = PyObject_CallObject(func, args);
Py_DECREF(args);
if (PyErr_Occurred()) {
PyObject *ptype, *pvalue, *ptraceback;
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
String msg = m_Language->ExceptionInfoToString(ptype, pvalue, ptraceback);
Py_XDECREF(ptype);
Py_XDECREF(pvalue);
Py_XDECREF(ptraceback);
BOOST_THROW_EXCEPTION(std::runtime_error("Error in Python script: " + msg));
}
Value vresult = PythonLanguage::MarshalFromPython(result);
Py_DECREF(result);
m_Language->SetCurrentInterpreter(interp);
PyEval_ReleaseThread(m_ThreadState);
return vresult;
} catch (...) {
m_Language->SetCurrentInterpreter(interp);
PyEval_ReleaseThread(m_ThreadState);
throw;
}
}

View File

@ -1,56 +0,0 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#ifndef PYTHONINTERPRETER_H
#define PYTHONINTERPRETER_H
#include <Python.h>
#include "python/pythonlanguage.h"
#include "base/scriptinterpreter.h"
namespace icinga
{
/**
* A Python script interpreter.
*
* @ingroup base
*/
class PythonInterpreter : public ScriptInterpreter
{
public:
DECLARE_PTR_TYPEDEFS(PythonInterpreter);
PythonInterpreter(const PythonLanguage::Ptr& language, const Script::Ptr& script);
~PythonInterpreter(void);
void RegisterPythonFunction(const String& name, PyObject *function);
void UnregisterPythonFunction(const String& name);
protected:
PythonLanguage::Ptr m_Language;
PyThreadState *m_ThreadState;
std::map<String, PyObject *> m_Functions;
virtual Value ProcessCall(const String& function, const std::vector<Value>& arguments);
};
}
#endif /* PYTHONINTERPRETER_H */

View File

@ -1,439 +0,0 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#include "python/pythonlanguage.h"
#include "python/pythoninterpreter.h"
#include "base/scriptfunction.h"
#include "base/dynamictype.h"
#include "base/objectlock.h"
#include "base/application.h"
#include "base/array.h"
#include <boost/foreach.hpp>
#include <boost/tuple/tuple.hpp>
using namespace icinga;
PythonInterpreter *PythonLanguage::m_CurrentInterpreter;
REGISTER_SCRIPTLANGUAGE("Python", PythonLanguage);
PyMethodDef PythonLanguage::m_NativeMethodDef[] = {
{ "RegisterFunction", &PythonLanguage::PyRegisterFunction, METH_VARARGS, NULL },
{ NULL, NULL, 0, NULL } /* sentinel */
};
PythonLanguage::PythonLanguage(void)
: ScriptLanguage(), m_Initialized(false)
{ }
void PythonLanguage::InitializeOnce(void)
{
ObjectLock olock(this);
if (m_Initialized)
return;
Py_Initialize();
PyEval_InitThreads();
Py_SetProgramName(Application::GetArgV()[0]);
PySys_SetArgv(Application::GetArgC(), Application::GetArgV());
// See http://docs.python.org/2/c-api/init.html for an explanation.
PyRun_SimpleString("import sys; sys.path.pop(0)\n");
m_MainThreadState = PyThreadState_Get();
m_TracebackModule = PyImport_ImportModule("traceback");
m_NativeModule = Py_InitModule("ire", m_NativeMethodDef);
(void) PyThreadState_Swap(NULL);
PyEval_ReleaseLock();
String name;
BOOST_FOREACH(boost::tie(name, boost::tuples::ignore), ScriptFunctionRegistry::GetInstance()->GetItems()) {
RegisterNativeFunction(name);
}
ScriptFunctionRegistry::GetInstance()->OnRegistered.connect(boost::bind(&PythonLanguage::RegisterNativeFunction, this, _1));
ScriptFunctionRegistry::GetInstance()->OnUnregistered.connect(boost::bind(&PythonLanguage::UnregisterNativeFunction, this, _1));
m_Initialized = true;
}
PythonLanguage::~PythonLanguage(void)
{
/* Due to how we're destructing objects it might not be safe to
* call Py_Finalize() when the Icinga instance is being shut
* down - so don't bother calling it. */
}
ScriptInterpreter::Ptr PythonLanguage::CreateInterpreter(const Script::Ptr& script)
{
InitializeOnce();
return make_shared<PythonInterpreter>(GetSelf(), script);
}
PyThreadState *PythonLanguage::GetMainThreadState(void) const
{
ObjectLock olock(this);
return m_MainThreadState;
}
PyObject *PythonLanguage::MarshalToPython(const Value& value)
{
String svalue;
switch (value.GetType()) {
case ValueEmpty:
Py_INCREF(Py_None);
return Py_None;
case ValueNumber:
return PyFloat_FromDouble(value);
case ValueString:
svalue = value;
return PyString_FromString(svalue.CStr());
case ValueObject:
if (value.IsObjectType<DynamicObject>()) {
DynamicObject::Ptr dobj = value;
String type = dobj->GetType()->GetName();
String name = dobj->GetName();
PyObject *ptype = PyString_FromString(type.CStr());
if (ptype == NULL)
return NULL;
PyObject *pname = PyString_FromString(name.CStr());
if (pname == NULL) {
Py_DECREF(ptype);
return NULL;
}
PyObject *result = PyTuple_New(2);
if (result == NULL) {
Py_DECREF(ptype);
Py_DECREF(pname);
return NULL;
}
(void) PyTuple_SetItem(result, 0, ptype);
(void) PyTuple_SetItem(result, 1, pname);
return result;
} else if (value.IsObjectType<Dictionary>()) {
Dictionary::Ptr dict = value;
ObjectLock olock(dict);
PyObject *pdict = PyDict_New();
String key;
Value value;
BOOST_FOREACH(boost::tie(key, value), dict) {
PyObject *dv = MarshalToPython(value);
PyDict_SetItemString(pdict, key.CStr(), dv);
Py_DECREF(dv);
}
return pdict;
} else if (value.IsObjectType<Array>()) {
Array::Ptr arr = value;
ObjectLock olock(arr);
PyObject *plist = PyList_New(0);
BOOST_FOREACH(const Value& value, arr) {
PyObject *dv = MarshalToPython(value);
PyList_Append(plist, dv);
Py_DECREF(dv);
}
return plist;
}
Py_INCREF(Py_None);
return Py_None;
default:
BOOST_THROW_EXCEPTION(std::invalid_argument("Unexpected variant type."));
}
}
Value PythonLanguage::MarshalFromPython(PyObject *value)
{
if (value == Py_None) {
return Empty;
} else if (PyDict_Check(value)) {
Dictionary::Ptr dict = make_shared<Dictionary>();
PyObject *dk, *dv;
Py_ssize_t pos = 0;
while (PyDict_Next(value, &pos, &dk, &dv)) {
String ik = PyString_AsString(dk);
Value iv = MarshalFromPython(dv);
dict->Set(ik, iv);
}
return dict;
} else if (PyList_Check(value)) {
Array::Ptr arr = make_shared<Array>();
for (Py_ssize_t pos = 0; pos < PyList_Size(value); pos++) {
PyObject *dv = PyList_GetItem(value, pos);
Value iv = MarshalFromPython(dv);
arr->Add(iv);
}
return arr;
} else if (PyTuple_Check(value) && PyTuple_Size(value) == 2) {
PyObject *ptype, *pname;
ptype = PyTuple_GetItem(value, 0);
if (ptype == NULL || !PyString_Check(ptype))
BOOST_THROW_EXCEPTION(std::invalid_argument("Tuple must contain two strings."));
String type = PyString_AsString(ptype);
pname = PyTuple_GetItem(value, 1);
if (pname == NULL || !PyString_Check(pname))
BOOST_THROW_EXCEPTION(std::invalid_argument("Tuple must contain two strings."));
String name = PyString_AsString(pname);
DynamicType::Ptr dtype = DynamicType::GetByName(type);
if (!dtype)
BOOST_THROW_EXCEPTION(std::invalid_argument("Type '" + type + "' does not exist."));
DynamicObject::Ptr object = dtype->GetObject(name);
if (!object)
BOOST_THROW_EXCEPTION(std::invalid_argument("Object '" + name + "' of type '" + type + "' does not exist."));
return object;
} else if (PyFloat_Check(value)) {
return PyFloat_AsDouble(value);
} else if (PyInt_Check(value)) {
return PyInt_AsLong(value);
} else if (PyString_Check(value)) {
return PyString_AsString(value);
} else {
return Empty;
}
}
String PythonLanguage::ExceptionInfoToString(PyObject *type, PyObject *exc, PyObject *tb) const
{
ObjectLock olock(this);
PyObject *tb_dict = PyModule_GetDict(m_TracebackModule);
PyObject *format_exception = PyDict_GetItemString(tb_dict, "format_exception");
if (!PyCallable_Check(format_exception))
return "Failed to format exception information.";
PyObject *result = PyObject_CallFunctionObjArgs(format_exception, type, exc, tb, NULL);
Py_DECREF(format_exception);
Py_DECREF(tb_dict);
if (!result || !PyList_Check(result)) {
Py_XDECREF(result);
return "format_exception() returned something that is not a list.";
}
String msg;
for (Py_ssize_t i = 0; i < PyList_Size(result); i++) {
PyObject *li = PyList_GetItem(result, i);
if (!li || !PyString_Check(li)) {
Py_DECREF(result);
return "format_exception() returned something that is not a list of strings.";
}
msg += PyString_AsString(li);
}
Py_DECREF(result);
return msg;
}
PyObject *PythonLanguage::PyCallNativeFunction(PyObject *self, PyObject *args)
{
assert(PyString_Check(self));
char *name = PyString_AsString(self);
ScriptFunction::Ptr function = ScriptFunctionRegistry::GetInstance()->GetItem(name);
std::vector<Value> arguments;
if (args != NULL) {
if (PyTuple_Check(args)) {
for (Py_ssize_t i = 0; i < PyTuple_Size(args); i++) {
PyObject *arg = PyTuple_GetItem(args, i);
arguments.push_back(MarshalFromPython(arg));
}
} else {
arguments.push_back(MarshalFromPython(args));
}
}
PyThreadState *tstate = PyEval_SaveThread();
Value result;
try {
result = function->Invoke(arguments);
} catch (const std::exception& ex) {
PyEval_RestoreThread(tstate);
String message = DiagnosticInformation(ex);
PyErr_SetString(PyExc_RuntimeError, message.CStr());
return NULL;
}
PyEval_RestoreThread(tstate);
return MarshalToPython(result);
}
/**
* Registers a native function.
*
* @param name The name of the native function.
*/
void PythonLanguage::RegisterNativeFunction(const String& name)
{
ObjectLock olock(this);
PyThreadState *tstate = PyThreadState_Swap(m_MainThreadState);
PyObject *pname = PyString_FromString(name.CStr());
PyMethodDef *md = new PyMethodDef;
md->ml_name = strdup(name.CStr());
md->ml_meth = &PythonLanguage::PyCallNativeFunction;
md->ml_flags = METH_VARARGS;
md->ml_doc = NULL;
PyObject *pfunc = PyCFunction_NewEx(md, pname, m_NativeModule);
(void) PyModule_AddObject(m_NativeModule, name.CStr(), pfunc);
(void) PyThreadState_Swap(tstate);
}
/**
* Unregisters a native function.
*
* @param name The name of the native function.
*/
void PythonLanguage::UnregisterNativeFunction(const String& name)
{
ObjectLock olock(this);
PyThreadState *tstate = PyThreadState_Swap(m_MainThreadState);
PyObject *pdict = PyModule_GetDict(m_NativeModule);
PyObject *pname = PyString_FromString(name.CStr());
PyCFunctionObject *pfunc = (PyCFunctionObject *)PyDict_GetItem(pdict, pname);
if (pfunc && PyCFunction_Check(pfunc)) {
/* Eww. */
free(const_cast<char *>(pfunc->m_ml->ml_name));
delete pfunc->m_ml;
}
(void) PyDict_DelItem(pdict, pname);
Py_DECREF(pname);
(void) PyThreadState_Swap(tstate);
}
PyObject *PythonLanguage::PyRegisterFunction(PyObject *, PyObject *args)
{
char *name;
PyObject *object;
if (!PyArg_ParseTuple(args, "sO", &name, &object))
return NULL;
PythonInterpreter *interp = GetCurrentInterpreter();
if (interp == NULL) {
PyErr_SetString(PyExc_RuntimeError, "GetCurrentInterpreter() returned NULL.");
return NULL;
}
if (!PyCallable_Check(object)) {
PyErr_SetString(PyExc_RuntimeError, "Function object is not callable.");
return NULL;
}
interp->RegisterPythonFunction(name, object);
Py_INCREF(Py_None);
return Py_None;
}
/**
* Retrieves the current interpreter object. Caller must hold the GIL.
*
* @returns The current interpreter.
*/
PythonInterpreter *PythonLanguage::GetCurrentInterpreter(void)
{
return m_CurrentInterpreter;
}
/**
* Sets the current interpreter. Caller must hold the GIL.
*
* @param interpreter The interpreter.
*/
void PythonLanguage::SetCurrentInterpreter(PythonInterpreter *interpreter)
{
m_CurrentInterpreter = interpreter;
}

View File

@ -1,76 +0,0 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#ifndef PYTHONLANGUAGE_H
#define PYTHONLANGUAGE_H
#include <Python.h>
#include "base/scriptlanguage.h"
namespace icinga
{
class PythonInterpreter;
/**
* The Python scripting language.
*
* @ingroup base
*/
class PythonLanguage : public ScriptLanguage
{
public:
DECLARE_PTR_TYPEDEFS(PythonLanguage);
PythonLanguage(void);
~PythonLanguage(void);
virtual ScriptInterpreter::Ptr CreateInterpreter(const Script::Ptr& script);
PyThreadState *GetMainThreadState(void) const;
static PythonInterpreter *GetCurrentInterpreter(void);
static void SetCurrentInterpreter(PythonInterpreter *interpreter);
static PyObject *MarshalToPython(const Value& value);
static Value MarshalFromPython(PyObject *value);
String ExceptionInfoToString(PyObject *type, PyObject *exc, PyObject *tb) const;
private:
bool m_Initialized;
PyThreadState *m_MainThreadState;
PyObject *m_NativeModule;
PyObject *m_TracebackModule;
static PythonInterpreter *m_CurrentInterpreter;
void RegisterNativeFunction(const String& name);
void UnregisterNativeFunction(const String& name);
static PyObject *PyCallNativeFunction(PyObject *self, PyObject *args);
static PyObject *PyRegisterFunction(PyObject *self, PyObject *args);
static PyMethodDef m_NativeMethodDef[];
void InitializeOnce(void);
};
}
#endif /* PYTHONLANGUAGE_H */