]> granicus.if.org Git - icinga2/commitdiff
Implement support for agent-based checks.
authorGunnar Beutner <gunnar.beutner@netways.de>
Sat, 12 Apr 2014 02:21:09 +0000 (04:21 +0200)
committerGunnar Beutner <gunnar.beutner@netways.de>
Sat, 12 Apr 2014 02:21:09 +0000 (04:21 +0200)
Refs #4865

12 files changed:
components/CMakeLists.txt
components/agent/CMakeLists.txt [new file with mode: 0644]
components/agent/agent-type.conf [new file with mode: 0644]
components/agent/agentchecktask.cpp [new file with mode: 0644]
components/agent/agentchecktask.h [new file with mode: 0644]
components/agent/agentlistener.cpp [new file with mode: 0644]
components/agent/agentlistener.h [new file with mode: 0644]
components/agent/agentlistener.ti [new file with mode: 0644]
itl/command-common.conf
itl/command.conf
lib/icinga/checkable-check.cpp
lib/icinga/checkable.h

index 646172121bfcd2aaaaf69684154bbc69ed6f5c94..527a938e9b11383d60627e88b72a6ba4d43121b7 100644 (file)
@@ -1,3 +1,4 @@
+add_subdirectory(agent)
 add_subdirectory(checker)
 add_subdirectory(cluster)
 add_subdirectory(compat)
