Put running downtimes in effect

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().
This commit is contained in:
Edgar Fuß 2018-10-18 18:42:21 +02:00 committed by Michael Friedrich
parent e76ec0d42e
commit 3b4dc854cf
4 changed files with 140 additions and 12 deletions

View 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;

View 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();

View File

@ -117,6 +117,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();
@ -133,10 +194,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;
@ -146,24 +209,29 @@ 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()
@ -175,7 +243,13 @@ void ScheduledDowntime::CreateNextDowntime()
return;
}
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;
@ -187,10 +261,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,

View 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();