]> granicus.if.org Git - icinga2/commitdiff
Implement support for signals
authorGunnar Beutner <gunnar@beutner.name>
Thu, 20 Nov 2014 05:53:57 +0000 (06:53 +0100)
committerGunnar Beutner <gunnar@beutner.name>
Thu, 20 Nov 2014 05:54:48 +0000 (06:54 +0100)
fixes #7744

lib/base/CMakeLists.txt
lib/base/scriptsignal.cpp [new file with mode: 0644]
lib/base/scriptsignal.hpp [new file with mode: 0644]
lib/base/scriptutils.cpp
lib/base/scriptutils.hpp
lib/cli/daemoncommand.cpp
lib/config/config_lexer.ll
lib/config/config_parser.yy
lib/config/expression.cpp
lib/config/expression.hpp

index 293dea4523499da9ef8b2d7f0d761dc69c43d3d1..b8bc72888b41e736c30cf698fb3846b366f64ea6 100644 (file)
@@ -27,7 +27,7 @@ set(base_SOURCES
   convert.cpp debuginfo.cpp dictionary.cpp dynamicobject.cpp dynamicobject.thpp dynamictype.cpp
   exception.cpp fifo.cpp filelogger.cpp filelogger.thpp initialize.cpp json.cpp logger.cpp logger.thpp
   netstring.cpp networkstream.cpp object.cpp primitivetype.cpp process.cpp
-  ringbuffer.cpp scriptfunction.cpp scriptfunctionwrapper.cpp
+  ringbuffer.cpp scriptfunction.cpp scriptfunctionwrapper.cpp scriptsignal.cpp
   scriptutils.cpp scriptvariable.cpp serializer.cpp socket.cpp stacktrace.cpp
   statsfunction.cpp stdiostream.cpp stream.cpp streamlogger.cpp streamlogger.thpp string.cpp 
   sysloglogger.cpp sysloglogger.thpp tcpsocket.cpp thinmutex.cpp threadpool.cpp timer.cpp
diff --git a/lib/base/scriptsignal.cpp b/lib/base/scriptsignal.cpp
new file mode 100644 (file)
index 0000000..4c64ccb
--- /dev/null
@@ -0,0 +1,56 @@
+/******************************************************************************
+ * 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/scriptsignal.hpp"
+#include "base/scriptvariable.hpp"
+
+using namespace icinga;
+
+void ScriptSignal::AddSlot(const Callback& slot)
+{
+       m_Slots.push_back(slot);
+}
+
+Value ScriptSignal::Invoke(const std::vector<Value>& arguments)
+{
+       BOOST_FOREACH(const Callback& slot, m_Slots)
+               slot(arguments);
+}
+
+ScriptSignal::Ptr ScriptSignal::GetByName(const String& name)
+{
+       ScriptVariable::Ptr sv = ScriptVariable::GetByName(name);
+
+       if (!sv)
+               return ScriptSignal::Ptr();
+
+       return sv->GetData();
+}
+
+void ScriptSignal::Register(const String& name, const ScriptSignal::Ptr& function)
+{
+       ScriptVariable::Ptr sv = ScriptVariable::Set(name, function);
+       sv->SetConstant(true);
+}
+
+void ScriptSignal::Unregister(const String& name)
+{
+       ScriptVariable::Unregister(name);
+}
+
diff --git a/lib/base/scriptsignal.hpp b/lib/base/scriptsignal.hpp
new file mode 100644 (file)
index 0000000..15f434d
--- /dev/null
@@ -0,0 +1,65 @@
+/******************************************************************************
+ * 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 SCRIPTSIGNAL_H
+#define SCRIPTSIGNAL_H
+
+#include "base/i2-base.hpp"
+#include "base/value.hpp"
+#include <vector>
+#include <boost/function.hpp>
+
+namespace icinga
+{
+
+/**
+ * A signal that can be subscribed to by scripts.
+ *
+ * @ingroup base
+ */
+class I2_BASE_API ScriptSignal : public Object
+{
+public:
+       DECLARE_PTR_TYPEDEFS(ScriptSignal);
+
+       typedef boost::function<void (const std::vector<Value>& arguments)> Callback;
+
+       void AddSlot(const Callback& slot);
+       Value Invoke(const std::vector<Value>& arguments = std::vector<Value>());
+
+       static ScriptSignal::Ptr GetByName(const String& name);
+       static void Register(const String& name, const ScriptSignal::Ptr& signal);
+       static void Unregister(const String& name);
+
+private:
+       std::vector<Callback> m_Slots;
+};
+
+#define REGISTER_SCRIPTSIGNAL(name) \
+       namespace { namespace UNIQUE_NAME(sig) { namespace sig ## name { \
+               void RegisterSignal(void) { \
+                       ScriptSignal::Ptr sig = new icinga::ScriptSignal(); \
+                       ScriptSignal::Register(#name, sig); \
+               } \
+               INITIALIZE_ONCE(RegisterSignal); \
+       } } }
+
+}
+
+#endif /* SCRIPTSIGNAL_H */
index 3cbbd55a7ed2980ea687dcf79a896449ae0848e7..3a7f9732ff073f9331a4616de77acd0f71f561be 100644 (file)
@@ -26,6 +26,7 @@
 #include "base/objectlock.hpp"
 #include "base/dynamictype.hpp"
 #include "base/application.hpp"
