From 2e944b18b3614130bc5745a52e2b4831e16a5668 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Thu, 22 Apr 2021 16:30:00 +0200 Subject: [PATCH 1/6] Introduce ConfigObject#GetAttribute() refs #8717 --- lib/base/configobject.cpp | 28 ++++++++++++++++++++++++++++ lib/base/configobject.hpp | 1 + 2 files changed, 29 insertions(+) diff --git a/lib/base/configobject.cpp b/lib/base/configobject.cpp index 81ea917b66c..c2cc6f15bd1 100644 --- a/lib/base/configobject.cpp +++ b/lib/base/configobject.cpp @@ -87,6 +87,34 @@ class ModAttrValidationUtils final : public ValidationUtils } }; +bool ConfigObject::GetAttribute(const String& attr, Value *result) +{ + std::vector tokens = attr.Split("."); + auto current (tokens.begin()); + auto end (tokens.end()); + Object::Ptr subTree (this); + Value branch; + + for (;;) { + if (!subTree->GetOwnField(*current, &branch)) { + return false; + } + + if (++current == end) { + break; + } + + if (!branch.IsObject()) { + return false; + } + + subTree = branch.Get(); + } + + *result = std::move(branch); + return true; +} + void ConfigObject::ModifyAttribute(const String& attr, const Value& value, bool updateVersion) { Dictionary::Ptr original_attributes = GetOriginalAttributes(); diff --git a/lib/base/configobject.hpp b/lib/base/configobject.hpp index 5596363703c..8ecf2e001d4 100644 --- a/lib/base/configobject.hpp +++ b/lib/base/configobject.hpp @@ -36,6 +36,7 @@ class ConfigObject : public ObjectImpl ConfigObject::Ptr GetZone() const; + bool GetAttribute(const String& attr, Value *result); void ModifyAttribute(const String& attr, const Value& value, bool updateVersion = true); void RestoreAttribute(const String& attr, bool updateVersion = true); bool IsAttributeModified(const String& attr) const; From 89f782f5f7493fc5a8398b2620de03e6e7a69e43 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Thu, 22 Apr 2021 16:53:53 +0200 Subject: [PATCH 2/6] Introduce ConfigObject#get_attribute() refs #8717 --- lib/base/configobject-script.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/base/configobject-script.cpp b/lib/base/configobject-script.cpp index 46a9ca27cac..e5d2399401e 100644 --- a/lib/base/configobject-script.cpp +++ b/lib/base/configobject-script.cpp @@ -4,10 +4,28 @@ #include "base/dictionary.hpp" #include "base/function.hpp" #include "base/functionwrapper.hpp" +#include "base/reference.hpp" #include "base/scriptframe.hpp" using namespace icinga; +static bool ConfigObjectGetAttribute(const String& attr, const Reference::Ptr& result) +{ + ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); + ConfigObject::Ptr self = vframe->Self; + + REQUIRE_NOT_NULL(self); + + Value temp; + bool ok = self->GetAttribute(attr, &temp); + + if (ok && result) { + result->Set(temp); + } + + return ok; +} + static void ConfigObjectModifyAttribute(const String& attr, const Value& value) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); @@ -27,6 +45,7 @@ static void ConfigObjectRestoreAttribute(const String& attr) Object::Ptr ConfigObject::GetPrototype() { static Dictionary::Ptr prototype = new Dictionary({ + { "get_attribute", new Function("ConfigObject#get_attribute", ConfigObjectGetAttribute, { "attr", "result" }, false) }, { "modify_attribute", new Function("ConfigObject#modify_attribute", ConfigObjectModifyAttribute, { "attr", "value" }, false) }, { "restore_attribute", new Function("ConfigObject#restore_attribute", ConfigObjectRestoreAttribute, { "attr", "value" }, false) } }); From a94efb533853eb4ed54603c2f0e4f4ddab00e8ba Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Thu, 22 Apr 2021 17:09:48 +0200 Subject: [PATCH 3/6] Introduce Internal.serialize() refs #8717 --- lib/base/CMakeLists.txt | 2 +- lib/base/serializer-script.cpp | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 lib/base/serializer-script.cpp diff --git a/lib/base/CMakeLists.txt b/lib/base/CMakeLists.txt index 9707d293593..d22000a922b 100644 --- a/lib/base/CMakeLists.txt +++ b/lib/base/CMakeLists.txt @@ -59,7 +59,7 @@ set(base_SOURCES scriptframe.cpp scriptframe.hpp scriptglobal.cpp scriptglobal.hpp scriptutils.cpp scriptutils.hpp - serializer.cpp serializer.hpp + serializer.cpp serializer.hpp serializer-script.cpp shared.hpp shared-object.hpp singleton.hpp diff --git a/lib/base/serializer-script.cpp b/lib/base/serializer-script.cpp new file mode 100644 index 00000000000..38c0f838066 --- /dev/null +++ b/lib/base/serializer-script.cpp @@ -0,0 +1,8 @@ +/* Icinga 2 | (c) 2021 Icinga GmbH | GPLv2+ */ + +#include "base/function.hpp" +#include "base/serializer.hpp" + +using namespace icinga; + +REGISTER_FUNCTION(Internal, serialize, &Serialize, "value:attribute_types"); From 95be500693df1f6db99d72428b9c058da757f7fa Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Wed, 21 Apr 2021 16:12:54 +0200 Subject: [PATCH 4/6] ConfigObject::DumpModifiedAttributes(): pass original value to callback as well refs #8717 --- lib/base/configobject.cpp | 4 ++-- lib/base/configobject.hpp | 2 +- lib/icinga/icingaapplication.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/base/configobject.cpp b/lib/base/configobject.cpp index c2cc6f15bd1..d3d237583b9 100644 --- a/lib/base/configobject.cpp +++ b/lib/base/configobject.cpp @@ -649,7 +649,7 @@ void ConfigObject::StopObjects() } } -void ConfigObject::DumpModifiedAttributes(const std::function& callback) +void ConfigObject::DumpModifiedAttributes(const std::function& callback) { for (const Type::Ptr& type : Type::GetAllTypes()) { auto *dtype = dynamic_cast(type.get()); @@ -703,7 +703,7 @@ void ConfigObject::DumpModifiedAttributes(const std::function static void RestoreObjects(const String& filename, int attributeTypes = FAState); static void StopObjects(); - static void DumpModifiedAttributes(const std::function& callback); + static void DumpModifiedAttributes(const std::function& callback); static Object::Ptr GetPrototype(); diff --git a/lib/icinga/icingaapplication.cpp b/lib/icinga/icingaapplication.cpp index 1ff303dcb6c..373a4d1ea97 100644 --- a/lib/icinga/icingaapplication.cpp +++ b/lib/icinga/icingaapplication.cpp @@ -175,7 +175,7 @@ void IcingaApplication::DumpModifiedAttributes() fp.exceptions(std::ofstream::failbit | std::ofstream::badbit); ConfigObject::Ptr previousObject; - ConfigObject::DumpModifiedAttributes([&fp, &previousObject](const ConfigObject::Ptr& object, const String& attr, const Value& value) { + ConfigObject::DumpModifiedAttributes([&fp, &previousObject](const ConfigObject::Ptr& object, const String& attr, const Value&, const Value& value) { PersistModAttrHelper(fp, previousObject, object, attr, value); }); From 09244bc57225fde167f7da2e47c580080cae4a30 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Wed, 21 Apr 2021 16:15:27 +0200 Subject: [PATCH 5/6] IcingaApplication::DumpModifiedAttributes(): pass original value to PersistModAttrHelper() as well refs #8717 --- lib/icinga/icingaapplication.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/icinga/icingaapplication.cpp b/lib/icinga/icingaapplication.cpp index 373a4d1ea97..561c5327f08 100644 --- a/lib/icinga/icingaapplication.cpp +++ b/lib/icinga/icingaapplication.cpp @@ -121,7 +121,7 @@ void IcingaApplication::OnShutdown() DumpProgramState(); } -static void PersistModAttrHelper(std::fstream& fp, ConfigObject::Ptr& previousObject, const ConfigObject::Ptr& object, const String& attr, const Value& value) +static void PersistModAttrHelper(std::fstream& fp, ConfigObject::Ptr& previousObject, const ConfigObject::Ptr& object, const String& attr, const Value& original, const Value& modified) { if (object != previousObject) { if (previousObject) { @@ -145,7 +145,7 @@ static void PersistModAttrHelper(std::fstream& fp, ConfigObject::Ptr& previousOb Array::Ptr args2 = new Array({ attr, - value + modified }); ConfigWriter::EmitFunctionCall(fp, "modify_attribute", args2); @@ -175,8 +175,8 @@ void IcingaApplication::DumpModifiedAttributes() fp.exceptions(std::ofstream::failbit | std::ofstream::badbit); ConfigObject::Ptr previousObject; - ConfigObject::DumpModifiedAttributes([&fp, &previousObject](const ConfigObject::Ptr& object, const String& attr, const Value&, const Value& value) { - PersistModAttrHelper(fp, previousObject, object, attr, value); + ConfigObject::DumpModifiedAttributes([&fp, &previousObject](const ConfigObject::Ptr& object, const String& attr, const Value& original, const Value& modified) { + PersistModAttrHelper(fp, previousObject, object, attr, original, modified); }); if (previousObject) { From 206a0fa7506ef581eb8d2c1f82e3e62f34908bc4 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Wed, 11 Aug 2021 13:42:22 +0200 Subject: [PATCH 6/6] PersistModAttrHelper(): only modify attribute if the object config didn't change refs #8717 --- lib/icinga/icingaapplication.cpp | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/lib/icinga/icingaapplication.cpp b/lib/icinga/icingaapplication.cpp index 561c5327f08..6bff03c96a9 100644 --- a/lib/icinga/icingaapplication.cpp +++ b/lib/icinga/icingaapplication.cpp @@ -18,6 +18,8 @@ #include "base/initialize.hpp" #include "base/statsfunction.hpp" #include "base/loader.hpp" +#include "base/json.hpp" +#include "base/serializer.hpp" #include using namespace icinga; @@ -138,10 +140,29 @@ static void PersistModAttrHelper(std::fstream& fp, ConfigObject::Ptr& previousOb }); ConfigWriter::EmitFunctionCall(fp, "get_object", args1); - ConfigWriter::EmitRaw(fp, "\nif (obj) {\n"); + ConfigWriter::EmitRaw(fp, "\nif (obj) {\n\tvar result\n"); } - ConfigWriter::EmitRaw(fp, "\tobj."); + ConfigWriter::EmitRaw(fp, "\tif ("); + + if (original.GetType() == ValueEmpty) { + ConfigWriter::EmitRaw(fp, "!obj.get_attribute("); + ConfigWriter::EmitString(fp, attr); + ConfigWriter::EmitRaw(fp, ", &result) || Json.encode(Internal.serialize(result, "); + ConfigWriter::EmitNumber(fp, FAConfig); + ConfigWriter::EmitRaw(fp, ")) == "); + ConfigWriter::EmitString(fp, "null"); + } else { + ConfigWriter::EmitRaw(fp, "obj.get_attribute("); + ConfigWriter::EmitString(fp, attr); + ConfigWriter::EmitRaw(fp, ", &result) && Json.encode(Internal.serialize(result, "); + ConfigWriter::EmitNumber(fp, FAConfig); + ConfigWriter::EmitRaw(fp, ")) == Json.encode("); + ConfigWriter::EmitValue(fp, 1, Serialize(original, FAConfig)); + ConfigWriter::EmitRaw(fp, ")"); + } + + ConfigWriter::EmitRaw(fp, ") {\n\t\tobj."); Array::Ptr args2 = new Array({ attr, @@ -149,7 +170,7 @@ static void PersistModAttrHelper(std::fstream& fp, ConfigObject::Ptr& previousOb }); ConfigWriter::EmitFunctionCall(fp, "modify_attribute", args2); - ConfigWriter::EmitRaw(fp, "\n"); + ConfigWriter::EmitRaw(fp, "\n\t}\n"); previousObject = object; }