mirror of
https://github.com/Icinga/icinga2.git
synced 2025-07-31 01:24:19 +02:00
parent
0571d8a464
commit
45270f1bb8
@ -1,6 +1,4 @@
|
||||
add_subdirectory(agent)
|
||||
add_subdirectory(checker)
|
||||
add_subdirectory(cluster)
|
||||
add_subdirectory(compat)
|
||||
add_subdirectory(db_ido_mysql)
|
||||
add_subdirectory(db_ido_pgsql)
|
||||
|
@ -1,39 +0,0 @@
|
||||
# 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)
|
||||
|
||||
#install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/icinga2/agent\")")
|
||||
install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/icinga2/agent/inventory\")")
|
||||
|
@ -1,39 +0,0 @@
|
||||
/******************************************************************************
|
||||
* 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"
|
||||
}
|
@ -1,133 +0,0 @@
|
||||
/******************************************************************************
|
||||
* 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() && !SendResult(kv.first, false)) {
|
||||
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);
|
||||
}
|
||||
|
||||
bool AgentCheckTask::SendResult(const Checkable::Ptr& checkable, bool enqueue)
|
||||
{
|
||||
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_identity = MacroProcessor::ResolveMacros("$agent_identity$", resolvers, checkable->GetLastCheckResult());
|
||||
String agent_host = MacroProcessor::ResolveMacros("$agent_host$", resolvers, checkable->GetLastCheckResult());
|
||||
String agent_service = MacroProcessor::ResolveMacros("$agent_service$", resolvers, checkable->GetLastCheckResult());
|
||||
|
||||
if (agent_identity.IsEmpty() || agent_host.IsEmpty()) {
|
||||
Log(LogWarning, "agent", "'agent_name' and 'agent_host' must be set for agent checks.");
|
||||
return false;
|
||||
}
|
||||
|
||||
String agent_peer_host = MacroProcessor::ResolveMacros("$agent_peer_host$", resolvers, checkable->GetLastCheckResult());
|
||||
String agent_peer_port = MacroProcessor::ResolveMacros("$agent_peer_port$", resolvers, checkable->GetLastCheckResult());
|
||||
|
||||
double now = Utility::GetTime();
|
||||
|
||||
BOOST_FOREACH(const AgentListener::Ptr& al, DynamicType::GetObjects<AgentListener>()) {
|
||||
double seen = al->GetAgentSeen(agent_identity);
|
||||
|
||||
if (seen < now - 300)
|
||||
continue;
|
||||
|
||||
CheckResult::Ptr cr = al->GetCheckResult(agent_identity, agent_host, agent_service);
|
||||
|
||||
if (cr) {
|
||||
checkable->ProcessCheckResult(cr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (enqueue) {
|
||||
{
|
||||
boost::mutex::scoped_lock lock(l_Mutex);
|
||||
l_PendingChecks[checkable] = now;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const AgentListener::Ptr& al, DynamicType::GetObjects<AgentListener>()) {
|
||||
if (!agent_peer_host.IsEmpty() && !agent_peer_port.IsEmpty())
|
||||
al->AddConnection(agent_peer_host, agent_peer_port);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void AgentCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr)
|
||||
{
|
||||
SendResult(checkable, true);
|
||||
}
|
@ -1,323 +0,0 @@
|
||||
/******************************************************************************
|
||||
* 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"
|
||||
#include <fstream>
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_TYPE(AgentListener);
|
||||
|
||||
/**
|
||||
* Starts the component.
|
||||
*/
|
||||
void AgentListener::Start(void)
|
||||
{
|
||||
DynamicObject::Start();
|
||||
|
||||
m_Results = make_shared<Dictionary>();
|
||||
|
||||
/* 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();
|
||||
m_AgentTimer->Reschedule(0);
|
||||
}
|
||||
|
||||
shared_ptr<SSL_CTX> AgentListener::GetSSLContext(void) const
|
||||
{
|
||||
return m_SSLContext;
|
||||
}
|
||||
|
||||
String AgentListener::GetInventoryDir(void)
|
||||
{
|
||||
return Application::GetLocalStateDir() + "/lib/icinga2/agent/inventory/";
|
||||
}
|
||||
|
||||
/**
|
||||
* 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");
|
||||
|
||||
TlsStream::Ptr tlsStream;
|
||||
|
||||
{
|
||||
ObjectLock olock(this);
|
||||
tlsStream = make_shared<TlsStream>(client, 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);
|
||||
}
|
||||
|
||||
try {
|
||||
Dictionary::Ptr message = JsonRpc::ReadMessage(tlsStream);
|
||||
MessageHandler(tlsStream, identity, message);
|
||||
} catch (const std::exception& ex) {
|
||||
Log(LogWarning, "agent", "Error while reading JSON-RPC message for agent '" + identity + "': " + DiagnosticInformation(ex));
|
||||
}
|
||||
|
||||
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 hosts = make_shared<Dictionary>();
|
||||
|
||||
BOOST_FOREACH(const Host::Ptr& host, DynamicType::GetObjects<Host>()) {
|
||||
Dictionary::Ptr hostInfo = make_shared<Dictionary>();
|
||||
|
||||
hostInfo->Set("cr", Serialize(host->GetLastCheckResult()));
|
||||
|
||||
Dictionary::Ptr services = make_shared<Dictionary>();
|
||||
|
||||
BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) {
|
||||
Dictionary::Ptr serviceInfo = make_shared<Dictionary>();
|
||||
serviceInfo->Set("cr", Serialize(service->GetLastCheckResult()));
|
||||
services->Set(service->GetShortName(), serviceInfo);
|
||||
}
|
||||
|
||||
hostInfo->Set("services", services);
|
||||
|
||||
hosts->Set(host->GetName(), hostInfo);
|
||||
}
|
||||
|
||||
Dictionary::Ptr params = make_shared<Dictionary>();
|
||||
params->Set("hosts", hosts);
|
||||
|
||||
Dictionary::Ptr request = make_shared<Dictionary>();
|
||||
request->Set("method", "push_crs");
|
||||
request->Set("params", params);
|
||||
|
||||
JsonRpc::SendMessage(sender, request);
|
||||
}
|
||||
}
|
||||
|
||||
if (method == "push_crs") {
|
||||
Value paramsv = message->Get("params");
|
||||
|
||||
if (paramsv.IsEmpty() || !paramsv.IsObjectType<Dictionary>())
|
||||
return;
|
||||
|
||||
Dictionary::Ptr params = paramsv;
|
||||
|
||||
params->Set("seen", Utility::GetTime());
|
||||
|
||||
Dictionary::Ptr inventoryDescr = make_shared<Dictionary>();
|
||||
inventoryDescr->Set("identity", identity);
|
||||
inventoryDescr->Set("params", params);
|
||||
|
||||
String inventoryFile = GetInventoryDir() + SHA256(identity);
|
||||
String inventoryTempFile = inventoryFile + ".tmp";
|
||||
|
||||
std::ofstream fp(inventoryTempFile.CStr(), std::ofstream::out | std::ostream::trunc);
|
||||
fp << JsonSerialize(inventoryDescr);
|
||||
fp.close();
|
||||
|
||||
#ifdef _WIN32
|
||||
_unlink(inventoryFile.CStr());
|
||||
#endif /* _WIN32 */
|
||||
|
||||
if (rename(inventoryTempFile.CStr(), inventoryFile.CStr()) < 0) {
|
||||
BOOST_THROW_EXCEPTION(posix_error()
|
||||
<< boost::errinfo_api_function("rename")
|
||||
<< boost::errinfo_errno(errno)
|
||||
<< boost::errinfo_file_name(inventoryTempFile));
|
||||
}
|
||||
|
||||
m_Results->Set(identity, params);
|
||||
}
|
||||
}
|
||||
|
||||
double AgentListener::GetAgentSeen(const String& agentIdentity)
|
||||
{
|
||||
Dictionary::Ptr agentparams = m_Results->Get(agentIdentity);
|
||||
|
||||
if (!agentparams)
|
||||
return 0;
|
||||
|
||||
return agentparams->Get("seen");
|
||||
}
|
||||
|
||||
CheckResult::Ptr AgentListener::GetCheckResult(const String& agentIdentity, const String& hostName, const String& serviceName)
|
||||
{
|
||||
Dictionary::Ptr agentparams = m_Results->Get(agentIdentity);
|
||||
|
||||
if (!agentparams)
|
||||
return CheckResult::Ptr();
|
||||
|
||||
Value hostsv = agentparams->Get("hosts");
|
||||
|
||||
if (hostsv.IsEmpty() || !hostsv.IsObjectType<Dictionary>())
|
||||
return CheckResult::Ptr();
|
||||
|
||||
Dictionary::Ptr hosts = hostsv;
|
||||
|
||||
Value hostv = hosts->Get(hostName);
|
||||
|
||||
if (hostv.IsEmpty() || !hostv.IsObjectType<Dictionary>())
|
||||
return CheckResult::Ptr();
|
||||
|
||||
Dictionary::Ptr host = hostv;
|
||||
|
||||
if (serviceName.IsEmpty()) {
|
||||
Value hostcrv = Deserialize(host->Get("cr"));
|
||||
|
||||
if (hostcrv.IsEmpty() || !hostcrv.IsObjectType<CheckResult>())
|
||||
return CheckResult::Ptr();
|
||||
|
||||
return hostcrv;
|
||||
} else {
|
||||
Value servicesv = host->Get("services");
|
||||
|
||||
if (servicesv.IsEmpty() || !servicesv.IsObjectType<Dictionary>())
|
||||
return CheckResult::Ptr();
|
||||
|
||||
Dictionary::Ptr services = servicesv;
|
||||
|
||||
Value servicev = services->Get(serviceName);
|
||||
|
||||
if (servicev.IsEmpty() || !servicev.IsObjectType<Dictionary>())
|
||||
return CheckResult::Ptr();
|
||||
|
||||
Dictionary::Ptr service = servicev;
|
||||
|
||||
Value servicecrv = Deserialize(service->Get("cr"));
|
||||
|
||||
if (servicecrv.IsEmpty() || !servicecrv.IsObjectType<CheckResult>())
|
||||
return CheckResult::Ptr();
|
||||
|
||||
return servicecrv;
|
||||
}
|
||||
}
|
||||
|
||||
void AgentListener::AgentTimerHandler(void)
|
||||
{
|
||||
String host = GetUpstreamHost();
|
||||
String port = GetUpstreamPort();
|
||||
|
||||
if (host.IsEmpty() || port.IsEmpty())
|
||||
return;
|
||||
|
||||
AddConnection(host, port);
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
#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;
|
||||
};
|
||||
|
||||
}
|
@ -21,7 +21,7 @@ mkembedconfig_target(checker-type.conf checker-type.cpp)
|
||||
|
||||
add_library(checker SHARED checkercomponent.cpp checkercomponent.th checker-type.cpp)
|
||||
|
||||
target_link_libraries(checker ${Boost_LIBRARIES} base config icinga)
|
||||
target_link_libraries(checker ${Boost_LIBRARIES} base config icinga remote)
|
||||
|
||||
set_target_properties (
|
||||
checker PROPERTIES
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "checker/checkercomponent.h"
|
||||
#include "icinga/icingaapplication.h"
|
||||
#include "icinga/cib.h"
|
||||
#include "remote/apilistener.h"
|
||||
#include "base/dynamictype.h"
|
||||
#include "base/objectlock.h"
|
||||
#include "base/utility.h"
|
||||
@ -63,7 +64,6 @@ void CheckerComponent::OnConfigLoaded(void)
|
||||
{
|
||||
DynamicObject::OnStarted.connect(bind(&CheckerComponent::ObjectHandler, this, _1));
|
||||
DynamicObject::OnStopped.connect(bind(&CheckerComponent::ObjectHandler, this, _1));
|
||||
DynamicObject::OnAuthorityChanged.connect(bind(&CheckerComponent::ObjectHandler, this, _1));
|
||||
|
||||
Checkable::OnNextCheckChanged.connect(bind(&CheckerComponent::NextCheckChangedHandler, this, _1));
|
||||
}
|
||||
@ -117,12 +117,6 @@ void CheckerComponent::CheckThreadProc(void)
|
||||
CheckTimeView::iterator it = idx.begin();
|
||||
Checkable::Ptr checkable = *it;
|
||||
|
||||
if (!checkable->HasAuthority("checker")) {
|
||||
m_IdleCheckables.erase(checkable);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
double wait = checkable->GetNextCheck() - Utility::GetTime();
|
||||
|
||||
if (wait > 0) {
|
||||
@ -227,7 +221,7 @@ void CheckerComponent::ExecuteCheckHelper(const Checkable::Ptr& checkable)
|
||||
if (it != m_PendingCheckables.end()) {
|
||||
m_PendingCheckables.erase(it);
|
||||
|
||||
if (checkable->IsActive() && checkable->HasAuthority("checker"))
|
||||
if (checkable->IsActive())
|
||||
m_IdleCheckables.insert(checkable);
|
||||
|
||||
m_CV.notify_all();
|
||||
@ -257,10 +251,13 @@ void CheckerComponent::ObjectHandler(const DynamicObject::Ptr& object)
|
||||
|
||||
Checkable::Ptr checkable = static_pointer_cast<Checkable>(object);
|
||||
|
||||
Zone::Ptr zone = Zone::GetByName(checkable->GetZone());
|
||||
bool same_zone = (!zone || Zone::GetLocalZone() == zone);
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_Mutex);
|
||||
|
||||
if (object->IsActive() && object->HasAuthority("checker")) {
|
||||
if (object->IsActive() && same_zone) {
|
||||
if (m_PendingCheckables.find(checkable) != m_PendingCheckables.end())
|
||||
return;
|
||||
|
||||
|
@ -1,40 +0,0 @@
|
||||
# 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(clusterlistener.ti clusterlistener.th)
|
||||
|
||||
mkembedconfig_target(cluster-type.conf cluster-type.cpp)
|
||||
|
||||
add_library(cluster SHARED
|
||||
clusterchecktask.cpp clusterlink.cpp clusterlistener.cpp clusterlistener.th
|
||||
cluster-type.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(cluster ${Boost_LIBRARIES} base config icinga remote)
|
||||
|
||||
set_target_properties (
|
||||
cluster PROPERTIES
|
||||
INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2
|
||||
FOLDER Components
|
||||
)
|
||||
|
||||
install(TARGETS cluster RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2)
|
||||
|
||||
#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\")")
|
||||
|
@ -1,38 +0,0 @@
|
||||
/******************************************************************************
|
||||
* 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 ClusterListener {
|
||||
%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 %array "peers" {
|
||||
%attribute %name(Endpoint) "*"
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,139 +0,0 @@
|
||||
/******************************************************************************
|
||||
* 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 CLUSTERLISTENER_H
|
||||
#define CLUSTERLISTENER_H
|
||||
|
||||
#include "cluster/clusterlistener.th"
|
||||
#include "cluster/clusterlink.h"
|
||||
#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 "base/stdiostream.h"
|
||||
#include "base/workqueue.h"
|
||||
#include "icinga/service.h"
|
||||
#include "remote/endpoint.h"
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
/**
|
||||
* @ingroup cluster
|
||||
*/
|
||||
struct EndpointPeerInfo
|
||||
{
|
||||
double Seen;
|
||||
Array::Ptr Peers;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup cluster
|
||||
*/
|
||||
class ClusterListener : public ObjectImpl<ClusterListener>
|
||||
{
|
||||
public:
|
||||
DECLARE_PTR_TYPEDEFS(ClusterListener);
|
||||
DECLARE_TYPENAME(ClusterListener);
|
||||
|
||||
static Value StatsFunc(Dictionary::Ptr& status, Dictionary::Ptr& perfdata);
|
||||
|
||||
virtual void Start(void);
|
||||
virtual void Stop(void);
|
||||
|
||||
shared_ptr<SSL_CTX> GetSSLContext(void) const;
|
||||
String GetClusterDir(void) const;
|
||||
|
||||
std::pair<Dictionary::Ptr, Dictionary::Ptr> GetClusterStatus(void);
|
||||
|
||||
private:
|
||||
shared_ptr<SSL_CTX> m_SSLContext;
|
||||
|
||||
WorkQueue m_RelayQueue;
|
||||
WorkQueue m_MessageQueue;
|
||||
WorkQueue m_LogQueue;
|
||||
|
||||
Timer::Ptr m_ClusterTimer;
|
||||
void ClusterTimerHandler(void);
|
||||
|
||||
std::set<TcpSocket::Ptr> m_Servers;
|
||||
|
||||
void AddListener(const String& service);
|
||||
void AddConnection(const String& node, const String& service);
|
||||
|
||||
static void ConfigGlobHandler(const Dictionary::Ptr& config, const String& file, bool basename);
|
||||
|
||||
void NewClientHandler(const Socket::Ptr& client, TlsRole role);
|
||||
void ListenerThreadProc(const Socket::Ptr& server);
|
||||
|
||||
std::map<String, EndpointPeerInfo> m_VisibleEndpoints;
|
||||
|
||||
void UpdateLinks(void);
|
||||
|
||||
void AsyncRelayMessage(const Endpoint::Ptr& source, const Endpoint::Ptr& destination, const Dictionary::Ptr& message, bool persistent);
|
||||
void RelayMessage(const Endpoint::Ptr& source, const Endpoint::Ptr& destination, const Dictionary::Ptr& message, bool persistent);
|
||||
|
||||
void OpenLogFile(void);
|
||||
void RotateLogFile(void);
|
||||
void CloseLogFile(void);
|
||||
static void LogGlobHandler(std::vector<int>& files, const String& file);
|
||||
void ReplayLog(const Endpoint::Ptr& endpoint, const Stream::Ptr& stream);
|
||||
|
||||
Stream::Ptr m_LogFile;
|
||||
size_t m_LogMessageCount;
|
||||
|
||||
void CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const String& authority);
|
||||
void NextCheckChangedHandler(const Checkable::Ptr& checkable, double nextCheck, const String& authority);
|
||||
void NextNotificationChangedHandler(const Notification::Ptr& notification, double nextCheck, const String& authority);
|
||||
void ForceNextCheckChangedHandler(const Checkable::Ptr& checkable, bool forced, const String& authority);
|
||||
void ForceNextNotificationChangedHandler(const Checkable::Ptr& checkable, bool forced, const String& authority);
|
||||
void EnableActiveChecksChangedHandler(const Checkable::Ptr& checkable, bool enabled, const String& authority);
|
||||
void EnablePassiveChecksChangedHandler(const Checkable::Ptr& checkable, bool enabled, const String& authority);
|
||||
void EnableNotificationsChangedHandler(const Checkable::Ptr& checkable, bool enabled, const String& authority);
|
||||
void EnableFlappingChangedHandler(const Checkable::Ptr& checkable, bool enabled, const String& authority);
|
||||
void CommentAddedHandler(const Checkable::Ptr& checkable, const Comment::Ptr& comment, const String& authority);
|
||||
void CommentRemovedHandler(const Checkable::Ptr& checkable, const Comment::Ptr& comment, const String& authority);
|
||||
void DowntimeAddedHandler(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime, const String& authority);
|
||||
void DowntimeRemovedHandler(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime, const String& authority);
|
||||
void AcknowledgementSetHandler(const Checkable::Ptr& checkable, const String& author, const String& comment, AcknowledgementType type, double expiry, const String& authority);
|
||||
void AcknowledgementClearedHandler(const Checkable::Ptr& checkable, const String& authority);
|
||||
|
||||
void AsyncMessageHandler(const Endpoint::Ptr& sender, const Dictionary::Ptr& message);
|
||||
void MessageHandler(const Endpoint::Ptr& sender, const Dictionary::Ptr& message);
|
||||
|
||||
bool IsAuthority(const DynamicObject::Ptr& object, const String& type);
|
||||
void UpdateAuthority(void);
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* CLUSTERLISTENER_H */
|
@ -21,7 +21,7 @@ mkembedconfig_target(demo-type.conf demo-type.cpp)
|
||||
|
||||
add_library(demo SHARED demo.cpp demo.th demo-type.cpp)
|
||||
|
||||
target_link_libraries(demo ${Boost_LIBRARIES} base config icinga)
|
||||
target_link_libraries(demo ${Boost_LIBRARIES} base config icinga remote)
|
||||
|
||||
set_target_properties (
|
||||
demo PROPERTIES
|
||||
|
@ -18,6 +18,8 @@
|
||||
******************************************************************************/
|
||||
|
||||
#include "demo/demo.h"
|
||||
#include "remote/apilistener.h"
|
||||
#include "remote/apifunction.h"
|
||||
#include "base/dynamictype.h"
|
||||
#include "base/logger_fwd.h"
|
||||
|
||||
@ -25,6 +27,8 @@ using namespace icinga;
|
||||
|
||||
REGISTER_TYPE(Demo);
|
||||
|
||||
REGISTER_APIFUNCTION(HelloWorld, demo, &Demo::DemoMessageHandler);
|
||||
|
||||
/**
|
||||
* Starts the component.
|
||||
*/
|
||||
@ -39,19 +43,23 @@ void Demo::Start(void)
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the component.
|
||||
*/
|
||||
void Demo::Stop(void)
|
||||
{
|
||||
/* Nothing to do here. */
|
||||
}
|
||||
|
||||
/**
|
||||
* Periodically sends a demo::HelloWorld message.
|
||||
*
|
||||
* @param - Event arguments for the timer.
|
||||
* Periodically broadcasts an API message.
|
||||
*/
|
||||
void Demo::DemoTimerHandler(void)
|
||||
{
|
||||
Log(LogInformation, "demo", "Hello World!");
|
||||
Dictionary::Ptr message = make_shared<Dictionary>();
|
||||
message->Set("method", "demo::HelloWorld");
|
||||
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
if (listener) {
|
||||
listener->RelayMessage(MessageOrigin(), DynamicObject::Ptr(), message, true);
|
||||
Log(LogInformation, "demo", "Sent demo::HelloWorld message");
|
||||
}
|
||||
}
|
||||
|
||||
Value Demo::DemoMessageHandler(const MessageOrigin& origin, const Dictionary::Ptr& params)
|
||||
{
|
||||
Log(LogInformation, "demo", "Got demo message from '" + origin.FromClient->GetEndpoint()->GetName() + "'");
|
||||
|
||||
return Empty;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define DEMO_H
|
||||
|
||||
#include "demo/demo.th"
|
||||
#include "remote/messageorigin.h"
|
||||
#include "base/timer.h"
|
||||
|
||||
namespace icinga
|
||||
@ -36,7 +37,9 @@ public:
|
||||
DECLARE_TYPENAME(Demo);
|
||||
|
||||
virtual void Start(void);
|
||||
virtual void Stop(void);
|
||||
|
||||
static Value DemoMessageHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||
|
||||
|
||||
private:
|
||||
Timer::Ptr m_DemoTimer;
|
||||
|
@ -40,7 +40,7 @@ install_if_not_exists(icinga2/conf.d/hosts/localhost/users.conf ${CMAKE_INSTALL_
|
||||
install_if_not_exists(icinga2/conf.d/notifications.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/conf.d)
|
||||
install_if_not_exists(icinga2/conf.d/timeperiods.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/conf.d)
|
||||
install_if_not_exists(icinga2/conf.d/users.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/conf.d)
|
||||
install_if_not_exists(icinga2/features-available/agent.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available)
|
||||
install_if_not_exists(icinga2/features-available/api.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available)
|
||||
install_if_not_exists(icinga2/features-available/checker.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available)
|
||||
install_if_not_exists(icinga2/features-available/command.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available)
|
||||
install_if_not_exists(icinga2/features-available/compatlog.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available)
|
||||
@ -59,6 +59,8 @@ install_if_not_exists(icinga2/scripts/mail-host-notification.sh ${CMAKE_INSTALL_
|
||||
install_if_not_exists(icinga2/scripts/mail-service-notification.sh ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/scripts)
|
||||
install_if_not_exists(logrotate.d/icinga2 ${CMAKE_INSTALL_SYSCONFDIR}/logrotate.d)
|
||||
|
||||
install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_SYSCONFDIR}/icinga2/pki\")")
|
||||
|
||||
if(NOT WIN32)
|
||||
install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_SYSCONFDIR}/icinga2/features-enabled\")")
|
||||
install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -E create_symlink ../features-available/checker.conf \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_SYSCONFDIR}/icinga2/features-enabled/checker.conf\")")
|
||||
|
@ -1,7 +1,13 @@
|
||||
/**
|
||||
* This file defines global constants which can be used in
|
||||
* the other configuration files. At a minimum the
|
||||
* PluginDir constant should be defined.
|
||||
* the other configuration files.
|
||||
*/
|
||||
|
||||
/* The directory which contains the plugins from the Monitoring Plugins project. */
|
||||
const PluginDir = "/usr/lib/nagios/plugins"
|
||||
|
||||
/* Our local instance name. This should be the common name from the API certificate */
|
||||
const NodeName = "localhost"
|
||||
|
||||
/* Our local zone name. */
|
||||
const ZoneName = "master"
|
||||
|
@ -1,11 +0,0 @@
|
||||
/**
|
||||
* The agent listener accepts checks from agents.
|
||||
*/
|
||||
|
||||
library "agent"
|
||||
|
||||
object AgentListener "agent" {
|
||||
cert_path = SysconfDir + "/icinga2/pki/your-master.crt"
|
||||
key_path = SysconfDir + "/icinga2/pki/your-master.key"
|
||||
ca_path = SysconfDir + "/icinga2/pki/ca.crt"
|
||||
}
|
27
etc/icinga2/features-available/api.conf
Normal file
27
etc/icinga2/features-available/api.conf
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* The API listener is used for distributed monitoring setups.
|
||||
*/
|
||||
|
||||
object ApiListener "api" {
|
||||
cert_path = SysconfDir + "/icinga2/pki/" + NodeName + ".crt"
|
||||
key_path = SysconfDir + "/icinga2/pki/" + NodeName + ".key"
|
||||
ca_path = SysconfDir + "/icinga2/pki/ca.crt"
|
||||
}
|
||||
|
||||
object Endpoint NodeName {
|
||||
host = NodeName
|
||||
}
|
||||
|
||||
object Zone ZoneName {
|
||||
endpoints = [ NodeName ]
|
||||
}
|
||||
|
||||
/*object Endpoint "satellite.example.org" {
|
||||
host = "satellite.example.org"
|
||||
}
|
||||
|
||||
object Zone "satellite" {
|
||||
parent = "master"
|
||||
endpoints = [ "satellite.example.org" ]
|
||||
}*/
|
||||
|
@ -652,6 +652,9 @@ VOID WINAPI ServiceMain(DWORD argc, LPSTR *argv)
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
/* must be called before using any other libbase functions */
|
||||
Application::InitializeBase();
|
||||
|
||||
/* Set command-line arguments. */
|
||||
Application::SetArgC(argc);
|
||||
Application::SetArgV(argv);
|
||||
|
@ -103,6 +103,11 @@ Application::~Application(void)
|
||||
m_Instance = NULL;
|
||||
}
|
||||
|
||||
void Application::InitializeBase(void)
|
||||
{
|
||||
Utility::ExecuteDeferredInitializers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a pointer to the application singleton object.
|
||||
*
|
||||
|
@ -26,9 +26,8 @@
|
||||
#include "base/dynamicobject.h"
|
||||
#include "base/process.h"
|
||||
|
||||
namespace icinga {
|
||||
|
||||
class Component;
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
/**
|
||||
* Abstract base class for applications.
|
||||
@ -41,6 +40,8 @@ public:
|
||||
|
||||
~Application(void);
|
||||
|
||||
static void InitializeBase(void);
|
||||
|
||||
static Application::Ptr GetInstance(void);
|
||||
|
||||
int Run(void);
|
||||
|
@ -44,8 +44,7 @@ INITIALIZE_ONCE(&DynamicObject::StaticInitialize);
|
||||
|
||||
boost::signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnStarted;
|
||||
boost::signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnStopped;
|
||||
boost::signals2::signal<void (const DynamicObject::Ptr&, const String&)> DynamicObject::OnStateChanged;
|
||||
boost::signals2::signal<void (const DynamicObject::Ptr&, const String&, bool)> DynamicObject::OnAuthorityChanged;
|
||||
boost::signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnStateChanged;
|
||||
boost::signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnVarsChanged;
|
||||
|
||||
void DynamicObject::StaticInitialize(void)
|
||||
@ -71,56 +70,6 @@ bool DynamicObject::IsActive(void) const
|
||||
return GetActive();
|
||||
}
|
||||
|
||||
void DynamicObject::SetAuthority(const String& type, bool value)
|
||||
{
|
||||
ASSERT(!OwnsLock());
|
||||
|
||||
{
|
||||
ObjectLock olock(this);
|
||||
|
||||
bool old_value = HasAuthority(type);
|
||||
|
||||
if (old_value == value)
|
||||
return;
|
||||
|
||||
if (GetAuthorityInfo() == NULL)
|
||||
SetAuthorityInfo(make_shared<Dictionary>());
|
||||
|
||||
GetAuthorityInfo()->Set(type, value);
|
||||
}
|
||||
|
||||
OnAuthorityChanged(GetSelf(), type, value);
|
||||
}
|
||||
|
||||
bool DynamicObject::HasAuthority(const String& type) const
|
||||
{
|
||||
Dictionary::Ptr authorityInfo = GetAuthorityInfo();
|
||||
|
||||
if (!authorityInfo || !authorityInfo->Contains(type))
|
||||
return true;
|
||||
|
||||
return authorityInfo->Get(type);
|
||||
}
|
||||
|
||||
void DynamicObject::SetPrivileges(const String& instance, int privs)
|
||||
{
|
||||
m_Privileges[instance] = privs;
|
||||
}
|
||||
|
||||
bool DynamicObject::HasPrivileges(const String& instance, int privs) const
|
||||
{
|
||||
if (privs == 0)
|
||||
return true;
|
||||
|
||||
std::map<String, int>::const_iterator it;
|
||||
it = m_Privileges.find(instance);
|
||||
|
||||
if (it == m_Privileges.end())
|
||||
return false;
|
||||
|
||||
return (it->second & privs) == privs;
|
||||
}
|
||||
|
||||
void DynamicObject::SetExtension(const String& key, const Object::Ptr& object)
|
||||
{
|
||||
Dictionary::Ptr extensions = GetExtensions();
|
||||
|
@ -77,8 +77,7 @@ public:
|
||||
|
||||
static boost::signals2::signal<void (const DynamicObject::Ptr&)> OnStarted;
|
||||
static boost::signals2::signal<void (const DynamicObject::Ptr&)> OnStopped;
|
||||
static boost::signals2::signal<void (const DynamicObject::Ptr&, const String&)> OnStateChanged;
|
||||
static boost::signals2::signal<void (const DynamicObject::Ptr&, const String&, bool)> OnAuthorityChanged;
|
||||
static boost::signals2::signal<void (const DynamicObject::Ptr&)> OnStateChanged;
|
||||
static boost::signals2::signal<void (const DynamicObject::Ptr&)> OnVarsChanged;
|
||||
|
||||
Value InvokeMethod(const String& method, const std::vector<Value>& arguments);
|
||||
@ -87,12 +86,6 @@ public:
|
||||
|
||||
bool IsActive(void) const;
|
||||
|
||||
void SetAuthority(const String& type, bool value);
|
||||
bool HasAuthority(const String& type) const;
|
||||
|
||||
void SetPrivileges(const String& instance, int privs);
|
||||
bool HasPrivileges(const String& instance, int privs) const;
|
||||
|
||||
void SetExtension(const String& key, const Object::Ptr& object);
|
||||
Object::Ptr GetExtension(const String& key);
|
||||
void ClearExtension(const String& key);
|
||||
|
@ -20,12 +20,10 @@ abstract class DynamicObject
|
||||
}}}
|
||||
};
|
||||
[config, get_protected] String type (TypeName);
|
||||
[config] String package;
|
||||
[config] String zone;
|
||||
[config, get_protected] Array::Ptr templates;
|
||||
[config] Dictionary::Ptr methods;
|
||||
[config] Dictionary::Ptr vars (VarsRaw);
|
||||
[config] Array::Ptr domains;
|
||||
[config] Array::Ptr authorities;
|
||||
[get_protected] bool active;
|
||||
[get_protected] bool start_called;
|
||||
[get_protected] bool stop_called;
|
||||
|
@ -30,11 +30,7 @@ typedef void (*InitializeFunc)(void);
|
||||
|
||||
inline bool InitializeOnceHelper(InitializeFunc func)
|
||||
{
|
||||
if (Utility::GetLoadingLibrary())
|
||||
Utility::AddDeferredInitializer(func);
|
||||
else
|
||||
func();
|
||||
|
||||
Utility::AddDeferredInitializer(func);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1,21 +1,21 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
******************************************************************************/
|
||||
* 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 "base/serializer.h"
|
||||
#include "base/type.h"
|
||||
|
@ -27,7 +27,8 @@
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
namespace icinga {
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
/**
|
||||
* Base class for connection-oriented sockets.
|
||||
|
@ -29,6 +29,12 @@
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
enum ConnectionRole
|
||||
{
|
||||
RoleClient,
|
||||
RoleServer
|
||||
};
|
||||
|
||||
struct ReadLineContext
|
||||
{
|
||||
ReadLineContext(void) : Buffer(NULL), Size(0), Eof(false), MustRead(true)
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "base/application.h"
|
||||
#include "base/debug.h"
|
||||
#include "base/utility.h"
|
||||
#include "base/logger_fwd.h"
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
@ -48,7 +47,7 @@ struct icinga::TimerNextExtractor
|
||||
* @param wtimer Weak pointer to the timer.
|
||||
* @returns The next timestamp
|
||||
*/
|
||||
double operator()(const weak_ptr<Timer>& wtimer)
|
||||
double operator()(const weak_ptr<Timer>& wtimer) const
|
||||
{
|
||||
Timer::Ptr timer = wtimer.lock();
|
||||
|
||||
@ -87,7 +86,7 @@ void Timer::Initialize(void)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(l_Mutex);
|
||||
l_StopThread = false;
|
||||
l_Thread = boost::thread(boost::bind(&Timer::TimerThreadProc));
|
||||
l_Thread = boost::thread(&Timer::TimerThreadProc);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -296,7 +295,7 @@ void Timer::TimerThreadProc(void)
|
||||
|
||||
double wait = timer->m_Next - Utility::GetTime();
|
||||
|
||||
if (wait > 0) {
|
||||
if (wait > 0.01) {
|
||||
/* Make sure the timer we just examined can be destroyed while we're waiting. */
|
||||
timer.reset();
|
||||
|
||||
|
@ -36,7 +36,7 @@ bool I2_EXPORT TlsStream::m_SSLIndexInitialized = false;
|
||||
* @param role The role of the client.
|
||||
* @param sslContext The SSL context for the client.
|
||||
*/
|
||||
TlsStream::TlsStream(const Socket::Ptr& socket, TlsRole role, shared_ptr<SSL_CTX> sslContext)
|
||||
TlsStream::TlsStream(const Socket::Ptr& socket, ConnectionRole role, shared_ptr<SSL_CTX> sslContext)
|
||||
: m_Socket(socket), m_Role(role)
|
||||
{
|
||||
m_SSL = shared_ptr<SSL>(SSL_new(sslContext.get()), SSL_free);
|
||||
@ -62,7 +62,7 @@ TlsStream::TlsStream(const Socket::Ptr& socket, TlsRole role, shared_ptr<SSL_CTX
|
||||
BIO_set_nbio(m_BIO, 1);
|
||||
SSL_set_bio(m_SSL.get(), m_BIO, m_BIO);
|
||||
|
||||
if (m_Role == TlsRoleServer)
|
||||
if (m_Role == RoleServer)
|
||||
SSL_set_accept_state(m_SSL.get());
|
||||
else
|
||||
SSL_set_connect_state(m_SSL.get());
|
||||
@ -90,13 +90,11 @@ shared_ptr<X509> TlsStream::GetPeerCertificate(void) const
|
||||
|
||||
void TlsStream::Handshake(void)
|
||||
{
|
||||
ASSERT(!OwnsLock());
|
||||
|
||||
for (;;) {
|
||||
int rc, err;
|
||||
|
||||
{
|
||||
ObjectLock olock(this);
|
||||
boost::mutex::scoped_lock lock(m_SSLLock);
|
||||
rc = SSL_do_handshake(m_SSL.get());
|
||||
|
||||
if (rc > 0)
|
||||
@ -128,15 +126,13 @@ void TlsStream::Handshake(void)
|
||||
*/
|
||||
size_t TlsStream::Read(void *buffer, size_t count)
|
||||
{
|
||||
ASSERT(!OwnsLock());
|
||||
|
||||
size_t left = count;
|
||||
|
||||
while (left > 0) {
|
||||
int rc, err;
|
||||
|
||||
{
|
||||
ObjectLock olock(this);
|
||||
boost::mutex::scoped_lock lock(m_SSLLock);
|
||||
rc = SSL_read(m_SSL.get(), ((char *)buffer) + (count - left), left);
|
||||
|
||||
if (rc <= 0)
|
||||
@ -169,15 +165,13 @@ size_t TlsStream::Read(void *buffer, size_t count)
|
||||
|
||||
void TlsStream::Write(const void *buffer, size_t count)
|
||||
{
|
||||
ASSERT(!OwnsLock());
|
||||
|
||||
size_t left = count;
|
||||
|
||||
while (left > 0) {
|
||||
int rc, err;
|
||||
|
||||
{
|
||||
ObjectLock olock(this);
|
||||
boost::mutex::scoped_lock lock(m_SSLLock);
|
||||
rc = SSL_write(m_SSL.get(), ((const char *)buffer) + (count - left), left);
|
||||
|
||||
if (rc <= 0)
|
||||
@ -211,13 +205,11 @@ void TlsStream::Write(const void *buffer, size_t count)
|
||||
*/
|
||||
void TlsStream::Close(void)
|
||||
{
|
||||
ASSERT(!OwnsLock());
|
||||
|
||||
for (;;) {
|
||||
int rc, err;
|
||||
|
||||
{
|
||||
ObjectLock olock(this);
|
||||
boost::mutex::scoped_lock lock(m_SSLLock);
|
||||
|
||||
do {
|
||||
rc = SSL_shutdown(m_SSL.get());
|
||||
|
@ -28,12 +28,6 @@
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
enum TlsRole
|
||||
{
|
||||
TlsRoleClient,
|
||||
TlsRoleServer
|
||||
};
|
||||
|
||||
/**
|
||||
* A TLS stream.
|
||||
*
|
||||
@ -44,7 +38,7 @@ class I2_BASE_API TlsStream : public Stream
|
||||
public:
|
||||
DECLARE_PTR_TYPEDEFS(TlsStream);
|
||||
|
||||
TlsStream(const Socket::Ptr& socket, TlsRole role, shared_ptr<SSL_CTX> sslContext);
|
||||
TlsStream(const Socket::Ptr& socket, ConnectionRole role, shared_ptr<SSL_CTX> sslContext);
|
||||
|
||||
shared_ptr<X509> GetClientCertificate(void) const;
|
||||
shared_ptr<X509> GetPeerCertificate(void) const;
|
||||
@ -59,11 +53,12 @@ public:
|
||||
virtual bool IsEof(void) const;
|
||||
|
||||
private:
|
||||
boost::mutex m_SSLLock;
|
||||
shared_ptr<SSL> m_SSL;
|
||||
BIO *m_BIO;
|
||||
|
||||
Socket::Ptr m_Socket;
|
||||
TlsRole m_Role;
|
||||
ConnectionRole m_Role;
|
||||
|
||||
static int m_SSLIndex;
|
||||
static bool m_SSLIndexInitialized;
|
||||
|
@ -370,21 +370,9 @@ Utility::LoadExtensionLibrary(const String& library)
|
||||
|
||||
Log(LogInformation, "base", "Loading library '" + path + "'");
|
||||
|
||||
m_DeferredInitializers.reset(new std::vector<boost::function<void(void)> >());
|
||||
|
||||
#ifdef _WIN32
|
||||
HMODULE hModule;
|
||||
HMODULE hModule = LoadLibrary(path.CStr());
|
||||
|
||||
try {
|
||||
SetLoadingLibrary(true);
|
||||
hModule = LoadLibrary(path.CStr());
|
||||
} catch (...) {
|
||||
SetLoadingLibrary(false);
|
||||
throw;
|
||||
}
|
||||
|
||||
SetLoadingLibrary(false);
|
||||
|
||||
if (hModule == NULL) {
|
||||
BOOST_THROW_EXCEPTION(win32_error()
|
||||
<< boost::errinfo_api_function("LoadLibrary")
|
||||
@ -392,44 +380,35 @@ Utility::LoadExtensionLibrary(const String& library)
|
||||
<< boost::errinfo_file_name(path));
|
||||
}
|
||||
#else /* _WIN32 */
|
||||
void *hModule;
|
||||
void *hModule = dlopen(path.CStr(), RTLD_NOW);
|
||||
|
||||
try {
|
||||
hModule = dlopen(path.CStr(), RTLD_NOW);
|
||||
} catch (...) {
|
||||
SetLoadingLibrary(false);
|
||||
throw;
|
||||
}
|
||||
|
||||
SetLoadingLibrary(false);
|
||||
|
||||
if (hModule == NULL) {
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Could not load library '" + path + "': " + dlerror()));
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
BOOST_FOREACH(const boost::function<void(void)>& callback, *m_DeferredInitializers.get())
|
||||
callback();
|
||||
ExecuteDeferredInitializers();
|
||||
|
||||
m_DeferredInitializers.reset();
|
||||
|
||||
return hModule;
|
||||
}
|
||||
|
||||
bool Utility::GetLoadingLibrary(void)
|
||||
void Utility::ExecuteDeferredInitializers(void)
|
||||
{
|
||||
bool *loading = m_LoadingLibrary.get();
|
||||
return loading && *loading;
|
||||
}
|
||||
if (!m_DeferredInitializers.get())
|
||||
return;
|
||||
|
||||
void Utility::SetLoadingLibrary(bool loading)
|
||||
{
|
||||
bool *ploading = new bool(loading);
|
||||
m_LoadingLibrary.reset(ploading);
|
||||
BOOST_FOREACH(const boost::function<void(void)>& callback, *m_DeferredInitializers.get())
|
||||
callback();
|
||||
|
||||
m_DeferredInitializers.reset();
|
||||
}
|
||||
|
||||
void Utility::AddDeferredInitializer(const boost::function<void(void)>& callback)
|
||||
{
|
||||
if (!m_DeferredInitializers.get())
|
||||
m_DeferredInitializers.reset(new std::vector<boost::function<void(void)> >());
|
||||
|
||||
m_DeferredInitializers.get()->push_back(callback);
|
||||
}
|
||||
|
||||
@ -536,9 +515,7 @@ bool Utility::Glob(const String& pathSpec, const boost::function<void (const Str
|
||||
struct stat statbuf;
|
||||
|
||||
if (stat(*gp, &statbuf) < 0)
|
||||
BOOST_THROW_EXCEPTION(posix_error()
|
||||
<< boost::errinfo_api_function("stat")
|
||||
<< boost::errinfo_errno(errno));
|
||||
continue;
|
||||
|
||||
if (!S_ISDIR(statbuf.st_mode) && !S_ISREG(statbuf.st_mode))
|
||||
continue;
|
||||
|
@ -97,9 +97,8 @@ public:
|
||||
#endif /* _WIN32 */
|
||||
LoadExtensionLibrary(const String& library);
|
||||
|
||||
static bool GetLoadingLibrary(void);
|
||||
static void SetLoadingLibrary(bool loading);
|
||||
static void AddDeferredInitializer(const boost::function<void(void)>& callback);
|
||||
static void ExecuteDeferredInitializers(void);
|
||||
|
||||
#ifndef _WIN32
|
||||
static void SetNonBlocking(int fd);
|
||||
|
@ -523,7 +523,7 @@ Value AExpression::OpObject(const AExpression* expr, const Dictionary::Ptr& loca
|
||||
String type = left->Get(1);
|
||||
AExpression::Ptr aname = left->Get(2);
|
||||
AExpression::Ptr filter = left->Get(3);
|
||||
String package = left->Get(4);
|
||||
String zone = left->Get(4);
|
||||
|
||||
String name = aname->Evaluate(locals);
|
||||
|
||||
@ -561,7 +561,7 @@ Value AExpression::OpObject(const AExpression* expr, const Dictionary::Ptr& loca
|
||||
item->AddExpression(exprl);
|
||||
item->SetAbstract(abstract);
|
||||
item->SetScope(locals);
|
||||
item->SetPackage(package);
|
||||
item->SetZone(zone);
|
||||
item->Compile()->Register();
|
||||
|
||||
ObjectRule::AddRule(type, name, exprl, filter, expr->m_DebugInfo, locals);
|
||||
|
@ -24,7 +24,7 @@
|
||||
%require "type",
|
||||
%attribute %string "type",
|
||||
|
||||
%attribute %string "package",
|
||||
%attribute %name(Zone) "zone",
|
||||
|
||||
%attribute %array "templates" {
|
||||
%attribute %string "*"
|
||||
@ -35,10 +35,6 @@
|
||||
%attribute %dictionary "vars" {
|
||||
%attribute %string "*"
|
||||
},
|
||||
|
||||
%attribute %array "domains" {
|
||||
%attribute %string "*"
|
||||
}
|
||||
}
|
||||
|
||||
%type Logger {
|
||||
|
@ -231,7 +231,7 @@ ignore return T_IGNORE;
|
||||
function return T_FUNCTION;
|
||||
lambda return T_LAMBDA;
|
||||
return return T_RETURN;
|
||||
package return T_PACKAGE;
|
||||
zone return T_ZONE;
|
||||
\<\< { yylval->op = &AExpression::OpShiftLeft; return T_SHIFT_LEFT; }
|
||||
\>\> { yylval->op = &AExpression::OpShiftRight; return T_SHIFT_RIGHT; }
|
||||
\<= { yylval->op = &AExpression::OpLessThanOrEqual; return T_LESS_THAN_OR_EQUAL; }
|
||||
|
@ -160,7 +160,7 @@ static void MakeRBinaryOp(Value** result, AExpression::OpCallback& op, Value *le
|
||||
%token T_FUNCTION "function (T_FUNCTION)"
|
||||
%token T_LAMBDA "lambda (T_LAMBDA)"
|
||||
%token T_RETURN "return (T_RETURN)"
|
||||
%token T_PACKAGE "package (T_PACKAGE)"
|
||||
%token T_ZONE "zone (T_ZONE)"
|
||||
|
||||
%type <text> identifier
|
||||
%type <array> rterm_items
|
||||
@ -214,7 +214,7 @@ static std::stack<TypeRuleList::Ptr> m_RuleLists;
|
||||
static ConfigType::Ptr m_Type;
|
||||
|
||||
static Dictionary::Ptr m_ModuleScope;
|
||||
static String m_Package;
|
||||
static String m_Zone;
|
||||
static int m_StatementNum;
|
||||
|
||||
static bool m_Apply;
|
||||
@ -227,7 +227,7 @@ void ConfigCompiler::Compile(void)
|
||||
{
|
||||
m_ModuleScope = make_shared<Dictionary>();
|
||||
|
||||
String parentPackage = m_Package;
|
||||
String parentZone = m_Zone;
|
||||
int parentStatementNum = m_StatementNum;
|
||||
m_StatementNum = 0;
|
||||
|
||||
@ -240,7 +240,7 @@ void ConfigCompiler::Compile(void)
|
||||
ConfigCompilerContext::GetInstance()->AddMessage(true, DiagnosticInformation(ex));
|
||||
}
|
||||
|
||||
m_Package = parentPackage;
|
||||
m_Zone = parentZone;
|
||||
m_StatementNum = parentStatementNum;
|
||||
}
|
||||
|
||||
@ -253,7 +253,7 @@ statements: /* empty */
|
||||
| statements statement
|
||||
;
|
||||
|
||||
statement: type | package | include | include_recursive | library | constant
|
||||
statement: type | zone | include | include_recursive | library | constant
|
||||
{
|
||||
m_StatementNum++;
|
||||
}
|
||||
@ -269,37 +269,39 @@ statement: type | package | include | include_recursive | library | constant
|
||||
}
|
||||
;
|
||||
|
||||
package: T_PACKAGE rterm sep
|
||||
zone: T_ZONE rterm sep
|
||||
{
|
||||
AExpression::Ptr aexpr = *$2;
|
||||
delete $2;
|
||||
|
||||
if (!m_Package.IsEmpty())
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Package name cannot be changed once it's been set."));
|
||||
if (!m_Zone.IsEmpty())
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Zone name cannot be changed once it's been set."));
|
||||
|
||||
if (m_StatementNum != 0)
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("'package' directive must be the first statement in a file."));
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("'zone' directive must be the first statement in a file."));
|
||||
|
||||
m_Package = aexpr->Evaluate(m_ModuleScope);
|
||||
m_Zone = aexpr->Evaluate(m_ModuleScope);
|
||||
}
|
||||
| T_PACKAGE rterm rterm_scope sep
|
||||
| T_ZONE rterm
|
||||
{
|
||||
AExpression::Ptr aexpr = *$2;
|
||||
delete $2;
|
||||
|
||||
AExpression::Ptr ascope = *$3;
|
||||
delete $3;
|
||||
if (!m_Zone.IsEmpty())
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Zone name cannot be changed once it's been set."));
|
||||
|
||||
if (!m_Package.IsEmpty())
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Package name cannot be changed once it's been set."));
|
||||
|
||||
m_Package = aexpr->Evaluate(m_ModuleScope);
|
||||
m_Zone = aexpr->Evaluate(m_ModuleScope);
|
||||
}
|
||||
rterm_scope sep
|
||||
{
|
||||
AExpression::Ptr ascope = *$4;
|
||||
delete $4;
|
||||
|
||||
try {
|
||||
ascope->Evaluate(m_ModuleScope);
|
||||
m_Package = String();
|
||||
m_Zone = String();
|
||||
} catch (...) {
|
||||
m_Package = String();
|
||||
m_Zone = String();
|
||||
}
|
||||
}
|
||||
;
|
||||
@ -511,7 +513,7 @@ object:
|
||||
|
||||
args->Add(filter);
|
||||
|
||||
args->Add(m_Package);
|
||||
args->Add(m_Zone);
|
||||
|
||||
$$ = new Value(make_shared<AExpression>(&AExpression::OpObject, args, exprl, DebugInfoRange(@2, @5)));
|
||||
|
||||
|
@ -50,10 +50,10 @@ ConfigItem::ItemMap ConfigItem::m_Items;
|
||||
ConfigItem::ConfigItem(const String& type, const String& name,
|
||||
bool abstract, const AExpression::Ptr& exprl,
|
||||
const DebugInfo& debuginfo, const Dictionary::Ptr& scope,
|
||||
const String& package)
|
||||
const String& zone)
|
||||
: m_Type(type), m_Name(name), m_Abstract(abstract), m_Validated(false),
|
||||
m_ExpressionList(exprl), m_DebugInfo(debuginfo),
|
||||
m_Scope(scope), m_Package(package)
|
||||
m_Scope(scope), m_Zone(zone)
|
||||
{
|
||||
}
|
||||
|
||||
@ -119,6 +119,8 @@ Dictionary::Ptr ConfigItem::GetProperties(void)
|
||||
if (!m_Properties) {
|
||||
m_Properties = make_shared<Dictionary>();
|
||||
m_Properties->Set("type", m_Type);
|
||||
if (!m_Zone.IsEmpty())
|
||||
m_Properties->Set("zone", m_Zone);
|
||||
m_Properties->Set("__parent", m_Scope);
|
||||
GetExpressionList()->Evaluate(m_Properties);
|
||||
m_Properties->Remove("__parent");
|
||||
|
@ -39,7 +39,7 @@ public:
|
||||
|
||||
ConfigItem(const String& type, const String& name, bool abstract,
|
||||
const AExpression::Ptr& exprl, const DebugInfo& debuginfo,
|
||||
const Dictionary::Ptr& scope, const String& package);
|
||||
const Dictionary::Ptr& scope, const String& zone);
|
||||
|
||||
String GetType(void) const;
|
||||
String GetName(void) const;
|
||||
@ -57,7 +57,7 @@ public:
|
||||
|
||||
Dictionary::Ptr GetScope(void) const;
|
||||
|
||||
String GetPackage(void) const;
|
||||
String GetZone(void) const;
|
||||
|
||||
static ConfigItem::Ptr GetObject(const String& type,
|
||||
const String& name);
|
||||
@ -81,7 +81,7 @@ private:
|
||||
items. */
|
||||
DebugInfo m_DebugInfo; /**< Debug information. */
|
||||
Dictionary::Ptr m_Scope; /**< variable scope. */
|
||||
String m_Package; /**< The package. */
|
||||
String m_Zone; /**< The zone. */
|
||||
|
||||
DynamicObject::Ptr m_Object;
|
||||
|
||||
|
@ -60,9 +60,9 @@ void ConfigItemBuilder::SetScope(const Dictionary::Ptr& scope)
|
||||
m_Scope = scope;
|
||||
}
|
||||
|
||||
void ConfigItemBuilder::SetPackage(const String& package)
|
||||
void ConfigItemBuilder::SetZone(const String& zone)
|
||||
{
|
||||
m_Package = package;
|
||||
m_Zone = zone;
|
||||
}
|
||||
|
||||
void ConfigItemBuilder::AddExpression(const AExpression::Ptr& expr)
|
||||
@ -104,5 +104,5 @@ ConfigItem::Ptr ConfigItemBuilder::Compile(void)
|
||||
AExpression::Ptr exprl = make_shared<AExpression>(&AExpression::OpDict, exprs, true, m_DebugInfo);
|
||||
|
||||
return make_shared<ConfigItem>(m_Type, m_Name, m_Abstract, exprl,
|
||||
m_DebugInfo, m_Scope, m_Package);
|
||||
m_DebugInfo, m_Scope, m_Zone);
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ public:
|
||||
void SetName(const String& name);
|
||||
void SetAbstract(bool abstract);
|
||||
void SetScope(const Dictionary::Ptr& scope);
|
||||
void SetPackage(const String& name);
|
||||
void SetZone(const String& zone);
|
||||
|
||||
void AddExpression(const AExpression::Ptr& expr);
|
||||
|
||||
@ -59,7 +59,7 @@ private:
|
||||
Array::Ptr m_Expressions; /**< Expressions for this item. */
|
||||
DebugInfo m_DebugInfo; /**< Debug information. */
|
||||
Dictionary::Ptr m_Scope; /**< variable scope. */
|
||||
String m_Package; /**< The package. */
|
||||
String m_Zone; /**< The zone. */
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ void DbEvents::StaticInitialize(void)
|
||||
Checkable::OnAcknowledgementSet.connect(boost::bind(&DbEvents::AddAcknowledgement, _1, _4));
|
||||
Checkable::OnAcknowledgementCleared.connect(boost::bind(&DbEvents::RemoveAcknowledgement, _1));
|
||||
|
||||
Checkable::OnNextCheckChanged.connect(bind(&DbEvents::NextCheckChangedHandler, _1, _2, _3));
|
||||
Checkable::OnNextCheckChanged.connect(bind(&DbEvents::NextCheckChangedHandler, _1, _2));
|
||||
Checkable::OnFlappingChanged.connect(bind(&DbEvents::FlappingChangedHandler, _1, _2));
|
||||
Checkable::OnNotificationSentToAllUsers.connect(bind(&DbEvents::LastNotificationChangedHandler, _1, _2));
|
||||
|
||||
@ -78,7 +78,7 @@ void DbEvents::StaticInitialize(void)
|
||||
}
|
||||
|
||||
/* check events */
|
||||
void DbEvents::NextCheckChangedHandler(const Checkable::Ptr& checkable, double nextCheck, const String& authority)
|
||||
void DbEvents::NextCheckChangedHandler(const Checkable::Ptr& checkable, double nextCheck)
|
||||
{
|
||||
Host::Ptr host;
|
||||
Service::Ptr service;
|
||||
|
@ -72,7 +72,7 @@ public:
|
||||
static void AddLogHistory(const Checkable::Ptr& checkable, String buffer, LogEntryType type);
|
||||
|
||||
/* Status */
|
||||
static void NextCheckChangedHandler(const Checkable::Ptr& checkable, double nextCheck, const String& authority);
|
||||
static void NextCheckChangedHandler(const Checkable::Ptr& checkable, double nextCheck);
|
||||
static void FlappingChangedHandler(const Checkable::Ptr& checkable, FlappingState state);
|
||||
static void LastNotificationChangedHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable);
|
||||
|
||||
|
@ -39,7 +39,7 @@ INITIALIZE_ONCE(&EndpointDbObject::StaticInitialize);
|
||||
void EndpointDbObject::StaticInitialize(void)
|
||||
{
|
||||
Endpoint::OnConnected.connect(boost::bind(&EndpointDbObject::UpdateConnectedStatus, _1));
|
||||
Endpoint::OnDisconnected.connect(boost::bind(&EndpointDbObject::UpdateDisconnectedStatus, _1));
|
||||
Endpoint::OnDisconnected.connect(boost::bind(&EndpointDbObject::UpdateConnectedStatus, _1));
|
||||
}
|
||||
|
||||
EndpointDbObject::EndpointDbObject(const DbType::Ptr& type, const String& name1, const String& name2)
|
||||
@ -73,16 +73,8 @@ Dictionary::Ptr EndpointDbObject::GetStatusFields(void) const
|
||||
|
||||
void EndpointDbObject::UpdateConnectedStatus(const Endpoint::Ptr& endpoint)
|
||||
{
|
||||
UpdateConnectedStatusInternal(endpoint, true);
|
||||
}
|
||||
bool connected = EndpointIsConnected(endpoint);
|
||||
|
||||
void EndpointDbObject::UpdateDisconnectedStatus(const Endpoint::Ptr& endpoint)
|
||||
{
|
||||
UpdateConnectedStatusInternal(endpoint, false);
|
||||
}
|
||||
|
||||
void EndpointDbObject::UpdateConnectedStatusInternal(const Endpoint::Ptr& endpoint, bool connected)
|
||||
{
|
||||
Log(LogDebug, "db_ido", "update is_connected=" + Convert::ToString(connected ? 1 : 0) + " for endpoint '" + endpoint->GetName() + "'");
|
||||
|
||||
DbQuery query1;
|
||||
|
@ -49,8 +49,6 @@ protected:
|
||||
|
||||
private:
|
||||
static void UpdateConnectedStatus(const Endpoint::Ptr& endpoint);
|
||||
static void UpdateDisconnectedStatus(const Endpoint::Ptr& endpoint);
|
||||
static void UpdateConnectedStatusInternal(const Endpoint::Ptr& endpoint, bool connected);
|
||||
static int EndpointIsConnected(const Endpoint::Ptr& endpoint);
|
||||
};
|
||||
|
||||
|
@ -21,7 +21,6 @@ mkclass_target(checkresult.ti checkresult.th)
|
||||
mkclass_target(command.ti command.th)
|
||||
mkclass_target(comment.ti comment.th)
|
||||
mkclass_target(dependency.ti dependency.th)
|
||||
mkclass_target(domain.ti domain.th)
|
||||
mkclass_target(downtime.ti downtime.th)
|
||||
mkclass_target(eventcommand.ti eventcommand.th)
|
||||
mkclass_target(hostgroup.ti hostgroup.th)
|
||||
@ -41,10 +40,10 @@ mkclass_target(user.ti user.th)
|
||||
mkembedconfig_target(icinga-type.conf icinga-type.cpp)
|
||||
|
||||
add_library(icinga SHARED
|
||||
api.cpp checkable.cpp checkable.th checkable-dependency.cpp checkable-downtime.cpp checkable-event.cpp
|
||||
api.cpp apievents.cpp checkable.cpp checkable.th checkable-dependency.cpp checkable-downtime.cpp checkable-event.cpp
|
||||
checkable-flapping.cpp checkcommand.cpp checkcommand.th checkresult.cpp checkresult.th
|
||||
cib.cpp command.cpp command.th comment.cpp comment.th compatutility.cpp dependency.cpp dependency.th
|
||||
dependency-apply.cpp domain.cpp domain.th downtime.cpp downtime.th eventcommand.cpp eventcommand.th
|
||||
dependency-apply.cpp downtime.cpp downtime.th eventcommand.cpp eventcommand.th
|
||||
externalcommandprocessor.cpp host.cpp host.th hostgroup.cpp hostgroup.th icingaapplication.cpp
|
||||
icingaapplication.th icingastatuswriter.cpp icingastatuswriter.th legacytimeperiod.cpp macroprocessor.cpp
|
||||
notificationcommand.cpp notificationcommand.th notification.cpp notification.th notification-apply.cpp
|
||||
@ -54,7 +53,7 @@ add_library(icinga SHARED
|
||||
user.cpp user.th usergroup.cpp usergroup.th icinga-type.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(icinga ${Boost_LIBRARIES} base config)
|
||||
target_link_libraries(icinga ${Boost_LIBRARIES} base config remote)
|
||||
|
||||
set_target_properties (
|
||||
icinga PROPERTIES
|
||||
|
@ -18,15 +18,20 @@
|
||||
******************************************************************************/
|
||||
|
||||
#include "icinga/api.h"
|
||||
#include "base/scriptfunction.h"
|
||||
#include "remote/apifunction.h"
|
||||
#include "base/logger_fwd.h"
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_SCRIPTFUNCTION(GetAnswerToEverything, &API::GetAnswerToEverything);
|
||||
REGISTER_APIFUNCTION(GetAnswerToEverything, uapi, boost::bind(&API::GetAnswerToEverything, _2));
|
||||
|
||||
int API::GetAnswerToEverything(const String& text)
|
||||
Value API::GetAnswerToEverything(const Dictionary::Ptr& params)
|
||||
{
|
||||
String text;
|
||||
|
||||
if (params)
|
||||
text = params->Get("text");
|
||||
|
||||
Log(LogInformation, "icinga", "Hello from the Icinga 2 API: " + text);
|
||||
|
||||
return 42;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define API_H
|
||||
|
||||
#include "icinga/i2-icinga.h"
|
||||
#include "remote/apiclient.h"
|
||||
#include "base/value.h"
|
||||
#include <vector>
|
||||
|
||||
@ -28,14 +29,12 @@ namespace icinga
|
||||
{
|
||||
|
||||
/**
|
||||
* A state change message for a service.
|
||||
*
|
||||
* @ingroup icinga
|
||||
*/
|
||||
class I2_ICINGA_API API
|
||||
{
|
||||
public:
|
||||
static int GetAnswerToEverything(const String& text);
|
||||
static Value GetAnswerToEverything(const Dictionary::Ptr& params);
|
||||
|
||||
private:
|
||||
API(void);
|
||||
|
967
lib/icinga/apievents.cpp
Normal file
967
lib/icinga/apievents.cpp
Normal file
@ -0,0 +1,967 @@
|
||||
/******************************************************************************
|
||||
* 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 "icinga/apievents.h"
|
||||
#include "icinga/service.h"
|
||||
#include "remote/apilistener.h"
|
||||
#include "remote/apiclient.h"
|
||||
#include "remote/apifunction.h"
|
||||
#include "base/application.h"
|
||||
#include "base/dynamictype.h"
|
||||
#include "base/objectlock.h"
|
||||
#include "base/utility.h"
|
||||
#include "base/logger_fwd.h"
|
||||
#include "base/exception.h"
|
||||
#include "base/initialize.h"
|
||||
#include <fstream>
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
INITIALIZE_ONCE(&ApiEvents::StaticInitialize);
|
||||
|
||||
REGISTER_APIFUNCTION(CheckResult, event, &ApiEvents::CheckResultAPIHandler);
|
||||
REGISTER_APIFUNCTION(SetNextCheck, event, &ApiEvents::NextCheckChangedAPIHandler);
|
||||
REGISTER_APIFUNCTION(SetNextNotification, event, &ApiEvents::NextNotificationChangedAPIHandler);
|
||||
REGISTER_APIFUNCTION(SetForceNextCheck, event, &ApiEvents::ForceNextCheckChangedAPIHandler);
|
||||
REGISTER_APIFUNCTION(SetForceNextNotification, event, &ApiEvents::ForceNextNotificationChangedAPIHandler);
|
||||
REGISTER_APIFUNCTION(SetEnableActiveChecks, event, &ApiEvents::EnableActiveChecksChangedAPIHandler);
|
||||
REGISTER_APIFUNCTION(SetEnablePassiveChecks, event, &ApiEvents::EnablePassiveChecksChangedAPIHandler);
|
||||
REGISTER_APIFUNCTION(SetEnableNotifications, event, &ApiEvents::EnableNotificationsChangedAPIHandler);
|
||||
REGISTER_APIFUNCTION(SetEnableFlapping, event, &ApiEvents::EnableFlappingChangedAPIHandler);
|
||||
REGISTER_APIFUNCTION(AddComment, event, &ApiEvents::CommentAddedAPIHandler);
|
||||
REGISTER_APIFUNCTION(RemoveComment, event, &ApiEvents::CommentRemovedAPIHandler);
|
||||
REGISTER_APIFUNCTION(AddDowntime, event, &ApiEvents::DowntimeAddedAPIHandler);
|
||||
REGISTER_APIFUNCTION(RemoveDowntime, event, &ApiEvents::DowntimeRemovedAPIHandler);
|
||||
REGISTER_APIFUNCTION(SetAcknowledgement, event, &ApiEvents::AcknowledgementSetAPIHandler);
|
||||
REGISTER_APIFUNCTION(ClearAcknowledgement, event, &ApiEvents::AcknowledgementClearedAPIHandler);
|
||||
REGISTER_APIFUNCTION(UpdateRepository, event, &ApiEvents::UpdateRepositoryAPIHandler);
|
||||
|
||||
static Timer::Ptr l_RepositoryTimer;
|
||||
|
||||
void ApiEvents::StaticInitialize(void)
|
||||
{
|
||||
Checkable::OnNewCheckResult.connect(&ApiEvents::CheckResultHandler);
|
||||
Checkable::OnNextCheckChanged.connect(&ApiEvents::NextCheckChangedHandler);
|
||||
Notification::OnNextNotificationChanged.connect(&ApiEvents::NextNotificationChangedHandler);
|
||||
Checkable::OnForceNextCheckChanged.connect(&ApiEvents::ForceNextCheckChangedHandler);
|
||||
Checkable::OnForceNextNotificationChanged.connect(&ApiEvents::ForceNextNotificationChangedHandler);
|
||||
Checkable::OnEnableActiveChecksChanged.connect(&ApiEvents::EnableActiveChecksChangedHandler);
|
||||
Checkable::OnEnablePassiveChecksChanged.connect(&ApiEvents::EnablePassiveChecksChangedHandler);
|
||||
Checkable::OnEnableNotificationsChanged.connect(&ApiEvents::EnableNotificationsChangedHandler);
|
||||
Checkable::OnEnableFlappingChanged.connect(&ApiEvents::EnableFlappingChangedHandler);
|
||||
Checkable::OnCommentAdded.connect(&ApiEvents::CommentAddedHandler);
|
||||
Checkable::OnCommentRemoved.connect(&ApiEvents::CommentRemovedHandler);
|
||||
Checkable::OnDowntimeAdded.connect(&ApiEvents::DowntimeAddedHandler);
|
||||
Checkable::OnDowntimeRemoved.connect(&ApiEvents::DowntimeRemovedHandler);
|
||||
Checkable::OnAcknowledgementSet.connect(&ApiEvents::AcknowledgementSetHandler);
|
||||
Checkable::OnAcknowledgementCleared.connect(&ApiEvents::AcknowledgementClearedHandler);
|
||||
|
||||
l_RepositoryTimer = make_shared<Timer>();
|
||||
l_RepositoryTimer->SetInterval(60);
|
||||
l_RepositoryTimer->OnTimerExpired.connect(boost::bind(&ApiEvents::RepositoryTimerHandler));
|
||||
l_RepositoryTimer->Start();
|
||||
l_RepositoryTimer->Reschedule(0);
|
||||
}
|
||||
|
||||
void ApiEvents::CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const MessageOrigin& origin)
|
||||
{
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
if (!listener)
|
||||
return;
|
||||
|
||||
Dictionary::Ptr message = make_shared<Dictionary>();
|
||||
message->Set("jsonrpc", "2.0");
|
||||
message->Set("method", "event::CheckResult");
|
||||
|
||||
Host::Ptr host;
|
||||
Service::Ptr service;
|
||||
tie(host, service) = GetHostService(checkable);
|
||||
|
||||
Dictionary::Ptr params = make_shared<Dictionary>();
|
||||
params->Set("host", host->GetName());
|
||||
if (service)
|
||||
params->Set("service", service->GetShortName());
|
||||
params->Set("cr", Serialize(cr));
|
||||
|
||||
message->Set("params", params);
|
||||
|
||||
listener->RelayMessage(origin, checkable, message, true);
|
||||
}
|
||||
|
||||
Value ApiEvents::CheckResultAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params)
|
||||
{
|
||||
if (!params)
|
||||
return Empty;
|
||||
|
||||
Value crv = params->Get("cr");
|
||||
|
||||
CheckResult::Ptr cr = Deserialize(crv, true);
|
||||
|
||||
Host::Ptr host = Host::GetByName(params->Get("host"));
|
||||
|
||||
if (!host)
|
||||
return Empty;
|
||||
|
||||
Checkable::Ptr checkable;
|
||||
|
||||
if (params->Contains("service"))
|
||||
checkable = host->GetServiceByShortName(params->Get("service"));
|
||||
else
|
||||
checkable = host;
|
||||
|
||||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->ProcessCheckResult(cr, origin);
|
||||
|
||||
return Empty;
|
||||
}
|
||||
|
||||
void ApiEvents::NextCheckChangedHandler(const Checkable::Ptr& checkable, double nextCheck, const MessageOrigin& origin)
|
||||
{
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
if (!listener)
|
||||
return;
|
||||
|
||||
Host::Ptr host;
|
||||
Service::Ptr service;
|
||||
tie(host, service) = GetHostService(checkable);
|
||||
|
||||
Dictionary::Ptr params = make_shared<Dictionary>();
|
||||
params->Set("host", host->GetName());
|
||||
if (service)
|
||||
params->Set("service", service->GetShortName());
|
||||
params->Set("next_check", nextCheck);
|
||||
|
||||
Dictionary::Ptr message = make_shared<Dictionary>();
|
||||
message->Set("jsonrpc", "2.0");
|
||||
message->Set("method", "event::SetNextCheck");
|
||||
message->Set("params", params);
|
||||
|
||||
listener->RelayMessage(origin, checkable, message, true);
|
||||
}
|
||||
|
||||
Value ApiEvents::NextCheckChangedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params)
|
||||
{
|
||||
if (!params)
|
||||
return Empty;
|
||||
|
||||
Host::Ptr host = Host::GetByName(params->Get("host"));
|
||||
|
||||
if (!host)
|
||||
return Empty;
|
||||
|
||||
Checkable::Ptr checkable;
|
||||
|
||||
if (params->Contains("service"))
|
||||
checkable = host->GetServiceByShortName(params->Get("service"));
|
||||
else
|
||||
checkable = host;
|
||||
|
||||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->SetNextCheck(params->Get("next_check"), origin);
|
||||
|
||||
return Empty;
|
||||
}
|
||||
|
||||
void ApiEvents::NextNotificationChangedHandler(const Notification::Ptr& notification, double nextNotification, const MessageOrigin& origin)
|
||||
{
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
if (!listener)
|
||||
return;
|
||||
|
||||
Dictionary::Ptr params = make_shared<Dictionary>();
|
||||
params->Set("notification", notification->GetName());
|
||||
params->Set("next_notification", nextNotification);
|
||||
|
||||
Dictionary::Ptr message = make_shared<Dictionary>();
|
||||
message->Set("jsonrpc", "2.0");
|
||||
message->Set("method", "event::SetNextNotification");
|
||||
message->Set("params", params);
|
||||
|
||||
listener->RelayMessage(origin, notification, message, true);
|
||||
}
|
||||
|
||||
Value ApiEvents::NextNotificationChangedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params)
|
||||
{
|
||||
if (!params)
|
||||
return Empty;
|
||||
|
||||
Notification::Ptr notification = Notification::GetByName(params->Get("notification"));
|
||||
|
||||
if (!notification)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(notification))
|
||||
return Empty;
|
||||
|
||||
notification->SetNextNotification(params->Get("next_notification"), origin);
|
||||
|
||||
return Empty;
|
||||
}
|
||||
|
||||
void ApiEvents::ForceNextCheckChangedHandler(const Checkable::Ptr& checkable, bool forced, const MessageOrigin& origin)
|
||||
{
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
if (!listener)
|
||||
return;
|
||||
|
||||
Host::Ptr host;
|
||||
Service::Ptr service;
|
||||
tie(host, service) = GetHostService(checkable);
|
||||
|
||||
Dictionary::Ptr params = make_shared<Dictionary>();
|
||||
params->Set("host", host->GetName());
|
||||
if (service)
|
||||
params->Set("service", service->GetShortName());
|
||||
params->Set("forced", forced);
|
||||
|
||||
Dictionary::Ptr message = make_shared<Dictionary>();
|
||||
message->Set("jsonrpc", "2.0");
|
||||
message->Set("method", "event::SetForceNextCheck");
|
||||
message->Set("params", params);
|
||||
|
||||
listener->RelayMessage(origin, checkable, message, true);
|
||||
}
|
||||
|
||||
Value ApiEvents::ForceNextCheckChangedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params)
|
||||
{
|
||||
if (!params)
|
||||
return Empty;
|
||||
|
||||
Host::Ptr host = Host::GetByName(params->Get("host"));
|
||||
|
||||
if (!host)
|
||||
return Empty;
|
||||
|
||||
Checkable::Ptr checkable;
|
||||
|
||||
if (params->Contains("service"))
|
||||
checkable = host->GetServiceByShortName(params->Get("service"));
|
||||
else
|
||||
checkable = host;
|
||||
|
||||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->SetForceNextCheck(params->Get("forced"), origin);
|
||||
|
||||
return Empty;
|
||||
}
|
||||
|
||||
void ApiEvents::ForceNextNotificationChangedHandler(const Checkable::Ptr& checkable, bool forced, const MessageOrigin& origin)
|
||||
{
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
if (!listener)
|
||||
return;
|
||||
|
||||
Host::Ptr host;
|
||||
Service::Ptr service;
|
||||
tie(host, service) = GetHostService(checkable);
|
||||
|
||||
Dictionary::Ptr params = make_shared<Dictionary>();
|
||||
params->Set("host", host->GetName());
|
||||
if (service)
|
||||
params->Set("service", service->GetShortName());
|
||||
params->Set("forced", forced);
|
||||
|
||||
Dictionary::Ptr message = make_shared<Dictionary>();
|
||||
message->Set("jsonrpc", "2.0");
|
||||
message->Set("method", "event::SetForceNextNotification");
|
||||
message->Set("params", params);
|
||||
|
||||
listener->RelayMessage(origin, checkable, message, true);
|
||||
}
|
||||
|
||||
Value ApiEvents::ForceNextNotificationChangedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params)
|
||||
{
|
||||
if (!params)
|
||||
return Empty;
|
||||
|
||||
Host::Ptr host = Host::GetByName(params->Get("host"));
|
||||
|
||||
if (!host)
|
||||
return Empty;
|
||||
|
||||
Checkable::Ptr checkable;
|
||||
|
||||
if (params->Contains("service"))
|
||||
checkable = host->GetServiceByShortName(params->Get("service"));
|
||||
else
|
||||
checkable = host;
|
||||
|
||||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->SetForceNextNotification(params->Get("forced"), origin);
|
||||
|
||||
return Empty;
|
||||
}
|
||||
|
||||
void ApiEvents::EnableActiveChecksChangedHandler(const Checkable::Ptr& checkable, bool enabled, const MessageOrigin& origin)
|
||||
{
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
if (!listener)
|
||||
return;
|
||||
|
||||
Host::Ptr host;
|
||||
Service::Ptr service;
|
||||
tie(host, service) = GetHostService(checkable);
|
||||
|
||||
Dictionary::Ptr params = make_shared<Dictionary>();
|
||||
params->Set("host", host->GetName());
|
||||
if (service)
|
||||
params->Set("service", service->GetShortName());
|
||||
params->Set("enabled", enabled);
|
||||
|
||||
Dictionary::Ptr message = make_shared<Dictionary>();
|
||||
message->Set("jsonrpc", "2.0");
|
||||
message->Set("method", "event::SetEnableActiveChecks");
|
||||
message->Set("params", params);
|
||||
|
||||
listener->RelayMessage(origin, checkable, message, true);
|
||||
}
|
||||
|
||||
Value ApiEvents::EnableActiveChecksChangedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params)
|
||||
{
|
||||
if (!params)
|
||||
return Empty;
|
||||
|
||||
Host::Ptr host = Host::GetByName(params->Get("host"));
|
||||
|
||||
if (!host)
|
||||
return Empty;
|
||||
|
||||
Checkable::Ptr checkable;
|
||||
|
||||
if (params->Contains("service"))
|
||||
checkable = host->GetServiceByShortName(params->Get("service"));
|
||||
else
|
||||
checkable = host;
|
||||
|
||||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->SetEnableActiveChecks(params->Get("enabled"), origin);
|
||||
|
||||
return Empty;
|
||||
}
|
||||
|
||||
void ApiEvents::EnablePassiveChecksChangedHandler(const Checkable::Ptr& checkable, bool enabled, const MessageOrigin& origin)
|
||||
{
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
if (!listener)
|
||||
return;
|
||||
|
||||
Host::Ptr host;
|
||||
Service::Ptr service;
|
||||
tie(host, service) = GetHostService(checkable);
|
||||
|
||||
Dictionary::Ptr params = make_shared<Dictionary>();
|
||||
params->Set("host", host->GetName());
|
||||
if (service)
|
||||
params->Set("service", service->GetShortName());
|
||||
params->Set("enabled", enabled);
|
||||
|
||||
Dictionary::Ptr message = make_shared<Dictionary>();
|
||||
message->Set("jsonrpc", "2.0");
|
||||
message->Set("method", "event::SetEnablePassiveChecks");
|
||||
message->Set("params", params);
|
||||
|
||||
listener->RelayMessage(origin, checkable, message, true);
|
||||
}
|
||||
|
||||
Value ApiEvents::EnablePassiveChecksChangedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params)
|
||||
{
|
||||
if (!params)
|
||||
return Empty;
|
||||
|
||||
Host::Ptr host = Host::GetByName(params->Get("host"));
|
||||
|
||||
if (!host)
|
||||
return Empty;
|
||||
|
||||
Checkable::Ptr checkable;
|
||||
|
||||
if (params->Contains("service"))
|
||||
checkable = host->GetServiceByShortName(params->Get("service"));
|
||||
else
|
||||
checkable = host;
|
||||
|
||||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->SetEnablePassiveChecks(params->Get("enabled"), origin);
|
||||
|
||||
return Empty;
|
||||
}
|
||||
|
||||
void ApiEvents::EnableNotificationsChangedHandler(const Checkable::Ptr& checkable, bool enabled, const MessageOrigin& origin)
|
||||
{
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
if (!listener)
|
||||
return;
|
||||
|
||||
Host::Ptr host;
|
||||
Service::Ptr service;
|
||||
tie(host, service) = GetHostService(checkable);
|
||||
|
||||
Dictionary::Ptr params = make_shared<Dictionary>();
|
||||
params->Set("host", host->GetName());
|
||||
if (service)
|
||||
params->Set("service", service->GetShortName());
|
||||
params->Set("enabled", enabled);
|
||||
|
||||
Dictionary::Ptr message = make_shared<Dictionary>();
|
||||
message->Set("jsonrpc", "2.0");
|
||||
message->Set("method", "event::SetEnableNotifications");
|
||||
message->Set("params", params);
|
||||
|
||||
listener->RelayMessage(origin, checkable, message, true);
|
||||
}
|
||||
|
||||
Value ApiEvents::EnableNotificationsChangedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params)
|
||||
{
|
||||
if (!params)
|
||||
return Empty;
|
||||
|
||||
Host::Ptr host = Host::GetByName(params->Get("host"));
|
||||
|
||||
if (!host)
|
||||
return Empty;
|
||||
|
||||
Checkable::Ptr checkable;
|
||||
|
||||
if (params->Contains("service"))
|
||||
checkable = host->GetServiceByShortName(params->Get("service"));
|
||||
else
|
||||
checkable = host;
|
||||
|
||||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->SetEnableNotifications(params->Get("enabled"), origin);
|
||||
|
||||
return Empty;
|
||||
}
|
||||
|
||||
void ApiEvents::EnableFlappingChangedHandler(const Checkable::Ptr& checkable, bool enabled, const MessageOrigin& origin)
|
||||
{
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
if (!listener)
|
||||
return;
|
||||
|
||||
Host::Ptr host;
|
||||
Service::Ptr service;
|
||||
tie(host, service) = GetHostService(checkable);
|
||||
|
||||
Dictionary::Ptr params = make_shared<Dictionary>();
|
||||
params->Set("host", host->GetName());
|
||||
if (service)
|
||||
params->Set("service", service->GetShortName());
|
||||
params->Set("enabled", enabled);
|
||||
|
||||
Dictionary::Ptr message = make_shared<Dictionary>();
|
||||
message->Set("jsonrpc", "2.0");
|
||||
message->Set("method", "event::SetEnableFlapping");
|
||||
message->Set("params", params);
|
||||
|
||||
listener->RelayMessage(origin, checkable, message, true);
|
||||
}
|
||||
|
||||
Value ApiEvents::EnableFlappingChangedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params)
|
||||
{
|
||||
if (!params)
|
||||
return Empty;
|
||||
|
||||
Host::Ptr host = Host::GetByName(params->Get("host"));
|
||||
|
||||
if (!host)
|
||||
return Empty;
|
||||
|
||||
Checkable::Ptr checkable;
|
||||
|
||||
if (params->Contains("service"))
|
||||
checkable = host->GetServiceByShortName(params->Get("service"));
|
||||
else
|
||||
checkable = host;
|
||||
|
||||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->SetEnableFlapping(params->Get("enabled"), origin);
|
||||
|
||||
return Empty;
|
||||
}
|
||||
|
||||
void ApiEvents::CommentAddedHandler(const Checkable::Ptr& checkable, const Comment::Ptr& comment, const MessageOrigin& origin)
|
||||
{
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
if (!listener)
|
||||
return;
|
||||
|
||||
Host::Ptr host;
|
||||
Service::Ptr service;
|
||||
tie(host, service) = GetHostService(checkable);
|
||||
|
||||
Dictionary::Ptr params = make_shared<Dictionary>();
|
||||
params->Set("host", host->GetName());
|
||||
if (service)
|
||||
params->Set("service", service->GetShortName());
|
||||
params->Set("comment", Serialize(comment));
|
||||
|
||||
Dictionary::Ptr message = make_shared<Dictionary>();
|
||||
message->Set("jsonrpc", "2.0");
|
||||
message->Set("method", "event::AddComment");
|
||||
message->Set("params", params);
|
||||
|
||||
listener->RelayMessage(origin, checkable, message, true);
|
||||
}
|
||||
|
||||
Value ApiEvents::CommentAddedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params)
|
||||
{
|
||||
if (!params)
|
||||
return Empty;
|
||||
|
||||
Host::Ptr host = Host::GetByName(params->Get("host"));
|
||||
|
||||
if (!host)
|
||||
return Empty;
|
||||
|
||||
Checkable::Ptr checkable;
|
||||
|
||||
if (params->Contains("service"))
|
||||
checkable = host->GetServiceByShortName(params->Get("service"));
|
||||
else
|
||||
checkable = host;
|
||||
|
||||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
Comment::Ptr comment = Deserialize(params->Get("comment"), true);
|
||||
|
||||
checkable->AddComment(comment->GetEntryType(), comment->GetAuthor(),
|
||||
comment->GetText(), comment->GetExpireTime(), comment->GetId(), origin);
|
||||
|
||||
return Empty;
|
||||
}
|
||||
|
||||
void ApiEvents::CommentRemovedHandler(const Checkable::Ptr& checkable, const Comment::Ptr& comment, const MessageOrigin& origin)
|
||||
{
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
if (!listener)
|
||||
return;
|
||||
|
||||
Host::Ptr host;
|
||||
Service::Ptr service;
|
||||
tie(host, service) = GetHostService(checkable);
|
||||
|
||||
Dictionary::Ptr params = make_shared<Dictionary>();
|
||||
params->Set("host", host->GetName());
|
||||
if (service)
|
||||
params->Set("service", service->GetShortName());
|
||||
params->Set("id", comment->GetId());
|
||||
|
||||
Dictionary::Ptr message = make_shared<Dictionary>();
|
||||
message->Set("jsonrpc", "2.0");
|
||||
message->Set("method", "event::RemoveComment");
|
||||
message->Set("params", params);
|
||||
|
||||
listener->RelayMessage(origin, checkable, message, true);
|
||||
}
|
||||
|
||||
Value ApiEvents::CommentRemovedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params)
|
||||
{
|
||||
if (!params)
|
||||
return Empty;
|
||||
|
||||
Host::Ptr host = Host::GetByName(params->Get("host"));
|
||||
|
||||
if (!host)
|
||||
return Empty;
|
||||
|
||||
Checkable::Ptr checkable;
|
||||
|
||||
if (params->Contains("service"))
|
||||
checkable = host->GetServiceByShortName(params->Get("service"));
|
||||
else
|
||||
checkable = host;
|
||||
|
||||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->RemoveComment(params->Get("id"), origin);
|
||||
|
||||
return Empty;
|
||||
}
|
||||
|
||||
void ApiEvents::DowntimeAddedHandler(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime, const MessageOrigin& origin)
|
||||
{
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
if (!listener)
|
||||
return;
|
||||
|
||||
Host::Ptr host;
|
||||
Service::Ptr service;
|
||||
tie(host, service) = GetHostService(checkable);
|
||||
|
||||
Dictionary::Ptr params = make_shared<Dictionary>();
|
||||
params->Set("host", host->GetName());
|
||||
if (service)
|
||||
params->Set("service", service->GetShortName());
|
||||
params->Set("downtime", Serialize(downtime));
|
||||
|
||||
Dictionary::Ptr message = make_shared<Dictionary>();
|
||||
message->Set("jsonrpc", "2.0");
|
||||
message->Set("method", "event::AddDowntime");
|
||||
message->Set("params", params);
|
||||
|
||||
listener->RelayMessage(origin, checkable, message, true);
|
||||
}
|
||||
|
||||
Value ApiEvents::DowntimeAddedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params)
|
||||
{
|
||||
if (!params)
|
||||
return Empty;
|
||||
|
||||
Host::Ptr host = Host::GetByName(params->Get("host"));
|
||||
|
||||
if (!host)
|
||||
return Empty;
|
||||
|
||||
Checkable::Ptr checkable;
|
||||
|
||||
if (params->Contains("service"))
|
||||
checkable = host->GetServiceByShortName(params->Get("service"));
|
||||
else
|
||||
checkable = host;
|
||||
|
||||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
Downtime::Ptr downtime = Deserialize(params->Get("downtime"), true);
|
||||
|
||||
checkable->AddDowntime(downtime->GetAuthor(), downtime->GetComment(),
|
||||
downtime->GetStartTime(), downtime->GetEndTime(),
|
||||
downtime->GetFixed(), downtime->GetTriggeredBy(),
|
||||
downtime->GetDuration(), downtime->GetScheduledBy(),
|
||||
downtime->GetId(), origin);
|
||||
|
||||
return Empty;
|
||||
}
|
||||
|
||||
void ApiEvents::DowntimeRemovedHandler(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime, const MessageOrigin& origin)
|
||||
{
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
if (!listener)
|
||||
return;
|
||||
|
||||
Host::Ptr host;
|
||||
Service::Ptr service;
|
||||
tie(host, service) = GetHostService(checkable);
|
||||
|
||||
Dictionary::Ptr params = make_shared<Dictionary>();
|
||||
params->Set("host", host->GetName());
|
||||
if (service)
|
||||
params->Set("service", service->GetShortName());
|
||||
params->Set("id", downtime->GetId());
|
||||
|
||||
Dictionary::Ptr message = make_shared<Dictionary>();
|
||||
message->Set("jsonrpc", "2.0");
|
||||
message->Set("method", "event::RemoveDowntime");
|
||||
message->Set("params", params);
|
||||
|
||||
listener->RelayMessage(origin, checkable, message, true);
|
||||
}
|
||||
|
||||
Value ApiEvents::DowntimeRemovedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params)
|
||||
{
|
||||
if (!params)
|
||||
return Empty;
|
||||
|
||||
Host::Ptr host = Host::GetByName(params->Get("host"));
|
||||
|
||||
if (!host)
|
||||
return Empty;
|
||||
|
||||
Checkable::Ptr checkable;
|
||||
|
||||
if (params->Contains("service"))
|
||||
checkable = host->GetServiceByShortName(params->Get("service"));
|
||||
else
|
||||
checkable = host;
|
||||
|
||||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->RemoveDowntime(params->Get("id"), false, origin);
|
||||
|
||||
return Empty;
|
||||
}
|
||||
|
||||
void ApiEvents::AcknowledgementSetHandler(const Checkable::Ptr& checkable,
|
||||
const String& author, const String& comment, AcknowledgementType type,
|
||||
double expiry, const MessageOrigin& origin)
|
||||
{
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
if (!listener)
|
||||
return;
|
||||
|
||||
Host::Ptr host;
|
||||
Service::Ptr service;
|
||||
tie(host, service) = GetHostService(checkable);
|
||||
|
||||
Dictionary::Ptr params = make_shared<Dictionary>();
|
||||
params->Set("host", host->GetName());
|
||||
if (service)
|
||||
params->Set("service", service->GetShortName());
|
||||
params->Set("author", author);
|
||||
params->Set("comment", comment);
|
||||
params->Set("acktype", type);
|
||||
params->Set("expiry", expiry);
|
||||
|
||||
Dictionary::Ptr message = make_shared<Dictionary>();
|
||||
message->Set("jsonrpc", "2.0");
|
||||
message->Set("method", "event::SetAcknowledgement");
|
||||
message->Set("params", params);
|
||||
|
||||
listener->RelayMessage(origin, checkable, message, true);
|
||||
}
|
||||
|
||||
Value ApiEvents::AcknowledgementSetAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params)
|
||||
{
|
||||
if (!params)
|
||||
return Empty;
|
||||
|
||||
Host::Ptr host = Host::GetByName(params->Get("host"));
|
||||
|
||||
if (!host)
|
||||
return Empty;
|
||||
|
||||
Checkable::Ptr checkable;
|
||||
|
||||
if (params->Contains("service"))
|
||||
checkable = host->GetServiceByShortName(params->Get("service"));
|
||||
else
|
||||
checkable = host;
|
||||
|
||||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->AcknowledgeProblem(params->Get("author"), params->Get("comment"),
|
||||
static_cast<AcknowledgementType>(static_cast<int>(params->Get("acktype"))),
|
||||
params->Get("expiry"), origin);
|
||||
|
||||
return Empty;
|
||||
}
|
||||
|
||||
void ApiEvents::AcknowledgementClearedHandler(const Checkable::Ptr& checkable, const MessageOrigin& origin)
|
||||
{
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
if (!listener)
|
||||
return;
|
||||
|
||||
Host::Ptr host;
|
||||
Service::Ptr service;
|
||||
tie(host, service) = GetHostService(checkable);
|
||||
|
||||
Dictionary::Ptr params = make_shared<Dictionary>();
|
||||
params->Set("host", host->GetName());
|
||||
if (service)
|
||||
params->Set("service", service->GetShortName());
|
||||
|
||||
Dictionary::Ptr message = make_shared<Dictionary>();
|
||||
message->Set("jsonrpc", "2.0");
|
||||
message->Set("method", "event::ClearAcknowledgement");
|
||||
message->Set("params", params);
|
||||
|
||||
listener->RelayMessage(origin, checkable, message, true);
|
||||
}
|
||||
|
||||
Value ApiEvents::AcknowledgementClearedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params)
|
||||
{
|
||||
if (!params)
|
||||
return Empty;
|
||||
|
||||
Host::Ptr host = Host::GetByName(params->Get("host"));
|
||||
|
||||
if (!host)
|
||||
return Empty;
|
||||
|
||||
Checkable::Ptr checkable;
|
||||
|
||||
if (params->Contains("service"))
|
||||
checkable = host->GetServiceByShortName(params->Get("service"));
|
||||
else
|
||||
checkable = host;
|
||||
|
||||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->ClearAcknowledgement(origin);
|
||||
|
||||
return Empty;
|
||||
}
|
||||
|
||||
void ApiEvents::RepositoryTimerHandler(void)
|
||||
{
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
if (!listener)
|
||||
return;
|
||||
|
||||
Dictionary::Ptr repository = make_shared<Dictionary>();
|
||||
|
||||
BOOST_FOREACH(const Host::Ptr& host, DynamicType::GetObjects<Host>()) {
|
||||
Array::Ptr services = make_shared<Array>();
|
||||
|
||||
BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) {
|
||||
services->Add(service->GetName());
|
||||
}
|
||||
|
||||
repository->Set(host->GetName(), services);
|
||||
}
|
||||
|
||||
Endpoint::Ptr my_endpoint = Endpoint::GetLocalEndpoint();
|
||||
Zone::Ptr my_zone = my_endpoint->GetZone();
|
||||
|
||||
Dictionary::Ptr params = make_shared<Dictionary>();
|
||||
params->Set("endpoint", my_endpoint->GetName());
|
||||
|
||||
Zone::Ptr parent_zone = my_zone->GetParent();
|
||||
if (parent_zone)
|
||||
params->Set("parent_zone", parent_zone->GetName());
|
||||
|
||||
params->Set("zone", my_zone->GetName());
|
||||
params->Set("repository", repository);
|
||||
|
||||
Dictionary::Ptr message = make_shared<Dictionary>();
|
||||
message->Set("jsonrpc", "2.0");
|
||||
message->Set("method", "event::UpdateRepository");
|
||||
message->Set("params", params);
|
||||
|
||||
listener->RelayMessage(MessageOrigin(), my_zone, message, true);
|
||||
}
|
||||
|
||||
String ApiEvents::GetRepositoryDir(void)
|
||||
{
|
||||
return Application::GetLocalStateDir() + "/lib/icinga2/api/repository/";
|
||||
}
|
||||
|
||||
Value ApiEvents::UpdateRepositoryAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params)
|
||||
{
|
||||
if (!params)
|
||||
return Empty;
|
||||
|
||||
Zone::Ptr zone = Zone::GetByName(params->Get("zone"));
|
||||
|
||||
if (!zone || (origin.FromZone && !origin.FromZone->CanAccessObject(zone)))
|
||||
return Empty;
|
||||
|
||||
String repositoryFile = GetRepositoryDir() + SHA256(params->Get("endpoint"));
|
||||
String repositoryTempFile = repositoryFile + ".tmp";
|
||||
|
||||
std::ofstream fp(repositoryTempFile.CStr(), std::ofstream::out | std::ostream::trunc);
|
||||
fp << JsonSerialize(params);
|
||||
fp.close();
|
||||
|
||||
#ifdef _WIN32
|
||||
_unlink(inventoryFile.CStr());
|
||||
#endif /* _WIN32 */
|
||||
|
||||
if (rename(repositoryTempFile.CStr(), repositoryFile.CStr()) < 0) {
|
||||
BOOST_THROW_EXCEPTION(posix_error()
|
||||
<< boost::errinfo_api_function("rename")
|
||||
<< boost::errinfo_errno(errno)
|
||||
<< boost::errinfo_file_name(repositoryTempFile));
|
||||
}
|
||||
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
if (!listener)
|
||||
return Empty;
|
||||
|
||||
Dictionary::Ptr message = make_shared<Dictionary>();
|
||||
message->Set("jsonrpc", "2.0");
|
||||
message->Set("method", "event::UpdateRepository");
|
||||
message->Set("params", params);
|
||||
|
||||
listener->RelayMessage(origin, Zone::GetLocalZone(), message, true);
|
||||
|
||||
return Empty;
|
||||
}
|
93
lib/icinga/apievents.h
Normal file
93
lib/icinga/apievents.h
Normal file
@ -0,0 +1,93 @@
|
||||
/******************************************************************************
|
||||
* 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 APIEVENTS_H
|
||||
#define APIEVENTS_H
|
||||
|
||||
#include "icinga/checkable.h"
|
||||
#include "remote/apiclient.h"
|
||||
#include "base/stream.h"
|
||||
#include "base/timer.h"
|
||||
#include "base/array.h"
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
/**
|
||||
* @ingroup icinga
|
||||
*/
|
||||
class I2_ICINGA_API ApiEvents
|
||||
{
|
||||
public:
|
||||
static void StaticInitialize(void);
|
||||
|
||||
static void CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const MessageOrigin& origin);
|
||||
static Value CheckResultAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||
|
||||
static void NextCheckChangedHandler(const Checkable::Ptr& checkable, double nextCheck, const MessageOrigin& origin);
|
||||
static Value NextCheckChangedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||
|
||||
static void NextNotificationChangedHandler(const Notification::Ptr& notification, double nextCheck, const MessageOrigin& origin);
|
||||
static Value NextNotificationChangedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||
|
||||
static void ForceNextCheckChangedHandler(const Checkable::Ptr& checkable, bool forced, const MessageOrigin& origin);
|
||||
static Value ForceNextCheckChangedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||
|
||||
static void ForceNextNotificationChangedHandler(const Checkable::Ptr& checkable, bool forced, const MessageOrigin& origin);
|
||||
static Value ForceNextNotificationChangedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||
|
||||
static void EnableActiveChecksChangedHandler(const Checkable::Ptr& checkable, bool enabled, const MessageOrigin& origin);
|
||||
static Value EnableActiveChecksChangedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||
|
||||
static void EnablePassiveChecksChangedHandler(const Checkable::Ptr& checkable, bool enabled, const MessageOrigin& origin);
|
||||
static Value EnablePassiveChecksChangedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||
|
||||
static void EnableNotificationsChangedHandler(const Checkable::Ptr& checkable, bool enabled, const MessageOrigin& origin);
|
||||
static Value EnableNotificationsChangedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||
|
||||
static void EnableFlappingChangedHandler(const Checkable::Ptr& checkable, bool enabled, const MessageOrigin& origin);
|
||||
static Value EnableFlappingChangedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||
|
||||
static void CommentAddedHandler(const Checkable::Ptr& checkable, const Comment::Ptr& comment, const MessageOrigin& origin);
|
||||
static Value CommentAddedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||
|
||||
static void CommentRemovedHandler(const Checkable::Ptr& checkable, const Comment::Ptr& comment, const MessageOrigin& origin);
|
||||
static Value CommentRemovedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||
|
||||
static void DowntimeAddedHandler(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime, const MessageOrigin& origin);
|
||||
static Value DowntimeAddedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||
|
||||
static void DowntimeRemovedHandler(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime, const MessageOrigin& origin);
|
||||
static Value DowntimeRemovedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||
|
||||
static void AcknowledgementSetHandler(const Checkable::Ptr& checkable, const String& author, const String& comment, AcknowledgementType type, double expiry, const MessageOrigin& origin);
|
||||
static Value AcknowledgementSetAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||
|
||||
static void AcknowledgementClearedHandler(const Checkable::Ptr& checkable, const MessageOrigin& origin);
|
||||
static Value AcknowledgementClearedAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||
|
||||
static String GetRepositoryDir(void);
|
||||
static void RepositoryTimerHandler(void);
|
||||
static Value UpdateRepositoryAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* APIEVENTS_H */
|
@ -21,6 +21,7 @@
|
||||
#include "icinga/checkcommand.h"
|
||||
#include "icinga/icingaapplication.h"
|
||||
#include "icinga/cib.h"
|
||||
#include "remote/apilistener.h"
|
||||
#include "base/dynamictype.h"
|
||||
#include "base/objectlock.h"
|
||||
#include "base/logger_fwd.h"
|
||||
@ -33,16 +34,16 @@
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, const CheckResult::Ptr&, const String&)> Checkable::OnNewCheckResult;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, const CheckResult::Ptr&, StateType, const String&)> Checkable::OnStateChange;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, const CheckResult::Ptr&, const MessageOrigin&)> Checkable::OnNewCheckResult;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, const CheckResult::Ptr&, StateType, const MessageOrigin&)> Checkable::OnStateChange;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, NotificationType, const CheckResult::Ptr&, const String&, const String&)> Checkable::OnNotificationsRequested;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, double, const String&)> Checkable::OnNextCheckChanged;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, bool, const String&)> Checkable::OnForceNextCheckChanged;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, bool, const String&)> Checkable::OnForceNextNotificationChanged;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, bool, const String&)> Checkable::OnEnableActiveChecksChanged;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, bool, const String&)> Checkable::OnEnablePassiveChecksChanged;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, bool, const String&)> Checkable::OnEnableNotificationsChanged;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, bool, const String&)> Checkable::OnEnableFlappingChanged;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, double, const MessageOrigin&)> Checkable::OnNextCheckChanged;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, bool, const MessageOrigin&)> Checkable::OnForceNextCheckChanged;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, bool, const MessageOrigin&)> Checkable::OnForceNextNotificationChanged;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, bool, const MessageOrigin&)> Checkable::OnEnableActiveChecksChanged;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, bool, const MessageOrigin&)> Checkable::OnEnablePassiveChecksChanged;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, bool, const MessageOrigin&)> Checkable::OnEnableNotificationsChanged;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, bool, const MessageOrigin&)> Checkable::OnEnableFlappingChanged;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, FlappingState)> Checkable::OnFlappingChanged;
|
||||
|
||||
CheckCommand::Ptr Checkable::GetCheckCommand(void) const
|
||||
@ -115,11 +116,11 @@ long Checkable::GetSchedulingOffset(void)
|
||||
return m_SchedulingOffset;
|
||||
}
|
||||
|
||||
void Checkable::SetNextCheck(double nextCheck, const String& authority)
|
||||
void Checkable::SetNextCheck(double nextCheck, const MessageOrigin& origin)
|
||||
{
|
||||
SetNextCheckRaw(nextCheck);
|
||||
|
||||
OnNextCheckChanged(GetSelf(), nextCheck, authority);
|
||||
OnNextCheckChanged(GetSelf(), nextCheck, origin);
|
||||
}
|
||||
|
||||
double Checkable::GetNextCheck(void)
|
||||
@ -171,11 +172,11 @@ bool Checkable::GetEnableActiveChecks(void) const
|
||||
return GetEnableActiveChecksRaw();
|
||||
}
|
||||
|
||||
void Checkable::SetEnableActiveChecks(bool enabled, const String& authority)
|
||||
void Checkable::SetEnableActiveChecks(bool enabled, const MessageOrigin& origin)
|
||||
{
|
||||
SetOverrideEnableActiveChecks(enabled);
|
||||
|
||||
OnEnableActiveChecksChanged(GetSelf(), enabled, authority);
|
||||
OnEnableActiveChecksChanged(GetSelf(), enabled, origin);
|
||||
}
|
||||
|
||||
bool Checkable::GetEnablePassiveChecks(void) const
|
||||
@ -186,11 +187,11 @@ bool Checkable::GetEnablePassiveChecks(void) const
|
||||
return GetEnablePassiveChecksRaw();
|
||||
}
|
||||
|
||||
void Checkable::SetEnablePassiveChecks(bool enabled, const String& authority)
|
||||
void Checkable::SetEnablePassiveChecks(bool enabled, const MessageOrigin& origin)
|
||||
{
|
||||
SetOverrideEnablePassiveChecks(enabled);
|
||||
|
||||
OnEnablePassiveChecksChanged(GetSelf(), enabled, authority);
|
||||
OnEnablePassiveChecksChanged(GetSelf(), enabled, origin);
|
||||
}
|
||||
|
||||
bool Checkable::GetForceNextCheck(void) const
|
||||
@ -198,11 +199,11 @@ bool Checkable::GetForceNextCheck(void) const
|
||||
return GetForceNextCheckRaw();
|
||||
}
|
||||
|
||||
void Checkable::SetForceNextCheck(bool forced, const String& authority)
|
||||
void Checkable::SetForceNextCheck(bool forced, const MessageOrigin& origin)
|
||||
{
|
||||
SetForceNextCheckRaw(forced);
|
||||
|
||||
OnForceNextCheckChanged(GetSelf(), forced, authority);
|
||||
OnForceNextCheckChanged(GetSelf(), forced, origin);
|
||||
}
|
||||
|
||||
int Checkable::GetMaxCheckAttempts(void) const
|
||||
@ -218,7 +219,7 @@ void Checkable::SetMaxCheckAttempts(int attempts)
|
||||
SetOverrideMaxCheckAttempts(attempts);
|
||||
}
|
||||
|
||||
void Checkable::ProcessCheckResult(const CheckResult::Ptr& cr, const String& authority)
|
||||
void Checkable::ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrigin& origin)
|
||||
{
|
||||
{
|
||||
ObjectLock olock(this);
|
||||
@ -239,7 +240,7 @@ void Checkable::ProcessCheckResult(const CheckResult::Ptr& cr, const String& aut
|
||||
if (cr->GetExecutionEnd() == 0)
|
||||
cr->SetExecutionEnd(now);
|
||||
|
||||
if (authority.IsEmpty())
|
||||
if (origin.IsLocal())
|
||||
cr->SetCheckSource(IcingaApplication::GetInstance()->GetNodeName());
|
||||
|
||||
bool reachable = IsReachable();
|
||||
@ -399,15 +400,15 @@ void Checkable::ProcessCheckResult(const CheckResult::Ptr& cr, const String& aut
|
||||
// " threshold: " + Convert::ToString(GetFlappingThreshold()) +
|
||||
// "% current: " + Convert::ToString(GetFlappingCurrent()) + "%.");
|
||||
|
||||
OnNewCheckResult(GetSelf(), cr, authority);
|
||||
OnNewCheckResult(GetSelf(), cr, origin);
|
||||
|
||||
/* signal status updates to for example db_ido */
|
||||
OnStateChanged(GetSelf(), authority);
|
||||
OnStateChanged(GetSelf());
|
||||
|
||||
if (hardChange)
|
||||
OnStateChange(GetSelf(), cr, StateTypeHard, authority);
|
||||
OnStateChange(GetSelf(), cr, StateTypeHard, origin);
|
||||
else if (stateChange)
|
||||
OnStateChange(GetSelf(), cr, StateTypeSoft, authority);
|
||||
OnStateChange(GetSelf(), cr, StateTypeSoft, origin);
|
||||
|
||||
if (GetStateType() == StateTypeSoft || hardChange || recovery)
|
||||
ExecuteEventHandler();
|
||||
|
@ -33,8 +33,8 @@ static std::map<int, String> l_LegacyCommentsCache;
|
||||
static std::map<String, Checkable::WeakPtr> l_CommentsCache;
|
||||
static Timer::Ptr l_CommentsExpireTimer;
|
||||
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, const Comment::Ptr&, const String&)> Checkable::OnCommentAdded;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, const Comment::Ptr&, const String&)> Checkable::OnCommentRemoved;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, const Comment::Ptr&, const MessageOrigin&)> Checkable::OnCommentAdded;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, const Comment::Ptr&, const MessageOrigin&)> Checkable::OnCommentRemoved;
|
||||
|
||||
int Checkable::GetNextCommentID(void)
|
||||
{
|
||||
@ -44,7 +44,7 @@ int Checkable::GetNextCommentID(void)
|
||||
}
|
||||
|
||||
String Checkable::AddComment(CommentType entryType, const String& author,
|
||||
const String& text, double expireTime, const String& id, const String& authority)
|
||||
const String& text, double expireTime, const String& id, const MessageOrigin& origin)
|
||||
{
|
||||
String uid;
|
||||
|
||||
@ -78,7 +78,7 @@ String Checkable::AddComment(CommentType entryType, const String& author,
|
||||
l_CommentsCache[uid] = GetSelf();
|
||||
}
|
||||
|
||||
OnCommentAdded(GetSelf(), comment, authority);
|
||||
OnCommentAdded(GetSelf(), comment, origin);
|
||||
|
||||
return uid;
|
||||
}
|
||||
@ -100,7 +100,7 @@ void Checkable::RemoveAllComments(void)
|
||||
}
|
||||
}
|
||||
|
||||
void Checkable::RemoveComment(const String& id, const String& authority)
|
||||
void Checkable::RemoveComment(const String& id, const MessageOrigin& origin)
|
||||
{
|
||||
Checkable::Ptr owner = GetOwnerByCommentID(id);
|
||||
|
||||
@ -126,7 +126,7 @@ void Checkable::RemoveComment(const String& id, const String& authority)
|
||||
l_CommentsCache.erase(id);
|
||||
}
|
||||
|
||||
OnCommentRemoved(owner, comment, authority);
|
||||
OnCommentRemoved(owner, comment, origin);
|
||||
}
|
||||
|
||||
String Checkable::GetCommentIDFromLegacyID(int id)
|
||||
|
@ -35,8 +35,8 @@ static std::map<int, String> l_LegacyDowntimesCache;
|
||||
static std::map<String, Checkable::WeakPtr> l_DowntimesCache;
|
||||
static Timer::Ptr l_DowntimesExpireTimer;
|
||||
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, const Downtime::Ptr&, const String&)> Checkable::OnDowntimeAdded;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, const Downtime::Ptr&, const String&)> Checkable::OnDowntimeRemoved;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, const Downtime::Ptr&, const MessageOrigin&)> Checkable::OnDowntimeAdded;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, const Downtime::Ptr&, const MessageOrigin&)> Checkable::OnDowntimeRemoved;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, const Downtime::Ptr&)> Checkable::OnDowntimeTriggered;
|
||||
|
||||
int Checkable::GetNextDowntimeID(void)
|
||||
@ -49,7 +49,7 @@ int Checkable::GetNextDowntimeID(void)
|
||||
String Checkable::AddDowntime(const String& author, const String& comment,
|
||||
double startTime, double endTime, bool fixed,
|
||||
const String& triggeredBy, double duration, const String& scheduledBy,
|
||||
const String& id, const String& authority)
|
||||
const String& id, const MessageOrigin& origin)
|
||||
{
|
||||
String uid;
|
||||
|
||||
@ -106,12 +106,12 @@ String Checkable::AddDowntime(const String& author, const String& comment,
|
||||
Log(LogDebug, "icinga", "Added downtime with ID '" + Convert::ToString(downtime->GetLegacyId()) +
|
||||
"' between '" + Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", startTime) + "' and '" + Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", endTime) + "'.");
|
||||
|
||||
OnDowntimeAdded(GetSelf(), downtime, authority);
|
||||
OnDowntimeAdded(GetSelf(), downtime, origin);
|
||||
|
||||
return uid;
|
||||
}
|
||||
|
||||
void Checkable::RemoveDowntime(const String& id, bool cancelled, const String& authority)
|
||||
void Checkable::RemoveDowntime(const String& id, bool cancelled, const MessageOrigin& origin)
|
||||
{
|
||||
Checkable::Ptr owner = GetOwnerByDowntimeID(id);
|
||||
|
||||
@ -146,7 +146,7 @@ void Checkable::RemoveDowntime(const String& id, bool cancelled, const String& a
|
||||
|
||||
Log(LogDebug, "icinga", "Removed downtime with ID '" + Convert::ToString(downtime->GetLegacyId()) + "' from service '" + owner->GetName() + "'.");
|
||||
|
||||
OnDowntimeRemoved(owner, downtime, authority);
|
||||
OnDowntimeRemoved(owner, downtime, origin);
|
||||
}
|
||||
|
||||
void Checkable::TriggerDowntimes(void)
|
||||
|
@ -47,12 +47,12 @@ bool Checkable::GetEnableFlapping(void) const
|
||||
return GetEnableFlappingRaw();
|
||||
}
|
||||
|
||||
void Checkable::SetEnableFlapping(bool enabled, const String& authority)
|
||||
void Checkable::SetEnableFlapping(bool enabled, const MessageOrigin& origin)
|
||||
{
|
||||
SetOverrideEnableFlapping(enabled);
|
||||
|
||||
OnFlappingChanged(GetSelf(), enabled ? FlappingEnabled : FlappingDisabled);
|
||||
OnEnableFlappingChanged(GetSelf(), enabled, authority);
|
||||
OnEnableFlappingChanged(GetSelf(), enabled, origin);
|
||||
}
|
||||
|
||||
void Checkable::UpdateFlappingStatus(bool stateChange)
|
||||
|
@ -108,11 +108,11 @@ bool Checkable::GetEnableNotifications(void) const
|
||||
return GetEnableNotificationsRaw();
|
||||
}
|
||||
|
||||
void Checkable::SetEnableNotifications(bool enabled, const String& authority)
|
||||
void Checkable::SetEnableNotifications(bool enabled, const MessageOrigin& origin)
|
||||
{
|
||||
SetOverrideEnableNotifications(enabled);
|
||||
|
||||
OnEnableNotificationsChanged(GetSelf(), enabled, authority);
|
||||
OnEnableNotificationsChanged(GetSelf(), enabled, origin);
|
||||
}
|
||||
|
||||
bool Checkable::GetForceNextNotification(void) const
|
||||
@ -120,9 +120,9 @@ bool Checkable::GetForceNextNotification(void) const
|
||||
return GetForceNextNotificationRaw();
|
||||
}
|
||||
|
||||
void Checkable::SetForceNextNotification(bool forced, const String& authority)
|
||||
void Checkable::SetForceNextNotification(bool forced, const MessageOrigin& origin)
|
||||
{
|
||||
SetForceNextNotificationRaw(forced);
|
||||
|
||||
OnForceNextNotificationChanged(GetSelf(), forced, authority);
|
||||
OnForceNextNotificationChanged(GetSelf(), forced, origin);
|
||||
}
|
||||
|
@ -39,8 +39,8 @@ REGISTER_TYPE(Checkable);
|
||||
|
||||
INITIALIZE_ONCE(&Checkable::StartDowntimesExpiredTimer);
|
||||
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, const String&, const String&, AcknowledgementType, double, const String&)> Checkable::OnAcknowledgementSet;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, const String&)> Checkable::OnAcknowledgementCleared;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, const String&, const String&, AcknowledgementType, double, const MessageOrigin&)> Checkable::OnAcknowledgementSet;
|
||||
boost::signals2::signal<void (const Checkable::Ptr&, const MessageOrigin&)> Checkable::OnAcknowledgementCleared;
|
||||
|
||||
Checkable::Checkable(void)
|
||||
: m_CheckRunning(false)
|
||||
@ -129,7 +129,7 @@ bool Checkable::IsAcknowledged(void)
|
||||
return GetAcknowledgement() != AcknowledgementNone;
|
||||
}
|
||||
|
||||
void Checkable::AcknowledgeProblem(const String& author, const String& comment, AcknowledgementType type, double expiry, const String& authority)
|
||||
void Checkable::AcknowledgeProblem(const String& author, const String& comment, AcknowledgementType type, double expiry, const MessageOrigin& origin)
|
||||
{
|
||||
{
|
||||
ObjectLock olock(this);
|
||||
@ -140,17 +140,17 @@ void Checkable::AcknowledgeProblem(const String& author, const String& comment,
|
||||
|
||||
OnNotificationsRequested(GetSelf(), NotificationAcknowledgement, GetLastCheckResult(), author, comment);
|
||||
|
||||
OnAcknowledgementSet(GetSelf(), author, comment, type, expiry, authority);
|
||||
OnAcknowledgementSet(GetSelf(), author, comment, type, expiry, origin);
|
||||
}
|
||||
|
||||
void Checkable::ClearAcknowledgement(const String& authority)
|
||||
void Checkable::ClearAcknowledgement(const MessageOrigin& origin)
|
||||
{
|
||||
ASSERT(OwnsLock());
|
||||
|
||||
SetAcknowledgementRaw(AcknowledgementNone);
|
||||
SetAcknowledgementExpiry(0);
|
||||
|
||||
OnAcknowledgementCleared(GetSelf(), authority);
|
||||
OnAcknowledgementCleared(GetSelf(), origin);
|
||||
}
|
||||
|
||||
bool Checkable::GetEnablePerfdata(void) const
|
||||
@ -161,7 +161,7 @@ bool Checkable::GetEnablePerfdata(void) const
|
||||
return GetEnablePerfdataRaw();
|
||||
}
|
||||
|
||||
void Checkable::SetEnablePerfdata(bool enabled, const String& authority)
|
||||
void Checkable::SetEnablePerfdata(bool enabled, const MessageOrigin& origin)
|
||||
{
|
||||
SetOverrideEnablePerfdata(enabled);
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "icinga/notification.h"
|
||||
#include "icinga/comment.h"
|
||||
#include "icinga/downtime.h"
|
||||
#include "remote/messageorigin.h"
|
||||
#include "base/i2-base.h"
|
||||
#include "base/array.h"
|
||||
#include <boost/signals2.hpp>
|
||||
@ -97,8 +98,8 @@ public:
|
||||
|
||||
AcknowledgementType GetAcknowledgement(void);
|
||||
|
||||
void AcknowledgeProblem(const String& author, const String& comment, AcknowledgementType type, double expiry = 0, const String& authority = String());
|
||||
void ClearAcknowledgement(const String& authority = String());
|
||||
void AcknowledgeProblem(const String& author, const String& comment, AcknowledgementType type, double expiry = 0, const MessageOrigin& origin = MessageOrigin());
|
||||
void ClearAcknowledgement(const MessageOrigin& origin = MessageOrigin());
|
||||
|
||||
/* Checks */
|
||||
shared_ptr<CheckCommand> GetCheckCommand(void) const;
|
||||
@ -119,7 +120,7 @@ public:
|
||||
long GetSchedulingOffset(void);
|
||||
void SetSchedulingOffset(long offset);
|
||||
|
||||
void SetNextCheck(double nextCheck, const String& authority = String());
|
||||
void SetNextCheck(double nextCheck, const MessageOrigin& origin = MessageOrigin());
|
||||
double GetNextCheck(void);
|
||||
void UpdateNextCheck(void);
|
||||
|
||||
@ -128,18 +129,18 @@ public:
|
||||
double GetLastCheck(void) const;
|
||||
|
||||
bool GetEnableActiveChecks(void) const;
|
||||
void SetEnableActiveChecks(bool enabled, const String& authority = String());
|
||||
void SetEnableActiveChecks(bool enabled, const MessageOrigin& origin = MessageOrigin());
|
||||
|
||||
bool GetEnablePassiveChecks(void) const;
|
||||
void SetEnablePassiveChecks(bool enabled, const String& authority = String());
|
||||
void SetEnablePassiveChecks(bool enabled, const MessageOrigin& origin = MessageOrigin());
|
||||
|
||||
bool GetForceNextCheck(void) const;
|
||||
void SetForceNextCheck(bool forced, const String& authority = String());
|
||||
void SetForceNextCheck(bool forced, const MessageOrigin& origin = MessageOrigin());
|
||||
|
||||
static void UpdateStatistics(const CheckResult::Ptr& cr);
|
||||
|
||||
void ExecuteCheck(void);
|
||||
void ProcessCheckResult(const CheckResult::Ptr& cr, const String& authority = String());
|
||||
void ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrigin& origin = MessageOrigin());
|
||||
|
||||
int GetModifiedAttributes(void) const;
|
||||
void SetModifiedAttributes(int flags);
|
||||
@ -149,15 +150,15 @@ public:
|
||||
static double CalculateExecutionTime(const CheckResult::Ptr& cr);
|
||||
static double CalculateLatency(const CheckResult::Ptr& cr);
|
||||
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, double, const String&)> OnNextCheckChanged;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, bool, const String&)> OnForceNextCheckChanged;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, bool, const String&)> OnForceNextNotificationChanged;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, bool, const String&)> OnEnableActiveChecksChanged;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, bool, const String&)> OnEnablePassiveChecksChanged;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, bool, const String&)> OnEnableNotificationsChanged;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, bool, const String&)> OnEnableFlappingChanged;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, const CheckResult::Ptr&, const String&)> OnNewCheckResult;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, const CheckResult::Ptr&, StateType, const String&)> OnStateChange;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, double, const MessageOrigin&)> OnNextCheckChanged;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, bool, const MessageOrigin&)> OnForceNextCheckChanged;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, bool, const MessageOrigin&)> OnForceNextNotificationChanged;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, bool, const MessageOrigin&)> OnEnableActiveChecksChanged;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, bool, const MessageOrigin&)> OnEnablePassiveChecksChanged;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, bool, const MessageOrigin&)> OnEnableNotificationsChanged;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, bool, const MessageOrigin&)> OnEnableFlappingChanged;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, const CheckResult::Ptr&, const MessageOrigin&)> OnNewCheckResult;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, const CheckResult::Ptr&, StateType, const MessageOrigin&)> OnStateChange;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, NotificationType, const CheckResult::Ptr&,
|
||||
const String&, const String&)> OnNotificationsRequested;
|
||||
static boost::signals2::signal<void (const Notification::Ptr&, const Checkable::Ptr&, const std::set<User::Ptr>&,
|
||||
@ -169,15 +170,15 @@ public:
|
||||
static boost::signals2::signal<void (const Notification::Ptr&, const Checkable::Ptr&, const std::set<User::Ptr>&,
|
||||
const NotificationType&, const CheckResult::Ptr&, const String&,
|
||||
const String&)> OnNotificationSentToAllUsers;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, const Comment::Ptr&, const String&)> OnCommentAdded;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, const Comment::Ptr&, const String&)> OnCommentRemoved;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, const Downtime::Ptr&, const String&)> OnDowntimeAdded;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, const Downtime::Ptr&, const String&)> OnDowntimeRemoved;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, const Comment::Ptr&, const MessageOrigin&)> OnCommentAdded;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, const Comment::Ptr&, const MessageOrigin&)> OnCommentRemoved;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, const Downtime::Ptr&, const MessageOrigin&)> OnDowntimeAdded;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, const Downtime::Ptr&, const MessageOrigin&)> OnDowntimeRemoved;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, FlappingState)> OnFlappingChanged;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, const Downtime::Ptr&)> OnDowntimeTriggered;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, const String&, const String&, AcknowledgementType,
|
||||
double, const String&)> OnAcknowledgementSet;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, const String&)> OnAcknowledgementCleared;
|
||||
double, const MessageOrigin&)> OnAcknowledgementSet;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&, const MessageOrigin&)> OnAcknowledgementCleared;
|
||||
static boost::signals2::signal<void (const Checkable::Ptr&)> OnEventCommandExecuted;
|
||||
|
||||
/* Downtimes */
|
||||
@ -189,9 +190,9 @@ public:
|
||||
double startTime, double endTime, bool fixed,
|
||||
const String& triggeredBy, double duration,
|
||||
const String& scheduledBy = String(), const String& id = String(),
|
||||
const String& authority = String());
|
||||
const MessageOrigin& origin = MessageOrigin());
|
||||
|
||||
static void RemoveDowntime(const String& id, bool cancelled, const String& = String());
|
||||
static void RemoveDowntime(const String& id, bool cancelled, const MessageOrigin& origin = MessageOrigin());
|
||||
|
||||
void TriggerDowntimes(void);
|
||||
static void TriggerDowntime(const String& id);
|
||||
@ -209,11 +210,11 @@ public:
|
||||
static int GetNextCommentID(void);
|
||||
|
||||
String AddComment(CommentType entryType, const String& author,
|
||||
const String& text, double expireTime, const String& id = String(), const String& authority = String());
|
||||
const String& text, double expireTime, const String& id = String(), const MessageOrigin& origin = MessageOrigin());
|
||||
|
||||
void RemoveAllComments(void);
|
||||
void RemoveCommentsByType(int type);
|
||||
static void RemoveComment(const String& id, const String& authority = String());
|
||||
static void RemoveComment(const String& id, const MessageOrigin& origin = MessageOrigin());
|
||||
|
||||
static String GetCommentIDFromLegacyID(int id);
|
||||
static Checkable::Ptr GetOwnerByCommentID(const String& id);
|
||||
@ -221,7 +222,7 @@ public:
|
||||
|
||||
/* Notifications */
|
||||
bool GetEnableNotifications(void) const;
|
||||
void SetEnableNotifications(bool enabled, const String& authority = String());
|
||||
void SetEnableNotifications(bool enabled, const MessageOrigin& origin = MessageOrigin());
|
||||
|
||||
void SendNotifications(NotificationType type, const CheckResult::Ptr& cr, const String& author = "", const String& text = "");
|
||||
|
||||
@ -229,7 +230,7 @@ public:
|
||||
void AddNotification(const Notification::Ptr& notification);
|
||||
void RemoveNotification(const Notification::Ptr& notification);
|
||||
|
||||
void SetForceNextNotification(bool force, const String& authority = String());
|
||||
void SetForceNextNotification(bool force, const MessageOrigin& origin = MessageOrigin());
|
||||
bool GetForceNextNotification(void) const;
|
||||
|
||||
void ResetNotificationNumbers(void);
|
||||
@ -247,14 +248,14 @@ public:
|
||||
double GetFlappingCurrent(void) const;
|
||||
|
||||
bool GetEnableFlapping(void) const;
|
||||
void SetEnableFlapping(bool enabled, const String& authority = String());
|
||||
void SetEnableFlapping(bool enabled, const MessageOrigin& origin = MessageOrigin());
|
||||
|
||||
bool IsFlapping(void) const;
|
||||
void UpdateFlappingStatus(bool stateChange);
|
||||
|
||||
/* Performance data */
|
||||
bool GetEnablePerfdata(void) const;
|
||||
void SetEnablePerfdata(bool enabled, const String& authority = String());
|
||||
void SetEnablePerfdata(bool enabled, const MessageOrigin& origin = MessageOrigin());
|
||||
|
||||
/* Dependencies */
|
||||
void AddDependency(const shared_ptr<Dependency>& dep);
|
||||
|
@ -1,11 +0,0 @@
|
||||
#include "base/dynamicobject.h"
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
class Domain : DynamicObject
|
||||
{
|
||||
[config] Dictionary::Ptr acl;
|
||||
};
|
||||
|
||||
}
|
@ -28,6 +28,7 @@
|
||||
#include "icinga/checkcommand.h"
|
||||
#include "icinga/eventcommand.h"
|
||||
#include "icinga/notificationcommand.h"
|
||||
#include "remote/apifunction.h"
|
||||
#include "base/convert.h"
|
||||
#include "base/logger_fwd.h"
|
||||
#include "base/objectlock.h"
|
||||
@ -41,8 +42,7 @@
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
static boost::once_flag l_InitializeOnce = BOOST_ONCE_INIT;
|
||||
static boost::mutex l_Mutex;
|
||||
INITIALIZE_ONCE(&ExternalCommandProcessor::StaticInitialize);
|
||||
|
||||
typedef boost::function<void (double time, const std::vector<String>& arguments)> ExternalCommandCallback;
|
||||
|
||||
@ -53,18 +53,46 @@ struct ExternalCommandInfo
|
||||
size_t MaxArgs;
|
||||
};
|
||||
|
||||
static std::map<String, ExternalCommandInfo> l_Commands;
|
||||
static boost::mutex& GetMutex(void)
|
||||
{
|
||||
static boost::mutex mtx;
|
||||
return mtx;
|
||||
}
|
||||
static std::map<String, ExternalCommandInfo>& GetCommands(void)
|
||||
{
|
||||
static std::map<String, ExternalCommandInfo> commands;
|
||||
return commands;
|
||||
}
|
||||
|
||||
boost::signals2::signal<void (double, const String&, const std::vector<String>&)> ExternalCommandProcessor::OnNewExternalCommand;
|
||||
|
||||
static Value ExternalCommandAPIWrapper(const String& command, const Dictionary::Ptr& params)
|
||||
{
|
||||
std::vector<String> arguments;
|
||||
|
||||
if (params) {
|
||||
int i = 0;
|
||||
while (params->Contains("arg" + Convert::ToString(i))) {
|
||||
arguments.push_back(params->Get("arg" + Convert::ToString(i)));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
ExternalCommandProcessor::Execute(Utility::GetTime(), command, arguments);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void RegisterCommand(const String& command, const ExternalCommandCallback& callback, size_t minArgs = 0, size_t maxArgs = -1)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(l_Mutex);
|
||||
boost::mutex::scoped_lock lock(GetMutex());
|
||||
ExternalCommandInfo eci;
|
||||
eci.Callback = callback;
|
||||
eci.MinArgs = minArgs;
|
||||
eci.MaxArgs = (maxArgs == -1) ? minArgs : maxArgs;
|
||||
l_Commands[command] = eci;
|
||||
GetCommands()[command] = eci;
|
||||
|
||||
ApiFunction::Ptr afunc = make_shared<ApiFunction>(boost::bind(&ExternalCommandAPIWrapper, command, _2));
|
||||
ApiFunction::Register("extcmd::" + command, afunc);
|
||||
}
|
||||
|
||||
void ExternalCommandProcessor::Execute(const String& line)
|
||||
@ -100,17 +128,15 @@ void ExternalCommandProcessor::Execute(const String& line)
|
||||
|
||||
void ExternalCommandProcessor::Execute(double time, const String& command, const std::vector<String>& arguments)
|
||||
{
|
||||
boost::call_once(l_InitializeOnce, &ExternalCommandProcessor::Initialize);
|
||||
|
||||
ExternalCommandInfo eci;
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(l_Mutex);
|
||||
boost::mutex::scoped_lock lock(GetMutex());
|
||||
|
||||
std::map<String, ExternalCommandInfo>::iterator it;
|
||||
it = l_Commands.find(command);
|
||||
it = GetCommands().find(command);
|
||||
|
||||
if (it == l_Commands.end())
|
||||
if (it == GetCommands().end())
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("The external command '" + command + "' does not exist."));
|
||||
|
||||
eci = it->second;
|
||||
@ -143,7 +169,7 @@ void ExternalCommandProcessor::Execute(double time, const String& command, const
|
||||
eci.Callback(time, realArguments);
|
||||
}
|
||||
|
||||
void ExternalCommandProcessor::Initialize(void)
|
||||
void ExternalCommandProcessor::StaticInitialize(void)
|
||||
{
|
||||
RegisterCommand("PROCESS_HOST_CHECK_RESULT", &ExternalCommandProcessor::ProcessHostCheckResult, 3);
|
||||
RegisterCommand("PROCESS_SERVICE_CHECK_RESULT", &ExternalCommandProcessor::ProcessServiceCheckResult, 4);
|
||||
|
@ -37,13 +37,13 @@ public:
|
||||
static void Execute(const String& line);
|
||||
static void Execute(double time, const String& command, const std::vector<String>& arguments);
|
||||
|
||||
static boost::signals2::signal<void (double, const String&, const std::vector<String>&)> OnNewExternalCommand;
|
||||
static void StaticInitialize(void);
|
||||
|
||||
static boost::signals2::signal<void(double, const String&, const std::vector<String>&)> OnNewExternalCommand;
|
||||
|
||||
private:
|
||||
ExternalCommandProcessor(void);
|
||||
|
||||
static void Initialize(void);
|
||||
|
||||
static void ProcessHostCheckResult(double time, const std::vector<String>& arguments);
|
||||
static void ProcessServiceCheckResult(double time, const std::vector<String>& arguments);
|
||||
static void ScheduleHostCheck(double time, const std::vector<String>& arguments);
|
||||
|
@ -232,12 +232,6 @@
|
||||
|
||||
}
|
||||
|
||||
%type Domain {
|
||||
%attribute %dictionary "acl" {
|
||||
%attribute %number "*"
|
||||
}
|
||||
}
|
||||
|
||||
%type ScheduledDowntime {
|
||||
%require "host_name",
|
||||
%attribute %name(Host) "host_name",
|
||||
|
@ -39,7 +39,7 @@ REGISTER_TYPE(Notification);
|
||||
REGISTER_SCRIPTFUNCTION(ValidateNotificationFilters, &Notification::ValidateFilters);
|
||||
INITIALIZE_ONCE(&Notification::StaticInitialize);
|
||||
|
||||
boost::signals2::signal<void (const Notification::Ptr&, double, const String&)> Notification::OnNextNotificationChanged;
|
||||
boost::signals2::signal<void (const Notification::Ptr&, double, const MessageOrigin&)> Notification::OnNextNotificationChanged;
|
||||
|
||||
String NotificationNameComposer::MakeName(const String& shortName, const Dictionary::Ptr props) const
|
||||
{
|
||||
@ -180,11 +180,11 @@ double Notification::GetNextNotification(void) const
|
||||
* Sets the timestamp when the next periodical notification should be sent.
|
||||
* This does not affect notifications that are sent for state changes.
|
||||
*/
|
||||
void Notification::SetNextNotification(double time, const String& authority)
|
||||
void Notification::SetNextNotification(double time, const MessageOrigin& origin)
|
||||
{
|
||||
SetNextNotificationRaw(time);
|
||||
|
||||
OnNextNotificationChanged(GetSelf(), time, authority);
|
||||
OnNextNotificationChanged(GetSelf(), time, origin);
|
||||
}
|
||||
|
||||
void Notification::UpdateNotificationNumber(void)
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "icinga/user.h"
|
||||
#include "icinga/usergroup.h"
|
||||
#include "icinga/timeperiod.h"
|
||||
#include "remote/messageorigin.h"
|
||||
#include "config/applyrule.h"
|
||||
#include "base/array.h"
|
||||
|
||||
@ -86,7 +87,7 @@ public:
|
||||
std::set<UserGroup::Ptr> GetUserGroups(void) const;
|
||||
|
||||
double GetNextNotification(void) const;
|
||||
void SetNextNotification(double time, const String& authority = String());
|
||||
void SetNextNotification(double time, const MessageOrigin& origin = MessageOrigin());
|
||||
|
||||
void UpdateNotificationNumber(void);
|
||||
void ResetNotificationNumber(void);
|
||||
@ -97,7 +98,7 @@ public:
|
||||
|
||||
static String NotificationTypeToString(NotificationType type);
|
||||
|
||||
static boost::signals2::signal<void (const Notification::Ptr&, double, const String&)> OnNextNotificationChanged;
|
||||
static boost::signals2::signal<void (const Notification::Ptr&, double, const MessageOrigin&)> OnNextNotificationChanged;
|
||||
|
||||
static void RegisterApplyRuleHandler(void);
|
||||
|
||||
|
@ -22,7 +22,7 @@ else()
|
||||
endif()
|
||||
|
||||
add_library(methods SHARED
|
||||
castfuncs.cpp icingachecktask.cpp nullchecktask.cpp nulleventtask.cpp
|
||||
castfuncs.cpp clusterchecktask.cpp icingachecktask.cpp nullchecktask.cpp nulleventtask.cpp
|
||||
pluginchecktask.cpp plugineventtask.cpp pluginnotificationtask.cpp
|
||||
randomchecktask.cpp timeperiodtask.cpp ${WindowsSources}
|
||||
)
|
||||
|
@ -17,8 +17,8 @@
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#include "cluster/clusterchecktask.h"
|
||||
#include "cluster/clusterlistener.h"
|
||||
#include "methods/clusterchecktask.h"
|
||||
#include "remote/apilistener.h"
|
||||
#include "remote/endpoint.h"
|
||||
#include "icinga/cib.h"
|
||||
#include "icinga/service.h"
|
||||
@ -35,38 +35,39 @@ using namespace icinga;
|
||||
|
||||
REGISTER_SCRIPTFUNCTION(ClusterCheck, &ClusterCheckTask::ScriptFunc);
|
||||
|
||||
void ClusterCheckTask::ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr)
|
||||
void ClusterCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr)
|
||||
{
|
||||
/* fetch specific cluster status */
|
||||
std::pair<Dictionary::Ptr, Dictionary::Ptr> stats;
|
||||
BOOST_FOREACH(const ClusterListener::Ptr& cluster_listener, DynamicType::GetObjects<ClusterListener>()) {
|
||||
/* XXX there's only one cluster listener */
|
||||
stats = cluster_listener->GetClusterStatus();
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
if (!listener) {
|
||||
cr->SetOutput("No API listener is configured for this instance.");
|
||||
cr->SetState(ServiceUnknown);
|
||||
checkable->ProcessCheckResult(cr);
|
||||
return;
|
||||
}
|
||||
|
||||
std::pair<Dictionary::Ptr, Dictionary::Ptr> stats = listener->GetStatus();
|
||||
|
||||
Dictionary::Ptr status = stats.first;
|
||||
|
||||
/* use feature stats perfdata */
|
||||
std::pair<Dictionary::Ptr, Dictionary::Ptr> feature_stats = CIB::GetFeatureStats();
|
||||
Dictionary::Ptr perfdata = feature_stats.second;
|
||||
cr->SetPerformanceData(feature_stats.second);
|
||||
|
||||
String connected_endpoints = FormatArray(status->Get("conn_endpoints"));
|
||||
String not_connected_endpoints = FormatArray(status->Get("not_conn_endpoints"));
|
||||
|
||||
ServiceState state = ServiceOK;
|
||||
String output = "Icinga 2 Cluster is running: Connected Endpoints: "+ Convert::ToString(status->Get("num_conn_endpoints")) + " (" +
|
||||
connected_endpoints + ").";
|
||||
|
||||
if (status->Get("num_not_conn_endpoints") > 0) {
|
||||
state = ServiceCritical;
|
||||
output = "Icinga 2 Cluster Problem: " + Convert::ToString(status->Get("num_not_conn_endpoints")) +
|
||||
" Endpoints (" + not_connected_endpoints + ") not connected.";
|
||||
cr->SetState(ServiceCritical);
|
||||
cr->SetOutput("Icinga 2 Cluster is running: Connected Endpoints: "+ Convert::ToString(status->Get("num_conn_endpoints")) + " (" +
|
||||
connected_endpoints + ").");
|
||||
} else {
|
||||
cr->SetState(ServiceOK);
|
||||
cr->SetOutput("Icinga 2 Cluster Problem: " + Convert::ToString(status->Get("num_not_conn_endpoints")) +
|
||||
" Endpoints (" + not_connected_endpoints + ") not connected.");
|
||||
}
|
||||
|
||||
cr->SetOutput(output);
|
||||
cr->SetPerformanceData(perfdata);
|
||||
cr->SetState(state);
|
||||
service->ProcessCheckResult(cr);
|
||||
checkable->ProcessCheckResult(cr);
|
||||
}
|
||||
|
||||
String ClusterCheckTask::FormatArray(const Array::Ptr& arr)
|
||||
@ -88,4 +89,3 @@ String ClusterCheckTask::FormatArray(const Array::Ptr& arr)
|
||||
|
||||
return str;
|
||||
}
|
||||
|
@ -15,12 +15,15 @@
|
||||
# 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(apilistener.ti apilistener.th)
|
||||
mkclass_target(endpoint.ti endpoint.th)
|
||||
mkclass_target(zone.ti zone.th)
|
||||
|
||||
mkembedconfig_target(remote-type.conf remote-type.cpp)
|
||||
|
||||
add_library(remote SHARED
|
||||
endpoint.cpp endpoint.th jsonrpc.cpp remote-type.cpp
|
||||
apiclient.cpp apifunction.cpp apilistener.cpp apilistener.th endpoint.cpp
|
||||
endpoint.th jsonrpc.cpp messageorigin.cpp remote-type.cpp zone.cpp zone.th
|
||||
)
|
||||
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
@ -39,4 +42,7 @@ install(
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2
|
||||
)
|
||||
|
||||
#install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/icinga2/api\")")
|
||||
install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/icinga2/api/log\")")
|
||||
install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/icinga2/api/repository\")")
|
||||
|
||||
|
200
lib/remote/apiclient.cpp
Normal file
200
lib/remote/apiclient.cpp
Normal file
@ -0,0 +1,200 @@
|
||||
/******************************************************************************
|
||||
* 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 "remote/apiclient.h"
|
||||
#include "remote/apilistener.h"
|
||||
#include "remote/apifunction.h"
|
||||
#include "remote/jsonrpc.h"
|
||||
#include "base/application.h"
|
||||
#include "base/dynamictype.h"
|
||||
#include "base/objectlock.h"
|
||||
#include "base/utility.h"
|
||||
#include "base/logger_fwd.h"
|
||||
#include "base/exception.h"
|
||||
#include "base/initialize.h"
|
||||
#include "config/configitembuilder.h"
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
Timer::Ptr ApiClient::m_KeepAliveTimer;
|
||||
|
||||
INITIALIZE_ONCE(&ApiClient::StaticInitialize);
|
||||
|
||||
static Value SetLogPositionHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||
REGISTER_APIFUNCTION(SetLogPosition, log, &SetLogPositionHandler);
|
||||
|
||||
ApiClient::ApiClient(const Endpoint::Ptr& endpoint, const Stream::Ptr& stream, ConnectionRole role)
|
||||
: m_Endpoint(endpoint), m_Stream(stream), m_Role(role), m_Seen(Utility::GetTime())
|
||||
{ }
|
||||
|
||||
void ApiClient::StaticInitialize(void)
|
||||
{
|
||||
m_KeepAliveTimer = make_shared<Timer>();
|
||||
m_KeepAliveTimer->OnTimerExpired.connect(boost::bind(&ApiClient::KeepAliveTimerHandler));
|
||||
m_KeepAliveTimer->SetInterval(5);
|
||||
m_KeepAliveTimer->Start();
|
||||
}
|
||||
|
||||
void ApiClient::Start(void)
|
||||
{
|
||||
boost::thread thread(boost::bind(&ApiClient::MessageThreadProc, static_cast<ApiClient::Ptr>(GetSelf())));
|
||||
thread.detach();
|
||||
}
|
||||
|
||||
Endpoint::Ptr ApiClient::GetEndpoint(void) const
|
||||
{
|
||||
return m_Endpoint;
|
||||
}
|
||||
|
||||
Stream::Ptr ApiClient::GetStream(void) const
|
||||
{
|
||||
return m_Stream;
|
||||
}
|
||||
|
||||
ConnectionRole ApiClient::GetRole(void) const
|
||||
{
|
||||
return m_Role;
|
||||
}
|
||||
|
||||
void ApiClient::SendMessage(const Dictionary::Ptr& message)
|
||||
{
|
||||
try {
|
||||
ObjectLock olock(m_Stream);
|
||||
JsonRpc::SendMessage(m_Stream, message);
|
||||
if (message->Get("method") != "log::SetLogPosition")
|
||||
m_Seen = Utility::GetTime();
|
||||
} catch (const std::exception& ex) {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "Error while sending JSON-RPC message for endpoint '" << m_Endpoint->GetName() << "': " << DiagnosticInformation(ex);
|
||||
Log(LogWarning, "remote", msgbuf.str());
|
||||
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
void ApiClient::Disconnect(void)
|
||||
{
|
||||
Log(LogWarning, "remote", "API client disconnected for endpoint '" + m_Endpoint->GetName() + "'");
|
||||
m_Stream->Close();
|
||||
m_Endpoint->RemoveClient(GetSelf());
|
||||
}
|
||||
|
||||
bool ApiClient::ProcessMessage(void)
|
||||
{
|
||||
Dictionary::Ptr message = JsonRpc::ReadMessage(m_Stream);
|
||||
|
||||
if (!message)
|
||||
return false;
|
||||
|
||||
if (message->Get("method") != "log::SetLogPosition")
|
||||
m_Seen = Utility::GetTime();
|
||||
|
||||
if (message->Contains("ts")) {
|
||||
double ts = message->Get("ts");
|
||||
|
||||
/* ignore old messages */
|
||||
if (ts < m_Endpoint->GetRemoteLogPosition())
|
||||
return true;
|
||||
|
||||
m_Endpoint->SetRemoteLogPosition(ts);
|
||||
}
|
||||
|
||||
MessageOrigin origin;
|
||||
origin.FromClient = GetSelf();
|
||||
|
||||
if (m_Endpoint->GetZone() != Zone::GetLocalZone())
|
||||
origin.FromZone = m_Endpoint->GetZone();
|
||||
else
|
||||
origin.FromZone = Zone::GetByName(message->Get("originZone"));
|
||||
|
||||
String method = message->Get("method");
|
||||
|
||||
Log(LogDebug, "remote", "Received '" + method + "' message from '" + m_Endpoint->GetName() + "'");
|
||||
|
||||
Dictionary::Ptr resultMessage = make_shared<Dictionary>();
|
||||
|
||||
try {
|
||||
ApiFunction::Ptr afunc = ApiFunction::GetByName(method);
|
||||
|
||||
if (!afunc)
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Function '" + method + "' does not exist."));
|
||||
|
||||
resultMessage->Set("result", afunc->Invoke(origin, message->Get("params")));
|
||||
} catch (std::exception& ex) {
|
||||
resultMessage->Set("error", DiagnosticInformation(ex));
|
||||
}
|
||||
|
||||
if (message->Contains("id")) {
|
||||
resultMessage->Set("jsonrpc", "2.0");
|
||||
resultMessage->Set("id", message->Get("id"));
|
||||
JsonRpc::SendMessage(m_Stream, resultMessage);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ApiClient::MessageThreadProc(void)
|
||||
{
|
||||
Utility::SetThreadName("API Client");
|
||||
|
||||
try {
|
||||
while (ProcessMessage())
|
||||
; /* empty loop body */
|
||||
|
||||
Disconnect();
|
||||
} catch (const std::exception& ex) {
|
||||
Log(LogWarning, "remote", "Error while reading JSON-RPC message for endpoint '" + m_Endpoint->GetName() + "': " + DiagnosticInformation(ex));
|
||||
}
|
||||
}
|
||||
|
||||
void ApiClient::KeepAliveTimerHandler(void)
|
||||
{
|
||||
double now = Utility::GetTime();
|
||||
|
||||
BOOST_FOREACH(const Endpoint::Ptr& endpoint, DynamicType::GetObjects<Endpoint>()) {
|
||||
if (endpoint->GetZone() == Zone::GetLocalZone())
|
||||
continue;
|
||||
|
||||
if (endpoint->GetSyncing() || endpoint->GetKeepAlive() <= 0)
|
||||
continue;
|
||||
|
||||
double timeout = now - endpoint->GetKeepAlive();
|
||||
|
||||
BOOST_FOREACH(const ApiClient::Ptr& client, endpoint->GetClients()) {
|
||||
if (client->m_Seen < timeout) {
|
||||
Log(LogInformation, "remote", "Closing connection with inactive endpoint '" + endpoint->GetName() + "'");
|
||||
client->Disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Value SetLogPositionHandler(const MessageOrigin& origin, const Dictionary::Ptr& params)
|
||||
{
|
||||
if (!params)
|
||||
return Empty;
|
||||
|
||||
double log_position = params->Get("log_position");
|
||||
Endpoint::Ptr endpoint = origin.FromClient->GetEndpoint();
|
||||
|
||||
if (log_position > endpoint->GetLocalLogPosition())
|
||||
endpoint->SetLocalLogPosition(log_position);
|
||||
|
||||
return Empty;
|
||||
}
|
@ -17,34 +17,63 @@
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef AGENTCHECKTASK_H
|
||||
#define AGENTCHECKTASK_H
|
||||
#ifndef APICLIENT_H
|
||||
#define APICLIENT_H
|
||||
|
||||
#include "icinga/service.h"
|
||||
#include "remote/endpoint.h"
|
||||
#include "base/stream.h"
|
||||
#include "base/timer.h"
|
||||
#include "base/array.h"
|
||||
#include "remote/i2-remote.h"
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
enum ClientRole
|
||||
{
|
||||
ClientInbound,
|
||||
ClientOutbound
|
||||
};
|
||||
|
||||
/**
|
||||
* Agent check type.
|
||||
* An API client connection.
|
||||
*
|
||||
* @ingroup methods
|
||||
* @ingroup remote
|
||||
*/
|
||||
class AgentCheckTask
|
||||
class I2_REMOTE_API ApiClient : public Object
|
||||
{
|
||||
public:
|
||||
DECLARE_PTR_TYPEDEFS(ApiClient);
|
||||
|
||||
ApiClient(const Endpoint::Ptr& endpoint, const Stream::Ptr& stream, ConnectionRole role);
|
||||
|
||||
static void StaticInitialize(void);
|
||||
static void ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr);
|
||||
|
||||
void Start(void);
|
||||
|
||||
Endpoint::Ptr GetEndpoint(void) const;
|
||||
Stream::Ptr GetStream(void) const;
|
||||
ConnectionRole GetRole(void) const;
|
||||
|
||||
void Disconnect(void);
|
||||
|
||||
void SendMessage(const Dictionary::Ptr& request);
|
||||
|
||||
private:
|
||||
AgentCheckTask(void);
|
||||
|
||||
static void AgentTimerHandler(void);
|
||||
Endpoint::Ptr m_Endpoint;
|
||||
Stream::Ptr m_Stream;
|
||||
ConnectionRole m_Role;
|
||||
double m_Seen;
|
||||
bool m_Syncing;
|
||||
|
||||
static bool SendResult(const Checkable::Ptr& checkable, bool enqueue);
|
||||
bool ProcessMessage(void);
|
||||
void MessageThreadProc(void);
|
||||
|
||||
static Timer::Ptr m_KeepAliveTimer;
|
||||
static void KeepAliveTimerHandler(void);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* AGENTCHECKTASK_H */
|
||||
#endif /* APICLIENT_H */
|
59
lib/remote/apifunction.cpp
Normal file
59
lib/remote/apifunction.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
/******************************************************************************
|
||||
* 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 "remote/apifunction.h"
|
||||
#include "base/registry.h"
|
||||
#include "base/singleton.h"
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
ApiFunction::ApiFunction(const Callback& function)
|
||||
: m_Callback(function)
|
||||
{ }
|
||||
|
||||
Value ApiFunction::Invoke(const MessageOrigin& origin, const Dictionary::Ptr& arguments)
|
||||
{
|
||||
return m_Callback(origin, arguments);
|
||||
}
|
||||
|
||||
RegisterApiFunctionHelper::RegisterApiFunctionHelper(const String& name, const ApiFunction::Callback& function)
|
||||
{
|
||||
ApiFunction::Ptr func = make_shared<ApiFunction>(function);
|
||||
ApiFunctionRegistry::GetInstance()->Register(name, func);
|
||||
}
|
||||
|
||||
ApiFunction::Ptr ApiFunction::GetByName(const String& name)
|
||||
{
|
||||
return ApiFunctionRegistry::GetInstance()->GetItem(name);
|
||||
}
|
||||
|
||||
void ApiFunction::Register(const String& name, const ApiFunction::Ptr& function)
|
||||
{
|
||||
ApiFunctionRegistry::GetInstance()->Register(name, function);
|
||||
}
|
||||
|
||||
void ApiFunction::Unregister(const String& name)
|
||||
{
|
||||
ApiFunctionRegistry::GetInstance()->Unregister(name);
|
||||
}
|
||||
|
||||
ApiFunctionRegistry *ApiFunctionRegistry::GetInstance(void)
|
||||
{
|
||||
return Singleton<ApiFunctionRegistry>::GetInstance();
|
||||
}
|
87
lib/remote/apifunction.h
Normal file
87
lib/remote/apifunction.h
Normal file
@ -0,0 +1,87 @@
|
||||
/******************************************************************************
|
||||
* 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 APIFUNCTION_H
|
||||
#define APIFUNCTION_H
|
||||
|
||||
#include "remote/i2-remote.h"
|
||||
#include "remote/apiclient.h"
|
||||
#include "remote/messageorigin.h"
|
||||
#include "base/registry.h"
|
||||
#include "base/singleton.h"
|
||||
#include "base/value.h"
|
||||
#include "base/dictionary.h"
|
||||
#include <vector>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
/**
|
||||
* An API function.
|
||||
*
|
||||
* @ingroup base
|
||||
*/
|
||||
class I2_REMOTE_API ApiFunction : public Object
|
||||
{
|
||||
public:
|
||||
DECLARE_PTR_TYPEDEFS(ApiFunction);
|
||||
|
||||
typedef boost::function<Value(const MessageOrigin& origin, const Dictionary::Ptr&)> Callback;
|
||||
|
||||
ApiFunction(const Callback& function);
|
||||
|
||||
Value Invoke(const MessageOrigin& origin, const Dictionary::Ptr& arguments);
|
||||
|
||||
static ApiFunction::Ptr GetByName(const String& name);
|
||||
static void Register(const String& name, const ApiFunction::Ptr& function);
|
||||
static void Unregister(const String& name);
|
||||
|
||||
private:
|
||||
Callback m_Callback;
|
||||
};
|
||||
|
||||
/**
|
||||
* A registry for API functions.
|
||||
*
|
||||
* @ingroup base
|
||||
*/
|
||||
class I2_REMOTE_API ApiFunctionRegistry : public Registry<ApiFunctionRegistry, ApiFunction::Ptr>
|
||||
{
|
||||
public:
|
||||
static ApiFunctionRegistry *GetInstance(void);
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper class for registering ApiFunction implementation classes.
|
||||
*
|
||||
* @ingroup base
|
||||
*/
|
||||
class I2_REMOTE_API RegisterApiFunctionHelper
|
||||
{
|
||||
public:
|
||||
RegisterApiFunctionHelper(const String& name, const ApiFunction::Callback& function);
|
||||
};
|
||||
|
||||
#define REGISTER_APIFUNCTION(name, ns, callback) \
|
||||
I2_EXPORT icinga::RegisterApiFunctionHelper g_RegisterAF_ ## name(#ns "::" #name, callback)
|
||||
|
||||
}
|
||||
|
||||
#endif /* APIFUNCTION_H */
|
633
lib/remote/apilistener.cpp
Normal file
633
lib/remote/apilistener.cpp
Normal file
@ -0,0 +1,633 @@
|
||||
/******************************************************************************
|
||||
* 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 "remote/apilistener.h"
|
||||
#include "remote/apiclient.h"
|
||||
#include "remote/endpoint.h"
|
||||
#include "remote/jsonrpc.h"
|
||||
#include "base/convert.h"
|
||||
#include "base/netstring.h"
|
||||
#include "base/dynamictype.h"
|
||||
#include "base/logger_fwd.h"
|
||||
#include "base/objectlock.h"
|
||||
#include "base/stdiostream.h"
|
||||
#include "base/networkstream.h"
|
||||
#include "base/application.h"
|
||||
#include "base/context.h"
|
||||
#include "base/statsfunction.h"
|
||||
#include <fstream>
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_TYPE(ApiListener);
|
||||
|
||||
boost::signals2::signal<void(bool)> ApiListener::OnMasterChanged;
|
||||
|
||||
REGISTER_STATSFUNCTION(ApiListenerStats, &ApiListener::StatsFunc);
|
||||
|
||||
void ApiListener::OnConfigLoaded(void)
|
||||
{
|
||||
/* set up SSL context */
|
||||
shared_ptr<X509> cert = GetX509Certificate(GetCertPath());
|
||||
SetIdentity(GetCertificateCN(cert));
|
||||
Log(LogInformation, "remote", "My API identity: " + GetIdentity());
|
||||
|
||||
m_SSLContext = MakeSSLContext(GetCertPath(), GetKeyPath(), GetCaPath());
|
||||
|
||||
if (!GetCrlPath().IsEmpty())
|
||||
AddCRLToSSLContext(m_SSLContext, GetCrlPath());
|
||||
|
||||
if (!Endpoint::GetByName(GetIdentity()))
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Endpoint object for '" + GetIdentity() + "' is missing."));
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the component.
|
||||
*/
|
||||
void ApiListener::Start(void)
|
||||
{
|
||||
if (std::distance(DynamicType::GetObjects<ApiListener>().first, DynamicType::GetObjects<ApiListener>().second) > 1)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Only one ApiListener object is allowed."));
|
||||
|
||||
DynamicObject::Start();
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock(m_LogLock);
|
||||
RotateLogFile();
|
||||
OpenLogFile();
|
||||
}
|
||||
|
||||
/* create the primary JSON-RPC listener */
|
||||
AddListener(GetBindPort());
|
||||
|
||||
m_Timer = make_shared<Timer>();
|
||||
m_Timer->OnTimerExpired.connect(boost::bind(&ApiListener::ApiTimerHandler, this));
|
||||
m_Timer->SetInterval(5);
|
||||
m_Timer->Start();
|
||||
m_Timer->Reschedule(0);
|
||||
|
||||
OnMasterChanged(true);
|
||||
}
|
||||
|
||||
ApiListener::Ptr ApiListener::GetInstance(void)
|
||||
{
|
||||
BOOST_FOREACH(const ApiListener::Ptr& listener, DynamicType::GetObjects<ApiListener>())
|
||||
return listener;
|
||||
|
||||
return ApiListener::Ptr();
|
||||
}
|
||||
|
||||
shared_ptr<SSL_CTX> ApiListener::GetSSLContext(void) const
|
||||
{
|
||||
return m_SSLContext;
|
||||
}
|
||||
|
||||
Endpoint::Ptr ApiListener::GetMaster(void) const
|
||||
{
|
||||
Zone::Ptr zone = Zone::GetLocalZone();
|
||||
std::vector<String> names;
|
||||
|
||||
BOOST_FOREACH(const Endpoint::Ptr& endpoint, zone->GetEndpoints())
|
||||
if (endpoint->IsConnected() || endpoint->GetName() == GetIdentity())
|
||||
names.push_back(endpoint->GetName());
|
||||
|
||||
std::sort(names.begin(), names.end());
|
||||
|
||||
return Endpoint::GetByName(*names.begin());
|
||||
}
|
||||
|
||||
bool ApiListener::IsMaster(void) const
|
||||
{
|
||||
return GetMaster()->GetName() == GetIdentity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new JSON-RPC listener on the specified port.
|
||||
*
|
||||
* @param service The port to listen on.
|
||||
*/
|
||||
void ApiListener::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(&ApiListener::ListenerThreadProc, this, server));
|
||||
thread.detach();
|
||||
|
||||
m_Servers.insert(server);
|
||||
}
|
||||
|
||||
void ApiListener::ListenerThreadProc(const Socket::Ptr& server)
|
||||
{
|
||||
Utility::SetThreadName("API Listener");
|
||||
|
||||
server->Listen();
|
||||
|
||||
for (;;) {
|
||||
Socket::Ptr client = server->Accept();
|
||||
|
||||
Utility::QueueAsyncCallback(boost::bind(&ApiListener::NewClientHandler, this, client, RoleServer));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ApiListener::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(&ApiListener::NewClientHandler, this, client, RoleClient));
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a new client connection.
|
||||
*
|
||||
* @param client The new client.
|
||||
*/
|
||||
void ApiListener::NewClientHandler(const Socket::Ptr& client, ConnectionRole role)
|
||||
{
|
||||
CONTEXT("Handling new API client connection");
|
||||
|
||||
TlsStream::Ptr tlsStream;
|
||||
|
||||
{
|
||||
ObjectLock olock(this);
|
||||
tlsStream = make_shared<TlsStream>(client, role, m_SSLContext);
|
||||
}
|
||||
|
||||
tlsStream->Handshake();
|
||||
|
||||
shared_ptr<X509> cert = tlsStream->GetPeerCertificate();
|
||||
String identity = GetCertificateCN(cert);
|
||||
|
||||
Endpoint::Ptr endpoint = Endpoint::GetByName(identity);
|
||||
|
||||
if (!endpoint) {
|
||||
Log(LogInformation, "remote", "New client for unknown endpoint '" + identity + "'");
|
||||
return;
|
||||
}
|
||||
|
||||
Log(LogInformation, "remote", "New client connection for identity '" + identity + "'");
|
||||
|
||||
bool need_sync = !endpoint->IsConnected();
|
||||
|
||||
ApiClient::Ptr aclient = make_shared<ApiClient>(endpoint, tlsStream, role);
|
||||
aclient->Start();
|
||||
|
||||
if (need_sync) {
|
||||
{
|
||||
ObjectLock olock(endpoint);
|
||||
|
||||
endpoint->SetSyncing(true);
|
||||
}
|
||||
|
||||
ReplayLog(aclient);
|
||||
}
|
||||
|
||||
endpoint->AddClient(aclient);
|
||||
}
|
||||
|
||||
void ApiListener::ApiTimerHandler(void)
|
||||
{
|
||||
double now = Utility::GetTime();
|
||||
|
||||
std::vector<int> files;
|
||||
Utility::Glob(GetApiDir() + "log/*", boost::bind(&ApiListener::LogGlobHandler, boost::ref(files), _1), GlobFile);
|
||||
std::sort(files.begin(), files.end());
|
||||
|
||||
BOOST_FOREACH(int ts, files) {
|
||||
bool need = false;
|
||||
|
||||
BOOST_FOREACH(const Endpoint::Ptr& endpoint, DynamicType::GetObjects<Endpoint>()) {
|
||||
if (endpoint->GetName() == GetIdentity())
|
||||
continue;
|
||||
|
||||
if (endpoint->GetLogDuration() >= 0 && ts < now - endpoint->GetLogDuration())
|
||||
continue;
|
||||
|
||||
if (ts > endpoint->GetLocalLogPosition()) {
|
||||
need = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!need) {
|
||||
String path = GetApiDir() + "log/" + Convert::ToString(ts);
|
||||
Log(LogInformation, "remote", "Removing old log file: " + path);
|
||||
(void)unlink(path.CStr());
|
||||
}
|
||||
}
|
||||
|
||||
if (IsMaster()) {
|
||||
Zone::Ptr my_zone = Zone::GetLocalZone();
|
||||
|
||||
BOOST_FOREACH(const Endpoint::Ptr& endpoint, DynamicType::GetObjects<Endpoint>()) {
|
||||
if (endpoint->IsConnected() || endpoint->GetName() == GetIdentity())
|
||||
continue;
|
||||
|
||||
if (endpoint->GetHost().IsEmpty() || endpoint->GetPort().IsEmpty())
|
||||
continue;
|
||||
|
||||
Zone::Ptr their_zone = endpoint->GetZone();
|
||||
|
||||
if (my_zone != their_zone && my_zone != their_zone->GetParent() && their_zone != my_zone->GetParent())
|
||||
continue;
|
||||
|
||||
AddConnection(endpoint->GetHost(), endpoint->GetPort());
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const Endpoint::Ptr& endpoint, DynamicType::GetObjects<Endpoint>()) {
|
||||
if (!endpoint->IsConnected())
|
||||
continue;
|
||||
|
||||
double ts = endpoint->GetRemoteLogPosition();
|
||||
|
||||
if (ts == 0)
|
||||
continue;
|
||||
|
||||
Dictionary::Ptr lparams = make_shared<Dictionary>();
|
||||
lparams->Set("log_position", ts);
|
||||
|
||||
Dictionary::Ptr lmessage = make_shared<Dictionary>();
|
||||
lmessage->Set("jsonrpc", "2.0");
|
||||
lmessage->Set("method", "log::SetLogPosition");
|
||||
lmessage->Set("params", lparams);
|
||||
|
||||
BOOST_FOREACH(const ApiClient::Ptr& client, endpoint->GetClients())
|
||||
client->SendMessage(lmessage);
|
||||
|
||||
Log(LogInformation, "remote", "Setting log position for identity '" + endpoint->GetName() + "': " +
|
||||
Utility::FormatDateTime("%Y/%m/%d %H:%M:%S", ts));
|
||||
}
|
||||
|
||||
Log(LogInformation, "remote", "Current master: " + GetMaster()->GetName());
|
||||
|
||||
std::vector<String> names;
|
||||
BOOST_FOREACH(const Endpoint::Ptr& endpoint, DynamicType::GetObjects<Endpoint>())
|
||||
if (endpoint->IsConnected())
|
||||
names.push_back(endpoint->GetName() + " (" + Convert::ToString(endpoint->GetClients().size()) + ")");
|
||||
|
||||
Log(LogInformation, "remote", "Connected endpoints: " + Utility::NaturalJoin(names));
|
||||
}
|
||||
|
||||
void ApiListener::RelayMessage(const MessageOrigin& origin, const DynamicObject::Ptr& secobj, const Dictionary::Ptr& message, bool log)
|
||||
{
|
||||
m_RelayQueue.Enqueue(boost::bind(&ApiListener::SyncRelayMessage, this, origin, secobj, message, log));
|
||||
}
|
||||
|
||||
void ApiListener::PersistMessage(const Dictionary::Ptr& message)
|
||||
{
|
||||
double ts = message->Get("ts");
|
||||
|
||||
ASSERT(ts != 0);
|
||||
|
||||
Dictionary::Ptr pmessage = make_shared<Dictionary>();
|
||||
pmessage->Set("timestamp", ts);
|
||||
|
||||
pmessage->Set("message", JsonSerialize(message));
|
||||
|
||||
boost::mutex::scoped_lock lock(m_LogLock);
|
||||
if (m_LogFile) {
|
||||
NetString::WriteStringToStream(m_LogFile, JsonSerialize(pmessage));
|
||||
m_LogMessageCount++;
|
||||
SetLogMessageTimestamp(ts);
|
||||
|
||||
if (m_LogMessageCount > 50000) {
|
||||
CloseLogFile();
|
||||
RotateLogFile();
|
||||
OpenLogFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ApiListener::SyncRelayMessage(const MessageOrigin& origin, const DynamicObject::Ptr& secobj, const Dictionary::Ptr& message, bool log)
|
||||
{
|
||||
double ts = Utility::GetTime();
|
||||
message->Set("ts", ts);
|
||||
|
||||
Log(LogDebug, "remote", "Relaying '" + message->Get("method") + "' message");
|
||||
|
||||
if (log)
|
||||
m_LogQueue.Enqueue(boost::bind(&ApiListener::PersistMessage, this, message));
|
||||
|
||||
if (origin.FromZone)
|
||||
message->Set("originZone", origin.FromZone->GetName());
|
||||
|
||||
bool is_master = IsMaster();
|
||||
Endpoint::Ptr master = GetMaster();
|
||||
Zone::Ptr my_zone = Zone::GetLocalZone();
|
||||
|
||||
std::vector<Endpoint::Ptr> skippedEndpoints;
|
||||
std::set<Zone::Ptr> finishedZones;
|
||||
|
||||
BOOST_FOREACH(const Endpoint::Ptr& endpoint, DynamicType::GetObjects<Endpoint>()) {
|
||||
/* don't relay messages to ourselves or disconnected endpoints */
|
||||
if (endpoint->GetName() == GetIdentity() || !endpoint->IsConnected())
|
||||
continue;
|
||||
|
||||
Zone::Ptr target_zone = endpoint->GetZone();
|
||||
|
||||
/* don't relay the message to the zone through more than one endpoint */
|
||||
if (finishedZones.find(target_zone) != finishedZones.end()) {
|
||||
skippedEndpoints.push_back(endpoint);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* don't relay messages back to the endpoint which we got the message from */
|
||||
if (origin.FromClient && endpoint == origin.FromClient->GetEndpoint()) {
|
||||
skippedEndpoints.push_back(endpoint);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* don't relay messages back to the zone which we got the message from */
|
||||
if (origin.FromZone && target_zone == origin.FromZone) {
|
||||
skippedEndpoints.push_back(endpoint);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* only relay message to the master if we're not currently the master */
|
||||
if (!is_master && master != endpoint) {
|
||||
skippedEndpoints.push_back(endpoint);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* only relay the message to a) the same zone, b) the parent zone and c) direct child zones */
|
||||
if (target_zone != my_zone && target_zone != my_zone->GetParent() &&
|
||||
secobj->GetZone() != target_zone->GetName()) {
|
||||
skippedEndpoints.push_back(endpoint);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* only relay messages to zones which have access to the object */
|
||||
if (!target_zone->CanAccessObject(secobj))
|
||||
continue;
|
||||
|
||||
finishedZones.insert(target_zone);
|
||||
|
||||
{
|
||||
ObjectLock olock(endpoint);
|
||||
|
||||
if (!endpoint->GetSyncing()) {
|
||||
Log(LogDebug, "remote", "Sending message to '" + endpoint->GetName() + "'");
|
||||
|
||||
BOOST_FOREACH(const ApiClient::Ptr& client, endpoint->GetClients())
|
||||
client->SendMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const Endpoint::Ptr& endpoint, skippedEndpoints)
|
||||
endpoint->SetLocalLogPosition(ts);
|
||||
}
|
||||
|
||||
String ApiListener::GetApiDir(void)
|
||||
{
|
||||
return Application::GetLocalStateDir() + "/lib/icinga2/api/";
|
||||
}
|
||||
|
||||
/* must hold m_LogLock */
|
||||
void ApiListener::OpenLogFile(void)
|
||||
{
|
||||
String path = GetApiDir() + "log/current";
|
||||
|
||||
std::fstream *fp = new std::fstream(path.CStr(), std::fstream::out | std::ofstream::app);
|
||||
|
||||
if (!fp->good()) {
|
||||
Log(LogWarning, "cluster", "Could not open spool file: " + path);
|
||||
return;
|
||||
}
|
||||
|
||||
StdioStream::Ptr logStream = make_shared<StdioStream>(fp, true);
|
||||
#ifdef HAVE_BIOZLIB
|
||||
m_LogFile = make_shared<ZlibStream>(logStream);
|
||||
#else /* HAVE_BIOZLIB */
|
||||
m_LogFile = logStream;
|
||||
#endif /* HAVE_BIOZLIB */
|
||||
m_LogMessageCount = 0;
|
||||
SetLogMessageTimestamp(Utility::GetTime());
|
||||
}
|
||||
|
||||
/* must hold m_LogLock */
|
||||
void ApiListener::CloseLogFile(void)
|
||||
{
|
||||
if (!m_LogFile)
|
||||
return;
|
||||
|
||||
m_LogFile->Close();
|
||||
m_LogFile.reset();
|
||||
}
|
||||
|
||||
/* must hold m_LogLock */
|
||||
void ApiListener::RotateLogFile(void)
|
||||
{
|
||||
double ts = GetLogMessageTimestamp();
|
||||
|
||||
if (ts == 0)
|
||||
ts = Utility::GetTime();
|
||||
|
||||
String oldpath = GetApiDir() + "log/current";
|
||||
String newpath = GetApiDir() + "log/" + Convert::ToString(static_cast<int>(ts)+1);
|
||||
(void) rename(oldpath.CStr(), newpath.CStr());
|
||||
}
|
||||
|
||||
void ApiListener::LogGlobHandler(std::vector<int>& files, const String& file)
|
||||
{
|
||||
String name = Utility::BaseName(file);
|
||||
|
||||
int ts;
|
||||
|
||||
try {
|
||||
ts = Convert::ToLong(name);
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
return;
|
||||
}
|
||||
|
||||
files.push_back(ts);
|
||||
}
|
||||
|
||||
void ApiListener::ReplayLog(const ApiClient::Ptr& client)
|
||||
{
|
||||
Endpoint::Ptr endpoint = client->GetEndpoint();
|
||||
|
||||
CONTEXT("Replaying log for Endpoint '" + endpoint->GetName() + "'");
|
||||
|
||||
int count = -1;
|
||||
double peer_ts = endpoint->GetLocalLogPosition();
|
||||
bool last_sync = false;
|
||||
|
||||
for (;;) {
|
||||
boost::mutex::scoped_lock lock(m_LogLock);
|
||||
|
||||
CloseLogFile();
|
||||
RotateLogFile();
|
||||
|
||||
if (count == -1 || count > 50000) {
|
||||
OpenLogFile();
|
||||
lock.unlock();
|
||||
} else {
|
||||
last_sync = true;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
|
||||
std::vector<int> files;
|
||||
Utility::Glob(GetApiDir() + "log/*", boost::bind(&ApiListener::LogGlobHandler, boost::ref(files), _1), GlobFile);
|
||||
std::sort(files.begin(), files.end());
|
||||
|
||||
BOOST_FOREACH(int ts, files) {
|
||||
String path = GetApiDir() + "log/" + Convert::ToString(ts);
|
||||
|
||||
if (ts < peer_ts)
|
||||
continue;
|
||||
|
||||
Log(LogInformation, "cluster", "Replaying log: " + path);
|
||||
|
||||
std::fstream *fp = new std::fstream(path.CStr(), std::fstream::in);
|
||||
StdioStream::Ptr logStream = make_shared<StdioStream>(fp, true);
|
||||
#ifdef HAVE_BIOZLIB
|
||||
ZlibStream::Ptr lstream = make_shared<ZlibStream>(logStream);
|
||||
#else /* HAVE_BIOZLIB */
|
||||
Stream::Ptr lstream = logStream;
|
||||
#endif /* HAVE_BIOZLIB */
|
||||
|
||||
String message;
|
||||
while (true) {
|
||||
Dictionary::Ptr pmessage;
|
||||
|
||||
try {
|
||||
if (!NetString::ReadStringFromStream(lstream, &message))
|
||||
break;
|
||||
|
||||
pmessage = JsonDeserialize(message);
|
||||
} catch (const std::exception&) {
|
||||
Log(LogWarning, "cluster", "Unexpected end-of-file for cluster log: " + path);
|
||||
|
||||
/* Log files may be incomplete or corrupted. This is perfectly OK. */
|
||||
break;
|
||||
}
|
||||
|
||||
if (pmessage->Get("timestamp") <= peer_ts)
|
||||
continue;
|
||||
|
||||
NetString::WriteStringToStream(client->GetStream(), pmessage->Get("message"));
|
||||
count++;
|
||||
|
||||
peer_ts = pmessage->Get("timestamp");
|
||||
}
|
||||
|
||||
lstream->Close();
|
||||
}
|
||||
|
||||
Log(LogInformation, "cluster", "Replayed " + Convert::ToString(count) + " messages.");
|
||||
|
||||
if (last_sync) {
|
||||
{
|
||||
ObjectLock olock2(endpoint);
|
||||
endpoint->SetSyncing(false);
|
||||
}
|
||||
|
||||
OpenLogFile();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Value ApiListener::StatsFunc(Dictionary::Ptr& status, Dictionary::Ptr& perfdata)
|
||||
{
|
||||
Dictionary::Ptr nodes = make_shared<Dictionary>();
|
||||
std::pair<Dictionary::Ptr, Dictionary::Ptr> stats;
|
||||
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
if (!listener)
|
||||
return 0;
|
||||
|
||||
stats = listener->GetStatus();
|
||||
|
||||
BOOST_FOREACH(Dictionary::Pair const& kv, stats.second)
|
||||
perfdata->Set("api_" + kv.first, kv.second);
|
||||
|
||||
status->Set("api", stats.first);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::pair<Dictionary::Ptr, Dictionary::Ptr> ApiListener::GetStatus(void)
|
||||
{
|
||||
Dictionary::Ptr status = make_shared<Dictionary>();
|
||||
Dictionary::Ptr perfdata = make_shared<Dictionary>();
|
||||
|
||||
/* cluster stats */
|
||||
status->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>()) {
|
||||
if (endpoint->GetName() == GetIdentity())
|
||||
continue;
|
||||
|
||||
count_endpoints++;
|
||||
|
||||
if (!endpoint->IsConnected())
|
||||
not_connected_endpoints->Add(endpoint->GetName());
|
||||
else
|
||||
connected_endpoints->Add(endpoint->GetName());
|
||||
}
|
||||
|
||||
status->Set("num_endpoints", count_endpoints);
|
||||
status->Set("num_conn_endpoints", connected_endpoints->GetLength());
|
||||
status->Set("num_not_conn_endpoints", not_connected_endpoints->GetLength());
|
||||
status->Set("conn_endpoints", connected_endpoints);
|
||||
status->Set("not_conn_endpoints", not_connected_endpoints);
|
||||
|
||||
perfdata->Set("num_endpoints", count_endpoints);
|
||||
perfdata->Set("num_conn_endpoints", Convert::ToDouble(connected_endpoints->GetLength()));
|
||||
perfdata->Set("num_not_conn_endpoints", Convert::ToDouble(not_connected_endpoints->GetLength()));
|
||||
|
||||
return std::make_pair(status, perfdata);
|
||||
}
|
@ -17,61 +17,89 @@
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef AGENTLISTENER_H
|
||||
#define AGENTLISTENER_H
|
||||
#ifndef APILISTENER_H
|
||||
#define APILISTENER_H
|
||||
|
||||
#include "agent/agentlistener.th"
|
||||
#include "remote/apilistener.th"
|
||||
#include "remote/apiclient.h"
|
||||
#include "remote/endpoint.h"
|
||||
#include "remote/zone.h"
|
||||
#include "remote/messageorigin.h"
|
||||
#include "base/dynamicobject.h"
|
||||
#include "base/timer.h"
|
||||
#include "base/array.h"
|
||||
#include "base/workqueue.h"
|
||||
#include "base/tcpsocket.h"
|
||||
#include "base/tlsstream.h"
|
||||
#include "base/utility.h"
|
||||
#include "base/tlsutility.h"
|
||||
#include "icinga/service.h"
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
class ApiClient;
|
||||
|
||||
/**
|
||||
* @ingroup agent
|
||||
*/
|
||||
class AgentListener : public ObjectImpl<AgentListener>
|
||||
* @ingroup remote
|
||||
*/
|
||||
class I2_REMOTE_API ApiListener : public ObjectImpl<ApiListener>
|
||||
{
|
||||
public:
|
||||
DECLARE_PTR_TYPEDEFS(AgentListener);
|
||||
DECLARE_TYPENAME(AgentListener);
|
||||
DECLARE_PTR_TYPEDEFS(ApiListener);
|
||||
DECLARE_TYPENAME(ApiListener);
|
||||
|
||||
virtual void Start(void);
|
||||
static boost::signals2::signal<void(bool)> OnMasterChanged;
|
||||
|
||||
static ApiListener::Ptr GetInstance(void);
|
||||
|
||||
shared_ptr<SSL_CTX> GetSSLContext(void) const;
|
||||
|
||||
double GetAgentSeen(const String& agentIdentity);
|
||||
CheckResult::Ptr GetCheckResult(const String& agentIdentity, const String& hostName, const String& serviceName);
|
||||
Endpoint::Ptr GetMaster(void) const;
|
||||
bool IsMaster(void) const;
|
||||
|
||||
static String GetApiDir(void);
|
||||
|
||||
void RelayMessage(const MessageOrigin& origin, const DynamicObject::Ptr& secobj, const Dictionary::Ptr& message, bool log);
|
||||
|
||||
static Value StatsFunc(Dictionary::Ptr& status, Dictionary::Ptr& perfdata);
|
||||
std::pair<Dictionary::Ptr, Dictionary::Ptr> GetStatus(void);
|
||||
|
||||
protected:
|
||||
virtual void OnConfigLoaded(void);
|
||||
virtual void Start(void);
|
||||
|
||||
private:
|
||||
shared_ptr<SSL_CTX> m_SSLContext;
|
||||
std::set<TcpSocket::Ptr> m_Servers;
|
||||
Timer::Ptr m_Timer;
|
||||
|
||||
Dictionary::Ptr m_Results;
|
||||
|
||||
Timer::Ptr m_AgentTimer;
|
||||
void AgentTimerHandler(void);
|
||||
void ApiTimerHandler(void);
|
||||
|
||||
void AddListener(const String& service);
|
||||
void AddConnection(const String& node, const String& service);
|
||||
|
||||
void NewClientHandler(const Socket::Ptr& client, TlsRole role);
|
||||
void NewClientHandler(const Socket::Ptr& client, ConnectionRole role);
|
||||
void ListenerThreadProc(const Socket::Ptr& server);
|
||||
|
||||
void MessageHandler(const TlsStream::Ptr& sender, const String& identity, const Dictionary::Ptr& message);
|
||||
|
||||
static String GetInventoryDir(void);
|
||||
WorkQueue m_RelayQueue;
|
||||
WorkQueue m_LogQueue;
|
||||
|
||||
friend class AgentCheckTask;
|
||||
boost::mutex m_LogLock;
|
||||
Stream::Ptr m_LogFile;
|
||||
size_t m_LogMessageCount;
|
||||
|
||||
void SyncRelayMessage(const MessageOrigin& origin, const DynamicObject::Ptr& secobj, const Dictionary::Ptr& message, bool log);
|
||||
void PersistMessage(const Dictionary::Ptr& message);
|
||||
|
||||
void OpenLogFile(void);
|
||||
void RotateLogFile(void);
|
||||
void CloseLogFile(void);
|
||||
static void LogGlobHandler(std::vector<int>& files, const String& file);
|
||||
void ReplayLog(const ApiClient::Ptr& client);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* AGENTLISTENER_H */
|
||||
#endif /* APILISTENER_H */
|
@ -1,19 +1,22 @@
|
||||
#include "base/dynamicobject.h"
|
||||
#include "base/application.h"
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
class ClusterListener : DynamicObject
|
||||
class ApiListener : 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] Array::Ptr peers;
|
||||
[config] String bind_port {
|
||||
default {{{ return "5665"; }}}
|
||||
};
|
||||
|
||||
[state] double log_message_timestamp;
|
||||
|
||||
String identity;
|
||||
};
|
||||
|
@ -18,116 +18,100 @@
|
||||
******************************************************************************/
|
||||
|
||||
#include "remote/endpoint.h"
|
||||
#include "remote/apilistener.h"
|
||||
#include "remote/apiclient.h"
|
||||
#include "remote/jsonrpc.h"
|
||||
#include "remote/zone.h"
|
||||
#include "base/application.h"
|
||||
#include "base/dynamictype.h"
|
||||
#include "base/objectlock.h"
|
||||
#include "base/utility.h"
|
||||
#include "base/logger_fwd.h"
|
||||
#include "base/exception.h"
|
||||
#include "config/configitembuilder.h"
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_TYPE(Endpoint);
|
||||
|
||||
boost::signals2::signal<void (const Endpoint::Ptr&)> Endpoint::OnConnected;
|
||||
boost::signals2::signal<void (const Endpoint::Ptr&)> Endpoint::OnDisconnected;
|
||||
boost::signals2::signal<void (const Endpoint::Ptr&, const Dictionary::Ptr&)> Endpoint::OnMessageReceived;
|
||||
boost::signals2::signal<void(const Endpoint::Ptr&, const ApiClient::Ptr&)> Endpoint::OnConnected;
|
||||
boost::signals2::signal<void(const Endpoint::Ptr&, const ApiClient::Ptr&)> Endpoint::OnDisconnected;
|
||||
|
||||
void Endpoint::OnConfigLoaded(void)
|
||||
{
|
||||
DynamicObject::OnConfigLoaded();
|
||||
|
||||
BOOST_FOREACH(const Zone::Ptr& zone, DynamicType::GetObjects<Zone>()) {
|
||||
const std::set<Endpoint::Ptr> members = zone->GetEndpoints();
|
||||
|
||||
if (members.find(GetSelf()) != members.end()) {
|
||||
if (m_Zone)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Endpoint '" + GetName() + "' is in more than one zone."));
|
||||
|
||||
m_Zone = zone;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_Zone)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Endpoint '" + GetName() + "' does not belong to a zone."));
|
||||
}
|
||||
|
||||
void Endpoint::AddClient(const ApiClient::Ptr& client)
|
||||
{
|
||||
bool was_master = ApiListener::GetInstance()->IsMaster();
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_ClientsLock);
|
||||
m_Clients.insert(client);
|
||||
}
|
||||
|
||||
bool is_master = ApiListener::GetInstance()->IsMaster();
|
||||
|
||||
if (was_master != is_master)
|
||||
ApiListener::OnMasterChanged(is_master);
|
||||
|
||||
OnConnected(GetSelf(), client);
|
||||
}
|
||||
|
||||
void Endpoint::RemoveClient(const ApiClient::Ptr& client)
|
||||
{
|
||||
bool was_master = ApiListener::GetInstance()->IsMaster();
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_ClientsLock);
|
||||
m_Clients.erase(client);
|
||||
}
|
||||
|
||||
bool is_master = ApiListener::GetInstance()->IsMaster();
|
||||
|
||||
if (was_master != is_master)
|
||||
ApiListener::OnMasterChanged(is_master);
|
||||
|
||||
OnDisconnected(GetSelf(), client);
|
||||
}
|
||||
|
||||
std::set<ApiClient::Ptr> Endpoint::GetClients(void) const
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_ClientsLock);
|
||||
return m_Clients;
|
||||
}
|
||||
|
||||
Zone::Ptr Endpoint::GetZone(void) const
|
||||
{
|
||||
return m_Zone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this endpoint is connected.
|
||||
*
|
||||
* @returns true if the endpoint is connected, false otherwise.
|
||||
*/
|
||||
bool Endpoint::IsConnected(void) const
|
||||
{
|
||||
return GetClient() != NULL;
|
||||
boost::mutex::scoped_lock lock(m_ClientsLock);
|
||||
return !m_Clients.empty();
|
||||
}
|
||||
|
||||
bool Endpoint::IsAvailable(void) const
|
||||
Endpoint::Ptr Endpoint::GetLocalEndpoint(void)
|
||||
{
|
||||
return GetSeen() > Utility::GetTime() - 30;
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
if (!listener)
|
||||
return Endpoint::Ptr();
|
||||
|
||||
return Endpoint::GetByName(listener->GetIdentity());
|
||||
}
|
||||
|
||||
Stream::Ptr Endpoint::GetClient(void) const
|
||||
{
|
||||
return m_Client;
|
||||
}
|
||||
|
||||
void Endpoint::SetClient(const Stream::Ptr& client)
|
||||
{
|
||||
SetBlockedUntil(Utility::GetTime() + 15);
|
||||
|
||||
if (m_Client)
|
||||
m_Client->Close();
|
||||
|
||||
m_Client = client;
|
||||
|
||||
if (client) {
|
||||
boost::thread thread(boost::bind(&Endpoint::MessageThreadProc, this, client));
|
||||
thread.detach();
|
||||
|
||||
OnConnected(GetSelf());
|
||||
Log(LogInformation, "remote", "Endpoint connected: " + GetName());
|
||||
} else {
|
||||
OnDisconnected(GetSelf());
|
||||
Log(LogInformation, "remote", "Endpoint disconnected: " + GetName());
|
||||
}
|
||||
}
|
||||
|
||||
void Endpoint::SendMessage(const Dictionary::Ptr& message)
|
||||
{
|
||||
Stream::Ptr client = GetClient();
|
||||
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
try {
|
||||
JsonRpc::SendMessage(client, message);
|
||||
} catch (const std::exception& ex) {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "Error while sending JSON-RPC message for endpoint '" << GetName() << "': " << DiagnosticInformation(ex);
|
||||
Log(LogWarning, "remote", msgbuf.str());
|
||||
|
||||
m_Client.reset();
|
||||
|
||||
OnDisconnected(GetSelf());
|
||||
Log(LogWarning, "remote", "Endpoint disconnected: " + GetName());
|
||||
}
|
||||
}
|
||||
|
||||
void Endpoint::MessageThreadProc(const Stream::Ptr& stream)
|
||||
{
|
||||
Utility::SetThreadName("EndpointMsg");
|
||||
|
||||
for (;;) {
|
||||
Dictionary::Ptr message;
|
||||
|
||||
try {
|
||||
message = JsonRpc::ReadMessage(stream);
|
||||
} catch (const std::exception& ex) {
|
||||
Log(LogWarning, "remote", "Error while reading JSON-RPC message for endpoint '" + GetName() + "': " + DiagnosticInformation(ex));
|
||||
|
||||
m_Client.reset();
|
||||
|
||||
OnDisconnected(GetSelf());
|
||||
Log(LogWarning, "remote", "Endpoint disconnected: " + GetName());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
OnMessageReceived(GetSelf(), message);
|
||||
}
|
||||
}
|
||||
|
||||
bool Endpoint::HasFeature(const String& type) const
|
||||
{
|
||||
Dictionary::Ptr features = GetFeatures();
|
||||
|
||||
if (!features)
|
||||
return false;
|
||||
|
||||
return features->Get(type);
|
||||
}
|
||||
|
||||
|
@ -29,12 +29,13 @@
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
class EndpointManager;
|
||||
class ApiClient;
|
||||
class Zone;
|
||||
|
||||
/**
|
||||
* An endpoint that can be used to send and receive messages.
|
||||
*
|
||||
* @ingroup cluster
|
||||
* @ingroup remote
|
||||
*/
|
||||
class I2_REMOTE_API Endpoint : public ObjectImpl<Endpoint>
|
||||
{
|
||||
@ -42,26 +43,26 @@ public:
|
||||
DECLARE_PTR_TYPEDEFS(Endpoint);
|
||||
DECLARE_TYPENAME(Endpoint);
|
||||
|
||||
static boost::signals2::signal<void (const Endpoint::Ptr&)> OnConnected;
|
||||
static boost::signals2::signal<void (const Endpoint::Ptr&)> OnDisconnected;
|
||||
static boost::signals2::signal<void (const Endpoint::Ptr&, const Dictionary::Ptr&)> OnMessageReceived;
|
||||
static boost::signals2::signal<void(const Endpoint::Ptr&, const shared_ptr<ApiClient>&)> OnConnected;
|
||||
static boost::signals2::signal<void(const Endpoint::Ptr&, const shared_ptr<ApiClient>&)> OnDisconnected;
|
||||
|
||||
Stream::Ptr GetClient(void) const;
|
||||
void SetClient(const Stream::Ptr& client);
|
||||
void AddClient(const shared_ptr<ApiClient>& client);
|
||||
void RemoveClient(const shared_ptr<ApiClient>& client);
|
||||
std::set<shared_ptr<ApiClient> > GetClients(void) const;
|
||||
|
||||
shared_ptr<Zone> GetZone(void) const;
|
||||
|
||||
bool IsConnected(void) const;
|
||||
bool IsAvailable(void) const;
|
||||
|
||||
void SendMessage(const Dictionary::Ptr& request);
|
||||
static Endpoint::Ptr GetLocalEndpoint(void);
|
||||
|
||||
bool HasFeature(const String& type) const;
|
||||
protected:
|
||||
virtual void OnConfigLoaded(void);
|
||||
|
||||
private:
|
||||
Stream::Ptr m_Client;
|
||||
boost::thread m_Thread;
|
||||
Array::Ptr m_ConnectedEndpoints;
|
||||
|
||||
void MessageThreadProc(const Stream::Ptr& stream);
|
||||
mutable boost::mutex m_ClientsLock;
|
||||
std::set<shared_ptr<ApiClient> > m_Clients;
|
||||
shared_ptr<Zone> m_Zone;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -6,19 +6,20 @@ namespace icinga
|
||||
class Endpoint : DynamicObject
|
||||
{
|
||||
[config] String host;
|
||||
[config] String port;
|
||||
[config] Array::Ptr config_files;
|
||||
[config] Array::Ptr config_files_recursive;
|
||||
[config] Array::Ptr accept_config;
|
||||
[config] int metric;
|
||||
[config] String port {
|
||||
default {{{ return "5665"; }}}
|
||||
};
|
||||
[config] double keep_alive {
|
||||
default {{{ return 300; }}}
|
||||
};
|
||||
[config] double log_duration {
|
||||
default {{{ return 86400; }}}
|
||||
};
|
||||
|
||||
[state] double seen;
|
||||
[state] double local_log_position;
|
||||
[state] double remote_log_position;
|
||||
[state] Dictionary::Ptr features;
|
||||
|
||||
bool syncing;
|
||||
double blocked_until;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -17,14 +17,16 @@
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#include "icinga/domain.h"
|
||||
#include "base/dynamictype.h"
|
||||
#include "remote/messageorigin.h"
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_TYPE(Domain);
|
||||
|
||||
int Domain::GetPrivileges(const String& instance) const
|
||||
bool MessageOrigin::IsLocal(void) const
|
||||
{
|
||||
return GetAcl()->Get(instance);
|
||||
return !FromClient;
|
||||
}
|
||||
|
||||
bool MessageOrigin::IsSameZone(void) const
|
||||
{
|
||||
return !FromZone;
|
||||
}
|
@ -17,30 +17,27 @@
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef DOMAIN_H
|
||||
#define DOMAIN_H
|
||||
#ifndef MESSAGEORIGIN_H
|
||||
#define MESSAGEORIGIN_H
|
||||
|
||||
#include "icinga/i2-icinga.h"
|
||||
#include "icinga/domain.th"
|
||||
#include "base/dictionary.h"
|
||||
#include "remote/zone.h"
|
||||
#include "remote/apiclient.h"
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
/**
|
||||
* A domain.
|
||||
*
|
||||
* @ingroup icinga
|
||||
* @ingroup remote
|
||||
*/
|
||||
class I2_ICINGA_API Domain : public ObjectImpl<Domain>
|
||||
struct I2_REMOTE_API MessageOrigin
|
||||
{
|
||||
public:
|
||||
DECLARE_PTR_TYPEDEFS(Domain);
|
||||
DECLARE_TYPENAME(Domain);
|
||||
Zone::Ptr FromZone;
|
||||
ApiClient::Ptr FromClient;
|
||||
|
||||
int GetPrivileges(const String& instance) const;
|
||||
bool IsLocal(void) const;
|
||||
bool IsSameZone(void) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* DOMAIN_H */
|
||||
#endif /* MESSAGEORIGIN_H */
|
@ -17,28 +17,34 @@
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
%type Endpoint {
|
||||
%require "host",
|
||||
%attribute %string "host",
|
||||
%type ApiListener {
|
||||
%require "cert_path",
|
||||
%attribute %string "cert_path",
|
||||
|
||||
%require "port",
|
||||
%require "key_path",
|
||||
%attribute %string "key_path",
|
||||
|
||||
%require "ca_path",
|
||||
%attribute %string "ca_path",
|
||||
|
||||
%attribute %string "crl_path",
|
||||
|
||||
%attribute %string "bind_host",
|
||||
%attribute %string "bind_port"
|
||||
}
|
||||
|
||||
%type Endpoint {
|
||||
%attribute %string "host",
|
||||
%attribute %string "port",
|
||||
|
||||
%attribute %number "metric",
|
||||
%attribute %number "keep_alive",
|
||||
%attribute %number "log_duration"
|
||||
}
|
||||
|
||||
%attribute %array "config_files" {
|
||||
%attribute %string "*"
|
||||
},
|
||||
%type Zone {
|
||||
%attribute %name(Zone) "parent",
|
||||
|
||||
%attribute %array "config_files_recursive" {
|
||||
%attribute %string "*",
|
||||
%attribute %dictionary "*" {
|
||||
%attribute %string "path",
|
||||
%attribute %string "pattern"
|
||||
}
|
||||
},
|
||||
|
||||
%attribute %array "accept_config" {
|
||||
%attribute %array "endpoints" {
|
||||
%attribute %name(Endpoint) "*"
|
||||
}
|
||||
}
|
||||
|
@ -17,53 +17,56 @@
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#include "cluster/clusterlink.h"
|
||||
#include "remote/zone.h"
|
||||
#include "base/application.h"
|
||||
#include "base/dynamictype.h"
|
||||
#include "base/objectlock.h"
|
||||
#include "base/utility.h"
|
||||
#include "base/logger_fwd.h"
|
||||
#include "base/exception.h"
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
ClusterLink::ClusterLink(const String& from, const String& to)
|
||||
REGISTER_TYPE(Zone);
|
||||
|
||||
Zone::Ptr Zone::GetParent(void) const
|
||||
{
|
||||
if (from < to) {
|
||||
From = from;
|
||||
To = to;
|
||||
} else {
|
||||
From = to;
|
||||
To = from;
|
||||
}
|
||||
return Zone::GetByName(GetParentRaw());
|
||||
}
|
||||
|
||||
int ClusterLink::GetMetric(void) const
|
||||
std::set<Endpoint::Ptr> Zone::GetEndpoints(void) const
|
||||
{
|
||||
int metric = 0;
|
||||
std::set<Endpoint::Ptr> result;
|
||||
|
||||
Endpoint::Ptr fromEp = Endpoint::GetByName(From);
|
||||
if (fromEp)
|
||||
metric += fromEp->GetMetric();
|
||||
BOOST_FOREACH(const String& endpoint, GetEndpointsRaw())
|
||||
result.insert(Endpoint::GetByName(endpoint));
|
||||
|
||||
Endpoint::Ptr toEp = Endpoint::GetByName(To);
|
||||
if (toEp)
|
||||
metric += toEp->GetMetric();
|
||||
|
||||
return metric;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ClusterLink::operator<(const ClusterLink& other) const
|
||||
bool Zone::CanAccessObject(const DynamicObject::Ptr& object) const
|
||||
{
|
||||
if (From < other.From)
|
||||
return true;
|
||||
Zone::Ptr object_zone;
|
||||
|
||||
if (dynamic_pointer_cast<Zone>(object))
|
||||
object_zone = static_pointer_cast<Zone>(object);
|
||||
else
|
||||
return To < other.To;
|
||||
}
|
||||
Zone::GetByName(object->GetZone());
|
||||
|
||||
bool ClusterLinkMetricLessComparer::operator()(const ClusterLink& a, const ClusterLink& b) const
|
||||
{
|
||||
int metricA = a.GetMetric();
|
||||
int metricB = b.GetMetric();
|
||||
|
||||
if (metricA < metricB)
|
||||
return true;
|
||||
else if (metricB > metricA)
|
||||
if (!object_zone)
|
||||
return false;
|
||||
else
|
||||
return a < b;
|
||||
|
||||
while (object_zone) {
|
||||
if (object_zone.get() == this)
|
||||
return true;
|
||||
|
||||
object_zone = object_zone->GetParent();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Zone::Ptr Zone::GetLocalZone(void)
|
||||
{
|
||||
return Endpoint::GetLocalEndpoint()->GetZone();
|
||||
}
|
@ -17,33 +17,35 @@
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef CLUSTERLINK_H
|
||||
#define CLUSTERLINK_H
|
||||
#ifndef ZONE_H
|
||||
#define ZONE_H
|
||||
|
||||
#include "remote/zone.th"
|
||||
#include "remote/endpoint.h"
|
||||
#include "base/array.h"
|
||||
#include "remote/i2-remote.h"
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
/**
|
||||
* @ingroup cluster
|
||||
* @ingroup remote
|
||||
*/
|
||||
struct ClusterLink
|
||||
class I2_REMOTE_API Zone : public ObjectImpl<Zone>
|
||||
{
|
||||
String From;
|
||||
String To;
|
||||
public:
|
||||
DECLARE_PTR_TYPEDEFS(Zone);
|
||||
DECLARE_TYPENAME(Zone);
|
||||
|
||||
ClusterLink(const String& from, const String& to);
|
||||
Zone::Ptr GetParent(void) const;
|
||||
std::set<Endpoint::Ptr> GetEndpoints(void) const;
|
||||
|
||||
int GetMetric(void) const;
|
||||
bool operator<(const ClusterLink& other) const;
|
||||
};
|
||||
bool CanAccessObject(const DynamicObject::Ptr& object) const;
|
||||
|
||||
struct ClusterLinkMetricLessComparer
|
||||
{
|
||||
bool operator()(const ClusterLink& a, const ClusterLink& b) const;
|
||||
static Zone::Ptr GetLocalZone(void);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* CLUSTERLINK_H */
|
||||
#endif /* ZONE_H */
|
12
lib/remote/zone.ti
Normal file
12
lib/remote/zone.ti
Normal file
@ -0,0 +1,12 @@
|
||||
#include "base/dynamicobject.h"
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
class Zone : DynamicObject
|
||||
{
|
||||
[config] String parent (ParentRaw);
|
||||
[config] Array::Ptr endpoints (EndpointsRaw);
|
||||
};
|
||||
|
||||
}
|
@ -60,6 +60,8 @@ static void Callback(int *counter)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(invoke)
|
||||
{
|
||||
Utility::Sleep(5);
|
||||
|
||||
int counter;
|
||||
Timer::Ptr timer = make_shared<Timer>();
|
||||
timer->OnTimerExpired.connect(boost::bind(&Callback, &counter));
|
||||
|
@ -20,5 +20,17 @@
|
||||
#define BOOST_TEST_MAIN
|
||||
#define BOOST_TEST_MODULE icinga2_test
|
||||
|
||||
#include "base/application.h"
|
||||
#include <BoostTestTargetConfig.h>
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
struct InitLibBase
|
||||
{
|
||||
InitLibBase(void)
|
||||
{
|
||||
Application::InitializeBase();
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_GLOBAL_FIXTURE(InitLibBase);
|
||||
|
Loading…
x
Reference in New Issue
Block a user