]> granicus.if.org Git - icinga2/commitdiff
Fix persistent comments for Acknowledgements 4956/head
authorRune Darrud <theflyingcorpse@gmail.com>
Wed, 25 Jan 2017 20:21:22 +0000 (21:21 +0100)
committerMichael Friedrich <michael.friedrich@icinga.com>
Wed, 10 May 2017 15:10:22 +0000 (17:10 +0200)
fixes #4818

Signed-off-by: Michael Friedrich <michael.friedrich@icinga.com>
15 files changed:
doc/12-icinga2-api.md
doc/9-object-types.md
lib/db_ido/dbevents.cpp
lib/icinga/apiactions.cpp
lib/icinga/apievents.cpp
lib/icinga/apievents.hpp
lib/icinga/checkable-comment.cpp
lib/icinga/checkable.cpp
lib/icinga/checkable.hpp
lib/icinga/clusterevents.cpp
lib/icinga/clusterevents.hpp
lib/icinga/comment.cpp
lib/icinga/comment.hpp
lib/icinga/comment.ti
lib/icinga/externalcommandprocessor.cpp

index 0c92e3af27360faf5a6aae356c60b71661b013c8..594c8da5639f32727cba69bccba9cbd27651f501 100644 (file)
@@ -905,13 +905,14 @@ are disabled.
 
 Send a `POST` request to the URL endpoint `/v1/actions/acknowledge-problem`.
 
