From: Michael Friedrich Date: Fri, 11 Sep 2015 12:09:46 +0000 (+0200) Subject: Config Sync: Properly modify attributes and object version X-Git-Tag: v2.4.0~317 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b2715943c6bc77a76cea9b36a494162542a7c339;p=icinga2 Config Sync: Properly modify attributes and object version refs #9927 --- diff --git a/lib/base/configobject.cpp b/lib/base/configobject.cpp index 871336068..58e279eaa 100644 --- a/lib/base/configobject.cpp +++ b/lib/base/configobject.cpp @@ -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(); diff --git a/lib/base/configobject.hpp b/lib/base/configobject.hpp index fae5e0520..e8b7eae18 100644 --- a/lib/base/configobject.hpp +++ b/lib/base/configobject.hpp @@ -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; diff --git a/lib/remote/apilistener-configsync.cpp b/lib/remote/apilistener-configsync.cpp index 62c9ff52d..f244938ae 100644 --- a/lib/remote/apilistener-configsync.cpp +++ b/lib/remote/apilistener-configsync.cpp @@ -23,6 +23,7 @@ #include "remote/jsonrpc.hpp" #include "base/configtype.hpp" #include "base/json.hpp" +#include "base/convert.hpp" #include 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)->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; } } diff --git a/lib/remote/apilistener.cpp b/lib/remote/apilistener.cpp index cb1b6c3f1..78db25756 100644 --- a/lib/remote/apilistener.cpp +++ b/lib/remote/apilistener.cpp @@ -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.";