icinga2/lib/db_ido/dbevents.cpp
Michael Friedrich 0cbedf495a IDO: Ensure that the notification insert id is passed to contactnotification inserts
We cannot add the notification insert id directly
to the following contactnotifications queries. Instead
we need to pass a DbValue reference which gets set after
the notification insert id is calculated.
The contactnotifications insert queries are fired as query
group calling CanExecuteQuery() and FieldToEscapedString().
If the notification id does not exist yet, the queries are
moved to the end of the queue.
Once the contactnotifications queries are fired the DbValue
reference is destroyed.

This patch also removes the old notification insert id cache
which was broken in many ways.

fixes #11387
2016-04-20 10:07:24 +02:00

1501 lines
49 KiB
C++

/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2016 Icinga Development Team (https://www.icinga.org/) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#include "db_ido/dbevents.hpp"
#include "db_ido/dbtype.hpp"
#include "db_ido/dbvalue.hpp"
#include "base/convert.hpp"
#include "base/objectlock.hpp"
#include "base/initialize.hpp"
#include "base/configtype.hpp"
#include "base/utility.hpp"
#include "base/logger.hpp"
#include "remote/endpoint.hpp"
#include "icinga/notification.hpp"
#include "icinga/checkcommand.hpp"
#include "icinga/eventcommand.hpp"
#include "icinga/externalcommandprocessor.hpp"
#include "icinga/compatutility.hpp"
#include "icinga/icingaapplication.hpp"
#include <boost/foreach.hpp>
#include <boost/algorithm/string/join.hpp>
using namespace icinga;
INITIALIZE_ONCE(&DbEvents::StaticInitialize);
void DbEvents::StaticInitialize(void)
{
/* Status */
Comment::OnCommentAdded.connect(boost::bind(&DbEvents::AddComment, _1));
Comment::OnCommentRemoved.connect(boost::bind(&DbEvents::RemoveComment, _1));
Downtime::OnDowntimeAdded.connect(boost::bind(&DbEvents::AddDowntime, _1));
Downtime::OnDowntimeRemoved.connect(boost::bind(&DbEvents::RemoveDowntime, _1));
Downtime::OnDowntimeTriggered.connect(boost::bind(&DbEvents::TriggerDowntime, _1));
Checkable::OnAcknowledgementSet.connect(boost::bind(&DbEvents::AddAcknowledgement, _1, _4));
Checkable::OnAcknowledgementCleared.connect(boost::bind(&DbEvents::RemoveAcknowledgement, _1));
Checkable::OnNextCheckUpdated.connect(boost::bind(&DbEvents::NextCheckUpdatedHandler, _1));
Checkable::OnFlappingChanged.connect(boost::bind(&DbEvents::FlappingChangedHandler, _1));
Checkable::OnNotificationSentToAllUsers.connect(boost::bind(&DbEvents::LastNotificationChangedHandler, _1, _2));
Checkable::OnEnableActiveChecksChanged.connect(boost::bind(&DbEvents::EnableActiveChecksChangedHandler, _1));
Checkable::OnEnablePassiveChecksChanged.connect(boost::bind(&DbEvents::EnablePassiveChecksChangedHandler, _1));
Checkable::OnEnableNotificationsChanged.connect(boost::bind(&DbEvents::EnableNotificationsChangedHandler, _1));
Checkable::OnEnablePerfdataChanged.connect(boost::bind(&DbEvents::EnablePerfdataChangedHandler, _1));
Checkable::OnEnableFlappingChanged.connect(boost::bind(&DbEvents::EnableFlappingChangedHandler, _1));
Checkable::OnReachabilityChanged.connect(boost::bind(&DbEvents::ReachabilityChangedHandler, _1, _2, _3));
/* History */
Comment::OnCommentAdded.connect(boost::bind(&DbEvents::AddCommentHistory, _1));
Downtime::OnDowntimeAdded.connect(boost::bind(&DbEvents::AddDowntimeHistory, _1));
Checkable::OnAcknowledgementSet.connect(boost::bind(&DbEvents::AddAcknowledgementHistory, _1, _2, _3, _4, _5, _6));
Checkable::OnNotificationSentToAllUsers.connect(boost::bind(&DbEvents::AddNotificationHistory, _1, _2, _3, _4, _5, _6, _7));
Checkable::OnStateChange.connect(boost::bind(&DbEvents::AddStateChangeHistory, _1, _2, _3));
Checkable::OnNewCheckResult.connect(boost::bind(&DbEvents::AddCheckResultLogHistory, _1, _2));
Checkable::OnNotificationSentToUser.connect(boost::bind(&DbEvents::AddNotificationSentLogHistory, _1, _2, _3, _4, _5, _6, _7));
Checkable::OnFlappingChanged.connect(boost::bind(&DbEvents::AddFlappingChangedLogHistory, _1));
Checkable::OnEnableFlappingChanged.connect(boost::bind(&DbEvents::AddEnableFlappingChangedLogHistory, _1));
Downtime::OnDowntimeTriggered.connect(boost::bind(&DbEvents::AddTriggerDowntimeLogHistory, _1));
Downtime::OnDowntimeRemoved.connect(boost::bind(&DbEvents::AddRemoveDowntimeLogHistory, _1));
Checkable::OnFlappingChanged.connect(boost::bind(&DbEvents::AddFlappingChangedHistory, _1));
Checkable::OnEnableFlappingChanged.connect(boost::bind(&DbEvents::AddEnableFlappingChangedHistory, _1));
Checkable::OnNewCheckResult.connect(boost::bind(&DbEvents::AddCheckableCheckHistory, _1, _2));
Checkable::OnEventCommandExecuted.connect(boost::bind(&DbEvents::AddEventHandlerHistory, _1));
ExternalCommandProcessor::OnNewExternalCommand.connect(boost::bind(&DbEvents::AddExternalCommandHistory, _1, _2, _3));
}
/* check events */
void DbEvents::NextCheckUpdatedHandler(const Checkable::Ptr& checkable)
{
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
DbQuery query1;
if (service)
query1.Table = "servicestatus";
else
query1.Table = "hoststatus";
query1.Type = DbQueryUpdate;
query1.Category = DbCatState;
query1.StatusUpdate = true;
query1.Object = DbObject::GetOrCreateByObject(checkable);
Dictionary::Ptr fields1 = new Dictionary();
fields1->Set("next_check", DbValue::FromTimestamp(checkable->GetNextCheck()));
query1.Fields = fields1;
query1.WhereCriteria = new Dictionary();
if (service)
query1.WhereCriteria->Set("service_object_id", service);
else
query1.WhereCriteria->Set("host_object_id", host);
DbObject::OnQuery(query1);
}
void DbEvents::FlappingChangedHandler(const Checkable::Ptr& checkable)
{
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
DbQuery query1;
if (service)
query1.Table = "servicestatus";
else
query1.Table = "hoststatus";
query1.Type = DbQueryUpdate;
query1.Category = DbCatState;
query1.StatusUpdate = true;
query1.Object = DbObject::GetOrCreateByObject(checkable);
Dictionary::Ptr fields1 = new Dictionary();
fields1->Set("is_flapping", CompatUtility::GetCheckableIsFlapping(checkable));
fields1->Set("percent_state_change", CompatUtility::GetCheckablePercentStateChange(checkable));
query1.Fields = fields1;
query1.WhereCriteria = new Dictionary();
if (service)
query1.WhereCriteria->Set("service_object_id", service);
else
query1.WhereCriteria->Set("host_object_id", host);
query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
DbObject::OnQuery(query1);
}
void DbEvents::LastNotificationChangedHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable)
{
double now = Utility::GetTime();
std::pair<unsigned long, unsigned long> now_bag = CompatUtility::ConvertTimestamp(now);
std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(notification->GetNextNotification());
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
DbQuery query1;
if (service)
query1.Table = "servicestatus";
else
query1.Table = "hoststatus";
query1.Type = DbQueryUpdate;
query1.Category = DbCatState;
query1.StatusUpdate = true;
query1.Object = DbObject::GetOrCreateByObject(checkable);
Dictionary::Ptr fields1 = new Dictionary();
fields1->Set("last_notification", DbValue::FromTimestamp(now_bag.first));
fields1->Set("next_notification", DbValue::FromTimestamp(time_bag.first));
fields1->Set("current_notification_number", notification->GetNotificationNumber());
query1.Fields = fields1;
query1.WhereCriteria = new Dictionary();
if (service)
query1.WhereCriteria->Set("service_object_id", service);
else
query1.WhereCriteria->Set("host_object_id", host);
query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
DbObject::OnQuery(query1);
}
void DbEvents::ReachabilityChangedHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, std::set<Checkable::Ptr> children)
{
int is_reachable = 0;
if (cr->GetState() == ServiceOK)
is_reachable = 1;
Log(LogDebug, "DbEvents")
<< "Updating reachability for checkable '" << checkable->GetName() << "': " << (is_reachable ? "" : "not" ) << " reachable for " << children.size() << " children.";
BOOST_FOREACH(const Checkable::Ptr& child, children) {
Log(LogDebug, "DbEvents")
<< "Updating reachability for checkable '" << child->GetName() << "': " << (is_reachable ? "" : "not" ) << " reachable.";
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(child);
DbQuery query1;
if (service)
query1.Table = "servicestatus";
else
query1.Table = "hoststatus";
query1.Type = DbQueryUpdate;
query1.Category = DbCatState;
query1.StatusUpdate = true;
query1.Object = DbObject::GetOrCreateByObject(child);
Dictionary::Ptr fields1 = new Dictionary();
fields1->Set("is_reachable", is_reachable);
query1.Fields = fields1;
query1.WhereCriteria = new Dictionary();
if (service)
query1.WhereCriteria->Set("service_object_id", service);
else
query1.WhereCriteria->Set("host_object_id", host);
query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
DbObject::OnQuery(query1);
}
}
/* enable changed events */
void DbEvents::EnableActiveChecksChangedHandler(const Checkable::Ptr& checkable)
{
EnableChangedHandlerInternal(checkable, "active_checks_enabled", checkable->GetEnableActiveChecks());
}
void DbEvents::EnablePassiveChecksChangedHandler(const Checkable::Ptr& checkable)
{
EnableChangedHandlerInternal(checkable, "passive_checks_enabled", checkable->GetEnablePassiveChecks());
}
void DbEvents::EnableNotificationsChangedHandler(const Checkable::Ptr& checkable)
{
EnableChangedHandlerInternal(checkable, "notifications_enabled", checkable->GetEnableNotifications());
}
void DbEvents::EnablePerfdataChangedHandler(const Checkable::Ptr& checkable)
{
EnableChangedHandlerInternal(checkable, "process_performance_data", checkable->GetEnablePerfdata());
}
void DbEvents::EnableFlappingChangedHandler(const Checkable::Ptr& checkable)
{
EnableChangedHandlerInternal(checkable, "flap_detection_enabled", checkable->GetEnableFlapping());
}
void DbEvents::EnableChangedHandlerInternal(const Checkable::Ptr& checkable, const String& fieldName, bool enabled)
{
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
DbQuery query1;
if (service)
query1.Table = "servicestatus";
else
query1.Table = "hoststatus";
query1.Type = DbQueryUpdate;
query1.Category = DbCatState;
query1.StatusUpdate = true;
query1.Object = DbObject::GetOrCreateByObject(checkable);
Dictionary::Ptr fields1 = new Dictionary();
fields1->Set(fieldName, enabled);
query1.Fields = fields1;
query1.WhereCriteria = new Dictionary();
if (service)
query1.WhereCriteria->Set("service_object_id", service);
else
query1.WhereCriteria->Set("host_object_id", host);
query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
DbObject::OnQuery(query1);
}
/* comments */
void DbEvents::AddComments(const Checkable::Ptr& checkable)
{
std::set<Comment::Ptr> comments = checkable->GetComments();
if (comments.empty())
return;
std::vector<DbQuery> queries;
DbQuery query1;
query1.Table = "comments";
query1.Type = DbQueryDelete;
query1.Category = DbCatComment;
query1.WhereCriteria = new Dictionary();
query1.WhereCriteria->Set("object_id", checkable);
queries.push_back(query1);
BOOST_FOREACH(const Comment::Ptr& comment, comments) {
AddCommentInternal(queries, comment, false);
}
DbObject::OnMultipleQueries(queries);
}
void DbEvents::AddComment(const Comment::Ptr& comment)
{
std::vector<DbQuery> queries;
RemoveCommentInternal(queries, comment);
AddCommentInternal(queries, comment, false);
DbObject::OnMultipleQueries(queries);
}
void DbEvents::AddCommentHistory(const Comment::Ptr& comment)
{
std::vector<DbQuery> queries;
AddCommentInternal(queries, comment, true);
DbObject::OnMultipleQueries(queries);
}
void DbEvents::AddCommentInternal(std::vector<DbQuery>& queries, const Comment::Ptr& comment, bool historical)
{
Checkable::Ptr checkable = comment->GetCheckable();
unsigned long entry_time = static_cast<long>(comment->GetEntryTime());
unsigned long entry_time_usec = (comment->GetEntryTime() - entry_time) * 1000 * 1000;
Dictionary::Ptr fields1 = new Dictionary();
fields1->Set("entry_time", DbValue::FromTimestamp(entry_time));
fields1->Set("entry_time_usec", entry_time_usec);
fields1->Set("entry_type", comment->GetEntryType());
fields1->Set("object_id", checkable);
if (checkable->GetType() == ConfigType::GetByName("Host")) {
fields1->Set("comment_type", 2);
/* requires idoutils 1.10 schema fix */
fields1->Set("internal_comment_id", comment->GetLegacyId());
} else if (checkable->GetType() == ConfigType::GetByName("Service")) {
fields1->Set("comment_type", 1);
fields1->Set("internal_comment_id", comment->GetLegacyId());
} else {
Log(LogDebug, "DbEvents", "unknown object type for adding comment.");
return;
}
fields1->Set("name", comment->GetName());
fields1->Set("comment_time", DbValue::FromTimestamp(entry_time)); /* same as entry_time */
fields1->Set("author_name", comment->GetAuthor());
fields1->Set("comment_data", comment->GetText());
fields1->Set("is_persistent", 1);
fields1->Set("comment_source", 1); /* external */
fields1->Set("expires", (comment->GetExpireTime() > 0) ? 1 : 0);
fields1->Set("expiration_time", DbValue::FromTimestamp(comment->GetExpireTime()));
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
String node = IcingaApplication::GetInstance()->GetNodeName();
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
if (endpoint)
fields1->Set("endpoint_object_id", endpoint);
DbQuery query1;
if (!historical) {
query1.Table = "comments";
} else {
query1.Table = "commenthistory";
}
query1.Type = DbQueryInsert;
query1.Category = DbCatComment;
query1.Fields = fields1;
queries.push_back(query1);
}
void DbEvents::RemoveComment(const Comment::Ptr& comment)
{
std::vector<DbQuery> queries;
RemoveCommentInternal(queries, comment);
DbObject::OnMultipleQueries(queries);
}
void DbEvents::RemoveCommentInternal(std::vector<DbQuery>& queries, const Comment::Ptr& comment)
{
Checkable::Ptr checkable = comment->GetCheckable();
/* Status */
DbQuery query1;
query1.Table = "comments";
query1.Type = DbQueryDelete;
query1.Category = DbCatComment;
query1.WhereCriteria = new Dictionary();
query1.WhereCriteria->Set("object_id", checkable);
query1.WhereCriteria->Set("internal_comment_id", comment->GetLegacyId());
queries.push_back(query1);
/* History - update deletion time for service/host */
unsigned long entry_time = static_cast<long>(comment->GetEntryTime());
double now = Utility::GetTime();
std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
DbQuery query2;
query2.Table = "commenthistory";
query2.Type = DbQueryUpdate;
query2.Category = DbCatComment;
Dictionary::Ptr fields2 = new Dictionary();
fields2->Set("deletion_time", DbValue::FromTimestamp(time_bag.first));
fields2->Set("deletion_time_usec", time_bag.second);
query2.Fields = fields2;
query2.WhereCriteria = new Dictionary();
query2.WhereCriteria->Set("internal_comment_id", comment->GetLegacyId());
query2.WhereCriteria->Set("object_id", checkable);
query2.WhereCriteria->Set("comment_time", DbValue::FromTimestamp(entry_time));
query2.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
queries.push_back(query2);
}
/* downtimes */
void DbEvents::AddDowntimes(const Checkable::Ptr& checkable)
{
std::set<Downtime::Ptr> downtimes = checkable->GetDowntimes();
if (downtimes.empty())
return;
std::vector<DbQuery> queries;
DbQuery query1;
query1.Table = "scheduleddowntime";
query1.Type = DbQueryDelete;
query1.Category = DbCatDowntime;
query1.WhereCriteria = new Dictionary();
query1.WhereCriteria->Set("object_id", checkable);
queries.push_back(query1);
BOOST_FOREACH(const Downtime::Ptr& downtime, downtimes) {
AddDowntimeInternal(queries, downtime, false);
}
DbObject::OnMultipleQueries(queries);
}
void DbEvents::AddDowntime(const Downtime::Ptr& downtime)
{
std::vector<DbQuery> queries;
RemoveDowntimeInternal(queries, downtime);
AddDowntimeInternal(queries, downtime, false);
DbObject::OnMultipleQueries(queries);
}
void DbEvents::AddDowntimeHistory(const Downtime::Ptr& downtime)
{
std::vector<DbQuery> queries;
AddDowntimeInternal(queries, downtime, true);
DbObject::OnMultipleQueries(queries);
}
void DbEvents::AddDowntimeInternal(std::vector<DbQuery>& queries, const Downtime::Ptr& downtime, bool historical)
{
Checkable::Ptr checkable = downtime->GetCheckable();
Dictionary::Ptr fields1 = new Dictionary();
fields1->Set("entry_time", DbValue::FromTimestamp(downtime->GetEntryTime()));
fields1->Set("object_id", checkable);
if (checkable->GetType() == ConfigType::GetByName("Host")) {
fields1->Set("downtime_type", 2);
/* requires idoutils 1.10 schema fix */
fields1->Set("internal_downtime_id", downtime->GetLegacyId());
} else if (checkable->GetType() == ConfigType::GetByName("Service")) {
fields1->Set("downtime_type", 1);
fields1->Set("internal_downtime_id", downtime->GetLegacyId());
} else {
Log(LogDebug, "DbEvents", "unknown object type for adding downtime.");
return;
}
fields1->Set("name", downtime->GetName());
fields1->Set("author_name", downtime->GetAuthor());
fields1->Set("comment_data", downtime->GetComment());
fields1->Set("triggered_by_id", Downtime::GetByName(downtime->GetTriggeredBy()));
fields1->Set("is_fixed", downtime->GetFixed() ? 1 : 0);
fields1->Set("duration", downtime->GetDuration());
fields1->Set("scheduled_start_time", DbValue::FromTimestamp(downtime->GetStartTime()));
fields1->Set("scheduled_end_time", DbValue::FromTimestamp(downtime->GetEndTime()));
fields1->Set("was_started", ((downtime->GetStartTime() <= Utility::GetTime()) ? 1 : 0));
fields1->Set("is_in_effect", (downtime->IsActive() ? 1 : 0));
fields1->Set("trigger_time", DbValue::FromTimestamp(downtime->GetTriggerTime()));
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
String node = IcingaApplication::GetInstance()->GetNodeName();
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
if (endpoint)
fields1->Set("endpoint_object_id", endpoint);
DbQuery query1;
if (!historical)
query1.Table = "scheduleddowntime";
else
query1.Table = "downtimehistory";
query1.Type = DbQueryInsert;
query1.Category = DbCatDowntime;
query1.Fields = fields1;
queries.push_back(query1);
/* host/service status */
if (!historical) {
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
DbQuery query2;
if (service)
query2.Table = "servicestatus";
else
query2.Table = "hoststatus";
query2.Type = DbQueryUpdate;
query2.Category = DbCatState;
query2.StatusUpdate = true;
query2.Object = DbObject::GetOrCreateByObject(checkable);
Dictionary::Ptr fields2 = new Dictionary();
fields2->Set("scheduled_downtime_depth", checkable->GetDowntimeDepth());
query2.Fields = fields2;
query2.WhereCriteria = new Dictionary();
if (service)
query2.WhereCriteria->Set("service_object_id", service);
else
query2.WhereCriteria->Set("host_object_id", host);
query2.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
queries.push_back(query2);
}
}
void DbEvents::RemoveDowntime(const Downtime::Ptr& downtime)
{
std::vector<DbQuery> queries;
RemoveDowntimeInternal(queries, downtime);
DbObject::OnMultipleQueries(queries);
}
void DbEvents::RemoveDowntimeInternal(std::vector<DbQuery>& queries, const Downtime::Ptr& downtime)
{
Checkable::Ptr checkable = downtime->GetCheckable();
/* Status */
DbQuery query1;
query1.Table = "scheduleddowntime";
query1.Type = DbQueryDelete;
query1.Category = DbCatDowntime;
query1.WhereCriteria = new Dictionary();
query1.WhereCriteria->Set("object_id", checkable);
query1.WhereCriteria->Set("internal_downtime_id", downtime->GetLegacyId());
query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
queries.push_back(query1);
/* History - update actual_end_time, was_cancelled for service (and host in case) */
double now = Utility::GetTime();
std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
DbQuery query3;
query3.Table = "downtimehistory";
query3.Type = DbQueryUpdate;
query3.Category = DbCatDowntime;
Dictionary::Ptr fields3 = new Dictionary();
fields3->Set("was_cancelled", downtime->GetWasCancelled() ? 1 : 0);
fields3->Set("actual_end_time", DbValue::FromTimestamp(time_bag.first));
fields3->Set("actual_end_time_usec", time_bag.second);
fields3->Set("is_in_effect", 0);
query3.Fields = fields3;
query3.WhereCriteria = new Dictionary();
query3.WhereCriteria->Set("object_id", checkable);
query3.WhereCriteria->Set("internal_downtime_id", downtime->GetLegacyId());
query3.WhereCriteria->Set("entry_time", DbValue::FromTimestamp(downtime->GetEntryTime()));
query3.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
queries.push_back(query3);
/* host/service status */
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
DbQuery query4;
if (service)
query4.Table = "servicestatus";
else
query4.Table = "hoststatus";
query4.Type = DbQueryUpdate;
query4.Category = DbCatState;
query4.StatusUpdate = true;
query4.Object = DbObject::GetOrCreateByObject(checkable);
Dictionary::Ptr fields4 = new Dictionary();
fields4->Set("scheduled_downtime_depth", checkable->GetDowntimeDepth());
query4.Fields = fields4;
query4.WhereCriteria = new Dictionary();
if (service)
query4.WhereCriteria->Set("service_object_id", service);
else
query4.WhereCriteria->Set("host_object_id", host);
query4.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
queries.push_back(query4);
}
void DbEvents::TriggerDowntime(const Downtime::Ptr& downtime)
{
Checkable::Ptr checkable = downtime->GetCheckable();
double now = Utility::GetTime();
std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
/* Status */
DbQuery query1;
query1.Table = "scheduleddowntime";
query1.Type = DbQueryUpdate;
query1.Category = DbCatDowntime;
Dictionary::Ptr fields1 = new Dictionary();
fields1->Set("was_started", 1);
fields1->Set("actual_start_time", DbValue::FromTimestamp(time_bag.first));
fields1->Set("actual_start_time_usec", time_bag.second);
fields1->Set("is_in_effect", (downtime->IsActive() ? 1 : 0));
fields1->Set("trigger_time", DbValue::FromTimestamp(downtime->GetTriggerTime()));
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
query1.WhereCriteria = new Dictionary();
query1.WhereCriteria->Set("object_id", checkable);
query1.WhereCriteria->Set("internal_downtime_id", downtime->GetLegacyId());
query1.Fields = fields1;
DbObject::OnQuery(query1);
/* History - downtime was started for service (and host in case) */
DbQuery query3;
query3.Table = "downtimehistory";
query3.Type = DbQueryUpdate;
query3.Category = DbCatDowntime;
Dictionary::Ptr fields3 = new Dictionary();
fields3->Set("was_started", 1);
fields3->Set("is_in_effect", 1);
fields3->Set("actual_start_time", DbValue::FromTimestamp(time_bag.first));
fields3->Set("actual_start_time_usec", time_bag.second);
fields3->Set("trigger_time", DbValue::FromTimestamp(downtime->GetTriggerTime()));
query3.Fields = fields3;
query3.WhereCriteria = new Dictionary();
query3.WhereCriteria->Set("internal_downtime_id", downtime->GetLegacyId());
query3.WhereCriteria->Set("entry_time", DbValue::FromTimestamp(downtime->GetEntryTime()));
query3.WhereCriteria->Set("scheduled_start_time", DbValue::FromTimestamp(downtime->GetStartTime()));
query3.WhereCriteria->Set("scheduled_end_time", DbValue::FromTimestamp(downtime->GetEndTime()));
query3.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
DbObject::OnQuery(query3);
/* host/service status */
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
DbQuery query4;
if (service)
query4.Table = "servicestatus";
else
query4.Table = "hoststatus";
query4.Type = DbQueryUpdate;
query4.Category = DbCatState;
query4.StatusUpdate = true;
query4.Object = DbObject::GetOrCreateByObject(checkable);
Dictionary::Ptr fields4 = new Dictionary();
fields4->Set("scheduled_downtime_depth", checkable->GetDowntimeDepth());
query4.Fields = fields4;
query4.WhereCriteria = new Dictionary();
if (service)
query4.WhereCriteria->Set("service_object_id", service);
else
query4.WhereCriteria->Set("host_object_id", host);
query4.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
DbObject::OnQuery(query4);
}
/* acknowledgements */
void DbEvents::AddAcknowledgementHistory(const Checkable::Ptr& checkable, const String& author, const String& comment,
AcknowledgementType type, bool notify, double expiry)
{
Log(LogDebug, "DbEvents")
<< "add acknowledgement history for '" << checkable->GetName() << "'";
double now = Utility::GetTime();
std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
unsigned long end_time = static_cast<long>(expiry);
DbQuery query1;
query1.Table = "acknowledgements";
query1.Type = DbQueryInsert;
query1.Category = DbCatAcknowledgement;
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
Dictionary::Ptr fields1 = new Dictionary();
fields1->Set("entry_time", DbValue::FromTimestamp(time_bag.first));
fields1->Set("entry_time_usec", time_bag.second);
fields1->Set("acknowledgement_type", type);
fields1->Set("object_id", checkable);
fields1->Set("state", service ? static_cast<int>(service->GetState()) : static_cast<int>(host->GetState()));
fields1->Set("author_name", author);
fields1->Set("comment_data", comment);
fields1->Set("persistent_comment", 1); //always persistent
fields1->Set("notify_contacts", notify ? 1 : 0);
fields1->Set("is_sticky", type == AcknowledgementSticky ? 1 : 0);
fields1->Set("end_time", DbValue::FromTimestamp(end_time));
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
String node = IcingaApplication::GetInstance()->GetNodeName();
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
if (endpoint)
fields1->Set("endpoint_object_id", endpoint);
query1.Fields = fields1;
DbObject::OnQuery(query1);
}
void DbEvents::AddAcknowledgement(const Checkable::Ptr& checkable, AcknowledgementType type)
{
Log(LogDebug, "DbEvents")
<< "add acknowledgement for '" << checkable->GetName() << "'";
AddAcknowledgementInternal(checkable, type, true);
}
void DbEvents::RemoveAcknowledgement(const Checkable::Ptr& checkable)
{
Log(LogDebug, "DbEvents")
<< "remove acknowledgement for '" << checkable->GetName() << "'";
AddAcknowledgementInternal(checkable, AcknowledgementNone, false);
}
void DbEvents::AddAcknowledgementInternal(const Checkable::Ptr& checkable, AcknowledgementType type, bool add)
{
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
DbQuery query1;
if (service)
query1.Table = "servicestatus";
else
query1.Table = "hoststatus";
query1.Type = DbQueryUpdate;
query1.Category = DbCatState;
query1.StatusUpdate = true;
query1.Object = DbObject::GetOrCreateByObject(checkable);
Dictionary::Ptr fields1 = new Dictionary();
fields1->Set("acknowledgement_type", type);
fields1->Set("problem_has_been_acknowledged", add ? 1 : 0);
query1.Fields = fields1;
query1.WhereCriteria = new Dictionary();
if (service)
query1.WhereCriteria->Set("service_object_id", service);
else
query1.WhereCriteria->Set("host_object_id", host);
query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
DbObject::OnQuery(query1);
}
/* notifications */
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)
{
Log(LogDebug, "DbEvents")
<< "add notification history for '" << checkable->GetName() << "'";
/* start and end happen at the same time */
double now = Utility::GetTime();
std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
DbQuery query1;
query1.Table = "notifications";
query1.Type = DbQueryInsert;
query1.Category = DbCatNotification;
query1.NotificationInsertID = new DbValue(DbValueObjectInsertID, -1);
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
Dictionary::Ptr fields1 = new Dictionary();
fields1->Set("notification_type", 1); /* service */
fields1->Set("notification_reason", CompatUtility::MapNotificationReasonType(type));
fields1->Set("object_id", checkable);
fields1->Set("start_time", DbValue::FromTimestamp(time_bag.first));
fields1->Set("start_time_usec", time_bag.second);
fields1->Set("end_time", DbValue::FromTimestamp(time_bag.first));
fields1->Set("end_time_usec", time_bag.second);
fields1->Set("state", service ? static_cast<int>(service->GetState()) : static_cast<int>(host->GetState()));
if (cr) {
fields1->Set("output", CompatUtility::GetCheckResultOutput(cr));
fields1->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr));
}
fields1->Set("escalated", 0);
fields1->Set("contacts_notified", static_cast<long>(users.size()));
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
String node = IcingaApplication::GetInstance()->GetNodeName();
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
if (endpoint)
fields1->Set("endpoint_object_id", endpoint);
query1.Fields = fields1;
DbObject::OnQuery(query1);
std::vector<DbQuery> queries;
BOOST_FOREACH(const User::Ptr& user, users) {
Log(LogDebug, "DbEvents")
<< "add contact notification history for service '" << checkable->GetName() << "' and user '" << user->GetName() << "'.";
DbQuery query2;
query2.Table = "contactnotifications";
query2.Type = DbQueryInsert;
query2.Category = DbCatNotification;
Dictionary::Ptr fields2 = new Dictionary();
fields2->Set("contact_object_id", user);
fields2->Set("start_time", DbValue::FromTimestamp(time_bag.first));
fields2->Set("start_time_usec", time_bag.second);
fields2->Set("end_time", DbValue::FromTimestamp(time_bag.first));
fields2->Set("end_time_usec", time_bag.second);
fields2->Set("notification_id", query1.NotificationInsertID);
fields2->Set("instance_id", 0); /* DbConnection class fills in real ID */
query2.Fields = fields2;
queries.push_back(query2);
}
DbObject::OnMultipleQueries(queries);
}
/* statehistory */
void DbEvents::AddStateChangeHistory(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, StateType type)
{
Log(LogDebug, "DbEvents")
<< "add state change history for '" << checkable->GetName() << "'";
double ts = cr->GetExecutionEnd();
std::pair<unsigned long, unsigned long> state_time_bag = CompatUtility::ConvertTimestamp(ts);
DbQuery query1;
query1.Table = "statehistory";
query1.Type = DbQueryInsert;
query1.Category = DbCatStateHistory;
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
Dictionary::Ptr fields1 = new Dictionary();
fields1->Set("state_time", DbValue::FromTimestamp(state_time_bag.first));
fields1->Set("state_time_usec", state_time_bag.second);
fields1->Set("object_id", checkable);
fields1->Set("state_change", 1); /* service */
fields1->Set("state", service ? static_cast<int>(service->GetState()) : static_cast<int>(host->GetState()));
fields1->Set("state_type", checkable->GetStateType());
fields1->Set("current_check_attempt", checkable->GetCheckAttempt());
fields1->Set("max_check_attempts", checkable->GetMaxCheckAttempts());
if (service) {
fields1->Set("last_state", service->GetLastState());
fields1->Set("last_hard_state", service->GetLastHardState());
} else {
fields1->Set("last_state", host->GetLastState());
fields1->Set("last_hard_state", host->GetLastHardState());
}
if (cr) {
fields1->Set("output", CompatUtility::GetCheckResultOutput(cr));
fields1->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr));
fields1->Set("check_source", cr->GetCheckSource());
}
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
String node = IcingaApplication::GetInstance()->GetNodeName();
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
if (endpoint)
fields1->Set("endpoint_object_id", endpoint);
query1.Fields = fields1;
DbObject::OnQuery(query1);
}
/* logentries */
void DbEvents::AddCheckResultLogHistory(const Checkable::Ptr& checkable, const CheckResult::Ptr &cr)
{
Dictionary::Ptr vars_after = cr->GetVarsAfter();
long state_after = vars_after->Get("state");
long stateType_after = vars_after->Get("state_type");
long attempt_after = vars_after->Get("attempt");
bool reachable_after = vars_after->Get("reachable");
Dictionary::Ptr vars_before = cr->GetVarsBefore();
if (vars_before) {
long state_before = vars_before->Get("state");
long stateType_before = vars_before->Get("state_type");
long attempt_before = vars_before->Get("attempt");
bool reachable_before = vars_before->Get("reachable");
if (state_before == state_after && stateType_before == stateType_after &&
attempt_before == attempt_after && reachable_before == reachable_after)
return; /* Nothing changed, ignore this checkresult. */
}
LogEntryType type;
String output;
if (cr)
output = CompatUtility::GetCheckResultOutput(cr);
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
std::ostringstream msgbuf;
if (service) {
msgbuf << "SERVICE ALERT: "
<< host->GetName() << ";"
<< service->GetShortName() << ";"
<< Service::StateToString(service->GetState()) << ";"
<< Service::StateTypeToString(service->GetStateType()) << ";"
<< attempt_after << ";"
<< output << ""
<< "";
switch (service->GetState()) {
case ServiceOK:
type = LogEntryTypeServiceOk;
break;
case ServiceUnknown:
type = LogEntryTypeServiceUnknown;
break;
case ServiceWarning:
type = LogEntryTypeServiceWarning;
break;
case ServiceCritical:
type = LogEntryTypeServiceCritical;
break;
default:
Log(LogCritical, "DbEvents")
<< "Unknown service state: " << state_after;
return;
}
} else {
msgbuf << "HOST ALERT: "
<< host->GetName() << ";"
<< CompatUtility::GetHostStateString(host) << ";"
<< Host::StateTypeToString(host->GetStateType()) << ";"
<< attempt_after << ";"
<< output << ""
<< "";
switch (host->GetState()) {
case HostUp:
type = LogEntryTypeHostUp;
break;
case HostDown:
type = LogEntryTypeHostDown;
break;
default:
Log(LogCritical, "DbEvents")
<< "Unknown host state: " << state_after;
return;
}
if (!reachable_after)
type = LogEntryTypeHostUnreachable;
}
AddLogHistory(checkable, msgbuf.str(), type);
}
void DbEvents::AddTriggerDowntimeLogHistory(const Downtime::Ptr& downtime)
{
Checkable::Ptr checkable = downtime->GetCheckable();
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
std::ostringstream msgbuf;
if (service) {
msgbuf << "SERVICE DOWNTIME ALERT: "
<< host->GetName() << ";"
<< service->GetShortName() << ";"
<< "STARTED" << "; "
<< "Service has entered a period of scheduled downtime."
<< "";
} else {
msgbuf << "HOST DOWNTIME ALERT: "
<< host->GetName() << ";"
<< "STARTED" << "; "
<< "Service has entered a period of scheduled downtime."
<< "";
}
AddLogHistory(checkable, msgbuf.str(), LogEntryTypeInfoMessage);
}
void DbEvents::AddRemoveDowntimeLogHistory(const Downtime::Ptr& downtime)
{
Checkable::Ptr checkable = downtime->GetCheckable();
String downtime_output;
String downtime_state_str;
if (downtime->GetWasCancelled()) {
downtime_output = "Scheduled downtime for service has been cancelled.";
downtime_state_str = "CANCELLED";
} else {
downtime_output = "Service has exited from a period of scheduled downtime.";
downtime_state_str = "STOPPED";
}
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
std::ostringstream msgbuf;
if (service) {
msgbuf << "SERVICE DOWNTIME ALERT: "
<< host->GetName() << ";"
<< service->GetShortName() << ";"
<< downtime_state_str << "; "
<< downtime_output
<< "";
} else {
msgbuf << "HOST DOWNTIME ALERT: "
<< host->GetName() << ";"
<< downtime_state_str << "; "
<< downtime_output
<< "";
}
AddLogHistory(checkable, msgbuf.str(), LogEntryTypeInfoMessage);
}
void DbEvents::AddNotificationSentLogHistory(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const User::Ptr& user,
NotificationType notification_type, const CheckResult::Ptr& cr,
const String& author, const String& comment_text)
{
CheckCommand::Ptr commandObj = checkable->GetCheckCommand();
String check_command = "";
if (commandObj)
check_command = commandObj->GetName();
String notification_type_str = Notification::NotificationTypeToString(notification_type);
String author_comment = "";
if (notification_type == NotificationCustom || notification_type == NotificationAcknowledgement) {
author_comment = ";" + author + ";" + comment_text;
}
if (!cr)
return;
String output;
if (cr)
output = CompatUtility::GetCheckResultOutput(cr);
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
std::ostringstream msgbuf;
if (service) {
msgbuf << "SERVICE NOTIFICATION: "
<< user->GetName() << ";"
<< host->GetName() << ";"
<< service->GetShortName() << ";"
<< notification_type_str << " "
<< "(" << Service::StateToString(service->GetState()) << ");"
<< check_command << ";"
<< output << author_comment
<< "";
} else {
msgbuf << "HOST NOTIFICATION: "
<< user->GetName() << ";"
<< host->GetName() << ";"
<< notification_type_str << " "
<< "(" << Host::StateToString(host->GetState()) << ");"
<< check_command << ";"
<< output << author_comment
<< "";
}
AddLogHistory(checkable, msgbuf.str(), LogEntryTypeHostNotification);
}
void DbEvents::AddFlappingChangedLogHistory(const Checkable::Ptr& checkable)
{
String flapping_state_str;
String flapping_output;
if (checkable->IsFlapping()) {
flapping_output = "Service appears to have started flapping (" + Convert::ToString(checkable->GetFlappingCurrent()) + "% change >= " + Convert::ToString(checkable->GetFlappingThreshold()) + "% threshold)";
flapping_state_str = "STARTED";
} else {
flapping_output = "Service appears to have stopped flapping (" + Convert::ToString(checkable->GetFlappingCurrent()) + "% change < " + Convert::ToString(checkable->GetFlappingThreshold()) + "% threshold)";
flapping_state_str = "STOPPED";
}
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
std::ostringstream msgbuf;
if (service) {
msgbuf << "SERVICE FLAPPING ALERT: "
<< host->GetName() << ";"
<< service->GetShortName() << ";"
<< flapping_state_str << "; "
<< flapping_output
<< "";
} else {
msgbuf << "HOST FLAPPING ALERT: "
<< host->GetName() << ";"
<< flapping_state_str << "; "
<< flapping_output
<< "";
}
AddLogHistory(checkable, msgbuf.str(), LogEntryTypeInfoMessage);
}
void DbEvents::AddEnableFlappingChangedLogHistory(const Checkable::Ptr& checkable)
{
if (!checkable->GetEnableFlapping())
return;
String flapping_output = "Flap detection has been disabled";
String flapping_state_str = "DISABLED";
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
std::ostringstream msgbuf;
if (service) {
msgbuf << "SERVICE FLAPPING ALERT: "
<< host->GetName() << ";"
<< service->GetShortName() << ";"
<< flapping_state_str << "; "
<< flapping_output
<< "";
} else {
msgbuf << "HOST FLAPPING ALERT: "
<< host->GetName() << ";"
<< flapping_state_str << "; "
<< flapping_output
<< "";
}
AddLogHistory(checkable, msgbuf.str(), LogEntryTypeInfoMessage);
}
void DbEvents::AddLogHistory(const Checkable::Ptr& checkable, String buffer, LogEntryType type)
{
Log(LogDebug, "DbEvents")
<< "add log entry history for '" << checkable->GetName() << "'";
double now = Utility::GetTime();
std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
DbQuery query1;
query1.Table = "logentries";
query1.Type = DbQueryInsert;
query1.Category = DbCatLog;
Dictionary::Ptr fields1 = new Dictionary();
fields1->Set("logentry_time", DbValue::FromTimestamp(time_bag.first));
fields1->Set("entry_time", DbValue::FromTimestamp(time_bag.first));
fields1->Set("entry_time_usec", time_bag.second);
fields1->Set("object_id", checkable); // added in 1.10 see #4754
fields1->Set("logentry_type", type);
fields1->Set("logentry_data", buffer);
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
String node = IcingaApplication::GetInstance()->GetNodeName();
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
if (endpoint)
fields1->Set("endpoint_object_id", endpoint);
query1.Fields = fields1;
DbObject::OnQuery(query1);
}
/* flappinghistory */
void DbEvents::AddFlappingChangedHistory(const Checkable::Ptr& checkable)
{
Log(LogDebug, "DbEvents")
<< "add flapping history for '" << checkable->GetName() << "'";
double now = Utility::GetTime();
std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
DbQuery query1;
query1.Table = "flappinghistory";
query1.Type = DbQueryInsert;
query1.Category = DbCatFlapping;
Dictionary::Ptr fields1 = new Dictionary();
fields1->Set("event_time", DbValue::FromTimestamp(time_bag.first));
fields1->Set("event_time_usec", time_bag.second);
if (checkable->IsFlapping())
fields1->Set("event_type", 1000);
else {
fields1->Set("event_type", 1001);
fields1->Set("reason_type", 1);
}
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
fields1->Set("flapping_type", service ? 1 : 0);
fields1->Set("object_id", checkable);
fields1->Set("percent_state_change", checkable->GetFlappingCurrent());
fields1->Set("low_threshold", checkable->GetFlappingThreshold());
fields1->Set("high_threshold", checkable->GetFlappingThreshold());
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
String node = IcingaApplication::GetInstance()->GetNodeName();
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
if (endpoint)
fields1->Set("endpoint_object_id", endpoint);
query1.Fields = fields1;
DbObject::OnQuery(query1);
}
void DbEvents::AddEnableFlappingChangedHistory(const Checkable::Ptr& checkable)
{
Log(LogDebug, "DbEvents")
<< "add flapping history for '" << checkable->GetName() << "'";
double now = Utility::GetTime();
std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
DbQuery query1;
query1.Table = "flappinghistory";
query1.Type = DbQueryInsert;
query1.Category = DbCatFlapping;
Dictionary::Ptr fields1 = new Dictionary();
fields1->Set("event_time", DbValue::FromTimestamp(time_bag.first));
fields1->Set("event_time_usec", time_bag.second);
if (!checkable->GetEnableFlapping())
return;
fields1->Set("event_type", 1001);
fields1->Set("reason_type", 2);
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
fields1->Set("flapping_type", service ? 1 : 0);
fields1->Set("object_id", checkable);
fields1->Set("percent_state_change", checkable->GetFlappingCurrent());
fields1->Set("low_threshold", checkable->GetFlappingThreshold());
fields1->Set("high_threshold", checkable->GetFlappingThreshold());
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
String node = IcingaApplication::GetInstance()->GetNodeName();
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
if (endpoint)
fields1->Set("endpoint_object_id", endpoint);
query1.Fields = fields1;
DbObject::OnQuery(query1);
}
/* servicechecks */
void DbEvents::AddCheckableCheckHistory(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr)
{
if (!cr)
return;
Log(LogDebug, "DbEvents")
<< "add checkable check history for '" << checkable->GetName() << "'";
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
std::ostringstream msgbuf;
DbQuery query1;
query1.Table = service ? "servicechecks" : "hostchecks";
query1.Type = DbQueryInsert;
query1.Category = DbCatCheck;
Dictionary::Ptr fields1 = new Dictionary();
fields1->Set("check_type", CompatUtility::GetCheckableCheckType(checkable));
fields1->Set("current_check_attempt", checkable->GetCheckAttempt());
fields1->Set("max_check_attempts", checkable->GetMaxCheckAttempts());
fields1->Set("state_type", checkable->GetStateType());
double start = cr->GetExecutionStart();
std::pair<unsigned long, unsigned long> time_bag_start = CompatUtility::ConvertTimestamp(start);
double end = cr->GetExecutionEnd();
std::pair<unsigned long, unsigned long> time_bag_end = CompatUtility::ConvertTimestamp(end);
double execution_time = Service::CalculateExecutionTime(cr);
fields1->Set("start_time", DbValue::FromTimestamp(time_bag_start.first));
fields1->Set("start_time_usec", time_bag_start.second);
fields1->Set("end_time", DbValue::FromTimestamp(time_bag_end.first));
fields1->Set("end_time_usec", time_bag_end.second);
fields1->Set("command_object_id", checkable->GetCheckCommand());
fields1->Set("command_args", Empty);
fields1->Set("command_line", CompatUtility::GetCommandLine(checkable->GetCheckCommand()));
fields1->Set("execution_time", Convert::ToString(execution_time));
fields1->Set("latency", Convert::ToString(Service::CalculateLatency(cr)));
fields1->Set("return_code", cr->GetExitStatus());
fields1->Set("output", CompatUtility::GetCheckResultOutput(cr));
fields1->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr));
fields1->Set("perfdata", CompatUtility::GetCheckResultPerfdata(cr));
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
if (service) {
fields1->Set("service_object_id", service);
fields1->Set("state", service->GetState());
} else {
fields1->Set("host_object_id", host);
fields1->Set("state", host->GetState());
}
String node = IcingaApplication::GetInstance()->GetNodeName();
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
if (endpoint)
fields1->Set("endpoint_object_id", endpoint);
query1.Fields = fields1;
DbObject::OnQuery(query1);
}
/* eventhandlers */
void DbEvents::AddEventHandlerHistory(const Checkable::Ptr& checkable)
{
Log(LogDebug, "DbEvents")
<< "add eventhandler history for '" << checkable->GetName() << "'";
double now = Utility::GetTime();
std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
DbQuery query1;
query1.Table = "eventhandlers";
query1.Type = DbQueryInsert;
query1.Category = DbCatEventHandler;
Dictionary::Ptr fields1 = new Dictionary();
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
fields1->Set("eventhandler_type", service ? 1 : 0);
fields1->Set("object_id", checkable);
fields1->Set("state", service ? static_cast<int>(service->GetState()) : static_cast<int>(host->GetState()));
fields1->Set("state_type", checkable->GetStateType());
fields1->Set("start_time", DbValue::FromTimestamp(time_bag.first));
fields1->Set("start_time_usec", time_bag.second);
fields1->Set("end_time", DbValue::FromTimestamp(time_bag.first));
fields1->Set("end_time_usec", time_bag.second);
fields1->Set("command_object_id", checkable->GetEventCommand());
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
String node = IcingaApplication::GetInstance()->GetNodeName();
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
if (endpoint)
fields1->Set("endpoint_object_id", endpoint);
query1.Fields = fields1;
DbObject::OnQuery(query1);
}
/* externalcommands */
void DbEvents::AddExternalCommandHistory(double time, const String& command, const std::vector<String>& arguments)
{
Log(LogDebug, "DbEvents", "add external command history");
DbQuery query1;
query1.Table = "externalcommands";
query1.Type = DbQueryInsert;
query1.Category = DbCatExternalCommand;
Dictionary::Ptr fields1 = new Dictionary();
fields1->Set("entry_time", DbValue::FromTimestamp(static_cast<long>(time)));
fields1->Set("command_type", CompatUtility::MapExternalCommandType(command));
fields1->Set("command_name", command);
fields1->Set("command_args", boost::algorithm::join(arguments, ";"));
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
String node = IcingaApplication::GetInstance()->GetNodeName();
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
if (endpoint)
fields1->Set("endpoint_object_id", endpoint);
query1.Fields = fields1;
DbObject::OnQuery(query1);
}