-  Parameter | Type      | Description
-  ----------|-----------|--------------
-  author    | string    | **Required.** Name of the author, may be empty.
-  comment   | string    | **Required.** Comment text, may be empty.
-  expiry    | timestamp | **Optional.** Whether the acknowledgement will be removed at the timestamp.
-  sticky    | boolean   | **Optional.** Whether the acknowledgement will be set until the service or host fully recovers. Defaults to `false`.
-  notify    | boolean   | **Optional.** Whether a notification of the `Acknowledgement` type will be sent. Defaults to `false`.
+  Parameter            | Type      | Description
+  ---------------------|-----------|--------------
+  author               | string    | **Required.** Name of the author, may be empty.
+  comment              | string    | **Required.** Comment text, may be empty.
+  expiry               | timestamp | **Optional.** Whether the acknowledgement will be removed at the timestamp.
+  sticky               | boolean   | **Optional.** Whether the acknowledgement will be set until the service or host fully recovers. Defaults to `false`.
+  notify               | boolean   | **Optional.** Whether a notification of the `Acknowledgement` type will be sent. Defaults to `false`.
+  persistent           | boolean   | **Optional.** When the comment is of type `Acknowledgement` and this is set to `true`, the comment will remain after the acknowledgement recovers or expires. Defaults to `false`.
 
 In addition to these parameters a [filter](12-icinga2-api.md#icinga2-api-filters) must be provided. The valid types for this action are `Host` and `Service`.
 
index 0dda7f9c1207a0b688987503315f8f8968be1d13..d7b53b444772f5608f371af1d82db6b3aa8e4dda 100644 (file)
@@ -252,6 +252,7 @@ Configuration Attributes:
   entry_time      | **Optional.** The unix timestamp when this comment was added.
   entry_type      | **Optional.** The comment type (`User` = 1, `Downtime` = 2, `Flapping` = 3, `Acknowledgement` = 4).
   expire_time     | **Optional.** The comment's expire time as unix timestamp.
+  persistent      | **Optional.** Only evaluated for `entry_type` Acknowledgement. `true` does not remove the comment when the acknowledgement is removed.
 
 ## <a id="objecttype-compatlogger"></a> CompatLogger
 
index 0a6a0d578c3d34da9450ebc06573e77f1e04e034..d5e39d52dc6e115e98eb9f78c68f52cda4ded8cc 100644 (file)
@@ -354,7 +354,7 @@ void DbEvents::AddCommentInternal(std::vector<DbQuery>& queries, const Comment::
        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("is_persistent", comment->GetPersistent() ? 1 : 0);
        fields1->Set("comment_source", 1); /* external */
        fields1->Set("expires", (comment->GetExpireTime() > 0) ? 1 : 0);
        fields1->Set("expiration_time", DbValue::FromTimestamp(comment->GetExpireTime()));
index d4211357b507db8bda2e47e69914f1a2ed0a00a5..dacd8fc71afd870d2a869bbc81cdbd33dbaf276e 100644 (file)
@@ -194,12 +194,15 @@ Dictionary::Ptr ApiActions::AcknowledgeProblem(const ConfigObject::Ptr& object,
 
        AcknowledgementType sticky = AcknowledgementNormal;
        bool notify = false;
+       bool persistent = false;
        double timestamp = 0.0;
 
        if (params->Contains("sticky") && HttpUtility::GetLastParameter(params, "sticky"))
                sticky = AcknowledgementSticky;
        if (params->Contains("notify"))
                notify = HttpUtility::GetLastParameter(params, "notify");
+       if (params->Contains("persistent"))
+               persistent = HttpUtility::GetLastParameter(params, "persistent");
        if (params->Contains("expiry"))
                timestamp = HttpUtility::GetLastParameter(params, "expiry");
        else
@@ -218,7 +221,7 @@ Dictionary::Ptr ApiActions::AcknowledgeProblem(const ConfigObject::Ptr& object,
        }
 
        Comment::AddComment(checkable, CommentAcknowledgement, HttpUtility::GetLastParameter(params, "author"),
-           HttpUtility::GetLastParameter(params, "comment"), timestamp);
+           HttpUtility::GetLastParameter(params, "comment"), persistent, timestamp);
        checkable->AcknowledgeProblem(HttpUtility::GetLastParameter(params, "author"),
            HttpUtility::GetLastParameter(params, "comment"), sticky, notify, timestamp);
 
@@ -254,7 +257,7 @@ Dictionary::Ptr ApiActions::AddComment(const ConfigObject::Ptr& object,
 
        String commentName = Comment::AddComment(checkable, CommentUser,
            HttpUtility::GetLastParameter(params, "author"),
-           HttpUtility::GetLastParameter(params, "comment"), 0);
+           HttpUtility::GetLastParameter(params, "comment"), false, 0);
 
        Comment::Ptr comment = Comment::GetByName(commentName);
 
index cd69bfdd74b141726d2454b67079a224e76d8366..0fb38e19013fc126b4349e8b80f69e9adcc5b7a0 100644 (file)
@@ -178,7 +178,7 @@ void ApiEvents::FlappingChangedHandler(const Checkable::Ptr& checkable, const Me
 
 void ApiEvents::AcknowledgementSetHandler(const Checkable::Ptr& checkable,
     const String& author, const String& comment, AcknowledgementType type,
-    bool notify, double expiry, const MessageOrigin::Ptr& origin)
+    bool notify, bool persistent, double expiry, const MessageOrigin::Ptr& origin)
 {
        std::vector<EventQueue::Ptr> queues = EventQueue::GetQueuesForType("AcknowledgementSet");
 
@@ -206,6 +206,7 @@ void ApiEvents::AcknowledgementSetHandler(const Checkable::Ptr& checkable,
        result->Set("comment", comment);
        result->Set("acknowledgement_type", type);
        result->Set("notify", notify);
+       result->Set("persistent", persistent);
        result->Set("expiry", expiry);
 
        for (const EventQueue::Ptr& queue : queues) {
index 2ca07b4ee97d72013fda2fb4ee582de4ed5c4ec3..a71615b41f3e2f28ce8faa2f2dcd53f8472a6f9e 100644 (file)
@@ -46,7 +46,7 @@ public:
 
        static void AcknowledgementSetHandler(const Checkable::Ptr& checkable,
            const String& author, const String& comment, AcknowledgementType type,
-           bool notify, double expiry, const MessageOrigin::Ptr& origin);
+           bool notify, bool persistent, double expiry, const MessageOrigin::Ptr& origin);
        static void AcknowledgementClearedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin);
 
        static void CommentAddedHandler(const Comment::Ptr& comment);
index e91321b296f7f3b568bf80e0bcdf0aba551f0d8a..97a0fcff40714a78238ba5b545d28fd3f668734b 100644 (file)
@@ -38,6 +38,10 @@ void Checkable::RemoveAllComments(void)
 void Checkable::RemoveCommentsByType(int type)
 {
        for (const Comment::Ptr& comment : GetComments()) {
+               /* Do not remove persistent comments from an acknowledgement */
+               if (comment->GetEntryType() == CommentAcknowledgement && comment->GetPersistent())
+                       continue;
+
                if (comment->GetEntryType() == type)
                        Comment::RemoveComment(comment->GetName());
        }
index d34204a5a7d7110580ac2aa2c7bf18d0277a0e1d..100b8ed2b65fd48e6b35376501f4b184411451d8 100644 (file)
@@ -30,7 +30,7 @@ using namespace icinga;
 REGISTER_TYPE_WITH_PROTOTYPE(Checkable, Checkable::GetPrototype());
 INITIALIZE_ONCE(&Checkable::StaticInitialize);
 
-boost::signals2::signal<void (const Checkable::Ptr&, const String&, const String&, AcknowledgementType, bool, double, const MessageOrigin::Ptr&)> Checkable::OnAcknowledgementSet;
+boost::signals2::signal<void (const Checkable::Ptr&, const String&, const String&, AcknowledgementType, bool, bool, double, const MessageOrigin::Ptr&)> Checkable::OnAcknowledgementSet;
 boost::signals2::signal<void (const Checkable::Ptr&, const MessageOrigin::Ptr&)> Checkable::OnAcknowledgementCleared;
 
 void Checkable::StaticInitialize(void)
@@ -122,7 +122,7 @@ bool Checkable::IsAcknowledged(void) const
        return const_cast<Checkable *>(this)->GetAcknowledgement() != AcknowledgementNone;
 }
 
-void Checkable::AcknowledgeProblem(const String& author, const String& comment, AcknowledgementType type, bool notify, double expiry, const MessageOrigin::Ptr& origin)
+void Checkable::AcknowledgeProblem(const String& author, const String& comment, AcknowledgementType type, bool notify, bool persistent, double expiry, const MessageOrigin::Ptr& origin)
 {
        SetAcknowledgementRaw(type);
        SetAcknowledgementExpiry(expiry);
@@ -130,7 +130,7 @@ void Checkable::AcknowledgeProblem(const String& author, const String& comment,
        if (notify && !IsPaused())
                OnNotificationsRequested(this, NotificationAcknowledgement, GetLastCheckResult(), author, comment, MessageOrigin::Ptr());
 
-       OnAcknowledgementSet(this, author, comment, type, notify, expiry, origin);
+       OnAcknowledgementSet(this, author, comment, type, notify, persistent, expiry, origin);
 }
 
 void Checkable::ClearAcknowledgement(const MessageOrigin::Ptr& origin)
index c24a421af788802010715b033aff01452b8bee60..03fd5ae141e9eae8fad937e37ac91b5199c47646 100644 (file)
@@ -98,7 +98,7 @@ public:
 
        AcknowledgementType GetAcknowledgement(void);
 
-       void AcknowledgeProblem(const String& author, const String& comment, AcknowledgementType type, bool notify = true, double expiry = 0, const MessageOrigin::Ptr& origin = MessageOrigin::Ptr());
+       void AcknowledgeProblem(const String& author, const String& comment, AcknowledgementType type, bool notify = true, bool persistent = false, double expiry = 0, const MessageOrigin::Ptr& origin = MessageOrigin::Ptr());
        void ClearAcknowledgement(const MessageOrigin::Ptr& origin = MessageOrigin::Ptr());
 
        virtual int GetSeverity(void) const override;
@@ -139,7 +139,7 @@ public:
            const NotificationType&, const CheckResult::Ptr&, const String&,
            const String&, const MessageOrigin::Ptr&)> OnNotificationSentToAllUsers;
        static boost::signals2::signal<void (const Checkable::Ptr&, const String&, const String&, AcknowledgementType,
-                                            bool, double, const MessageOrigin::Ptr&)> OnAcknowledgementSet;
+                                            bool, bool, double, const MessageOrigin::Ptr&)> OnAcknowledgementSet;
        static boost::signals2::signal<void (const Checkable::Ptr&, const MessageOrigin::Ptr&)> OnAcknowledgementCleared;
        static boost::signals2::signal<void (const Checkable::Ptr&)> OnNextCheckUpdated;
        static boost::signals2::signal<void (const Checkable::Ptr&)> OnEventCommandExecuted;
index aa5ce9b43af56bae1958a803bc1a17a855b0395e..11151467a7964bdcc22c8468391803ac93f71338 100644 (file)
@@ -445,7 +445,7 @@ Value ClusterEvents::ForceNextNotificationChangedAPIHandler(const MessageOrigin:
 
 void ClusterEvents::AcknowledgementSetHandler(const Checkable::Ptr& checkable,
     const String& author, const String& comment, AcknowledgementType type,
-    bool notify, double expiry, const MessageOrigin::Ptr& origin)
+    bool notify, bool persistent, double expiry, const MessageOrigin::Ptr& origin)
 {
        ApiListener::Ptr listener = ApiListener::GetInstance();
 
@@ -510,7 +510,7 @@ Value ClusterEvents::AcknowledgementSetAPIHandler(const MessageOrigin::Ptr& orig
 
        checkable->AcknowledgeProblem(params->Get("author"), params->Get("comment"),
            static_cast<AcknowledgementType>(static_cast<int>(params->Get("acktype"))),
-           params->Get("notify"), params->Get("expiry"), origin);
+           params->Get("notify"), params->Get("persistent"), params->Get("expiry"), origin);
 
        return Empty;
 }
index 6078af5d6ef00218a077aa311d711f24c126040b..702f145ef662010eb6db7480d9be771f11367de0 100644 (file)
@@ -53,7 +53,7 @@ public:
        static Value ForceNextNotificationChangedAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
 
        static void AcknowledgementSetHandler(const Checkable::Ptr& checkable, const String& author, const String& comment, AcknowledgementType type,
-           bool notify, double expiry, const MessageOrigin::Ptr& origin);
+           bool notify, bool persistent, double expiry, const MessageOrigin::Ptr& origin);
        static Value AcknowledgementSetAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
 
        static void AcknowledgementClearedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin);
