diff --git a/lib/icingadb/icingadb-objects.cpp b/lib/icingadb/icingadb-objects.cpp index 920251969..e46012ba1 100644 --- a/lib/icingadb/icingadb-objects.cpp +++ b/lib/icingadb/icingadb-objects.cpp @@ -19,6 +19,7 @@ #include "icinga/command.hpp" #include "icinga/compatutility.hpp" #include "icinga/customvarobject.hpp" +#include "icinga/dependency.hpp" #include "icinga/host.hpp" #include "icinga/service.hpp" #include "icinga/hostgroup.hpp" @@ -61,6 +62,7 @@ std::vector IcingaDB::GetTypes() // Then sync them for similar reasons. Downtime::TypeInstance, Comment::TypeInstance, + Dependency::TypeInstance, HostGroup::TypeInstance, ServiceGroup::TypeInstance, @@ -791,6 +793,137 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S return; } + if (type == Dependency::TypeInstance) { + auto& dependencyNodes (hMSets[m_PrefixConfigObject + "dependency:node"]); + auto& dependencyEdges (hMSets[m_PrefixConfigObject + "dependency:edge"]); + auto& redundancyGroups (hMSets[m_PrefixConfigObject + "redundancygroup"]); + + Dependency::Ptr dependency = static_pointer_cast(object); + + Host::Ptr parentHost, childHost; + Service::Ptr parentService, childService; + tie(parentHost, parentService) = GetHostService(dependency->GetParent()); + tie(childHost, childService) = GetHostService(dependency->GetChild()); + String redundancyGroup = dependency->GetRedundancyGroup(); + + String redundancyGroupId, dependencyNodeParentId, dependencyNodeChildId, dependencyNodeReduId; + + Dictionary::Ptr parentNodeData, childNodeData; + + if (parentService) { + dependencyNodeParentId = HashValue(new Array({ + m_EnvironmentId, + GetObjectIdentifier(parentHost), + GetObjectIdentifier(parentService)})); + parentNodeData = new Dictionary({ + {"environment_id", m_EnvironmentId}, + {"host_id", GetObjectIdentifier(parentHost)}, + {"service_id", GetObjectIdentifier(parentService)}}); + + m_CheckablesToDependencies->Set(GetObjectIdentifier(parentService), dependency); + } else { + dependencyNodeParentId = HashValue(new Array({ + m_EnvironmentId, + GetObjectIdentifier(parentHost)})); + parentNodeData = new Dictionary({ + {"environment_id", m_EnvironmentId}, + {"host_id", GetObjectIdentifier(parentHost)}}); + + m_CheckablesToDependencies->Set(GetObjectIdentifier(parentHost), dependency); + } + + if (childService) { + dependencyNodeChildId = HashValue(new Array({ + m_EnvironmentId, + GetObjectIdentifier(childHost), + GetObjectIdentifier(childService)})); + childNodeData = new Dictionary({ + {"environment_id", m_EnvironmentId}, + {"host_id", GetObjectIdentifier(childHost)}, + {"service_id", GetObjectIdentifier(childService)}}); + + m_CheckablesToDependencies->Set(GetObjectIdentifier(childService), dependency); + } else { + dependencyNodeChildId = HashValue(new Array({ + m_EnvironmentId, + GetObjectIdentifier(childHost)})); + childNodeData = new Dictionary({ + {"environment_id", m_EnvironmentId}, + {"host_id", GetObjectIdentifier(childHost)}}); + + m_CheckablesToDependencies->Set(GetObjectIdentifier(childHost), dependency); + } + + dependencyNodes.emplace_back(dependencyNodeParentId); + dependencyNodes.emplace_back(JsonEncode(parentNodeData)); + dependencyNodes.emplace_back(dependencyNodeChildId); + dependencyNodes.emplace_back(JsonEncode(childNodeData)); + + if (runtimeUpdate) { + AddObjectDataToRuntimeUpdates(runtimeUpdates, dependencyNodeParentId, m_PrefixConfigObject + "dependency:node", parentNodeData); + AddObjectDataToRuntimeUpdates(runtimeUpdates, dependencyNodeChildId, m_PrefixConfigObject + "dependency:node", childNodeData); + } + + if (!redundancyGroup.IsEmpty()) { + /* TODO: name should be suffixed with names of all children. + * however, at this point I don't have this information, + * only the direct neighbors. + */ + redundancyGroupId = HashValue(new Array({m_EnvironmentId, redundancyGroup, dependencyNodeChildId})); + dependencyNodeReduId = redundancyGroupId; + + redundancyGroups.emplace_back(redundancyGroupId); + Dictionary::Ptr groupData = new Dictionary({ + {"environment_id", m_EnvironmentId}, + {"name", redundancyGroupId}, + {"display_name", redundancyGroup}}); + redundancyGroups.emplace_back(JsonEncode(groupData)); + + dependencyNodes.emplace_back(dependencyNodeReduId); + Dictionary::Ptr reduNodeData = new Dictionary({ + {"environment_id", m_EnvironmentId}, + {"redundancy_group_id", redundancyGroupId}}); + dependencyNodes.emplace_back(JsonEncode(reduNodeData)); + + String edgeInId = HashValue(new Array({m_EnvironmentId, dependencyNodeChildId, dependencyNodeReduId})); + dependencyEdges.emplace_back(edgeInId); + Dictionary::Ptr edgeInData = new Dictionary({ + {"environment_id", m_EnvironmentId}, + {"from_node_id", dependencyNodeChildId}, + {"to_node_id", dependencyNodeReduId}}); + dependencyEdges.emplace_back(JsonEncode(edgeInData)); + + String edgeOutId = HashValue(new Array({m_EnvironmentId, dependencyNodeReduId, dependencyNodeParentId})); + dependencyEdges.emplace_back(edgeOutId); + Dictionary::Ptr edgeOutData = new Dictionary({ + {"environment_id", m_EnvironmentId}, + {"from_node_id", dependencyNodeReduId}, + {"to_node_id", dependencyNodeParentId}, + {"dependency_id", GetObjectIdentifier(dependency)}}); + dependencyEdges.emplace_back(JsonEncode(edgeOutData)); + + if (runtimeUpdate) { + AddObjectDataToRuntimeUpdates(runtimeUpdates, redundancyGroupId, m_PrefixConfigObject + "redundancygroup", groupData); + AddObjectDataToRuntimeUpdates(runtimeUpdates, dependencyNodeReduId, m_PrefixConfigObject + "dependency:node", reduNodeData); + AddObjectDataToRuntimeUpdates(runtimeUpdates, edgeInId, m_PrefixConfigObject + "dependency:edge", edgeInData); + AddObjectDataToRuntimeUpdates(runtimeUpdates, edgeOutId, m_PrefixConfigObject + "dependency:edge", edgeOutData); + } + } else { + String edgeId = HashValue(new Array({m_EnvironmentId, dependencyNodeChildId, dependencyNodeParentId})); + dependencyEdges.emplace_back(edgeId); + Dictionary::Ptr edgeData = new Dictionary({ + {"environment_id", m_EnvironmentId}, + {"from_node_id", dependencyNodeChildId}, + {"to_node_id", dependencyNodeParentId}, + {"dependency_id", GetObjectIdentifier(dependency)}}); + dependencyEdges.emplace_back(JsonEncode(edgeData)); + + if (runtimeUpdate) { + AddObjectDataToRuntimeUpdates(runtimeUpdates, edgeId, m_PrefixConfigObject + "dependency:edge", edgeData); + } + } + } + if (type == TimePeriod::TypeInstance) { TimePeriod::Ptr timeperiod = static_pointer_cast(object); @@ -1121,6 +1254,47 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S } } +void IcingaDB::UpdateDependencyState(const Dependency::Ptr& dependency) +{ + if (!m_Rcon || !m_Rcon->IsConnected()) { + return; + } + + auto& redundancyGroupStates (hMSets[m_PrefixConfigObject + "redundancygroup:state"]); + + String redundancyGroup = dependency->GetRedundancyGroup(); + + if (!redundancyGroup.IsEmpty()) { + Host::Ptr childHost; + Service::Ptr childService; + tie(childHost, childService) = GetHostService(dependency->GetChild()); + + String dependencyNodeChildId = HashValue( + (childService) + ? new Array({ m_EnvironmentId, GetObjectIdentifier(childHost), GetObjectIdentifier(childService) }) + : new Array({ m_EnvironmentId, GetObjectIdentifier(childHost) })); + String redundancyGroupId = HashValue(new Array({ + m_EnvironmentId, + redundancyGroup, + dependencyNodeChildId})); + + redundancyGroupStates.emplace_back(redundancyGroupId); + Dictionary::Ptr groupStateData = new Dictionary({ + {"environment_id", m_EnvironmentId}, + {"redundancy_group_id", redundancyGroupId}, + {"failed", !((childService) ? childService->IsReachable() : childHost->IsReachable())}, + {"last_state_change", TimestampToMilliseconds(Utility::GetTime())}}); + redundancyGroupStates.emplace_back(JsonEncode(groupStateData)); + + // TODO + // AddObjectDataToRuntimeUpdates(runtimeUpdates, redundancyGroupId, m_PrefixConfigObject + "redundancygroup:state", groupStateData); + // dataClone->Set("id", objectKey); // redundancyGroupId + // dataClone->Set("redis_key", redisKey); // m_PrefixConfigObject + "redundancygroup:state" + // dataClone->Set("runtime_type", "upsert"); + // runtimeUpdates.emplace_back(dataClone); + } +} + /** * Update the state information of a checkable in Redis. * @@ -1450,6 +1624,32 @@ bool IcingaDB::PrepareObject(const ConfigObject::Ptr& object, Dictionary::Ptr& a return true; } + if (type == Dependency::TypeInstance) { + Dependency::Ptr dependency = static_pointer_cast(object); + String redundancyGroup = dependency->GetRedundancyGroup(); + + attributes->Set("name", GetObjectIdentifier(dependency)); + + if (!redundancyGroup.IsEmpty()) { + Host::Ptr childHost; + Service::Ptr childService; + tie(childHost, childService) = GetHostService(dependency->GetChild()); + + String dependencyNodeChildId = HashValue( + (childService) + ? new Array({ m_EnvironmentId, GetObjectIdentifier(childHost), GetObjectIdentifier(childService) }) + : new Array({ m_EnvironmentId, GetObjectIdentifier(childHost) })); + String redundancyGroupId = HashValue(new Array({ + m_EnvironmentId, + redundancyGroup, + dependencyNodeChildId})); + + attributes->Set("redundancy_group_id", redundancyGroupId); + } + + return true; + } + if (type == Downtime::TypeInstance) { Downtime::Ptr downtime = static_pointer_cast(object); diff --git a/lib/icingadb/icingadb.cpp b/lib/icingadb/icingadb.cpp index 8d3b9099b..3c623259b 100644 --- a/lib/icingadb/icingadb.cpp +++ b/lib/icingadb/icingadb.cpp @@ -38,6 +38,8 @@ IcingaDB::IcingaDB() m_PrefixConfigObject = "icinga:"; m_PrefixConfigCheckSum = "icinga:checksum:"; + + m_CheckablesToDependencies = new Dictionary(); } void IcingaDB::Validate(int types, const ValidationUtils& utils) diff --git a/lib/icingadb/icingadb.hpp b/lib/icingadb/icingadb.hpp index b943d7f4b..c5b499318 100644 --- a/lib/icingadb/icingadb.hpp +++ b/lib/icingadb/icingadb.hpp @@ -103,6 +103,7 @@ private: std::vector GetTypeDumpSignalKeys(const Type::Ptr& type); void InsertObjectDependencies(const ConfigObject::Ptr& object, const String typeName, std::map>& hMSets, std::vector& runtimeUpdates, bool runtimeUpdate); + void UpdateDependencyState(const Dependency::Ptr& dependency); void UpdateState(const Checkable::Ptr& checkable, StateUpdate mode); void SendConfigUpdate(const ConfigObject::Ptr& object, bool runtimeUpdate); void CreateConfigUpdate(const ConfigObject::Ptr& object, const String type, std::map>& hMSets, @@ -224,6 +225,8 @@ private: std::unordered_map m_Rcons; std::atomic_size_t m_PendingRcons; + Dictionary::Ptr m_CheckablesToDependencies; + struct { DumpedGlobals CustomVar, ActionUrl, NotesUrl, IconImage; } m_DumpedGlobals;