Fix object sync for modified attributes

refs #9851
refs #9927
refs #9081
This commit is contained in:
Michael Friedrich 2015-09-29 14:21:57 +02:00
parent 487ef513cf
commit bb3b724219
1 changed files with 78 additions and 68 deletions

View File

@ -24,6 +24,10 @@
#include "base/configtype.hpp"
#include "base/json.hpp"
#include "base/convert.hpp"
#include "config/vmops.hpp"
#include <boost/foreach.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <fstream>
using namespace icinga;
@ -109,11 +113,14 @@ Value ApiListener::ConfigUpdateObjectAPIHandler(const MessageOrigin::Ptr& origin
ConfigObject::Ptr object = dtype->GetObject(objName);
if (!object) {
String config = params->Get("config");
if (!object && !config.IsEmpty()) {
/* object does not exist, create it through the API */
Array::Ptr errors = new Array();
if (!ConfigObjectUtility::CreateObject(Type::GetByName(objType),
objName, params->Get("config"), errors)) {
objName, config, errors)) {
Log(LogCritical, "ApiListener")
<< "Could not create object '" << objName << "':";
@ -121,15 +128,17 @@ Value ApiListener::ConfigUpdateObjectAPIHandler(const MessageOrigin::Ptr& origin
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);
return Empty;
}
} else {
/* object exists, update its attributes if version was changed */
if (objVersion > object->GetVersion()) {
/* object was created, update its version to its origin */
object = dtype->GetObject(objName);
object->SetVersion(objVersion, false, origin);
}
/* update object attributes if version was changed */
if (object && objVersion > object->GetVersion()) {
Log(LogInformation, "ApiListener")
<< "Processing config update for object '" << object->GetName()
<< "': Object version " << object->GetVersion()
@ -149,7 +158,7 @@ Value ApiListener::ConfigUpdateObjectAPIHandler(const MessageOrigin::Ptr& origin
}
/* keep the object version in sync with the sender */
object->SetVersion(objVersion);
object->SetVersion(objVersion, false, origin);
} else {
Log(LogNotice, "ApiListener")
<< "Discarding config update for object '" << object->GetName()
@ -157,7 +166,6 @@ Value ApiListener::ConfigUpdateObjectAPIHandler(const MessageOrigin::Ptr& origin
<< " is more recent than the received version " << objVersion << ".";
return Empty;
}
}
return Empty;
}
@ -211,7 +219,12 @@ Value ApiListener::ConfigDeleteObjectAPIHandler(const MessageOrigin::Ptr& origin
ConfigObject::Ptr object = dtype->GetObject(params->Get("name"));
if (object) {
if (!object) {
Log(LogNotice, "ApiListener")
<< "Could not delete non-existing object '" << params->Get("name") << "'.";
return Empty;
}
if (object->GetPackage() != "_api") {
Log(LogCritical, "ApiListener")
<< "Could not delete object '" << object->GetName() << "': Not created by the API.";
@ -219,8 +232,8 @@ Value ApiListener::ConfigDeleteObjectAPIHandler(const MessageOrigin::Ptr& origin
}
Array::Ptr errors = new Array();
bool cascade = true; //TODO pass that through the cluster
if (!ConfigObjectUtility::DeleteObject(object, cascade, errors)) {
if (!ConfigObjectUtility::DeleteObject(object, true, errors)) {
Log(LogCritical, "ApiListener", "Could not delete object:");
ObjectLock olock(errors);
@ -228,10 +241,6 @@ Value ApiListener::ConfigDeleteObjectAPIHandler(const MessageOrigin::Ptr& origin
Log(LogCritical, "ApiListener", error);
}
}
} else {
Log(LogNotice, "ApiListener")
<< "Could not delete non-existing object '" << params->Get("name") << "'.";
}
return Empty;
}
@ -239,9 +248,6 @@ Value ApiListener::ConfigDeleteObjectAPIHandler(const MessageOrigin::Ptr& origin
void ApiListener::UpdateConfigObject(const ConfigObject::Ptr& object, const MessageOrigin::Ptr& origin,
const JsonRpcConnection::Ptr& client)
{
if (object->GetPackage() != "_api")
return;
/* don't sync objects without a zone attribute */
if (object->GetZoneName().IsEmpty())
return;
@ -257,6 +263,7 @@ void ApiListener::UpdateConfigObject(const ConfigObject::Ptr& object, const Mess
/* required for acceptance criteria on the client */
params->Set("zone", object->GetZoneName());
if (object->GetPackage() == "_api") {
String file = ConfigObjectUtility::GetObjectConfigPath(object->GetReflectionType(), object->GetName());
std::ifstream fp(file.CStr(), std::ifstream::binary);
@ -265,6 +272,7 @@ void ApiListener::UpdateConfigObject(const ConfigObject::Ptr& object, const Mess
String content((std::istreambuf_iterator<char>(fp)), std::istreambuf_iterator<char>());
params->Set("config", content);
}
Dictionary::Ptr original_attributes = object->GetOriginalAttributes();
Dictionary::Ptr modified_attributes = new Dictionary();
@ -272,9 +280,14 @@ void ApiListener::UpdateConfigObject(const ConfigObject::Ptr& object, const Mess
if (original_attributes) {
ObjectLock olock(original_attributes);
BOOST_FOREACH(const Dictionary::Pair& kv, original_attributes) {
int fid = object->GetReflectionType()->GetFieldId(kv.first);
//TODO-MA: vars.os
Value value = static_cast<Object::Ptr>(object)->GetField(fid);
std::vector<String> tokens;
boost::algorithm::split(tokens, kv.first, boost::is_any_of("."));
Value value = object;
BOOST_FOREACH(const String& token, tokens) {
value = VMOps::GetField(value, token);
}
modified_attributes->Set(kv.first, value);
}
}
@ -343,9 +356,6 @@ void ApiListener::SendRuntimeConfigObjects(const JsonRpcConnection::Ptr& aclient
BOOST_FOREACH(const ConfigType::Ptr& dt, ConfigType::GetTypes()) {
BOOST_FOREACH(const ConfigObject::Ptr& object, dt->GetObjects()) {
if (object->GetPackage() != "_api")
continue;
String objZone = object->GetZoneName();
/* don't sync objects without a zone attribute */