mirror of https://github.com/Icinga/icinga2.git
parent
a05c31cda2
commit
ebf8ed3019
|
@ -19,7 +19,6 @@ mkclass_target(application.ti application.th)
|
|||
mkclass_target(dynamicobject.ti dynamicobject.th)
|
||||
mkclass_target(filelogger.ti filelogger.th)
|
||||
mkclass_target(logger.ti logger.th)
|
||||
mkclass_target(script.ti script.th)
|
||||
mkclass_target(streamlogger.ti streamlogger.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
|
||||
exception.cpp fifo.cpp filelogger.cpp filelogger.th logger.cpp logger.th
|
||||
netstring.cpp networkstream.cpp object.cpp objectlock.cpp process.cpp
|
||||
process-unix.cpp process-windows.cpp qstring.cpp ringbuffer.cpp script.cpp
|
||||
script.th scriptfunction.cpp scriptfunctionwrapper.cpp scriptinterpreter.cpp
|
||||
scriptlanguage.cpp scriptutils.cpp scriptvariable.cpp serializer.cpp socket.cpp stacktrace.cpp
|
||||
process-unix.cpp process-windows.cpp qstring.cpp ringbuffer.cpp
|
||||
scriptfunction.cpp scriptfunctionwrapper.cpp scriptutils.cpp
|
||||
scriptvariable.cpp serializer.cpp socket.cpp stacktrace.cpp
|
||||
statsfunction.cpp stdiostream.cpp stream_bio.cpp stream.cpp streamlogger.cpp streamlogger.th
|
||||
sysloglogger.cpp sysloglogger.th tcpsocket.cpp threadpool.cpp timer.cpp
|
||||
tlsstream.cpp tlsutility.cpp type.cpp unixsocket.cpp utility.cpp value.cpp
|
||||
|
|
|
@ -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());
|
||||
}
|
|
@ -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 */
|
|
@ -1,12 +0,0 @@
|
|||
#include "base/dynamicobject.h"
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
class Script : DynamicObject
|
||||
{
|
||||
[config] String language;
|
||||
[config] String "code";
|
||||
};
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
Loading…
Reference in New Issue