index 138a9863b8c1fc20a1f88164d5384ac5c861ad1e..fc267039c0c5f3f6c2e08a0877ecc7ad1f4004e9 100644 (file)
@@ -150,7 +150,7 @@ int Comment::GetNextCommentID(void)
 }
 
 String Comment::AddComment(const Checkable::Ptr& checkable, CommentType entryType, const String& author,
-    const String& text, double expireTime, const String& id, const MessageOrigin::Ptr& origin)
+    const String& text, bool persistent, double expireTime, const String& id, const MessageOrigin::Ptr& origin)
 {
        String fullName;
 
@@ -163,6 +163,7 @@ String Comment::AddComment(const Checkable::Ptr& checkable, CommentType entryTyp
 
        attrs->Set("author", author);
        attrs->Set("text", text);
+       attrs->Set("persistent", persistent);
        attrs->Set("expire_time", expireTime);
        attrs->Set("entry_type", entryType);
        attrs->Set("entry_time", Utility::GetTime());
@@ -247,8 +248,13 @@ void Comment::CommentsExpireTimerHandler(void)
        }
 
        for (const Comment::Ptr& comment : comments) {
-               /* Only remove comment which are activated after daemon start. */
-               if (comment->IsActive() && comment->IsExpired())
+               /* Only remove comments which are activated after daemon start. */
+               if (comment->IsActive() && comment->IsExpired()) {
+                       /* Do not remove persistent comments from an acknowledgement */
+                       if (comment->GetEntryType() == CommentAcknowledgement && comment->GetPersistent())
+                               continue;
+
                        RemoveComment(comment->GetName());
+               }
        }
 }
