diff --git a/doc/09-object-types.md b/doc/09-object-types.md index d04f78156..8d91b7b30 100644 --- a/doc/09-object-types.md +++ b/doc/09-object-types.md @@ -1385,6 +1385,7 @@ Configuration Attributes: fixed | Boolean | **Optional.** Whether this is a fixed downtime. Defaults to `true`. duration | Duration | **Optional.** How long the downtime lasts. Only has an effect for flexible (non-fixed) downtimes. ranges | Dictionary | **Required.** A dictionary containing information which days and durations apply to this timeperiod. + child\_options | String | **Optional.** Schedule child downtimes. `DowntimeNoChildren` does not do anything, `DowntimeTriggeredChildren` schedules child downtimes triggered by this downtime, `DowntimeTriggeredChildren` schedules non-triggered downtimes. Defaults to `DowntimeNoChildren`. ScheduledDowntime objects have composite names, i.e. their names are based on the `host_name` and `service_name` attributes and the diff --git a/doc/12-icinga2-api.md b/doc/12-icinga2-api.md index 722b88a2b..50b107c88 100644 --- a/doc/12-icinga2-api.md +++ b/doc/12-icinga2-api.md @@ -1117,7 +1117,7 @@ Send a `POST` request to the URL endpoint `/v1/actions/schedule-downtime`. fixed | Boolean | **Optional.** Defaults to `true`. If true, the downtime is `fixed` otherwise `flexible`. See [downtimes](08-advanced-topics.md#downtimes) for more information. duration | Number | **Required for flexible downtimes.** Duration of the downtime in seconds if `fixed` is set to false. trigger\_name | String | **Optional.** Sets the trigger for a triggered downtime. See [downtimes](08-advanced-topics.md#downtimes) for more information on triggered downtimes. - child\_options | Number | **Optional.** Schedule child downtimes. `0` does not do anything, `1` schedules child downtimes triggered by this downtime, `2` schedules non-triggered downtimes. Defaults to `0`. + child\_options| String | **Optional.** Schedule child downtimes. `DowntimeNoChildren` does not do anything, `DowntimeTriggeredChildren` schedules child downtimes triggered by this downtime, `DowntimeTriggeredChildren` schedules non-triggered downtimes. Defaults to `DowntimeNoChildren`. In addition to these parameters a [filter](12-icinga2-api.md#icinga2-api-filters) must be provided. The valid types for this action are `Host` and `Service`. diff --git a/lib/icinga/apiactions.cpp b/lib/icinga/apiactions.cpp index 2a373eb1c..0c28fe944 100644 --- a/lib/icinga/apiactions.cpp +++ b/lib/icinga/apiactions.cpp @@ -366,30 +366,30 @@ Dictionary::Ptr ApiActions::ScheduleDowntime(const ConfigObject::Ptr& object, }); /* Schedule downtime for all child objects. */ - int childOptions = 0; + DowntimeChildOptions childOptions = DowntimeNoChildren; if (params->Contains("child_options")) - childOptions = HttpUtility::GetLastParameter(params, "child_options"); + childOptions = Downtime::ChildOptionsFromValue(HttpUtility::GetLastParameter(params, "child_options")); - if (childOptions > 0) { - /* '1' schedules child downtimes triggered by the parent downtime. - * '2' schedules non-triggered downtimes for all children. + if (childOptions != DowntimeNoChildren) { + /* 'DowntimeTriggeredChildren' schedules child downtimes triggered by the parent downtime. + * 'DowntimeNonTriggeredChildren' schedules non-triggered downtimes for all children. */ - if (childOptions == 1) + if (childOptions == DowntimeTriggeredChildren) triggerName = downtimeName; - Log(LogCritical, "ApiActions") + Log(LogNotice, "ApiActions") << "Processing child options " << childOptions << " for downtime " << downtimeName; ArrayData childDowntimes; for (const Checkable::Ptr& child : checkable->GetAllChildren()) { - Log(LogCritical, "ApiActions") + Log(LogNotice, "ApiActions") << "Scheduling downtime for child object " << child->GetName(); String childDowntimeName = Downtime::AddDowntime(child, author, comment, startTime, endTime, fixed, triggerName, duration); - Log(LogCritical, "ApiActions") + Log(LogNotice, "ApiActions") << "Add child downtime '" << childDowntimeName << "'."; Downtime::Ptr childDowntime = Downtime::GetByName(childDowntimeName); diff --git a/lib/icinga/downtime.cpp b/lib/icinga/downtime.cpp index 8c3584a4b..6e5bc0210 100644 --- a/lib/icinga/downtime.cpp +++ b/lib/icinga/downtime.cpp @@ -42,6 +42,15 @@ boost::signals2::signal Downtime::OnDowntimeTrigger REGISTER_TYPE(Downtime); +INITIALIZE_ONCE(&Downtime::StaticInitialize); + +void Downtime::StaticInitialize() +{ + ScriptGlobal::Set("DowntimeNoChildren", "DowntimeNoChildren"); + ScriptGlobal::Set("DowntimeTriggeredChildren", "DowntimeTriggeredChildren"); + ScriptGlobal::Set("DowntimeNonTriggeredChildren", "DowntimeNonTriggeredChildren"); +} + String DowntimeNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const { Downtime::Ptr downtime = dynamic_pointer_cast(context); @@ -420,3 +429,20 @@ void Downtime::ValidateEndTime(const Lazy& lvalue, const ValidationUt if (lvalue() <= 0) BOOST_THROW_EXCEPTION(ValidationError(this, { "end_time" }, "End time must be greater than 0.")); } + +DowntimeChildOptions Downtime::ChildOptionsFromValue(const Value& options) +{ + if (options == "DowntimeNoChildren") + return DowntimeNoChildren; + else if (options == "DowntimeTriggeredChildren") + return DowntimeTriggeredChildren; + else if (options == "DowntimeNonTriggeredChildren") + return DowntimeNonTriggeredChildren; + else if (options.IsNumber()) { + int number = options; + if (number >= 0 && number <= 2) + return static_cast(number); + } + + BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid child option specified")); +} diff --git a/lib/icinga/downtime.hpp b/lib/icinga/downtime.hpp index 6d4ba0a21..c4646eabb 100644 --- a/lib/icinga/downtime.hpp +++ b/lib/icinga/downtime.hpp @@ -28,6 +28,13 @@ namespace icinga { +enum DowntimeChildOptions +{ + DowntimeNoChildren, + DowntimeTriggeredChildren, + DowntimeNonTriggeredChildren +}; + /** * A downtime. * @@ -51,6 +58,8 @@ public: bool IsExpired() const; bool HasValidConfigOwner() const; + static void StaticInitialize(); + static int GetNextDowntimeID(); static String AddDowntime(const intrusive_ptr& checkable, const String& author, @@ -65,6 +74,8 @@ public: static String GetDowntimeIDFromLegacyID(int id); + static DowntimeChildOptions ChildOptionsFromValue(const Value& options); + protected: void OnAllConfigLoaded() override; void Start(bool runtimeCreated) override; diff --git a/lib/icinga/scheduleddowntime.cpp b/lib/icinga/scheduleddowntime.cpp index 6a715fc40..80d7617ba 100644 --- a/lib/icinga/scheduleddowntime.cpp +++ b/lib/icinga/scheduleddowntime.cpp @@ -191,9 +191,35 @@ void ScheduledDowntime::CreateNextDowntime() return; } - Downtime::AddDowntime(GetCheckable(), GetAuthor(), GetComment(), + String downtimeName = Downtime::AddDowntime(GetCheckable(), GetAuthor(), GetComment(), segment.first, segment.second, GetFixed(), String(), GetDuration(), GetName(), GetName()); + + Downtime::Ptr downtime = Downtime::GetByName(downtimeName); + + int childOptions = Downtime::ChildOptionsFromValue(GetChildOptions()); + if (childOptions > 0) { + /* 'DowntimeTriggeredChildren' schedules child downtimes triggered by the parent downtime. + * 'DowntimeNonTriggeredChildren' schedules non-triggered downtimes for all children. + */ + String triggerName; + if (childOptions == 1) + triggerName = downtimeName; + + Log(LogNotice, "ScheduledDowntime") + << "Processing child options " << childOptions << " for downtime " << downtimeName; + + for (const Checkable::Ptr& child : GetCheckable()->GetAllChildren()) { + Log(LogNotice, "ScheduledDowntime") + << "Scheduling downtime for child object " << child->GetName(); + + String childDowntimeName = Downtime::AddDowntime(child, GetAuthor(), GetComment(), + segment.first, segment.second, GetFixed(), triggerName, GetDuration(), GetName(), GetName()); + + Log(LogNotice, "ScheduledDowntime") + << "Add child downtime '" << childDowntimeName << "'."; + } + } } void ScheduledDowntime::ValidateRanges(const Lazy& lvalue, const ValidationUtils& utils) @@ -226,3 +252,13 @@ void ScheduledDowntime::ValidateRanges(const Lazy& lvalue, cons } } +void ScheduledDowntime::ValidateChildOptions(const Lazy& lvalue, const ValidationUtils& utils) +{ + ObjectImpl::ValidateChildOptions(lvalue, utils); + + try { + Downtime::ChildOptionsFromValue(lvalue()); + } catch (const std::exception&) { + BOOST_THROW_EXCEPTION(ValidationError(this, { "child_options" }, "Invalid child_options specified")); + } +} \ No newline at end of file diff --git a/lib/icinga/scheduleddowntime.hpp b/lib/icinga/scheduleddowntime.hpp index 86138fa04..7fbcd1e12 100644 --- a/lib/icinga/scheduleddowntime.hpp +++ b/lib/icinga/scheduleddowntime.hpp @@ -49,6 +49,7 @@ public: static void EvaluateApplyRules(const intrusive_ptr& service); void ValidateRanges(const Lazy& lvalue, const ValidationUtils& utils) override; + void ValidateChildOptions(const Lazy& lvalue, const ValidationUtils& utils) override; protected: void OnAllConfigLoaded() override; diff --git a/lib/icinga/scheduleddowntime.ti b/lib/icinga/scheduleddowntime.ti index e119eaa11..e2d2aca30 100644 --- a/lib/icinga/scheduleddowntime.ti +++ b/lib/icinga/scheduleddowntime.ti @@ -77,6 +77,10 @@ class ScheduledDowntime : CustomVarObject < ScheduledDowntimeNameComposer default {{{ return true; }}} }; + [config] Value child_options { + default {{{ return "DowntimeNoChildren"; }}} + }; + [config, required] Dictionary::Ptr ranges; };