diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 12:34:54 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 12:34:54 +0000 |
commit | 0915b3ef56dfac3113cce55a59a5765dc94976be (patch) | |
tree | a8fea11d50b4f083e1bf0f90025ece7f0824784a /lib/db_ido/dbobject.cpp | |
parent | Initial commit. (diff) | |
download | icinga2-upstream.tar.xz icinga2-upstream.zip |
Adding upstream version 2.13.6.upstream/2.13.6upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | lib/db_ido/dbobject.cpp | 430 |
1 files changed, 430 insertions, 0 deletions
diff --git a/lib/db_ido/dbobject.cpp b/lib/db_ido/dbobject.cpp new file mode 100644 index 0000000..406bf52 --- /dev/null +++ b/lib/db_ido/dbobject.cpp @@ -0,0 +1,430 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#include "db_ido/dbobject.hpp" +#include "db_ido/dbtype.hpp" +#include "db_ido/dbvalue.hpp" +#include "icinga/customvarobject.hpp" +#include "icinga/service.hpp" +#include "icinga/compatutility.hpp" +#include "icinga/checkcommand.hpp" +#include "icinga/eventcommand.hpp" +#include "icinga/notificationcommand.hpp" +#include "remote/endpoint.hpp" +#include "base/configobject.hpp" +#include "base/configtype.hpp" +#include "base/json.hpp" +#include "base/serializer.hpp" +#include "base/json.hpp" +#include "base/convert.hpp" +#include "base/objectlock.hpp" +#include "base/utility.hpp" +#include "base/initialize.hpp" +#include "base/logger.hpp" + +using namespace icinga; + +boost::signals2::signal<void (const DbQuery&)> DbObject::OnQuery; +boost::signals2::signal<void (const std::vector<DbQuery>&)> DbObject::OnMultipleQueries; +boost::signals2::signal<void (const std::function<void (const DbObject::QueryCallbacks&)>&)> DbObject::OnMakeQueries; + +INITIALIZE_ONCE(&DbObject::StaticInitialize); + +DbObject::DbObject(intrusive_ptr<DbType> type, String name1, String name2) + : m_Name1(std::move(name1)), m_Name2(std::move(name2)), m_Type(std::move(type)), m_LastConfigUpdate(0), m_LastStatusUpdate(0) +{ } + +void DbObject::StaticInitialize() +{ + /* triggered in ProcessCheckResult(), requires UpdateNextCheck() to be called before */ + ConfigObject::OnStateChanged.connect([](const ConfigObject::Ptr& object) { StateChangedHandler(object); }); + CustomVarObject::OnVarsChanged.connect([](const CustomVarObject::Ptr& customVar, const Value&) { VarsChangedHandler(customVar); }); + + /* triggered on create, update and delete objects */ + ConfigObject::OnVersionChanged.connect([](const ConfigObject::Ptr& object, const Value&) { VersionChangedHandler(object); }); +} + +void DbObject::SetObject(const ConfigObject::Ptr& object) +{ + m_Object = object; +} + +ConfigObject::Ptr DbObject::GetObject() const +{ + return m_Object; +} + +String DbObject::GetName1() const +{ + return m_Name1; +} + +String DbObject::GetName2() const +{ + return m_Name2; +} + +DbType::Ptr DbObject::GetType() const +{ + return m_Type; +} + +String DbObject::CalculateConfigHash(const Dictionary::Ptr& configFields) const +{ + Dictionary::Ptr configFieldsDup = configFields->ShallowClone(); + + { + ObjectLock olock(configFieldsDup); + + for (const Dictionary::Pair& kv : configFieldsDup) { + if (kv.second.IsObjectType<ConfigObject>()) { + ConfigObject::Ptr obj = kv.second; + configFieldsDup->Set(kv.first, obj->GetName()); + } + } + } + + Array::Ptr data = new Array(); + data->Add(configFieldsDup); + + CustomVarObject::Ptr custom_var_object = dynamic_pointer_cast<CustomVarObject>(GetObject()); + + if (custom_var_object) + data->Add(custom_var_object->GetVars()); + + return HashValue(data); +} + +String DbObject::HashValue(const Value& value) +{ + Value temp; + + Type::Ptr type = value.GetReflectionType(); + + if (ConfigObject::TypeInstance->IsAssignableFrom(type)) + temp = Serialize(value, FAConfig); + else + temp = value; + + return SHA256(JsonEncode(temp)); +} + +void DbObject::SendConfigUpdateHeavy(const Dictionary::Ptr& configFields) +{ + /* update custom var config and status */ + SendVarsConfigUpdateHeavy(); + + /* config attributes */ + if (!configFields) + return; + + ASSERT(configFields->Contains("config_hash")); + + ConfigObject::Ptr object = GetObject(); + + DbQuery query; + query.Table = GetType()->GetTable() + "s"; + query.Type = DbQueryInsert | DbQueryUpdate; + query.Category = DbCatConfig; + query.Fields = configFields; + query.Fields->Set(GetType()->GetIDColumn(), object); + query.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */ + query.Fields->Set("config_type", 1); + query.WhereCriteria = new Dictionary({ + { GetType()->GetIDColumn(), object } + }); + query.Object = this; + query.ConfigUpdate = true; + OnQuery(query); + + m_LastConfigUpdate = Utility::GetTime(); + + OnConfigUpdateHeavy(); +} + +void DbObject::SendConfigUpdateLight() +{ + OnConfigUpdateLight(); +} + +void DbObject::SendStatusUpdate() +{ + /* status attributes */ + Dictionary::Ptr fields = GetStatusFields(); + + if (!fields) + return; + + DbQuery query; + query.Table = GetType()->GetTable() + "status"; + query.Type = DbQueryInsert | DbQueryUpdate; + query.Category = DbCatState; + query.Fields = fields; + query.Fields->Set(GetType()->GetIDColumn(), GetObject()); + + /* do not override endpoint_object_id for endpoints & zones */ + if (query.Table != "endpointstatus" && query.Table != "zonestatus") { + String node = IcingaApplication::GetInstance()->GetNodeName(); + + Endpoint::Ptr endpoint = Endpoint::GetByName(node); + if (endpoint) + query.Fields->Set("endpoint_object_id", endpoint); + } + + query.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */ + + query.Fields->Set("status_update_time", DbValue::FromTimestamp(Utility::GetTime())); + query.WhereCriteria = new Dictionary({ + { GetType()->GetIDColumn(), GetObject() } + }); + query.Object = this; + query.StatusUpdate = true; + OnQuery(query); + + m_LastStatusUpdate = Utility::GetTime(); + + OnStatusUpdate(); +} + +void DbObject::SendVarsConfigUpdateHeavy() +{ + ConfigObject::Ptr obj = GetObject(); + + CustomVarObject::Ptr custom_var_object = dynamic_pointer_cast<CustomVarObject>(obj); + + if (!custom_var_object) + return; + + std::vector<DbQuery> queries; + + DbQuery query1; + query1.Table = "customvariables"; + query1.Type = DbQueryDelete; + query1.Category = DbCatConfig; + query1.WhereCriteria = new Dictionary({ + { "object_id", obj } + }); + queries.emplace_back(std::move(query1)); + + DbQuery query2; + query2.Table = "customvariablestatus"; + query2.Type = DbQueryDelete; + query2.Category = DbCatConfig; + query2.WhereCriteria = new Dictionary({ + { "object_id", obj } + }); + queries.emplace_back(std::move(query2)); + + Dictionary::Ptr vars = custom_var_object->GetVars(); + + if (vars) { + ObjectLock olock (vars); + + for (const Dictionary::Pair& kv : vars) { + if (kv.first.IsEmpty()) + continue; + + String value; + int is_json = 0; + + if (kv.second.IsObjectType<Array>() || kv.second.IsObjectType<Dictionary>()) { + value = JsonEncode(kv.second); + is_json = 1; + } else + value = kv.second; + + DbQuery query3; + query3.Table = "customvariables"; + query3.Type = DbQueryInsert; + query3.Category = DbCatConfig; + query3.Fields = new Dictionary({ + { "varname", kv.first }, + { "varvalue", value }, + { "is_json", is_json }, + { "config_type", 1 }, + { "object_id", obj }, + { "instance_id", 0 } /* DbConnection class fills in real ID */ + }); + queries.emplace_back(std::move(query3)); + + DbQuery query4; + query4.Table = "customvariablestatus"; + query4.Type = DbQueryInsert; + query4.Category = DbCatState; + + query4.Fields = new Dictionary({ + { "varname", kv.first }, + { "varvalue", value }, + { "is_json", is_json }, + { "status_update_time", DbValue::FromTimestamp(Utility::GetTime()) }, + { "object_id", obj }, + { "instance_id", 0 } /* DbConnection class fills in real ID */ + }); + + queries.emplace_back(std::move(query4)); + } + } + + OnMultipleQueries(queries); +} + +void DbObject::SendVarsStatusUpdate() +{ + ConfigObject::Ptr obj = GetObject(); + + CustomVarObject::Ptr custom_var_object = dynamic_pointer_cast<CustomVarObject>(obj); + + if (!custom_var_object) + return; + + Dictionary::Ptr vars = custom_var_object->GetVars(); + + if (vars) { + std::vector<DbQuery> queries; + ObjectLock olock (vars); + + for (const Dictionary::Pair& kv : vars) { + if (kv.first.IsEmpty()) + continue; + + String value; + int is_json = 0; + + if (kv.second.IsObjectType<Array>() || kv.second.IsObjectType<Dictionary>()) { + value = JsonEncode(kv.second); + is_json = 1; + } else + value = kv.second; + + DbQuery query; + query.Table = "customvariablestatus"; + query.Type = DbQueryInsert | DbQueryUpdate; + query.Category = DbCatState; + + query.Fields = new Dictionary({ + { "varname", kv.first }, + { "varvalue", value }, + { "is_json", is_json }, + { "status_update_time", DbValue::FromTimestamp(Utility::GetTime()) }, + { "object_id", obj }, + { "instance_id", 0 } /* DbConnection class fills in real ID */ + }); + + query.WhereCriteria = new Dictionary({ + { "object_id", obj }, + { "varname", kv.first } + }); + + queries.emplace_back(std::move(query)); + } + + OnMultipleQueries(queries); + } +} + +double DbObject::GetLastConfigUpdate() const +{ + return m_LastConfigUpdate; +} + +double DbObject::GetLastStatusUpdate() const +{ + return m_LastStatusUpdate; +} + +void DbObject::OnConfigUpdateHeavy() +{ + /* Default handler does nothing. */ +} + +void DbObject::OnConfigUpdateLight() +{ + /* Default handler does nothing. */ +} + +void DbObject::OnStatusUpdate() +{ + /* Default handler does nothing. */ +} + +DbObject::Ptr DbObject::GetOrCreateByObject(const ConfigObject::Ptr& object) +{ + std::unique_lock<std::mutex> lock(GetStaticMutex()); + + DbObject::Ptr dbobj = object->GetExtension("DbObject"); + + if (dbobj) + return dbobj; + + DbType::Ptr dbtype = DbType::GetByName(object->GetReflectionType()->GetName()); + + if (!dbtype) + return nullptr; + + Service::Ptr service; + String name1, name2; + + service = dynamic_pointer_cast<Service>(object); + + if (service) { + Host::Ptr host = service->GetHost(); + + name1 = service->GetHost()->GetName(); + name2 = service->GetShortName(); + } else { + if (object->GetReflectionType() == CheckCommand::TypeInstance || + object->GetReflectionType() == EventCommand::TypeInstance || + object->GetReflectionType() == NotificationCommand::TypeInstance) { + Command::Ptr command = dynamic_pointer_cast<Command>(object); + name1 = CompatUtility::GetCommandName(command); + } + else + name1 = object->GetName(); + } + + dbobj = dbtype->GetOrCreateObjectByName(name1, name2); + + dbobj->SetObject(object); + object->SetExtension("DbObject", dbobj); + + return dbobj; +} + +void DbObject::StateChangedHandler(const ConfigObject::Ptr& object) +{ + DbObject::Ptr dbobj = GetOrCreateByObject(object); + + if (!dbobj) + return; + + dbobj->SendStatusUpdate(); +} + +void DbObject::VarsChangedHandler(const CustomVarObject::Ptr& object) +{ + DbObject::Ptr dbobj = GetOrCreateByObject(object); + + if (!dbobj) + return; + + dbobj->SendVarsStatusUpdate(); +} + +void DbObject::VersionChangedHandler(const ConfigObject::Ptr& object) +{ + DbObject::Ptr dbobj = DbObject::GetOrCreateByObject(object); + + if (dbobj) { + Dictionary::Ptr configFields = dbobj->GetConfigFields(); + String configHash = dbobj->CalculateConfigHash(configFields); + configFields->Set("config_hash", configHash); + + dbobj->SendConfigUpdateHeavy(configFields); + dbobj->SendStatusUpdate(); + } +} + +std::mutex& DbObject::GetStaticMutex() +{ + static std::mutex mutex; + return mutex; +} |