]> granicus.if.org Git - icinga2/blobdiff - lib/icinga/notification-apply.cpp
Move the VMFrame class to libbase
[icinga2] / lib / icinga / notification-apply.cpp
index 5149a2aa13e392fae3b96a40697a2a2103c355e9..ed829f1e584507404d434fd6dddc29576e838b8c 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  * Icinga 2                                                                   *
- * Copyright (C) 2012-present Icinga Development Team (http://www.icinga.org) *
+ * Copyright (C) 2012-2014 Icinga Development Team (http://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                *
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
  ******************************************************************************/
 
-#include "icinga/service.h"
-#include "config/configitembuilder.h"
-#include "base/initialize.h"
-#include "base/dynamictype.h"
-#include "base/convert.h"
-#include "base/logger_fwd.h"
-#include "base/context.h"
+#include "icinga/notification.hpp"
+#include "icinga/service.hpp"
+#include "config/configitembuilder.hpp"
+#include "config/applyrule.hpp"
+#include "config/configcompilercontext.hpp"
+#include "base/initialize.hpp"
+#include "base/dynamictype.hpp"
+#include "base/logger.hpp"
+#include "base/context.hpp"
+#include "base/workqueue.hpp"
+#include "base/scripterror.hpp"
 #include <boost/foreach.hpp>
 
 using namespace icinga;
@@ -35,10 +39,42 @@ void Notification::RegisterApplyRuleHandler(void)
        std::vector<String> targets;
        targets.push_back("Host");
        targets.push_back("Service");
-       ApplyRule::RegisterType("Notification", targets, &Notification::EvaluateApplyRules);
+       ApplyRule::RegisterType("Notification", targets);
 }
 
-void Notification::EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyRule& rule)
+void Notification::EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, const String& name, ScriptFrame& frame, const ApplyRule& rule)
+{
+       DebugInfo di = rule.GetDebugInfo();
+
+       Log(LogDebug, "Notification")
+           << "Applying notification '" << name << "' to object '" << checkable->GetName() << "' for rule " << di;
+
+       ConfigItemBuilder::Ptr builder = new ConfigItemBuilder(di);
+       builder->SetType("Notification");
+       builder->SetName(name);
+       builder->SetScope(frame.Locals);
+
+       Host::Ptr host;
+       Service::Ptr service;
+       tie(host, service) = GetHostService(checkable);
+
+       builder->AddExpression(new SetExpression(MakeIndexer("host_name"), OpSetLiteral, MakeLiteral(host->GetName()), false, di));
+
+       if (service)
+               builder->AddExpression(new SetExpression(MakeIndexer("service_name"), OpSetLiteral, MakeLiteral(service->GetShortName()), false, di));
+
+       String zone = checkable->GetZone();
+
+       if (!zone.IsEmpty())
+               builder->AddExpression(new SetExpression(MakeIndexer("zone"), OpSetLiteral, MakeLiteral(zone), false, di));
+
+       builder->AddExpression(new OwnedExpression(rule.GetExpression()));
+
+       ConfigItem::Ptr notificationItem = builder->Compile();
+       notificationItem->Commit();
+}
+
+bool Notification::EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyRule& rule)
 {
        DebugInfo di = rule.GetDebugInfo();
 
@@ -50,68 +86,92 @@ void Notification::EvaluateApplyRule(const Checkable::Ptr& checkable, const Appl
        Service::Ptr service;
        tie(host, service) = GetHostService(checkable);
 
-       Dictionary::Ptr locals = make_shared<Dictionary>();
-       locals->Set("host", host);
+       ScriptFrame frame;
+       if (rule.GetScope())
+               rule.GetScope()->CopyTo(frame.Locals);
+       frame.Locals->Set("host", host);
        if (service)
-               locals->Set("service", service);
-
-       if (!rule.EvaluateFilter(locals))
-               return;
+               frame.Locals->Set("service", service);
 
-       std::ostringstream msgbuf2;
-       msgbuf2 << "Applying notification '" << rule.GetName() << "' to object '" << checkable->GetName() << "' for rule " << di;
-       Log(LogDebug, "icinga", msgbuf2.str());
+       if (!rule.EvaluateFilter(frame))
+               return false;
 
-       std::ostringstream namebuf;
-       namebuf << checkable->GetName() << "!" << rule.GetName();
-       String name = namebuf.str();
+       Value vinstances;
 
-       ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
-       builder->SetType("Notification");
-       builder->SetName(name);
-       builder->SetScope(rule.GetScope());
-
-       builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet,
-           make_shared<AExpression>(&AExpression::OpLiteral, "host_name", di),
-           make_shared<AExpression>(&AExpression::OpLiteral, host->GetName(), di),
-           di));
-
-       if (service) {
-               builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet,
-                   make_shared<AExpression>(&AExpression::OpLiteral, "service_name", di),
-                   make_shared<AExpression>(&AExpression::OpLiteral, service->GetShortName(), di),
-                   di));
+       if (rule.GetFTerm()) {
+               vinstances = rule.GetFTerm()->Evaluate(frame);
+       } else {
+               Array::Ptr instances = new Array();
+               instances->Add("");
+               vinstances = instances;
        }
 
