]> granicus.if.org Git - icinga2/commitdiff
Implemented user groups.
authorGunnar Beutner <gunnar.beutner@netways.de>
Wed, 27 Feb 2013 20:49:03 +0000 (21:49 +0100)
committerGunnar Beutner <gunnar.beutner@netways.de>
Wed, 27 Feb 2013 20:49:03 +0000 (21:49 +0100)
18 files changed:
components/compat/compatcomponent.cpp
itl/types.conf
lib/base/i2-base.h
lib/icinga/Makefile.am
lib/icinga/host.cpp
lib/icinga/hostgroup.cpp
lib/icinga/hostgroup.h
lib/icinga/i2-icinga.h
lib/icinga/icinga.vcxproj
lib/icinga/notification.cpp
lib/icinga/notification.h
lib/icinga/service-notification.cpp
lib/icinga/servicegroup.cpp
lib/icinga/servicegroup.h
lib/icinga/user.cpp
lib/icinga/user.h
lib/icinga/usergroup.cpp [new file with mode: 0644]
lib/icinga/usergroup.h [new file with mode: 0644]

index c04e59070cc4b38024e8a4c0f0df6386a18bb813..229fe35d85b5968acb1cb89dcc5aa58b8f59e06a 100644 (file)
@@ -91,7 +91,7 @@ String CompatComponent::GetCommandPath(void) const
 void CompatComponent::Start(void)
 {
        m_StatusTimer = boost::make_shared<Timer>();
-       m_StatusTimer->SetInterval(15);
+       m_StatusTimer->SetInterval(5);
        m_StatusTimer->OnTimerExpired.connect(boost::bind(&CompatComponent::StatusTimerHandler, this));
        m_StatusTimer->Start();
        m_StatusTimer->Reschedule(0);
index af7b941970926bdcc1ed5c81faccf002874cd5e0..0814e730e10bdfda123aaa754b1c18b0461a1799 100644 (file)
@@ -117,6 +117,10 @@ type Host {
 
                        %attribute dictionary "users" {
                                %attribute string "*"
+                       },
+
+                       %attribute dictionary "groups" {
+                               %attribute string "*"
                        }
                }
        },
@@ -209,6 +213,10 @@ type Service {
 
                        %attribute dictionary "users" {
                                %attribute string "*"
+                       },
+
+                       %attribute dictionary "groups" {
+                               %attribute string "*"
                        }
                }
        },