diff --git a/components/agent/CMakeLists.txt b/components/agent/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6a956e9
--- /dev/null
@@ -0,0 +1,36 @@
+# Icinga 2
+# Copyright (C) 2012-2014 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.
+
+mkclass_target(agentlistener.ti agentlistener.th)
+
+mkembedconfig_target(agent-type.conf agent-type.cpp)
+
+add_library(agent SHARED
+  agentchecktask.cpp agentlistener.cpp agentlistener.th
+  agent-type.cpp
+)
+
+target_link_libraries(agent ${Boost_LIBRARIES} base config icinga remote)
+
+set_target_properties (
+  agent PROPERTIES
+  INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2
+  FOLDER Components
+)
+
+install(TARGETS agent RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2)
+
diff --git a/components/agent/agent-type.conf b/components/agent/agent-type.conf
new file mode 100644 (file)
index 0000000..58a88dc
--- /dev/null
@@ -0,0 +1,39 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012-2014 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.             *
+ ******************************************************************************/
+
+%type AgentListener {
+       %attribute %string "cert_path",
+       %require "cert_path",
+
+       %attribute %string "key_path",
+       %require "key_path",
+
+       %attribute %string "ca_path",
+       %require "ca_path",
+
+       %attribute %string "crl_path",
+
+       %attribute %string "bind_host",
+       %attribute %string "bind_port",
+       
+       %attribute %string "upstream_name",
+       %attribute %string "upstream_host",
+       %attribute %string "upstream_port",
+       %attribute %number "upstream_interval"
+}
diff --git a/components/agent/agentchecktask.cpp b/components/agent/agentchecktask.cpp
new file mode 100644 (file)
index 0000000..6b6e3a2
--- /dev/null
@@ -0,0 +1,107 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012-2014 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 "agent/agentchecktask.h"
+#include "agent/agentlistener.h"
+#include "icinga/service.h"
+#include "icinga/checkcommand.h"
+#include "icinga/macroprocessor.h"
+#include "icinga/icingaapplication.h"
+#include "base/application.h"
+#include "base/objectlock.h"
+#include "base/convert.h"
+#include "base/utility.h"
+#include "base/initialize.h"
+#include "base/scriptfunction.h"
+#include "base/dynamictype.h"
+
+using namespace icinga;
+
+boost::mutex l_Mutex;
+std::map<Checkable::Ptr, double> l_PendingChecks;
+Timer::Ptr l_AgentTimer;
+
+INITIALIZE_ONCE(&AgentCheckTask::StaticInitialize);
+REGISTER_SCRIPTFUNCTION(AgentCheck, &AgentCheckTask::ScriptFunc);
+
+void AgentCheckTask::StaticInitialize(void)
+{
+       l_AgentTimer = make_shared<Timer>();
+       l_AgentTimer->OnTimerExpired.connect(boost::bind(&AgentCheckTask::AgentTimerHandler));
+       l_AgentTimer->SetInterval(60);
+       l_AgentTimer->Start();
+}
+
+void AgentCheckTask::AgentTimerHandler(void)
+{
+       boost::mutex::scoped_lock lock(l_Mutex);
+
+       std::map<Checkable::Ptr, double> newmap;
+       std::pair<Checkable::Ptr, double> kv;
+       
+       double now = Utility::GetTime();
+
+       BOOST_FOREACH(kv, l_PendingChecks) {
+               if (kv.second < now - 60 && kv.first->IsCheckPending()) {
+                       CheckResult::Ptr cr = make_shared<CheckResult>();
+                       cr->SetOutput("Agent isn't responding.");
+                       cr->SetState(ServiceCritical);
+                       kv.first->ProcessCheckResult(cr);
+               } else {
+                       newmap.insert(kv);
+               }
+       }
+       
+       l_PendingChecks.swap(newmap);
+}
+
+void AgentCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr)
+{
+       Host::Ptr host;
+       Service::Ptr service;
+       tie(host, service) = GetHostService(checkable);
+
+       MacroProcessor::ResolverList resolvers;
+       if (service)
+               resolvers.push_back(std::make_pair("service", service));
+       resolvers.push_back(std::make_pair("host", host));
+       resolvers.push_back(std::make_pair("command", checkable->GetCheckCommand()));
+       resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance()));
+
+       String agent_host = MacroProcessor::ResolveMacros("$agent_host$", resolvers, checkable->GetLastCheckResult());
+       String agent_port = MacroProcessor::ResolveMacros("$agent_port$", resolvers, checkable->GetLastCheckResult());
+
+       if (agent_host.IsEmpty() || agent_port.IsEmpty()) {
+               Log(LogWarning, "agent", "'agent_host' and 'agent_port' must be set for agent checks.");
+               return;
+       }
+       
+       std::pair<String, String> key = std::make_pair(agent_host, agent_port);
+       
+       double now = Utility::GetTime();
+       
+       {
+               boost::mutex::scoped_lock lock(l_Mutex);
+               l_PendingChecks[checkable] = now;
+       }
+       
+       BOOST_FOREACH(const AgentListener::Ptr& al, DynamicType::GetObjects<AgentListener>()) {
+               al->AddConnection(agent_host, agent_port);
+       }
+}
diff --git a/components/agent/agentchecktask.h b/components/agent/agentchecktask.h
new file mode 100644 (file)
index 0000000..2102f2a
--- /dev/null
@@ -0,0 +1,48 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012-2014 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 AGENTCHECKTASK_H
+#define AGENTCHECKTASK_H
+
+#include "icinga/service.h"
+#include "base/timer.h"
+
+namespace icinga
+{
+
+/**
+ * Agent check type.
+ *
+ * @ingroup methods
+ */
+class AgentCheckTask
+{
+public:
+       static void StaticInitialize(void);
+       static void ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr);
+
+private:
+       AgentCheckTask(void);
+       
+       static void AgentTimerHandler(void);
+};
+
+}
+
+#endif /* AGENTCHECKTASK_H */
diff --git a/components/agent/agentlistener.cpp b/components/agent/agentlistener.cpp
new file mode 100644 (file)
index 0000000..4529357
--- /dev/null
@@ -0,0 +1,260 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012-2014 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 "agent/agentlistener.h"
+#include "remote/jsonrpc.h"
+#include "icinga/icingaapplication.h"
+#include "base/netstring.h"
+#include "base/dynamictype.h"
+#include "base/logger_fwd.h"
+#include "base/objectlock.h"
+#include "base/networkstream.h"
+#include "base/application.h"
+#include "base/context.h"
+
+using namespace icinga;
+
+REGISTER_TYPE(AgentListener);
+
+/**
+ * Starts the component.
+ */
+void AgentListener::Start(void)
+{
+       DynamicObject::Start();
+
+       /* set up SSL context */
+       shared_ptr<X509> cert = GetX509Certificate(GetCertPath());
+       SetIdentity(GetCertificateCN(cert));
+       Log(LogInformation, "agent", "My identity: " + GetIdentity());
+
+       m_SSLContext = MakeSSLContext(GetCertPath(), GetKeyPath(), GetCaPath());
+
+       if (!GetCrlPath().IsEmpty())
+               AddCRLToSSLContext(m_SSLContext, GetCrlPath());
+
+       /* create the primary JSON-RPC listener */
+       if (!GetBindPort().IsEmpty())
+               AddListener(GetBindPort());
+               
+       m_AgentTimer = make_shared<Timer>();
+       m_AgentTimer->OnTimerExpired.connect(boost::bind(&AgentListener::AgentTimerHandler, this));
+       m_AgentTimer->SetInterval(GetUpstreamInterval());
+       m_AgentTimer->Start();
+}
+
+shared_ptr<SSL_CTX> AgentListener::GetSSLContext(void) const
+{
+       return m_SSLContext;
+}
+
+/**
+ * Creates a new JSON-RPC listener on the specified port.
+ *
+ * @param service The port to listen on.
+ */
+void AgentListener::AddListener(const String& service)
+{
+       ObjectLock olock(this);
+
+       shared_ptr<SSL_CTX> sslContext = m_SSLContext;
+
+       if (!sslContext)
+               BOOST_THROW_EXCEPTION(std::logic_error("SSL context is required for AddListener()"));
+
+       std::ostringstream s;
+       s << "Adding new listener: port " << service;
+       Log(LogInformation, "agent", s.str());
+
+       TcpSocket::Ptr server = make_shared<TcpSocket>();
+       server->Bind(service, AF_INET6);
+
+       boost::thread thread(boost::bind(&AgentListener::ListenerThreadProc, this, server));
+       thread.detach();
+
+       m_Servers.insert(server);
+}
+
+void AgentListener::ListenerThreadProc(const Socket::Ptr& server)
+{
+       Utility::SetThreadName("Cluster Listener");
+
+       server->Listen();
+
+       for (;;) {
+               Socket::Ptr client = server->Accept();
+
+               Utility::QueueAsyncCallback(boost::bind(&AgentListener::NewClientHandler, this, client, TlsRoleServer));
+       }
+}
+
+/**
+ * Creates a new JSON-RPC client and connects to the specified host and port.
+ *
+ * @param node The remote host.
+ * @param service The remote port.
+ */
+void AgentListener::AddConnection(const String& node, const String& service) {
+       {
+               ObjectLock olock(this);
+
+               shared_ptr<SSL_CTX> sslContext = m_SSLContext;
+
+               if (!sslContext)
+                       BOOST_THROW_EXCEPTION(std::logic_error("SSL context is required for AddConnection()"));
+       }
+
+       TcpSocket::Ptr client = make_shared<TcpSocket>();
+
+       client->Connect(node, service);
+       Utility::QueueAsyncCallback(boost::bind(&AgentListener::NewClientHandler, this, client, TlsRoleClient));
+}
+
+/**
+ * Processes a new client connection.
+ *
+ * @param client The new client.
+ */
+void AgentListener::NewClientHandler(const Socket::Ptr& client, TlsRole role)
+{
+       CONTEXT("Handling new agent client connection");
+
+       NetworkStream::Ptr netStream = make_shared<NetworkStream>(client);
+
+       TlsStream::Ptr tlsStream = make_shared<TlsStream>(netStream, role, m_SSLContext);
+       tlsStream->Handshake();
+
+       shared_ptr<X509> cert = tlsStream->GetPeerCertificate();
+       String identity = GetCertificateCN(cert);
+
+       Log(LogInformation, "agent", "New client connection for identity '" + identity + "'");
+
+       if (identity != GetUpstreamName()) {
+               Dictionary::Ptr request = make_shared<Dictionary>();
+               request->Set("method", "get_crs");
+               JsonRpc::SendMessage(tlsStream, request);
+       }
+
+       Dictionary::Ptr message;
+
+       try {
+               message = JsonRpc::ReadMessage(tlsStream);
+       } catch (const std::exception& ex) {
+               Log(LogWarning, "agent", "Error while reading JSON-RPC message for agent '" + identity + "': " + DiagnosticInformation(ex));
+
+               return;
+       }
+
+       MessageHandler(tlsStream, identity, message);
+       
+       tlsStream->Close();
+}
+
+void AgentListener::MessageHandler(const TlsStream::Ptr& sender, const String& identity, const Dictionary::Ptr& message)
+{
+       CONTEXT("Processing agent message of type '" + message->Get("method") + "'");
+       
+       String method = message->Get("method");
+       
+       if (identity == GetUpstreamName()) {
+               if (method == "get_crs") {
+                       Dictionary::Ptr services = make_shared<Dictionary>();
+
+                       Host::Ptr host = Host::GetByName("localhost");
+                       
+                       if (!host)
+                               Log(LogWarning, "agent", "Agent doesn't have any services for 'localhost'.");
+                       else {
+                               BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) {
+                                       services->Set(service->GetShortName(), Serialize(service->GetLastCheckResult()));
+                               }
+                       }
+                       
+                       Dictionary::Ptr params = make_shared<Dictionary>();
+                       params->Set("services", services);
+                       params->Set("host", Serialize(host->GetLastCheckResult()));
+                       
+                       Dictionary::Ptr request = make_shared<Dictionary>();
+                       request->Set("method", "push_crs");
+                       request->Set("params", params);
+                       
+                       JsonRpc::SendMessage(sender, request);
+               }
+       }
+       
+       if (method == "push_crs") {
+               Host::Ptr host = Host::GetByName(identity);
+               
+               if (!host) {
+                       Log(LogWarning, "agent", "Ignoring check results for host '" + identity + "'.");
+                       return;
+               }
+               
+               Dictionary::Ptr params = message->Get("params");
+               
+               if (!params)
+                       return;
+
+               Value hostcr = Deserialize(params->Get("host"), true);
+               
+               if (!hostcr.IsObjectType<CheckResult>()) {
+                       Log(LogWarning, "agent", "Ignoring invalid check result for host '" + identity + "'.");
+               } else {
+                       CheckResult::Ptr cr = hostcr;
+                       host->ProcessCheckResult(cr);
+               }
+
+               Dictionary::Ptr services = params->Get("services");
+               
+               if (!services)
+                       return;
+               
+               Dictionary::Pair kv;
+               
+               BOOST_FOREACH(kv, services) {
+                       Service::Ptr service = host->GetServiceByShortName(kv.first);
+                       
+                       if (!service) {
+                               Log(LogWarning, "agent", "Ignoring check result for service '" + kv.first + "' on host '" + identity + "'.");
+                               continue;
+                       }
+                       
+                       Value servicecr = Deserialize(kv.second, true);
+                       
+                       if (!servicecr.IsObjectType<CheckResult>()) {
+                               Log(LogWarning, "agent", "Ignoring invalid check result for service '" + kv.first + "' on host '" + identity + "'.");
+                               continue;
+                       }
+                       
+                       CheckResult::Ptr cr = servicecr;
+                       service->ProcessCheckResult(cr);
+               }
+       }
+}
+
+void AgentListener::AgentTimerHandler(void)
+{
+       String host = GetUpstreamHost();
+       String port = GetUpstreamPort();
+
+       if (host.IsEmpty() || port.IsEmpty())
+               return;
+       
+       AddConnection(host, port);
+}
diff --git a/components/agent/agentlistener.h b/components/agent/agentlistener.h
new file mode 100644 (file)
index 0000000..6025b62
--- /dev/null
@@ -0,0 +1,70 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012-2014 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 AGENTLISTENER_H
+#define AGENTLISTENER_H
+
+#include "agent/agentlistener.th"
+#include "base/dynamicobject.h"
+#include "base/timer.h"
+#include "base/array.h"
+#include "base/tcpsocket.h"
+#include "base/tlsstream.h"
+#include "base/utility.h"
+#include "base/tlsutility.h"
+#include "icinga/service.h"
+
+namespace icinga
+{
+
+/**
+ * @ingroup agent
+ */
+class AgentListener : public ObjectImpl<AgentListener>
+{
+public:
+       DECLARE_PTR_TYPEDEFS(AgentListener);
+       DECLARE_TYPENAME(AgentListener);
+
+       virtual void Start(void);
+
+       shared_ptr<SSL_CTX> GetSSLContext(void) const;
+
+private:
+       shared_ptr<SSL_CTX> m_SSLContext;
+       std::set<TcpSocket::Ptr> m_Servers;
+       Timer::Ptr m_Timer;
+
+       Timer::Ptr m_AgentTimer;
+       void AgentTimerHandler(void);
+
+       void AddListener(const String& service);
+       void AddConnection(const String& node, const String& service);
+
+       void NewClientHandler(const Socket::Ptr& client, TlsRole role);
+       void ListenerThreadProc(const Socket::Ptr& server);
+
+       void MessageHandler(const TlsStream::Ptr& sender, const String& identity, const Dictionary::Ptr& message);
+       
+       friend class AgentCheckTask;
+};
+
+}
+
+#endif /* AGENTLISTENER_H */
diff --git a/components/agent/agentlistener.ti b/components/agent/agentlistener.ti
new file mode 100644 (file)
index 0000000..e42c942
--- /dev/null
@@ -0,0 +1,24 @@
+#include "base/dynamicobject.h"
+#include "base/application.h"
+
+namespace icinga
+{
+
+class AgentListener : DynamicObject
+{
+       [config] String cert_path;
+       [config] String key_path;
+       [config] String ca_path;
+       [config] String crl_path;
+       [config] String bind_host;
+       [config] String bind_port;
+       [config] String upstream_host;
+       [config] String upstream_port;
+       [config] String upstream_name;
+       [config] int upstream_interval {
+               default {{{ return 60; }}}
+       };
+       String identity;
+};
+
+}
index 9ad92d200b96c8ba030e869cc052ebfd921488c5..adc29de075dee54e80f22219b9f531d1cd55bab9 100644 (file)
@@ -284,3 +284,8 @@ object CheckCommand "snmp-extend"{
 
        vars.community = "public"
 }
