]> granicus.if.org Git - icinga2/commitdiff
Implement support for persisting modified attributes
authorGunnar Beutner <gunnar@beutner.name>
Wed, 12 Aug 2015 07:52:29 +0000 (09:52 +0200)
committerGunnar Beutner <gunnar@beutner.name>
Sat, 15 Aug 2015 18:07:10 +0000 (20:07 +0200)
fixes #9093

icinga-app/icinga.cpp
lib/base/application.cpp
lib/base/application.hpp
lib/base/dynamicobject.cpp
lib/base/dynamicobject.hpp
lib/icinga/icingaapplication.cpp

index 9810d3a7cd99b30ccd642a2e2c34748d7bf3e0d1..12601381ee321c8c64c5d796b306ba8d3e6bd547 100644 (file)
@@ -263,6 +263,7 @@ int Main(void)
        }
 
        Application::DeclareStatePath(Application::GetLocalStateDir() + "/lib/icinga2/icinga2.state");
+       Application::DeclareModAttrPath(Application::GetLocalStateDir() + "/lib/icinga2/modified-attributes.conf");
        Application::DeclareObjectsPath(Application::GetLocalStateDir() + "/cache/icinga2/icinga2.debug");
        Application::DeclareVarsPath(Application::GetLocalStateDir() + "/cache/icinga2/icinga2.vars");
        Application::DeclarePidPath(Application::GetRunDir() + "/icinga2/icinga2.pid");
index 785ed6333c74d435114c4fb2b96493bfd3eeefdc..9a42f6989e387e03e53dbe48a453bcb1fce07044 100644 (file)
@@ -600,6 +600,7 @@ void Application::DisplayInfoMessage(std::ostream& os, bool skipVersion)
           << "  Local state directory: " << GetLocalStateDir() << "\n"
           << "  Package data directory: " << GetPkgDataDir() << "\n"
           << "  State path: " << GetStatePath() << "\n"
+          << "  Modified attributes path: " << GetModAttrPath() << "\n"
           << "  Objects path: " << GetObjectsPath() << "\n"
           << "  Vars path: " << GetVarsPath() << "\n"
           << "  PID path: " << GetPidPath() << "\n";
@@ -1281,6 +1282,27 @@ void Application::DeclareStatePath(const String& path)
                ScriptGlobal::Set("StatePath", path);
 }
 