index 078f64e30ffea8017915551de072fe59fc98e57e..67669ba08a7eada88df8cc8defa06ef7792a32c7 100644 (file)
@@ -49,7 +49,7 @@ public:
        static int GetNextCommentID(void);
 
        static String AddComment(const intrusive_ptr<Checkable>& checkable, CommentType entryType,
-           const String& author, const String& text, double expireTime,
+           const String& author, const String& text, bool persistent, double expireTime,
            const String& id = String(), const MessageOrigin::Ptr& origin = MessageOrigin::Ptr());
 
        static void RemoveComment(const String& id, const MessageOrigin::Ptr& origin = MessageOrigin::Ptr());
index 0187b49fe16836d9c0cd32f6ecd8cd3e5cc4fc1f..aaf3e39863b3e98a2bee179a901ae53d487a8306 100644 (file)
@@ -87,6 +87,7 @@ class Comment : ConfigObject < CommentNameComposer
        };
        [config, required] String author;
        [config, required] String text;
+       [config] bool persistent;
        [config] Timestamp expire_time;
        [state] int legacy_id;
 };
index 75e21bf9187c5b5e033eeffe4924186265106292..a7d97ad0179634c9aa577c4a89ccf7ba2f5b474d 100644 (file)
@@ -621,6 +621,7 @@ void ExternalCommandProcessor::AcknowledgeSvcProblem(double, const std::vector<S
 {
        bool sticky = (Convert::ToLong(arguments[2]) == 2 ? true : false);
        bool notify = (Convert::ToLong(arguments[3]) > 0 ? true : false);
+       bool persistent = (Convert::ToLong(arguments[4]) > 0 ? true : false);
 
        Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]);
 
