1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
3 #include "db_ido/dbobject.hpp"
4 #include "db_ido/dbtype.hpp"
5 #include "db_ido/dbvalue.hpp"
6 #include "icinga/customvarobject.hpp"
7 #include "icinga/service.hpp"
8 #include "icinga/compatutility.hpp"
9 #include "icinga/checkcommand.hpp"
10 #include "icinga/eventcommand.hpp"
11 #include "icinga/notificationcommand.hpp"
12 #include "remote/endpoint.hpp"
13 #include "base/configobject.hpp"
14 #include "base/configtype.hpp"
15 #include "base/json.hpp"
16 #include "base/serializer.hpp"
17 #include "base/json.hpp"
18 #include "base/convert.hpp"
19 #include "base/objectlock.hpp"
20 #include "base/utility.hpp"
21 #include "base/initialize.hpp"
22 #include "base/logger.hpp"
24 using namespace icinga;
26 boost::signals2::signal<void (const DbQuery&)> DbObject::OnQuery;
27 boost::signals2::signal<void (const std::vector<DbQuery>&)> DbObject::OnMultipleQueries;
29 INITIALIZE_ONCE(&DbObject::StaticInitialize);
31 DbObject::DbObject(intrusive_ptr<DbType> type, String name1, String name2)
32 : m_Name1(std::move(name1)), m_Name2(std::move(name2)), m_Type(std::move(type)), m_LastConfigUpdate(0), m_LastStatusUpdate(0)
35 void DbObject::StaticInitialize()
37 /* triggered in ProcessCheckResult(), requires UpdateNextCheck() to be called before */
38 ConfigObject::OnStateChanged.connect(std::bind(&DbObject::StateChangedHandler, _1));
39 CustomVarObject::OnVarsChanged.connect(std::bind(&DbObject::VarsChangedHandler, _1));
41 /* triggered on create, update and delete objects */
42 ConfigObject::OnVersionChanged.connect(std::bind(&DbObject::VersionChangedHandler, _1));
45 void DbObject::SetObject(const ConfigObject::Ptr& object)
50 ConfigObject::Ptr DbObject::GetObject() const
55 String DbObject::GetName1() const
60 String DbObject::GetName2() const
65 DbType::Ptr DbObject::GetType() const
70 String DbObject::CalculateConfigHash(const Dictionary::Ptr& configFields) const
72 Dictionary::Ptr configFieldsDup = configFields->ShallowClone();
75 ObjectLock olock(configFieldsDup);
77 for (const Dictionary::Pair& kv : configFieldsDup) {
78 if (kv.second.IsObjectType<ConfigObject>()) {
79 ConfigObject::Ptr obj = kv.second;
80 configFieldsDup->Set(kv.first, obj->GetName());
85 Array::Ptr data = new Array();
86 data->Add(configFieldsDup);
88 CustomVarObject::Ptr custom_var_object = dynamic_pointer_cast<CustomVarObject>(GetObject());
90 if (custom_var_object)
91 data->Add(custom_var_object->GetVars());
93 return HashValue(data);
96 String DbObject::HashValue(const Value& value)
100 Type::Ptr type = value.GetReflectionType();
102 if (ConfigObject::TypeInstance->IsAssignableFrom(type))
103 temp = Serialize(value, FAConfig);
107 return SHA256(JsonEncode(temp));
110 void DbObject::SendConfigUpdateHeavy(const Dictionary::Ptr& configFields)
112 /* update custom var config and status */
113 SendVarsConfigUpdateHeavy();
114 SendVarsStatusUpdate();
116 /* config attributes */
120 ASSERT(configFields->Contains("config_hash"));
122 ConfigObject::Ptr object = GetObject();
125 query.Table = GetType()->GetTable() + "s";
126 query.Type = DbQueryInsert | DbQueryUpdate;
127 query.Category = DbCatConfig;
128 query.Fields = configFields;
129 query.Fields->Set(GetType()->GetIDColumn(), object);
130 query.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */
131 query.Fields->Set("config_type", 1);
132 query.WhereCriteria = new Dictionary({
133 { GetType()->GetIDColumn(), object }
136 query.ConfigUpdate = true;
139 m_LastConfigUpdate = Utility::GetTime();
141 OnConfigUpdateHeavy();
144 void DbObject::SendConfigUpdateLight()
146 OnConfigUpdateLight();
149 void DbObject::SendStatusUpdate()
151 /* status attributes */
152 Dictionary::Ptr fields = GetStatusFields();
158 query.Table = GetType()->GetTable() + "status";
159 query.Type = DbQueryInsert | DbQueryUpdate;
160 query.Category = DbCatState;
161 query.Fields = fields;
162 query.Fields->Set(GetType()->GetIDColumn(), GetObject());
164 /* do not override endpoint_object_id for endpoints & zones */
165 if (query.Table != "endpointstatus" && query.Table != "zonestatus") {
166 String node = IcingaApplication::GetInstance()->GetNodeName();
168 Endpoint::Ptr endpoint = Endpoint::GetByName(node);
170 query.Fields->Set("endpoint_object_id", endpoint);
173 query.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */
175 query.Fields->Set("status_update_time", DbValue::FromTimestamp(Utility::GetTime()));
176 query.WhereCriteria = new Dictionary({
177 { GetType()->GetIDColumn(), GetObject() }
180 query.StatusUpdate = true;
183 m_LastStatusUpdate = Utility::GetTime();
188 void DbObject::SendVarsConfigUpdateHeavy()
190 ConfigObject::Ptr obj = GetObject();
192 CustomVarObject::Ptr custom_var_object = dynamic_pointer_cast<CustomVarObject>(obj);
194 if (!custom_var_object)
197 std::vector<DbQuery> queries;
200 query1.Table = "customvariables";
201 query1.Type = DbQueryDelete;
202 query1.Category = DbCatConfig;
203 query1.WhereCriteria = new Dictionary({
206 queries.emplace_back(std::move(query1));
209 query2.Table = "customvariablestatus";
210 query2.Type = DbQueryDelete;
211 query2.Category = DbCatConfig;
212 query2.WhereCriteria = new Dictionary({
215 queries.emplace_back(std::move(query2));
217 Dictionary::Ptr vars = custom_var_object->GetVars();
220 ObjectLock olock (vars);
222 for (const Dictionary::Pair& kv : vars) {
223 if (kv.first.IsEmpty())
229 if (kv.second.IsObjectType<Array>() || kv.second.IsObjectType<Dictionary>()) {
230 value = JsonEncode(kv.second);
236 query3.Table = "customvariables";
237 query3.Type = DbQueryInsert;
238 query3.Category = DbCatConfig;
239 query3.Fields = new Dictionary({
240 { "varname", kv.first },
241 { "varvalue", value },
242 { "is_json", is_json },
243 { "config_type", 1 },
244 { "object_id", obj },
245 { "instance_id", 0 } /* DbConnection class fills in real ID */
247 queries.emplace_back(std::move(query3));
251 OnMultipleQueries(queries);
254 void DbObject::SendVarsStatusUpdate()
256 ConfigObject::Ptr obj = GetObject();
258 CustomVarObject::Ptr custom_var_object = dynamic_pointer_cast<CustomVarObject>(obj);
260 if (!custom_var_object)
263 Dictionary::Ptr vars = custom_var_object->GetVars();
266 std::vector<DbQuery> queries;
267 ObjectLock olock (vars);
269 for (const Dictionary::Pair& kv : vars) {
270 if (kv.first.IsEmpty())
276 if (kv.second.IsObjectType<Array>() || kv.second.IsObjectType<Dictionary>()) {
277 value = JsonEncode(kv.second);
283 query.Table = "customvariablestatus";
284 query.Type = DbQueryInsert | DbQueryUpdate;
285 query.Category = DbCatState;
287 query.Fields = new Dictionary({
288 { "varname", kv.first },
289 { "varvalue", value },
290 { "is_json", is_json },
291 { "status_update_time", DbValue::FromTimestamp(Utility::GetTime()) },
292 { "object_id", obj },
293 { "instance_id", 0 } /* DbConnection class fills in real ID */
296 query.WhereCriteria = new Dictionary({
297 { "object_id", obj },
298 { "varname", kv.first }
301 queries.emplace_back(std::move(query));
304 OnMultipleQueries(queries);
308 double DbObject::GetLastConfigUpdate() const
310 return m_LastConfigUpdate;
313 double DbObject::GetLastStatusUpdate() const
315 return m_LastStatusUpdate;
318 void DbObject::OnConfigUpdateHeavy()
320 /* Default handler does nothing. */
323 void DbObject::OnConfigUpdateLight()
325 /* Default handler does nothing. */
328 void DbObject::OnStatusUpdate()
330 /* Default handler does nothing. */
333 DbObject::Ptr DbObject::GetOrCreateByObject(const ConfigObject::Ptr& object)
335 boost::mutex::scoped_lock lock(GetStaticMutex());
337 DbObject::Ptr dbobj = object->GetExtension("DbObject");
342 DbType::Ptr dbtype = DbType::GetByName(object->GetReflectionType()->GetName());
347 Service::Ptr service;
350 service = dynamic_pointer_cast<Service>(object);
353 Host::Ptr host = service->GetHost();
355 name1 = service->GetHost()->GetName();
356 name2 = service->GetShortName();
358 if (object->GetReflectionType() == CheckCommand::TypeInstance ||
359 object->GetReflectionType() == EventCommand::TypeInstance ||
360 object->GetReflectionType() == NotificationCommand::TypeInstance) {
361 Command::Ptr command = dynamic_pointer_cast<Command>(object);
362 name1 = CompatUtility::GetCommandName(command);
365 name1 = object->GetName();
368 dbobj = dbtype->GetOrCreateObjectByName(name1, name2);
370 dbobj->SetObject(object);
371 object->SetExtension("DbObject", dbobj);
376 void DbObject::StateChangedHandler(const ConfigObject::Ptr& object)
378 DbObject::Ptr dbobj = GetOrCreateByObject(object);
383 dbobj->SendStatusUpdate();
386 void DbObject::VarsChangedHandler(const CustomVarObject::Ptr& object)
388 DbObject::Ptr dbobj = GetOrCreateByObject(object);
393 dbobj->SendVarsStatusUpdate();
396 void DbObject::VersionChangedHandler(const ConfigObject::Ptr& object)
398 DbObject::Ptr dbobj = DbObject::GetOrCreateByObject(object);
401 Dictionary::Ptr configFields = dbobj->GetConfigFields();
402 String configHash = dbobj->CalculateConfigHash(configFields);
403 configFields->Set("config_hash", configHash);
405 dbobj->SendConfigUpdateHeavy(configFields);
406 dbobj->SendStatusUpdate();
410 boost::mutex& DbObject::GetStaticMutex()
412 static boost::mutex mutex;