mirror of https://github.com/Icinga/icinga2.git
Implement exclude and include ability for TimePeriod objects
This feature allows to exclude and include specific time period objects and their time ranges from an existing time period object. This comes in handy when e.g. excluding holidays. fixes #7355 Signed-off-by: Michael Friedrich <michael.friedrich@netways.de>
This commit is contained in:
parent
d49b63d2ab
commit
54e1c8a9d5
1
AUTHORS
1
AUTHORS
|
@ -71,6 +71,7 @@ Paul Richards <paul@minimoo.org>
|
|||
Per von Zweigbergk <pvz@itassistans.se>
|
||||
Petr Ruzicka <petr.ruzicka@gmail.com>
|
||||
Phil Hutchinson <phil@volumedia.co.uk>
|
||||
Philipp Dallig <philipp.dallig@gmail.com>
|
||||
Ralph Breier <ralph.breier@roedl.com>
|
||||
Reto Zeder <reto.zeder@arcade.ch>
|
||||
Ricardo Bartels <ricardo@bitchbrothers.com>
|
||||
|
|
|
@ -132,8 +132,9 @@ re-notify if the problem persists.
|
|||
|
||||
## <a id="timeperiods"></a> Time Periods
|
||||
|
||||
Time Periods define time ranges in Icinga where event actions are
|
||||
triggered, for example whether a service check is executed or not within
|
||||
[Time Periods](6-object-types.md#objecttype-timeperiod) define
|
||||
time ranges in Icinga where event actions are triggered, for
|
||||
example whether a service check is executed or not within
|
||||
the `check_period` attribute. Or a notification should be sent to
|
||||
users or not, filtered by the `period` and `notification_period`
|
||||
configuration attributes for `Notification` and `User` objects.
|
||||
|
@ -208,6 +209,67 @@ Use the `period` attribute to assign time periods to
|
|||
period = "workhours"
|
||||
}
|
||||
|
||||
### <a id="timeperiods-includes-excludes"></a> Time Periods Inclusion and Exclusion
|
||||
|
||||
Sometimes it is necessary to exclude certain time ranges from
|
||||
your default time period definitions. For example if you don't
|
||||
want to send out any notification during the holiday season,
|
||||
or if you only want to allow small time windows for executed checks.
|
||||
|
||||
The [TimePeriod object](6-object-types.md#objecttype-timeperiod)
|
||||
provides the `includes` and `excludes` attributes to solve this issue.
|
||||
`prefer_includes` defines whether included or excluded time periods are
|
||||
preferred.
|
||||
|
||||
The following example defines a time period called `holidays` where
|
||||
notifications should be supressed:
|
||||
|
||||
object TimePeriod "holidays" {
|
||||
import "legacy-timeperiod"
|
||||
|
||||
ranges = {
|
||||
"january 1" = "00:00-24:00" //new year's day
|
||||
"july 4" = "00:00-24:00" //independence day
|
||||
"december 25" = "00:00-24:00" //christmas
|
||||
"december 31" = "18:00-24:00" //new year's eve (6pm+)
|
||||
"2017-04-16" = "00:00-24:00" //easter 2017
|
||||
"monday -1 may" = "00:00-24:00" //memorial day (last monday in may)
|
||||
"monday 1 september" = "00:00-24:00" //labor day (1st monday in september)
|
||||
"thursday 4 november" = "00:00-24:00" //thanksgiving (4th thursday in november)
|
||||
}
|
||||
}
|
||||
|
||||
In addition to that the time period `weekends` defines an additional
|
||||
time window which should be excluded from notifications:
|
||||
|
||||
object TimePeriod "weekends-excluded" {
|
||||
import "legacy-timeperiod"
|
||||
|
||||
ranges = {
|
||||
"saturday" = "00:00-09:00,18:00-24:00"
|
||||
"sunday" = "00:00-09:00,18:00-24:00"
|
||||
}
|
||||
}
|
||||
|
||||
The time period `prod-notification` defines the default time ranges
|
||||
and adds the excluded time period names as an array.
|
||||
|
||||
object TimePeriod "prod-notification" {
|
||||
import "legacy-timeperiod"
|
||||
|
||||
excludes = [ "holidays", "weekends-excluded" ]
|
||||
|
||||
ranges = {
|
||||
"monday" = "00:00-24:00"
|
||||
"tuesday" = "00:00-24:00"
|
||||
"wednesday" = "00:00-24:00"
|
||||
"thursday" = "00:00-24:00"
|
||||
"friday" = "00:00-24:00"
|
||||
"saturday" = "00:00-24:00"
|
||||
"sunday" = "00:00-24:00"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
## <a id="use-functions-object-config"></a> Use Functions in Object Configuration
|
||||
|
||||
|
|
|
@ -1380,6 +1380,9 @@ Configuration Attributes:
|
|||
display_name |**Optional.** A short description of the time period.
|
||||
update |**Required.** The "update" script method takes care of updating the internal representation of the time period. In virtually all cases you should import the "legacy-timeperiod" template to take care of this setting.
|
||||
ranges |**Required.** A dictionary containing information which days and durations apply to this timeperiod.
|
||||
prefer_includes |**Optional.** Boolean whether to prefer timeperiods `includes` or `excludes`. Default to true.
|
||||
excludes |**Optional.** An array of timeperiods, which should exclude from your timerange.
|
||||
includes |**Optional.** An array of timeperiods, which should include into your timerange
|
||||
|
||||
The `/etc/icinga2/conf.d/timeperiods.conf` file is usually used to define
|
||||
timeperiods including this one.
|
||||
|
|
|
@ -162,7 +162,8 @@ void CheckerComponent::CheckThreadProc(void)
|
|||
|
||||
if (tp && !tp->IsInside(Utility::GetTime())) {
|
||||
Log(LogNotice, "CheckerComponent")
|
||||
<< "Skipping check for object '" << checkable->GetName() << "': not in check_period";
|
||||
<< "Skipping check for object '" << checkable->GetName()
|
||||
<< "': not in check period '" << tp->GetName() << "'";
|
||||
check = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -250,7 +250,8 @@ void Notification::BeginExecuteNotification(NotificationType type, const CheckRe
|
|||
|
||||
if (tp && !tp->IsInside(Utility::GetTime())) {
|
||||
Log(LogNotice, "Notification")
|
||||
<< "Not sending notifications for notification object '" << GetName() << "': not in timeperiod";
|
||||
<< "Not sending notifications for notification object '" << GetName()
|
||||
<< "': not in timeperiod '" << tp->GetName() << "'";
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -402,7 +403,8 @@ bool Notification::CheckNotificationUserFilters(NotificationType type, const Use
|
|||
if (tp && !tp->IsInside(Utility::GetTime())) {
|
||||
Log(LogNotice, "Notification")
|
||||
<< "Not sending notifications for notification object '"
|
||||
<< GetName() << " and user '" << user->GetName() << "': user not in timeperiod";
|
||||
<< GetName() << " and user '" << user->GetName()
|
||||
<< "': user period not in timeperiod '" << tp->GetName() << "'";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -77,15 +77,22 @@ void TimePeriod::AddSegment(double begin, double end)
|
|||
if (segment->Get("begin") <= begin && segment->Get("end") >= end)
|
||||
return; /* New segment is fully contained in this segment. */
|
||||
|
||||
if (segment->Get("begin") <= begin && segment->Get("end") >= begin) {
|
||||
segment->Set("end", end); /* Extend an existing segment. */
|
||||
if (segment->Get("begin") >= begin && segment->Get("end") <= end) {
|
||||
segment->Set("begin", begin);
|
||||
segment->Set("end", end); /* Extend an existing segment to both sides */
|
||||
return;
|
||||
}
|
||||
|
||||
if (segment->Get("end") >= begin && segment->Get("end") <= end) {
|
||||
segment->Set("end", end); /* Extend an existing segment to right. */
|
||||
return;
|
||||
}
|
||||
|
||||
if (segment->Get("begin") >= begin && segment->Get("begin") <= end) {
|
||||
segment->Set("begin", begin); /* Extend an existing segment. */
|
||||
segment->Set("begin", begin); /* Extend an existing segment to left. */
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,6 +149,21 @@ void TimePeriod::RemoveSegment(double begin, double end)
|
|||
continue;
|
||||
}
|
||||
|
||||
/* Cut between */
|
||||
if (segment->Get("begin") < begin && segment->Get("end") > end) {
|
||||
Dictionary::Ptr firstsegment = new Dictionary();
|
||||
firstsegment->Set("begin", segment->Get("begin"));
|
||||
firstsegment->Set("end", begin);
|
||||
|
||||
Dictionary::Ptr secondsegment = new Dictionary();
|
||||
secondsegment->Set("begin", end);
|
||||
secondsegment->Set("end", segment->Get("end"));
|
||||
|
||||
newSegments->Add(firstsegment);
|
||||
newSegments->Add(secondsegment);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Adjust the begin/end timestamps so as to not overlap with the specified range. */
|
||||
if (segment->Get("begin") > begin && segment->Get("begin") < end)
|
||||
segment->Set("begin", end);
|
||||
|
@ -157,6 +179,11 @@ void TimePeriod::RemoveSegment(double begin, double end)
|
|||
Dump();
|
||||
}
|
||||
|
||||
void TimePeriod::RemoveSegment(const Dictionary::Ptr& segment)
|
||||
{
|
||||
RemoveSegment(segment->Get("begin"), segment->Get("end"));
|
||||
}
|
||||
|
||||
void TimePeriod::PurgeSegments(double end)
|
||||
{
|
||||
ASSERT(OwnsLock());
|
||||
|
@ -187,6 +214,23 @@ void TimePeriod::PurgeSegments(double end)
|
|||
SetSegments(newSegments);
|
||||
}
|
||||
|
||||
void TimePeriod::Merge(const TimePeriod::Ptr& timeperiod, bool include)
|
||||
{
|
||||
Log(LogDebug, "TimePeriod")
|
||||
<< "Merge TimePeriod '" << GetName() << "' with '" << timeperiod->GetName() << "' "
|
||||
<< "Method: " << (include ? "include" : "exclude");
|
||||
|
||||
Array::Ptr segments = timeperiod->GetSegments();
|
||||
|
||||
if (segments) {
|
||||
ObjectLock dlock(segments);
|
||||
ObjectLock ilock(this);
|
||||
BOOST_FOREACH(const Dictionary::Ptr& segment, segments) {
|
||||
include ? AddSegment(segment) : RemoveSegment(segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TimePeriod::UpdateRegion(double begin, double end, bool clearExisting)
|
||||
{
|
||||
if (!clearExisting) {
|
||||
|
@ -215,6 +259,34 @@ void TimePeriod::UpdateRegion(double begin, double end, bool clearExisting)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool preferInclude = GetPreferIncludes();
|
||||
|
||||
/* First handle the non preferred timeranges */
|
||||
Array::Ptr timeranges = preferInclude ? GetExcludes() : GetIncludes();
|
||||
|
||||
if (timeranges) {
|
||||
ObjectLock olock(timeranges);
|
||||
BOOST_FOREACH(const String& name, timeranges) {
|
||||
const TimePeriod::Ptr timeperiod = TimePeriod::GetByName(name);
|
||||
|
||||
if (timeperiod)
|
||||
Merge(timeperiod, !preferInclude);
|
||||
}
|
||||
}
|
||||
|
||||
/* Preferred timeranges must be handled at the end */
|
||||
timeranges = preferInclude ? GetIncludes() : GetExcludes();
|
||||
|
||||
if (timeranges) {
|
||||
ObjectLock olock(timeranges);
|
||||
BOOST_FOREACH(const String& name, timeranges) {
|
||||
const TimePeriod::Ptr timeperiod = TimePeriod::GetByName(name);
|
||||
|
||||
if (timeperiod)
|
||||
Merge(timeperiod, preferInclude);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TimePeriod::GetIsInside(void) const
|
||||
|
|
|
@ -54,8 +54,11 @@ private:
|
|||
void AddSegment(double s, double end);
|
||||
void AddSegment(const Dictionary::Ptr& segment);
|
||||
void RemoveSegment(double begin, double end);
|
||||
void RemoveSegment(const Dictionary::Ptr& segment);
|
||||
void PurgeSegments(double end);
|
||||
|
||||
void Merge(const TimePeriod::Ptr& timeperiod, bool include = true);
|
||||
|
||||
void Dump(void);
|
||||
|
||||
static void UpdateTimerHandler(void);
|
||||
|
|
|
@ -37,6 +37,15 @@ class TimePeriod : CustomVarObject
|
|||
};
|
||||
[config] Dictionary::Ptr ranges;
|
||||
[config, required] Function::Ptr update;
|
||||
[config] bool prefer_includes {
|
||||
default {{{ return true; }}}
|
||||
};
|
||||
[config] array(name(TimePeriod)) excludes {
|
||||
default {{{ return new Array(); }}}
|
||||
};
|
||||
[config] array(name(TimePeriod)) includes {
|
||||
default {{{ return new Array(); }}}
|
||||
};
|
||||
[state, no_user_modify] Value valid_begin;
|
||||
[state, no_user_modify] Value valid_end;
|
||||
[state, no_user_modify] Array::Ptr segments;
|
||||
|
|
Loading…
Reference in New Issue