IcingaDB: Start keeping track of Host/Service to Dependency relationship

This does not work in this state!
Trying to refresh Dependency if a Host or Service being member
of this Dependency has a state change.
This commit is contained in:
Alvar Penning 2024-10-21 16:00:39 +02:00 committed by Yonas Habteab
parent 8714f72d65
commit ef93f945a2
3 changed files with 205 additions and 0 deletions

View File

@ -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<Type::Ptr> 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<Dependency>(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<TimePeriod>(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<Dependency>(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<Downtime>(object);

View File

@ -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)

View File

@ -103,6 +103,7 @@ private:
std::vector<String> GetTypeDumpSignalKeys(const Type::Ptr& type);
void InsertObjectDependencies(const ConfigObject::Ptr& object, const String typeName, std::map<String, std::vector<String>>& hMSets,
std::vector<Dictionary::Ptr>& 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<String, std::vector<String>>& hMSets,
@ -224,6 +225,8 @@ private:
std::unordered_map<ConfigType*, RedisConnection::Ptr> m_Rcons;
std::atomic_size_t m_PendingRcons;
Dictionary::Ptr m_CheckablesToDependencies;
struct {
DumpedGlobals CustomVar, ActionUrl, NotesUrl, IconImage;
} m_DumpedGlobals;