+
+object CheckCommand "agent" {
+       import "agent-check-command"
+}
+
index bb57314def725b6c1a482188f8c60f5f3fc2797a..972a2a1aca02a52ac3a2ded8ef5321a4e5b57b6e 100644 (file)
@@ -31,6 +31,10 @@ template CheckCommand "plugin-check-command" {
        methods.execute = "PluginCheck"
 }
 
+template CheckCommand "agent-check-command" {
+       methods.execute = "AgentCheck"
+}
+
 template NotificationCommand "plugin-notification-command" {
        methods.execute = "PluginNotification"
 }
index 6a51b4a0aa8d80685a51a21727038ab8c824d941..3194b3e563ac726f8c01f08a4567fad82cbc22f2 100644 (file)
@@ -429,6 +429,12 @@ void Checkable::ProcessCheckResult(const CheckResult::Ptr& cr, const String& aut
                OnNotificationsRequested(GetSelf(), recovery ? NotificationRecovery : NotificationProblem, cr, "", "");
 }
 
+bool Checkable::IsCheckPending(void) const
+{
+       ObjectLock olock(this);
+       return m_CheckRunning;
+}
+
 void Checkable::ExecuteCheck(void)
 {
        CONTEXT("Executing check for object '" + GetName() + "'");
index 474ee7b185df981a32f3c3ebfb4fd52013611b8d..3539119f457a1e8e7e81bafe8487d53356822846 100644 (file)
@@ -157,6 +157,8 @@ public:
        int GetModifiedAttributes(void) const;
        void SetModifiedAttributes(int flags);
 
+       bool IsCheckPending(void) const;
+
        static double CalculateExecutionTime(const CheckResult::Ptr& cr);
        static double CalculateLatency(const CheckResult::Ptr& cr);