mirror of https://github.com/Icinga/icinga2.git
Merge pull request #9009 from Icinga/bugfix/icingadb-runtime-updates-delete-relationships
Icinga DB: Make sure object relationships are handled correctly during runtime updates
This commit is contained in:
commit
4d3b1709fd
|
@ -235,10 +235,10 @@ Object::Ptr Dictionary::Clone() const
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing all keys
|
||||
* Returns an ordered vector containing all keys
|
||||
* which are currently set in this directory.
|
||||
*
|
||||
* @returns an array of key names
|
||||
* @returns an ordered vector of key names
|
||||
*/
|
||||
std::vector<String> Dictionary::GetKeys() const
|
||||
{
|
||||
|
|
|
@ -11,11 +11,11 @@ namespace icinga
|
|||
abstract class Command : CustomVarObject
|
||||
{
|
||||
[config] Value command (CommandLine);
|
||||
[config] Value arguments;
|
||||
[config, signal_with_old_value] Value arguments;
|
||||
[config] int timeout {
|
||||
default {{{ return 60; }}}
|
||||
};
|
||||
[config] Dictionary::Ptr env;
|
||||
[config, signal_with_old_value] Dictionary::Ptr env;
|
||||
[config, required] Function::Ptr execute;
|
||||
};
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace icinga
|
|||
|
||||
abstract class CustomVarObject : ConfigObject
|
||||
{
|
||||
[config] Dictionary::Ptr vars;
|
||||
[config, signal_with_old_value] Dictionary::Ptr vars;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ class Host : Checkable
|
|||
load_after Endpoint;
|
||||
load_after Zone;
|
||||
|
||||
[config, no_user_modify, required] array(name(HostGroup)) groups {
|
||||
[config, no_user_modify, required, signal_with_old_value] array(name(HostGroup)) groups {
|
||||
default {{{ return new Array(); }}}
|
||||
};
|
||||
|
||||
|
|
|
@ -133,6 +133,9 @@ void Notification::Start(bool runtimeCreated)
|
|||
if (ApiListener::IsHACluster() && GetNextNotification() < Utility::GetTime() + 60)
|
||||
SetNextNotification(Utility::GetTime() + 60, true);
|
||||
|
||||
for (const UserGroup::Ptr& group : GetUserGroups())
|
||||
group->AddNotification(this);
|
||||
|
||||
ObjectImpl<Notification>::Start(runtimeCreated);
|
||||
}
|
||||
|
||||
|
@ -144,6 +147,9 @@ void Notification::Stop(bool runtimeRemoved)
|
|||
|
||||
if (obj)
|
||||
obj->UnregisterNotification(this);
|
||||
|
||||
for (const UserGroup::Ptr& group : GetUserGroups())
|
||||
group->RemoveNotification(this);
|
||||
}
|
||||
|
||||
Checkable::Ptr Notification::GetCheckable() const
|
||||
|
|
|
@ -36,8 +36,8 @@ class Notification : CustomVarObject < NotificationNameComposer
|
|||
return TimePeriod::GetByName(GetPeriodRaw());
|
||||
}}}
|
||||
};
|
||||
[config, protected] array(name(User)) users (UsersRaw);
|
||||
[config, protected] array(name(UserGroup)) user_groups (UserGroupsRaw);
|
||||
[config, signal_with_old_value] array(name(User)) users (UsersRaw);
|
||||
[config, signal_with_old_value] array(name(UserGroup)) user_groups (UserGroupsRaw);
|
||||
[config] Dictionary::Ptr times;
|
||||
[config] array(Value) types;
|
||||
[no_user_view, no_user_modify] int type_filter_real (TypeFilter);
|
||||
|
|
|
@ -27,7 +27,7 @@ class Service : Checkable < ServiceNameComposer
|
|||
load_after Host;
|
||||
load_after Zone;
|
||||
|
||||
[config, no_user_modify, required] array(name(ServiceGroup)) groups {
|
||||
[config, no_user_modify, required, signal_with_old_value] array(name(ServiceGroup)) groups {
|
||||
default {{{ return new Array(); }}}
|
||||
};
|
||||
|
||||
|
|
|
@ -18,15 +18,15 @@ class TimePeriod : CustomVarObject
|
|||
return m_DisplayName.m_Value;
|
||||
}}}
|
||||
};
|
||||
[config] Dictionary::Ptr ranges;
|
||||
[config, signal_with_old_value] Dictionary::Ptr ranges;
|
||||
[config, required] Function::Ptr update;
|
||||
[config] bool prefer_includes {
|
||||
default {{{ return true; }}}
|
||||
};
|
||||
[config, required] array(name(TimePeriod)) excludes {
|
||||
[config, required, signal_with_old_value] array(name(TimePeriod)) excludes {
|
||||
default {{{ return new Array(); }}}
|
||||
};
|
||||
[config, required] array(name(TimePeriod)) includes {
|
||||
[config, required, signal_with_old_value] array(name(TimePeriod)) includes {
|
||||
default {{{ return new Array(); }}}
|
||||
};
|
||||
[state, no_user_modify] Value valid_begin;
|
||||
|
|
|
@ -19,7 +19,7 @@ class User : CustomVarObject
|
|||
return m_DisplayName.m_Value;
|
||||
}}}
|
||||
};
|
||||
[config, no_user_modify, required] array(name(UserGroup)) groups {
|
||||
[config, no_user_modify, required, signal_with_old_value] array(name(UserGroup)) groups {
|
||||
default {{{ return new Array(); }}}
|
||||
};
|
||||
[config, navigation] name(TimePeriod) period (PeriodRaw) {
|
||||
|
|
|
@ -76,6 +76,24 @@ void UserGroup::RemoveMember(const User::Ptr& user)
|
|||
m_Members.erase(user);
|
||||
}
|
||||
|
||||
std::set<Notification::Ptr> UserGroup::GetNotifications() const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_UserGroupMutex);
|
||||
return m_Notifications;
|
||||
}
|
||||
|
||||
void UserGroup::AddNotification(const Notification::Ptr& notification)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_UserGroupMutex);
|
||||
m_Notifications.insert(notification);
|
||||
}
|
||||
|
||||
void UserGroup::RemoveNotification(const Notification::Ptr& notification)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_UserGroupMutex);
|
||||
m_Notifications.erase(notification);
|
||||
}
|
||||
|
||||
bool UserGroup::ResolveGroupMembership(const User::Ptr& user, bool add, int rstack) {
|
||||
|
||||
if (add && rstack > 20) {
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace icinga
|
|||
{
|
||||
|
||||
class ConfigItem;
|
||||
class Notification;
|
||||
|
||||
/**
|
||||
* An Icinga user group.
|
||||
|
@ -27,6 +28,10 @@ public:
|
|||
void AddMember(const User::Ptr& user);
|
||||
void RemoveMember(const User::Ptr& user);
|
||||
|
||||
std::set<intrusive_ptr<Notification>> GetNotifications() const;
|
||||
void AddNotification(const intrusive_ptr<Notification>& notification);
|
||||
void RemoveNotification(const intrusive_ptr<Notification>& notification);
|
||||
|
||||
bool ResolveGroupMembership(const User::Ptr& user, bool add = true, int rstack = 0);
|
||||
|
||||
static void EvaluateObjectRules(const User::Ptr& user);
|
||||
|
@ -34,6 +39,7 @@ public:
|
|||
private:
|
||||
mutable std::mutex m_UserGroupMutex;
|
||||
std::set<User::Ptr> m_Members;
|
||||
std::set<intrusive_ptr<Notification>> m_Notifications;
|
||||
|
||||
static bool EvaluateObjectRule(const User::Ptr& user, const intrusive_ptr<ConfigItem>& group);
|
||||
};
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "base/array.hpp"
|
||||
#include "base/exception.hpp"
|
||||
#include "base/utility.hpp"
|
||||
#include "base/object-packer.hpp"
|
||||
#include "icinga/command.hpp"
|
||||
#include "icinga/compatutility.hpp"
|
||||
#include "icinga/customvarobject.hpp"
|
||||
|
@ -35,6 +36,7 @@
|
|||
#include <mutex>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
|
@ -127,6 +129,40 @@ void IcingaDB::ConfigStaticInitialize()
|
|||
Service::OnHostProblemChanged.connect([](const Service::Ptr& service, const CheckResult::Ptr&, const MessageOrigin::Ptr&) {
|
||||
IcingaDB::StateChangeHandler(service);
|
||||
});
|
||||
|
||||
Notification::OnUsersRawChangedWithOldValue.connect([](const Notification::Ptr& notification, const Value& oldValues, const Value& newValues) {
|
||||
IcingaDB::NotificationUsersChangedHandler(notification, oldValues, newValues);
|
||||
});
|
||||
Notification::OnUserGroupsRawChangedWithOldValue.connect([](const Notification::Ptr& notification, const Value& oldValues, const Value& newValues) {
|
||||
IcingaDB::NotificationUserGroupsChangedHandler(notification, oldValues, newValues);
|
||||
});
|
||||
TimePeriod::OnRangesChangedWithOldValue.connect([](const TimePeriod::Ptr& timeperiod, const Value& oldValues, const Value& newValues) {
|
||||
IcingaDB::TimePeriodRangesChangedHandler(timeperiod, oldValues, newValues);
|
||||
});
|
||||
TimePeriod::OnIncludesChangedWithOldValue.connect([](const TimePeriod::Ptr& timeperiod, const Value& oldValues, const Value& newValues) {
|
||||
IcingaDB::TimePeriodIncludesChangedHandler(timeperiod, oldValues, newValues);
|
||||
});
|
||||
TimePeriod::OnExcludesChangedWithOldValue.connect([](const TimePeriod::Ptr& timeperiod, const Value& oldValues, const Value& newValues) {
|
||||
IcingaDB::TimePeriodExcludesChangedHandler(timeperiod, oldValues, newValues);
|
||||
});
|
||||
User::OnGroupsChangedWithOldValue.connect([](const User::Ptr& user, const Value& oldValues, const Value& newValues) {
|
||||
IcingaDB::UserGroupsChangedHandler(user, oldValues, newValues);
|
||||
});
|
||||
Host::OnGroupsChangedWithOldValue.connect([](const Host::Ptr& host, const Value& oldValues, const Value& newValues) {
|
||||
IcingaDB::HostGroupsChangedHandler(host, oldValues, newValues);
|
||||
});
|
||||
Service::OnGroupsChangedWithOldValue.connect([](const Service::Ptr& service, const Value& oldValues, const Value& newValues) {
|
||||
IcingaDB::ServiceGroupsChangedHandler(service, oldValues, newValues);
|
||||
});
|
||||
Command::OnEnvChangedWithOldValue.connect([](const ConfigObject::Ptr& command, const Value& oldValues, const Value& newValues) {
|
||||
IcingaDB::CommandEnvChangedHandler(command, oldValues, newValues);
|
||||
});
|
||||
Command::OnArgumentsChangedWithOldValue.connect([](const ConfigObject::Ptr& command, const Value& oldValues, const Value& newValues) {
|
||||
IcingaDB::CommandArgumentsChangedHandler(command, oldValues, newValues);
|
||||
});
|
||||
CustomVarObject::OnVarsChangedWithOldValue.connect([](const ConfigObject::Ptr& object, const Value& oldValues, const Value& newValues) {
|
||||
IcingaDB::CustomVarsChangedHandler(object, oldValues, newValues);
|
||||
});
|
||||
}
|
||||
|
||||
void IcingaDB::UpdateAllConfigObjects()
|
||||
|
@ -609,7 +645,7 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S
|
|||
CustomVarObject::Ptr customVarObject = dynamic_pointer_cast<CustomVarObject>(object);
|
||||
|
||||
if (customVarObject) {
|
||||
auto vars(SerializeVars(customVarObject));
|
||||
auto vars(SerializeVars(customVarObject->GetVars()));
|
||||
if (vars) {
|
||||
auto& typeCvs (hMSets[m_PrefixConfigObject + typeName + ":customvar"]);
|
||||
auto& allCvs (hMSets[m_PrefixConfigObject + "customvar"]);
|
||||
|
@ -825,12 +861,7 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S
|
|||
|
||||
if (type == User::TypeInstance) {
|
||||
User::Ptr user = static_pointer_cast<User>(object);
|
||||
|
||||
Array::Ptr groups;
|
||||
ConfigObject::Ptr (*getGroup)(const String& name);
|
||||
|
||||
groups = user->GetGroups();
|
||||
getGroup = &::GetObjectByName<UserGroup>;
|
||||
Array::Ptr groups = user->GetGroups();
|
||||
|
||||
if (groups) {
|
||||
ObjectLock groupsLock(groups);
|
||||
|
@ -839,9 +870,10 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S
|
|||
groupIds->Reserve(groups->GetLength());
|
||||
|
||||
auto& members (hMSets[m_PrefixConfigObject + typeName + "group:member"]);
|
||||
auto& notificationRecipients (hMSets[m_PrefixConfigObject + "notification:recipient"]);
|
||||
|
||||
for (auto& group : groups) {
|
||||
auto groupObj ((*getGroup)(group));
|
||||
UserGroup::Ptr groupObj = UserGroup::GetByName(group);
|
||||
String groupId = GetObjectIdentifier(groupObj);
|
||||
String id = HashValue(new Array({m_EnvironmentId, groupObj->GetName(), object->GetName()}));
|
||||
members.emplace_back(id);
|
||||
|
@ -850,6 +882,16 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S
|
|||
|
||||
if (runtimeUpdate) {
|
||||
AddObjectDataToRuntimeUpdates(runtimeUpdates, id, m_PrefixConfigObject + typeName + "group:member", data);
|
||||
|
||||
// Recipients are handled by notifications during initial dumps and only need to be handled here during runtime (e.g. User creation).
|
||||
for (auto& notification : groupObj->GetNotifications()) {
|
||||
String recipientId = HashValue(new Array({m_EnvironmentId, "usergroupuser", user->GetName(), groupObj->GetName(), notification->GetName()}));
|
||||
notificationRecipients.emplace_back(recipientId);
|
||||
Dictionary::Ptr recipientData = new Dictionary({{"notification_id", GetObjectIdentifier(notification)}, {"environment_id", m_EnvironmentId}, {"user_id", objectKey}, {"usergroup_id", groupId}});
|
||||
notificationRecipients.emplace_back(JsonEncode(recipientData));
|
||||
|
||||
AddObjectDataToRuntimeUpdates(runtimeUpdates, recipientId, m_PrefixConfigObject + "notification:recipient", recipientData);
|
||||
}
|
||||
}
|
||||
|
||||
groupIds->Add(groupId);
|
||||
|
@ -863,10 +905,6 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S
|
|||
Notification::Ptr notification = static_pointer_cast<Notification>(object);
|
||||
|
||||
std::set<User::Ptr> users = notification->GetUsers();
|
||||
|
||||
std::set<User::Ptr> allUsers;
|
||||
std::copy(users.begin(), users.end(), std::inserter(allUsers, allUsers.begin()));
|
||||
|
||||
Array::Ptr userIds = new Array();
|
||||
|
||||
auto usergroups(notification->GetUserGroups());
|
||||
|
@ -875,16 +913,22 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S
|
|||
userIds->Reserve(users.size());
|
||||
|
||||
auto& usrs (hMSets[m_PrefixConfigObject + typeName + ":user"]);
|
||||
auto& notificationRecipients (hMSets[m_PrefixConfigObject + typeName + ":recipient"]);
|
||||
|
||||
for (auto& user : users) {
|
||||
String userId = GetObjectIdentifier(user);
|
||||
String id = HashValue(new Array({m_EnvironmentId, user->GetName(), object->GetName()}));
|
||||
String id = HashValue(new Array({m_EnvironmentId, "user", user->GetName(), object->GetName()}));
|
||||
usrs.emplace_back(id);
|
||||
notificationRecipients.emplace_back(id);
|
||||
|
||||
Dictionary::Ptr data = new Dictionary({{"notification_id", objectKey}, {"environment_id", m_EnvironmentId}, {"user_id", userId}});
|
||||
usrs.emplace_back(JsonEncode(data));
|
||||
String dataJson = JsonEncode(data);
|
||||
usrs.emplace_back(dataJson);
|
||||
notificationRecipients.emplace_back(dataJson);
|
||||
|
||||
if (runtimeUpdate) {
|
||||
AddObjectDataToRuntimeUpdates(runtimeUpdates, id, m_PrefixConfigObject + typeName + ":user", data);
|
||||
AddObjectDataToRuntimeUpdates(runtimeUpdates, id, m_PrefixConfigObject + typeName + ":recipient", data);
|
||||
}
|
||||
|
||||
userIds->Add(userId);
|
||||
|
@ -893,43 +937,38 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S
|
|||
usergroupIds->Reserve(usergroups.size());
|
||||
|
||||
auto& groups (hMSets[m_PrefixConfigObject + typeName + ":usergroup"]);
|
||||
auto& notificationRecipients (hMSets[m_PrefixConfigObject + typeName + ":recipient"]);
|
||||
|
||||
for (auto& usergroup : usergroups) {
|
||||
String usergroupId = GetObjectIdentifier(usergroup);
|
||||
|
||||
auto groupMembers = usergroup->GetMembers();
|
||||
std::copy(groupMembers.begin(), groupMembers.end(), std::inserter(allUsers, allUsers.begin()));
|
||||
|
||||
String id = HashValue(new Array({m_EnvironmentId, "usergroup", usergroup->GetName(), object->GetName()}));
|
||||
groups.emplace_back(id);
|
||||
Dictionary::Ptr groupData = new Dictionary({{"notification_id", objectKey}, {"environment_id", m_EnvironmentId}, {"usergroup_id", usergroupId}});
|
||||
groups.emplace_back(JsonEncode(groupData));
|
||||
|
||||
notificationRecipients.emplace_back(id);
|
||||
Dictionary::Ptr notificationRecipientData = new Dictionary({{"notification_id", objectKey}, {"environment_id", m_EnvironmentId}, {"usergroup_id", usergroupId}});
|
||||
notificationRecipients.emplace_back(JsonEncode(notificationRecipientData));
|
||||
|
||||
Dictionary::Ptr groupData = new Dictionary({{"notification_id", objectKey}, {"environment_id", m_EnvironmentId}, {"usergroup_id", usergroupId}});
|
||||
String groupDataJson = JsonEncode(groupData);
|
||||
groups.emplace_back(groupDataJson);
|
||||
notificationRecipients.emplace_back(groupDataJson);
|
||||
|
||||
if (runtimeUpdate) {
|
||||
AddObjectDataToRuntimeUpdates(runtimeUpdates, id, m_PrefixConfigObject + typeName + ":usergroup", groupData);
|
||||
AddObjectDataToRuntimeUpdates(runtimeUpdates, id, m_PrefixConfigObject + typeName + ":recipient", notificationRecipientData);
|
||||
AddObjectDataToRuntimeUpdates(runtimeUpdates, id, m_PrefixConfigObject + typeName + ":recipient", groupData);
|
||||
}
|
||||
|
||||
for (const User::Ptr& user : usergroup->GetMembers()) {
|
||||
String userId = GetObjectIdentifier(user);
|
||||
String recipientId = HashValue(new Array({m_EnvironmentId, "usergroupuser", user->GetName(), usergroup->GetName(), notification->GetName()}));
|
||||
notificationRecipients.emplace_back(recipientId);
|
||||
Dictionary::Ptr userData = new Dictionary({{"notification_id", objectKey}, {"environment_id", m_EnvironmentId}, {"user_id", userId}, {"usergroup_id", usergroupId}});
|
||||
notificationRecipients.emplace_back(JsonEncode(userData));
|
||||
|
||||
if (runtimeUpdate) {
|
||||
AddObjectDataToRuntimeUpdates(runtimeUpdates, recipientId, m_PrefixConfigObject + typeName + ":recipient", userData);
|
||||
}
|
||||
}
|
||||
|
||||
usergroupIds->Add(usergroupId);
|
||||
}
|
||||
|
||||
for (auto& user : allUsers) {
|
||||
String userId = GetObjectIdentifier(user);
|
||||
String id = HashValue(new Array({m_EnvironmentId, "user", user->GetName(), object->GetName()}));
|
||||
notificationRecipients.emplace_back(id);
|
||||
Dictionary::Ptr data = new Dictionary({{"notification_id", objectKey}, {"environment_id", m_EnvironmentId}, {"user_id", userId}});
|
||||
notificationRecipients.emplace_back(JsonEncode(data));
|
||||
|
||||
if (runtimeUpdate) {
|
||||
AddObjectDataToRuntimeUpdates(runtimeUpdates, id, m_PrefixConfigObject + typeName + ":recipient", data);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1121,10 +1160,11 @@ void IcingaDB::SendConfigUpdate(const ConfigObject::Ptr& object, bool runtimeUpd
|
|||
void IcingaDB::AddObjectDataToRuntimeUpdates(std::vector<Dictionary::Ptr>& runtimeUpdates, const String& objectKey,
|
||||
const String& redisKey, const Dictionary::Ptr& data)
|
||||
{
|
||||
data->Set("id", objectKey);
|
||||
data->Set("redis_key", redisKey);
|
||||
data->Set("runtime_type", "upsert");
|
||||
runtimeUpdates.emplace_back(data);
|
||||
Dictionary::Ptr dataClone = data->ShallowClone();
|
||||
dataClone->Set("id", objectKey);
|
||||
dataClone->Set("redis_key", redisKey);
|
||||
dataClone->Set("runtime_type", "upsert");
|
||||
runtimeUpdates.emplace_back(dataClone);
|
||||
}
|
||||
|
||||
// Takes object and collects IcingaDB relevant attributes and computes checksums. Returns whether the object is relevant
|
||||
|
@ -1456,7 +1496,8 @@ IcingaDB::CreateConfigUpdate(const ConfigObject::Ptr& object, const String typeN
|
|||
|
||||
void IcingaDB::SendConfigDelete(const ConfigObject::Ptr& object)
|
||||
{
|
||||
String typeName = object->GetReflectionType()->GetName().ToLower();
|
||||
Type::Ptr type = object->GetReflectionType();
|
||||
String typeName = type->GetName().ToLower();
|
||||
String objectKey = GetObjectIdentifier(object);
|
||||
|
||||
m_Rcon->FireAndForgetQueries({
|
||||
|
@ -1468,12 +1509,23 @@ void IcingaDB::SendConfigDelete(const ConfigObject::Ptr& object)
|
|||
}
|
||||
}, Prio::Config);
|
||||
|
||||
auto checkable (dynamic_pointer_cast<Checkable>(object));
|
||||
CustomVarObject::Ptr customVarObject = dynamic_pointer_cast<CustomVarObject>(object);
|
||||
|
||||
if (customVarObject) {
|
||||
Dictionary::Ptr vars = customVarObject->GetVars();
|
||||
SendCustomVarsChanged(object, vars, nullptr);
|
||||
}
|
||||
|
||||
if (type == Host::TypeInstance || type == Service::TypeInstance) {
|
||||
Checkable::Ptr checkable = static_pointer_cast<Checkable>(object);
|
||||
|
||||
Host::Ptr host;
|
||||
Service::Ptr service;
|
||||
tie(host, service) = GetHostService(checkable);
|
||||
|
||||
if (checkable) {
|
||||
m_Rcon->FireAndForgetQuery({
|
||||
"ZREM",
|
||||
dynamic_pointer_cast<Service>(checkable) ? "icinga:nextupdate:service" : "icinga:nextupdate:host",
|
||||
service ? "icinga:nextupdate:service" : "icinga:nextupdate:host",
|
||||
GetObjectIdentifier(checkable)
|
||||
}, Prio::CheckResult);
|
||||
|
||||
|
@ -1481,6 +1533,42 @@ void IcingaDB::SendConfigDelete(const ConfigObject::Ptr& object)
|
|||
{"HDEL", m_PrefixConfigObject + typeName + ":state", objectKey},
|
||||
{"HDEL", m_PrefixConfigCheckSum + typeName + ":state", objectKey}
|
||||
}, Prio::RuntimeStateSync);
|
||||
|
||||
if (service) {
|
||||
SendGroupsChanged<ServiceGroup>(checkable, service->GetGroups(), nullptr);
|
||||
} else {
|
||||
SendGroupsChanged<HostGroup>(checkable, host->GetGroups(), nullptr);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == TimePeriod::TypeInstance) {
|
||||
TimePeriod::Ptr timeperiod = static_pointer_cast<TimePeriod>(object);
|
||||
SendTimePeriodRangesChanged(timeperiod, timeperiod->GetRanges(), nullptr);
|
||||
SendTimePeriodIncludesChanged(timeperiod, timeperiod->GetIncludes(), nullptr);
|
||||
SendTimePeriodExcludesChanged(timeperiod, timeperiod->GetExcludes(), nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == User::TypeInstance) {
|
||||
User::Ptr user = static_pointer_cast<User>(object);
|
||||
SendGroupsChanged<UserGroup>(user, user->GetGroups(), nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == Notification::TypeInstance) {
|
||||
Notification::Ptr notification = static_pointer_cast<Notification>(object);
|
||||
SendNotificationUsersChanged(notification, notification->GetUsersRaw(), nullptr);
|
||||
SendNotificationUserGroupsChanged(notification, notification->GetUserGroupsRaw(), nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == CheckCommand::TypeInstance || type == NotificationCommand::TypeInstance || type == EventCommand::TypeInstance) {
|
||||
Command::Ptr command = static_pointer_cast<Command>(object);
|
||||
SendCommandArgumentsChanged(command, command->GetArguments(), nullptr);
|
||||
SendCommandEnvChanged(command, command->GetEnv(), nullptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2174,6 +2262,150 @@ void IcingaDB::SendAcknowledgementCleared(const Checkable::Ptr& checkable, const
|
|||
m_Rcon->FireAndForgetQuery(std::move(xAdd), Prio::History);
|
||||
}
|
||||
|
||||
void IcingaDB::SendNotificationUsersChanged(const Notification::Ptr& notification, const Array::Ptr& oldValues, const Array::Ptr& newValues) {
|
||||
if (!m_Rcon || !m_Rcon->IsConnected() || oldValues == newValues) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Value> deletedUsers = GetArrayDeletedValues(oldValues, newValues);
|
||||
|
||||
for (const auto& userName : deletedUsers) {
|
||||
String id = HashValue(new Array({m_EnvironmentId, "user", userName, notification->GetName()}));
|
||||
DeleteRelationship(id, "notification:user");
|
||||
DeleteRelationship(id, "notification:recipient");
|
||||
}
|
||||
}
|
||||
|
||||
void IcingaDB::SendNotificationUserGroupsChanged(const Notification::Ptr& notification, const Array::Ptr& oldValues, const Array::Ptr& newValues) {
|
||||
if (!m_Rcon || !m_Rcon->IsConnected() || oldValues == newValues) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Value> deletedUserGroups = GetArrayDeletedValues(oldValues, newValues);
|
||||
|
||||
for (const auto& userGroupName : deletedUserGroups) {
|
||||
UserGroup::Ptr userGroup = UserGroup::GetByName(userGroupName);
|
||||
String id = HashValue(new Array({m_EnvironmentId, "usergroup", userGroupName, notification->GetName()}));
|
||||
DeleteRelationship(id, "notification:usergroup");
|
||||
DeleteRelationship(id, "notification:recipient");
|
||||
|
||||
for (const User::Ptr& user : userGroup->GetMembers()) {
|
||||
String userId = HashValue(new Array({m_EnvironmentId, "usergroupuser", user->GetName(), userGroupName, notification->GetName()}));
|
||||
DeleteRelationship(userId, "notification:recipient");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IcingaDB::SendTimePeriodRangesChanged(const TimePeriod::Ptr& timeperiod, const Dictionary::Ptr& oldValues, const Dictionary::Ptr& newValues) {
|
||||
if (!m_Rcon || !m_Rcon->IsConnected() || oldValues == newValues) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<String> deletedKeys = GetDictionaryDeletedKeys(oldValues, newValues);
|
||||
String typeName = GetLowerCaseTypeNameDB(timeperiod);
|
||||
|
||||
for (const auto& rangeKey : deletedKeys) {
|
||||
String id = HashValue(new Array({m_EnvironmentId, rangeKey, oldValues->Get(rangeKey), timeperiod->GetName()}));
|
||||
DeleteRelationship(id, "timeperiod:range");
|
||||
}
|
||||
}
|
||||
|
||||
void IcingaDB::SendTimePeriodIncludesChanged(const TimePeriod::Ptr& timeperiod, const Array::Ptr& oldValues, const Array::Ptr& newValues) {
|
||||
if (!m_Rcon || !m_Rcon->IsConnected() || oldValues == newValues) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Value> deletedIncludes = GetArrayDeletedValues(oldValues, newValues);
|
||||
|
||||
for (const auto& includeName : deletedIncludes) {
|
||||
String id = HashValue(new Array({m_EnvironmentId, includeName, timeperiod->GetName()}));
|
||||
DeleteRelationship(id, "timeperiod:override:include");
|
||||
}
|
||||
}
|
||||
|
||||
void IcingaDB::SendTimePeriodExcludesChanged(const TimePeriod::Ptr& timeperiod, const Array::Ptr& oldValues, const Array::Ptr& newValues) {
|
||||
if (!m_Rcon || !m_Rcon->IsConnected() || oldValues == newValues) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Value> deletedExcludes = GetArrayDeletedValues(oldValues, newValues);
|
||||
|
||||
for (const auto& excludeName : deletedExcludes) {
|
||||
String id = HashValue(new Array({m_EnvironmentId, excludeName, timeperiod->GetName()}));
|
||||
DeleteRelationship(id, "timeperiod:override:exclude");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void IcingaDB::SendGroupsChanged(const ConfigObject::Ptr& object, const Array::Ptr& oldValues, const Array::Ptr& newValues) {
|
||||
if (!m_Rcon || !m_Rcon->IsConnected() || oldValues == newValues) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Value> deletedGroups = GetArrayDeletedValues(oldValues, newValues);
|
||||
String typeName = GetLowerCaseTypeNameDB(object);
|
||||
|
||||
for (const auto& groupName : deletedGroups) {
|
||||
typename T::Ptr group = ConfigObject::GetObject<T>(groupName);
|
||||
String id = HashValue(new Array({m_EnvironmentId, group->GetName(), object->GetName()}));
|
||||
DeleteRelationship(id, typeName + "group:member");
|
||||
|
||||
if (std::is_same<T, UserGroup>::value) {
|
||||
UserGroup::Ptr userGroup = dynamic_pointer_cast<UserGroup>(group);
|
||||
|
||||
for (const auto& notification : userGroup->GetNotifications()) {
|
||||
String userId = HashValue(new Array({m_EnvironmentId, "usergroupuser", object->GetName(), groupName, notification->GetName()}));
|
||||
DeleteRelationship(userId, "notification:recipient");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IcingaDB::SendCommandEnvChanged(const ConfigObject::Ptr& command, const Dictionary::Ptr& oldValues, const Dictionary::Ptr& newValues) {
|
||||
if (!m_Rcon || !m_Rcon->IsConnected() || oldValues == newValues) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<String> deletedKeys = GetDictionaryDeletedKeys(oldValues, newValues);
|
||||
String typeName = GetLowerCaseTypeNameDB(command);
|
||||
|
||||
for (const auto& envvarKey : deletedKeys) {
|
||||
String id = HashValue(new Array({m_EnvironmentId, envvarKey, command->GetName()}));
|
||||
DeleteRelationship(id, typeName + ":envvar", true);
|
||||
}
|
||||
}
|
||||
|
||||
void IcingaDB::SendCommandArgumentsChanged(const ConfigObject::Ptr& command, const Dictionary::Ptr& oldValues, const Dictionary::Ptr& newValues) {
|
||||
if (!m_Rcon || !m_Rcon->IsConnected() || oldValues == newValues) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<String> deletedKeys = GetDictionaryDeletedKeys(oldValues, newValues);
|
||||
String typeName = GetLowerCaseTypeNameDB(command);
|
||||
|
||||
for (const auto& argumentKey : deletedKeys) {
|
||||
String id = HashValue(new Array({m_EnvironmentId, argumentKey, command->GetName()}));
|
||||
DeleteRelationship(id, typeName + ":argument", true);
|
||||
}
|
||||
}
|
||||
|
||||
void IcingaDB::SendCustomVarsChanged(const ConfigObject::Ptr& object, const Dictionary::Ptr& oldValues, const Dictionary::Ptr& newValues) {
|
||||
if (!m_Rcon || !m_Rcon->IsConnected() || oldValues == newValues) {
|
||||
return;
|
||||
}
|
||||
|
||||
Dictionary::Ptr oldVars = SerializeVars(oldValues);
|
||||
Dictionary::Ptr newVars = SerializeVars(newValues);
|
||||
|
||||
std::vector<String> deletedVars = GetDictionaryDeletedKeys(oldVars, newVars);
|
||||
String typeName = GetLowerCaseTypeNameDB(object);
|
||||
|
||||
for (const auto& varId : deletedVars) {
|
||||
String id = HashValue(new Array({m_EnvironmentId, varId, object->GetName()}));
|
||||
DeleteRelationship(id, typeName + ":customvar");
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary::Ptr IcingaDB::SerializeState(const Checkable::Ptr& checkable)
|
||||
{
|
||||
Dictionary::Ptr attrs = new Dictionary();
|
||||
|
@ -2473,3 +2705,89 @@ void IcingaDB::AcknowledgementClearedHandler(const Checkable::Ptr& checkable, co
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IcingaDB::NotificationUsersChangedHandler(const Notification::Ptr& notification, const Array::Ptr& oldValues, const Array::Ptr& newValues) {
|
||||
for (const IcingaDB::Ptr& rw : ConfigType::GetObjectsByType<IcingaDB>()) {
|
||||
rw->SendNotificationUsersChanged(notification, oldValues, newValues);
|
||||
}
|
||||
}
|
||||
|
||||
void IcingaDB::NotificationUserGroupsChangedHandler(const Notification::Ptr& notification, const Array::Ptr& oldValues, const Array::Ptr& newValues) {
|
||||
for (const IcingaDB::Ptr& rw : ConfigType::GetObjectsByType<IcingaDB>()) {
|
||||
rw->SendNotificationUserGroupsChanged(notification, oldValues, newValues);
|
||||
}
|
||||
}
|
||||
|
||||
void IcingaDB::TimePeriodRangesChangedHandler(const TimePeriod::Ptr& timeperiod, const Dictionary::Ptr& oldValues, const Dictionary::Ptr& newValues) {
|
||||
for (const IcingaDB::Ptr& rw : ConfigType::GetObjectsByType<IcingaDB>()) {
|
||||
rw->SendTimePeriodRangesChanged(timeperiod, oldValues, newValues);
|
||||
}
|
||||
}
|
||||
|
||||
void IcingaDB::TimePeriodIncludesChangedHandler(const TimePeriod::Ptr& timeperiod, const Array::Ptr& oldValues, const Array::Ptr& newValues) {
|
||||
for (const IcingaDB::Ptr& rw : ConfigType::GetObjectsByType<IcingaDB>()) {
|
||||
rw->SendTimePeriodIncludesChanged(timeperiod, oldValues, newValues);
|
||||
}
|
||||
}
|
||||
|
||||
void IcingaDB::TimePeriodExcludesChangedHandler(const TimePeriod::Ptr& timeperiod, const Array::Ptr& oldValues, const Array::Ptr& newValues) {
|
||||
for (const IcingaDB::Ptr& rw : ConfigType::GetObjectsByType<IcingaDB>()) {
|
||||
rw->SendTimePeriodExcludesChanged(timeperiod, oldValues, newValues);
|
||||
}
|
||||
}
|
||||
|
||||
void IcingaDB::UserGroupsChangedHandler(const User::Ptr& user, const Array::Ptr& oldValues, const Array::Ptr& newValues) {
|
||||
for (const IcingaDB::Ptr& rw : ConfigType::GetObjectsByType<IcingaDB>()) {
|
||||
rw->SendGroupsChanged<UserGroup>(user, oldValues, newValues);
|
||||
}
|
||||
}
|
||||
|
||||
void IcingaDB::HostGroupsChangedHandler(const Host::Ptr& host, const Array::Ptr& oldValues, const Array::Ptr& newValues) {
|
||||
for (const IcingaDB::Ptr& rw : ConfigType::GetObjectsByType<IcingaDB>()) {
|
||||
rw->SendGroupsChanged<HostGroup>(host, oldValues, newValues);
|
||||
}
|
||||
}
|
||||
|
||||
void IcingaDB::ServiceGroupsChangedHandler(const Service::Ptr& service, const Array::Ptr& oldValues, const Array::Ptr& newValues) {
|
||||
for (const IcingaDB::Ptr& rw : ConfigType::GetObjectsByType<IcingaDB>()) {
|
||||
rw->SendGroupsChanged<ServiceGroup>(service, oldValues, newValues);
|
||||
}
|
||||
}
|
||||
|
||||
void IcingaDB::CommandEnvChangedHandler(const ConfigObject::Ptr& command, const Dictionary::Ptr& oldValues, const Dictionary::Ptr& newValues) {
|
||||
for (const IcingaDB::Ptr& rw : ConfigType::GetObjectsByType<IcingaDB>()) {
|
||||
rw->SendCommandEnvChanged(command, oldValues, newValues);
|
||||
}
|
||||
}
|
||||
|
||||
void IcingaDB::CommandArgumentsChangedHandler(const ConfigObject::Ptr& command, const Dictionary::Ptr& oldValues, const Dictionary::Ptr& newValues) {
|
||||
for (const IcingaDB::Ptr& rw : ConfigType::GetObjectsByType<IcingaDB>()) {
|
||||
rw->SendCommandArgumentsChanged(command, oldValues, newValues);
|
||||
}
|
||||
}
|
||||
|
||||
void IcingaDB::CustomVarsChangedHandler(const ConfigObject::Ptr& object, const Dictionary::Ptr& oldValues, const Dictionary::Ptr& newValues) {
|
||||
for (const IcingaDB::Ptr& rw : ConfigType::GetObjectsByType<IcingaDB>()) {
|
||||
rw->SendCustomVarsChanged(object, oldValues, newValues);
|
||||
}
|
||||
}
|
||||
|
||||
void IcingaDB::DeleteRelationship(const String& id, const String& redisKeyWithoutPrefix, bool hasChecksum) {
|
||||
Log(LogNotice, "IcingaDB") << "Deleting relationship '" << redisKeyWithoutPrefix << " -> '" << id << "'";
|
||||
|
||||
String redisKey = m_PrefixConfigObject + redisKeyWithoutPrefix;
|
||||
|
||||
std::vector<std::vector<String>> queries;
|
||||
|
||||
if (hasChecksum) {
|
||||
queries.push_back({"HDEL", m_PrefixConfigCheckSum + redisKeyWithoutPrefix, id});
|
||||
}
|
||||
|
||||
queries.push_back({"HDEL", redisKey, id});
|
||||
queries.push_back({
|
||||
"XADD", "icinga:runtime", "MAXLEN", "~", "1000000", "*",
|
||||
"redis_key", redisKey, "id", id, "runtime_type", "delete"
|
||||
});
|
||||
|
||||
m_Rcon->FireAndForgetQueries(queries, Prio::Config);
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ String IcingaDB::CalcEventID(const char* eventType, const ConfigObject::Ptr& obj
|
|||
static const std::set<String> metadataWhitelist ({"package", "source_location", "templates"});
|
||||
|
||||
/**
|
||||
* Prepare object's custom vars for being written to Redis
|
||||
* Prepare custom vars for being written to Redis
|
||||
*
|
||||
* object.vars = {
|
||||
* "disks": {
|
||||
|
@ -124,14 +124,12 @@ static const std::set<String> metadataWhitelist ({"package", "source_location",
|
|||
* }
|
||||
* }
|
||||
*
|
||||
* @param object Config object with custom vars
|
||||
* @param Dictionary Config object with custom vars
|
||||
*
|
||||
* @return JSON-like data structure for Redis
|
||||
* @return JSON-like data structure for Redis
|
||||
*/
|
||||
Dictionary::Ptr IcingaDB::SerializeVars(const CustomVarObject::Ptr& object)
|
||||
Dictionary::Ptr IcingaDB::SerializeVars(const Dictionary::Ptr& vars)
|
||||
{
|
||||
Dictionary::Ptr vars = object->GetVars();
|
||||
|
||||
if (!vars)
|
||||
return nullptr;
|
||||
|
||||
|
@ -258,3 +256,49 @@ String IcingaDB::IcingaToStreamValue(const Value& value)
|
|||
return JsonEncode(value);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the items that exist in "arrayOld" but not in "arrayNew"
|
||||
std::vector<Value> IcingaDB::GetArrayDeletedValues(const Array::Ptr& arrayOld, const Array::Ptr& arrayNew) {
|
||||
std::vector<Value> deletedValues;
|
||||
|
||||
if (!arrayOld) {
|
||||
return deletedValues;
|
||||
}
|
||||
|
||||
if (!arrayNew) {
|
||||
return std::vector<Value>(arrayOld->Begin(), arrayOld->End());
|
||||
}
|
||||
|
||||
std::vector<Value> vectorOld(arrayOld->Begin(), arrayOld->End());
|
||||
std::sort(vectorOld.begin(), vectorOld.end());
|
||||
vectorOld.erase(std::unique(vectorOld.begin(), vectorOld.end()), vectorOld.end());
|
||||
|
||||
std::vector<Value> vectorNew(arrayNew->Begin(), arrayNew->End());
|
||||
std::sort(vectorNew.begin(), vectorNew.end());
|
||||
vectorNew.erase(std::unique(vectorNew.begin(), vectorNew.end()), vectorNew.end());
|
||||
|
||||
std::set_difference(vectorOld.begin(), vectorOld.end(), vectorNew.begin(), vectorNew.end(), std::back_inserter(deletedValues));
|
||||
|
||||
return deletedValues;
|
||||
}
|
||||
|
||||
// Returns the keys that exist in "dictOld" but not in "dictNew"
|
||||
std::vector<String> IcingaDB::GetDictionaryDeletedKeys(const Dictionary::Ptr& dictOld, const Dictionary::Ptr& dictNew) {
|
||||
std::vector<String> deletedKeys;
|
||||
|
||||
if (!dictOld) {
|
||||
return deletedKeys;
|
||||
}
|
||||
|
||||
std::vector<String> oldKeys = dictOld->GetKeys();
|
||||
|
||||
if (!dictNew) {
|
||||
return oldKeys;
|
||||
}
|
||||
|
||||
std::vector<String> newKeys = dictNew->GetKeys();
|
||||
|
||||
std::set_difference(oldKeys.begin(), oldKeys.end(), newKeys.begin(), newKeys.end(), std::back_inserter(deletedKeys));
|
||||
|
||||
return deletedKeys;
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ private:
|
|||
void SendStateChange(const ConfigObject::Ptr& object, const CheckResult::Ptr& cr, StateType type);
|
||||
void AddObjectDataToRuntimeUpdates(std::vector<Dictionary::Ptr>& runtimeUpdates, const String& objectKey,
|
||||
const String& redisKey, const Dictionary::Ptr& data);
|
||||
void DeleteRelationship(const String& id, const String& redisKeyWithoutPrefix, bool hasChecksum = false);
|
||||
|
||||
void SendSentNotification(
|
||||
const Notification::Ptr& notification, const Checkable::Ptr& checkable, const std::set<User::Ptr>& users,
|
||||
|
@ -93,6 +94,16 @@ private:
|
|||
void SendNextUpdate(const Checkable::Ptr& checkable);
|
||||
void SendAcknowledgementSet(const Checkable::Ptr& checkable, const String& author, const String& comment, AcknowledgementType type, bool persistent, double changeTime, double expiry);
|
||||
void SendAcknowledgementCleared(const Checkable::Ptr& checkable, const String& removedBy, double changeTime, double ackLastChange);
|
||||
void SendNotificationUsersChanged(const Notification::Ptr& notification, const Array::Ptr& oldValues, const Array::Ptr& newValues);
|
||||
void SendNotificationUserGroupsChanged(const Notification::Ptr& notification, const Array::Ptr& oldValues, const Array::Ptr& newValues);
|
||||
void SendTimePeriodRangesChanged(const TimePeriod::Ptr& timeperiod, const Dictionary::Ptr& oldValues, const Dictionary::Ptr& newValues);
|
||||
void SendTimePeriodIncludesChanged(const TimePeriod::Ptr& timeperiod, const Array::Ptr& oldValues, const Array::Ptr& newValues);
|
||||
void SendTimePeriodExcludesChanged(const TimePeriod::Ptr& timeperiod, const Array::Ptr& oldValues, const Array::Ptr& newValues);
|
||||
template<class T>
|
||||
void SendGroupsChanged(const ConfigObject::Ptr& command, const Array::Ptr& oldValues, const Array::Ptr& newValues);
|
||||
void SendCommandEnvChanged(const ConfigObject::Ptr& command, const Dictionary::Ptr& oldValues, const Dictionary::Ptr& newValues);
|
||||
void SendCommandArgumentsChanged(const ConfigObject::Ptr& command, const Dictionary::Ptr& oldValues, const Dictionary::Ptr& newValues);
|
||||
void SendCustomVarsChanged(const ConfigObject::Ptr& object, const Dictionary::Ptr& oldValues, const Dictionary::Ptr& newValues);
|
||||
|
||||
std::vector<String> UpdateObjectAttrs(const ConfigObject::Ptr& object, int fieldType, const String& typeNameOverride);
|
||||
Dictionary::Ptr SerializeState(const Checkable::Ptr& checkable);
|
||||
|
@ -105,11 +116,13 @@ private:
|
|||
static String FormatCommandLine(const Value& commandLine);
|
||||
static long long TimestampToMilliseconds(double timestamp);
|
||||
static String IcingaToStreamValue(const Value& value);
|
||||
static std::vector<Value> GetArrayDeletedValues(const Array::Ptr& arrayOld, const Array::Ptr& arrayNew);
|
||||
static std::vector<String> GetDictionaryDeletedKeys(const Dictionary::Ptr& dictOld, const Dictionary::Ptr& dictNew);
|
||||
|
||||
static String GetObjectIdentifier(const ConfigObject::Ptr& object);
|
||||
static String CalcEventID(const char* eventType, const ConfigObject::Ptr& object, double eventTime = 0, NotificationType nt = NotificationType(0));
|
||||
static Dictionary::Ptr SerializeVars(const CustomVarObject::Ptr& object);
|
||||
static const char* GetNotificationTypeByEnum(NotificationType type);
|
||||
static Dictionary::Ptr SerializeVars(const Dictionary::Ptr& vars);
|
||||
|
||||
static String HashValue(const Value& value);
|
||||
static String HashValue(const Value& value, const std::set<String>& propertiesBlacklist, bool propertiesWhitelist = false);
|
||||
|
@ -135,6 +148,17 @@ private:
|
|||
static void NextCheckChangedHandler(const Checkable::Ptr& checkable);
|
||||
static void AcknowledgementSetHandler(const Checkable::Ptr& checkable, const String& author, const String& comment, AcknowledgementType type, bool persistent, double changeTime, double expiry);
|
||||
static void AcknowledgementClearedHandler(const Checkable::Ptr& checkable, const String& removedBy, double changeTime);
|
||||
static void NotificationUsersChangedHandler(const Notification::Ptr& notification, const Array::Ptr& oldValues, const Array::Ptr& newValues);
|
||||
static void NotificationUserGroupsChangedHandler(const Notification::Ptr& notification, const Array::Ptr& oldValues, const Array::Ptr& newValues);
|
||||
static void TimePeriodRangesChangedHandler(const TimePeriod::Ptr& timeperiod, const Dictionary::Ptr& oldValues, const Dictionary::Ptr& newValues);
|
||||
static void TimePeriodIncludesChangedHandler(const TimePeriod::Ptr& timeperiod, const Array::Ptr& oldValues, const Array::Ptr& newValues);
|
||||
static void TimePeriodExcludesChangedHandler(const TimePeriod::Ptr& timeperiod, const Array::Ptr& oldValues, const Array::Ptr& newValues);
|
||||
static void UserGroupsChangedHandler(const User::Ptr& user, const Array::Ptr&, const Array::Ptr& newValues);
|
||||
static void HostGroupsChangedHandler(const Host::Ptr& host, const Array::Ptr& oldValues, const Array::Ptr& newValues);
|
||||
static void ServiceGroupsChangedHandler(const Service::Ptr& service, const Array::Ptr& oldValues, const Array::Ptr& newValues);
|
||||
static void CommandEnvChangedHandler(const ConfigObject::Ptr& command, const Dictionary::Ptr& oldValues, const Dictionary::Ptr& newValues);
|
||||
static void CommandArgumentsChangedHandler(const ConfigObject::Ptr& command, const Dictionary::Ptr& oldValues, const Dictionary::Ptr& newValues);
|
||||
static void CustomVarsChangedHandler(const ConfigObject::Ptr& object, const Dictionary::Ptr& oldValues, const Dictionary::Ptr& newValues);
|
||||
|
||||
void AssertOnWorkQueue();
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ add_boost_test(base
|
|||
base_dictionary/remove
|
||||
base_dictionary/clone
|
||||
base_dictionary/json
|
||||
base_dictionary/keys_ordered
|
||||
base_fifo/construct
|
||||
base_fifo/io
|
||||
base_json/encode
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#include "base/dictionary.hpp"
|
||||
#include "base/objectlock.hpp"
|
||||
#include "base/json.hpp"
|
||||
#include "base/string.hpp"
|
||||
#include "base/utility.hpp"
|
||||
#include <BoostTestTargetConfig.h>
|
||||
|
||||
using namespace icinga;
|
||||
|
@ -183,4 +185,16 @@ BOOST_AUTO_TEST_CASE(json)
|
|||
BOOST_CHECK(deserialized->Get("test2") == "hello world");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(keys_ordered)
|
||||
{
|
||||
Dictionary::Ptr dictionary = new Dictionary();
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
dictionary->Set(std::to_string(Utility::Random()), Utility::Random());
|
||||
}
|
||||
|
||||
std::vector<String> keys = dictionary->GetKeys();
|
||||
BOOST_CHECK(std::is_sorted(keys.begin(), keys.end()));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
|
@ -134,6 +134,7 @@ no_user_view { yylval->num = FANoUserView; return T_FIELD_ATTRIBUTE; }
|
|||
deprecated { yylval->num = FADeprecated; return T_FIELD_ATTRIBUTE; }
|
||||
get_virtual { yylval->num = FAGetVirtual; return T_FIELD_ATTRIBUTE; }
|
||||
set_virtual { yylval->num = FASetVirtual; return T_FIELD_ATTRIBUTE; }
|
||||
signal_with_old_value { yylval->num = FASignalWithOldValue; return T_FIELD_ATTRIBUTE; }
|
||||
virtual { yylval->num = FAGetVirtual | FASetVirtual; return T_FIELD_ATTRIBUTE; }
|
||||
navigation { return T_NAVIGATION; }
|
||||
validator { return T_VALIDATOR; }
|
||||
|
|
|
@ -830,10 +830,10 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
|
|||
m_Impl << "void ObjectImpl<" << klass.Name << ">::Set" << field.GetFriendlyName() << "(" << field.Type.GetArgumentType() << " value, bool suppress_events, const Value& cookie)" << std::endl
|
||||
<< "{" << std::endl;
|
||||
|
||||
if (field.Type.IsName || !field.TrackAccessor.empty())
|
||||
m_Impl << "\t" << "Value oldValue = Get" << field.GetFriendlyName() << "();" << std::endl;
|
||||
if (field.Type.IsName || !field.TrackAccessor.empty() || field.Attributes & FASignalWithOldValue)
|
||||
m_Impl << "\t" << "Value oldValue = Get" << field.GetFriendlyName() << "();" << std::endl
|
||||
<< "\t" << "auto *dobj = dynamic_cast<ConfigObject *>(this);" << std::endl;
|
||||
|
||||
|
||||
if (field.SetAccessor.empty() && !(field.Attributes & FANoStorage))
|
||||
m_Impl << "\t" << "m_" << field.GetFriendlyName() << ".store(value);" << std::endl;
|
||||
else
|
||||
|
@ -841,16 +841,22 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
|
|||
|
||||
if (field.Type.IsName || !field.TrackAccessor.empty()) {
|
||||
if (field.Name != "active") {
|
||||
m_Impl << "\t" << "auto *dobj = dynamic_cast<ConfigObject *>(this);" << std::endl
|
||||
<< "\t" << "if (!dobj || dobj->IsActive())" << std::endl
|
||||
m_Impl << "\t" << "if (!dobj || dobj->IsActive())" << std::endl
|
||||
<< "\t";
|
||||
}
|
||||
|
||||
m_Impl << "\t" << "Track" << field.GetFriendlyName() << "(oldValue, value);" << std::endl;
|
||||
}
|
||||
|
||||
m_Impl << "\t" << "if (!suppress_events)" << std::endl
|
||||
<< "\t\t" << "Notify" << field.GetFriendlyName() << "(cookie);" << std::endl
|
||||
m_Impl << "\t" << "if (!suppress_events) {" << std::endl
|
||||
<< "\t\t" << "Notify" << field.GetFriendlyName() << "(cookie);" << std::endl;
|
||||
|
||||
if (field.Attributes & FASignalWithOldValue) {
|
||||
m_Impl << "\t\t" << "if (!dobj || dobj->IsActive())" << std::endl
|
||||
<< "\t\t\t" << "On" << field.GetFriendlyName() << "ChangedWithOldValue(static_cast<" << klass.Name << " *>(this), oldValue, value);" << std::endl;
|
||||
}
|
||||
|
||||
m_Impl << "\t" "}" << std::endl << std::endl
|
||||
<< "}" << std::endl << std::endl;
|
||||
}
|
||||
}
|
||||
|
@ -1053,6 +1059,15 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
|
|||
for (const Field& field : klass.Fields) {
|
||||
m_Header << "\t" << "static boost::signals2::signal<void (const intrusive_ptr<" << klass.Name << ">&, const Value&)> On" << field.GetFriendlyName() << "Changed;" << std::endl;
|
||||
m_Impl << std::endl << "boost::signals2::signal<void (const intrusive_ptr<" << klass.Name << ">&, const Value&)> ObjectImpl<" << klass.Name << ">::On" << field.GetFriendlyName() << "Changed;" << std::endl << std::endl;
|
||||
|
||||
if (field.Attributes & FASignalWithOldValue) {
|
||||
m_Header << "\t" << "static boost::signals2::signal<void (const intrusive_ptr<" << klass.Name
|
||||
<< ">&, const Value&, const Value&)> On" << field.GetFriendlyName() << "ChangedWithOldValue;"
|
||||
<< std::endl;
|
||||
m_Impl << std::endl << "boost::signals2::signal<void (const intrusive_ptr<" << klass.Name
|
||||
<< ">&, const Value&, const Value&)> ObjectImpl<" << klass.Name << ">::On"
|
||||
<< field.GetFriendlyName() << "ChangedWithOldValue;" << std::endl << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,8 @@ enum FieldAttribute
|
|||
FADeprecated = 4096,
|
||||
FAGetVirtual = 8192,
|
||||
FASetVirtual = 16384,
|
||||
FAActivationPriority = 32768
|
||||
FAActivationPriority = 32768,
|
||||
FASignalWithOldValue = 65536,
|
||||
};
|
||||
|
||||
struct FieldType
|
||||
|
|
Loading…
Reference in New Issue