mirror of https://github.com/Icinga/icinga2.git
Merge pull request #9212 from Icinga/bugfix/multi-ido-notification-id
IDO: fix incorrect contacts in notification history with multiple IDO instances on a single node
This commit is contained in:
commit
5383df3c79
|
@ -45,8 +45,19 @@ void DbConnection::Start(bool runtimeCreated)
|
||||||
Log(LogInformation, "DbConnection")
|
Log(LogInformation, "DbConnection")
|
||||||
<< "'" << GetName() << "' started.";
|
<< "'" << GetName() << "' started.";
|
||||||
|
|
||||||
DbObject::OnQuery.connect([this](const DbQuery& query) { ExecuteQuery(query); });
|
auto onQuery = [this](const DbQuery& query) { ExecuteQuery(query); };
|
||||||
DbObject::OnMultipleQueries.connect([this](const std::vector<DbQuery>& multiQueries) { ExecuteMultipleQueries(multiQueries); });
|
DbObject::OnQuery.connect(onQuery);
|
||||||
|
|
||||||
|
auto onMultipleQueries = [this](const std::vector<DbQuery>& multiQueries) { ExecuteMultipleQueries(multiQueries); };
|
||||||
|
DbObject::OnMultipleQueries.connect(onMultipleQueries);
|
||||||
|
|
||||||
|
DbObject::QueryCallbacks queryCallbacks;
|
||||||
|
queryCallbacks.Query = onQuery;
|
||||||
|
queryCallbacks.MultipleQueries = onMultipleQueries;
|
||||||
|
|
||||||
|
DbObject::OnMakeQueries.connect([queryCallbacks](const std::function<void (const DbObject::QueryCallbacks&)>& queryFunc) {
|
||||||
|
queryFunc(queryCallbacks);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void DbConnection::Stop(bool runtimeRemoved)
|
void DbConnection::Stop(bool runtimeRemoved)
|
||||||
|
|
|
@ -837,72 +837,79 @@ void DbEvents::AddAcknowledgementInternal(const Checkable::Ptr& checkable, Ackno
|
||||||
void DbEvents::AddNotificationHistory(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const std::set<User::Ptr>& users, NotificationType type,
|
void DbEvents::AddNotificationHistory(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const std::set<User::Ptr>& users, NotificationType type,
|
||||||
const CheckResult::Ptr& cr, const String& author, const String& text)
|
const CheckResult::Ptr& cr, const String& author, const String& text)
|
||||||
{
|
{
|
||||||
/* start and end happen at the same time */
|
/* NotificationInsertID has to be tracked per IDO instance, therefore the OnQuery and OnMultipleQueries signals
|
||||||
std::pair<unsigned long, unsigned long> timeBag = ConvertTimestamp(Utility::GetTime());
|
* cannot be called directly as all IDO instances would insert rows with the same ID which is (most likely) only
|
||||||
|
* correct in one database. Instead, pass a lambda which generates the queries with new DbValue for
|
||||||
|
* NotificationInsertID each IDO instance.
|
||||||
|
*/
|
||||||
|
DbObject::OnMakeQueries([&checkable, &users, &type, &cr](const DbObject::QueryCallbacks& callbacks) {
|
||||||
|
/* start and end happen at the same time */
|
||||||
|
std::pair<unsigned long, unsigned long> timeBag = ConvertTimestamp(Utility::GetTime());
|
||||||
|
|
||||||
DbQuery query1;
|
DbQuery query1;
|
||||||
query1.Table = "notifications";
|
query1.Table = "notifications";
|
||||||
query1.Type = DbQueryInsert;
|
query1.Type = DbQueryInsert;
|
||||||
query1.Category = DbCatNotification;
|
query1.Category = DbCatNotification;
|
||||||
query1.NotificationInsertID = new DbValue(DbValueObjectInsertID, -1);
|
query1.NotificationInsertID = new DbValue(DbValueObjectInsertID, -1);
|
||||||
|
|
||||||
Host::Ptr host;
|
Host::Ptr host;
|
||||||
Service::Ptr service;
|
Service::Ptr service;
|
||||||
tie(host, service) = GetHostService(checkable);
|
tie(host, service) = GetHostService(checkable);
|
||||||
|
|
||||||
Dictionary::Ptr fields1 = new Dictionary();
|
Dictionary::Ptr fields1 = new Dictionary();
|
||||||
fields1->Set("notification_type", 1); /* service */
|
fields1->Set("notification_type", 1); /* service */
|
||||||
fields1->Set("notification_reason", MapNotificationReasonType(type));
|
fields1->Set("notification_reason", MapNotificationReasonType(type));
|
||||||
fields1->Set("object_id", checkable);
|
fields1->Set("object_id", checkable);
|
||||||
fields1->Set("start_time", DbValue::FromTimestamp(timeBag.first));
|
fields1->Set("start_time", DbValue::FromTimestamp(timeBag.first));
|
||||||
fields1->Set("start_time_usec", timeBag.second);
|
fields1->Set("start_time_usec", timeBag.second);
|
||||||
fields1->Set("end_time", DbValue::FromTimestamp(timeBag.first));
|
fields1->Set("end_time", DbValue::FromTimestamp(timeBag.first));
|
||||||
fields1->Set("end_time_usec", timeBag.second);
|
fields1->Set("end_time_usec", timeBag.second);
|
||||||
|
|
||||||
if (service)
|
if (service)
|
||||||
fields1->Set("state", service->GetState());
|
fields1->Set("state", service->GetState());
|
||||||
else
|
else
|
||||||
fields1->Set("state", GetHostState(host));
|
fields1->Set("state", GetHostState(host));
|
||||||
|
|
||||||
if (cr) {
|
if (cr) {
|
||||||
fields1->Set("output", CompatUtility::GetCheckResultOutput(cr));
|
fields1->Set("output", CompatUtility::GetCheckResultOutput(cr));
|
||||||
fields1->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr));
|
fields1->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr));
|
||||||
}
|
}
|
||||||
|
|
||||||
fields1->Set("escalated", 0);
|
fields1->Set("escalated", 0);
|
||||||
fields1->Set("contacts_notified", static_cast<long>(users.size()));
|
fields1->Set("contacts_notified", static_cast<long>(users.size()));
|
||||||
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
||||||
|
|
||||||
Endpoint::Ptr endpoint = Endpoint::GetByName(IcingaApplication::GetInstance()->GetNodeName());
|
Endpoint::Ptr endpoint = Endpoint::GetByName(IcingaApplication::GetInstance()->GetNodeName());
|
||||||
|
|
||||||
if (endpoint)
|
if (endpoint)
|
||||||
fields1->Set("endpoint_object_id", endpoint);
|
fields1->Set("endpoint_object_id", endpoint);
|
||||||
|
|
||||||
query1.Fields = fields1;
|
query1.Fields = fields1;
|
||||||
DbObject::OnQuery(query1);
|
callbacks.Query(query1);
|
||||||
|
|
||||||
std::vector<DbQuery> queries;
|
std::vector<DbQuery> queries;
|
||||||
|
|
||||||
for (const User::Ptr& user : users) {
|
for (const User::Ptr& user : users) {
|
||||||
DbQuery query2;
|
DbQuery query2;
|
||||||
query2.Table = "contactnotifications";
|
query2.Table = "contactnotifications";
|
||||||
query2.Type = DbQueryInsert;
|
query2.Type = DbQueryInsert;
|
||||||
query2.Category = DbCatNotification;
|
query2.Category = DbCatNotification;
|
||||||
|
|
||||||
query2.Fields = new Dictionary({
|
query2.Fields = new Dictionary({
|
||||||
{ "contact_object_id", user },
|
{ "contact_object_id", user },
|
||||||
{ "start_time", DbValue::FromTimestamp(timeBag.first) },
|
{ "start_time", DbValue::FromTimestamp(timeBag.first) },
|
||||||
{ "start_time_usec", timeBag.second },
|
{ "start_time_usec", timeBag.second },
|
||||||
{ "end_time", DbValue::FromTimestamp(timeBag.first) },
|
{ "end_time", DbValue::FromTimestamp(timeBag.first) },
|
||||||
{ "end_time_usec", timeBag.second },
|
{ "end_time_usec", timeBag.second },
|
||||||
{ "notification_id", query1.NotificationInsertID },
|
{ "notification_id", query1.NotificationInsertID },
|
||||||
{ "instance_id", 0 } /* DbConnection class fills in real ID */
|
{ "instance_id", 0 } /* DbConnection class fills in real ID */
|
||||||
});
|
});
|
||||||
|
|
||||||
queries.emplace_back(std::move(query2));
|
queries.emplace_back(std::move(query2));
|
||||||
}
|
}
|
||||||
|
|
||||||
DbObject::OnMultipleQueries(queries);
|
callbacks.MultipleQueries(queries);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* statehistory */
|
/* statehistory */
|
||||||
|
|
|
@ -25,6 +25,7 @@ using namespace icinga;
|
||||||
|
|
||||||
boost::signals2::signal<void (const DbQuery&)> DbObject::OnQuery;
|
boost::signals2::signal<void (const DbQuery&)> DbObject::OnQuery;
|
||||||
boost::signals2::signal<void (const std::vector<DbQuery>&)> DbObject::OnMultipleQueries;
|
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);
|
INITIALIZE_ONCE(&DbObject::StaticInitialize);
|
||||||
|
|
||||||
|
|
|
@ -61,8 +61,14 @@ public:
|
||||||
|
|
||||||
static DbObject::Ptr GetOrCreateByObject(const ConfigObject::Ptr& object);
|
static DbObject::Ptr GetOrCreateByObject(const ConfigObject::Ptr& object);
|
||||||
|
|
||||||
|
struct QueryCallbacks {
|
||||||
|
std::function<void(const DbQuery&)> Query;
|
||||||
|
std::function<void(const std::vector<DbQuery>&)> MultipleQueries;
|
||||||
|
};
|
||||||
|
|
||||||
static boost::signals2::signal<void (const DbQuery&)> OnQuery;
|
static boost::signals2::signal<void (const DbQuery&)> OnQuery;
|
||||||
static boost::signals2::signal<void (const std::vector<DbQuery>&)> OnMultipleQueries;
|
static boost::signals2::signal<void (const std::vector<DbQuery>&)> OnMultipleQueries;
|
||||||
|
static boost::signals2::signal<void (const std::function<void (const QueryCallbacks&)>&)> OnMakeQueries;
|
||||||
|
|
||||||
void SendConfigUpdateHeavy(const Dictionary::Ptr& configFields);
|
void SendConfigUpdateHeavy(const Dictionary::Ptr& configFields);
|
||||||
void SendConfigUpdateLight();
|
void SendConfigUpdateLight();
|
||||||
|
|
Loading…
Reference in New Issue