]> granicus.if.org Git - icinga2/commitdiff
Config Sync: Properly modify attributes and object version
authorMichael Friedrich <michael.friedrich@netways.de>
Fri, 11 Sep 2015 12:09:46 +0000 (14:09 +0200)
committerMichael Friedrich <michael.friedrich@netways.de>
Thu, 17 Sep 2015 12:20:44 +0000 (14:20 +0200)
refs #9927

lib/base/configobject.cpp
lib/base/configobject.hpp
lib/remote/apilistener-configsync.cpp
lib/remote/apilistener.cpp

index 8713360682542035f6e35042d85ac498cc8f945c..58e279eaa6d2b75e7943af6740f89795f28a8ae0 100644 (file)
@@ -115,7 +115,7 @@ public:
        }
 };
 
-void ConfigObject::ModifyAttribute(const String& attr, const Value& value)
+void ConfigObject::ModifyAttribute(const String& attr, const Value& value, bool updateVersion)
 {
        Dictionary::Ptr original_attributes = GetOriginalAttributes();
        bool updated_original_attributes = false;
@@ -184,7 +184,9 @@ void ConfigObject::ModifyAttribute(const String& attr, const Value& value)
        ValidateField(fid, newValue, utils);
 
        SetField(fid, newValue);
-       SetVersion(GetVersion() + 1);
+
+       if (updateVersion)
+               SetVersion(GetVersion() + 1);
 
        if (updated_original_attributes)
                NotifyOriginalAttributes();
index fae5e0520ed9fa1c454ba15a46e75c8cbaacaddf..e8b7eae18a2bdec47e294f70877ca558823a838e 100644 (file)
@@ -53,7 +53,7 @@ public:
        Value GetExtension(const String& key);
        void ClearExtension(const String& key);
 
-       void ModifyAttribute(const String& attr, const Value& value);
+       void ModifyAttribute(const String& attr, const Value& value, bool updateVersion = true);
        void RestoreAttribute(const String& attr);
        bool IsAttributeModified(const String& attr) const;
 
index 62c9ff52d02912c89e59a90981c5905bc52de8d5..f244938ae4917bb64c3740a8d6b4c279a2376440 100644 (file)
@@ -23,6 +23,7 @@
 #include "remote/jsonrpc.hpp"
 #include "base/configtype.hpp"
 #include "base/json.hpp"
+#include "base/convert.hpp"
 #include <fstream>
 
 using namespace icinga;
@@ -85,51 +86,66 @@ Value ApiListener::ConfigUpdateObjectAPIHandler(const MessageOrigin::Ptr& origin
        }
 
        /* update the object */
-       ConfigType::Ptr dtype = ConfigType::GetByName(params->Get("type"));
+       String objType = params->Get("type");
+       String objName = params->Get("name");
+       int objVersion = Convert::ToLong(params->Get("version"));
+
+       ConfigType::Ptr dtype = ConfigType::GetByName(objType);
 
        if (!dtype) {
                Log(LogCritical, "ApiListener")
-                   << "Config type '" << params->Get("type") << "' does not exist.";
+                   << "Config type '" << objType << "' does not exist.";
                return Empty;
        }
 
-       ConfigObject::Ptr object = dtype->GetObject(params->Get("name"));
+       ConfigObject::Ptr object = dtype->GetObject(objName);
 
        if (!object) {
+               /* object does not exist, create it through the API */
                Array::Ptr errors = new Array();
-               if (!ConfigObjectUtility::CreateObject(Type::GetByName(params->Get("type")),
-                   params->Get("name"), params->Get("config"), errors)) {
-                       Log(LogCritical, "ApiListener", "Could not create object:");
+               if (!ConfigObjectUtility::CreateObject(Type::GetByName(objType),
+                   objName, params->Get("config"), errors)) {
+                       Log(LogCritical, "ApiListener")
+                           << "Could not create object '" << objName << "':";
 
                        ObjectLock olock(errors);
                        BOOST_FOREACH(const String& error, errors) {
                                Log(LogCritical, "ApiListener", error);
                        }
+               } else {
+                       /* object was created, update its version to its origin */
+                       ConfigObject::Ptr newObj = dtype->GetObject(objName);
+                       if (newObj)
+                               newObj->SetVersion(objVersion);
                }
-
-               //TODO-MA: modified attributes, same version
        } else {
                /* object exists, update its attributes if version was changed */
-               if (params->Get("version") > object->GetVersion()) {
+               if (objVersion > object->GetVersion()) {
                        Log(LogInformation, "ApiListener")
                            << "Processing config update for object '" << object->GetName()
-                           << "': Object version '" << object->GetVersion()
-                           << "' is older than the received version '" << params->Get("version") << "'.";
+                           << "': Object version " << object->GetVersion()
+                           << " is older than the received version " << objVersion << ".";
 
                        Dictionary::Ptr modified_attributes = params->Get("modified_attributes");
 
                        if (modified_attributes) {
                                ObjectLock olock(modified_attributes);
                                BOOST_FOREACH(const Dictionary::Pair& kv, modified_attributes) {
-                                       int fid = object->GetReflectionType()->GetFieldId(kv.first);
-                                       static_cast<Object::Ptr>(object)->SetField(fid, kv.second, false, origin);
+                                       /* update all modified attributes
+                                        * but do not update the object version yet.
+                                        * This triggers cluster events otherwise.
+                                        */
+                                       object->ModifyAttribute(kv.first, kv.second, false);
                                }
                        }
+
+                       /* keep the object version in sync with the sender */
+                       object->SetVersion(objVersion);
                } else {
                        Log(LogWarning, "ApiListener")
-                           << "Skipping config update for object '" << object->GetName()
-                           << "': Object version '" << object->GetVersion()
-                           << "' is more recent than the received version '" << params->Get("version") << "'.";
+                           << "Discarding config update for object '" << object->GetName()
+                           << "': Object version " << object->GetVersion()
+                           << " is more recent than the received version " << objVersion << ".";
                        return Empty;
                }
        }
index cb1b6c3f1c092d94d3f053c0a88f98ef11bad2e5..78db2575640653cc3b7580cc3730a4aef7b1a6a8 100644 (file)
@@ -807,6 +807,11 @@ void ApiListener::ReplayLog(const JsonRpcConnection::Ptr& client)
                        logStream->Close();
                }
 
+               if (count > 0) {
+                       Log(LogInformation, "ApiListener")
+                          << "Replayed " << count << " messages.";
+               }
+
                Log(LogNotice, "ApiListener")
                   << "Replayed " << count << " messages.";