+/**
+ * Retrieves the path for the modified attributes file.
+ *
+ * @returns The path.
+ */
+String Application::GetModAttrPath(void)
+{
+       return ScriptGlobal::Get("ModAttrPath", &Empty);
+}
+
+/**
+ * Sets the path for the modified attributes file.
+ *
+ * @param path The new path.
+ */
+void Application::DeclareModAttrPath(const String& path)
+{
+       if (!ScriptGlobal::Exists("ModAttrPath"))
+               ScriptGlobal::Set("ModAttrPath", path);
+}
+
 /**
  * Retrieves the path for the objects file.
  *
index a874db9c0f5f61e14bbab5d698edadd197a9bb0a..47b1c291562cb76a8410d15d3aeb3ca6c99c4c9b 100644 (file)
@@ -106,6 +106,9 @@ public:
        static String GetStatePath(void);
        static void DeclareStatePath(const String& path);
 
+       static String GetModAttrPath(void);
+       static void DeclareModAttrPath(const String& path);
+
        static String GetObjectsPath(void);
        static void DeclareObjectsPath(const String& path);
 
index 9a7c2ca29e48681635f757c8e3bab5cde6d7d71d..5f09b1140b8acb63ae1a8c37ceb0ce51f50989e2 100644 (file)
@@ -404,6 +404,27 @@ void DynamicObject::StopObjects(void)
        }
 }
 
+void DynamicObject::DumpModifiedAttributes(const boost::function<void(const DynamicObject::Ptr&, const String&, const Value&)>& callback)
+{
+       BOOST_FOREACH(const DynamicType::Ptr& dt, DynamicType::GetTypes()) {
+               BOOST_FOREACH(const DynamicObject::Ptr& object, dt->GetObjects()) {
+                       Dictionary::Ptr originalAttributes = object->GetOriginalAttributes();
+
+                       if (!originalAttributes)
+                               continue;
+
+                       ObjectLock olock(originalAttributes);
+                       BOOST_FOREACH(const Dictionary::Pair& kv, originalAttributes) {
+                               // TODO-MA: vars.os
+                               int fid = object->GetReflectionType()->GetFieldId(kv.first);
+                               Value value = object->GetField(fid);
+                               callback(object, kv.first, value);
+                       }
+               }
+       }
+
+}
+
 DynamicObject::Ptr DynamicObject::GetObject(const String& type, const String& name)
 {
        DynamicType::Ptr dtype = DynamicType::GetByName(type);
index 0d7e78be6c57d4527fc5e382c546bd5dd22361ec..1a60e0f3d71dd66d0514d4635d74b7a17e77f971 100644 (file)
@@ -86,6 +86,8 @@ public:
        static void RestoreObjects(const String& filename, int attributeTypes = FAState);
        static void StopObjects(void);
 
+       static void DumpModifiedAttributes(const boost::function<void(const DynamicObject::Ptr&, const String&, const Value&)>& callback);
+
        static Object::Ptr GetPrototype(void);
 
 protected:
index ef48b092e9874fd76321b296e53e7eb4cd91975d..1b811c607602d21749d293241e3d668212eae8f7 100644 (file)
@@ -20,6 +20,7 @@
 #include "icinga/icingaapplication.hpp"
 #include "icinga/icingaapplication.tcpp"
 #include "icinga/cib.hpp"
+#include "config/configwriter.cpp"
 #include "base/dynamictype.hpp"
 #include "base/logger.hpp"
 #include "base/objectlock.hpp"
@@ -102,6 +103,18 @@ int IcingaApplication::Main(void)
        l_RetentionTimer->OnTimerExpired.connect(boost::bind(&IcingaApplication::DumpProgramState, this));
        l_RetentionTimer->Start();
 
+       /* restore modified attributes */
+       Expression *expression = ConfigCompiler::CompileFile(GetModAttrPath());
+
+       if (expression) {
+               try {
+                       ScriptFrame frame;
+                       expression->Evaluate(frame);
+               } catch (const std::exception& ex) {
+                       Log(LogCritical, "config", DiagnosticInformation(ex));
+               }
+       }
+
        RunEventLoop();
 
        Log(LogInformation, "IcingaApplication", "Icinga has shut down.");
@@ -121,9 +134,43 @@ void IcingaApplication::OnShutdown(void)
        DumpProgramState();
 }
 
+static void PersistModAttrHelper(const ConfigWriter::Ptr& cw, DynamicObject::Ptr& previousObject, const DynamicObject::Ptr& object, const String& attr, const Value& value)
+{
+       if (object != previousObject) {
+               if (previousObject)
+                       cw->EmitRaw("}\n\n");
+
+               cw->EmitRaw("var obj = get_object(");
+               cw->EmitIdentifier(object->GetReflectionType()->GetName(), 0);
+               cw->EmitRaw(", ");
+               cw->EmitString(object->GetName());
+               cw->EmitRaw(")\n");
+
+               cw->EmitRaw("if (obj) {\n");
+       }
+
+       cw->EmitRaw("\tobj.");
+
+       Array::Ptr args2 = new Array();
+       args2->Add(attr);
+       args2->Add(value);
+       cw->EmitFunctionCall("modify_attribute", args2);
+
+       cw->EmitRaw("\n");
+
+       previousObject = object;
+}
+
 void IcingaApplication::DumpProgramState(void)
 {
        DynamicObject::DumpObjects(GetStatePath());
+
+       ConfigWriter::Ptr cw = new ConfigWriter(GetModAttrPath());
+       DynamicObject::Ptr previousObject;
+       DynamicObject::DumpModifiedAttributes(boost::bind(&PersistModAttrHelper, cw, boost::ref(previousObject), _1, _2, _3));
+
+       if (previousObject)
+               cw->EmitRaw("\n}\n");
 }
 
 IcingaApplication::Ptr IcingaApplication::GetInstance(void)