]> granicus.if.org Git - icinga2/commitdiff
Put running downtimes in effect 6704/head
authorEdgar Fuß <ef@math.uni-bonn.de>
Thu, 18 Oct 2018 16:42:21 +0000 (18:42 +0200)
committerGitHub <noreply@github.com>
Thu, 18 Oct 2018 16:42:21 +0000 (18:42 +0200)
If Icinga2 was restarted with a newly configured downtime that should
be in effect at the time of restart, the should-be-running segment of
it was not put into effect.

Add new LegacyTimePeriod::FindRunningSegment() and
ScheduledDowntime::FindRunningSegment() functions, call the latter in
ScheduledDowntime::CreateNextDowntime() before trying the old
ScheduledDowntime::FindNextSegment().

lib/icinga/legacytimeperiod.cpp
lib/icinga/legacytimeperiod.hpp
lib/icinga/scheduleddowntime.cpp
lib/icinga/scheduleddowntime.hpp

index 777a1cc10ebca0ab8ba1ad1fee9eefe44a3207db..7751a7e02e5e812e47c60a8fbb5070ec62fafa0e 100644 (file)
@@ -388,6 +388,56 @@ void LegacyTimePeriod::ProcessTimeRanges(const String& timeranges, tm *reference
        }
 }
 
+Dictionary::Ptr LegacyTimePeriod::FindRunningSegment(const String& daydef, const String& timeranges, tm *reference)
+{
+       tm begin, end, iter;
+       time_t tsend, tsiter, tsref;
+       int stride;
+
+       tsref = mktime(reference);
+
+       ParseTimeRange(daydef, &begin, &end, &stride, reference);
+
+       iter = begin;
+
+       tsend = mktime(&end);
+
+       do {
+               if (IsInTimeRange(&begin, &end, stride, &iter)) {
+                       Array::Ptr segments = new Array();
+                       ProcessTimeRanges(timeranges, &iter, segments);
+
+                       Dictionary::Ptr bestSegment;
+                       double bestEnd;
+
+                       ObjectLock olock(segments);
+                       for (const Dictionary::Ptr& segment : segments) {
+                               double begin = segment->Get("begin");
+                               double end = segment->Get("end");
+
+                               if (begin >= tsref || end < tsref)
+                                       continue;
+
+                               if (!bestSegment || end > bestEnd) {
+                                       bestSegment = segment;
+                                       bestEnd = end;
+                               }
+                       }
+
+                       if (bestSegment)
+                               return bestSegment;
+               }
+
+               iter.tm_mday++;
+               iter.tm_hour = 0;
+               iter.tm_min = 0;
+               iter.tm_sec = 0;
+               tsiter = mktime(&iter);
+       } while (tsiter < tsend);
+
+       return nullptr;
+}
+
 Dictionary::Ptr LegacyTimePeriod::FindNextSegment(const String& daydef, const String& timeranges, tm *reference)
 {
        tm begin, end, iter, ref;
index 9bec5b68c379ef4923ae536efad09bef95e86bed..57f3cae75294d090d20bcf68d1e410c24d207edd 100644 (file)
@@ -48,6 +48,7 @@ public:
        static Dictionary::Ptr ProcessTimeRange(const String& timerange, tm *reference);
        static void ProcessTimeRanges(const String& timeranges, tm *reference, const Array::Ptr& result);
        static Dictionary::Ptr FindNextSegment(const String& daydef, const String& timeranges, tm *reference);
+       static Dictionary::Ptr FindRunningSegment(const String& daydef, const String& timeranges, tm *reference);
 
 private:
        LegacyTimePeriod();
index be463613e38383927b1a5071ca64d83bf58788cb..1809343bdc3c6f23c41b1e70850cecf62c8bba6f 100644 (file)
@@ -116,6 +116,67 @@ Checkable::Ptr ScheduledDowntime::GetCheckable() const
                return host->GetServiceByShortName(GetServiceName());
 }
 
