diff --git a/lib/db_ido/dbevents.cpp b/lib/db_ido/dbevents.cpp index 6aa4ec9f4..7c7175fce 100644 --- a/lib/db_ido/dbevents.cpp +++ b/lib/db_ido/dbevents.cpp @@ -61,6 +61,8 @@ void DbEvents::StaticInitialize(void) Checkable::OnEnablePerfdataChanged.connect(boost::bind(&DbEvents::EnablePerfdataChangedHandler, _1, _2)); Checkable::OnEnableFlappingChanged.connect(boost::bind(&DbEvents::EnableFlappingChangedHandler, _1, _2)); + Checkable::OnReachabilityChanged.connect(boost::bind(&DbEvents::ReachabilityChangedHandler, _1, _2, _3)); + /* History */ Checkable::OnCommentAdded.connect(boost::bind(&DbEvents::AddCommentHistory, _1, _2)); Checkable::OnDowntimeAdded.connect(boost::bind(&DbEvents::AddDowntimeHistory, _1, _2)); @@ -191,6 +193,52 @@ void DbEvents::LastNotificationChangedHandler(const Notification::Ptr& notificat DbObject::OnQuery(query1); } +void DbEvents::ReachabilityChangedHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, std::set children) +{ + int is_reachable = 0; + + if (cr->GetState() == ServiceOK) + is_reachable = 1; + + Log(LogDebug, "DbEvents") + << "Updating reachability for checkable '" << checkable->GetName() << "': " << (is_reachable ? "" : "not" ) << " reachable for " << children.size() << " children."; + + BOOST_FOREACH(const Checkable::Ptr& child, children) { + Log(LogDebug, "DbEvents") + << "Updating reachability for checkable '" << child->GetName() << "': " << (is_reachable ? "" : "not" ) << " reachable."; + + Host::Ptr host; + Service::Ptr service; + tie(host, service) = GetHostService(child); + + DbQuery query1; + if (service) + query1.Table = "servicestatus"; + else + query1.Table = "hoststatus"; + + query1.Type = DbQueryInsert | DbQueryUpdate; + query1.Category = DbCatState; + query1.StatusUpdate = true; + query1.Object = DbObject::GetOrCreateByObject(child); + + Dictionary::Ptr fields1 = new Dictionary(); + fields1->Set("is_reachable", is_reachable); + + query1.Fields = fields1; + + query1.WhereCriteria = new Dictionary(); + if (service) + query1.WhereCriteria->Set("service_object_id", service); + else + query1.WhereCriteria->Set("host_object_id", host); + + query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */ + + DbObject::OnQuery(query1); + } +} + /* enable changed events */ void DbEvents::EnableActiveChecksChangedHandler(const Checkable::Ptr& checkable, bool enabled) { diff --git a/lib/db_ido/dbevents.hpp b/lib/db_ido/dbevents.hpp index 3044bebdf..586fe18ea 100644 --- a/lib/db_ido/dbevents.hpp +++ b/lib/db_ido/dbevents.hpp @@ -102,6 +102,8 @@ public: static void RemoveAcknowledgement(const Checkable::Ptr& checkable); static void AddAcknowledgementInternal(const Checkable::Ptr& checkable, AcknowledgementType type, bool add); + static void ReachabilityChangedHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, std::set children); + /* comment, downtime, acknowledgement history */ static void AddCommentHistory(const Checkable::Ptr& checkable, const Comment::Ptr& comment); static void AddDowntimeHistory(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime); diff --git a/lib/icinga/checkable-check.cpp b/lib/icinga/checkable-check.cpp index 4da2f5e1e..60a39ef54 100644 --- a/lib/icinga/checkable-check.cpp +++ b/lib/icinga/checkable-check.cpp @@ -37,6 +37,7 @@ using namespace icinga; boost::signals2::signal Checkable::OnNewCheckResult; boost::signals2::signal Checkable::OnStateChange; +boost::signals2::signal, const MessageOrigin&)> Checkable::OnReachabilityChanged; boost::signals2::signal Checkable::OnNotificationsRequested; boost::signals2::signal Checkable::OnNextCheckChanged; boost::signals2::signal Checkable::OnForceNextCheckChanged; @@ -293,6 +294,8 @@ void Checkable::ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrig long attempt = 1; + std::set children = GetChildren(); + if (!old_cr) { SetStateType(StateTypeHard); } else if (cr->GetState() == ServiceOK) { @@ -306,6 +309,10 @@ void Checkable::ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrig ResetNotificationNumbers(); SetLastStateOK(Utility::GetTime()); + + /* update reachability for child objects in OK state */ + if (!children.empty()) + OnReachabilityChanged(this, cr, children, origin); } else { if (old_attempt >= GetMaxCheckAttempts()) { SetStateType(StateTypeHard); @@ -330,6 +337,10 @@ void Checkable::ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrig SetLastStateUnknown(Utility::GetTime()); break; } + + /* update reachability for child objects in NOT-OK state */ + if (!children.empty()) + OnReachabilityChanged(this, cr, children, origin); } if (!reachable) diff --git a/lib/icinga/checkable.hpp b/lib/icinga/checkable.hpp index 9ea2bb104..0d603cd7b 100644 --- a/lib/icinga/checkable.hpp +++ b/lib/icinga/checkable.hpp @@ -168,6 +168,7 @@ public: static boost::signals2::signal OnNewCheckResult; static boost::signals2::signal OnStateChange; + static boost::signals2::signal, const MessageOrigin&)> OnReachabilityChanged; static boost::signals2::signal OnNotificationsRequested; static boost::signals2::signal&, diff --git a/test/config/7683.conf b/test/config/7683.conf new file mode 100644 index 000000000..4e1a9869b --- /dev/null +++ b/test/config/7683.conf @@ -0,0 +1,27 @@ +object Host "7683-parent" { + check_command = "dummy" + vars.dummy_state = 0 +} + + +object Host "7683-child1" { + check_command = "dummy" + vars.dummy_state = 0 +} + +object Host "7683-child2" { + check_command = "dummy" + vars.dummy_state = 0 +} + +object Service "7683-service" { + check_command = "dummy" + host_name = "7683-parent" + vars.dummy_state = 0 +} + +apply Dependency "test-host" to Host { + parent_host_name = "7683-parent" + assign where match("7683-child*", host.name) +} +