mirror of
https://github.com/Icinga/icinga2.git
synced 2025-07-27 07:34:15 +02:00
Fix persisting and restoring modified attributes for custom attribute indexers
fixes #9935 fixes #9968
This commit is contained in:
parent
ff59402a10
commit
12cf90c67c
@ -130,20 +130,14 @@ void ConfigObject::ModifyAttribute(const String& attr, const Value& value, bool
|
|||||||
int fid = type->GetFieldId(fieldName);
|
int fid = type->GetFieldId(fieldName);
|
||||||
Field field = type->GetFieldInfo(fid);
|
Field field = type->GetFieldInfo(fid);
|
||||||
|
|
||||||
Value oldValue = GetField(fid);
|
|
||||||
|
|
||||||
if (field.Attributes & FAConfig) {
|
if (field.Attributes & FAConfig) {
|
||||||
if (!original_attributes) {
|
if (!original_attributes) {
|
||||||
original_attributes = new Dictionary();
|
original_attributes = new Dictionary();
|
||||||
SetOriginalAttributes(original_attributes, true);
|
SetOriginalAttributes(original_attributes, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!original_attributes->Contains(fieldName)) {
|
|
||||||
updated_original_attributes = true;
|
|
||||||
original_attributes->Set(fieldName, oldValue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value oldValue = GetField(fid);
|
||||||
Value newValue;
|
Value newValue;
|
||||||
|
|
||||||
if (tokens.size() > 1) {
|
if (tokens.size() > 1) {
|
||||||
@ -155,12 +149,16 @@ void ConfigObject::ModifyAttribute(const String& attr, const Value& value, bool
|
|||||||
newValue = current;
|
newValue = current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String prefix = tokens[0];
|
||||||
|
|
||||||
for (std::vector<String>::size_type i = 1; i < tokens.size() - 1; i++) {
|
for (std::vector<String>::size_type i = 1; i < tokens.size() - 1; i++) {
|
||||||
if (!current.IsObjectType<Dictionary>())
|
if (!current.IsObjectType<Dictionary>())
|
||||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Value must be a dictionary."));
|
BOOST_THROW_EXCEPTION(std::invalid_argument("Value must be a dictionary."));
|
||||||
|
|
||||||
Dictionary::Ptr dict = current;
|
Dictionary::Ptr dict = current;
|
||||||
|
|
||||||
const String& key = tokens[i];
|
const String& key = tokens[i];
|
||||||
|
prefix += "." + key;
|
||||||
|
|
||||||
if (!dict->Contains(key)) {
|
if (!dict->Contains(key)) {
|
||||||
current = new Dictionary();
|
current = new Dictionary();
|
||||||
@ -174,12 +172,51 @@ void ConfigObject::ModifyAttribute(const String& attr, const Value& value, bool
|
|||||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Value must be a dictionary."));
|
BOOST_THROW_EXCEPTION(std::invalid_argument("Value must be a dictionary."));
|
||||||
|
|
||||||
Dictionary::Ptr dict = current;
|
Dictionary::Ptr dict = current;
|
||||||
|
|
||||||
const String& key = tokens[tokens.size() - 1];
|
const String& key = tokens[tokens.size() - 1];
|
||||||
|
prefix += "." + key;
|
||||||
|
|
||||||
|
/* clone it for original attributes */
|
||||||
|
oldValue = dict->Get(key).Clone();
|
||||||
|
|
||||||
|
if (field.Attributes & FAConfig) {
|
||||||
|
updated_original_attributes = true;
|
||||||
|
|
||||||
|
if (oldValue.IsObjectType<Dictionary>()) {
|
||||||
|
Dictionary::Ptr oldDict = oldValue;
|
||||||
|
ObjectLock olock(oldDict);
|
||||||
|
BOOST_FOREACH(const Dictionary::Pair& kv, oldDict) {
|
||||||
|
String key = prefix + "." + kv.first;
|
||||||
|
if (!original_attributes->Contains(key))
|
||||||
|
original_attributes->Set(key, kv.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store the new value as null */
|
||||||
|
if (value.IsObjectType<Dictionary>()) {
|
||||||
|
Dictionary::Ptr valueDict = value;
|
||||||
|
ObjectLock olock(valueDict);
|
||||||
|
BOOST_FOREACH(const Dictionary::Pair& kv, valueDict) {
|
||||||
|
String key = attr + "." + kv.first;
|
||||||
|
if (!original_attributes->Contains(key))
|
||||||
|
original_attributes->Set(key, Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!original_attributes->Contains(attr))
|
||||||
|
original_attributes->Set(attr, oldValue);
|
||||||
|
}
|
||||||
|
|
||||||
dict->Set(key, value);
|
dict->Set(key, value);
|
||||||
} else
|
} else {
|
||||||
newValue = value;
|
newValue = value;
|
||||||
|
|
||||||
|
if (field.Attributes & FAConfig) {
|
||||||
|
if (!original_attributes->Contains(attr)) {
|
||||||
|
updated_original_attributes = true;
|
||||||
|
original_attributes->Set(attr, oldValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ModAttrValidationUtils utils;
|
ModAttrValidationUtils utils;
|
||||||
ValidateField(fid, newValue, utils);
|
ValidateField(fid, newValue, utils);
|
||||||
|
|
||||||
@ -208,9 +245,10 @@ void ConfigObject::RestoreAttribute(const String& attr)
|
|||||||
|
|
||||||
Dictionary::Ptr original_attributes = GetOriginalAttributes();
|
Dictionary::Ptr original_attributes = GetOriginalAttributes();
|
||||||
|
|
||||||
if (!original_attributes || !original_attributes->Contains(fieldName))
|
if (!original_attributes)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
Value oldValue = original_attributes->Get(attr);
|
||||||
Value newValue;
|
Value newValue;
|
||||||
|
|
||||||
if (tokens.size() > 1) {
|
if (tokens.size() > 1) {
|
||||||
@ -220,45 +258,87 @@ void ConfigObject::RestoreAttribute(const String& attr)
|
|||||||
if (current.IsEmpty())
|
if (current.IsEmpty())
|
||||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot restore non-existing object attribute"));
|
BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot restore non-existing object attribute"));
|
||||||
|
|
||||||
Value old = original_attributes->Get(fieldName);
|
String prefix = tokens[0];
|
||||||
|
|
||||||
for (std::vector<String>::size_type i = 1; i < tokens.size() - 1; i++) {
|
for (std::vector<String>::size_type i = 1; i < tokens.size() - 1; i++) {
|
||||||
if (!current.IsObjectType<Dictionary>() || !old.IsObjectType<Dictionary>())
|
if (!current.IsObjectType<Dictionary>())
|
||||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Value must be a dictionary."));
|
BOOST_THROW_EXCEPTION(std::invalid_argument("Value must be a dictionary."));
|
||||||
|
|
||||||
Dictionary::Ptr currentDict = current;
|
Dictionary::Ptr dict = current;
|
||||||
Dictionary::Ptr oldDict = old;
|
|
||||||
|
|
||||||
const String& key = tokens[i];
|
const String& key = tokens[i];
|
||||||
|
prefix += "." + key;
|
||||||
|
|
||||||
if (!currentDict->Contains(key))
|
if (!dict->Contains(key))
|
||||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot restore non-existing object attribute"));
|
BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot restore non-existing object attribute"));
|
||||||
|
|
||||||
/* silently ignore missing old values */
|
current = dict->Get(key);
|
||||||
if (!oldDict->Contains(key))
|
|
||||||
return;
|
|
||||||
|
|
||||||
current = currentDict->Get(key);
|
|
||||||
old = oldDict->Get(key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!current.IsObjectType<Dictionary>() || !old.IsObjectType<Dictionary>())
|
if (!current.IsObjectType<Dictionary>())
|
||||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Value must be a dictionary."));
|
BOOST_THROW_EXCEPTION(std::invalid_argument("Value must be a dictionary."));
|
||||||
|
|
||||||
Dictionary::Ptr currentDict = current;
|
Dictionary::Ptr dict = current;
|
||||||
Dictionary::Ptr oldDict = old;
|
|
||||||
|
|
||||||
const String& key = tokens[tokens.size() - 1];
|
const String& key = tokens[tokens.size() - 1];
|
||||||
|
prefix += "." + key;
|
||||||
|
|
||||||
|
std::vector<String> restoredAttrs;
|
||||||
|
|
||||||
|
{
|
||||||
|
ObjectLock olock(original_attributes);
|
||||||
|
BOOST_FOREACH(const Dictionary::Pair& kv, original_attributes) {
|
||||||
|
std::vector<String> originalTokens;
|
||||||
|
boost::algorithm::split(originalTokens, kv.first, boost::is_any_of("."));
|
||||||
|
|
||||||
|
if (tokens.size() > originalTokens.size())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool match = true;
|
||||||
|
for (std::vector<String>::size_type i = 0; i < tokens.size(); i++) {
|
||||||
|
if (tokens[i] != originalTokens[i]) {
|
||||||
|
match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!match)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Dictionary::Ptr dict;
|
||||||
|
|
||||||
|
if (tokens.size() == originalTokens.size())
|
||||||
|
dict = current;
|
||||||
|
else {
|
||||||
|
Value currentSub = current;
|
||||||
|
|
||||||
|
for (std::vector<String>::size_type i = tokens.size() - 1; i < originalTokens.size() - 1; i++) {
|
||||||
|
dict = currentSub;
|
||||||
|
currentSub = dict->Get(originalTokens[i]);
|
||||||
|
|
||||||
|
if (!currentSub.IsObjectType<Dictionary>()) {
|
||||||
|
currentSub = new Dictionary();
|
||||||
|
dict->Set(originalTokens[i], currentSub);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dict = currentSub;
|
||||||
|
}
|
||||||
|
|
||||||
|
dict->Set(originalTokens[originalTokens.size() - 1], kv.second);
|
||||||
|
restoredAttrs.push_back(kv.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FOREACH(const String& attr, restoredAttrs)
|
||||||
|
original_attributes->Remove(attr);
|
||||||
|
|
||||||
Value oldValue = oldDict->Get(key).Clone();
|
|
||||||
currentDict->Set(key, oldValue);
|
|
||||||
|
|
||||||
oldDict->Remove(key);
|
|
||||||
} else {
|
} else {
|
||||||
newValue = original_attributes->Get(fieldName);
|
newValue = oldValue;
|
||||||
original_attributes->Remove(fieldName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
original_attributes->Remove(attr);
|
||||||
SetField(fid, newValue);
|
SetField(fid, newValue);
|
||||||
|
|
||||||
/* increment the version. although restoring would mean
|
/* increment the version. although restoring would mean
|
||||||
@ -557,10 +637,47 @@ void ConfigObject::DumpModifiedAttributes(const boost::function<void(const Confi
|
|||||||
|
|
||||||
ObjectLock olock(originalAttributes);
|
ObjectLock olock(originalAttributes);
|
||||||
BOOST_FOREACH(const Dictionary::Pair& kv, originalAttributes) {
|
BOOST_FOREACH(const Dictionary::Pair& kv, originalAttributes) {
|
||||||
|
String key = kv.first;
|
||||||
// TODO-MA: vars.os
|
// TODO-MA: vars.os
|
||||||
int fid = object->GetReflectionType()->GetFieldId(kv.first);
|
|
||||||
Value value = object->GetField(fid);
|
Type::Ptr type = object->GetReflectionType();
|
||||||
callback(object, kv.first, value);
|
|
||||||
|
std::vector<String> tokens;
|
||||||
|
boost::algorithm::split(tokens, key, boost::is_any_of("."));
|
||||||
|
|
||||||
|
String fieldName = tokens[0];
|
||||||
|
int fid = type->GetFieldId(fieldName);
|
||||||
|
|
||||||
|
Value currentValue = object->GetField(fid);
|
||||||
|
Value modifiedValue;
|
||||||
|
|
||||||
|
if (tokens.size() > 1) {
|
||||||
|
Value current = currentValue;
|
||||||
|
|
||||||
|
for (std::vector<String>::size_type i = 1; i < tokens.size() - 1; i++) {
|
||||||
|
if (!current.IsObjectType<Dictionary>())
|
||||||
|
BOOST_THROW_EXCEPTION(std::invalid_argument("Value must be a dictionary."));
|
||||||
|
|
||||||
|
Dictionary::Ptr dict = current;
|
||||||
|
const String& key = tokens[i];
|
||||||
|
|
||||||
|
if (!dict->Contains(key))
|
||||||
|
break;
|
||||||
|
|
||||||
|
current = dict->Get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!current.IsObjectType<Dictionary>())
|
||||||
|
BOOST_THROW_EXCEPTION(std::invalid_argument("Value must be a dictionary."));
|
||||||
|
|
||||||
|
Dictionary::Ptr dict = current;
|
||||||
|
const String& key = tokens[tokens.size() - 1];
|
||||||
|
|
||||||
|
modifiedValue = dict->Get(key);
|
||||||
|
} else
|
||||||
|
modifiedValue = currentValue;
|
||||||
|
|
||||||
|
callback(object, key, modifiedValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user