+std::pair<double, double> ScheduledDowntime::FindRunningSegment(double minEnd)
+{
+       time_t refts = Utility::GetTime();
+       tm reference = Utility::LocalTime(refts);
+
+       Log(LogDebug, "ScheduledDowntime")
+           << "Finding running scheduled downtime segment for time " << refts
+           << " (minEnd " << (minEnd > 0 ? Utility::FormatDateTime("%c", minEnd) : "-") << ")";
+
+       Dictionary::Ptr ranges = GetRanges();
+
+       if (!ranges)
+               return std::make_pair(0, 0);
+
+       Array::Ptr segments = new Array();
+
+       Dictionary::Ptr bestSegment;
+       double bestBegin, bestEnd;
+       double now = Utility::GetTime();
+
+       ObjectLock olock(ranges);
+
+       /* Find the longest lasting (and longer than minEnd, if given) segment that's already running */  
+       for (const Dictionary::Pair& kv : ranges) {
+               Log(LogDebug, "ScheduledDowntime")
+                   << "Evaluating (running?) segment: " << kv.first << ": " << kv.second;
+
+               Dictionary::Ptr segment = LegacyTimePeriod::FindRunningSegment(kv.first, kv.second, &reference);
+
+               if (!segment)
+                       continue;
+
+               double begin = segment->Get("begin");
+               double end = segment->Get("end");
+
+               Log(LogDebug, "ScheduledDowntime")
+                   << "Considering (running?) segment: " << Utility::FormatDateTime("%c", begin) << " -> " << Utility::FormatDateTime("%c", end);
+
+               if (begin >= now || end < now) {
+                       Log(LogDebug, "ScheduledDowntime") << "not running.";
+                       continue;
+               }
+               if (minEnd && end <= minEnd) {
+                       Log(LogDebug, "ScheduledDowntime") << "ending too early.";
+                       continue;
+               }
+
+               if (!bestSegment || end > bestEnd) {
+                       Log(LogDebug, "ScheduledDowntime") << "(best match yet)";
+                       bestSegment = segment;
+                       bestBegin = begin;
+                       bestEnd = end;
+               }
+       }
+
+       if (bestSegment)
+               return std::make_pair(bestBegin, bestEnd);
+
+       return std::make_pair(0, 0);
+}
+
 std::pair<double, double> ScheduledDowntime::FindNextSegment()
 {
        time_t refts = Utility::GetTime();
@@ -132,10 +193,12 @@ std::pair<double, double> ScheduledDowntime::FindNextSegment()
        Array::Ptr segments = new Array();
 
        Dictionary::Ptr bestSegment;
-       double bestBegin;
+       double bestBegin, bestEnd;
        double now = Utility::GetTime();
 
        ObjectLock olock(ranges);
+
+       /* Find the segment starting earliest */
        for (const Dictionary::Pair& kv : ranges) {
                Log(LogDebug, "ScheduledDowntime")
                        << "Evaluating segment: " << kv.first << ": " << kv.second;
@@ -145,29 +208,40 @@ std::pair<double, double> ScheduledDowntime::FindNextSegment()
                if (!segment)
                        continue;
 
-               Log(LogDebug, "ScheduledDowntime")
-                       << "Considering segment: " << Utility::FormatDateTime("%c", segment->Get("begin")) << " -> " << Utility::FormatDateTime("%c", segment->Get("end"));
-
                double begin = segment->Get("begin");
+               double end = segment->Get("end");
 
-               if (begin < now)
+               Log(LogDebug, "ScheduledDowntime")
+                       << "Considering segment: " << Utility::FormatDateTime("%c", begin) << " -> " << Utility::FormatDateTime("%c", end);
+
+               if (begin < now) {
+                       Log(LogDebug, "ScheduledDowntime") << "already running.";
                        continue;
+               }
 
                if (!bestSegment || begin < bestBegin) {
+                       Log(LogDebug, "ScheduledDowntime") << "(best match yet)";
                        bestSegment = segment;
                        bestBegin = begin;
+                       bestEnd = end;
                }
        }
 
        if (bestSegment)
-               return std::make_pair(bestSegment->Get("begin"), bestSegment->Get("end"));
-       else
-               return std::make_pair(0, 0);
+               return std::make_pair(bestBegin, bestEnd);
+
+       return std::make_pair(0, 0);
 }
 
 void ScheduledDowntime::CreateNextDowntime()
 {
+       double minEnd = 0;
+
        for (const Downtime::Ptr& downtime : GetCheckable()->GetDowntimes()) {
+               double end = downtime->GetEndTime();
+               if (end > minEnd)
+                       minEnd = end;
+
                if (downtime->GetScheduledBy() != GetName() ||
                        downtime->GetStartTime() < Utility::GetTime())
                        continue;
@@ -179,10 +253,12 @@ void ScheduledDowntime::CreateNextDowntime()
        Log(LogDebug, "ScheduledDowntime")
                << "Creating new Downtime for ScheduledDowntime \"" << GetName() << "\"";
 
-       std::pair<double, double> segment = FindNextSegment();
-
-       if (segment.first == 0 && segment.second == 0)
-               return;
+       std::pair<double, double> segment = FindRunningSegment(minEnd);
+       if (segment.first == 0 && segment.second == 0) {
+               segment = FindNextSegment();
+               if (segment.first == 0 && segment.second == 0)
+                       return;
+       }
 
        String downtimeName = Downtime::AddDowntime(GetCheckable(), GetAuthor(), GetComment(),
                segment.first, segment.second,
index 7fbcd1e126b74ce5b8899ecb8954cd5fb86536b6..a02ff6de2ffb2055e11554c132c7cab7f5b7bc0a 100644 (file)
@@ -58,6 +58,7 @@ protected:
 private:
        static void TimerProc();
 
+       std::pair<double, double> FindRunningSegment(double minEnd = 0);
        std::pair<double, double> FindNextSegment();
        void CreateNextDowntime();