]> granicus.if.org Git - icinga2/blobdiff - lib/icinga/notification-apply.cpp
Move the VMFrame class to libbase
[icinga2] / lib / icinga / notification-apply.cpp
index 8037cc72c5cebdabc2d8dd9703aba673af878c3b..ed829f1e584507404d434fd6dddc29576e838b8c 100644 (file)
  * 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,7 +39,39 @@ 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::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)
@@ -50,78 +86,92 @@ bool 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);
+               frame.Locals->Set("service", service);
 
-       if (!rule.EvaluateFilter(locals))
+       if (!rule.EvaluateFilter(frame))
                return false;
 
-       std::ostringstream msgbuf2;
-       msgbuf2 << "Applying notification '" << rule.GetName() << "' to object '" << checkable->GetName() << "' for rule " << di;
-       Log(LogDebug, "icinga", msgbuf2.str());
+       Value vinstances;
 
-       ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
-       builder->SetType("Notification");
-       builder->SetName(rule.GetName());
-       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());
-
-       ConfigItem::Ptr notificationItem = builder->Compile();
-       notificationItem->Register();
-       DynamicObject::Ptr dobj = notificationItem->Commit();
-       dobj->OnConfigLoaded();
-
-       return true;
-}
-
-void Notification::EvaluateApplyRules(const std::vector<ApplyRule>& rules)
-{
-       int apply_count = 0;
+       if (vinstances.IsObjectType<Array>()) {
+               if (!rule.GetFVVar().IsEmpty())
+                       BOOST_THROW_EXCEPTION(ScriptError("Array iterator requires value to be an array.", di));
 
-       BOOST_FOREACH(const ApplyRule& rule, rules) {
-               if (rule.GetTargetType() == "Host") {
-                       apply_count = 0;
+               Array::Ptr arr = vinstances;
 
-                       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();
 
-                               if (EvaluateApplyRule(host, rule))
-                                       apply_count++;
+                       if (!rule.GetFKVar().IsEmpty()) {
+                               frame.Locals->Set(rule.GetFKVar(), instance);
+                               name += instance;
                        }
 
-                       if (apply_count == 0)
-                               Log(LogWarning, "icinga", "Apply rule '" + rule.GetName() + "' for host does not match anywhere!");
+                       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);
+               }
+       }
 
-               } else if (rule.GetTargetType() == "Service") {
-                       apply_count = 0;
+       return true;
+}
 
-                       BOOST_FOREACH(const Service::Ptr& service, DynamicType::GetObjects<Service>()) {
-                               CONTEXT("Evaluating 'apply' rules for Service '" + service->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());
+               }
+       }
+}
 
-                               if(EvaluateApplyRule(service, rule))
-                                       apply_count++;
-                       }
+void Notification::EvaluateApplyRules(const Service::Ptr& service)
+{
+       CONTEXT("Evaluating 'apply' rules for service '" + service->GetName() + "'");
 
-                       if (apply_count == 0)
-                               Log(LogWarning, "icinga", "Apply rule '" + rule.GetName() + "' for service does not match anywhere!");
+       BOOST_FOREACH(ApplyRule& rule, ApplyRule::GetRules("Notification")) {
+               if (rule.GetTargetType() != "Service")
+                       continue;
 
-               } else {
-                       Log(LogWarning, "icinga", "Wrong target type for apply rule '" + rule.GetName() + "'!");
+               try {
+                       if (EvaluateApplyRule(service, rule))
+                               rule.AddMatch();
+               } catch (const ScriptError& ex) {
+                       ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo());
                }
        }
 }