]> granicus.if.org Git - icinga2/commitdiff
Cluster: Periodically dump status json.
authorMichael Friedrich <michael.friedrich@netways.de>
Thu, 13 Feb 2014 14:15:16 +0000 (15:15 +0100)
committerMichael Friedrich <michael.friedrich@netways.de>
Thu, 13 Feb 2014 15:34:15 +0000 (16:34 +0100)
Refs #5444

components/cluster/CMakeLists.txt
components/cluster/cluster-type.conf
components/cluster/clusterlistener.cpp
components/cluster/clusterlistener.h
components/cluster/clusterlistener.ti
doc/4.3-object-types.md

index 8695356deb497ef0d4392a1b0e8e8d25c5cdeaaf..f04e9d11b54e9614b9c6a09b01314ed6f42222ed 100644 (file)
@@ -38,4 +38,5 @@ install(TARGETS cluster RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DES
 #install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/icinga2/cluster\")")
 install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/icinga2/cluster/config\")")
 install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/icinga2/cluster/log\")")
+install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/cache/icinga2/cluster\")")
 
index b15a817d5a0fa6e62b6a378a7d1866b689b87afa..e36dc58bde28b528629c0d2196e60b44090a71af 100644 (file)
@@ -34,7 +34,10 @@ type ClusterListener {
 
        %attribute array "peers" {
                %attribute name(Endpoint) "*"
-       }
+       },
+
+        %attribute string "status_path",
+        %attribute number "status_update_interval"
 }
 
 type Endpoint {
index 3b51c5ee3688c70b45a7313da17bf1cb4223eb41..a27b0db8ee469ae01d8d59e49e0d5117813c4d37 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "cluster/clusterlistener.h"
 #include "cluster/endpoint.h"
+#include "icinga/cib.h"
 #include "icinga/domain.h"
 #include "icinga/icingaapplication.h"
 #include "base/netstring.h"
@@ -119,6 +120,12 @@ void ClusterListener::Start(void)
                        }
                }
        }
