From 9cdbbf4edec875ec359c773b5058aedd78c53afe Mon Sep 17 00:00:00 2001 From: Alvar Penning Date: Thu, 5 Jun 2025 13:35:12 +0200 Subject: [PATCH] IcingaDB::CalcEventID: No milliseconds as eventTime CalcEventID's internal logic uses the TimestampToMilliseconds function to convert the given eventTime to milliseconds. Within this function, the timestamp is capped to prevent an overflow. On three occasions, the input timestamp given to CalcEventID had already been converted using TimestampToMilliseconds. The second TimestampToMilliseconds function then checked the value and always returned the capped maximum value. Consequently, CalcEventID returned the same hash value for different timestamps. This affected SendFlappingChange, SendAcknowledgementSet, and SendAcknowledgementCleared. For example, when two acknowledgments were created for the same service, the calculated event_id representing the history table row would be identical. Fixes #10465 --- lib/icingadb/icingadb-objects.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/lib/icingadb/icingadb-objects.cpp b/lib/icingadb/icingadb-objects.cpp index 56b74a3c1..93e226a33 100644 --- a/lib/icingadb/icingadb-objects.cpp +++ b/lib/icingadb/icingadb-objects.cpp @@ -2452,17 +2452,17 @@ void IcingaDB::SendFlappingChange(const Checkable::Ptr& checkable, double change xAdd.emplace_back(GetObjectIdentifier(endpoint)); } - long long startTime; + double startTime; if (checkable->IsFlapping()) { - startTime = TimestampToMilliseconds(changeTime); + startTime = changeTime; xAdd.emplace_back("event_type"); xAdd.emplace_back("flapping_start"); xAdd.emplace_back("percent_state_change_start"); xAdd.emplace_back(Convert::ToString(checkable->GetFlappingCurrent())); } else { - startTime = TimestampToMilliseconds(flappingLastChange); + startTime = flappingLastChange; xAdd.emplace_back("event_type"); xAdd.emplace_back("flapping_end"); @@ -2472,12 +2472,14 @@ void IcingaDB::SendFlappingChange(const Checkable::Ptr& checkable, double change xAdd.emplace_back(Convert::ToString(checkable->GetFlappingCurrent())); } + long long startTs = TimestampToMilliseconds(startTime); + xAdd.emplace_back("start_time"); - xAdd.emplace_back(Convert::ToString(startTime)); + xAdd.emplace_back(Convert::ToString(startTs)); xAdd.emplace_back("event_id"); xAdd.emplace_back(CalcEventID(checkable->IsFlapping() ? "flapping_start" : "flapping_end", checkable, startTime)); xAdd.emplace_back("id"); - xAdd.emplace_back(HashValue(new Array({m_EnvironmentId, checkable->GetName(), startTime}))); + xAdd.emplace_back(HashValue(new Array({m_EnvironmentId, checkable->GetName(), startTs}))); m_HistoryBulker.ProduceOne(std::move(xAdd)); } @@ -2555,14 +2557,14 @@ void IcingaDB::SendAcknowledgementSet(const Checkable::Ptr& checkable, const Str xAdd.emplace_back(Convert::ToString(TimestampToMilliseconds(expiry))); } - long long setTime = TimestampToMilliseconds(changeTime); + long long setTs = TimestampToMilliseconds(changeTime); xAdd.emplace_back("set_time"); - xAdd.emplace_back(Convert::ToString(setTime)); + xAdd.emplace_back(Convert::ToString(setTs)); xAdd.emplace_back("event_id"); - xAdd.emplace_back(CalcEventID("ack_set", checkable, setTime)); + xAdd.emplace_back(CalcEventID("ack_set", checkable, changeTime)); xAdd.emplace_back("id"); - xAdd.emplace_back(HashValue(new Array({m_EnvironmentId, checkable->GetName(), setTime}))); + xAdd.emplace_back(HashValue(new Array({m_EnvironmentId, checkable->GetName(), setTs}))); m_HistoryBulker.ProduceOne(std::move(xAdd)); } @@ -2605,14 +2607,14 @@ void IcingaDB::SendAcknowledgementCleared(const Checkable::Ptr& checkable, const xAdd.emplace_back(GetObjectIdentifier(endpoint)); } - long long setTime = TimestampToMilliseconds(ackLastChange); + long long setTs = TimestampToMilliseconds(ackLastChange); xAdd.emplace_back("set_time"); - xAdd.emplace_back(Convert::ToString(setTime)); + xAdd.emplace_back(Convert::ToString(setTs)); xAdd.emplace_back("event_id"); - xAdd.emplace_back(CalcEventID("ack_clear", checkable, setTime)); + xAdd.emplace_back(CalcEventID("ack_clear", checkable, ackLastChange)); xAdd.emplace_back("id"); - xAdd.emplace_back(HashValue(new Array({m_EnvironmentId, checkable->GetName(), setTime}))); + xAdd.emplace_back(HashValue(new Array({m_EnvironmentId, checkable->GetName(), setTs}))); if (!removedBy.IsEmpty()) { xAdd.emplace_back("cleared_by");