Skip to content

Commit

Permalink
Evaluate apply filters in the for loop
Browse files Browse the repository at this point in the history
  • Loading branch information
gunnarbeutner committed Jan 29, 2015
1 parent 8878868 commit fb323ee
Show file tree
Hide file tree
Showing 14 changed files with 136 additions and 75 deletions.
6 changes: 0 additions & 6 deletions doc/3-monitoring-basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -427,8 +427,6 @@ You can also specifiy the check command that way.
notes = "Interface check for Port " + string(vars.port) + " in VLAN " + vars.vlan + " on Address " + vars.address + " QoS " + vars.qos
notes_url = "http://foreman.company.com/hosts/" + host.name
action_url = "http://snmp.checker.company.com/" + host.name + "if-" + if_name

assign where host.vars.interfaces
}

Note that numbers must be explicitely casted to string when adding to strings.
Expand Down Expand Up @@ -481,8 +479,6 @@ values for any object attribute specified in that apply rule.

notes_url = "http://foreman.company.com/hosts/" + host.name
action_url = "http://snmp.checker.company.com/" + host.name + "/" + vars.customer_id

assign where host.vars.hosting
}

### <a id="groups"></a> Groups
Expand Down Expand Up @@ -1003,8 +999,6 @@ string values for passing multiple partitions to the `check_disk` check plugin.

vars.disk_wfree = 10
vars.disk_cfree = 5

assign where host.vars.local_disks
}


Expand Down
2 changes: 0 additions & 2 deletions doc/4-configuring-icinga-2.md
Original file line number Diff line number Diff line change
Expand Up @@ -366,8 +366,6 @@ Configuration example:
check_command = "disk"

vars += config

assign where host.vars.disks
}

A similar example is used for the `http` services. That way you can make your
Expand Down
4 changes: 0 additions & 4 deletions etc/icinga2/conf.d/services.conf
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ apply Service for (http_vhost => config in host.vars.http_vhosts) {
check_command = "http"

vars += config

assign where host.vars.http_vhosts
}

apply Service for (disk => config in host.vars.disks) {
Expand All @@ -71,8 +69,6 @@ apply Service for (disk => config in host.vars.disks) {
check_command = "disk"

vars += config

assign where host.vars.disks
}

apply Service "icinga" {
Expand Down
20 changes: 20 additions & 0 deletions lib/base/dictionary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,23 @@ Dictionary::Ptr Dictionary::ShallowClone(void) const
CopyTo(clone);
return clone;
}

/**
* Returns an array containing all keys
* which are currently set in this directory.
*
* @returns an array of key names
*/
std::vector<String> Dictionary::GetKeys(void) const
{
ASSERT(!OwnsLock());
ObjectLock olock(this);

std::vector<String> keys;

BOOST_FOREACH(const Dictionary::Pair& kv, m_Data) {
keys.push_back(kv.first);
}

return keys;
}
3 changes: 3 additions & 0 deletions lib/base/dictionary.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "base/value.hpp"
#include <boost/range/iterator.hpp>
#include <map>
#include <vector>

namespace icinga
{
Expand Down Expand Up @@ -64,6 +65,8 @@ class I2_BASE_API Dictionary : public Object
void CopyTo(const Dictionary::Ptr& dest) const;
Dictionary::Ptr ShallowClone(void) const;

std::vector<String> GetKeys(void) const;

static Object::Ptr GetPrototype(void);

private:
Expand Down
17 changes: 12 additions & 5 deletions lib/config/config_parser.yy
Original file line number Diff line number Diff line change
Expand Up @@ -996,16 +996,23 @@ apply:
DictExpression *exprl = dynamic_cast<DictExpression *>($8);
exprl->MakeInline();

// assign && !ignore
if (!context->m_SeenAssign.top())
BOOST_THROW_EXCEPTION(ScriptError("'apply' is missing 'assign'", DebugInfoRange(@2, @3)));

bool seen_assign = context->m_SeenAssign.top();
context->m_SeenAssign.pop();

// assign && !ignore
if (!seen_assign && !context->m_FTerm.top())
BOOST_THROW_EXCEPTION(ScriptError("'apply' is missing 'assign'/'for'", DebugInfoRange(@2, @3)));

Expression *ignore = context->m_Ignore.top();
context->m_Ignore.pop();

Expression *assign = context->m_Assign.top();
Expression *assign;

if (!seen_assign)
assign = MakeLiteral(true);
else
assign = context->m_Assign.top();

context->m_Assign.pop();

Expression *filter;
Expand Down
39 changes: 25 additions & 14 deletions lib/icinga/dependency-apply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,11 @@ void Dependency::RegisterApplyRuleHandler(void)
ApplyRule::RegisterType("Dependency", targets);
}

void Dependency::EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, const String& name, ScriptFrame& frame, const ApplyRule& rule)
bool Dependency::EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, const String& name, ScriptFrame& frame, const ApplyRule& rule)
{
if (!rule.EvaluateFilter(frame))
return false;

DebugInfo di = rule.GetDebugInfo();

Log(LogDebug, "Dependency")
Expand Down Expand Up @@ -72,6 +75,8 @@ void Dependency::EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, cons

ConfigItem::Ptr dependencyItem = builder->Compile();
dependencyItem->Commit();

return true;
}

bool Dependency::EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyRule& rule)
Expand All @@ -93,52 +98,58 @@ bool Dependency::EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyR
if (service)
frame.Locals->Set("service", service);

