Icinga DB: make icinga:history:stream:notification#id deterministic

... i.e. UUID -> SHA1(x..., send time) given that SHA1(x...) = notification id.
Rationale: allow both masters to write the same notification history concurrently (while
not in split-brain), so that REPLACE INTO deduplicates the same events written twice.
This commit is contained in:
Alexander A. Klimov 2021-10-08 18:25:19 +02:00
parent c2422c56fe
commit 5c44365c4e
3 changed files with 38 additions and 5 deletions

View File

@ -1603,7 +1603,7 @@ void IcingaDB::SendStateChange(const ConfigObject::Ptr& object, const CheckResul
void IcingaDB::SendSentNotification( void IcingaDB::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,
NotificationType type, const CheckResult::Ptr& cr, const String& author, const String& text NotificationType type, const CheckResult::Ptr& cr, const String& author, const String& text, double sendTime
) )
{ {
if (!m_Rcon || !m_Rcon->IsConnected()) if (!m_Rcon || !m_Rcon->IsConnected())
@ -1620,10 +1620,15 @@ void IcingaDB::SendSentNotification(
auto usersAmount (users.size()); auto usersAmount (users.size());
auto notificationHistoryId = Utility::NewUniqueID(); auto notificationHistoryId = Utility::NewUniqueID();
auto sendTs (TimestampToMilliseconds(sendTime));
Array::Ptr rawId = new Array(Prepend(GetEnvironment(), GetObjectIdentifiersWithoutEnv(notification)));
rawId->Add(GetNotificationTypeByEnum(type));
rawId->Add(sendTs);
std::vector<String> xAdd ({ std::vector<String> xAdd ({
"XADD", "icinga:history:stream:notification", "*", "XADD", "icinga:history:stream:notification", "*",
"id", notificationHistoryId, "id", HashValue(rawId),
"environment_id", m_EnvironmentId, "environment_id", m_EnvironmentId,
"notification_id", GetObjectIdentifier(notification), "notification_id", GetObjectIdentifier(notification),
"host_id", GetObjectIdentifier(host), "host_id", GetObjectIdentifier(host),
@ -1633,7 +1638,7 @@ void IcingaDB::SendSentNotification(
"author", Utility::ValidateUTF8(author), "author", Utility::ValidateUTF8(author),
"text", Utility::ValidateUTF8(finalText), "text", Utility::ValidateUTF8(finalText),
"users_notified", Convert::ToString(usersAmount), "users_notified", Convert::ToString(usersAmount),
"send_time", Convert::ToString(TimestampToMilliseconds(Utility::GetTime())), "send_time", Convert::ToString(sendTs),
"event_id", Utility::NewUniqueID(), "event_id", Utility::NewUniqueID(),
"event_type", "notification" "event_type", "notification"
}); });
@ -2382,10 +2387,11 @@ void IcingaDB::NotificationSentToAllUsersHandler(
) )
{ {
auto rws (ConfigType::GetObjectsByType<IcingaDB>()); auto rws (ConfigType::GetObjectsByType<IcingaDB>());
auto sendTime (notification->GetLastNotification());
if (!rws.empty()) { if (!rws.empty()) {
for (auto& rw : rws) { for (auto& rw : rws) {
rw->SendSentNotification(notification, checkable, users, type, cr, author, text); rw->SendSentNotification(notification, checkable, users, type, cr, author, text, sendTime);
} }
} }
} }

View File

@ -149,6 +149,32 @@ Dictionary::Ptr IcingaDB::SerializeVars(const CustomVarObject::Ptr& object)
return res; return res;
} }
const char* IcingaDB::GetNotificationTypeByEnum(NotificationType type)
{
switch (type) {
case NotificationDowntimeStart:
return "downtime_start";
case NotificationDowntimeEnd:
return "downtime_end";
case NotificationDowntimeRemoved:
return "downtime_removed";
case NotificationCustom:
return "custom";
case NotificationAcknowledgement:
return "acknowledgement";
case NotificationProblem:
return "problem";
case NotificationRecovery:
return "recovery";
case NotificationFlappingStart:
return "flapping_start";
case NotificationFlappingEnd:
return "flapping_end";
}
VERIFY(!"Invalid notification type.");
}
static const std::set<String> propertiesBlacklistEmpty; static const std::set<String> propertiesBlacklistEmpty;
String IcingaDB::HashValue(const Value& value) String IcingaDB::HashValue(const Value& value)

View File

@ -81,7 +81,7 @@ private:
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,
NotificationType type, const CheckResult::Ptr& cr, const String& author, const String& text NotificationType type, const CheckResult::Ptr& cr, const String& author, const String& text, double sendTime
); );
void SendStartedDowntime(const Downtime::Ptr& downtime); void SendStartedDowntime(const Downtime::Ptr& downtime);
@ -109,6 +109,7 @@ private:
static String GetObjectIdentifier(const ConfigObject::Ptr& object); static String GetObjectIdentifier(const ConfigObject::Ptr& object);
static String GetEnvironment(); static String GetEnvironment();
static Dictionary::Ptr SerializeVars(const CustomVarObject::Ptr& object); static Dictionary::Ptr SerializeVars(const CustomVarObject::Ptr& object);
static const char* GetNotificationTypeByEnum(NotificationType type);
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);