From 25a268c1672782dd4494dccd6933179c80d6dce1 Mon Sep 17 00:00:00 2001 From: Michael Friedrich Date: Wed, 7 Aug 2013 15:39:09 +0200 Subject: [PATCH] ido: Experimental support for comments. refs #4380 --- lib/icinga/service-comment.cpp | 14 +++ lib/icinga/service.h | 15 +++- lib/ido/servicedbobject.cpp | 152 ++++++++++++++++++++++++++++++++- lib/ido/servicedbobject.h | 4 + 4 files changed, 183 insertions(+), 2 deletions(-) diff --git a/lib/icinga/service-comment.cpp b/lib/icinga/service-comment.cpp index 46fe4f35a..850835d52 100644 --- a/lib/icinga/service-comment.cpp +++ b/lib/icinga/service-comment.cpp @@ -37,6 +37,8 @@ static bool l_CommentsCacheNeedsUpdate = false; static Timer::Ptr l_CommentsCacheTimer; static Timer::Ptr l_CommentsExpireTimer; +boost::signals2::signal Service::OnCommentsChanged; + int Service::GetNextCommentID(void) { boost::mutex::scoped_lock lock(l_CommentMutex); @@ -95,11 +97,15 @@ String Service::AddComment(CommentType entryType, const String& author, l_CommentsCache[id] = GetSelf(); } + OnCommentsChanged(GetSelf(), id, CommentChangedAdded); + return id; } void Service::RemoveAllComments(void) { + OnCommentsChanged(GetSelf(), Empty, CommentChangedDeleted); + m_Comments = Empty; Touch("comments"); } @@ -118,6 +124,8 @@ void Service::RemoveComment(const String& id) comments->Remove(id); owner->Touch("comments"); + + OnCommentsChanged(owner, id, CommentChangedDeleted); } } @@ -242,6 +250,8 @@ void Service::RefreshCommentsCache(void) l_CommentsExpireTimer->OnTimerExpired.connect(boost::bind(&Service::CommentsExpireTimerHandler)); l_CommentsExpireTimer->Start(); } + + OnCommentsChanged(Service::Ptr(), Empty, CommentChangedUpdated); } void Service::RemoveCommentsByType(int type) @@ -272,6 +282,8 @@ void Service::RemoveCommentsByType(int type) ObjectLock olock(this); Touch("comments"); } + + OnCommentsChanged(GetSelf(), Empty, CommentChangedDeleted); } void Service::RemoveExpiredComments(void) @@ -302,6 +314,8 @@ void Service::RemoveExpiredComments(void) ObjectLock olock(this); Touch("comments"); } + + OnCommentsChanged(GetSelf(), Empty, CommentChangedDeleted); } void Service::CommentsExpireTimerHandler(void) diff --git a/lib/icinga/service.h b/lib/icinga/service.h index 34832eb3f..3bd47c6a4 100644 --- a/lib/icinga/service.h +++ b/lib/icinga/service.h @@ -74,7 +74,7 @@ enum DowntimeState }; /** - * The sate of service flapping. + * The state of service flapping. * * @ingroup icinga */ @@ -85,6 +85,18 @@ enum FlappingState FlappingStopped = 2 }; +/** + * The state of a changed comment + * + * @ingroup icinga + */ +enum CommentChangedType +{ + CommentChangedAdded = 0, + CommentChangedUpdated = 1, + CommentChangedDeleted = 2 +}; + class CheckCommand; class EventCommand; @@ -232,6 +244,7 @@ public: static boost::signals2::signal OnNotificationSentChanged; static boost::signals2::signal OnDowntimeChanged; static boost::signals2::signal OnFlappingChanged; + static boost::signals2::signal OnCommentsChanged; virtual bool ResolveMacro(const String& macro, const Dictionary::Ptr& cr, String *result) const; diff --git a/lib/ido/servicedbobject.cpp b/lib/ido/servicedbobject.cpp index 3b8f2b180..7b8bbd25b 100644 --- a/lib/ido/servicedbobject.cpp +++ b/lib/ido/servicedbobject.cpp @@ -21,17 +21,26 @@ #include "ido/dbtype.h" #include "ido/dbvalue.h" #include "base/objectlock.h" -#include "icinga/service.h" +#include "base/initialize.h" +#include "base/dynamictype.h" #include "icinga/notification.h" #include "icinga/checkcommand.h" #include "icinga/eventcommand.h" #include "icinga/compatutility.h" #include +#include using namespace icinga; REGISTER_DBTYPE(Service, "service", DbObjectTypeService, "service_object_id", ServiceDbObject); +INITIALIZE_ONCE(ServiceDbObject, &ServiceDbObject::StaticInitialize); + +void ServiceDbObject::StaticInitialize(void) +{ + Service::OnCommentsChanged.connect(boost::bind(&ServiceDbObject::CommentsChangedHandler, _1, _2, _3)); +} + ServiceDbObject::ServiceDbObject(const DbType::Ptr& type, const String& name1, const String& name2) : DbObject(type, name1, name2) { } @@ -230,3 +239,144 @@ void ServiceDbObject::OnStatusUpdate(void) dbobj->SendStatusUpdate(); } + +void ServiceDbObject::CommentsChangedHandler(const Service::Ptr& svcfilter, const String& id, CommentChangedType type) +{ + unsigned long entry_time; + unsigned long entry_time_usec; + Service::Ptr service; + Host::Ptr host; + Dictionary::Ptr comment; + DbQuery query1, query2, query_del1; + Dictionary::Ptr fields1, fields2; + + if (type == CommentChangedUpdated || type == CommentChangedDeleted) { + + /* we cannot determine which comment id is deleted + * ido schema does not store legacy id + */ + BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) { + service = static_pointer_cast(object); + + if (svcfilter && svcfilter != service) + continue; + + host = service->GetHost(); + + if (!host) + continue; + + /* delete all comments associated for this host/service */ + Log(LogDebug, "ido", "delete comments for '" + service->GetName() + "'"); + + query_del1; + query_del1.Table = "comments"; + query_del1.Type = DbQueryDelete; + query_del1.WhereCriteria = boost::make_shared(); + if (host->GetHostCheckService() == service) + query_del1.WhereCriteria->Set("object_id", host); + else + query_del1.WhereCriteria->Set("object_id", service); + + OnQuery(query_del1); + + /* dump all comments */ + Dictionary::Ptr comments = service->GetComments(); + + if (!comments) + continue; + + ObjectLock olock(comments); + + String cid; + BOOST_FOREACH(boost::tie(cid, comment), comments) { + Log(LogDebug, "ido", "adding service comment (id = " + cid + ") for '" + service->GetName() + "'"); + + entry_time = static_cast(comment->Get("entry_time")); + entry_time_usec = (comment->Get("entry_time") - entry_time) * 1000 * 1000; + + Dictionary::Ptr fields1 = boost::make_shared(); + fields1->Set("entry_time", DbValue::FromTimestamp(entry_time)); + fields1->Set("entry_time_usec", entry_time_usec); + fields1->Set("entry_type", comment->Get("entry_type")); + + if (host->GetHostCheckService() == service) { + fields1->Set("comment_type", 2); + fields1->Set("object_id", host); + } else { + fields1->Set("comment_type", 1); + fields1->Set("object_id", service); + } + + fields1->Set("comment_time", DbValue::FromTimestamp(Utility::GetTime())); + fields1->Set("internal_comment_id", comment->Get("legacy_id")); /* not sure if that's accurate? */ + fields1->Set("author_name", comment->Get("author")); + fields1->Set("comment_data", comment->Get("text")); + fields1->Set("is_persistent", 1); + fields1->Set("comment_source", 1); /* external */ + fields1->Set("expires", (comment->Get("expire_time") > 0) ? 1 : 0); + fields1->Set("expiration_time", comment->Get("expire_time")); + fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */ + + DbQuery query1; + query1.Table = "comments"; + query1.Type = DbQueryInsert; + query1.Fields = fields1; + OnQuery(query1); + } + } + + } else if (type == CommentChangedAdded) { + + service = svcfilter; + host = service->GetHost(); + + if (!host) + return; + + Dictionary::Ptr add_comment = Service::GetCommentByID(id); + + if (!add_comment || id.IsEmpty()) { + Log(LogWarning, "ido", "comment with id '" + id + "' does not exist. not adding it."); + return; + } + + /* newly added comment */ + Log(LogDebug, "ido", "adding service comment (id = " + id + ") for '" + service->GetName() + "'"); + + entry_time = static_cast(comment->Get("entry_time")); + entry_time_usec = (add_comment->Get("entry_time") - entry_time) * 1000 * 1000; + + fields2 = boost::make_shared(); + fields2->Set("entry_time", DbValue::FromTimestamp(entry_time)); + fields2->Set("entry_time_usec", entry_time_usec); + fields2->Set("entry_type", add_comment->Get("entry_type")); + + if (host->GetHostCheckService() == service) { + fields2->Set("comment_type", 2); + fields2->Set("object_id", host); + } else { + fields2->Set("comment_type", 1); + fields2->Set("object_id", service); + } + + fields2->Set("comment_time", DbValue::FromTimestamp(Utility::GetTime())); + fields2->Set("internal_comment_id", add_comment->Get("legacy_id")); /* not sure if that's accurate? */ + fields2->Set("author_name", add_comment->Get("author")); + fields2->Set("comment_data", add_comment->Get("text")); + fields2->Set("is_persistent", 1); + fields2->Set("comment_source", 1); /* external */ + fields2->Set("expires", (add_comment->Get("expire_time") > 0) ? 1 : 0); + fields2->Set("expiration_time", add_comment->Get("expire_time")); + fields2->Set("instance_id", 0); /* DbConnection class fills in real ID */ + + query2; + query2.Table = "comments"; + query2.Type = DbQueryInsert; + query2.Fields = fields2; + OnQuery(query2); + + } else { + Log(LogDebug, "ido", "invalid comment change type: " + type); + } +} diff --git a/lib/ido/servicedbobject.h b/lib/ido/servicedbobject.h index a00f75613..f1e5218bf 100644 --- a/lib/ido/servicedbobject.h +++ b/lib/ido/servicedbobject.h @@ -22,6 +22,7 @@ #include "ido/dbobject.h" #include "base/dynamicobject.h" +#include "icinga/service.h" namespace icinga { @@ -38,6 +39,8 @@ public: ServiceDbObject(const DbType::Ptr& type, const String& name1, const String& name2); + static void StaticInitialize(void); + virtual Dictionary::Ptr GetConfigFields(void) const; virtual Dictionary::Ptr GetStatusFields(void) const; @@ -47,6 +50,7 @@ protected: virtual void OnConfigUpdate(void); virtual void OnStatusUpdate(void); + static void CommentsChangedHandler(const Service::Ptr& service, const String& id, CommentChangedType type); }; } -- 2.40.0