Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Put newly configured already running ScheduledDowntime immediately in effect #6704

Merged
merged 3 commits into from
Oct 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions lib/icinga/legacytimeperiod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions lib/icinga/legacytimeperiod.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class LegacyTimePeriod
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();
Expand Down
107 changes: 88 additions & 19 deletions lib/icinga/scheduleddowntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -132,42 +193,55 @@ 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 << " at ";
<< "Evaluating segment: " << kv.first << ": " << kv.second;

Dictionary::Ptr segment = LegacyTimePeriod::FindNextSegment(kv.first, kv.second, &reference);

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");

Log(LogDebug, "ScheduledDowntime")
<< "Considering segment: " << Utility::FormatDateTime("%c", begin) << " -> " << Utility::FormatDateTime("%c", end);

if (begin < now)
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;
Expand All @@ -179,16 +253,11 @@ void ScheduledDowntime::CreateNextDowntime()
Log(LogDebug, "ScheduledDowntime")
<< "Creating new Downtime for ScheduledDowntime \"" << GetName() << "\"";

std::pair<double, double> segment = FindNextSegment();

std::pair<double, double> segment = FindRunningSegment(minEnd);
if (segment.first == 0 && segment.second == 0) {
tm reference = Utility::LocalTime(Utility::GetTime());
reference.tm_mday++;
reference.tm_hour = 0;
reference.tm_min = 0;
reference.tm_sec = 0;

return;
segment = FindNextSegment();
if (segment.first == 0 && segment.second == 0)
return;
}

String downtimeName = Downtime::AddDowntime(GetCheckable(), GetAuthor(), GetComment(),
Expand Down Expand Up @@ -261,4 +330,4 @@ void ScheduledDowntime::ValidateChildOptions(const Lazy<Value>& lvalue, const Va
} catch (const std::exception&) {
BOOST_THROW_EXCEPTION(ValidationError(this, { "child_options" }, "Invalid child_options specified"));
}
}
}
1 change: 1 addition & 0 deletions lib/icinga/scheduleddowntime.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class ScheduledDowntime final : public ObjectImpl<ScheduledDowntime>
private:
static void TimerProc();

std::pair<double, double> FindRunningSegment(double minEnd = 0);
std::pair<double, double> FindNextSegment();
void CreateNextDowntime();

Expand Down