2019-11-02 14:00:06 +01:00
|
|
|
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
|
2017-09-25 14:41:43 +02:00
|
|
|
|
2019-10-29 18:36:16 +01:00
|
|
|
#include "icingadb/icingadb.hpp"
|
|
|
|
#include "icingadb/icingadb-ti.cpp"
|
|
|
|
#include "icingadb/redisconnection.hpp"
|
2017-09-25 14:41:43 +02:00
|
|
|
#include "remote/eventqueue.hpp"
|
|
|
|
#include "base/json.hpp"
|
2018-10-30 16:00:41 +01:00
|
|
|
#include "icinga/checkable.hpp"
|
|
|
|
#include "icinga/host.hpp"
|
2017-10-12 17:46:06 +02:00
|
|
|
#include <boost/algorithm/string.hpp>
|
2019-11-02 18:01:31 +01:00
|
|
|
#include <memory>
|
2019-06-28 11:56:15 +02:00
|
|
|
#include <utility>
|
2017-09-25 14:41:43 +02:00
|
|
|
|
|
|
|
using namespace icinga;
|
|
|
|
|
2017-10-12 17:46:06 +02:00
|
|
|
#define MAX_EVENTS_DEFAULT 5000
|
2017-10-11 14:19:42 +02:00
|
|
|
|
2019-11-27 11:08:22 +01:00
|
|
|
using Prio = RedisConnection::QueryPriority;
|
|
|
|
|
2019-12-02 18:06:07 +01:00
|
|
|
static const char * const l_LuaPublishStats = R"EOF(
|
|
|
|
|
|
|
|
local xa = {'XADD', KEYS[1], '*'}
|
|
|
|
|
|
|
|
for i = 1, #ARGV do
|
|
|
|
table.insert(xa, ARGV[i])
|
|
|
|
end
|
|
|
|
|
|
|
|
local id = redis.call(unpack(xa))
|
|
|
|
|
|
|
|
local xr = redis.call('XRANGE', KEYS[1], '-', '+')
|
|
|
|
for i = 1, #xr - 1 do
|
|
|
|
redis.call('XDEL', KEYS[1], xr[i][1])
|
|
|
|
end
|
|
|
|
|
|
|
|
return id
|
|
|
|
|
|
|
|
)EOF";
|
|
|
|
|
2019-10-29 17:32:29 +01:00
|
|
|
REGISTER_TYPE(IcingaDB);
|
2017-09-25 14:41:43 +02:00
|
|
|
|
2019-10-29 17:32:29 +01:00
|
|
|
IcingaDB::IcingaDB()
|
2019-11-02 18:01:31 +01:00
|
|
|
: m_Rcon(nullptr)
|
2017-10-12 11:47:49 +02:00
|
|
|
{
|
2018-10-18 14:39:59 +02:00
|
|
|
m_Rcon = nullptr;
|
|
|
|
|
2019-10-29 17:32:29 +01:00
|
|
|
m_WorkQueue.SetName("IcingaDB");
|
2018-07-10 11:09:37 +02:00
|
|
|
|
2019-06-14 11:52:34 +02:00
|
|
|
m_PrefixConfigObject = "icinga:config:";
|
|
|
|
m_PrefixConfigCheckSum = "icinga:checksum:";
|
2019-09-17 11:20:52 +02:00
|
|
|
m_PrefixStateObject = "icinga:config:state:";
|
2017-10-12 11:47:49 +02:00
|
|
|
}
|
2017-09-25 14:41:43 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Starts the component.
|
|
|
|
*/
|
2019-10-29 17:32:29 +01:00
|
|
|
void IcingaDB::Start(bool runtimeCreated)
|
2017-09-25 14:41:43 +02:00
|
|
|
{
|
2019-10-29 17:32:29 +01:00
|
|
|
ObjectImpl<IcingaDB>::Start(runtimeCreated);
|
2017-09-25 14:41:43 +02:00
|
|
|
|
2019-10-29 17:32:29 +01:00
|
|
|
Log(LogInformation, "IcingaDB")
|
2018-05-15 14:43:01 +02:00
|
|
|
<< "'" << GetName() << "' started.";
|
2017-09-25 14:41:43 +02:00
|
|
|
|
|
|
|
m_ConfigDumpInProgress = false;
|
2018-10-18 14:39:59 +02:00
|
|
|
m_ConfigDumpDone = false;
|
|
|
|
|
|
|
|
m_Rcon = new RedisConnection(GetHost(), GetPort(), GetPath(), GetPassword(), GetDbIndex());
|
|
|
|
m_Rcon->Start();
|
2017-09-25 14:41:43 +02:00
|
|
|
|
2019-06-28 11:56:15 +02:00
|
|
|
m_WorkQueue.SetExceptionCallback([this](boost::exception_ptr exp) { ExceptionHandler(std::move(exp)); });
|
2017-09-25 14:41:43 +02:00
|
|
|
|
|
|
|
m_ReconnectTimer = new Timer();
|
|
|
|
m_ReconnectTimer->SetInterval(15);
|
2019-06-28 11:56:15 +02:00
|
|
|
m_ReconnectTimer->OnTimerExpired.connect([this](const Timer * const&) { ReconnectTimerHandler(); });
|
2017-09-25 14:41:43 +02:00
|
|
|
m_ReconnectTimer->Start();
|
|
|
|
m_ReconnectTimer->Reschedule(0);
|
|
|
|
|
|
|
|
m_StatsTimer = new Timer();
|
2019-05-13 11:37:54 +02:00
|
|
|
m_StatsTimer->SetInterval(1);
|
2019-06-28 11:56:15 +02:00
|
|
|
m_StatsTimer->OnTimerExpired.connect([this](const Timer * const&) { PublishStatsTimerHandler(); });
|
2017-09-25 14:41:43 +02:00
|
|
|
m_StatsTimer->Start();
|
|
|
|
|
2019-10-29 17:32:29 +01:00
|
|
|
m_WorkQueue.SetName("IcingaDB");
|
2017-10-02 09:59:11 +02:00
|
|
|
|
2019-12-17 16:41:34 +01:00
|
|
|
m_Rcon->SuppressQueryKind(Prio::CheckResult);
|
|
|
|
m_Rcon->SuppressQueryKind(Prio::State);
|
2017-09-25 14:41:43 +02:00
|
|
|
}
|
|
|
|
|
2019-10-29 17:32:29 +01:00
|
|
|
void IcingaDB::ExceptionHandler(boost::exception_ptr exp)
|
2017-09-25 14:41:43 +02:00
|
|
|
{
|
2019-10-29 17:32:29 +01:00
|
|
|
Log(LogCritical, "IcingaDB", "Exception during redis query. Verify that Redis is operational.");
|
2017-09-25 14:41:43 +02:00
|
|
|
|
2019-10-29 17:32:29 +01:00
|
|
|
Log(LogDebug, "IcingaDB")
|
2018-05-15 14:43:01 +02:00
|
|
|
<< "Exception during redis operation: " << DiagnosticInformation(exp);
|
2017-09-25 14:41:43 +02:00
|
|
|
}
|
|
|
|
|
2019-10-29 17:32:29 +01:00
|
|
|
void IcingaDB::ReconnectTimerHandler()
|
2017-09-25 14:41:43 +02:00
|
|
|
{
|
2019-06-28 11:56:15 +02:00
|
|
|
m_WorkQueue.Enqueue([this]() { TryToReconnect(); });
|
2017-09-25 14:41:43 +02:00
|
|
|
}
|
|
|
|
|
2019-10-29 17:32:29 +01:00
|
|
|
void IcingaDB::TryToReconnect()
|
2017-09-25 14:41:43 +02:00
|
|
|
{
|
|
|
|
AssertOnWorkQueue();
|
|
|
|
|
2018-10-25 17:48:32 +02:00
|
|
|
if (m_ConfigDumpDone)
|
2017-09-25 14:41:43 +02:00
|
|
|
return;
|
2018-10-25 17:48:32 +02:00
|
|
|
else
|
2018-10-18 14:39:59 +02:00
|
|
|
m_Rcon->Start();
|
2017-09-25 14:41:43 +02:00
|
|
|
|
2018-11-26 13:34:05 +01:00
|
|
|
if (!m_Rcon || !m_Rcon->IsConnected())
|
2018-10-25 17:48:32 +02:00
|
|
|
return;
|
2018-10-26 14:07:07 +02:00
|
|
|
|
2018-10-18 14:39:59 +02:00
|
|
|
if (m_ConfigDumpInProgress || m_ConfigDumpDone)
|
2017-09-25 14:41:43 +02:00
|
|
|
return;
|
2017-10-12 11:47:49 +02:00
|
|
|
|
2017-09-25 14:41:43 +02:00
|
|
|
/* Config dump */
|
|
|
|
m_ConfigDumpInProgress = true;
|
2019-01-28 15:19:10 +01:00
|
|
|
PublishStats();
|
2017-09-25 14:41:43 +02:00
|
|
|
|
|
|
|
UpdateAllConfigObjects();
|
|
|
|
|
2018-10-18 14:39:59 +02:00
|
|
|
m_ConfigDumpDone = true;
|
|
|
|
|
2017-09-25 14:41:43 +02:00
|
|
|
m_ConfigDumpInProgress = false;
|
|
|
|
}
|
|
|
|
|
2019-10-29 17:32:29 +01:00
|
|
|
void IcingaDB::PublishStatsTimerHandler(void)
|
2017-09-25 14:41:43 +02:00
|
|
|
{
|
2020-05-15 11:17:25 +02:00
|
|
|
PublishStats();
|
2017-09-25 14:41:43 +02:00
|
|
|
}
|
|
|
|
|
2019-10-29 17:32:29 +01:00
|
|
|
void IcingaDB::PublishStats()
|
2017-09-25 14:41:43 +02:00
|
|
|
{
|
2018-11-26 13:34:05 +01:00
|
|
|
if (!m_Rcon || !m_Rcon->IsConnected())
|
2018-10-26 14:07:07 +02:00
|
|
|
return;
|
|
|
|
|
2018-06-08 11:38:36 +02:00
|
|
|
Dictionary::Ptr status = GetStats();
|
2019-01-28 15:19:10 +01:00
|
|
|
status->Set("config_dump_in_progress", m_ConfigDumpInProgress);
|
2019-12-05 10:32:15 +01:00
|
|
|
status->Set("timestamp", TimestampToMilliseconds(Utility::GetTime()));
|
2017-09-25 14:41:43 +02:00
|
|
|
|
2019-12-02 18:06:07 +01:00
|
|
|
std::vector<String> eval ({"EVAL", l_LuaPublishStats, "1", "icinga:stats"});
|
|
|
|
|
|
|
|
{
|
|
|
|
ObjectLock statusLock (status);
|
|
|
|
for (auto& kv : status) {
|
|
|
|
eval.emplace_back(kv.first);
|
|
|
|
eval.emplace_back(JsonEncode(kv.second));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_Rcon->FireAndForgetQuery(std::move(eval), Prio::Heartbeat);
|
2017-09-25 14:41:43 +02:00
|
|
|
}
|
|
|
|
|
2019-10-29 17:32:29 +01:00
|
|
|
void IcingaDB::Stop(bool runtimeRemoved)
|
2017-09-25 14:41:43 +02:00
|
|
|
{
|
2019-10-29 17:32:29 +01:00
|
|
|
Log(LogInformation, "IcingaDB")
|
2018-05-15 14:43:01 +02:00
|
|
|
<< "'" << GetName() << "' stopped.";
|
2017-09-25 14:41:43 +02:00
|
|
|
|
2019-10-29 17:32:29 +01:00
|
|
|
ObjectImpl<IcingaDB>::Stop(runtimeRemoved);
|
2017-09-25 14:41:43 +02:00
|
|
|
}
|
|
|
|
|
2019-10-29 17:32:29 +01:00
|
|
|
void IcingaDB::AssertOnWorkQueue()
|
2017-09-25 14:41:43 +02:00
|
|
|
{
|
|
|
|
ASSERT(m_WorkQueue.IsWorkerThread());
|
|
|
|
}
|