]> granicus.if.org Git - icinga2/blobdiff - lib/icinga/notification-apply.cpp
Move the VMFrame class to libbase
[icinga2] / lib / icinga / notification-apply.cpp
index 7715bf40e2c2b0551d31e3c0ca4cd76e8fc7d2d8..ed829f1e584507404d434fd6dddc29576e838b8c 100644 (file)
@@ -27,7 +27,7 @@
 #include "base/logger.hpp"
 #include "base/context.hpp"
 #include "base/workqueue.hpp"
-#include "base/configerror.hpp"
+#include "base/scripterror.hpp"
 #include <boost/foreach.hpp>
 
 using namespace icinga;
@@ -39,123 +39,139 @@ 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);
 }
 
-bool Notification::EvaluateApplyRuleOne(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();
 
-       std::ostringstream msgbuf;
-       msgbuf << "Evaluating 'apply' rule (" << di << ")";
-       CONTEXT(msgbuf.str());
+       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);
 
-       Dictionary::Ptr locals = make_shared<Dictionary>();
-       locals->Set("__parent", rule.GetScope());
-       locals->Set("host", host);
-       if (service)
-               locals->Set("service", service);
-
-       if (!rule.EvaluateFilter(locals))
-               return false;
+       builder->AddExpression(new SetExpression(MakeIndexer("host_name"), OpSetLiteral, MakeLiteral(host->GetName()), false, di));
 
-       Log(LogDebug, "Notification")
-           << "Applying notification '" << rule.GetName() << "' to object '" << checkable->GetName() << "' for rule " << di;
-
-       ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
-       builder->SetType("Notification");
-       builder->SetName(rule.GetName());
-       builder->SetScope(locals);
-
-       builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
-           make_shared<Expression>(&Expression::OpLiteral, "host_name", di),
-           make_shared<Expression>(&Expression::OpLiteral, host->GetName(), di),
-           di));
-
-       if (service) {
-               builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
-                   make_shared<Expression>(&Expression::OpLiteral, "service_name", di),
-                   make_shared<Expression>(&Expression::OpLiteral, service->GetShortName(), di),
-                   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(make_shared<Expression>(&Expression::OpSet,
-                   make_shared<Expression>(&Expression::OpLiteral, "zone", di),
-                   make_shared<Expression>(&Expression::OpLiteral, zone, di),
-                   di));
-       }
+       if (!zone.IsEmpty())
+               builder->AddExpression(new SetExpression(MakeIndexer("zone"), OpSetLiteral, MakeLiteral(zone), false, di));
 
-       builder->AddExpression(rule.GetExpression());
+       builder->AddExpression(new OwnedExpression(rule.GetExpression()));
 
        ConfigItem::Ptr notificationItem = builder->Compile();
-       notificationItem->Register();
-       DynamicObject::Ptr dobj = notificationItem->Commit();
-       dobj->OnConfigLoaded();
-
-       return true;
+       notificationItem->Commit();
 }
 
-void Notification::EvaluateApplyRule(const ApplyRule& rule)
+bool Notification::EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyRule& rule)
 {
-       int apply_count = 0;
+       DebugInfo di = rule.GetDebugInfo();
 
-       if (rule.GetTargetType() == "Host") {
-               apply_count = 0;
+       std::ostringstream msgbuf;
+       msgbuf << "Evaluating 'apply' rule (" << di << ")";
+       CONTEXT(msgbuf.str());
 
-               BOOST_FOREACH(const Host::Ptr& host, DynamicType::GetObjectsByType<Host>()) {
-                       CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'");
+       Host::Ptr host;
+       Service::Ptr service;
+       tie(host, service) = GetHostService(checkable);
 
-                       try {
-                               if (EvaluateApplyRuleOne(host, rule))
-                                       apply_count++;
-                       } catch (const ConfigError& ex) {
-                               const DebugInfo *di = boost::get_error_info<errinfo_debuginfo>(ex);
-                               ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), di ? *di : DebugInfo());
-                       }
-               }
+       ScriptFrame frame;
+       if (rule.GetScope())
+               rule.GetScope()->CopyTo(frame.Locals);
+       frame.Locals->Set("host", host);
+       if (service)
+               frame.Locals->Set("service", service);
 
-               if (apply_count == 0)
-                       Log(LogWarning, "Notification")
-                           << "Apply rule '" << rule.GetName() << "' for host does not match anywhere!";
+       if (!rule.EvaluateFilter(frame))
+               return false;
 
-       } else if (rule.GetTargetType() == "Service") {
-               apply_count = 0;
+       Value vinstances;
 
-               BOOST_FOREACH(const Service::Ptr& service, DynamicType::GetObjectsByType<Service>()) {
-                       CONTEXT("Evaluating 'apply' rules for Service '" + service->GetName() + "'");
+       if (rule.GetFTerm()) {
+               vinstances = rule.GetFTerm()->Evaluate(frame);
+       } else {
+               Array::Ptr instances = new Array();
+               instances->Add("");
+               vinstances = instances;
+       }
+
+       if (vinstances.IsObjectType<Array>()) {
+               if (!rule.GetFVVar().IsEmpty())
+                       BOOST_THROW_EXCEPTION(ScriptError("Array iterator requires value to be an array.", di));
+
+               Array::Ptr arr = vinstances;
 
-                       try {
-                               if (EvaluateApplyRuleOne(service, rule))
-                                       apply_count++;
-                       } catch (const ConfigError& ex) {
-                               const DebugInfo *di = boost::get_error_info<errinfo_debuginfo>(ex);
-                               ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), di ? *di : DebugInfo());
+               ObjectLock olock(arr);
+               BOOST_FOREACH(const String& instance, arr) {
+                       String name = rule.GetName();
+
+                       if (!rule.GetFKVar().IsEmpty()) {
+                               frame.Locals->Set(rule.GetFKVar(), instance);
+                               name += instance;
                        }
+
+                       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);
+               }
+       }
 
-               if (apply_count == 0)
-                       Log(LogWarning, "Notification")
-                           << "Apply rule '" << rule.GetName() << "' for service does not match anywhere!";
+       return true;
+}
 
-       } else {
-               Log(LogWarning, "Notification")
-                   << "Wrong target type for apply rule '" << rule.GetName() << "'!";
+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 std::vector<ApplyRule>& rules)
+
+void Notification::EvaluateApplyRules(const Service::Ptr& service)
 {
-       ParallelWorkQueue upq;
+       CONTEXT("Evaluating 'apply' rules for service '" + service->GetName() + "'");
 
-       BOOST_FOREACH(const ApplyRule& rule, rules) {
-               upq.Enqueue(boost::bind(&Notification::EvaluateApplyRule, boost::cref(rule)));
-       }
+       BOOST_FOREACH(ApplyRule& rule, ApplyRule::GetRules("Notification")) {
+               if (rule.GetTargetType() != "Service")
+                       continue;
 
-       upq.Join();
+               try {
+                       if (EvaluateApplyRule(service, rule))
+                               rule.AddMatch();
+               } catch (const ScriptError& ex) {
+                       ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo());
+               }
+       }
 }