@@ -633,14 +634,15 @@ void ExternalCommandProcessor::AcknowledgeSvcProblem(double, const std::vector<S
        Log(LogNotice, "ExternalCommandProcessor")
            << "Setting acknowledgement for service '" << service->GetName() << "'" << (notify ? "" : ". Disabled notification");
 
-       Comment::AddComment(service, CommentAcknowledgement, arguments[5], arguments[6], 0);
-       service->AcknowledgeProblem(arguments[5], arguments[6], sticky ? AcknowledgementSticky : AcknowledgementNormal, notify);
+       Comment::AddComment(service, CommentAcknowledgement, arguments[5], arguments[6], persistent, 0);
+       service->AcknowledgeProblem(arguments[5], arguments[6], sticky ? AcknowledgementSticky : AcknowledgementNormal, persistent, notify);
 }
 
 void ExternalCommandProcessor::AcknowledgeSvcProblemExpire(double, const std::vector<String>& arguments)
 {
        bool sticky = (Convert::ToLong(arguments[2]) == 2 ? true : false);
        bool notify = (Convert::ToLong(arguments[3]) > 0 ? true : false);
+       bool persistent = (Convert::ToLong(arguments[4]) > 0 ? true : false);
        double timestamp = Convert::ToDouble(arguments[5]);
 
        Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]);
@@ -654,8 +656,8 @@ void ExternalCommandProcessor::AcknowledgeSvcProblemExpire(double, const std::ve
        Log(LogNotice, "ExternalCommandProcessor")
            << "Setting timed acknowledgement for service '" << service->GetName() << "'" << (notify ? "" : ". Disabled notification");
 
-       Comment::AddComment(service, CommentAcknowledgement, arguments[6], arguments[7], timestamp);
-       service->AcknowledgeProblem(arguments[6], arguments[7], sticky ? AcknowledgementSticky : AcknowledgementNormal, notify, timestamp);
+       Comment::AddComment(service, CommentAcknowledgement, arguments[6], arguments[7], persistent, timestamp);
+       service->AcknowledgeProblem(arguments[6], arguments[7], sticky ? AcknowledgementSticky : AcknowledgementNormal, notify, persistent, timestamp);
 }
 
 void ExternalCommandProcessor::RemoveSvcAcknowledgement(double, const std::vector<String>& arguments)