+
+       m_StatusTimer = make_shared<Timer>();
+       m_StatusTimer->SetInterval(GetStatusUpdateInterval());
+       m_StatusTimer->OnTimerExpired.connect(boost::bind(&ClusterListener::StatusTimerHandler, this));
+       m_StatusTimer->Start();
+       m_StatusTimer->Reschedule(0);
 }
 
 /**
@@ -1558,3 +1565,141 @@ bool ClusterListener::SupportsNotifications(void)
 
        return !type->GetObjects().empty() && IcingaApplication::GetInstance()->GetEnableNotifications();
 }
+
+bool ClusterListener::SupportsFeature(const String& name)
+{
+       DynamicType::Ptr type = DynamicType::GetByName(name);
+
+       if (!type)
+               return false;
+
+       return !type->GetObjects().empty();
+}
+
+void ClusterListener::StatusTimerHandler(void)
+{
+       Log(LogInformation, "cluster", "Writing cluster.json file");
+
+        String statuspath = GetStatusPath();
+        String statuspathtmp = statuspath + ".tmp"; /* XXX make this a global definition */
+
+        std::ofstream statusfp;
+        statusfp.open(statuspathtmp.CStr(), std::ofstream::out | std::ofstream::trunc);
+
+        statusfp << std::fixed;
+
+        statusfp << JsonSerialize(GetClusterStatus());
+
+        statusfp.close();
+
+#ifdef _WIN32
+        _unlink(statuspath.CStr());
+#endif /* _WIN32 */
+
+        if (rename(statuspathtmp.CStr(), statuspath.CStr()) < 0) {
+                BOOST_THROW_EXCEPTION(posix_error()
+                    << boost::errinfo_api_function("rename")
+                    << boost::errinfo_errno(errno)
+                    << boost::errinfo_file_name(statuspathtmp));
+        }
+
+        Log(LogInformation, "cluster", "Finished writing cluster.json file");
+}
+
+Dictionary::Ptr ClusterListener::GetClusterStatus(void)
+{
+       Dictionary::Ptr bag = make_shared<Dictionary>();
+
+       /* cluster stats */
+       bag->Set("node", IcingaApplication::GetInstance()->GetNodeName());
+       bag->Set("identity", GetIdentity());
+
+       double count_endpoints = 0;
+       Array::Ptr not_connected_endpoints = make_shared<Array>();
+       Array::Ptr connected_endpoints = make_shared<Array>();
+
+       BOOST_FOREACH(const Endpoint::Ptr& endpoint, DynamicType::GetObjects<Endpoint>()) {
+               count_endpoints++;
+
+               if(!endpoint->IsConnected() && endpoint->GetName() != GetIdentity())
+                       not_connected_endpoints->Add(endpoint->GetName());
+               else if(endpoint->IsConnected() && endpoint->GetName() != GetIdentity())
+                       connected_endpoints->Add(endpoint->GetName());
+       }
+
+       std::sort(not_connected_endpoints->Begin(), not_connected_endpoints->End());
+       std::sort(connected_endpoints->Begin(), connected_endpoints->End());
+
+       bag->Set("num_endpoints", count_endpoints);
+       bag->Set("num_conn_endpoints", connected_endpoints->GetLength());
+       bag->Set("num_not_conn_endpoints", not_connected_endpoints->GetLength());
+       bag->Set("conn_endpoints", connected_endpoints);
+       bag->Set("not_conn_endpoints", not_connected_endpoints);
+
+       /* features */
+       bag->Set("feature_CheckerComponent", SupportsChecks() ? 1 : 0);
+       bag->Set("feature_NotificationComponent", SupportsNotifications() ? 1 : 0);
+
+       /* XXX find a more generic way of getting features as a list */
+       bag->Set("feature_IdoMysqlConnection", SupportsFeature("IdoMysqlConnection") ? 1 : 0);
+       bag->Set("feature_IdoPgsqlConnection", SupportsFeature("IdoPgsqlConnection") ? 1 : 0);
+       bag->Set("feature_StatusDataWriter", SupportsFeature("StatusDataWriter") ? 1 : 0);
+       bag->Set("feature_CompatLogger", SupportsFeature("CompatLogger") ? 1 : 0);
+       bag->Set("feature_ExternalCommandListener", SupportsFeature("ExternalCommandListener") ? 1 : 0);
+       bag->Set("feature_CheckResultReader", SupportsFeature("CheckResultReader") ? 1 : 0);
+       bag->Set("feature_LivestatusListener", SupportsFeature("LivestatusListener") ? 1 : 0);
+       bag->Set("feature_GraphiteWriter", SupportsFeature("GraphiteWriter") ? 1 : 0);
+       bag->Set("feature_PerfdataWriter", SupportsFeature("PerfdataWriter") ? 1 : 0);
+       bag->Set("feature_FileLogger", SupportsFeature("FileLogger") ? 1 : 0);
+       bag->Set("feature_SyslogLogger", SupportsFeature("SyslogLogger") ? 1 : 0);
+
+
+       /* icinga stats */
+       double interval = Utility::GetTime() - Application::GetStartTime();
+
+       if (interval > 60)
+               interval = 60;
+
+       bag->Set("active_checks", CIB::GetActiveChecksStatistics(interval) / interval);
+       bag->Set("passive_checks", CIB::GetPassiveChecksStatistics(interval) / interval);
+
+       bag->Set("active_checks_1min", CIB::GetActiveChecksStatistics(60));
+       bag->Set("passive_checks_1min", CIB::GetPassiveChecksStatistics(60));
+       bag->Set("active_checks_5min", CIB::GetActiveChecksStatistics(60 * 5));
+       bag->Set("passive_checks_5min", CIB::GetPassiveChecksStatistics(60 * 5));
+       bag->Set("active_checks_15min", CIB::GetActiveChecksStatistics(60 * 15));
+       bag->Set("passive_checks_15min", CIB::GetPassiveChecksStatistics(60 * 15));
+
+       ServiceCheckStatistics scs = CIB::CalculateServiceCheckStats();
+
+       bag->Set("min_latency", scs.min_latency);
+       bag->Set("max_latency", scs.max_latency);
+       bag->Set("avg_latency", scs.avg_latency);
+       bag->Set("min_execution_time", scs.min_latency);
+       bag->Set("max_execution_time", scs.max_latency);
+       bag->Set("avg_execution_time", scs.avg_execution_time);
+
+       ServiceStatistics ss = CIB::CalculateServiceStats();
+
+       bag->Set("num_services_ok", ss.services_ok);
+       bag->Set("num_services_warning", ss.services_warning);
+       bag->Set("num_services_critical", ss.services_critical);
+       bag->Set("num_services_unknown", ss.services_unknown);
+       bag->Set("num_services_pending", ss.services_pending);
+       bag->Set("num_services_unreachable", ss.services_unreachable);
+       bag->Set("num_services_flapping", ss.services_flapping);
+       bag->Set("num_services_in_downtime", ss.services_in_downtime);
+       bag->Set("num_services_acknowledged", ss.services_acknowledged);
+
+       HostStatistics hs = CIB::CalculateHostStats();
+
+       bag->Set("num_hosts_up", hs.hosts_up);
+       bag->Set("num_hosts_down", hs.hosts_down);
+       bag->Set("num_hosts_unreachable", hs.hosts_unreachable);
+       bag->Set("num_hosts_flapping", hs.hosts_flapping);
+       bag->Set("num_hosts_in_downtime", hs.hosts_in_downtime);
+       bag->Set("num_hosts_acknowledged", hs.hosts_acknowledged);
+
+       return bag;
+}
+
index 776ce94eae6cc8433f14b958817f9594a392abbd..5f8e3bf40caf121e289a7a68cefc16454fdc8d18 100644 (file)
@@ -61,6 +61,9 @@ private:
        Timer::Ptr m_ClusterTimer;
        void ClusterTimerHandler(void);
 
