diff --git a/lib/redis/rediswriter-objects.cpp b/lib/redis/rediswriter-objects.cpp index 58876ca23..b810029d6 100644 --- a/lib/redis/rediswriter-objects.cpp +++ b/lib/redis/rediswriter-objects.cpp @@ -92,17 +92,25 @@ void RedisWriter::UpdateAllConfigObjects() { String lcType = type.second; m_Rcon->ExecuteQuery( - {"DEL", m_PrefixConfigCheckSum + lcType, m_PrefixConfigObject + lcType, m_PrefixStatusObject + lcType}); + {"DEL", m_PrefixConfigCheckSum + lcType, m_PrefixConfigObject + lcType, m_PrefixStateObject + lcType}); size_t bulkCounter = 0; - auto attributes = std::vector({"HMSET", m_PrefixConfigObject + lcType}); - auto customVars = std::vector({"HMSET", m_PrefixConfigCustomVar + lcType}); - auto checksums = std::vector({"HMSET", m_PrefixConfigCheckSum + lcType}); + std::vector attributes = {"HMSET", m_PrefixConfigObject + lcType}; + std::vector customVars = {"HMSET", m_PrefixConfigCustomVar + lcType}; + std::vector checksums = {"HMSET", m_PrefixConfigCheckSum + lcType}; + std::vector states = {"HMSET", m_PrefixStateObject + lcType }; + bool dumpState = (lcType == "host" || lcType == "service"); for (const ConfigObject::Ptr& object : type.first->GetObjects()) { if (lcType != GetLowerCaseTypeNameDB(object)) continue; CreateConfigUpdate(object, lcType, attributes, customVars, checksums, false); - SendStatusUpdate(object); + + // Write out inital state for checkables + if (dumpState) { + states.emplace_back(GetObjectIdentifier(object)); + states.emplace_back(JsonEncode(SerializeState(dynamic_pointer_cast(object)))); + } + bulkCounter++; if (!bulkCounter % 100) { if (attributes.size() > 2) { @@ -117,13 +125,10 @@ void RedisWriter::UpdateAllConfigObjects() m_Rcon->ExecuteQuery(checksums); checksums.erase(checksums.begin() + 2, checksums.end()); } - } - - if (lcType == "host" || lcType == "service") { - Dictionary::Ptr objectAttrs = SerializeState(object); - - m_Rcon->ExecuteQuery({"HSET", "icinga:status:object:" + lcType, GetObjectIdentifier(object), - JsonEncode(objectAttrs)}); + if (states.size() > 2) { + m_Rcon->ExecuteQuery(states); + states.erase(states.begin() + 2, states.end()); + } } } if (attributes.size() > 2) @@ -132,6 +137,8 @@ void RedisWriter::UpdateAllConfigObjects() m_Rcon->ExecuteQuery(customVars); if (checksums.size() > 2) m_Rcon->ExecuteQuery(checksums); + if (states.size() > 2) + m_Rcon->ExecuteQuery(states); m_Rcon->ExecuteQuery({"PUBLISH", "icinga:config:dump", lcType}); @@ -152,6 +159,12 @@ void RedisWriter::UpdateAllConfigObjects() << "Initial config/status dump finished in " << Utility::GetTime() - startTime << " seconds."; } +void RedisWriter::UpdateState(const Checkable::Ptr& checkable) { + Dictionary::Ptr stateAttrs = SerializeState(checkable); + + m_Rcon->ExecuteQuery({"HSET", m_PrefixStateObject + GetLowerCaseTypeNameDB(checkable), GetObjectIdentifier(checkable), JsonEncode(stateAttrs)}); +} + template static ConfigObject::Ptr GetObjectByName(const String& name) { @@ -166,15 +179,23 @@ void RedisWriter::SendConfigUpdate(const ConfigObject::Ptr& object, bool runtime String typeName = GetLowerCaseTypeNameDB(object); - auto attributes = std::vector({"HMSET", m_PrefixConfigObject + typeName}); - auto customVars = std::vector({"HMSET", m_PrefixConfigCustomVar + typeName}); - auto checksums = std::vector({"HMSET", m_PrefixConfigCheckSum + typeName}); + std::vector attribute = {"HSET", m_PrefixConfigObject + typeName}; + std::vector customVar = {"HSET", m_PrefixConfigCustomVar + typeName}; + std::vector checksum = {"HSET", m_PrefixConfigCheckSum + typeName}; + std::vector state = {"HSET", m_PrefixStateObject + typeName}; - CreateConfigUpdate(object, typeName, attributes, customVars, checksums, runtimeUpdate); - m_Rcon->ExecuteQuery(attributes); - m_Rcon->ExecuteQuery(customVars); - m_Rcon->ExecuteQuery(checksums); + CreateConfigUpdate(object, typeName, attribute, customVar, checksum, runtimeUpdate); + Checkable::Ptr checkable = dynamic_pointer_cast(object); + if (checkable) { + m_Rcon->ExecuteQuery({"HSET", m_PrefixStateObject + typeName, + GetObjectIdentifier(checkable), JsonEncode(SerializeState(checkable))}); + } + + m_Rcon->ExecuteQuery(attribute); + m_Rcon->ExecuteQuery(checksum); + if (customVar.size() > 2) + m_Rcon->ExecuteQuery(customVar); } void RedisWriter::MakeTypeChecksums(const ConfigObject::Ptr& object, std::set& propertiesBlacklist, @@ -564,8 +585,8 @@ void RedisWriter::SendConfigDelete(const ConfigObject::Ptr& object) m_Rcon->ExecuteQueries({ {"HDEL", m_PrefixConfigObject + typeName, objectKey}, - {"DEL", m_PrefixStatusObject + typeName + ":" + objectKey}, - {"PUBLISH", "icinga:config:delete", typeName + ":" + objectKey} + {"DEL", m_PrefixStateObject + typeName + ":" + objectKey}, + {"PUBLISH", "icinga:config:delete", typeName + ":" + objectKey} }); } @@ -586,7 +607,7 @@ void RedisWriter::SendStatusUpdate(const ConfigObject::Ptr& object) else streamname = "icinga:state:stream:host"; - Dictionary::Ptr objectAttrs = SerializeState(object); + Dictionary::Ptr objectAttrs = SerializeState(checkable); std::vector streamadd({"XADD", streamname, "*"}); ObjectLock olock(objectAttrs); @@ -598,39 +619,28 @@ void RedisWriter::SendStatusUpdate(const ConfigObject::Ptr& object) m_Rcon->ExecuteQuery(streamadd); } -Dictionary::Ptr RedisWriter::SerializeState(const Object::Ptr& object) +Dictionary::Ptr RedisWriter::SerializeState(const Checkable::Ptr& checkable) { Dictionary::Ptr attrs = new Dictionary(); - Checkable::Ptr checkable = dynamic_pointer_cast(object); - if (!checkable) - return nullptr; - - bool isHost; - Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); - if (service) - isHost = false; - else - isHost = true; - attrs->Set("id", GetObjectIdentifier(checkable));; attrs->Set("env_id", CalculateCheckSumString(GetEnvironment())); attrs->Set("state_type", checkable->GetStateType()); - if (isHost) - attrs->Set("state", host->GetState()); - else + if (service) attrs->Set("state", service->GetState()); - - if (isHost) - attrs->Set("last_hard_state", host->GetLastHardState()); else + attrs->Set("state", host->GetState()); + + if (service) attrs->Set("last_hard_state", service->GetLastHardState()); + else + attrs->Set("last_hard_state", host->GetLastHardState()); attrs->Set("check_attempt", checkable->GetCheckAttempt()); @@ -655,11 +665,12 @@ Dictionary::Ptr RedisWriter::SerializeState(const Object::Ptr& object) attrs->Set("is_problem", isProblem); bool isHandledNoDependency = isProblem && checkable->IsInDowntime() && checkable->IsAcknowledged(); - if (isHost) - attrs->Set("is_handled", isHandledNoDependency); - else + if (service) attrs->Set("is_handled", isHandledNoDependency && !checkable->IsStateOK(service->GetHost()->GetStateRaw())); + else + attrs->Set("is_handled", isHandledNoDependency); + attrs->Set("is_reachable", checkable->IsReachable()); attrs->Set("is_flapping", checkable->IsFlapping()); attrs->Set("is_acknowledged", checkable->IsAcknowledged()); diff --git a/lib/redis/rediswriter.cpp b/lib/redis/rediswriter.cpp index 41fe0d048..b9a6cc891 100644 --- a/lib/redis/rediswriter.cpp +++ b/lib/redis/rediswriter.cpp @@ -45,7 +45,7 @@ RedisWriter::RedisWriter() m_PrefixConfigObject = "icinga:config:object:"; m_PrefixConfigCheckSum = "icinga:config:checksum:"; m_PrefixConfigCustomVar = "icinga:config:customvar:"; - m_PrefixStatusObject = "icinga:status:object:"; + m_PrefixStateObject = "icinga:state:object:"; } /** @@ -307,6 +307,18 @@ void RedisWriter::SendEvent(const Dictionary::Ptr& event) return; String type = event->Get("type"); + + if (type == "CheckResult") { + Checkable::Ptr checkable; + if (event->Contains("service")) { + checkable = Service::GetByNamePair(event->Get("host"), event->Get("service")); + } else { + checkable = Host::GetByName(event->Get("host")); + } + // Update State for icingaweb + m_WorkQueue.Enqueue(std::bind(&RedisWriter::UpdateState, this, checkable)); + } + if (type.Contains("Acknowledgement")) { Checkable::Ptr checkable; diff --git a/lib/redis/rediswriter.hpp b/lib/redis/rediswriter.hpp index 5f07c652e..01e7dd35b 100644 --- a/lib/redis/rediswriter.hpp +++ b/lib/redis/rediswriter.hpp @@ -26,6 +26,7 @@ #include "base/timer.hpp" #include "base/workqueue.hpp" #include "redis/redisconnection.hpp" +#include "icinga/checkable.hpp" #include namespace icinga @@ -67,13 +68,14 @@ private: /* config & status dump */ void UpdateAllConfigObjects(); + void UpdateState(const Checkable::Ptr& checkable); void SendConfigUpdate(const ConfigObject::Ptr& object, bool runtimeUpdate); void CreateConfigUpdate(const ConfigObject::Ptr& object, const String type, std::vector& attributes, std::vector& customVars, std::vector& checksums, bool runtimeUpdate); void SendConfigDelete(const ConfigObject::Ptr& object); void SendStatusUpdate(const ConfigObject::Ptr& object); std::vector UpdateObjectAttrs(const ConfigObject::Ptr& object, int fieldType, const String& typeNameOverride); - Dictionary::Ptr SerializeState(const Object::Ptr& object); + Dictionary::Ptr SerializeState(const Checkable::Ptr& checkable); /* Stats */ Dictionary::Ptr GetStats(); @@ -119,7 +121,7 @@ private: String m_PrefixConfigObject; String m_PrefixConfigCheckSum; String m_PrefixConfigCustomVar; - String m_PrefixStatusObject; + String m_PrefixStateObject; bool m_ConfigDumpInProgress; bool m_ConfigDumpDone;