mirror of
https://github.com/Icinga/icinga2.git
synced 2025-07-16 10:14:28 +02:00
Implemented calling ScriptFunctions from Python.
This commit is contained in:
parent
a022be9de2
commit
4998563a74
@ -25,7 +25,7 @@ boost::signal<void (const String&, const ScriptFunction::Ptr&)> ScriptFunction::
|
|||||||
boost::signal<void (const String&)> ScriptFunction::OnUnregistered;
|
boost::signal<void (const String&)> ScriptFunction::OnUnregistered;
|
||||||
|
|
||||||
ScriptFunction::ScriptFunction(const Callback& function)
|
ScriptFunction::ScriptFunction(const Callback& function)
|
||||||
: m_Callback(function)
|
: m_Callback(function), m_ArgumentCount(-1)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void ScriptFunction::Register(const String& name, const ScriptFunction::Ptr& function)
|
void ScriptFunction::Register(const String& name, const ScriptFunction::Ptr& function)
|
||||||
@ -62,3 +62,43 @@ map<String, ScriptFunction::Ptr>& ScriptFunction::GetFunctions(void)
|
|||||||
static map<String, ScriptFunction::Ptr> functions;
|
static map<String, ScriptFunction::Ptr> functions;
|
||||||
return functions;
|
return functions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScriptFunction::SetArgumentCount(int count)
|
||||||
|
{
|
||||||
|
if (m_ArgumentCount >= 0)
|
||||||
|
m_ArgumentHints.resize(count);
|
||||||
|
|
||||||
|
m_ArgumentCount = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ScriptFunction::GetArgumentCount(void) const
|
||||||
|
{
|
||||||
|
return m_ArgumentCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptFunction::SetArgumentHint(int index, const ScriptArgumentHint& hint)
|
||||||
|
{
|
||||||
|
assert(index >= 0 && index < m_ArgumentCount);
|
||||||
|
|
||||||
|
m_ArgumentHints[index] = hint;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptArgumentHint ScriptFunction::GetArgumentHint(int index) const
|
||||||
|
{
|
||||||
|
if (m_ArgumentCount == -1 || index >= m_ArgumentCount)
|
||||||
|
return ScriptArgumentHint();
|
||||||
|
|
||||||
|
assert(index >= 0 && index < m_ArgumentHints.size());
|
||||||
|
|
||||||
|
return m_ArgumentHints[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptFunction::SetReturnHint(const ScriptArgumentHint& hint)
|
||||||
|
{
|
||||||
|
m_ReturnHint = hint;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptArgumentHint ScriptFunction::GetReturnHint(void) const
|
||||||
|
{
|
||||||
|
return m_ReturnHint;
|
||||||
|
}
|
||||||
|
@ -25,6 +25,20 @@ namespace icinga
|
|||||||
|
|
||||||
class ScriptTask;
|
class ScriptTask;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type hint.
|
||||||
|
*/
|
||||||
|
struct ScriptArgumentHint
|
||||||
|
{
|
||||||
|
bool RestrictType;
|
||||||
|
ValueType Type;
|
||||||
|
String Class;
|
||||||
|
|
||||||
|
ScriptArgumentHint(void)
|
||||||
|
: RestrictType(false), Type(ValueEmpty), Class()
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A script function that can be used to execute a script task.
|
* A script function that can be used to execute a script task.
|
||||||
*
|
*
|
||||||
@ -46,6 +60,15 @@ public:
|
|||||||
|
|
||||||
void Invoke(const shared_ptr<ScriptTask>& task, const vector<Value>& arguments);
|
void Invoke(const shared_ptr<ScriptTask>& task, const vector<Value>& arguments);
|
||||||
|
|
||||||
|
void SetArgumentCount(int count);
|
||||||
|
int GetArgumentCount(void) const;
|
||||||
|
|
||||||
|
void SetArgumentHint(int index, const ScriptArgumentHint& hint);
|
||||||
|
ScriptArgumentHint GetArgumentHint(int index) const;
|
||||||
|
|
||||||
|
void SetReturnHint(const ScriptArgumentHint& hint);
|
||||||
|
ScriptArgumentHint GetReturnHint(void) const;
|
||||||
|
|
||||||
static map<String, ScriptFunction::Ptr>& GetFunctions(void);
|
static map<String, ScriptFunction::Ptr>& GetFunctions(void);
|
||||||
|
|
||||||
static boost::signal<void (const String&, const ScriptFunction::Ptr&)> OnRegistered;
|
static boost::signal<void (const String&, const ScriptFunction::Ptr&)> OnRegistered;
|
||||||
@ -53,6 +76,9 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Callback m_Callback;
|
Callback m_Callback;
|
||||||
|
int m_ArgumentCount;
|
||||||
|
vector<ScriptArgumentHint> m_ArgumentHints;
|
||||||
|
ScriptArgumentHint m_ReturnHint;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,6 +40,9 @@ public:
|
|||||||
|
|
||||||
virtual ScriptInterpreter::Ptr CreateInterpreter(const Script::Ptr& script) = 0;
|
virtual ScriptInterpreter::Ptr CreateInterpreter(const Script::Ptr& script) = 0;
|
||||||
|
|
||||||
|
void SubscribeFunction(const String& name);
|
||||||
|
void UnsubscribeFunction(const String& name);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ScriptLanguage(void);
|
ScriptLanguage(void);
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@ pkglib_LTLIBRARIES = \
|
|||||||
libicinga.la
|
libicinga.la
|
||||||
|
|
||||||
libicinga_la_SOURCES = \
|
libicinga_la_SOURCES = \
|
||||||
|
api.cpp \
|
||||||
|
api.h \
|
||||||
checkresultmessage.cpp \
|
checkresultmessage.cpp \
|
||||||
checkresultmessage.h \
|
checkresultmessage.h \
|
||||||
cib.cpp \
|
cib.cpp \
|
||||||
|
36
lib/icinga/api.cpp
Normal file
36
lib/icinga/api.cpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Icinga 2 *
|
||||||
|
* Copyright (C) 2012 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 "i2-icinga.h"
|
||||||
|
|
||||||
|
using namespace icinga;
|
||||||
|
|
||||||
|
REGISTER_SCRIPTFUNCTION("GetAnswerToEverything", &API::GetAnswerToEverything);
|
||||||
|
|
||||||
|
void API::GetAnswerToEverything(const ScriptTask::Ptr& task, const vector<Value>& arguments)
|
||||||
|
{
|
||||||
|
if (arguments.size() < 1)
|
||||||
|
BOOST_THROW_EXCEPTION(invalid_argument("Text argument required."));
|
||||||
|
|
||||||
|
String text = arguments[0];
|
||||||
|
|
||||||
|
Logger::Write(LogInformation, "icinga", "Hello from the Icinga 2 API: " + text);
|
||||||
|
|
||||||
|
task->FinishResult(42);
|
||||||
|
}
|
42
lib/icinga/api.h
Normal file
42
lib/icinga/api.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Icinga 2 *
|
||||||
|
* Copyright (C) 2012 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 API_H
|
||||||
|
#define API_H
|
||||||
|
|
||||||
|
namespace icinga
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A state change message for a service.
|
||||||
|
*
|
||||||
|
* @ingroup icinga
|
||||||
|
*/
|
||||||
|
class I2_ICINGA_API API
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void GetAnswerToEverything(const ScriptTask::Ptr& task, const vector<Value>& arguments);
|
||||||
|
|
||||||
|
private:
|
||||||
|
API(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* API_H */
|
@ -64,4 +64,6 @@ using boost::algorithm::is_any_of;
|
|||||||
|
|
||||||
#include "cib.h"
|
#include "cib.h"
|
||||||
|
|
||||||
|
#include "api.h"
|
||||||
|
|
||||||
#endif /* I2ICINGA_H */
|
#endif /* I2ICINGA_H */
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="api.cpp" />
|
||||||
<ClCompile Include="checkresultmessage.cpp" />
|
<ClCompile Include="checkresultmessage.cpp" />
|
||||||
<ClCompile Include="cib.cpp" />
|
<ClCompile Include="cib.cpp" />
|
||||||
<ClCompile Include="externalcommandprocessor.cpp" />
|
<ClCompile Include="externalcommandprocessor.cpp" />
|
||||||
@ -45,6 +46,7 @@
|
|||||||
<ClCompile Include="servicegroup.cpp" />
|
<ClCompile Include="servicegroup.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="api.h" />
|
||||||
<ClInclude Include="checkresultmessage.h" />
|
<ClInclude Include="checkresultmessage.h" />
|
||||||
<ClInclude Include="cib.h" />
|
<ClInclude Include="cib.h" />
|
||||||
<ClInclude Include="externalcommandprocessor.h" />
|
<ClInclude Include="externalcommandprocessor.h" />
|
||||||
|
@ -51,7 +51,7 @@ PythonInterpreter::~PythonInterpreter(void)
|
|||||||
PyEval_ReleaseLock();
|
PyEval_ReleaseLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PythonInterpreter::RegisterFunction(const String& name, PyObject *function)
|
void PythonInterpreter::RegisterPythonFunction(const String& name, PyObject *function)
|
||||||
{
|
{
|
||||||
SubscribeFunction(name);
|
SubscribeFunction(name);
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ void PythonInterpreter::RegisterFunction(const String& name, PyObject *function)
|
|||||||
m_Functions[name] = function;
|
m_Functions[name] = function;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PythonInterpreter::UnregisterFunction(const String& name)
|
void PythonInterpreter::UnregisterPythonFunction(const String& name)
|
||||||
{
|
{
|
||||||
UnsubscribeFunction(name);
|
UnsubscribeFunction(name);
|
||||||
|
|
||||||
|
@ -37,8 +37,8 @@ public:
|
|||||||
PythonInterpreter(const PythonLanguage::Ptr& language, const Script::Ptr& script);
|
PythonInterpreter(const PythonLanguage::Ptr& language, const Script::Ptr& script);
|
||||||
~PythonInterpreter(void);
|
~PythonInterpreter(void);
|
||||||
|
|
||||||
void RegisterFunction(const String& name, PyObject *function);
|
void RegisterPythonFunction(const String& name, PyObject *function);
|
||||||
void UnregisterFunction(const String& name);
|
void UnregisterPythonFunction(const String& name);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PythonLanguage::Ptr m_Language;
|
PythonLanguage::Ptr m_Language;
|
||||||
|
@ -37,9 +37,19 @@ PythonLanguage::PythonLanguage(void)
|
|||||||
|
|
||||||
m_MainThreadState = PyThreadState_Get();
|
m_MainThreadState = PyThreadState_Get();
|
||||||
|
|
||||||
PyThreadState_Swap(NULL);
|
m_NativeModule = Py_InitModule("ire", NULL);
|
||||||
|
|
||||||
|
(void) PyThreadState_Swap(NULL);
|
||||||
PyEval_ReleaseLock();
|
PyEval_ReleaseLock();
|
||||||
|
|
||||||
|
String name;
|
||||||
|
ScriptFunction::Ptr function;
|
||||||
|
BOOST_FOREACH(tie(name, function), ScriptFunction::GetFunctions()) {
|
||||||
|
RegisterNativeFunction(name, function);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptFunction::OnRegistered.connect(boost::bind(&PythonLanguage::RegisterNativeFunction, this, _1, _2));
|
||||||
|
ScriptFunction::OnUnregistered.connect(boost::bind(&PythonLanguage::UnregisterNativeFunction, this, _1));
|
||||||
}
|
}
|
||||||
|
|
||||||
PythonLanguage::~PythonLanguage(void)
|
PythonLanguage::~PythonLanguage(void)
|
||||||
@ -58,3 +68,164 @@ PyThreadState *PythonLanguage::GetMainThreadState(void) const
|
|||||||
{
|
{
|
||||||
return m_MainThreadState;
|
return m_MainThreadState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject *PythonLanguage::MarshalToPython(const Value& value, const ScriptArgumentHint& hint)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
|
||||||
|
default:
|
||||||
|
BOOST_THROW_EXCEPTION(invalid_argument("Unexpected variant type."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Value PythonLanguage::MarshalFromPython(PyObject *value, const ScriptArgumentHint& hint)
|
||||||
|
{
|
||||||
|
if (value == Py_None) {
|
||||||
|
return Empty;
|
||||||
|
} else if (PyTuple_Check(value)) {
|
||||||
|
// TODO: look up object
|
||||||
|
} else if (PyFloat_Check(value)) {
|
||||||
|
return PyFloat_AsDouble(value);
|
||||||
|
} else if (PyString_Check(value)) {
|
||||||
|
return PyString_AsString(value);
|
||||||
|
} else {
|
||||||
|
return Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *PythonLanguage::CallNativeFunction(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
assert(PyString_Check(self));
|
||||||
|
|
||||||
|
char *name = PyString_AsString(self);
|
||||||
|
|
||||||
|
ScriptFunction::Ptr function = ScriptFunction::GetByName(name);
|
||||||
|
|
||||||
|
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, function->GetArgumentHint(i)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
arguments.push_back(MarshalFromPython(args, function->GetArgumentHint(0)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptTask::Ptr task = boost::make_shared<ScriptTask>(function, arguments);
|
||||||
|
task->Start();
|
||||||
|
task->Wait();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Value result = task->GetResult();
|
||||||
|
|
||||||
|
return MarshalToPython(result, function->GetReturnHint());
|
||||||
|
} catch (const std::exception& ex) {
|
||||||
|
String message = diagnostic_information(ex);
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, message.CStr());
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a native function.
|
||||||
|
*
|
||||||
|
* @param name The name of the native function.
|
||||||
|
* @param function The function.
|
||||||
|
*/
|
||||||
|
void PythonLanguage::RegisterNativeFunction(const String& name, const ScriptFunction::Ptr& function)
|
||||||
|
{
|
||||||
|
(void) PyThreadState_Swap(m_MainThreadState);
|
||||||
|
|
||||||
|
PyObject *pname = PyString_FromString(name.CStr());
|
||||||
|
|
||||||
|
PyMethodDef *md = new PyMethodDef;
|
||||||
|
md->ml_name = strdup(name.CStr());
|
||||||
|
md->ml_meth = &PythonLanguage::CallNativeFunction;
|
||||||
|
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(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters a native function.
|
||||||
|
*
|
||||||
|
* @param name The name of the native function.
|
||||||
|
*/
|
||||||
|
void PythonLanguage::UnregisterNativeFunction(const String& name)
|
||||||
|
{
|
||||||
|
(void) 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(NULL);
|
||||||
|
}
|
||||||
|
@ -40,8 +40,18 @@ public:
|
|||||||
virtual ScriptInterpreter::Ptr CreateInterpreter(const Script::Ptr& script);
|
virtual ScriptInterpreter::Ptr CreateInterpreter(const Script::Ptr& script);
|
||||||
|
|
||||||
PyThreadState *GetMainThreadState(void) const;
|
PyThreadState *GetMainThreadState(void) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PyThreadState *m_MainThreadState;
|
PyThreadState *m_MainThreadState;
|
||||||
|
PyObject *m_NativeModule;
|
||||||
|
|
||||||
|
void RegisterNativeFunction(const String& name, const ScriptFunction::Ptr& function);
|
||||||
|
void UnregisterNativeFunction(const String& name);
|
||||||
|
|
||||||
|
static PyObject *CallNativeFunction(PyObject *self, PyObject *args);
|
||||||
|
|
||||||
|
static PyObject *MarshalToPython(const Value& value, const ScriptArgumentHint& hint);
|
||||||
|
static Value MarshalFromPython(PyObject *value, const ScriptArgumentHint& hint);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user