@@ -680,6 +682,7 @@ void ExternalCommandProcessor::AcknowledgeHostProblem(double, const std::vector<
 {
        bool sticky = (Convert::ToLong(arguments[1]) == 2 ? true : false);
        bool notify = (Convert::ToLong(arguments[2]) > 0 ? true : false);
+       bool persistent = (Convert::ToLong(arguments[3]) > 0 ? true : false);
 
        Host::Ptr host = Host::GetByName(arguments[0]);
 
@@ -692,14 +695,15 @@ void ExternalCommandProcessor::AcknowledgeHostProblem(double, const std::vector<
        if (host->GetState() == HostUp)
                BOOST_THROW_EXCEPTION(std::invalid_argument("The host '" + arguments[0] + "' is OK."));
 
-       Comment::AddComment(host, CommentAcknowledgement, arguments[4], arguments[5], 0);
-       host->AcknowledgeProblem(arguments[4], arguments[5], sticky ? AcknowledgementSticky : AcknowledgementNormal, notify);
+       Comment::AddComment(host, CommentAcknowledgement, arguments[4], arguments[5], persistent, 0);
+       host->AcknowledgeProblem(arguments[4], arguments[5], sticky ? AcknowledgementSticky : AcknowledgementNormal, persistent, notify);
 }
 
 void ExternalCommandProcessor::AcknowledgeHostProblemExpire(double, const std::vector<String>& arguments)
 {
        bool sticky = (Convert::ToLong(arguments[1]) == 2 ? true : false);
        bool notify = (Convert::ToLong(arguments[2]) > 0 ? true : false);
+       bool persistent = (Convert::ToLong(arguments[3]) > 0 ? true : false);
        double timestamp = Convert::ToDouble(arguments[4]);
 
        Host::Ptr host = Host::GetByName(arguments[0]);
@@ -713,8 +717,8 @@ void ExternalCommandProcessor::AcknowledgeHostProblemExpire(double, const std::v
        if (host->GetState() == HostUp)
                BOOST_THROW_EXCEPTION(std::invalid_argument("The host '" + arguments[0] + "' is OK."));
 
-       Comment::AddComment(host, CommentAcknowledgement, arguments[5], arguments[6], timestamp);
-       host->AcknowledgeProblem(arguments[5], arguments[6], sticky ? AcknowledgementSticky : AcknowledgementNormal, notify, timestamp);
+       Comment::AddComment(host, CommentAcknowledgement, arguments[5], arguments[6], persistent, timestamp);
+       host->AcknowledgeProblem(arguments[5], arguments[6], sticky ? AcknowledgementSticky : AcknowledgementNormal, notify, persistent, timestamp);
 }
 
 void ExternalCommandProcessor::RemoveHostAcknowledgement(double, const std::vector<String>& arguments)
@@ -1286,7 +1290,7 @@ void ExternalCommandProcessor::AddHostComment(double, const std::vector<String>&
 
        Log(LogNotice, "ExternalCommandProcessor")
            << "Creating comment for host " << host->GetName();
-       (void) Comment::AddComment(host, CommentUser, arguments[2], arguments[3], 0);
+       (void) Comment::AddComment(host, CommentUser, arguments[2], arguments[3], false, 0);
 }
 
 void ExternalCommandProcessor::DelHostComment(double, const std::vector<String>& arguments)
@@ -1310,7 +1314,7 @@ void ExternalCommandProcessor::AddSvcComment(double, const std::vector<String>&
 
        Log(LogNotice, "ExternalCommandProcessor")
            << "Creating comment for service " << service->GetName();
-       (void) Comment::AddComment(service, CommentUser, arguments[3], arguments[4], 0);
+       (void) Comment::AddComment(service, CommentUser, arguments[3], arguments[4], false, 0);
 }
 
 void ExternalCommandProcessor::DelSvcComment(double, const std::vector<String>& arguments)