diff --git a/doc/4.3-object-types.md b/doc/4.3-object-types.md
index 7160492f3..57ff77b1d 100644
--- a/doc/4.3-object-types.md
+++ b/doc/4.3-object-types.md
@@ -53,6 +53,7 @@ Attributes:
Name |Description
----------------|----------------
display_name |**Optional.** A short description of the host group.
+ groups |**Optional.** An array of nested group names.
### Service
@@ -113,6 +114,7 @@ Attributes:
Name |Description
----------------|----------------
display_name |**Optional.** A short description of the service group.
+ groups |**Optional.** An array of nested group names.
### Notification
@@ -299,6 +301,7 @@ Attributes:
Name |Description
----------------|----------------
display_name |**Optional.** A short description of the user group.
+ groups |**Optional.** An array of nested group names.
### TimePeriod
diff --git a/lib/icinga/host.cpp b/lib/icinga/host.cpp
index 979388fcc..45697bc47 100644
--- a/lib/icinga/host.cpp
+++ b/lib/icinga/host.cpp
@@ -54,7 +54,7 @@ void Host::OnConfigLoaded(void)
HostGroup::Ptr hg = HostGroup::GetByName(name);
if (hg)
- hg->AddMember(GetSelf());
+ hg->ResolveGroupMembership(GetSelf(), true);
}
}
}
@@ -72,7 +72,7 @@ void Host::Stop(void)
HostGroup::Ptr hg = HostGroup::GetByName(name);
if (hg)
- hg->RemoveMember(GetSelf());
+ hg->ResolveGroupMembership(GetSelf(), false);
}
}
diff --git a/lib/icinga/hostgroup.cpp b/lib/icinga/hostgroup.cpp
index cc0d02eaa..d24e18dab 100644
--- a/lib/icinga/hostgroup.cpp
+++ b/lib/icinga/hostgroup.cpp
@@ -46,3 +46,33 @@ void HostGroup::RemoveMember(const Host::Ptr& host)
boost::mutex::scoped_lock lock(m_HostGroupMutex);
m_Members.erase(host);
}
+
+bool HostGroup::ResolveGroupMembership(Host::Ptr const& host, bool add, int rstack) {
+
+ if (add && rstack > 20) {
+ Log(LogWarning, "icinga", "Too many nested groups for group '" + GetName() + "': Host '" +
+ host->GetName() + "' membership assignment failed.");
+
+ return false;
+ }
+
+ Array::Ptr groups = GetGroups();
+
+ if (groups && groups->GetLength() > 0) {
+ ObjectLock olock(groups);
+
+ BOOST_FOREACH(const String& name, groups) {
+ HostGroup::Ptr group = HostGroup::GetByName(name);
+
+ if (group && !group->ResolveGroupMembership(host, add, rstack + 1))
+ return false;
+ }
+ }
+
+ if (add)
+ AddMember(host);
+ else
+ RemoveMember(host);
+
+ return true;
+}
diff --git a/lib/icinga/hostgroup.h b/lib/icinga/hostgroup.h
index b59b8446d..c0187c7db 100644
--- a/lib/icinga/hostgroup.h
+++ b/lib/icinga/hostgroup.h
@@ -42,6 +42,8 @@ public:
void AddMember(const Host::Ptr& host);
void RemoveMember(const Host::Ptr& host);
+ bool ResolveGroupMembership(Host::Ptr const& host, bool add = true, int rstack = 0);
+
private:
mutable boost::mutex m_HostGroupMutex;
std::set m_Members;
diff --git a/lib/icinga/hostgroup.ti b/lib/icinga/hostgroup.ti
index 71693eb3b..43f54c8f6 100644
--- a/lib/icinga/hostgroup.ti
+++ b/lib/icinga/hostgroup.ti
@@ -13,6 +13,8 @@ class HostGroup : DynamicObject
return m_DisplayName;
}}}
};
+
+ [config] Array::Ptr groups;
};
}
diff --git a/lib/icinga/icinga-type.conf b/lib/icinga/icinga-type.conf
index 455243371..048d6535a 100644
--- a/lib/icinga/icinga-type.conf
+++ b/lib/icinga/icinga-type.conf
@@ -72,6 +72,10 @@
%type HostGroup {
%attribute %string "display_name"
+
+ %attribute %array "groups" {
+ %attribute %name(HostGroup) "*"
+ },
}
%type Service %inherits Checkable {
@@ -87,6 +91,10 @@
%type ServiceGroup {
%attribute %string "display_name"
+
+ %attribute %array "groups" {
+ %attribute %name(ServiceGroup) "*"
+ },
}
%type Notification {
@@ -149,7 +157,11 @@
}
%type UserGroup {
- %attribute %string "display_name"
+ %attribute %string "display_name",
+
+ %attribute %array "groups" {
+ %attribute %name(UserGroup) "*"
+ },
}
%type TimePeriod {
diff --git a/lib/icinga/service.cpp b/lib/icinga/service.cpp
index 0fcaecac3..65e2d359d 100644
--- a/lib/icinga/service.cpp
+++ b/lib/icinga/service.cpp
@@ -57,7 +57,7 @@ void Service::OnConfigLoaded(void)
ServiceGroup::Ptr sg = ServiceGroup::GetByName(name);
if (sg)
- sg->AddMember(GetSelf());
+ sg->ResolveGroupMembership(GetSelf(), true);
}
}
diff --git a/lib/icinga/servicegroup.cpp b/lib/icinga/servicegroup.cpp
index a7ac2782e..9cf1b4042 100644
--- a/lib/icinga/servicegroup.cpp
+++ b/lib/icinga/servicegroup.cpp
@@ -47,3 +47,33 @@ void ServiceGroup::RemoveMember(const Service::Ptr& service)
boost::mutex::scoped_lock lock(m_ServiceGroupMutex);
m_Members.erase(service);
}
+
+bool ServiceGroup::ResolveGroupMembership(Service::Ptr const& service, bool add, int rstack) {
+
+ if (add && rstack > 20) {
+ Log(LogWarning, "icinga", "Too many nested groups for group '" + GetName() + "': Service '" +
+ service->GetName() + "' membership assignment failed.");
+
+ return false;
+ }
+
+ Array::Ptr groups = GetGroups();
+
+ if (groups && groups->GetLength() > 0) {
+ ObjectLock olock(groups);
+
+ BOOST_FOREACH(const String& name, groups) {
+ ServiceGroup::Ptr group = ServiceGroup::GetByName(name);
+
+ if (group && !group->ResolveGroupMembership(service, add, rstack + 1))
+ return false;
+ }
+ }
+
+ if (add)
+ AddMember(service);
+ else
+ RemoveMember(service);
+
+ return true;
+}
diff --git a/lib/icinga/servicegroup.h b/lib/icinga/servicegroup.h
index 1ad725ea6..7e93ea5eb 100644
--- a/lib/icinga/servicegroup.h
+++ b/lib/icinga/servicegroup.h
@@ -42,6 +42,8 @@ public:
void AddMember(const Service::Ptr& service);
void RemoveMember(const Service::Ptr& service);
+ bool ResolveGroupMembership(Service::Ptr const& service, bool add = true, int rstack = 0);
+
private:
mutable boost::mutex m_ServiceGroupMutex;
std::set m_Members;
diff --git a/lib/icinga/servicegroup.ti b/lib/icinga/servicegroup.ti
index c07fb4593..5d79331ee 100644
--- a/lib/icinga/servicegroup.ti
+++ b/lib/icinga/servicegroup.ti
@@ -13,6 +13,8 @@ class ServiceGroup : DynamicObject
return m_DisplayName;
}}}
};
+
+ [config] Array::Ptr groups;
};
}
diff --git a/lib/icinga/user.cpp b/lib/icinga/user.cpp
index a62c4eed3..bd9e9a75d 100644
--- a/lib/icinga/user.cpp
+++ b/lib/icinga/user.cpp
@@ -45,11 +45,12 @@ void User::OnConfigLoaded(void)
UserGroup::Ptr ug = UserGroup::GetByName(name);
if (ug)
- ug->AddMember(GetSelf());
+ ug->ResolveGroupMembership(GetSelf(), true);
}
}
}
+
void User::Stop(void)
{
DynamicObject::Stop();
@@ -63,7 +64,7 @@ void User::Stop(void)
UserGroup::Ptr ug = UserGroup::GetByName(name);
if (ug)
- ug->RemoveMember(GetSelf());
+ ug->ResolveGroupMembership(GetSelf(), false);
}
}
}
diff --git a/lib/icinga/usergroup.cpp b/lib/icinga/usergroup.cpp
index 989bc70ff..8ff0a88fb 100644
--- a/lib/icinga/usergroup.cpp
+++ b/lib/icinga/usergroup.cpp
@@ -46,3 +46,34 @@ void UserGroup::RemoveMember(const User::Ptr& user)
boost::mutex::scoped_lock lock(m_UserGroupMutex);
m_Members.erase(user);
}
+
+bool UserGroup::ResolveGroupMembership(User::Ptr const& user, bool add, int rstack) {
+
+ if (add && rstack > 20) {
+ Log(LogWarning, "icinga", "Too many nested groups for group '" + GetName() + "': User '" +
+ user->GetName() + "' membership assignment failed.");
+
+ return false;
+ }
+
+ Array::Ptr groups = GetGroups();
+
+ if (groups && groups->GetLength() > 0) {
+ ObjectLock olock(groups);
+
+ BOOST_FOREACH(const String& name, groups) {
+ UserGroup::Ptr group = UserGroup::GetByName(name);
+
+ if (group && !group->ResolveGroupMembership(user, add, rstack + 1))
+ return false;
+ }
+ }
+
+ if (add)
+ AddMember(user);
+ else
+ RemoveMember(user);
+
+ return true;
+}
+
diff --git a/lib/icinga/usergroup.h b/lib/icinga/usergroup.h
index 9359827be..3338c6cda 100644
--- a/lib/icinga/usergroup.h
+++ b/lib/icinga/usergroup.h
@@ -42,6 +42,8 @@ public:
void AddMember(const User::Ptr& user);
void RemoveMember(const User::Ptr& user);
+ bool ResolveGroupMembership(User::Ptr const& user, bool add = true, int rstack = 0);
+
private:
mutable boost::mutex m_UserGroupMutex;
std::set m_Members;
diff --git a/lib/icinga/usergroup.ti b/lib/icinga/usergroup.ti
index ebdf73f1f..38606d798 100644
--- a/lib/icinga/usergroup.ti
+++ b/lib/icinga/usergroup.ti
@@ -13,6 +13,8 @@ class UserGroup : DynamicObject
return m_DisplayName;
}}}
};
+
+ [config] Array::Ptr groups;
};
}