+#include "base/configerror.hpp"
 #include <boost/foreach.hpp>
 #include <boost/regex.hpp>
 #include <algorithm>
@@ -45,6 +46,7 @@ REGISTER_SCRIPTFUNCTION(typeof, &ScriptUtils::TypeOf);
 REGISTER_SCRIPTFUNCTION(keys, &ScriptUtils::Keys);
 REGISTER_SCRIPTFUNCTION(random, &Utility::Random);
 REGISTER_SCRIPTFUNCTION(__get_object, &ScriptUtils::GetObject);
+REGISTER_SCRIPTFUNCTION(assert, &ScriptUtils::Assert);
 
 bool ScriptUtils::Regex(const String& pattern, const String& text)
 {
@@ -218,3 +220,9 @@ DynamicObject::Ptr ScriptUtils::GetObject(const String& type, const String& name
        return dtype->GetObject(name);
 }
 
+void ScriptUtils::Assert(const Value& arg)
+{
+       if (!arg.ToBool())
+               BOOST_THROW_EXCEPTION(ConfigError("Assertion failed"));
+}
+
index 2dc01c03117d09bbbaceafb52673ecd1dad30ac2..a119d426960ce879644867f768fca9502676424c 100644 (file)
@@ -45,6 +45,7 @@ public:
        static Type::Ptr TypeOf(const Value& value);
        static Array::Ptr Keys(const Dictionary::Ptr& dict);
        static DynamicObject::Ptr GetObject(const String& type, const String& name);
+       static void Assert(const Value& arg);
 
 private:
        ScriptUtils(void);
index c2aed84fa8f2a0f1ade21b7bf74bea660c8e7a5e..a62e1fb864f69d5d32b8e0bd8d2cc3535674e966 100644 (file)
@@ -30,6 +30,7 @@
 #include "base/convert.hpp"
 #include "base/scriptvariable.hpp"
 #include "base/context.hpp"
+#include "base/scriptsignal.hpp"
 #include "config.h"
 #include <boost/program_options.hpp>
 #include <boost/tuple/tuple.hpp>
@@ -42,6 +43,7 @@ namespace po = boost::program_options;
 static po::variables_map g_AppParams;
 
 REGISTER_CLICOMMAND("daemon", DaemonCommand);
+REGISTER_SCRIPTSIGNAL(onload);
 
 static String LoadAppType(const String& typeSpec)
 {
@@ -156,6 +158,9 @@ static bool LoadConfigFiles(const boost::program_options::variables_map& vm, con
 
        ScriptVariable::WriteVariablesFile(varsfile);
 
+       ScriptSignal::Ptr loadSignal = ScriptSignal::GetByName("onload");
+       loadSignal->Invoke();
+
        return true;
 }
 
index 81777bff8179f4bf7328f9957be5e58aacc86cdf..64cf56fdb47c06402b9464db2c402a6ba4b1f8c7 100644 (file)
@@ -248,6 +248,7 @@ for                         return T_APPLY_FOR;
 __function                     return T_FUNCTION;
 __return                       return T_RETURN;
 __for                          return T_FOR;
+__signal                       return T_SIGNAL;
 =\>                            return T_FOLLOWS;
 \<\<                           return T_SHIFT_LEFT;
 \>\>                           return T_SHIFT_RIGHT;
index 90f206a6a222216a06c4bd3ea48ef2efa2aa737e..54744819eeb432e318014bc81ec751c68f6dcc2a 100644 (file)
@@ -160,6 +160,7 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig
 %token T_FUNCTION "function (T_FUNCTION)"
 %token T_RETURN "return (T_RETURN)"
 %token T_FOR "for (T_FOR)"
+%token T_SIGNAL "signal (T_SIGNAL)"
 %token T_FOLLOWS "=> (T_FOLLOWS)"
 
 %type <text> identifier
@@ -802,6 +803,11 @@ rterm: T_STRING
                $$ = new FunctionExpression("", *$3, aexpr, DebugInfoRange(@1, @5));
                delete $3;
        }
+       | T_SIGNAL identifier T_SET_ADD rterm
+       {
+               $$ = new SlotExpression($2, $4, DebugInfoRange(@1, @4));
+               free($2);
+       }
        | T_FOR '(' identifier T_FOLLOWS identifier T_IN rterm ')' rterm_scope
        {
                $$ = new ForExpression($3, $5, $7, $9, DebugInfoRange(@1, @9));
index 13c587ec3f2764203a83d7a770807f22cb67c09e..f37e353f646579065ebba56e99a83cb07edf5e07 100644 (file)
@@ -26,6 +26,7 @@
 #include "base/json.hpp"
 #include "base/scriptfunction.hpp"
 #include "base/scriptvariable.hpp"
+#include "base/scriptsignal.hpp"
 #include "base/utility.hpp"
 #include "base/objectlock.hpp"
 #include "base/object.hpp"
@@ -427,6 +428,33 @@ Value FunctionExpression::DoEvaluate(const Object::Ptr& context, DebugHint *dhin
        return func;
 }
 
+static void InvokeSlot(const Value& funcName, const std::vector<Value>& arguments)
+{
+       ScriptFunction::Ptr func;
+
+       if (funcName.IsObjectType<ScriptFunction>())
+               func = funcName;
+       else
+               func = ScriptFunction::GetByName(funcName);
+
+       if (!func)
+               BOOST_THROW_EXCEPTION(ConfigError("Function '" + funcName + "' does not exist."));
+
+       func->Invoke(arguments);
+}
+
+Value SlotExpression::DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const
+{
+       ScriptSignal::Ptr sig = ScriptSignal::GetByName(m_Signal);
+
+       if (!sig)
+               BOOST_THROW_EXCEPTION(ConfigError("Signal '" + m_Signal + "' does not exist."));
+
+       sig->AddSlot(boost::bind(InvokeSlot, m_Slot->Evaluate(context), _1));
+
+       return Empty;
+}
+
 Value ApplyExpression::DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const
 {
        String name = m_Name->Evaluate(context, dhint);
index 9c2b6fb56fff350577becaa3349c45daef19910b..1411b070db283ffac0d1de6cede922bb35f8d6b7 100644 (file)
@@ -581,6 +581,21 @@ private:
        boost::shared_ptr<Expression> m_Expression;
 };
 
+class I2_CONFIG_API SlotExpression : public DebuggableExpression
+{
+public:
+       SlotExpression(const String& signal, Expression *slot, const DebugInfo& debugInfo = DebugInfo())
+               : DebuggableExpression(debugInfo), m_Signal(signal), m_Slot(slot)
+       { }
+
+protected:
+       virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+
+private:
+       String m_Signal;
+       Expression *m_Slot;
+};
+
 class I2_CONFIG_API ApplyExpression : public DebuggableExpression
 {
 public: