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