diff --git a/lib/icinga/downtime.cpp b/lib/icinga/downtime.cpp index 914531339..8e5ccabba 100644 --- a/lib/icinga/downtime.cpp +++ b/lib/icinga/downtime.cpp @@ -246,6 +246,12 @@ Downtime::Ptr Downtime::AddDowntime(const Checkable::Ptr& checkable, const Strin if (localZone) { attrs->Set("authoritative_zone", localZone->GetName()); } + + auto sd (ScheduledDowntime::GetByName(scheduledDowntime)); + + if (sd) { + attrs->Set("config_owner_hash", sd->HashDowntimeOptions()); + } } Host::Ptr host; diff --git a/lib/icinga/downtime.ti b/lib/icinga/downtime.ti index ea3c1a5ee..a015942d3 100644 --- a/lib/icinga/downtime.ti +++ b/lib/icinga/downtime.ti @@ -69,6 +69,7 @@ class Downtime : ConfigObject < DowntimeNameComposer [state] int legacy_id; [state] bool was_cancelled; [config] String config_owner; + [config] String config_owner_hash; [config] String authoritative_zone; [no_user_view, no_user_modify] String removed_by; diff --git a/lib/icinga/scheduleddowntime.cpp b/lib/icinga/scheduleddowntime.cpp index ae38ca9b6..972a428ad 100644 --- a/lib/icinga/scheduleddowntime.cpp +++ b/lib/icinga/scheduleddowntime.cpp @@ -6,13 +6,17 @@ #include "icinga/downtime.hpp" #include "icinga/service.hpp" #include "base/timer.hpp" +#include "base/tlsutility.hpp" #include "base/configtype.hpp" #include "base/utility.hpp" #include "base/objectlock.hpp" +#include "base/object-packer.hpp" +#include "base/serializer.hpp" #include "base/convert.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include +#include using namespace icinga; @@ -94,6 +98,15 @@ void ScheduledDowntime::TimerProc() Log(LogCritical, "ScheduledDowntime") << "Exception occurred during creation of next downtime for scheduled downtime '" << sd->GetName() << "': " << DiagnosticInformation(ex, false); + continue; + } + + try { + sd->RemoveObsoleteDowntimes(); + } catch (const std::exception& ex) { + Log(LogCritical, "ScheduledDowntime") + << "Exception occurred during removal of obsolete downtime for scheduled downtime '" + << sd->GetName() << "': " << DiagnosticInformation(ex, false); } } } @@ -236,11 +249,16 @@ void ScheduledDowntime::CreateNextDowntime() } double minEnd = 0; + auto downtimeOptionsHash (HashDowntimeOptions()); for (const Downtime::Ptr& downtime : GetCheckable()->GetDowntimes()) { if (downtime->GetScheduledBy() != GetName()) continue; + auto configOwnerHash (downtime->GetConfigOwnerHash()); + if (!configOwnerHash.IsEmpty() && configOwnerHash != downtimeOptionsHash) + continue; + double end = downtime->GetEndTime(); if (end > minEnd) minEnd = end; @@ -292,6 +310,24 @@ void ScheduledDowntime::CreateNextDowntime() } } +void ScheduledDowntime::RemoveObsoleteDowntimes() +{ + auto name (GetName()); + auto downtimeOptionsHash (HashDowntimeOptions()); + + // Just to be sure start and removal don't happen at the same time + auto threshold (Utility::GetTime() + 5 * 60); + + for (const Downtime::Ptr& downtime : GetCheckable()->GetDowntimes()) { + if (downtime->GetScheduledBy() == name && downtime->GetStartTime() > threshold) { + auto configOwnerHash (downtime->GetConfigOwnerHash()); + + if (!configOwnerHash.IsEmpty() && configOwnerHash != downtimeOptionsHash) + Downtime::RemoveDowntime(downtime->GetName(), false, true); + } + } +} + void ScheduledDowntime::ValidateRanges(const Lazy& lvalue, const ValidationUtils& utils) { ObjectImpl::ValidateRanges(lvalue, utils); @@ -333,6 +369,22 @@ void ScheduledDowntime::ValidateChildOptions(const Lazy& lvalue, const Va } } +static const std::set l_SDDowntimeOptions ({ + "author", "child_options", "comment", "duration", "fixed", "ranges", "vars" +}); + +String ScheduledDowntime::HashDowntimeOptions() +{ + Dictionary::Ptr allOpts = Serialize(this, FAConfig); + Dictionary::Ptr opts = new Dictionary(); + + for (auto& opt : l_SDDowntimeOptions) { + opts->Set(opt, allOpts->Get(opt)); + } + + return SHA256(PackObject(opts)); +} + bool ScheduledDowntime::AllConfigIsLoaded() { return m_AllConfigLoaded.load(); diff --git a/lib/icinga/scheduleddowntime.hpp b/lib/icinga/scheduleddowntime.hpp index 90e12d240..f8d8e0840 100644 --- a/lib/icinga/scheduleddowntime.hpp +++ b/lib/icinga/scheduleddowntime.hpp @@ -35,6 +35,7 @@ public: void ValidateRanges(const Lazy& lvalue, const ValidationUtils& utils) override; void ValidateChildOptions(const Lazy& lvalue, const ValidationUtils& utils) override; + String HashDowntimeOptions(); protected: void OnAllConfigLoaded() override; @@ -46,6 +47,7 @@ private: std::pair FindRunningSegment(double minEnd = 0); std::pair FindNextSegment(); void CreateNextDowntime(); + void RemoveObsoleteDowntimes(); static std::atomic m_AllConfigLoaded;