diff --git a/lib/icinga/apiactions.cpp b/lib/icinga/apiactions.cpp index 3f18c1fc4..62c7b8387 100644 --- a/lib/icinga/apiactions.cpp +++ b/lib/icinga/apiactions.cpp @@ -408,7 +408,7 @@ Dictionary::Ptr ApiActions::ScheduleDowntime(const ConfigObject::Ptr& object, << "Creating downtime for service " << hostService->GetName() << " on host " << host->GetName(); Downtime::Ptr serviceDowntime = Downtime::AddDowntime(hostService, author, comment, startTime, endTime, - fixed, triggerName, duration); + fixed, triggerName, duration, String(), String(), downtimeName); String serviceDowntimeName = serviceDowntime->GetName(); serviceDowntimes.push_back(new Dictionary({ @@ -490,6 +490,8 @@ Dictionary::Ptr ApiActions::RemoveDowntime(const ConfigObject::Ptr& object, auto author (HttpUtility::GetLastParameter(params, "author")); Checkable::Ptr checkable = dynamic_pointer_cast(object); + size_t childCount = 0; + if (checkable) { std::set downtimes = checkable->GetDowntimes(); @@ -499,8 +501,10 @@ Dictionary::Ptr ApiActions::RemoveDowntime(const ConfigObject::Ptr& object, downtime->SetRemovedBy(author); } + childCount += downtime->GetChildren().size(); + try { - Downtime::RemoveDowntime(downtime->GetName(), true); + Downtime::RemoveDowntime(downtime->GetName(), true, true); } catch (const invalid_downtime_removal_error& error) { Log(LogWarning, "ApiActions") << error.what(); @@ -508,7 +512,8 @@ Dictionary::Ptr ApiActions::RemoveDowntime(const ConfigObject::Ptr& object, } } - return ApiActions::CreateResult(200, "Successfully removed all downtimes for object '" + checkable->GetName() + "'."); + return ApiActions::CreateResult(200, "Successfully removed all downtimes for object '" + + checkable->GetName() + "' and " + std::to_string(childCount) + " child downtimes."); } Downtime::Ptr downtime = static_pointer_cast(object); @@ -521,12 +526,14 @@ Dictionary::Ptr ApiActions::RemoveDowntime(const ConfigObject::Ptr& object, downtime->SetRemovedBy(author); } + childCount += downtime->GetChildren().size(); + try { String downtimeName = downtime->GetName(); + Downtime::RemoveDowntime(downtimeName, true, true); - Downtime::RemoveDowntime(downtimeName, true); - - return ApiActions::CreateResult(200, "Successfully removed downtime '" + downtimeName + "'."); + return ApiActions::CreateResult(200, "Successfully removed downtime '" + downtimeName + + "' and " + std::to_string(childCount) + " child downtimes."); } catch (const invalid_downtime_removal_error& error) { Log(LogWarning, "ApiActions") << error.what(); diff --git a/lib/icinga/checkable-downtime.cpp b/lib/icinga/checkable-downtime.cpp index f0c1c9c97..3729c27ab 100644 --- a/lib/icinga/checkable-downtime.cpp +++ b/lib/icinga/checkable-downtime.cpp @@ -12,7 +12,7 @@ using namespace icinga; void Checkable::RemoveAllDowntimes() { for (const Downtime::Ptr& downtime : GetDowntimes()) { - Downtime::RemoveDowntime(downtime->GetName(), true, true); + Downtime::RemoveDowntime(downtime->GetName(), true, true, true); } } diff --git a/lib/icinga/downtime.cpp b/lib/icinga/downtime.cpp index 8e5ccabba..086435236 100644 --- a/lib/icinga/downtime.cpp +++ b/lib/icinga/downtime.cpp @@ -114,6 +114,11 @@ void Downtime::Start(bool runtimeCreated) checkable->RegisterDowntime(this); + Downtime::Ptr parent = GetByName(GetParent()); + + if (parent) + parent->RegisterChild(this); + if (runtimeCreated) OnDowntimeAdded(this); @@ -141,6 +146,11 @@ void Downtime::Stop(bool runtimeRemoved) { GetCheckable()->UnregisterDowntime(this); + Downtime::Ptr parent = GetByName(GetParent()); + + if (parent) + parent->UnregisterChild(this); + if (runtimeRemoved) OnDowntimeRemoved(this); @@ -217,7 +227,7 @@ int Downtime::GetNextDowntimeID() Downtime::Ptr Downtime::AddDowntime(const Checkable::Ptr& checkable, const String& author, const String& comment, double startTime, double endTime, bool fixed, const String& triggeredBy, double duration, - const String& scheduledDowntime, const String& scheduledBy, + const String& scheduledDowntime, const String& scheduledBy, const String& parent, const String& id, const MessageOrigin::Ptr& origin) { String fullName; @@ -237,6 +247,7 @@ Downtime::Ptr Downtime::AddDowntime(const Checkable::Ptr& checkable, const Strin attrs->Set("duration", duration); attrs->Set("triggered_by", triggeredBy); attrs->Set("scheduled_by", scheduledBy); + attrs->Set("parent", parent); attrs->Set("config_owner", scheduledDowntime); attrs->Set("entry_time", Utility::GetTime()); @@ -319,7 +330,7 @@ Downtime::Ptr Downtime::AddDowntime(const Checkable::Ptr& checkable, const Strin return downtime; } -void Downtime::RemoveDowntime(const String& id, bool cancelled, bool expired, const MessageOrigin::Ptr& origin) +void Downtime::RemoveDowntime(const String& id, bool includeChildren, bool cancelled, bool expired, const MessageOrigin::Ptr& origin) { Downtime::Ptr downtime = Downtime::GetByName(id); @@ -333,6 +344,12 @@ void Downtime::RemoveDowntime(const String& id, bool cancelled, bool expired, co "'. It is owned by scheduled downtime object '" + config_owner + "'")); } + if (includeChildren) { + for (const Downtime::Ptr& child : downtime->GetChildren()) { + Downtime::RemoveDowntime(child->GetName(), true, true); + } + } + downtime->SetWasCancelled(cancelled); Array::Ptr errors = new Array(); @@ -371,6 +388,24 @@ void Downtime::RemoveDowntime(const String& id, bool cancelled, bool expired, co msg << " (Reason: " << reason << ")."; } +void Downtime::RegisterChild(const Downtime::Ptr& downtime) +{ + std::unique_lock lock(m_ChildrenMutex); + m_Children.insert(downtime); +} + +void Downtime::UnregisterChild(const Downtime::Ptr& downtime) +{ + std::unique_lock lock(m_ChildrenMutex); + m_Children.erase(downtime); +} + +std::set Downtime::GetChildren() const +{ + std::unique_lock lock(m_ChildrenMutex); + return m_Children; +} + bool Downtime::CanBeTriggered() { if (IsInEffect() && IsTriggered()) @@ -456,7 +491,7 @@ void Downtime::DowntimesExpireTimerHandler() for (const Downtime::Ptr& downtime : downtimes) { /* Only remove downtimes which are activated after daemon start. */ if (downtime->IsActive() && (downtime->IsExpired() || !downtime->HasValidConfigOwner())) - RemoveDowntime(downtime->GetName(), false, true); + RemoveDowntime(downtime->GetName(), false, false, true); } } diff --git a/lib/icinga/downtime.hpp b/lib/icinga/downtime.hpp index 6aac86148..e99e20ed7 100644 --- a/lib/icinga/downtime.hpp +++ b/lib/icinga/downtime.hpp @@ -48,10 +48,14 @@ public: static Ptr AddDowntime(const intrusive_ptr& checkable, const String& author, const String& comment, double startTime, double endTime, bool fixed, const String& triggeredBy, double duration, const String& scheduledDowntime = String(), - const String& scheduledBy = String(), const String& id = String(), + const String& scheduledBy = String(), const String& parent = String(), const String& id = String(), const MessageOrigin::Ptr& origin = nullptr); - static void RemoveDowntime(const String& id, bool cancelled, bool expired = false, const MessageOrigin::Ptr& origin = nullptr); + static void RemoveDowntime(const String& id, bool includeChildren, bool cancelled, bool expired = false, const MessageOrigin::Ptr& origin = nullptr); + + void RegisterChild(const Downtime::Ptr& downtime); + void UnregisterChild(const Downtime::Ptr& downtime); + std::set GetChildren() const; void TriggerDowntime(); @@ -70,6 +74,9 @@ protected: private: ObjectImpl::Ptr m_Checkable; + std::set m_Children; + mutable std::mutex m_ChildrenMutex; + bool CanBeTriggered(); static void DowntimesStartTimerHandler(); diff --git a/lib/icinga/downtime.ti b/lib/icinga/downtime.ti index a015942d3..502f48fc2 100644 --- a/lib/icinga/downtime.ti +++ b/lib/icinga/downtime.ti @@ -63,6 +63,7 @@ class Downtime : ConfigObject < DowntimeNameComposer [config] Timestamp duration; [config] String triggered_by; [config] String scheduled_by; + [config] String parent; [state] Array::Ptr triggers { default {{{ return new Array(); }}} }; diff --git a/lib/icinga/externalcommandprocessor.cpp b/lib/icinga/externalcommandprocessor.cpp index 1c7e67bd5..e79607761 100644 --- a/lib/icinga/externalcommandprocessor.cpp +++ b/lib/icinga/externalcommandprocessor.cpp @@ -986,7 +986,7 @@ void ExternalCommandProcessor::DelSvcDowntime(double, const std::vector& String rid = Downtime::GetDowntimeIDFromLegacyID(id); try { - Downtime::RemoveDowntime(rid, true); + Downtime::RemoveDowntime(rid, false, true); Log(LogNotice, "ExternalCommandProcessor") << "Removed downtime ID " << arguments[0]; @@ -1094,7 +1094,7 @@ void ExternalCommandProcessor::DelHostDowntime(double, const std::vector String rid = Downtime::GetDowntimeIDFromLegacyID(id); try { - Downtime::RemoveDowntime(rid, true); + Downtime::RemoveDowntime(rid, false, true); Log(LogNotice, "ExternalCommandProcessor") << "Removed downtime ID " << arguments[0]; @@ -1129,7 +1129,7 @@ void ExternalCommandProcessor::DelDowntimeByHostName(double, const std::vectorGetDowntimes()) { try { String downtimeName = downtime->GetName(); - Downtime::RemoveDowntime(downtimeName, true); + Downtime::RemoveDowntime(downtimeName, false, true); Log(LogNotice, "ExternalCommandProcessor") << "Removed downtime '" << downtimeName << "'."; @@ -1151,7 +1151,7 @@ void ExternalCommandProcessor::DelDowntimeByHostName(double, const std::vectorGetName(); - Downtime::RemoveDowntime(downtimeName, true); + Downtime::RemoveDowntime(downtimeName, false, true); Log(LogNotice, "ExternalCommandProcessor") << "Removed downtime '" << downtimeName << "'."; diff --git a/lib/icingadb/icingadb-objects.cpp b/lib/icingadb/icingadb-objects.cpp index 9d1405ff8..83683141a 100644 --- a/lib/icingadb/icingadb-objects.cpp +++ b/lib/icingadb/icingadb-objects.cpp @@ -1386,6 +1386,11 @@ bool IcingaDB::PrepareObject(const ConfigObject::Ptr& object, Dictionary::Ptr& a attributes->Set("scheduled_by", scheduledBy); } + auto parent (Downtime::GetByName(downtime->GetParent())); + if (parent) { + attributes->Set("parent_id", GetObjectIdentifier(parent)); + } + return true; } @@ -1739,6 +1744,13 @@ void IcingaDB::SendStartedDowntime(const Downtime::Ptr& downtime) xAdd.emplace_back(GetObjectIdentifier(endpoint)); } + auto parent (Downtime::GetByName(downtime->GetParent())); + + if (parent) { + xAdd.emplace_back("parent_id"); + xAdd.emplace_back(GetObjectIdentifier(parent)); + } + m_Rcon->FireAndForgetQuery(std::move(xAdd), Prio::History); } @@ -1812,6 +1824,13 @@ void IcingaDB::SendRemovedDowntime(const Downtime::Ptr& downtime) xAdd.emplace_back(GetObjectIdentifier(endpoint)); } + auto parent (Downtime::GetByName(downtime->GetParent())); + + if (parent) { + xAdd.emplace_back("parent_id"); + xAdd.emplace_back(GetObjectIdentifier(parent)); + } + m_Rcon->FireAndForgetQuery(std::move(xAdd), Prio::History); }