From: Gunnar Beutner Date: Wed, 12 Aug 2015 07:52:29 +0000 (+0200) Subject: Implement support for persisting modified attributes X-Git-Tag: v2.4.0~423 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a092c13acea780207d4024b34d393f0fcce4e562;p=icinga2 Implement support for persisting modified attributes fixes #9093 --- diff --git a/icinga-app/icinga.cpp b/icinga-app/icinga.cpp index 9810d3a7c..12601381e 100644 --- a/icinga-app/icinga.cpp +++ b/icinga-app/icinga.cpp @@ -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"); diff --git a/lib/base/application.cpp b/lib/base/application.cpp index 785ed6333..9a42f6989 100644 --- a/lib/base/application.cpp +++ b/lib/base/application.cpp @@ -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. * diff --git a/lib/base/application.hpp b/lib/base/application.hpp index a874db9c0..47b1c2915 100644 --- a/lib/base/application.hpp +++ b/lib/base/application.hpp @@ -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); diff --git a/lib/base/dynamicobject.cpp b/lib/base/dynamicobject.cpp index 9a7c2ca29..5f09b1140 100644 --- a/lib/base/dynamicobject.cpp +++ b/lib/base/dynamicobject.cpp @@ -404,6 +404,27 @@ void DynamicObject::StopObjects(void) } } +void DynamicObject::DumpModifiedAttributes(const boost::function& 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); diff --git a/lib/base/dynamicobject.hpp b/lib/base/dynamicobject.hpp index 0d7e78be6..1a60e0f3d 100644 --- a/lib/base/dynamicobject.hpp +++ b/lib/base/dynamicobject.hpp @@ -86,6 +86,8 @@ public: static void RestoreObjects(const String& filename, int attributeTypes = FAState); static void StopObjects(void); + static void DumpModifiedAttributes(const boost::function& callback); + static Object::Ptr GetPrototype(void); protected: diff --git a/lib/icinga/icingaapplication.cpp b/lib/icinga/icingaapplication.cpp index ef48b092e..1b811c607 100644 --- a/lib/icinga/icingaapplication.cpp +++ b/lib/icinga/icingaapplication.cpp @@ -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)