Redesign dependencies.

Fixes #3646
This commit is contained in:
Gunnar Beutner 2013-02-07 20:29:35 +01:00
parent 021ca76642
commit 1b4a9a3a21
9 changed files with 243 additions and 143 deletions

View File

@ -278,21 +278,14 @@ void CompatComponent::DumpHostStatus(ofstream& fp, const Host::Ptr& host)
state = 0; /* up */
fp << "hoststatus {" << "\n"
<< "\t" << "host_name=" << host->GetName() << "\n"
<< "\t" << "has_been_checked=1" << "\n"
<< "\t" << "should_be_scheduled=1" << "\n"
<< "\t" << "check_execution_time=0" << "\n"
<< "\t" << "check_latency=0" << "\n"
<< "\t" << "current_state=" << state << "\n"
<< "\t" << "state_type=1" << "\n"
<< "\t" << "last_check=" << Utility::GetTime() << "\n"
<< "\t" << "next_check=" << Utility::GetTime() << "\n"
<< "\t" << "current_attempt=1" << "\n"
<< "\t" << "max_attempts=1" << "\n"
<< "\t" << "active_checks_enabled=1" << "\n"
<< "\t" << "passive_checks_enabled=1" << "\n"
<< "\t" << "last_update=" << Utility::GetTime() << "\n"
<< "\t" << "problem_has_been_acknowledged=" << (host->GetAcknowledgement() != AcknowledgementNone ? 1 : 0) << "\n"
<< "\t" << "host_name=" << host->GetName() << "\n";
Service::Ptr hostcheck = host->GetHostCheckService();
if (hostcheck)
DumpServiceStatusAttrs(fp, hostcheck, CompatStateHost);
fp << "\t" << "problem_has_been_acknowledged=" << (host->GetAcknowledgement() != AcknowledgementNone ? 1 : 0) << "\n"
<< "\t" << "acknowledgement_type=" << static_cast<int>(host->GetAcknowledgement()) << "\n"
<< "\t" << "acknowledgement_end_time=" << host->GetAcknowledgementExpiry() << "\n"
<< "\t" << "scheduled_downtime_depth=" << (host->IsInDowntime() ? 1 : 0) << "\n"
@ -314,7 +307,7 @@ void CompatComponent::DumpHostObject(ofstream& fp, const Host::Ptr& host)
<< "\t" << "active_checks_enabled" << "\t" << 1 << "\n"
<< "\t" << "passive_checks_enabled" << "\t" << 1 << "\n";
set<Host::Ptr> parents = host->GetParents();
set<Host::Ptr> parents = host->GetParentHosts();
if (!parents.empty()) {
fp << "\t" << "parents" << "\t";
@ -326,7 +319,7 @@ void CompatComponent::DumpHostObject(ofstream& fp, const Host::Ptr& host)
<< "\n";
}
void CompatComponent::DumpServiceStatus(ofstream& fp, const Service::Ptr& service)
void CompatComponent::DumpServiceStatusAttrs(ofstream& fp, const Service::Ptr& service, CompatStateType type)
{
String output;
String perfdata;
@ -351,10 +344,17 @@ void CompatComponent::DumpServiceStatus(ofstream& fp, const Service::Ptr& servic
if (state > StateUnknown)
state = StateUnknown;
fp << "servicestatus {" << "\n"
<< "\t" << "host_name=" << service->GetHost()->GetName() << "\n"
<< "\t" << "service_description=" << service->GetName() << "\n"
<< "\t" << "check_interval=" << service->GetCheckInterval() / 60.0 << "\n"
if (type == CompatStateHost) {
if (state == StateOK || state == StateWarning)
state = 0;
else
state = 1;
if (!service->GetHost()->IsReachable())
state = 2;
}
fp << "\t" << "check_interval=" << service->GetCheckInterval() / 60.0 << "\n"
<< "\t" << "retry_interval=" << service->GetRetryInterval() / 60.0 << "\n"
<< "\t" << "has_been_checked=" << (service->GetLastCheckResult() ? 1 : 0) << "\n"
<< "\t" << "should_be_scheduled=1" << "\n"
@ -372,8 +372,18 @@ void CompatComponent::DumpServiceStatus(ofstream& fp, const Service::Ptr& servic
<< "\t" << "last_hard_state_change=" << service->GetLastHardStateChange() << "\n"
<< "\t" << "last_update=" << time(NULL) << "\n"
<< "\t" << "active_checks_enabled=" << (service->GetEnableActiveChecks() ? 1 : 0) <<"\n"
<< "\t" << "passive_checks_enabled=" << (service->GetEnablePassiveChecks() ? 1 : 0) << "\n"
<< "\t" << "problem_has_been_acknowledged=" << (service->GetAcknowledgement() != AcknowledgementNone ? 1 : 0) << "\n"
<< "\t" << "passive_checks_enabled=" << (service->GetEnablePassiveChecks() ? 1 : 0) << "\n";
}
void CompatComponent::DumpServiceStatus(ofstream& fp, const Service::Ptr& service)
{
fp << "servicestatus {" << "\n"
<< "\t" << "host_name=" << service->GetHost()->GetName() << "\n"
<< "\t" << "service_description=" << service->GetName() << "\n";
DumpServiceStatusAttrs(fp, service, CompatStateService);
fp << "\t" << "problem_has_been_acknowledged=" << (service->GetAcknowledgement() != AcknowledgementNone ? 1 : 0) << "\n"
<< "\t" << "acknowledgement_type=" << static_cast<int>(service->GetAcknowledgement()) << "\n"
<< "\t" << "acknowledgement_end_time=" << service->GetAcknowledgementExpiry() << "\n"
<< "\t" << "scheduled_downtime_depth=" << (service->IsInDowntime() ? 1 : 0) << "\n"
@ -399,23 +409,14 @@ void CompatComponent::DumpServiceObject(ofstream& fp, const Service::Ptr& servic
<< "\t" << "}" << "\n"
<< "\n";
Dictionary::Ptr dependencies = boost::make_shared<Dictionary>();
service->GetDependenciesRecursive(dependencies);
Value dependency;
BOOST_FOREACH(tie(tuples::ignore, dependency), dependencies) {
Service::Ptr depService = Service::GetByName(dependency);
/* ignore ourselves */
if (depService->GetName() == service->GetName())
continue;
BOOST_FOREACH(const Service::Ptr& parent, service->GetParentServices()) {
fp << "define servicedependency {" << "\n"
<< "\t" << "dependent_host_name" << "\t" << service->GetHost()->GetName() << "\n"
<< "\t" << "dependent_service_description" << "\t" << service->GetName() << "\n"
<< "\t" << "host_name" << "\t" << depService->GetHost()->GetName() << "\n"
<< "\t" << "service_description" << "\t" << depService->GetName() << "\n"
<< "\t" << "host_name" << "\t" << parent->GetHost()->GetName() << "\n"
<< "\t" << "service_description" << "\t" << parent->GetName() << "\n"
<< "\t" << "execution_failure_criteria" << "\t" << "n" << "\n"
<< "\t" << "notification_failure_criteria" << "\t" << "w,u,c" << "\n"
<< "\t" << "}" << "\n"
<< "\n";
}
@ -543,7 +544,7 @@ void CompatComponent::StatusTimerHandler(void)
objectfp.close();
if (rename(objectspathtmp.CStr(), objectspath.CStr()) < 0)
BOOST_THROW_EXCEPTION(PosixException("rename() failed", errno));
BOOST_THROW_EXCEPTION(PosixException("rename() failed", errno));
}
EXPORT_COMPONENT(compat, CompatComponent);

View File

@ -23,6 +23,12 @@
namespace icinga
{
enum CompatStateType
{
CompatStateService,
CompatStateHost
};
/**
* @ingroup compat
*/
@ -52,6 +58,8 @@ private:
void DumpHostStatus(ofstream& fp, const Host::Ptr& host);
void DumpHostObject(ofstream& fp, const Host::Ptr& host);
void DumpServiceStatusAttrs(ofstream& fp, const Service::Ptr& service, CompatStateType type);
template<typename T>
void DumpNameList(ofstream& fp, const T& list)
{

View File

@ -626,8 +626,6 @@ object Service "localhost-uptime" {
check_interval = 60,
retry_interval = 15,
dependencies = { "localhost-ping" },
servicegroups = { "all-services", "snmp" },
checkers = { "*" },
@ -722,7 +720,7 @@ object Host "localhost" {
hostgroups = { "all-hosts" },
hostchecks = { "ping" },
hostcheck = "ping",
dependencies = { "router-ping" }
services = {
@ -756,14 +754,19 @@ Attribute: hostgroups
Optional. A list of host groups this host belongs to.
Attribute: hostchecks
^^^^^^^^^^^^^^^^^^^^^
Attribute: hostcheck
^^^^^^^^^^^^^^^^^^^^
Optional. A list of services that are used to determine whether the host is up
or down.
Optional. A service that is used to determine whether the host is up or down.
Attribute: dependencies
^^^^^^^^^^^^^^^^^^^^^^^
Attribute: hostdependencies
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Optional. A list of hosts that are used to determine whether the host is
unreachable.
Attribute: servicedependencies
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Optional. A list of services that are used to determine whether the host is
unreachable.

View File

@ -25,5 +25,5 @@ abstract object Host "itl-host" {
hostgroups = { "all-hosts" },
services = { "ping4" },
hostchecks = { "ping4" }
hostcheck = "ping4"
}

View File

@ -50,13 +50,14 @@ type Logger {
type Host {
%attribute string "alias",
%attribute string "hostcheck",
%attribute dictionary "hostgroups" {
%attribute string "*"
},
%attribute dictionary "dependencies" {
%attribute dictionary "hostdependencies" {
%attribute string "*"
},
%attribute dictionary "hostchecks" {
%attribute dictionary "servicedependencies" {
%attribute string "*"
},
%attribute dictionary "services" {
@ -79,7 +80,10 @@ type Host {
%attribute dictionary "checkers" {
%attribute string "*"
},
%attribute dictionary "dependencies" {
%attribute dictionary "hostdependencies" {
%attribute string "*"
},
%attribute dictionary "servicedependencies" {
%attribute string "*"
}
}
@ -128,7 +132,10 @@ type Service {
%attribute number "max_check_attempts",
%attribute number "check_interval",
%attribute number "retry_interval",
%attribute dictionary "dependencies" {
%attribute dictionary "hostdependencies" {
%attribute string "*"
},
%attribute dictionary "servicedependencies" {
%attribute string "*"
},
%attribute dictionary "servicegroups" {

View File

@ -86,31 +86,6 @@ Dictionary::Ptr Host::GetGroups(void) const
return Get("hostgroups");
}
set<Host::Ptr> Host::GetParents(void)
{
set<Host::Ptr> parents;
Dictionary::Ptr dependencies = Get("dependencies");
if (dependencies) {
dependencies = Service::ResolveDependencies(GetSelf(), dependencies);
Value dependency;
BOOST_FOREACH(tie(tuples::ignore, dependency), dependencies) {
Service::Ptr service = Service::GetByName(dependency);
Host::Ptr parent = service->GetHost();
/* ignore ourselves */
if (parent->GetName() == GetName())
continue;
parents.insert(parent);
}
}
return parents;
}
Dictionary::Ptr Host::GetMacros(void) const
{
return Get("macros");
@ -130,21 +105,46 @@ Dictionary::Ptr Host::GetComments(void) const
return Get("comments");
}
Dictionary::Ptr Host::GetHostDependencies(void) const
{
return Get("hostdependencies");
}
Dictionary::Ptr Host::GetServiceDependencies(void) const
{
return Get("servicedependencies");
}
String Host::GetHostCheck(void) const
{
return Get("hostcheck");
}
bool Host::IsReachable(void)
{
Dictionary::Ptr dependencies = Get("dependencies");
if (dependencies) {
dependencies = Service::ResolveDependencies(GetSelf(), dependencies);
BOOST_FOREACH(const Service::Ptr& service, GetParentServices()) {
/* ignore pending services */
if (!service->GetLastCheckResult())
continue;
Value dependency;
BOOST_FOREACH(tie(tuples::ignore, dependency), dependencies) {
Service::Ptr service = Service::GetByName(dependency);
/* ignore soft states */
if (service->GetStateType() == StateTypeSoft)
continue;
if (!service->IsReachable() ||
(service->GetState() != StateOK && service->GetState() != StateWarning)) {
return false;
}
}
/* ignore services states OK and Warning */
if (service->GetState() == StateOK ||
service->GetState() == StateWarning)
continue;
return false;
}
BOOST_FOREACH(const Host::Ptr& host, GetParentHosts()) {
/* ignore hosts that are up */
if (host->IsUp())
continue;
return false;
}
return true;
@ -211,16 +211,6 @@ static void CopyServiceAttributes(const Host::Ptr& host, TDict serviceDesc,
Value checkers = serviceDesc->Get("checkers");
if (!checkers.IsEmpty())
builder->AddExpression("checkers", OperatorSet, checkers);
Value dependencies = serviceDesc->Get("dependencies");
if (!dependencies.IsEmpty())
builder->AddExpression("dependencies", OperatorPlus,
Service::ResolveDependencies(host, dependencies));
Value hostchecks = host->Get("hostchecks");
if (!hostchecks.IsEmpty())
builder->AddExpression("dependencies", OperatorPlus,
Service::ResolveDependencies(host, hostchecks));
}
void Host::ObjectCommittedHandler(const ConfigItem::Ptr& item)
@ -444,3 +434,59 @@ void Host::ValidateServiceDictionary(const ScriptTask::Ptr& task, const vector<V
task->FinishResult(Empty);
}
Service::Ptr Host::ResolveService(const String& name) const
{
String combinedName = GetName() + "-" + name;
if (Service::Exists(combinedName))
return Service::GetByName(combinedName);
else
return Service::GetByName(name);
}
set<Host::Ptr> Host::GetParentHosts(void) const
{
set<Host::Ptr> parents;
Dictionary::Ptr dependencies = GetHostDependencies();
if (dependencies) {
String key;
BOOST_FOREACH(tie(key, tuples::ignore), dependencies) {
if (key == GetName())
continue;
parents.insert(Host::GetByName(key));
}
}
return parents;
}
Service::Ptr Host::GetHostCheckService(void) const
{
String hostcheck = GetHostCheck();
if (hostcheck.IsEmpty())
return Service::Ptr();
return ResolveService(hostcheck);
}
set<Service::Ptr> Host::GetParentServices(void) const
{
set<Service::Ptr> parents;
Dictionary::Ptr dependencies = GetServiceDependencies();
if (dependencies) {
String key;
BOOST_FOREACH(tie(key, tuples::ignore), dependencies) {
parents.insert(ResolveService(key));
}
}
return parents;
}

View File

@ -27,7 +27,7 @@ class Service;
/**
* An Icinga host.
*
*
* @ingroup icinga
*/
class I2_ICINGA_API Host : public DynamicObject
@ -45,10 +45,12 @@ public:
String GetAlias(void) const;
Dictionary::Ptr GetGroups(void) const;
set<Host::Ptr> GetParents(void);
Dictionary::Ptr GetMacros(void) const;
Dictionary::Ptr GetDowntimes(void) const;
Dictionary::Ptr GetComments(void) const;
Dictionary::Ptr GetHostDependencies(void) const;
Dictionary::Ptr GetServiceDependencies(void) const;
String GetHostCheck(void) const;
AcknowledgementType GetAcknowledgement(void);
void SetAcknowledgement(AcknowledgementType acknowledgement);
@ -56,10 +58,16 @@ public:
double GetAcknowledgementExpiry(void) const;
void SetAcknowledgementExpiry(double timestamp);
shared_ptr<Service> GetHostCheckService(void) const;
set<Host::Ptr> GetParentHosts(void) const;
set<shared_ptr<Service> > GetParentServices(void) const;
bool IsReachable(void);
bool IsInDowntime(void) const;
bool IsUp(void);
shared_ptr<Service> ResolveService(const String& name) const;
set<shared_ptr<Service> > GetServices(void) const;
static void InvalidateServicesCache(void);

View File

@ -159,29 +159,14 @@ long Service::GetRetryInterval(void) const
return value;
}
Dictionary::Ptr Service::GetDependencies(void) const
Dictionary::Ptr Service::GetHostDependencies(void) const
{
return Get("dependencies");
return Get("hostdependencies");
}
void Service::GetDependenciesRecursive(const Dictionary::Ptr& result) const {
assert(result);
Dictionary::Ptr dependencies = GetDependencies();
if (!dependencies)
return;
Value dependency;
BOOST_FOREACH(tie(tuples::ignore, dependency), dependencies) {
if (result->Contains(dependency))
continue;
result->Set(dependency, dependency);
Service::Ptr service = Service::GetByName(dependency);
service->GetDependenciesRecursive(result);
}
Dictionary::Ptr Service::GetServiceDependencies(void) const
{
return Get("servicedependencies");
}
Dictionary::Ptr Service::GetGroups(void) const
@ -196,17 +181,7 @@ Dictionary::Ptr Service::GetCheckers(void) const
bool Service::IsReachable(void) const
{
Dictionary::Ptr dependencies = boost::make_shared<Dictionary>();
GetDependenciesRecursive(dependencies);
Value dependency;
BOOST_FOREACH(tie(tuples::ignore, dependency), dependencies) {
Service::Ptr service = Service::GetByName(dependency);
/* ignore ourselves */
if (service->GetName() == GetName())
continue;
BOOST_FOREACH(const Service::Ptr& service, GetParentServices()) {
/* ignore pending services */
if (!service->GetLastCheckResult())
continue;
@ -223,6 +198,14 @@ bool Service::IsReachable(void) const
return false;
}
BOOST_FOREACH(const Host::Ptr& host, GetParentHosts()) {
/* ignore hosts that are up */
if (host->IsUp())
continue;
return false;
}
return true;
}
@ -539,21 +522,23 @@ void Service::ApplyCheckResult(const Dictionary::Ptr& cr)
SetAcknowledgementExpiry(0);
}
/* reschedule dependencies */
Dictionary::Ptr dependencies = GetDependencies();
/* reschedule service dependencies */
BOOST_FOREACH(const Service::Ptr& parent, GetParentServices()) {
parent->SetNextCheck(Utility::GetTime());
}
if (dependencies) {
String svc;
BOOST_FOREACH(tie(tuples::ignore, svc), dependencies) {
if (!Service::Exists(svc))
continue;
Service::Ptr service = Service::GetByName(svc);
/* reschedule host dependencies */
BOOST_FOREACH(const Host::Ptr& parent, GetParentHosts()) {
String hostcheck = parent->GetHostCheck();
if (!hostcheck.IsEmpty()) {
Service::Ptr service = parent->ResolveService(hostcheck);
service->SetNextCheck(Utility::GetTime());
}
}
// TODO: notify our child services/hosts that our state has changed
}
if (GetState() != StateOK)
DowntimeProcessor::TriggerDowntimes(GetSelf());
}
@ -765,3 +750,42 @@ void Service::ProcessCheckResult(const Dictionary::Ptr& cr)
EndpointManager::GetInstance()->SendMulticastMessage(rm);
}
set<Host::Ptr> Service::GetParentHosts(void) const
{
set<Host::Ptr> parents;
/* The service's host is implicitly a parent. */
parents.insert(GetHost());
Dictionary::Ptr dependencies = GetHostDependencies();
if (dependencies) {
String key;
BOOST_FOREACH(tie(key, tuples::ignore), dependencies) {
parents.insert(Host::GetByName(key));
}
}
return parents;
}
set<Service::Ptr> Service::GetParentServices(void) const
{
set<Service::Ptr> parents;
Dictionary::Ptr dependencies = GetServiceDependencies();
if (dependencies) {
String key;
BOOST_FOREACH(tie(key, tuples::ignore), dependencies) {
Service::Ptr service = GetHost()->ResolveService(key);
if (service->GetName() == GetName())
continue;
parents.insert(service);
}
}
return parents;
}

View File

@ -81,11 +81,14 @@ public:
long GetMaxCheckAttempts(void) const;
long GetCheckInterval(void) const;
long GetRetryInterval(void) const;
Dictionary::Ptr GetDependencies(void) const;
void GetDependenciesRecursive(const Dictionary::Ptr& result) const;
Dictionary::Ptr GetHostDependencies(void) const;
Dictionary::Ptr GetServiceDependencies(void) const;
Dictionary::Ptr GetGroups(void) const;
Dictionary::Ptr GetCheckers(void) const;
set<Host::Ptr> GetParentHosts(void) const;
set<Service::Ptr> GetParentServices(void) const;
bool IsReachable(void) const;
bool IsInDowntime(void) const;
@ -93,7 +96,7 @@ public:
void SetSchedulingOffset(long offset);
void SetFirstCheck(bool first);
bool GetFirstCheck(void) const;
bool GetFirstCheck(void) const;
void SetNextCheck(double nextCheck);
double GetNextCheck(void);