From f48a6b429bc03ccf421f961e7ce3246207afe16d Mon Sep 17 00:00:00 2001 From: Michael Friedrich Date: Mon, 14 Apr 2014 20:59:41 +0200 Subject: [PATCH] Add nested group support for {Host,Service,User}Group. Fixes #5858 --- doc/4.3-object-types.md | 3 +++ lib/icinga/host.cpp | 4 ++-- lib/icinga/hostgroup.cpp | 30 ++++++++++++++++++++++++++++++ lib/icinga/hostgroup.h | 2 ++ lib/icinga/hostgroup.ti | 2 ++ lib/icinga/icinga-type.conf | 14 +++++++++++++- lib/icinga/service.cpp | 2 +- lib/icinga/servicegroup.cpp | 30 ++++++++++++++++++++++++++++++ lib/icinga/servicegroup.h | 2 ++ lib/icinga/servicegroup.ti | 2 ++ lib/icinga/user.cpp | 5 +++-- lib/icinga/usergroup.cpp | 31 +++++++++++++++++++++++++++++++ lib/icinga/usergroup.h | 2 ++ lib/icinga/usergroup.ti | 2 ++ 14 files changed, 125 insertions(+), 6 deletions(-) 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; }; }