-       builder->AddExpression(rule.GetExpression());
+       if (vinstances.IsObjectType<Array>()) {
+               if (!rule.GetFVVar().IsEmpty())
+                       BOOST_THROW_EXCEPTION(ScriptError("Array iterator requires value to be an array.", di));
 
-       ConfigItem::Ptr notificationItem = builder->Compile();
-       notificationItem->Register();
-       DynamicObject::Ptr dobj = notificationItem->Commit();
-       dobj->OnConfigLoaded();
-}
+               Array::Ptr arr = vinstances;
 
-void Notification::EvaluateApplyRules(const std::vector<ApplyRule>& rules)
-{
-       BOOST_FOREACH(const Host::Ptr& host, DynamicType::GetObjects<Host>()) {
-               CONTEXT("Evaluating 'apply' rules for Host '" + host->GetName() + "'");
+               ObjectLock olock(arr);
+               BOOST_FOREACH(const String& instance, arr) {
+                       String name = rule.GetName();
 
-               BOOST_FOREACH(const ApplyRule& rule, rules) {
-                       if (rule.GetTargetType() != "Host")
-                               continue;
+                       if (!rule.GetFKVar().IsEmpty()) {
+                               frame.Locals->Set(rule.GetFKVar(), instance);
+                               name += instance;
+                       }
 
-                       EvaluateApplyRule(host, rule);
+                       EvaluateApplyRuleInstance(checkable, name, frame, rule);
+               }
+       } else if (vinstances.IsObjectType<Dictionary>()) {
+               if (rule.GetFVVar().IsEmpty())
+                       BOOST_THROW_EXCEPTION(ScriptError("Dictionary iterator requires value to be a dictionary.", di));
+       
+               Dictionary::Ptr dict = vinstances;
+
+               ObjectLock olock(dict);
+               BOOST_FOREACH(const Dictionary::Pair& kv, dict) {
+                       frame.Locals->Set(rule.GetFKVar(), kv.first);
+                       frame.Locals->Set(rule.GetFVVar(), kv.second);
+
+                       EvaluateApplyRuleInstance(checkable, rule.GetName() + kv.first, frame, rule);
                }
        }
 
-       BOOST_FOREACH(const Service::Ptr& service, DynamicType::GetObjects<Service>()) {
-               CONTEXT("Evaluating 'apply' rules for Service '" + service->GetName() + "'");
+       return true;
+}
+
+void Notification::EvaluateApplyRules(const Host::Ptr& host)
+{
+       CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'");
+
+       BOOST_FOREACH(ApplyRule& rule, ApplyRule::GetRules("Notification"))
+       {
+               if (rule.GetTargetType() != "Host")
+                       continue;
+
+               try {
+                       if (EvaluateApplyRule(host, rule))
+                               rule.AddMatch();
+               } catch (const ScriptError& ex) {
+                       ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo());
+               }
+       }
+}
+
+void Notification::EvaluateApplyRules(const Service::Ptr& service)
+{
+       CONTEXT("Evaluating 'apply' rules for service '" + service->GetName() + "'");
 
-               BOOST_FOREACH(const ApplyRule& rule, rules) {
-                       if (rule.GetTargetType() != "Service")
-                               continue;
+       BOOST_FOREACH(ApplyRule& rule, ApplyRule::GetRules("Notification")) {
+               if (rule.GetTargetType() != "Service")
+                       continue;
 
-                       EvaluateApplyRule(service, rule);
+               try {
+                       if (EvaluateApplyRule(service, rule))
+                               rule.AddMatch();
+               } catch (const ScriptError& ex) {
+                       ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo());
                }
        }
 }