+       Timer::Ptr m_StatusTimer;
+        void StatusTimerHandler(void);
+
        std::set<TcpSocket::Ptr> m_Servers;
 
        void AddListener(const String& service);
@@ -107,12 +110,15 @@ private:
 
        static bool SupportsChecks(void);
        static bool SupportsNotifications(void);
+        static bool SupportsFeature(const String& name);
 
        void SetSecurityInfo(const Dictionary::Ptr& message, const DynamicObject::Ptr& object, int privs);
 
        void PersistMessage(const Endpoint::Ptr& source, const Dictionary::Ptr& message);
 
        static void MessageExceptionHandler(boost::exception_ptr exp);
+
+        Dictionary::Ptr GetClusterStatus(void);
 };
 
 }
index ac54697b1fe1e753e5bd50a632624d594553c230..78ddf27066ad6137737e246abd54abd206248b86 100644 (file)
@@ -1,4 +1,5 @@
 #include "base/dynamicobject.h"
+#include "base/application.h"
 
 namespace icinga
 {
@@ -14,6 +15,12 @@ class ClusterListener : DynamicObject
        [config] Array::Ptr peers;
        [state] double log_message_timestamp;
        String identity;
+       [config] String status_path {
+               default {{{ return Application::GetLocalStateDir() + "/cache/icinga2/cluster/cluster.json"; }}}
+       };
+       [config] double status_update_interval {
+               default {{{ return 15; }}}
+       };
 };
 
 }
index 4128f5c29af840e0d5285f57a70e697c04faec85..63a76668f3eb345ade6c4427aaeda7a910ad224c 100644 (file)
@@ -851,15 +851,17 @@ Example:
 
 Attributes:
 
-  Name            |Description
-  ----------------|----------------
-  cert\_path      |**Required.** Path to the public key.
-  key\_path       |**Required.** Path to the private key.
-  ca\_path        |**Required.** Path to the CA certificate file.
-  crl\_path       |**Optional.** Path to the CRL file.
-  bind\_host      |**Optional.** The IP address the cluster listener should be bound to.
-  bind\_port      |**Optional.** The port the cluster listener should be bound to.
-  peers           |**Optional.** A list of
+  Name                      |Description
+  --------------------------|--------------------------
+  cert\_path                |**Required.** Path to the public key.
+  key\_path                 |**Required.** Path to the private key.
+  ca\_path                  |**Required.** Path to the CA certificate file.
+  crl\_path                 |**Optional.** Path to the CRL file.
+  bind\_host                |**Optional.** The IP address the cluster listener should be bound to.
+  bind\_port                |**Optional.** The port the cluster listener should be bound to.
+  peers                     |**Optional.** A list of
+  status\_path              |**Optional.** Path to cluster status file. Defaults to IcingaLocalStateDir + "/cache/icinga2/cluster/cluster.json"
+  status\_update\_interval  |**Optional.** The interval in which the status files are updated. Defaults to 15 seconds.
 
 ### <a id="objecttype-endpoint"></a> Endpoint