@@ -243,9 +251,17 @@ type Notification {
        %attribute string "service",
 
        %attribute dictionary "macros" {
-                       %attribute string "*"
+               %attribute string "*"
+       },
+
+       %attribute dictionary "users" {
+               %attribute string "*"
        },
 
+       %attribute dictionary "groups" {
+               %attribute string "*"
+       },
        %attribute dictionary "notification_command" {
                %attribute string "_*"
        },
@@ -263,6 +279,15 @@ type Script {
 type User {
        %attribute dictionary "macros" {
                %attribute string "*"
+       },
+
+       %attribute dictionary "groups" {
+               %attribute string "*"
        }
 }
 
+type UserGroup {
+       %attribute string "display_name",
+       %attribute string "action_url",
+       %attribute string "notes_url"
+}
index ee80e4dfa601674716023af8185756f7cb45decf..a0c33dcbea996c2ed8dba8f0301a9762738ad6ef 100644 (file)
@@ -92,6 +92,7 @@
 #include <list>
 #include <algorithm>
 #include <deque>
+#include <iterator>
 
 using std::vector;
 using std::map;
index 9dba6e9f5dea62cd34370f4c22abfcb7210928cf..e0fea7705b634318e6dafa1da81046c21e9ca54c 100644 (file)
@@ -42,7 +42,9 @@ libicinga_la_SOURCES =  \
        servicegroup.cpp \
        servicegroup.h \
        user.cpp \
-       user.h
+       user.h \
+       usergroup.cpp \
+       usergroup.h
 
 libicinga_la_CPPFLAGS = \
        -DI2_ICINGA_BUILD \
index 6cb24c5559eb214a8e8893a4f756037c3c261b28..c2c72d62d5dcd33e03922f34d35b41506bbd5261 100644 (file)
@@ -22,7 +22,7 @@
 using namespace icinga;
 
 boost::mutex Host::m_ServiceMutex;
-map<String, map<String, weak_ptr<Service> > > Host::m_ServicesCache;
+map<String, map<String, Service::WeakPtr> > Host::m_ServicesCache;
 bool Host::m_ServicesCacheValid = true;
 
 REGISTER_SCRIPTFUNCTION("ValidateServiceDictionary", &Host::ValidateServiceDictionary);
@@ -345,7 +345,7 @@ void Host::RefreshServicesCache(void)
                m_ServicesCacheValid = true;
        }
 
-       map<String, map<String, weak_ptr<Service> > > newServicesCache;
+       map<String, map<String, Service::WeakPtr> > newServicesCache;
 
        BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
                const Service::Ptr& service = static_pointer_cast<Service>(object);
@@ -441,8 +441,8 @@ Service::Ptr Host::GetServiceByShortName(const Host::Ptr& self, const Value& nam
                {
                        boost::mutex::scoped_lock lock(m_ServiceMutex);
 
-                       map<String, weak_ptr<Service> >& services = m_ServicesCache[host_name];
-                       map<String, weak_ptr<Service> >::iterator it = services.find(name);
+                       map<String, Service::WeakPtr>& services = m_ServicesCache[host_name];
+                       map<String, Service::WeakPtr>::iterator it = services.find(name);
 
                        if (it != services.end()) {
                                Service::Ptr service = it->second.lock();
index ef97c42ff3452a885b2696415b6a5207981e497d..7b38fd1c110ff1d0a303f7f69dc6866a5c42c5c2 100644 (file)
@@ -126,7 +126,7 @@ void HostGroup::RefreshMembersCache(void)
                m_MembersCacheValid = true;
        }
 
-       map<String, vector<weak_ptr<Host> > > newMembersCache;
+       map<String, vector<Host::WeakPtr> > newMembersCache;
 
        BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Host")) {
                const Host::Ptr& host = static_pointer_cast<Host>(object);
index 97b802df406309d5ed3398b94993b420358254a7..1e865bf8481143890c04e9217cce6c5c26559d50 100644 (file)
@@ -56,7 +56,7 @@ private:
        Attribute<String> m_ActionUrl;
 
        static boost::mutex m_Mutex;
-       static map<String, vector<weak_ptr<Host> > > m_MembersCache;
+       static map<String, vector<Host::WeakPtr> > m_MembersCache;
        static bool m_MembersCacheValid;
 
        static void RefreshMembersCache(void);
index cb6f9c66d3e94c9ae50cff2657cfc0d403f2caa1..d368fdd93d08365612a3f01f24d3fc2c581a6277 100644 (file)
@@ -47,6 +47,7 @@ using boost::algorithm::is_any_of;
 #include "icingaapplication.h"
 
 #include "user.h"
+#include "usergroup.h"
 
 #include "notification.h"
 #include "notificationrequestmessage.h"
index 44201f77611f49abacffc35bfd48a8c322780e9d..7f55cdd0ab140c2a54e968a5a9ed4558b0fd2b14 100644 (file)
@@ -45,6 +45,7 @@
     <ClCompile Include="service-downtime.cpp" />
     <ClCompile Include="servicegroup.cpp" />
     <ClCompile Include="user.cpp" />
+    <ClCompile Include="usergroup.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="api.h" />
@@ -64,6 +65,7 @@
     <ClInclude Include="service.h" />
     <ClInclude Include="servicegroup.h" />
     <ClInclude Include="user.h" />
+    <ClInclude Include="usergroup.h" />
   </ItemGroup>
   <PropertyGroup Label="Globals">
     <ProjectGuid>{C1FC77E1-04A4-481B-A78B-2F7AF489C2F8}</ProjectGuid>
index be07a1f25c4026d3639998434ede42c089d70b86..a8a4e9e4625dea4ba1f1ee33b0ac9f782e474fb8 100644 (file)
@@ -29,6 +29,7 @@ Notification::Notification(const Dictionary::Ptr& properties)
        RegisterAttribute("notification_command", Attribute_Config, &m_NotificationCommand);
        RegisterAttribute("macros", Attribute_Config, &m_Macros);
        RegisterAttribute("users", Attribute_Config, &m_Users);
+       RegisterAttribute("groups", Attribute_Config, &m_Groups);
        RegisterAttribute("host_name", Attribute_Config, &m_HostName);
        RegisterAttribute("service", Attribute_Config, &m_Service);
 }
@@ -80,7 +81,33 @@ set<User::Ptr> Notification::GetUsers(void) const
        if (users) {
                String name;
                BOOST_FOREACH(tie(tuples::ignore, name), users) {
-                       result.insert(User::GetByName(name));
+                       User::Ptr user = User::GetByName(name);
+
+                       if (!user)
+                               continue;
+
+                       result.insert(user);
+               }
+       }
+
+       return result;
+}
+
+set<UserGroup::Ptr> Notification::GetGroups(void) const
+{
+       set<UserGroup::Ptr> result;
+
+       Dictionary::Ptr groups = m_Groups;
+
+       if (groups) {
+               String name;
+               BOOST_FOREACH(tie(tuples::ignore, name), groups) {
+                       UserGroup::Ptr ug = UserGroup::GetByName(name);
+
+                       if (!ug)
+                               continue;
+
+                       result.insert(ug);
                }
        }
 
@@ -120,12 +147,14 @@ void Notification::BeginExecuteNotification(const Notification::Ptr& self, Notif
 
        Service::Ptr service;
        set<User::Ptr> users;
+       set<UserGroup::Ptr> groups;
 
        {
                ObjectLock olock(self);
                macroDicts.push_back(self->GetMacros());
                service = self->GetService();
                users = self->GetUsers();
+               groups = self->GetGroups();
        }
 
        Host::Ptr host;
@@ -157,14 +186,20 @@ void Notification::BeginExecuteNotification(const Notification::Ptr& self, Notif
 
        Dictionary::Ptr macros = MacroProcessor::MergeMacroDicts(macroDicts);
 
-       int count = 0;
+       set<User::Ptr> allUsers;
+
+       std::copy(users.begin(), users.end(), std::inserter(allUsers, allUsers.begin()));
+
+       BOOST_FOREACH(const UserGroup::Ptr& ug, groups) {
+               set<User::Ptr> members = UserGroup::GetMembers(ug);
+               std::copy(members.begin(), members.end(), std::inserter(allUsers, allUsers.begin()));
+       }
 
-       BOOST_FOREACH(const User::Ptr& user, users) {
+       BOOST_FOREACH(const User::Ptr& user, allUsers) {
                BeginExecuteNotificationHelper(self, macros, type, user);
-               count++;
        }
 
-       if (count == 0) {
+       if (allUsers.size() == 0) {
                /* Send a notification even if there are no users specified. */
                BeginExecuteNotificationHelper(self, macros, type, User::Ptr());
        }
index 3b3c77e1221aa906d7c5868e85423f486754119e..4bbba987ee138eb915e3858aab123f30078acca9 100644 (file)
@@ -61,6 +61,7 @@ public:
        Value GetNotificationCommand(void) const;
        Dictionary::Ptr GetMacros(void) const;
        set<User::Ptr> GetUsers(void) const;
+       set<UserGroup::Ptr> GetGroups(void) const;
 
        static void BeginExecuteNotification(const Notification::Ptr& self, NotificationType type);
 
@@ -73,6 +74,7 @@ private:
        Attribute<Value> m_NotificationCommand;
        Attribute<Dictionary::Ptr> m_Macros;
        Attribute<Dictionary::Ptr> m_Users;
+       Attribute<Dictionary::Ptr> m_Groups;
        Attribute<String> m_HostName;
        Attribute<String> m_Service;
 
index 50641069422d9060743b207f0530483cc0035fdb..e066d180b10f325b1913f176aecd7dbb54ff78d9 100644 (file)
@@ -169,6 +169,10 @@ static void CopyNotificationAttributes(TDict notificationDesc, const ConfigItemB
        if (!users.IsEmpty())
                builder->AddExpression("users", OperatorPlus, users);
 
+       Value groups = notificationDesc->Get("groups");
+       if (!groups.IsEmpty())
+               builder->AddExpression("groups", OperatorPlus, groups);
+
        /*Value notificationInterval = notificationDesc->Get("notification_interval");
        if (!notificationInterval.IsEmpty())
                builder->AddExpression("notification_interval", OperatorSet, notificationInterval);*/
index 2700ec981a0741392e35e13375faf53330b3f51d..f807046dd2354a9bb5de642e54bc62dec3033a3e 100644 (file)
@@ -126,7 +126,7 @@ void ServiceGroup::RefreshMembersCache(void)
                m_MembersCacheValid = true;
        }
 
-       map<String, vector<weak_ptr<Service> > > newMembersCache;
+       map<String, vector<Service::WeakPtr> > newMembersCache;
 
        BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
                const Service::Ptr& service = static_pointer_cast<Service>(object);
index 9c041153b7a33d9c1e8031042bc27cbdb5a02b61..073f515bf8355b083d4241171175f4b24d66557b 100644 (file)
@@ -56,7 +56,7 @@ private:
        Attribute<String> m_ActionUrl;
 
        static boost::mutex m_Mutex;
-       static map<String, vector<weak_ptr<Service> > > m_MembersCache;
+       static map<String, vector<Service::WeakPtr> > m_MembersCache;
        static bool m_MembersCacheValid;
 
        static void RefreshMembersCache(void);
index b1f705a38f503a8bd1d977fa3fcfbf71aa3e9ca7..27b8cd4fcee5a5ad09e4c937b07cd132566ec31a 100644 (file)
@@ -27,6 +27,18 @@ User::User(const Dictionary::Ptr& properties)
        : DynamicObject(properties)
 {
        RegisterAttribute("macros", Attribute_Config, &m_Macros);
+       RegisterAttribute("groups", Attribute_Config, &m_Groups);
+}
+
+User::~User(void)
+{
+       UserGroup::InvalidateMembersCache();
+}
+
+void User::OnAttributeChanged(const String& name, const Value& oldValue)
+{
+       if (name == "groups")
+               UserGroup::InvalidateMembersCache();
 }
 
 User::Ptr User::GetByName(const String& name)
@@ -36,6 +48,11 @@ User::Ptr User::GetByName(const String& name)
        return dynamic_pointer_cast<User>(configObject);
 }
 
+Dictionary::Ptr User::GetGroups(void) const
+{
+       return m_Groups;
+}
+
 Dictionary::Ptr User::GetMacros(void) const
 {
        return m_Macros;
index 0c7e5f6a3048c49ba4e8aa0f60efceebf0501099..f9b475ca0ee0d5486e06af50497bc899658c06a8 100644 (file)
@@ -35,14 +35,21 @@ public:
        typedef weak_ptr<User> WeakPtr;
 
        User(const Dictionary::Ptr& properties);
+       ~User(void);
 
        static User::Ptr GetByName(const String& name);
 
+       Dictionary::Ptr GetGroups(void) const;
+
        Dictionary::Ptr GetMacros(void) const;
        static Dictionary::Ptr CalculateDynamicMacros(const User::Ptr& self);
 
+protected:
+       void OnAttributeChanged(const String& name, const Value& oldValue);
+
 private:
        Attribute<Dictionary::Ptr> m_Macros;
+       Attribute<Dictionary::Ptr> m_Groups;
 };
 
 }
diff --git a/lib/icinga/usergroup.cpp b/lib/icinga/usergroup.cpp
new file mode 100644 (file)
index 0000000..ec1e773
--- /dev/null
@@ -0,0 +1,149 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012 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 "i2-icinga.h"
+
+using namespace icinga;
+
+boost::mutex UserGroup::m_Mutex;
+map<String, vector<User::WeakPtr> > UserGroup::m_MembersCache;
+bool UserGroup::m_MembersCacheValid = true;
+
+REGISTER_TYPE(UserGroup, NULL);
+
+UserGroup::UserGroup(const Dictionary::Ptr& properties)
+       : DynamicObject(properties)
+{
+       RegisterAttribute("display_name", Attribute_Config, &m_DisplayName);
+       RegisterAttribute("notes_url", Attribute_Config, &m_NotesUrl);
+       RegisterAttribute("action_url", Attribute_Config, &m_ActionUrl);
+}
+
+UserGroup::~UserGroup(void)
+{
+       InvalidateMembersCache();
+}
+
+void UserGroup::OnRegistrationCompleted(void)
+{
+       InvalidateMembersCache();
+}
+
+String UserGroup::GetDisplayName(void) const
+{
+       if (!m_DisplayName.IsEmpty())
+               return m_DisplayName;
+       else
+               return GetName();
+}
+
+String UserGroup::GetNotesUrl(void) const
+{
+       return m_NotesUrl;
+}
+
+String UserGroup::GetActionUrl(void) const
+{
+       return m_ActionUrl;
+}
+
+/**
+ * @threadsafety Always.
+ */
+UserGroup::Ptr UserGroup::GetByName(const String& name)
+{
+       DynamicObject::Ptr configObject = DynamicObject::GetObject("UserGroup", name);
+
+       if (!configObject)
+               BOOST_THROW_EXCEPTION(invalid_argument("UserGroup '" + name + "' does not exist."));
+
+       return dynamic_pointer_cast<UserGroup>(configObject);
+}
+
+set<User::Ptr> UserGroup::GetMembers(const UserGroup::Ptr& self)
+{
+       String name;
+
+       {
+               ObjectLock olock(self);
+               name = self->GetName();
+       }
+
+       set<User::Ptr> users;
+
+       {
+               boost::mutex::scoped_lock lock(m_Mutex);
+
+               BOOST_FOREACH(const User::WeakPtr& wuser, m_MembersCache[name]) {
+                       User::Ptr user = wuser.lock();
+
+                       if (!user)
+                               continue;
+
+                       users.insert(user);
+               }
+       }
+
+       return users;
+}
+
+void UserGroup::InvalidateMembersCache(void)
+{
+       {
+               boost::mutex::scoped_lock lock(m_Mutex);
+
+               if (m_MembersCacheValid)
+                       Utility::QueueAsyncCallback(boost::bind(&UserGroup::RefreshMembersCache));
+
+               m_MembersCacheValid = false;
+       }
+}
+
+void UserGroup::RefreshMembersCache(void)
+{
+       {
+               boost::mutex::scoped_lock lock(m_Mutex);
+
+               if (m_MembersCacheValid)
+                       return;
+
+               m_MembersCacheValid = true;
+       }
+
+       map<String, vector<User::WeakPtr> > newMembersCache;
+
+       BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("User")) {
+               const User::Ptr& user = static_pointer_cast<User>(object);
+               ObjectLock olock(user);
+
+               Dictionary::Ptr dict;
+               dict = user->GetGroups();
+
+               if (dict) {
+                       ObjectLock mlock(dict);
+                       Value UserGroup;
+                       BOOST_FOREACH(tie(tuples::ignore, UserGroup), dict) {
+                               newMembersCache[UserGroup].push_back(user);
+                       }
+               }
+       }
+
+       boost::mutex::scoped_lock lock(m_Mutex);
+       m_MembersCache.swap(newMembersCache);
+}
diff --git a/lib/icinga/usergroup.h b/lib/icinga/usergroup.h
new file mode 100644 (file)
index 0000000..91a9cb7
--- /dev/null
@@ -0,0 +1,67 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012 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 USERGROUP_H
+#define USERGROUP_H
+
+namespace icinga
+{
+
+/**
+ * An Icinga user group.
+ *
+ * @ingroup icinga
+ */
+class I2_ICINGA_API UserGroup : public DynamicObject
+{
+public:
+       typedef shared_ptr<UserGroup> Ptr;
+       typedef weak_ptr<UserGroup> WeakPtr;
+
+       UserGroup(const Dictionary::Ptr& properties);
+       ~UserGroup(void);
+
+       static UserGroup::Ptr GetByName(const String& name);
+
+       String GetDisplayName(void) const;
+       String GetNotesUrl(void) const;
+       String GetActionUrl(void) const;
+
+       static set<User::Ptr> GetMembers(const UserGroup::Ptr& self);
+
+       static void InvalidateMembersCache(void);
+
+protected:
+       virtual void OnRegistrationCompleted(void);
+
+private:
+       Attribute<String> m_DisplayName;
+       Attribute<String> m_NotesUrl;
+       Attribute<String> m_ActionUrl;
+
+       static boost::mutex m_Mutex;
+       static map<String, vector<User::WeakPtr> > m_MembersCache;
+       static bool m_MembersCacheValid;
+
+       static void RefreshMembersCache(void);
+};
+
+}
+
+#endif /* HOSTGROUP_H */