mirror of https://github.com/Icinga/icinga2.git
parent
05810f053d
commit
22d53cf3b5
|
@ -132,6 +132,11 @@ void CheckerComponent::CheckThreadProc(void)
|
|||
bool check = true;
|
||||
|
||||
if (!forced) {
|
||||
if (!service->IsReachable(DependencyCheckExecution)) {
|
||||
Log(LogDebug, "icinga", "Skipping check for service '" + service->GetName() + "': Dependency failed.");
|
||||
check = false;
|
||||
}
|
||||
|
||||
if (!service->GetEnableActiveChecks() || !IcingaApplication::GetInstance()->GetEnableChecks()) {
|
||||
Log(LogDebug, "checker", "Skipping check for service '" + service->GetName() + "': active checks are disabled");
|
||||
check = false;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "icinga/timeperiod.h"
|
||||
#include "icinga/notificationcommand.h"
|
||||
#include "icinga/compatutility.h"
|
||||
#include "icinga/dependency.h"
|
||||
#include "base/dynamictype.h"
|
||||
#include "base/objectlock.h"
|
||||
#include "base/convert.h"
|
||||
|
@ -508,25 +509,6 @@ void StatusDataWriter::DumpServiceObject(std::ostream& fp, const Service::Ptr& s
|
|||
|
||||
fp << "\t" "}" "\n"
|
||||
"\n";
|
||||
|
||||
BOOST_FOREACH(const Service::Ptr& parent, service->GetParentServices()) {
|
||||
Host::Ptr host = service->GetHost();
|
||||
|
||||
Host::Ptr parent_host = parent->GetHost();
|
||||
|
||||
if (!parent_host)
|
||||
continue;
|
||||
|
||||
fp << "define servicedependency {" "\n"
|
||||
"\t" "dependent_host_name" "\t" << host->GetName() << "\n"
|
||||
"\t" "dependent_service_description" "\t" << service->GetShortName() << "\n"
|
||||
"\t" "host_name" "\t" << parent_host->GetName() << "\n"
|
||||
"\t" "service_description" "\t" << parent->GetShortName() << "\n"
|
||||
"\t" "execution_failure_criteria" "\t" "n" "\n"
|
||||
"\t" "notification_failure_criteria" "\t" "w,u,c" "\n"
|
||||
"\t" "}" "\n"
|
||||
"\n";
|
||||
}
|
||||
}
|
||||
|
||||
void StatusDataWriter::DumpCustomAttributes(std::ostream& fp, const DynamicObject::Ptr& object)
|
||||
|
@ -673,6 +655,28 @@ void StatusDataWriter::UpdateObjectsCache(void)
|
|||
DumpTimePeriod(objectfp, tp);
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const Dependency::Ptr& dep, DynamicType::GetObjects<Dependency>()) {
|
||||
Service::Ptr parent_service = dep->GetParentService();
|
||||
|
||||
if (!parent_service)
|
||||
continue;
|
||||
|
||||
Service::Ptr child_service = dep->GetChildService();
|
||||
|
||||
if (!child_service)
|
||||
continue;
|
||||
|
||||
objectfp << "define servicedependency {" "\n"
|
||||
"\t" "dependent_host_name" "\t" << child_service->GetHost()->GetName() << "\n"
|
||||
"\t" "dependent_service_description" "\t" << child_service->GetShortName() << "\n"
|
||||
"\t" "host_name" "\t" << parent_service->GetHost()->GetName() << "\n"
|
||||
"\t" "service_description" "\t" << parent_service->GetShortName() << "\n"
|
||||
"\t" "execution_failure_criteria" "\t" "n" "\n"
|
||||
"\t" "notification_failure_criteria" "\t" "w,u,c" "\n"
|
||||
"\t" "}" "\n"
|
||||
"\n";
|
||||
}
|
||||
|
||||
objectfp.close();
|
||||
|
||||
#ifdef _WIN32
|
||||
|
|
|
@ -17,12 +17,6 @@ Example:
|
|||
|
||||
groups = [ "all-hosts" ],
|
||||
|
||||
host_dependencies = [ "router" ],
|
||||
|
||||
service_dependencies = [
|
||||
{ host = "db-server", service = "mysql" }
|
||||
],
|
||||
|
||||
services["ping"] = {
|
||||
templates = [ "ping" ]
|
||||
},
|
||||
|
@ -46,9 +40,8 @@ Attributes:
|
|||
display_name |**Optional.** A short description of the host.
|
||||
check |**Optional.** A service that is used to determine whether the host is up or down. This must be a service short name of a service that belongs to the host.
|
||||
groups |**Optional.** A list of host groups this host belongs to.
|
||||
host_dependencies|**Optional.** A list of host names which this host depends on. These dependencies are used to determine whether the host is unreachable.
|
||||
service_dependencies|**Optional.** A list of services which this host depends on. Each array element must be a dictionary containing the keys "host" and "service". These dependencies are used to determine whether the host is unreachable.
|
||||
services |**Optional.** Inline definition of services. Each dictionary item specifies a service.<br /><br />The `templates` attribute can be used to specify an array of templates that should be inherited by the service.<br /><br />The new service's name is "hostname!service" - where "service" is the dictionary key in the services dictionary.<br /><br />The dictionary key is used as the service's short name.
|
||||
dependencies |**Optional.** Inline definition of dependencies. Each dictionary item specifies a dependency.<br /><br />The `templates` attribute can be used to specify an array of templates that should be inherited by the dependency object.<br /><br />The new dependency object's name is "hostname:service:dependency" - where "dependency" is the dictionary key in the dependencies dictionary.
|
||||
macros |**Optional.** A dictionary containing macros that are specific to this host.
|
||||
|
||||
### <a id="objecttype-hostgroup"></a> HostGroup
|
||||
|
@ -121,10 +114,9 @@ Attributes:
|
|||
event\_command |**Optional.** The name of an event command that should be executed every time the service's state changes.
|
||||
flapping\_threshold|**Optional.** The flapping threshold in percent when a service is considered to be flapping.
|
||||
volatile |**Optional.** The volatile setting enables always `HARD` state types if `NOT-OK` state changes occur.
|
||||
host_dependencies|**Optional.** A list of host names which this host depends on. These dependencies are used to determine whether the host is unreachable.
|
||||
service_dependencies|**Optional.** A list of services which this host depends on. Each array element must be a dictionary containing the keys "host" and "service". These dependencies are used to determine whether the host is unreachable.
|
||||
groups |**Optional.** The service groups this service belongs to.
|
||||
notifications |**Optional.** Inline definition of notifications. Each dictionary item specifies a notification.<br /><br />The `templates` attribute can be used to specify an array of templates that should be inherited by the notification object.<br /><br />The new notification object's name is "hostname:service:notification" - where "notification" is the dictionary key in the notifications dictionary.
|
||||
dependencies |**Optional.** Inline definition of dependencies. Each dictionary item specifies a dependency.<br /><br />The `templates` attribute can be used to specify an array of templates that should be inherited by the dependency object.<br /><br />The new dependency object's name is "hostname:service:dependency" - where "dependency" is the dictionary key in the dependencies dictionary.
|
||||
authorities |**Optional.** A list of Endpoints on which this service check will be executed in a cluster scenario.
|
||||
|
||||
### <a id="objecttype-servicegroup"></a> ServiceGroup
|
||||
|
@ -202,6 +194,50 @@ Available notification type and state filters:
|
|||
>
|
||||
> In order to notify on problem states, you will need the type filter `NotificationFilterProblem`.
|
||||
|
||||
### <a id="objecttype-dependency"></a> Dependency
|
||||
|
||||
Dependency objects are used to specify dependencies between hosts and services.
|
||||
|
||||
> **Best Practice**
|
||||
>
|
||||
> Rather than creating a `Dependency` object for a specific service it is usually easier
|
||||
> to just create a `Dependency` template and using the `dependencies` attribute in the `Service`
|
||||
> object to associate these templates with a service.
|
||||
|
||||
Example:
|
||||
|
||||
object Dependency "webserver-internet" {
|
||||
child_host = "webserver",
|
||||
child_service = "ping4",
|
||||
|
||||
parent_host = "internet",
|
||||
parent_service = "ping4",
|
||||
|
||||
state_filter = (StateFilterOK),
|
||||
|
||||
disable_checks = true
|
||||
}
|
||||
|
||||
Attributes:
|
||||
|
||||
Name |Description
|
||||
----------------|----------------
|
||||
parent_host |**Required.** The parent host.
|
||||
parent_service |**Optional.** The parent service. When not specified the host's check service is used.
|
||||
child_host |**Required.** The child host.
|
||||
child_service |**Optional.** The child service. When not specified the host's check service is used.
|
||||
disable_checks |**Optional.** Whether to disable checks when this dependency fails. Defaults to false.
|
||||
disable_notifications|**Optional.** Whether to disable notifications when this dependency fails. Defaults to true.
|
||||
period |**Optional.** Time period during which this dependency is enabled.
|
||||
state_filter |**Optional.** A set of type filters when this dependency should be OK. Defaults to (StateFilterOK | StateFilterWarning).
|
||||
|
||||
Available state filters:
|
||||
|
||||
StateFilterOK
|
||||
StateFilterWarning
|
||||
StateFilterCritical
|
||||
StateFilterUnknown
|
||||
|
||||
### <a id="objecttype-user"></a> User
|
||||
|
||||
A user.
|
||||
|
|
|
@ -19,6 +19,7 @@ mkclass_target(checkcommand.ti checkcommand.th)
|
|||
mkclass_target(checkresult.ti checkresult.th)
|
||||
mkclass_target(command.ti command.th)
|
||||
mkclass_target(comment.ti comment.th)
|
||||
mkclass_target(dependency.ti dependency.th)
|
||||
mkclass_target(domain.ti domain.th)
|
||||
mkclass_target(downtime.ti downtime.th)
|
||||
mkclass_target(eventcommand.ti eventcommand.th)
|
||||
|
@ -40,7 +41,7 @@ mkembedconfig_target(icinga-type.conf icinga-type.cpp)
|
|||
|
||||
add_library(icinga SHARED
|
||||
api.cpp api.h checkcommand.cpp checkcommand.th checkresult.cpp checkresult.th
|
||||
cib.cpp command.cpp command.th comment.cpp comment.th compatutility.cpp
|
||||
cib.cpp command.cpp command.th comment.cpp comment.th compatutility.cpp dependency.cpp dependency.th
|
||||
domain.cpp domain.th downtime.cpp downtime.th eventcommand.cpp eventcommand.th
|
||||
externalcommandprocessor.cpp host.cpp host.th hostgroup.cpp hostgroup.th
|
||||
icingaapplication.cpp icingaapplication.th icingastatuswriter.cpp
|
||||
|
@ -48,7 +49,7 @@ add_library(icinga SHARED
|
|||
macroprocessor.cpp macroresolver.cpp notificationcommand.cpp notificationcommand.th
|
||||
notification.cpp notification.th perfdatavalue.cpp perfdatavalue.th
|
||||
pluginutility.cpp scheduleddowntime.cpp scheduleddowntime.th service-check.cpp
|
||||
service-comment.cpp service.cpp service-downtime.cpp service-event.cpp
|
||||
service-comment.cpp service.cpp service-dependency.cpp service-downtime.cpp service-event.cpp
|
||||
service-flapping.cpp service.th servicegroup.cpp servicegroup.th
|
||||
service-notification.cpp timeperiod.cpp timeperiod.th user.cpp user.th
|
||||
usergroup.cpp usergroup.th icinga-type.cpp
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-present Icinga Development Team (http://www.icinga.org) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#include "icinga/dependency.h"
|
||||
#include "base/dynamictype.h"
|
||||
#include "base/objectlock.h"
|
||||
#include "base/logger_fwd.h"
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_TYPE(Dependency);
|
||||
|
||||
void Dependency::OnStateLoaded(void)
|
||||
{
|
||||
DynamicObject::Start();
|
||||
|
||||
ASSERT(!OwnsLock());
|
||||
|
||||
if (!GetChildService())
|
||||
Log(LogWarning, "icinga", "Dependency '" + GetName() + "' references an invalid child service and will be ignored.");
|
||||
else
|
||||
GetChildService()->AddDependency(GetSelf());
|
||||
|
||||
if (!GetParentService())
|
||||
Log(LogWarning, "icinga", "Dependency '" + GetName() + "' references an invalid parent service and will always fail.");
|
||||
else
|
||||
GetParentService()->AddReverseDependency(GetSelf());
|
||||
}
|
||||
|
||||
void Dependency::Stop(void)
|
||||
{
|
||||
DynamicObject::Stop();
|
||||
|
||||
if (GetChildService())
|
||||
GetChildService()->RemoveDependency(GetSelf());
|
||||
|
||||
if (GetParentService())
|
||||
GetParentService()->RemoveReverseDependency(GetSelf());
|
||||
}
|
||||
|
||||
bool Dependency::IsAvailable(DependencyType dt) const
|
||||
{
|
||||
Service::Ptr service = GetParentService();
|
||||
|
||||
if (!service)
|
||||
return false;
|
||||
|
||||
/* ignore if it's the same service */
|
||||
if (service == GetChildService()) {
|
||||
Log(LogDebug, "icinga", "Dependency '" + GetName() + "' passed: Parent and child service are identical.");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ignore pending services */
|
||||
if (!service->GetLastCheckResult()) {
|
||||
Log(LogDebug, "icinga", "Dependency '" + GetName() + "' passed: Service hasn't been checked yet.");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ignore soft states */
|
||||
if (service->GetStateType() == StateTypeSoft) {
|
||||
Log(LogDebug, "icinga", "Dependency '" + GetName() + "' passed: Service is in a soft state.");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* check state */
|
||||
if ((1 << static_cast<int>(service->GetState())) & GetStateFilter()) {
|
||||
Log(LogDebug, "icinga", "Dependency '" + GetName() + "' passed: Service matches state filter.");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ignore if not in time period */
|
||||
TimePeriod::Ptr tp = GetPeriod();
|
||||
if (tp && !tp->IsInside(Utility::GetTime())) {
|
||||
Log(LogDebug, "icinga", "Dependency '" + GetName() + "' passed: Outside time period.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dt == DependencyCheckExecution && !GetDisableChecks()) {
|
||||
Log(LogDebug, "icinga", "Dependency '" + GetName() + "' passed: Checks are not disabled.");
|
||||
return true;
|
||||
} else if (dt == DependencyNotification && !GetDisableNotifications()) {
|
||||
Log(LogDebug, "icinga", "Dependency '" + GetName() + "' passed: Notifications are not disabled");
|
||||
return true;
|
||||
}
|
||||
|
||||
Log(LogDebug, "icinga", "Dependency '" + GetName() + "' failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Service::Ptr Dependency::GetChildService(void) const
|
||||
{
|
||||
Host::Ptr host = Host::GetByName(GetChildHostRaw());
|
||||
|
||||
if (!host)
|
||||
return Service::Ptr();
|
||||
|
||||
if (GetChildServiceRaw().IsEmpty())
|
||||
return host->GetCheckService();
|
||||
|
||||
return host->GetServiceByShortName(GetChildServiceRaw());
|
||||
}
|
||||
|
||||
Service::Ptr Dependency::GetParentService(void) const
|
||||
{
|
||||
Host::Ptr host = Host::GetByName(GetParentHostRaw());
|
||||
|
||||
if (!host)
|
||||
return Service::Ptr();
|
||||
|
||||
if (GetParentServiceRaw().IsEmpty())
|
||||
return host->GetCheckService();
|
||||
|
||||
return host->GetServiceByShortName(GetParentServiceRaw());
|
||||
}
|
||||
|
||||
TimePeriod::Ptr Dependency::GetPeriod(void) const
|
||||
{
|
||||
return TimePeriod::GetByName(GetPeriodRaw());
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-present Icinga Development Team (http://www.icinga.org) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef DEPENDENCY_H
|
||||
#define DEPENDENCY_H
|
||||
|
||||
#include "icinga/i2-icinga.h"
|
||||
#include "icinga/dependency.th"
|
||||
#include "icinga/service.h"
|
||||
#include "base/array.h"
|
||||
#include "base/dictionary.h"
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
/**
|
||||
* A service dependency..
|
||||
*
|
||||
* @ingroup icinga
|
||||
*/
|
||||
class I2_ICINGA_API Dependency : public ObjectImpl<Dependency>
|
||||
{
|
||||
public:
|
||||
DECLARE_PTR_TYPEDEFS(Dependency);
|
||||
DECLARE_TYPENAME(Dependency);
|
||||
|
||||
Service::Ptr GetParentService(void) const;
|
||||
Service::Ptr GetChildService(void) const;
|
||||
|
||||
TimePeriod::Ptr GetPeriod(void) const;
|
||||
|
||||
bool IsAvailable(DependencyType dt) const;
|
||||
|
||||
protected:
|
||||
virtual void OnStateLoaded(void);
|
||||
virtual void Stop(void);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* DEPENDENCY_H */
|
|
@ -0,0 +1,25 @@
|
|||
#include "base/dynamicobject.h"
|
||||
#include "icinga/service.h"
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
class Dependency : DynamicObject
|
||||
{
|
||||
[config] String child_host (ChildHostRaw);
|
||||
[config] String child_service (ChildServiceRaw);
|
||||
|
||||
[config] String parent_host (ParentHostRaw);
|
||||
[config] String parent_service (ParentServiceRaw);
|
||||
|
||||
[config] String period (PeriodRaw);
|
||||
|
||||
[config] int state_filter {
|
||||
default {{{ return (1 << StateOK) | (1 << StateWarning); }}}
|
||||
};
|
||||
|
||||
[config] bool disable_checks;
|
||||
[config] bool disable_notifications;
|
||||
};
|
||||
|
||||
}
|
|
@ -84,54 +84,15 @@ void Host::Stop(void)
|
|||
// TODO: unregister slave services/notifications?
|
||||
}
|
||||
|
||||
bool Host::IsReachable(void) const
|
||||
bool Host::IsReachable(DependencyType dt, shared_ptr<Dependency> *failedDependency) const
|
||||
{
|
||||
ASSERT(!OwnsLock());
|
||||
|
||||
std::set<Service::Ptr> parentServices = GetParentServices();
|
||||
|
||||
BOOST_FOREACH(const Service::Ptr& service, parentServices) {
|
||||
ObjectLock olock(service);
|
||||
|
||||
/* ignore pending services */
|
||||
if (!service->GetLastCheckResult())
|
||||
continue;
|
||||
|
||||
/* ignore soft states */
|
||||
if (service->GetStateType() == StateTypeSoft)
|
||||
continue;
|
||||
|
||||
/* ignore services states OK and Warning */
|
||||
if (service->GetState() == StateOK ||
|
||||
service->GetState() == StateWarning)
|
||||
continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::set<Host::Ptr> parentHosts = GetParentHosts();
|
||||
|
||||
BOOST_FOREACH(const Host::Ptr& host, parentHosts) {
|
||||
Service::Ptr hc = host->GetCheckService();
|
||||
|
||||
/* ignore hosts that don't have a check */
|
||||
Service::Ptr hc = GetCheckService();
|
||||
if (!hc)
|
||||
continue;
|
||||
|
||||
ObjectLock olock(hc);
|
||||
|
||||
/* ignore soft states */
|
||||
if (hc->GetStateType() == StateTypeSoft)
|
||||
continue;
|
||||
|
||||
/* ignore hosts that are up */
|
||||
if (hc->GetState() == StateOK)
|
||||
continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
return hc->IsReachable(dt, failedDependency);
|
||||
}
|
||||
|
||||
void Host::UpdateSlaveServices(void)
|
||||
|
@ -238,7 +199,14 @@ int Host::GetTotalServices(void) const
|
|||
|
||||
Service::Ptr Host::GetServiceByShortName(const Value& name) const
|
||||
{
|
||||
if (name.IsScalar()) {
|
||||
if (name.IsEmpty()) {
|
||||
Service::Ptr hc = GetCheckService();
|
||||
|
||||
if (!hc)
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Host does not have a host check service: " + GetName()));
|
||||
|
||||
return hc;
|
||||
} else if (name.IsScalar()) {
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_ServicesMutex);
|
||||
|
||||
|
@ -259,48 +227,6 @@ Service::Ptr Host::GetServiceByShortName(const Value& name) const
|
|||
}
|
||||
}
|
||||
|
||||
std::set<Host::Ptr> Host::GetParentHosts(void) const
|
||||
{
|
||||
std::set<Host::Ptr> parents;
|
||||
|
||||
Array::Ptr dependencies = GetHostDependencies();
|
||||
|
||||
if (dependencies) {
|
||||
ObjectLock olock(dependencies);
|
||||
|
||||
BOOST_FOREACH(const Value& value, dependencies) {
|
||||
if (value == GetName())
|
||||
continue;
|
||||
|
||||
Host::Ptr host = GetByName(value);
|
||||
|
||||
parents.insert(host);
|
||||
}
|
||||
}
|
||||
|
||||
return parents;
|
||||
}
|
||||
|
||||
std::set<Host::Ptr> Host::GetChildHosts(void) const
|
||||
{
|
||||
std::set<Host::Ptr> children;
|
||||
|
||||
BOOST_FOREACH(const Host::Ptr& host, DynamicType::GetObjects<Host>()) {
|
||||
Array::Ptr dependencies = host->GetHostDependencies();
|
||||
|
||||
if (dependencies) {
|
||||
ObjectLock olock(dependencies);
|
||||
|
||||
BOOST_FOREACH(const Value& value, dependencies) {
|
||||
if (value == GetName())
|
||||
children.insert(host);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
|
||||
Service::Ptr Host::GetCheckService(void) const
|
||||
{
|
||||
String host_check = GetCheck();
|
||||
|
@ -311,21 +237,48 @@ Service::Ptr Host::GetCheckService(void) const
|
|||
return GetServiceByShortName(host_check);
|
||||
}
|
||||
|
||||
std::set<Host::Ptr> Host::GetParentHosts(void) const
|
||||
{
|
||||
std::set<Host::Ptr> result;
|
||||
Service::Ptr hc = GetCheckService();
|
||||
|
||||
if (hc)
|
||||
result = hc->GetParentHosts();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::set<Host::Ptr> Host::GetChildHosts(void) const
|
||||
{
|
||||
std::set<Host::Ptr> result;
|
||||
Service::Ptr hc = GetCheckService();
|
||||
|
||||
if (hc)
|
||||
result = hc->GetChildHosts();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::set<Service::Ptr> Host::GetParentServices(void) const
|
||||
{
|
||||
std::set<Service::Ptr> parents;
|
||||
std::set<Service::Ptr> result;
|
||||
Service::Ptr hc = GetCheckService();
|
||||
|
||||
Array::Ptr dependencies = GetServiceDependencies();
|
||||
if (hc)
|
||||
result = hc->GetParentServices();
|
||||
|
||||
if (dependencies) {
|
||||
ObjectLock olock(dependencies);
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const Value& value, dependencies) {
|
||||
parents.insert(GetServiceByShortName(value));
|
||||
}
|
||||
}
|
||||
std::set<Service::Ptr> Host::GetChildServices(void) const
|
||||
{
|
||||
std::set<Service::Ptr> result;
|
||||
Service::Ptr hc = GetCheckService();
|
||||
|
||||
return parents;
|
||||
if (hc)
|
||||
result = hc->GetChildServices();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
HostState Host::CalculateState(ServiceState state, bool reachable)
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace icinga
|
|||
{
|
||||
|
||||
class Service;
|
||||
class Dependency;
|
||||
|
||||
/**
|
||||
* The state of a host.
|
||||
|
@ -44,6 +45,13 @@ enum HostState
|
|||
HostUnreachable = 2
|
||||
};
|
||||
|
||||
enum DependencyType
|
||||
{
|
||||
DependencyState,
|
||||
DependencyCheckExecution,
|
||||
DependencyNotification
|
||||
};
|
||||
|
||||
/**
|
||||
* An Icinga host.
|
||||
*
|
||||
|
@ -56,11 +64,13 @@ public:
|
|||
DECLARE_TYPENAME(Host);
|
||||
|
||||
shared_ptr<Service> GetCheckService(void) const;
|
||||
|
||||
std::set<Host::Ptr> GetParentHosts(void) const;
|
||||
std::set<Host::Ptr> GetChildHosts(void) const;
|
||||
std::set<shared_ptr<Service> > GetParentServices(void) const;
|
||||
std::set<shared_ptr<Service> > GetChildServices(void) const;
|
||||
|
||||
bool IsReachable() const;
|
||||
bool IsReachable(DependencyType dt = DependencyState, shared_ptr<Dependency> *failedDependency = NULL) const;
|
||||
|
||||
shared_ptr<Service> GetServiceByShortName(const Value& name) const;
|
||||
|
||||
|
|
|
@ -15,10 +15,9 @@ class Host : DynamicObject
|
|||
};
|
||||
[config] Array::Ptr groups;
|
||||
[config] Dictionary::Ptr macros;
|
||||
[config] Array::Ptr host_dependencies;
|
||||
[config] Array::Ptr service_dependencies;
|
||||
[config] String check;
|
||||
[config, protected] Dictionary::Ptr services (ServiceDescriptions);
|
||||
[config] Dictionary::Ptr dependencies (DependencyDescriptions);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -23,18 +23,6 @@ type Host {
|
|||
%attribute array "groups" {
|
||||
%attribute name(HostGroup) "*"
|
||||
},
|
||||
%attribute array "host_dependencies" {
|
||||
%attribute name(Host) "*"
|
||||
},
|
||||
%attribute array "service_dependencies" {
|
||||
%attribute dictionary "*" {
|
||||
%require "host",
|
||||
%attribute name(Host) "host",
|
||||
|
||||
%require "service",
|
||||
%attribute string "service"
|
||||
}
|
||||
},
|
||||
%attribute dictionary "services" {
|
||||
%attribute dictionary "*" {
|
||||
%attribute array "templates" {
|
||||
|
@ -45,6 +33,16 @@ type Host {
|
|||
}
|
||||
},
|
||||
|
||||
%attribute dictionary "dependencies" {
|
||||
%attribute dictionary "*" {
|
||||
%attribute array "templates" {
|
||||
%attribute name(Dependency) "*"
|
||||
},
|
||||
|
||||
%attribute any "*"
|
||||
}
|
||||
},
|
||||
|
||||
%attribute dictionary "macros" {
|
||||
%attribute string "*"
|
||||
}
|
||||
|
@ -95,18 +93,16 @@ type Service {
|
|||
|
||||
%attribute number "volatile",
|
||||
|
||||
%attribute array "host_dependencies" {
|
||||
%attribute name(Host) "*"
|
||||
},
|
||||
%attribute array "service_dependencies" {
|
||||
%attribute dictionary "dependencies" {
|
||||
%attribute dictionary "*" {
|
||||
%require "host",
|
||||
%attribute name(Host) "host",
|
||||
%attribute array "templates" {
|
||||
%attribute name(Dependency) "*"
|
||||
},
|
||||
|
||||
%require "service",
|
||||
%attribute string "service"
|
||||
%attribute any "*"
|
||||
}
|
||||
},
|
||||
|
||||
%attribute array "groups" {
|
||||
%attribute name(ServiceGroup) "*"
|
||||
},
|
||||
|
@ -285,3 +281,19 @@ type ScheduledDowntime {
|
|||
|
||||
%attribute any "templates"
|
||||
}
|
||||
|
||||
type Dependency {
|
||||
%require "parent_host",
|
||||
%attribute name(Host) "parent_host",
|
||||
%attribute string "parent_service",
|
||||
|
||||
%require "child_host",
|
||||
%attribute name(Host) "child_host",
|
||||
%attribute string "child_service",
|
||||
|
||||
%attribute name(TimePeriod) "period",
|
||||
|
||||
%attribute number "state_filter",
|
||||
%attribute number "disable_checks",
|
||||
%attribute number "disable_notifications"
|
||||
}
|
||||
|
|
|
@ -240,6 +240,7 @@ void Service::ProcessCheckResult(const CheckResult::Ptr& cr, const String& autho
|
|||
cr->SetCheckSource(authority);
|
||||
|
||||
bool reachable = IsReachable();
|
||||
bool notification_reachable = IsReachable(DependencyNotification);
|
||||
|
||||
bool host_reachable = GetHost()->IsReachable();
|
||||
|
||||
|
@ -358,7 +359,7 @@ void Service::ProcessCheckResult(const CheckResult::Ptr& cr, const String& autho
|
|||
Service::UpdateStatistics(cr);
|
||||
|
||||
bool in_downtime = IsInDowntime();
|
||||
bool send_notification = hardChange && reachable && !in_downtime && !IsAcknowledged();
|
||||
bool send_notification = hardChange && notification_reachable && !in_downtime && !IsAcknowledged();
|
||||
|
||||
if (old_state == StateOK && old_stateType == StateTypeSoft)
|
||||
send_notification = false; /* Don't send notifications for SOFT-OK -> HARD-OK. */
|
||||
|
|
|
@ -0,0 +1,240 @@
|
|||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-present Icinga Development Team (http://www.icinga.org) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#include "icinga/service.h"
|
||||
#include "icinga/dependency.h"
|
||||
#include "config/configitembuilder.h"
|
||||
#include "base/dynamictype.h"
|
||||
#include "base/objectlock.h"
|
||||
#include "base/logger_fwd.h"
|
||||
#include "base/timer.h"
|
||||
#include "base/utility.h"
|
||||
#include "base/convert.h"
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
void Service::AddDependency(const Dependency::Ptr& dep)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_DependencyMutex);
|
||||
m_Dependencies.insert(dep);
|
||||
}
|
||||
|
||||
void Service::RemoveDependency(const Dependency::Ptr& dep)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_DependencyMutex);
|
||||
m_Dependencies.erase(dep);
|
||||
}
|
||||
|
||||
std::set<Dependency::Ptr> Service::GetDependencies(void) const
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_DependencyMutex);
|
||||
return m_Dependencies;
|
||||
}
|
||||
|
||||
void Service::AddReverseDependency(const Dependency::Ptr& dep)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_DependencyMutex);
|
||||
m_ReverseDependencies.insert(dep);
|
||||
}
|
||||
|
||||
void Service::RemoveReverseDependency(const Dependency::Ptr& dep)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_DependencyMutex);
|
||||
m_ReverseDependencies.erase(dep);
|
||||
}
|
||||
|
||||
std::set<Dependency::Ptr> Service::GetReverseDependencies(void) const
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_DependencyMutex);
|
||||
return m_ReverseDependencies;
|
||||
}
|
||||
|
||||
bool Service::IsReachable(DependencyType dt, Dependency::Ptr *failedDependency, int rstack) const
|
||||
{
|
||||
if (rstack > 20) {
|
||||
Log(LogWarning, "icinga", "Too many nested dependencies for service '" + GetName() + "': Dependency failed.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const Service::Ptr& service, GetParentServices()) {
|
||||
if (!service->IsReachable(dt, failedDependency, rstack + 1))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* implicit dependency on host's check service */
|
||||
if (dt == DependencyState || dt == DependencyNotification) {
|
||||
Service::Ptr hc = GetHost()->GetCheckService();
|
||||
|
||||
if (hc && hc->GetState() == StateCritical && hc->GetStateType() == StateTypeHard) {
|
||||
if (failedDependency)
|
||||
*failedDependency = Dependency::Ptr();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const Dependency::Ptr& dep, GetDependencies()) {
|
||||
if (!dep->IsAvailable(dt)) {
|
||||
if (failedDependency)
|
||||
*failedDependency = dep;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (failedDependency)
|
||||
*failedDependency = Dependency::Ptr();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::set<Host::Ptr> Service::GetParentHosts(void) const
|
||||
{
|
||||
std::set<Host::Ptr> result;
|
||||
|
||||
BOOST_FOREACH(const Service::Ptr& svc, GetParentServices())
|
||||
result.insert(svc->GetHost());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::set<Host::Ptr> Service::GetChildHosts(void) const
|
||||
{
|
||||
std::set<Host::Ptr> result;
|
||||
|
||||
BOOST_FOREACH(const Service::Ptr& svc, GetChildServices())
|
||||
result.insert(svc->GetHost());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::set<Service::Ptr> Service::GetParentServices(void) const
|
||||
{
|
||||
std::set<Service::Ptr> parents;
|
||||
|
||||
BOOST_FOREACH(const Dependency::Ptr& dep, GetDependencies()) {
|
||||
Service::Ptr service = dep->GetParentService();
|
||||
|
||||
if (service)
|
||||
parents.insert(service);
|
||||
}
|
||||
|
||||
return parents;
|
||||
}
|
||||
|
||||
std::set<Service::Ptr> Service::GetChildServices(void) const
|
||||
{
|
||||
std::set<Service::Ptr> parents;
|
||||
|
||||
BOOST_FOREACH(const Dependency::Ptr& dep, GetReverseDependencies()) {
|
||||
Service::Ptr service = dep->GetChildService();
|
||||
|
||||
if (service)
|
||||
parents.insert(service);
|
||||
}
|
||||
|
||||
return parents;
|
||||
}
|
||||
|
||||
void Service::UpdateSlaveDependencies(void)
|
||||
{
|
||||
/*
|
||||
* pass == 0 -> steal host's dependency definitions
|
||||
* pass == 1 -> service's dependencies
|
||||
*/
|
||||
for (int pass = 0; pass < 2; pass++) {
|
||||
/* Service dependency descs */
|
||||
Dictionary::Ptr descs;
|
||||
|
||||
if (pass == 0 && !IsHostCheck())
|
||||
continue;
|
||||
|
||||
if (pass == 0)
|
||||
descs = GetHost()->GetDependencyDescriptions();
|
||||
else
|
||||
GetDependencyDescriptions();
|
||||
|
||||
if (!descs || descs->GetLength() == 0)
|
||||
continue;
|
||||
|
||||
ConfigItem::Ptr item;
|
||||
|
||||
if (pass == 0)
|
||||
item = ConfigItem::GetObject("Host", GetHost()->GetName());
|
||||
else
|
||||
ConfigItem::GetObject("Service", GetName());
|
||||
|
||||
ObjectLock olock(descs);
|
||||
|
||||
BOOST_FOREACH(const Dictionary::Pair& kv, descs) {
|
||||
std::ostringstream namebuf;
|
||||
namebuf << GetName() << "!" << kv.first;
|
||||
String name = namebuf.str();
|
||||
|
||||
std::vector<String> path;
|
||||
path.push_back("dependencies");
|
||||
path.push_back(kv.first);
|
||||
|
||||
ExpressionList::Ptr exprl;
|
||||
|
||||
{
|
||||
ObjectLock ilock(item);
|
||||
|
||||
exprl = item->GetLinkedExpressionList();
|
||||
}
|
||||
|
||||
DebugInfo di;
|
||||
exprl->FindDebugInfoPath(path, di);
|
||||
|
||||
if (di.Path.IsEmpty())
|
||||
di = item->GetDebugInfo();
|
||||
|
||||
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
|
||||
builder->SetType("Dependency");
|
||||
builder->SetName(name);
|
||||
builder->AddExpression("child_host", OperatorSet, GetHost()->GetName());
|
||||
builder->AddExpression("child_service", OperatorSet, GetShortName());
|
||||
|
||||
Dictionary::Ptr dependency = kv.second;
|
||||
|
||||
Array::Ptr templates = dependency->Get("templates");
|
||||
|
||||
if (templates) {
|
||||
ObjectLock tlock(templates);
|
||||
|
||||
BOOST_FOREACH(const Value& tmpl, templates) {
|
||||
builder->AddParent(tmpl);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clone attributes from the scheduled downtime expression list. */
|
||||
ExpressionList::Ptr sd_exprl = make_shared<ExpressionList>();
|
||||
exprl->ExtractPath(path, sd_exprl);
|
||||
|
||||
builder->AddExpressionList(sd_exprl);
|
||||
|
||||
ConfigItem::Ptr dependencyItem = builder->Compile();
|
||||
dependencyItem->Register();
|
||||
DynamicObject::Ptr dobj = dependencyItem->Commit();
|
||||
dobj->OnConfigLoaded();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
#include "icinga/icingaapplication.h"
|
||||
#include "icinga/macroprocessor.h"
|
||||
#include "icinga/pluginutility.h"
|
||||
#include "icinga/dependency.h"
|
||||
#include "config/configitembuilder.h"
|
||||
#include "base/dynamictype.h"
|
||||
#include "base/objectlock.h"
|
||||
|
@ -77,6 +78,7 @@ void Service::OnConfigLoaded(void)
|
|||
|
||||
UpdateSlaveNotifications();
|
||||
UpdateSlaveScheduledDowntimes();
|
||||
UpdateSlaveDependencies();
|
||||
|
||||
SetSchedulingOffset(Utility::Random());
|
||||
}
|
||||
|
@ -138,60 +140,6 @@ bool Service::IsHostCheck(void) const
|
|||
|
||||
}
|
||||
|
||||
bool Service::IsReachable(void) const
|
||||
{
|
||||
ASSERT(!OwnsLock());
|
||||
|
||||
BOOST_FOREACH(const Service::Ptr& service, GetParentServices()) {
|
||||
/* ignore ourselves */
|
||||
if (service->GetName() == GetName())
|
||||
continue;
|
||||
|
||||
ObjectLock olock(service);
|
||||
|
||||
/* ignore pending services */
|
||||
if (!service->GetLastCheckResult())
|
||||
continue;
|
||||
|
||||
/* ignore soft states */
|
||||
if (service->GetStateType() == StateTypeSoft)
|
||||
continue;
|
||||
|
||||
/* ignore services states OK and Warning */
|
||||
if (service->GetState() == StateOK ||
|
||||
service->GetState() == StateWarning)
|
||||
continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const Host::Ptr& host, GetParentHosts()) {
|
||||
Service::Ptr hc = host->GetCheckService();
|
||||
|
||||
/* ignore hosts that don't have a hostcheck */
|
||||
if (!hc)
|
||||
continue;
|
||||
|
||||
/* ignore ourselves */
|
||||
if (hc->GetName() == GetName())
|
||||
continue;
|
||||
|
||||
ObjectLock olock(hc);
|
||||
|
||||
/* ignore soft states */
|
||||
if (hc->GetStateType() == StateTypeSoft)
|
||||
continue;
|
||||
|
||||
/* ignore hosts that are up */
|
||||
if (hc->GetState() == StateOK)
|
||||
continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AcknowledgementType Service::GetAcknowledgement(void)
|
||||
{
|
||||
ASSERT(OwnsLock());
|
||||
|
@ -239,51 +187,6 @@ void Service::ClearAcknowledgement(const String& authority)
|
|||
OnAcknowledgementCleared(GetSelf(), authority);
|
||||
}
|
||||
|
||||
std::set<Host::Ptr> Service::GetParentHosts(void) const
|
||||
{
|
||||
std::set<Host::Ptr> parents;
|
||||
|
||||
Host::Ptr host = GetHost();
|
||||
|
||||
/* The service's host is implicitly a parent. */
|
||||
parents.insert(host);
|
||||
|
||||
Array::Ptr dependencies = GetHostDependencies();
|
||||
|
||||
if (dependencies) {
|
||||
ObjectLock olock(dependencies);
|
||||
|
||||
BOOST_FOREACH(const String& dependency, dependencies) {
|
||||
parents.insert(Host::GetByName(dependency));
|
||||
}
|
||||
}
|
||||
|
||||
return parents;
|
||||
}
|
||||
|
||||
std::set<Service::Ptr> Service::GetParentServices(void) const
|
||||
{
|
||||
std::set<Service::Ptr> parents;
|
||||
|
||||
Host::Ptr host = GetHost();
|
||||
Array::Ptr dependencies = GetServiceDependencies();
|
||||
|
||||
if (host && dependencies) {
|
||||
ObjectLock olock(dependencies);
|
||||
|
||||
BOOST_FOREACH(const Value& dependency, dependencies) {
|
||||
Service::Ptr service = host->GetServiceByShortName(dependency);
|
||||
|
||||
if (!service || service->GetName() == GetName())
|
||||
continue;
|
||||
|
||||
parents.insert(service);
|
||||
}
|
||||
}
|
||||
|
||||
return parents;
|
||||
}
|
||||
|
||||
bool Service::GetEnablePerfdata(void) const
|
||||
{
|
||||
if (!GetOverrideEnablePerfdata().IsEmpty())
|
||||
|
|
|
@ -96,11 +96,13 @@ public:
|
|||
Host::Ptr GetHost(void) const;
|
||||
|
||||
std::set<Host::Ptr> GetParentHosts(void) const;
|
||||
std::set<Host::Ptr> GetChildHosts(void) const;
|
||||
std::set<Service::Ptr> GetParentServices(void) const;
|
||||
std::set<Service::Ptr> GetChildServices(void) const;
|
||||
|
||||
bool IsHostCheck(void) const;
|
||||
|
||||
bool IsReachable(void) const;
|
||||
bool IsReachable(DependencyType dt = DependencyState, shared_ptr<Dependency> *failedDependency = NULL, int rstack = 0) const;
|
||||
|
||||
AcknowledgementType GetAcknowledgement(void);
|
||||
|
||||
|
@ -273,6 +275,17 @@ public:
|
|||
bool GetEnablePerfdata(void) const;
|
||||
void SetEnablePerfdata(bool enabled, const String& authority = String());
|
||||
|
||||
/* Dependencies */
|
||||
void AddDependency(const shared_ptr<Dependency>& dep);
|
||||
void RemoveDependency(const shared_ptr<Dependency>& dep);
|
||||
std::set<shared_ptr<Dependency> > GetDependencies(void) const;
|
||||
|
||||
void AddReverseDependency(const shared_ptr<Dependency>& dep);
|
||||
void RemoveReverseDependency(const shared_ptr<Dependency>& dep);
|
||||
std::set<shared_ptr<Dependency> > GetReverseDependencies(void) const;
|
||||
|
||||
void UpdateSlaveDependencies(void);
|
||||
|
||||
protected:
|
||||
virtual void Start(void);
|
||||
|
||||
|
@ -297,6 +310,11 @@ private:
|
|||
|
||||
/* Notifications */
|
||||
std::set<Notification::Ptr> m_Notifications;
|
||||
|
||||
/* Dependencies */
|
||||
mutable boost::mutex m_DependencyMutex;
|
||||
std::set<shared_ptr<Dependency> > m_Dependencies;
|
||||
std::set<shared_ptr<Dependency> > m_ReverseDependencies;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -30,8 +30,6 @@ class Service : DynamicObject
|
|||
}}}
|
||||
};
|
||||
[config] Dictionary::Ptr macros;
|
||||
[config] Array::Ptr host_dependencies;
|
||||
[config] Array::Ptr service_dependencies;
|
||||
[config] Array::Ptr groups;
|
||||
[config, protected] String check_command (CheckCommandRaw);
|
||||
[config] int max_check_attempts (MaxCheckAttemptsRaw) {
|
||||
|
@ -60,6 +58,7 @@ class Service : DynamicObject
|
|||
};
|
||||
[config] Dictionary::Ptr notifications (NotificationDescriptions);
|
||||
[config] Dictionary::Ptr scheduled_downtimes (ScheduledDowntimeDescriptions);
|
||||
[config] Dictionary::Ptr dependencies (DependencyDescriptions);
|
||||
[config] bool enable_active_checks (EnableActiveChecksRaw) {
|
||||
default {{{ return true; }}}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue