mirror of
https://github.com/Icinga/icinga2.git
synced 2025-07-26 23:24:09 +02:00
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.
|
* 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
|
std::vector<String> Dictionary::GetKeys() const
|
||||||
{
|
{
|
||||||
|
@ -11,11 +11,11 @@ namespace icinga
|
|||||||
abstract class Command : CustomVarObject
|
abstract class Command : CustomVarObject
|
||||||
{
|
{
|
||||||
[config] Value command (CommandLine);
|
[config] Value command (CommandLine);
|
||||||
[config] Value arguments;
|
[config, signal_with_old_value] Value arguments;
|
||||||
[config] int timeout {
|
[config] int timeout {
|
||||||
default {{{ return 60; }}}
|
default {{{ return 60; }}}
|
||||||
};
|
};
|
||||||
[config] Dictionary::Ptr env;
|
[config, signal_with_old_value] Dictionary::Ptr env;
|
||||||
[config, required] Function::Ptr execute;
|
[config, required] Function::Ptr execute;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ namespace icinga
|
|||||||
|
|
||||||
abstract class CustomVarObject : ConfigObject
|
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 Endpoint;
|
||||||
load_after Zone;
|
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(); }}}
|
default {{{ return new Array(); }}}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -133,6 +133,9 @@ void Notification::Start(bool runtimeCreated)
|
|||||||
if (ApiListener::IsHACluster() && GetNextNotification() < Utility::GetTime() + 60)
|
if (ApiListener::IsHACluster() && GetNextNotification() < Utility::GetTime() + 60)
|
||||||
SetNextNotification(Utility::GetTime() + 60, true);
|
SetNextNotification(Utility::GetTime() + 60, true);
|
||||||
|
|
||||||
|
for (const UserGroup::Ptr& group : GetUserGroups())
|
||||||
|
group->AddNotification(this);
|
||||||
|
|
||||||
ObjectImpl<Notification>::Start(runtimeCreated);
|
ObjectImpl<Notification>::Start(runtimeCreated);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,6 +147,9 @@ void Notification::Stop(bool runtimeRemoved)
|
|||||||
|
|
||||||
if (obj)
|
if (obj)
|
||||||
obj->UnregisterNotification(this);
|
obj->UnregisterNotification(this);
|
||||||
|
|
||||||
|
for (const UserGroup::Ptr& group : GetUserGroups())
|
||||||
|
group->RemoveNotification(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Checkable::Ptr Notification::GetCheckable() const
|
Checkable::Ptr Notification::GetCheckable() const
|
||||||
|
@ -36,8 +36,8 @@ class Notification : CustomVarObject < NotificationNameComposer
|
|||||||
return TimePeriod::GetByName(GetPeriodRaw());
|
return TimePeriod::GetByName(GetPeriodRaw());
|
||||||
}}}
|
}}}
|
||||||
};
|
};
|
||||||
[config, protected] array(name(User)) users (UsersRaw);
|
[config, signal_with_old_value] array(name(User)) users (UsersRaw);
|
||||||
[config, protected] array(name(UserGroup)) user_groups (UserGroupsRaw);
|
[config, signal_with_old_value] array(name(UserGroup)) user_groups (UserGroupsRaw);
|
||||||
[config] Dictionary::Ptr times;
|
[config] Dictionary::Ptr times;
|
||||||
[config] array(Value) types;
|
[config] array(Value) types;
|
||||||
[no_user_view, no_user_modify] int type_filter_real (TypeFilter);
|
[no_user_view, no_user_modify] int type_filter_real (TypeFilter);
|
||||||
|
@ -27,7 +27,7 @@ class Service : Checkable < ServiceNameComposer
|
|||||||
load_after Host;
|
load_after Host;
|
||||||
load_after Zone;
|
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(); }}}
|
default {{{ return new Array(); }}}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,15 +18,15 @@ class TimePeriod : CustomVarObject
|
|||||||
return m_DisplayName.m_Value;
|
return m_DisplayName.m_Value;
|
||||||
}}}
|
}}}
|
||||||
};
|
};
|
||||||
[config] Dictionary::Ptr ranges;
|
[config, signal_with_old_value] Dictionary::Ptr ranges;
|
||||||
[config, required] Function::Ptr update;
|
[config, required] Function::Ptr update;
|
||||||
[config] bool prefer_includes {
|
[config] bool prefer_includes {
|
||||||
default {{{ return true; }}}
|
default {{{ return true; }}}
|
||||||
};
|
};
|
||||||
[config, required] array(name(TimePeriod)) excludes {
|
[config, required, signal_with_old_value] array(name(TimePeriod)) excludes {
|
||||||
default {{{ return new Array(); }}}
|
default {{{ return new Array(); }}}
|
||||||
};
|
};
|
||||||
[config, required] array(name(TimePeriod)) includes {
|
[config, required, signal_with_old_value] array(name(TimePeriod)) includes {
|
||||||
default {{{ return new Array(); }}}
|
default {{{ return new Array(); }}}
|
||||||
};
|
};
|
||||||
[state, no_user_modify] Value valid_begin;
|
[state, no_user_modify] Value valid_begin;
|
||||||
|
@ -19,7 +19,7 @@ class User : CustomVarObject
|
|||||||
return m_DisplayName.m_Value;
|
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(); }}}
|
default {{{ return new Array(); }}}
|
||||||
};
|
};
|
||||||
[config, navigation] name(TimePeriod) period (PeriodRaw) {
|
[config, navigation] name(TimePeriod) period (PeriodRaw) {
|
||||||
|
@ -76,6 +76,24 @@ void UserGroup::RemoveMember(const User::Ptr& user)
|
|||||||
m_Members.erase(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) {
|
bool UserGroup::ResolveGroupMembership(const User::Ptr& user, bool add, int rstack) {
|
||||||
|
|
||||||
if (add && rstack > 20) {
|
if (add && rstack > 20) {
|
||||||
|
@ -11,6 +11,7 @@ namespace icinga
|
|||||||
{
|
{
|
||||||
|
|
||||||
class ConfigItem;
|
class ConfigItem;
|
||||||
|
class Notification;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An Icinga user group.
|
* An Icinga user group.
|
||||||
@ -27,6 +28,10 @@ public:
|
|||||||
void AddMember(const User::Ptr& user);
|
void AddMember(const User::Ptr& user);
|
||||||
void RemoveMember(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);
|
bool ResolveGroupMembership(const User::Ptr& user, bool add = true, int rstack = 0);
|
||||||
|
|
||||||
static void EvaluateObjectRules(const User::Ptr& user);
|
static void EvaluateObjectRules(const User::Ptr& user);
|
||||||
@ -34,6 +39,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
mutable std::mutex m_UserGroupMutex;
|
mutable std::mutex m_UserGroupMutex;
|
||||||
std::set<User::Ptr> m_Members;
|
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);
|
static bool EvaluateObjectRule(const User::Ptr& user, const intrusive_ptr<ConfigItem>& group);
|
||||||
};
|
};
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "base/array.hpp"
|
#include "base/array.hpp"
|
||||||
#include "base/exception.hpp"
|
#include "base/exception.hpp"
|
||||||
#include "base/utility.hpp"
|
#include "base/utility.hpp"
|
||||||
|
#include "base/object-packer.hpp"
|
||||||
#include "icinga/command.hpp"
|
#include "icinga/command.hpp"
|
||||||
#include "icinga/compatutility.hpp"
|
#include "icinga/compatutility.hpp"
|
||||||
#include "icinga/customvarobject.hpp"
|
#include "icinga/customvarobject.hpp"
|
||||||
@ -35,6 +36,7 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
using namespace icinga;
|
using namespace icinga;
|
||||||
|
|
||||||
@ -127,6 +129,40 @@ void IcingaDB::ConfigStaticInitialize()
|
|||||||
Service::OnHostProblemChanged.connect([](const Service::Ptr& service, const CheckResult::Ptr&, const MessageOrigin::Ptr&) {
|
Service::OnHostProblemChanged.connect([](const Service::Ptr& service, const CheckResult::Ptr&, const MessageOrigin::Ptr&) {
|
||||||
IcingaDB::StateChangeHandler(service);
|
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()
|
void IcingaDB::UpdateAllConfigObjects()
|
||||||
@ -609,7 +645,7 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S
|
|||||||
CustomVarObject::Ptr customVarObject = dynamic_pointer_cast<CustomVarObject>(object);
|
CustomVarObject::Ptr customVarObject = dynamic_pointer_cast<CustomVarObject>(object);
|
||||||
|
|
||||||
if (customVarObject) {
|
if (customVarObject) {
|
||||||
auto vars(SerializeVars(customVarObject));
|
auto vars(SerializeVars(customVarObject->GetVars()));
|
||||||
if (vars) {
|
if (vars) {
|
||||||
auto& typeCvs (hMSets[m_PrefixConfigObject + typeName + ":customvar"]);
|
auto& typeCvs (hMSets[m_PrefixConfigObject + typeName + ":customvar"]);
|
||||||
auto& allCvs (hMSets[m_PrefixConfigObject + "customvar"]);
|
auto& allCvs (hMSets[m_PrefixConfigObject + "customvar"]);
|
||||||
@ -825,12 +861,7 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S
|
|||||||
|
|
||||||
if (type == User::TypeInstance) {
|
if (type == User::TypeInstance) {
|
||||||
User::Ptr user = static_pointer_cast<User>(object);
|
User::Ptr user = static_pointer_cast<User>(object);
|
||||||
|
Array::Ptr groups = user->GetGroups();
|
||||||
Array::Ptr groups;
|
|
||||||
ConfigObject::Ptr (*getGroup)(const String& name);
|
|
||||||
|
|
||||||
groups = user->GetGroups();
|
|
||||||
getGroup = &::GetObjectByName<UserGroup>;
|
|
||||||
|
|
||||||
if (groups) {
|
if (groups) {
|
||||||
ObjectLock groupsLock(groups);
|
ObjectLock groupsLock(groups);
|
||||||
@ -839,9 +870,10 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S
|
|||||||
groupIds->Reserve(groups->GetLength());
|
groupIds->Reserve(groups->GetLength());
|
||||||
|
|
||||||
auto& members (hMSets[m_PrefixConfigObject + typeName + "group:member"]);
|
auto& members (hMSets[m_PrefixConfigObject + typeName + "group:member"]);
|
||||||
|
auto& notificationRecipients (hMSets[m_PrefixConfigObject + "notification:recipient"]);
|
||||||
|
|
||||||
for (auto& group : groups) {
|
for (auto& group : groups) {
|
||||||
auto groupObj ((*getGroup)(group));
|
UserGroup::Ptr groupObj = UserGroup::GetByName(group);
|
||||||
String groupId = GetObjectIdentifier(groupObj);
|
String groupId = GetObjectIdentifier(groupObj);
|
||||||
String id = HashValue(new Array({m_EnvironmentId, groupObj->GetName(), object->GetName()}));
|
String id = HashValue(new Array({m_EnvironmentId, groupObj->GetName(), object->GetName()}));
|
||||||
members.emplace_back(id);
|
members.emplace_back(id);
|
||||||
@ -850,6 +882,16 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S
|
|||||||
|
|
||||||
if (runtimeUpdate) {
|
if (runtimeUpdate) {
|
||||||
AddObjectDataToRuntimeUpdates(runtimeUpdates, id, m_PrefixConfigObject + typeName + "group:member", data);
|
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);
|
groupIds->Add(groupId);
|
||||||
@ -863,10 +905,6 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S
|
|||||||
Notification::Ptr notification = static_pointer_cast<Notification>(object);
|
Notification::Ptr notification = static_pointer_cast<Notification>(object);
|
||||||
|
|
||||||
std::set<User::Ptr> users = notification->GetUsers();
|
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();
|
Array::Ptr userIds = new Array();
|
||||||
|
|
||||||
auto usergroups(notification->GetUserGroups());
|
auto usergroups(notification->GetUserGroups());
|
||||||
@ -875,16 +913,22 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S
|
|||||||
userIds->Reserve(users.size());
|
userIds->Reserve(users.size());
|
||||||
|
|
||||||
auto& usrs (hMSets[m_PrefixConfigObject + typeName + ":user"]);
|
auto& usrs (hMSets[m_PrefixConfigObject + typeName + ":user"]);
|
||||||
|
auto& notificationRecipients (hMSets[m_PrefixConfigObject + typeName + ":recipient"]);
|
||||||
|
|
||||||
for (auto& user : users) {
|
for (auto& user : users) {
|
||||||
String userId = GetObjectIdentifier(user);
|
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);
|
usrs.emplace_back(id);
|
||||||
|
notificationRecipients.emplace_back(id);
|
||||||
|
|
||||||
Dictionary::Ptr data = new Dictionary({{"notification_id", objectKey}, {"environment_id", m_EnvironmentId}, {"user_id", userId}});
|
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) {
|
if (runtimeUpdate) {
|
||||||
AddObjectDataToRuntimeUpdates(runtimeUpdates, id, m_PrefixConfigObject + typeName + ":user", data);
|
AddObjectDataToRuntimeUpdates(runtimeUpdates, id, m_PrefixConfigObject + typeName + ":user", data);
|
||||||
|
AddObjectDataToRuntimeUpdates(runtimeUpdates, id, m_PrefixConfigObject + typeName + ":recipient", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
userIds->Add(userId);
|
userIds->Add(userId);
|
||||||
@ -893,43 +937,38 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S
|
|||||||
usergroupIds->Reserve(usergroups.size());
|
usergroupIds->Reserve(usergroups.size());
|
||||||
|
|
||||||
auto& groups (hMSets[m_PrefixConfigObject + typeName + ":usergroup"]);
|
auto& groups (hMSets[m_PrefixConfigObject + typeName + ":usergroup"]);
|
||||||
auto& notificationRecipients (hMSets[m_PrefixConfigObject + typeName + ":recipient"]);
|
|
||||||
|
|
||||||
for (auto& usergroup : usergroups) {
|
for (auto& usergroup : usergroups) {
|
||||||
String usergroupId = GetObjectIdentifier(usergroup);
|
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()}));
|
String id = HashValue(new Array({m_EnvironmentId, "usergroup", usergroup->GetName(), object->GetName()}));
|
||||||
groups.emplace_back(id);
|
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);
|
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) {
|
if (runtimeUpdate) {
|
||||||
AddObjectDataToRuntimeUpdates(runtimeUpdates, id, m_PrefixConfigObject + typeName + ":usergroup", groupData);
|
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);
|
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;
|
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,
|
void IcingaDB::AddObjectDataToRuntimeUpdates(std::vector<Dictionary::Ptr>& runtimeUpdates, const String& objectKey,
|
||||||
const String& redisKey, const Dictionary::Ptr& data)
|
const String& redisKey, const Dictionary::Ptr& data)
|
||||||
{
|
{
|
||||||
data->Set("id", objectKey);
|
Dictionary::Ptr dataClone = data->ShallowClone();
|
||||||
data->Set("redis_key", redisKey);
|
dataClone->Set("id", objectKey);
|
||||||
data->Set("runtime_type", "upsert");
|
dataClone->Set("redis_key", redisKey);
|
||||||
runtimeUpdates.emplace_back(data);
|
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
|
// 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)
|
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);
|
String objectKey = GetObjectIdentifier(object);
|
||||||
|
|
||||||
m_Rcon->FireAndForgetQueries({
|
m_Rcon->FireAndForgetQueries({
|
||||||
@ -1468,12 +1509,23 @@ void IcingaDB::SendConfigDelete(const ConfigObject::Ptr& object)
|
|||||||
}
|
}
|
||||||
}, Prio::Config);
|
}, 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({
|
m_Rcon->FireAndForgetQuery({
|
||||||
"ZREM",
|
"ZREM",
|
||||||
dynamic_pointer_cast<Service>(checkable) ? "icinga:nextupdate:service" : "icinga:nextupdate:host",
|
service ? "icinga:nextupdate:service" : "icinga:nextupdate:host",
|
||||||
GetObjectIdentifier(checkable)
|
GetObjectIdentifier(checkable)
|
||||||
}, Prio::CheckResult);
|
}, Prio::CheckResult);
|
||||||
|
|
||||||
@ -1481,6 +1533,42 @@ void IcingaDB::SendConfigDelete(const ConfigObject::Ptr& object)
|
|||||||
{"HDEL", m_PrefixConfigObject + typeName + ":state", objectKey},
|
{"HDEL", m_PrefixConfigObject + typeName + ":state", objectKey},
|
||||||
{"HDEL", m_PrefixConfigCheckSum + typeName + ":state", objectKey}
|
{"HDEL", m_PrefixConfigCheckSum + typeName + ":state", objectKey}
|
||||||
}, Prio::RuntimeStateSync);
|
}, 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);
|
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 IcingaDB::SerializeState(const Checkable::Ptr& checkable)
|
||||||
{
|
{
|
||||||
Dictionary::Ptr attrs = new Dictionary();
|
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"});
|
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 = {
|
* object.vars = {
|
||||||
* "disks": {
|
* "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)
|
if (!vars)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
@ -258,3 +256,49 @@ String IcingaDB::IcingaToStreamValue(const Value& value)
|
|||||||
return JsonEncode(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 SendStateChange(const ConfigObject::Ptr& object, const CheckResult::Ptr& cr, StateType type);
|
||||||
void AddObjectDataToRuntimeUpdates(std::vector<Dictionary::Ptr>& runtimeUpdates, const String& objectKey,
|
void AddObjectDataToRuntimeUpdates(std::vector<Dictionary::Ptr>& runtimeUpdates, const String& objectKey,
|
||||||
const String& redisKey, const Dictionary::Ptr& data);
|
const String& redisKey, const Dictionary::Ptr& data);
|
||||||
|
void DeleteRelationship(const String& id, const String& redisKeyWithoutPrefix, bool hasChecksum = false);
|
||||||
|
|
||||||
void SendSentNotification(
|
void SendSentNotification(
|
||||||
const Notification::Ptr& notification, const Checkable::Ptr& checkable, const std::set<User::Ptr>& users,
|
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 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 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 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);
|
std::vector<String> UpdateObjectAttrs(const ConfigObject::Ptr& object, int fieldType, const String& typeNameOverride);
|
||||||
Dictionary::Ptr SerializeState(const Checkable::Ptr& checkable);
|
Dictionary::Ptr SerializeState(const Checkable::Ptr& checkable);
|
||||||
@ -105,11 +116,13 @@ private:
|
|||||||
static String FormatCommandLine(const Value& commandLine);
|
static String FormatCommandLine(const Value& commandLine);
|
||||||
static long long TimestampToMilliseconds(double timestamp);
|
static long long TimestampToMilliseconds(double timestamp);
|
||||||
static String IcingaToStreamValue(const Value& value);
|
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 GetObjectIdentifier(const ConfigObject::Ptr& object);
|
||||||
static String CalcEventID(const char* eventType, const ConfigObject::Ptr& object, double eventTime = 0, NotificationType nt = NotificationType(0));
|
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 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);
|
||||||
static String HashValue(const Value& value, const std::set<String>& propertiesBlacklist, bool propertiesWhitelist = false);
|
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 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 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 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();
|
void AssertOnWorkQueue();
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ add_boost_test(base
|
|||||||
base_dictionary/remove
|
base_dictionary/remove
|
||||||
base_dictionary/clone
|
base_dictionary/clone
|
||||||
base_dictionary/json
|
base_dictionary/json
|
||||||
|
base_dictionary/keys_ordered
|
||||||
base_fifo/construct
|
base_fifo/construct
|
||||||
base_fifo/io
|
base_fifo/io
|
||||||
base_json/encode
|
base_json/encode
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#include "base/dictionary.hpp"
|
#include "base/dictionary.hpp"
|
||||||
#include "base/objectlock.hpp"
|
#include "base/objectlock.hpp"
|
||||||
#include "base/json.hpp"
|
#include "base/json.hpp"
|
||||||
|
#include "base/string.hpp"
|
||||||
|
#include "base/utility.hpp"
|
||||||
#include <BoostTestTargetConfig.h>
|
#include <BoostTestTargetConfig.h>
|
||||||
|
|
||||||
using namespace icinga;
|
using namespace icinga;
|
||||||
@ -183,4 +185,16 @@ BOOST_AUTO_TEST_CASE(json)
|
|||||||
BOOST_CHECK(deserialized->Get("test2") == "hello world");
|
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()
|
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; }
|
deprecated { yylval->num = FADeprecated; return T_FIELD_ATTRIBUTE; }
|
||||||
get_virtual { yylval->num = FAGetVirtual; return T_FIELD_ATTRIBUTE; }
|
get_virtual { yylval->num = FAGetVirtual; return T_FIELD_ATTRIBUTE; }
|
||||||
set_virtual { yylval->num = FASetVirtual; 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; }
|
virtual { yylval->num = FAGetVirtual | FASetVirtual; return T_FIELD_ATTRIBUTE; }
|
||||||
navigation { return T_NAVIGATION; }
|
navigation { return T_NAVIGATION; }
|
||||||
validator { return T_VALIDATOR; }
|
validator { return T_VALIDATOR; }
|
||||||
|
@ -830,9 +830,9 @@ 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
|
m_Impl << "void ObjectImpl<" << klass.Name << ">::Set" << field.GetFriendlyName() << "(" << field.Type.GetArgumentType() << " value, bool suppress_events, const Value& cookie)" << std::endl
|
||||||
<< "{" << std::endl;
|
<< "{" << std::endl;
|
||||||
|
|
||||||
if (field.Type.IsName || !field.TrackAccessor.empty())
|
if (field.Type.IsName || !field.TrackAccessor.empty() || field.Attributes & FASignalWithOldValue)
|
||||||
m_Impl << "\t" << "Value oldValue = Get" << field.GetFriendlyName() << "();" << std::endl;
|
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))
|
if (field.SetAccessor.empty() && !(field.Attributes & FANoStorage))
|
||||||
m_Impl << "\t" << "m_" << field.GetFriendlyName() << ".store(value);" << std::endl;
|
m_Impl << "\t" << "m_" << field.GetFriendlyName() << ".store(value);" << std::endl;
|
||||||
@ -841,16 +841,22 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
|
|||||||
|
|
||||||
if (field.Type.IsName || !field.TrackAccessor.empty()) {
|
if (field.Type.IsName || !field.TrackAccessor.empty()) {
|
||||||
if (field.Name != "active") {
|
if (field.Name != "active") {
|
||||||
m_Impl << "\t" << "auto *dobj = dynamic_cast<ConfigObject *>(this);" << std::endl
|
m_Impl << "\t" << "if (!dobj || dobj->IsActive())" << std::endl
|
||||||
<< "\t" << "if (!dobj || dobj->IsActive())" << std::endl
|
|
||||||
<< "\t";
|
<< "\t";
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Impl << "\t" << "Track" << field.GetFriendlyName() << "(oldValue, value);" << std::endl;
|
m_Impl << "\t" << "Track" << field.GetFriendlyName() << "(oldValue, value);" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Impl << "\t" << "if (!suppress_events)" << std::endl
|
m_Impl << "\t" << "if (!suppress_events) {" << std::endl
|
||||||
<< "\t\t" << "Notify" << field.GetFriendlyName() << "(cookie);" << 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;
|
<< "}" << std::endl << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1053,6 +1059,15 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
|
|||||||
for (const Field& field : klass.Fields) {
|
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_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;
|
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,
|
FADeprecated = 4096,
|
||||||
FAGetVirtual = 8192,
|
FAGetVirtual = 8192,
|
||||||
FASetVirtual = 16384,
|
FASetVirtual = 16384,
|
||||||
FAActivationPriority = 32768
|
FAActivationPriority = 32768,
|
||||||
|
FASignalWithOldValue = 65536,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FieldType
|
struct FieldType
|
||||||
|
Loading…
x
Reference in New Issue
Block a user