if (!rule.EvaluateFilter(frame))
return false;

Value vinstances;

if (rule.GetFTerm()) {
vinstances = rule.GetFTerm()->Evaluate(frame);
try {
vinstances = rule.GetFTerm()->Evaluate(frame);
} catch (const std::exception&) {
/* Silently ignore errors here and assume there are no instances. */
return false;
}
} else {
Array::Ptr instances = new Array();
instances->Add("");
vinstances = instances;
}

bool match = false;

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;
Array::Ptr arrclone = arr->ShallowClone();

ObjectLock olock(arr);
BOOST_FOREACH(const String& instance, arr) {
ObjectLock olock(arrclone);
BOOST_FOREACH(const String& instance, arrclone) {
String name = rule.GetName();

if (!rule.GetFKVar().IsEmpty()) {
frame.Locals->Set(rule.GetFKVar(), instance);
name += instance;
}

EvaluateApplyRuleInstance(checkable, name, frame, rule);
if (EvaluateApplyRuleInstance(checkable, name, frame, rule))
match = true;
}
} 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);
BOOST_FOREACH(const String& key, dict->GetKeys()) {
frame.Locals->Set(rule.GetFKVar(), key);
frame.Locals->Set(rule.GetFVVar(), dict->Get(key));

EvaluateApplyRuleInstance(checkable, rule.GetName() + kv.first, frame, rule);
if (EvaluateApplyRuleInstance(checkable, rule.GetName() + key, frame, rule))
match = true;
}
}

return true;
return match;
}

void Dependency::EvaluateApplyRules(const Host::Ptr& host)
Expand Down
2 changes: 1 addition & 1 deletion lib/icinga/dependency.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class I2_ICINGA_API Dependency : public ObjectImpl<Dependency>
Checkable::Ptr m_Parent;
Checkable::Ptr m_Child;

static void EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, const String& name, ScriptFrame& frame, const ApplyRule& rule);
static bool EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, const String& name, ScriptFrame& frame, const ApplyRule& rule);
static bool EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyRule& rule);
};

Expand Down
34 changes: 22 additions & 12 deletions lib/icinga/notification-apply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,11 @@ void Notification::RegisterApplyRuleHandler(void)
ApplyRule::RegisterType("Notification", targets);
}

void Notification::EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, const String& name, ScriptFrame& frame, const ApplyRule& rule)
bool Notification::EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, const String& name, ScriptFrame& frame, const ApplyRule& rule)
{
if (!rule.EvaluateFilter(frame))
return false;

DebugInfo di = rule.GetDebugInfo();

Log(LogDebug, "Notification")
Expand Down Expand Up @@ -71,6 +74,8 @@ void Notification::EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, co

ConfigItem::Ptr notificationItem = builder->Compile();
notificationItem->Commit();

return true;
}

bool Notification::EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyRule& rule)
Expand All @@ -92,19 +97,23 @@ bool Notification::EvaluateApplyRule(const Checkable::Ptr& checkable, const Appl
if (service)
frame.Locals->Set("service", service);

if (!rule.EvaluateFilter(frame))
return false;

Value vinstances;

if (rule.GetFTerm()) {
vinstances = rule.GetFTerm()->Evaluate(frame);
try {
vinstances = rule.GetFTerm()->Evaluate(frame);
} catch (const std::exception&) {
/* Silently ignore errors here and assume there are no instances. */
return false;
}
} else {
Array::Ptr instances = new Array();
instances->Add("");
vinstances = instances;
}

bool match = false;

if (vinstances.IsObjectType<Array>()) {
if (!rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ScriptError("Array iterator requires value to be an array.", di));
Expand All @@ -120,24 +129,25 @@ bool Notification::EvaluateApplyRule(const Checkable::Ptr& checkable, const Appl
name += instance;
}

EvaluateApplyRuleInstance(checkable, name, frame, rule);
if (EvaluateApplyRuleInstance(checkable, name, frame, rule))
match = true;
}
} 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);
BOOST_FOREACH(const String& key, dict->GetKeys()) {
frame.Locals->Set(rule.GetFKVar(), key);
frame.Locals->Set(rule.GetFVVar(), dict->Get(key));

EvaluateApplyRuleInstance(checkable, rule.GetName() + kv.first, frame, rule);
if (EvaluateApplyRuleInstance(checkable, rule.GetName() + key, frame, rule))
match = true;
}
}

return true;
return match;
}

void Notification::EvaluateApplyRules(const Host::Ptr& host)
Expand Down
2 changes: 1 addition & 1 deletion lib/icinga/notification.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ class I2_ICINGA_API Notification : public ObjectImpl<Notification>
private:
void ExecuteNotificationHelper(NotificationType type, const User::Ptr& user, const CheckResult::Ptr& cr, bool force, const String& author = "", const String& text = "");

static void EvaluateApplyRuleInstance(const intrusive_ptr<Checkable>& checkable, const String& name, ScriptFrame& frame, const ApplyRule& rule);
static bool EvaluateApplyRuleInstance(const intrusive_ptr<Checkable>& checkable, const String& name, ScriptFrame& frame, const ApplyRule& rule);
static bool EvaluateApplyRule(const intrusive_ptr<Checkable>& checkable, const ApplyRule& rule);
};

Expand Down
Loading

0 comments on commit fb323ee

Please sign in to comment.