Refactor the macro resolver

Fixes #3884
This commit is contained in:
Gunnar Beutner 2013-03-22 14:40:55 +01:00
parent 97fee26289
commit 6d69d6c639
22 changed files with 450 additions and 205 deletions

View File

@ -30,6 +30,8 @@ libicinga_la_SOURCES = \
icingaapplication.h \ icingaapplication.h \
macroprocessor.cpp \ macroprocessor.cpp \
macroprocessor.h \ macroprocessor.h \
macroresolver.cpp \
macroresolver.h \
notification.cpp \ notification.cpp \
notification.h \ notification.h \
notificationrequestmessage.cpp \ notificationrequestmessage.cpp \

View File

@ -24,6 +24,7 @@
#include "base/objectlock.h" #include "base/objectlock.h"
#include "base/logger_fwd.h" #include "base/logger_fwd.h"
#include "base/timer.h" #include "base/timer.h"
#include "base/convert.h"
#include "config/configitembuilder.h" #include "config/configitembuilder.h"
#include "config/configcompilercontext.h" #include "config/configcompilercontext.h"
#include <boost/tuple/tuple.hpp> #include <boost/tuple/tuple.hpp>
@ -224,6 +225,7 @@ void Host::UpdateSlaveServices(void)
keys.insert("check_period"); keys.insert("check_period");
keys.insert("servicedependencies"); keys.insert("servicedependencies");
keys.insert("hostdependencies"); keys.insert("hostdependencies");
keys.insert("export_macros");
ExpressionList::Ptr host_exprl = boost::make_shared<ExpressionList>(); ExpressionList::Ptr host_exprl = boost::make_shared<ExpressionList>();
item->GetLinkedExpressionList()->ExtractFiltered(keys, host_exprl); item->GetLinkedExpressionList()->ExtractFiltered(keys, host_exprl);
@ -543,55 +545,81 @@ String Host::StateToString(HostState state)
} }
} }
Dictionary::Ptr Host::CalculateDynamicMacros(void) const bool Host::ResolveMacro(const String& macro, const Dictionary::Ptr& cr, String *result) const
{ {
ASSERT(!OwnsLock()); if (macro == "HOSTNAME" || macro == "HOSTALIAS") {
*result = GetName();
Dictionary::Ptr macros = boost::make_shared<Dictionary>(); return true;
}
{ else if (macro == "HOSTDISPLAYNAME") {
ObjectLock olock(this); *result = GetDisplayName();
return true;
macros->Set("HOSTNAME", GetName());
macros->Set("HOSTDISPLAYNAME", GetDisplayName());
macros->Set("HOSTALIAS", GetName());
} }
Dictionary::Ptr cr;
Service::Ptr hc = GetHostCheckService(); Service::Ptr hc = GetHostCheckService();
Dictionary::Ptr hccr;
if (hc) { if (hc) {
ObjectLock olock(hc);
ServiceState state = hc->GetState(); ServiceState state = hc->GetState();
bool reachable = IsReachable(); bool reachable = IsReachable();
macros->Set("HOSTSTATE", CalculateState(state, reachable)); if (macro == "HOSTSTATE") {
macros->Set("HOSTSTATEID", state); *result = Convert::ToString(CalculateState(state, reachable));
macros->Set("HOSTSTATETYPE", Service::StateTypeToString(hc->GetStateType())); return true;
macros->Set("HOSTATTEMPT", hc->GetCurrentCheckAttempt()); } else if (macro == "HOSTSTATEID") {
macros->Set("MAXHOSTATTEMPT", hc->GetMaxCheckAttempts()); *result = Convert::ToString(state);
return true;
} else if (macro == "HOSTSTATETYPE") {
*result = Service::StateTypeToString(hc->GetStateType());
return true;
} else if (macro == "HOSTATTEMPT") {
*result = Convert::ToString(hc->GetCurrentCheckAttempt());
return true;
} else if (macro == "MAXHOSTATTEMPT") {
*result = Convert::ToString(hc->GetMaxCheckAttempts());
return true;
} else if (macro == "LASTHOSTSTATE") {
*result = StateToString(GetLastState());
return true;
} else if (macro == "LASTHOSTSTATEID") {
*result = Convert::ToString(GetLastState());
return true;
} else if (macro == "LASTHOSTSTATETYPE") {
*result = Service::StateTypeToString(GetLastStateType());
return true;
} else if (macro == "LASTHOSTSTATECHANGE") {
*result = Convert::ToString((long)hc->GetLastStateChange());
return true;
}
macros->Set("LASTHOSTSTATE", StateToString(GetLastState())); hccr = hc->GetLastCheckResult();
macros->Set("LASTHOSTSTATEID", GetLastState());
macros->Set("LASTHOSTSTATETYPE", Service::StateTypeToString(GetLastStateType()));
macros->Set("LASTHOSTSTATECHANGE", (long)hc->GetLastStateChange());
cr = hc->GetLastCheckResult();
} }
if (cr) { if (hccr) {
macros->Set("HOSTLATENCY", Service::CalculateLatency(cr)); if (macro == "HOSTLATENCY") {
macros->Set("HOSTEXECUTIONTIME", Service::CalculateExecutionTime(cr)); *result = Convert::ToString(Service::CalculateLatency(hccr));
return true;
macros->Set("HOSTOUTPUT", cr->Get("output")); } else if (macro == "HOSTEXECUTIONTIME") {
macros->Set("HOSTPERFDATA", cr->Get("performance_data_raw")); *result = Convert::ToString(Service::CalculateExecutionTime(hccr));
return true;
macros->Set("LASTHOSTCHECK", (long)cr->Get("schedule_start")); } else if (macro == "HOSTOUTPUT") {
*result = hccr->Get("output");
return true;
} else if (macro == "HOSTPERFDATA") {
*result = hccr->Get("performance_data_raw");
return true;
} else if (macro == "LASTHOSTCHECK") {
*result = Convert::ToString((long)hccr->Get("schedule_start"));
return true;
}
} }
macros->Seal(); Dictionary::Ptr macros = GetMacros();
return macros; if (macros && macros->Contains(macro)) {
*result = macros->Get(macro);
return true;
}
return false;
} }

View File

@ -21,6 +21,7 @@
#define HOST_H #define HOST_H
#include "icinga/i2-icinga.h" #include "icinga/i2-icinga.h"
#include "icinga/macroresolver.h"
#include "base/array.h" #include "base/array.h"
#include "base/dynamicobject.h" #include "base/dynamicobject.h"
#include "base/dictionary.h" #include "base/dictionary.h"
@ -72,7 +73,7 @@ enum StateType
* *
* @ingroup icinga * @ingroup icinga
*/ */
class I2_ICINGA_API Host : public DynamicObject class I2_ICINGA_API Host : public DynamicObject, public MacroResolver
{ {
public: public:
typedef shared_ptr<Host> Ptr; typedef shared_ptr<Host> Ptr;
@ -91,8 +92,6 @@ public:
Array::Ptr GetServiceDependencies(void) const; Array::Ptr GetServiceDependencies(void) const;
String GetHostCheck(void) const; String GetHostCheck(void) const;
Dictionary::Ptr CalculateDynamicMacros(void) const;
shared_ptr<Service> GetHostCheckService(void) const; shared_ptr<Service> GetHostCheckService(void) const;
std::set<Host::Ptr> GetParentHosts(void) const; std::set<Host::Ptr> GetParentHosts(void) const;
std::set<shared_ptr<Service> > GetParentServices(void) const; std::set<shared_ptr<Service> > GetParentServices(void) const;
@ -114,6 +113,8 @@ public:
static String StateToString(HostState state); static String StateToString(HostState state);
virtual bool ResolveMacro(const String& macro, const Dictionary::Ptr& cr, String *result) const;
protected: protected:
virtual void OnRegistrationCompleted(void); virtual void OnRegistrationCompleted(void);
virtual void OnAttributeChanged(const String& name); virtual void OnAttributeChanged(const String& name);

View File

@ -50,6 +50,8 @@ type Host {
%attribute string "*" %attribute string "*"
}, },
%attribute array "export_macros",
%attribute string "check_period", %attribute string "check_period",
%attribute number "check_interval", %attribute number "check_interval",
%attribute number "retry_interval", %attribute number "retry_interval",
@ -74,7 +76,7 @@ type Host {
%require "service", %require "service",
%attribute string "service" %attribute string "service"
} }
} },
} }
}, },
@ -88,6 +90,8 @@ type Host {
%attribute string "*" %attribute string "*"
}, },
%attribute array "export_macros",
%attribute array "users" { %attribute array "users" {
%attribute string "*" %attribute string "*"
}, },
@ -109,6 +113,9 @@ type Host {
%attribute dictionary "macros" { %attribute dictionary "macros" {
%attribute string "*" %attribute string "*"
}, },
%attribute array "export_macros",
%attribute array "servicegroups" { %attribute array "servicegroups" {
%attribute string "*" %attribute string "*"
}, },
@ -143,6 +150,9 @@ type Service {
%attribute dictionary "macros" { %attribute dictionary "macros" {
%attribute string "*" %attribute string "*"
}, },
%attribute array "export_macros",
%attribute array "check_command" { %attribute array "check_command" {
%attribute string "*" %attribute string "*"
}, },
@ -190,6 +200,8 @@ type Service {
%attribute string "*" %attribute string "*"
}, },
%attribute array "export_macros"
%attribute array "users" { %attribute array "users" {
%attribute string "*" %attribute string "*"
}, },
@ -221,6 +233,8 @@ type Notification {
%attribute string "*" %attribute string "*"
}, },
%attribute array "export_macros"
%attribute array "users" { %attribute array "users" {
%attribute string "*" %attribute string "*"
}, },

View File

@ -33,6 +33,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="icingaapplication.cpp" /> <ClCompile Include="icingaapplication.cpp" />
<ClCompile Include="macroprocessor.cpp" /> <ClCompile Include="macroprocessor.cpp" />
<ClCompile Include="macroresolver.cpp" />
<ClCompile Include="notification.cpp" /> <ClCompile Include="notification.cpp" />
<ClCompile Include="notificationrequestmessage.cpp" /> <ClCompile Include="notificationrequestmessage.cpp" />
<ClCompile Include="pluginchecktask.cpp" /> <ClCompile Include="pluginchecktask.cpp" />
@ -58,6 +59,7 @@
<ClInclude Include="i2-icinga.h" /> <ClInclude Include="i2-icinga.h" />
<ClInclude Include="icingaapplication.h" /> <ClInclude Include="icingaapplication.h" />
<ClInclude Include="macroprocessor.h" /> <ClInclude Include="macroprocessor.h" />
<ClInclude Include="macroresolver.h" />
<ClInclude Include="notification.h" /> <ClInclude Include="notification.h" />
<ClInclude Include="notificationrequestmessage.h" /> <ClInclude Include="notificationrequestmessage.h" />
<ClInclude Include="pluginchecktask.h" /> <ClInclude Include="pluginchecktask.h" />
@ -240,4 +242,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
</Project> </Project>

View File

@ -22,6 +22,7 @@
#include "base/dynamictype.h" #include "base/dynamictype.h"
#include "base/logger_fwd.h" #include "base/logger_fwd.h"
#include "base/objectlock.h" #include "base/objectlock.h"
#include "base/convert.h"
#include "base/timer.h" #include "base/timer.h"
#include <boost/smart_ptr/make_shared.hpp> #include <boost/smart_ptr/make_shared.hpp>
@ -184,17 +185,33 @@ shared_ptr<SSL_CTX> IcingaApplication::GetSSLContext(void) const
return m_SSLContext; return m_SSLContext;
} }
Dictionary::Ptr IcingaApplication::CalculateDynamicMacros(void) bool IcingaApplication::ResolveMacro(const String& macro, const Dictionary::Ptr& cr, String *result) const
{ {
Dictionary::Ptr macros = boost::make_shared<Dictionary>();
double now = Utility::GetTime(); double now = Utility::GetTime();
macros->Set("TIMET", (long)now); if (macro == "TIMET") {
macros->Set("LONGDATETIME", Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", now)); *result = Convert::ToString((long)now);
macros->Set("SHORTDATETIME", Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", now)); return true;
macros->Set("DATE", Utility::FormatDateTime("%Y-%m-%d", now)); } else if (macro == "LONGDATETIME") {
macros->Set("TIME", Utility::FormatDateTime("%H:%M:%S %z", now)); *result = Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", now);
return true;
} else if (macro == "SHORTDATETIME") {
*result = Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", now);
return true;
} else if (macro == "DATE") {
*result = Utility::FormatDateTime("%Y-%m-%d", now);
return true;
} else if (macro == "TIME") {
*result = Utility::FormatDateTime("%H:%M:%S %z", now);
return true;
}
return macros; Dictionary::Ptr macros = GetMacros();
if (macros && macros->Contains(macro)) {
*result = macros->Get(macro);
return true;
}
return false;
} }

View File

@ -21,6 +21,7 @@
#define ICINGAAPPLICATION_H #define ICINGAAPPLICATION_H
#include "icinga/i2-icinga.h" #include "icinga/i2-icinga.h"
#include "icinga/macroresolver.h"
#include "base/application.h" #include "base/application.h"
#include "base/tlsutility.h" #include "base/tlsutility.h"
@ -32,7 +33,7 @@ namespace icinga
* *
* @ingroup icinga * @ingroup icinga
*/ */
class I2_ICINGA_API IcingaApplication : public Application class I2_ICINGA_API IcingaApplication : public Application, public MacroResolver
{ {
public: public:
typedef shared_ptr<IcingaApplication> Ptr; typedef shared_ptr<IcingaApplication> Ptr;
@ -55,7 +56,7 @@ public:
double GetStartTime(void) const; double GetStartTime(void) const;
static Dictionary::Ptr CalculateDynamicMacros(void); virtual bool ResolveMacro(const String& macro, const Dictionary::Ptr& cr, String *result) const;
private: private:
Attribute<String> m_CertPath; Attribute<String> m_CertPath;

View File

@ -18,24 +18,24 @@
******************************************************************************/ ******************************************************************************/
#include "icinga/macroprocessor.h" #include "icinga/macroprocessor.h"
#include "icinga/macroresolver.h"
#include "base/utility.h" #include "base/utility.h"
#include "base/array.h" #include "base/array.h"
#include "base/objectlock.h" #include "base/objectlock.h"
#include "base/logger_fwd.h"
#include <boost/tuple/tuple.hpp> #include <boost/tuple/tuple.hpp>
#include <boost/smart_ptr/make_shared.hpp> #include <boost/smart_ptr/make_shared.hpp>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
using namespace icinga; using namespace icinga;
Value MacroProcessor::ResolveMacros(const Value& cmd, const Dictionary::Ptr& macros, Value MacroProcessor::ResolveMacros(const Value& cmd, const std::vector<MacroResolver::Ptr>& resolvers,
const MacroProcessor::EscapeCallback& escapeFn) const Dictionary::Ptr& cr, const MacroProcessor::EscapeCallback& escapeFn)
{ {
Value result; Value result;
ASSERT(macros->IsSealed());
if (cmd.IsScalar()) { if (cmd.IsScalar()) {
result = InternalResolveMacros(cmd, macros, escapeFn); result = InternalResolveMacros(cmd, resolvers, cr, escapeFn);
} else if (cmd.IsObjectType<Array>()) { } else if (cmd.IsObjectType<Array>()) {
Array::Ptr resultArr = boost::make_shared<Array>(); Array::Ptr resultArr = boost::make_shared<Array>();
Array::Ptr arr = cmd; Array::Ptr arr = cmd;
@ -44,7 +44,7 @@ Value MacroProcessor::ResolveMacros(const Value& cmd, const Dictionary::Ptr& mac
BOOST_FOREACH(const Value& arg, arr) { BOOST_FOREACH(const Value& arg, arr) {
/* Note: don't escape macros here. */ /* Note: don't escape macros here. */
resultArr->Add(InternalResolveMacros(arg, macros, EscapeCallback())); resultArr->Add(InternalResolveMacros(arg, resolvers, cr, EscapeCallback()));
} }
result = resultArr; result = resultArr;
@ -55,8 +55,20 @@ Value MacroProcessor::ResolveMacros(const Value& cmd, const Dictionary::Ptr& mac
return result; return result;
} }
String MacroProcessor::InternalResolveMacros(const String& str, const Dictionary::Ptr& macros, bool MacroProcessor::ResolveMacro(const String& macro, const std::vector<MacroResolver::Ptr>& resolvers,
const MacroProcessor::EscapeCallback& escapeFn) const Dictionary::Ptr& cr, String *result)
{
BOOST_FOREACH(const MacroResolver::Ptr& resolver, resolvers) {
if (resolver->ResolveMacro(macro, cr, result))
return true;
}
return false;
}
String MacroProcessor::InternalResolveMacros(const String& str, const std::vector<MacroResolver::Ptr>& resolvers,
const Dictionary::Ptr& cr, const MacroProcessor::EscapeCallback& escapeFn)
{ {
size_t offset, pos_first, pos_second; size_t offset, pos_first, pos_second;
offset = 0; offset = 0;
@ -70,38 +82,21 @@ String MacroProcessor::InternalResolveMacros(const String& str, const Dictionary
String name = result.SubStr(pos_first + 1, pos_second - pos_first - 1); String name = result.SubStr(pos_first + 1, pos_second - pos_first - 1);
if (!macros || !macros->Contains(name)) String resolved_macro;
BOOST_THROW_EXCEPTION(std::runtime_error("Macro '" + name + "' is not defined.")); bool found = ResolveMacro(name, resolvers, cr, &resolved_macro);
String value = macros->Get(name); /* $$ is an escape sequence for $. */
result.Replace(pos_first, pos_second - pos_first + 1, value); if (name.IsEmpty()) {
offset = pos_first + value.GetLength(); resolved_macro = "$";
} found = true;
return result;
}
Dictionary::Ptr MacroProcessor::MergeMacroDicts(const std::vector<Dictionary::Ptr>& dicts)
{
Dictionary::Ptr result = boost::make_shared<Dictionary>();
BOOST_REVERSE_FOREACH(const Dictionary::Ptr& dict, dicts) {
if (!dict)
continue;
ObjectLock olock(dict);
String key;
Value value;
BOOST_FOREACH(boost::tie(key, value), dict) {
if (!value.IsScalar())
continue;
result->Set(key, value);
} }
}
result->Seal(); if (!found)
Log(LogWarning, "icinga", "Macro '" + name + "' is not defined.");
result.Replace(pos_first, pos_second - pos_first + 1, resolved_macro);
offset = pos_first + resolved_macro.GetLength();
}
return result; return result;
} }

View File

@ -21,6 +21,7 @@
#define MACROPROCESSOR_H #define MACROPROCESSOR_H
#include "icinga/i2-icinga.h" #include "icinga/i2-icinga.h"
#include "icinga/macroresolver.h"
#include "base/dictionary.h" #include "base/dictionary.h"
#include <boost/function.hpp> #include <boost/function.hpp>
#include <vector> #include <vector>
@ -38,15 +39,17 @@ class I2_ICINGA_API MacroProcessor
public: public:
typedef boost::function<String (const String&)> EscapeCallback; typedef boost::function<String (const String&)> EscapeCallback;
static Value ResolveMacros(const Value& str, const Dictionary::Ptr& macros, static Value ResolveMacros(const Value& str, const std::vector<MacroResolver::Ptr>& resolvers,
const EscapeCallback& escapeFn = EscapeCallback()); const Dictionary::Ptr& cr, const EscapeCallback& escapeFn = EscapeCallback());
static Dictionary::Ptr MergeMacroDicts(const std::vector<Dictionary::Ptr>& macroDicts); static bool ResolveMacro(const String& macro, const std::vector<MacroResolver::Ptr>& resolvers,
const Dictionary::Ptr& cr, String *result);
private: private:
MacroProcessor(void); MacroProcessor(void);
static String InternalResolveMacros(const String& str, static String InternalResolveMacros(const String& str,
const Dictionary::Ptr& macros, const EscapeCallback& escapeFn); const std::vector<MacroResolver::Ptr>& resolvers, const Dictionary::Ptr& cr,
const EscapeCallback& escapeFn);
}; };
} }

View File

@ -0,0 +1,42 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012 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 *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#include "icinga/macroresolver.h"
#include <boost/smart_ptr/make_shared.hpp>
using namespace icinga;
StaticMacroResolver::StaticMacroResolver(void)
: m_Macros(boost::make_shared<Dictionary>())
{ }
void StaticMacroResolver::Add(const String& macro, const String& value)
{
m_Macros->Set(macro, value);
}
bool StaticMacroResolver::ResolveMacro(const String& macro, const Dictionary::Ptr& cr, String *result) const
{
if (m_Macros->Contains(macro)) {
*result = m_Macros->Get(macro);
return true;
}
return false;
}

View File

@ -0,0 +1,62 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012 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 *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#ifndef MACRORESOLVER_H
#define MACRORESOLVER_H
#include "icinga/i2-icinga.h"
#include "base/dictionary.h"
#include "base/qstring.h"
namespace icinga
{
/**
* Resolves macros.
*
* @ingroup icinga
*/
class I2_ICINGA_API MacroResolver
{
public:
typedef shared_ptr<MacroResolver> Ptr;
typedef weak_ptr<MacroResolver> WeakPtr;
virtual bool ResolveMacro(const String& macro, const Dictionary::Ptr& cr, String *result) const = 0;
};
class I2_ICINGA_API StaticMacroResolver : public Object, public MacroResolver
{
public:
typedef shared_ptr<StaticMacroResolver> Ptr;
typedef weak_ptr<StaticMacroResolver> WeakPtr;
StaticMacroResolver(void);
void Add(const String& macro, const String& value);
virtual bool ResolveMacro(const String& macro, const Dictionary::Ptr& cr, String *result) const;
private:
Dictionary::Ptr m_Macros;
};
}
#endif /* MACRORESOLVER_H */

View File

@ -81,6 +81,11 @@ Dictionary::Ptr Notification::GetMacros(void) const
return m_Macros; return m_Macros;
} }
Array::Ptr Notification::GetExportMacros(void) const
{
return m_ExportMacros;
}
std::set<User::Ptr> Notification::GetUsers(void) const std::set<User::Ptr> Notification::GetUsers(void) const
{ {
std::set<User::Ptr> result; std::set<User::Ptr> result;
@ -214,8 +219,6 @@ void Notification::BeginExecuteNotification(NotificationType type, const Diction
SetLastNotification(Utility::GetTime()); SetLastNotification(Utility::GetTime());
} }
Dictionary::Ptr macros = cr->Get("macros");
std::set<User::Ptr> allUsers; std::set<User::Ptr> allUsers;
std::set<User::Ptr> users = GetUsers(); std::set<User::Ptr> users = GetUsers();
@ -228,12 +231,11 @@ void Notification::BeginExecuteNotification(NotificationType type, const Diction
BOOST_FOREACH(const User::Ptr& user, allUsers) { BOOST_FOREACH(const User::Ptr& user, allUsers) {
Log(LogDebug, "icinga", "Sending notification for user " + user->GetName()); Log(LogDebug, "icinga", "Sending notification for user " + user->GetName());
BeginExecuteNotificationHelper(macros, type, user, ignore_timeperiod); BeginExecuteNotificationHelper(type, user, cr, ignore_timeperiod);
} }
} }
void Notification::BeginExecuteNotificationHelper(const Dictionary::Ptr& notificationMacros, void Notification::BeginExecuteNotificationHelper(NotificationType type, const User::Ptr& user, const Dictionary::Ptr& cr, bool ignore_timeperiod)
NotificationType type, const User::Ptr& user, bool ignore_timeperiod)
{ {
ASSERT(!OwnsLock()); ASSERT(!OwnsLock());
@ -247,20 +249,12 @@ void Notification::BeginExecuteNotificationHelper(const Dictionary::Ptr& notific
} }
} }
std::vector<Dictionary::Ptr> macroDicts;
macroDicts.push_back(user->GetMacros());
macroDicts.push_back(user->CalculateDynamicMacros());
macroDicts.push_back(notificationMacros);
Dictionary::Ptr macros = MacroProcessor::MergeMacroDicts(macroDicts);
Notification::Ptr self = GetSelf(); Notification::Ptr self = GetSelf();
std::vector<Value> arguments; std::vector<Value> arguments;
arguments.push_back(self); arguments.push_back(self);
arguments.push_back(macros); arguments.push_back(user);
arguments.push_back(cr);
arguments.push_back(type); arguments.push_back(type);
ScriptTask::Ptr task = MakeMethodTask("notify", arguments); ScriptTask::Ptr task = MakeMethodTask("notify", arguments);
@ -312,3 +306,15 @@ void Notification::OnAttributeChanged(const String& name)
if (name == "host_name" || name == "service") if (name == "host_name" || name == "service")
Service::InvalidateNotificationsCache(); Service::InvalidateNotificationsCache();
} }
bool Notification::ResolveMacro(const String& macro, const Dictionary::Ptr& cr, String *result) const
{
Dictionary::Ptr macros = GetMacros();
if (macros && macros->Contains(macro)) {
*result = macros->Get(macro);
return true;
}
return false;
}

View File

@ -52,7 +52,7 @@ class Service;
* *
* @ingroup icinga * @ingroup icinga
*/ */
class I2_ICINGA_API Notification : public DynamicObject class I2_ICINGA_API Notification : public DynamicObject, public MacroResolver
{ {
public: public:
typedef shared_ptr<Notification> Ptr; typedef shared_ptr<Notification> Ptr;
@ -68,6 +68,7 @@ public:
double GetNotificationInterval(void) const; double GetNotificationInterval(void) const;
TimePeriod::Ptr GetNotificationPeriod(void) const; TimePeriod::Ptr GetNotificationPeriod(void) const;
Dictionary::Ptr GetMacros(void) const; Dictionary::Ptr GetMacros(void) const;
Array::Ptr GetExportMacros(void) const;
std::set<User::Ptr> GetUsers(void) const; std::set<User::Ptr> GetUsers(void) const;
std::set<UserGroup::Ptr> GetGroups(void) const; std::set<UserGroup::Ptr> GetGroups(void) const;
@ -81,6 +82,8 @@ public:
static String NotificationTypeToString(NotificationType type); static String NotificationTypeToString(NotificationType type);
virtual bool ResolveMacro(const String& macro, const Dictionary::Ptr& cr, String *result) const;
protected: protected:
void OnAttributeChanged(const String& name); void OnAttributeChanged(const String& name);
@ -91,6 +94,7 @@ private:
Attribute<double> m_LastNotification; Attribute<double> m_LastNotification;
Attribute<double> m_NextNotification; Attribute<double> m_NextNotification;
Attribute<Dictionary::Ptr> m_Macros; Attribute<Dictionary::Ptr> m_Macros;
Attribute<Array::Ptr> m_ExportMacros;
Attribute<Array::Ptr> m_Users; Attribute<Array::Ptr> m_Users;
Attribute<Array::Ptr> m_Groups; Attribute<Array::Ptr> m_Groups;
Attribute<String> m_HostName; Attribute<String> m_HostName;
@ -100,8 +104,7 @@ private:
void NotificationCompletedHandler(const ScriptTask::Ptr& task); void NotificationCompletedHandler(const ScriptTask::Ptr& task);
void BeginExecuteNotificationHelper(const Dictionary::Ptr& notificationMacros, void BeginExecuteNotificationHelper(NotificationType type, const User::Ptr& user, const Dictionary::Ptr& cr, bool ignore_timeperiod);
NotificationType type, const User::Ptr& user, bool ignore_timeperiod);
}; };
} }

View File

@ -21,6 +21,7 @@
#include "icinga/checkresultmessage.h" #include "icinga/checkresultmessage.h"
#include "icinga/service.h" #include "icinga/service.h"
#include "icinga/macroprocessor.h" #include "icinga/macroprocessor.h"
#include "icinga/icingaapplication.h"
#include "base/dynamictype.h" #include "base/dynamictype.h"
#include "base/objectlock.h" #include "base/objectlock.h"
#include "base/logger_fwd.h" #include "base/logger_fwd.h"
@ -117,8 +118,12 @@ void PerfdataWriter::CheckResultRequestHandler(const RequestMessage& request)
if (!cr) if (!cr)
return; return;
Dictionary::Ptr macros = cr->Get("macros"); std::vector<MacroResolver::Ptr> resolvers;
String line = MacroProcessor::ResolveMacros(GetFormatTemplate(), macros); resolvers.push_back(service);
resolvers.push_back(service->GetHost());
resolvers.push_back(IcingaApplication::GetInstance());
String line = MacroProcessor::ResolveMacros(GetFormatTemplate(), resolvers, cr);
ObjectLock olock(this); ObjectLock olock(this);
if (!m_OutputFile.good()) if (!m_OutputFile.good())

View File

@ -19,7 +19,9 @@
#include "icinga/pluginchecktask.h" #include "icinga/pluginchecktask.h"
#include "icinga/macroprocessor.h" #include "icinga/macroprocessor.h"
#include "icinga/icingaapplication.h"
#include "base/dynamictype.h" #include "base/dynamictype.h"
#include "base/logger_fwd.h"
#include <boost/algorithm/string/classification.hpp> #include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string/split.hpp>
#include <boost/smart_ptr/make_shared.hpp> #include <boost/smart_ptr/make_shared.hpp>
@ -38,16 +40,35 @@ void PluginCheckTask::ScriptFunc(const ScriptTask::Ptr& task, const std::vector<
if (arguments.size() < 1) if (arguments.size() < 1)
BOOST_THROW_EXCEPTION(std::invalid_argument("Missing argument: Service must be specified.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Missing argument: Service must be specified."));
if (arguments.size() < 2)
BOOST_THROW_EXCEPTION(std::invalid_argument("Missing argument: Macros must be specified."));
Service::Ptr service = arguments[0]; Service::Ptr service = arguments[0];
Dictionary::Ptr macros = arguments[1];
Value raw_command = service->GetCheckCommand(); Value raw_command = service->GetCheckCommand();
Value command = MacroProcessor::ResolveMacros(raw_command, macros, Utility::EscapeShellCmd);
Process::Ptr process = boost::make_shared<Process>(Process::SplitCommand(command), macros); std::vector<MacroResolver::Ptr> resolvers;
resolvers.push_back(service);
resolvers.push_back(service->GetHost());
resolvers.push_back(IcingaApplication::GetInstance());
Value command = MacroProcessor::ResolveMacros(raw_command, resolvers, Dictionary::Ptr(), Utility::EscapeShellCmd);
Dictionary::Ptr envMacros = boost::make_shared<Dictionary>();
Array::Ptr export_macros = service->GetExportMacros();
if (export_macros) {
BOOST_FOREACH(const String& macro, export_macros) {
String value;
if (!MacroProcessor::ResolveMacro(macro, resolvers, Dictionary::Ptr(), &value)) {
Log(LogWarning, "icinga", "export_macros for service '" + service->GetName() + "' refers to unknown macro '" + macro + "'");
continue;
}
envMacros->Set(macro, value);
}
}
Process::Ptr process = boost::make_shared<Process>(Process::SplitCommand(command), envMacros);
PluginCheckTask ct(task, process, command); PluginCheckTask ct(task, process, command);

View File

@ -21,9 +21,11 @@
#include "icinga/notification.h" #include "icinga/notification.h"
#include "icinga/service.h" #include "icinga/service.h"
#include "icinga/macroprocessor.h" #include "icinga/macroprocessor.h"
#include "icinga/icingaapplication.h"
#include "base/scriptfunction.h" #include "base/scriptfunction.h"
#include "base/logger_fwd.h" #include "base/logger_fwd.h"
#include <boost/smart_ptr/make_shared.hpp> #include <boost/smart_ptr/make_shared.hpp>
#include <boost/foreach.hpp>
using namespace icinga; using namespace icinga;
@ -40,14 +42,18 @@ void PluginNotificationTask::ScriptFunc(const ScriptTask::Ptr& task, const std::
BOOST_THROW_EXCEPTION(std::invalid_argument("Missing argument: Notification target must be specified.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Missing argument: Notification target must be specified."));
if (arguments.size() < 2) if (arguments.size() < 2)
BOOST_THROW_EXCEPTION(std::invalid_argument("Missing argument: Macros must be specified.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Missing argument: User must be specified."));
if (arguments.size() < 3) if (arguments.size() < 3)
BOOST_THROW_EXCEPTION(std::invalid_argument("Missing argument: CheckResult must be specified."));
if (arguments.size() < 4)
BOOST_THROW_EXCEPTION(std::invalid_argument("Missing argument: Notification type must be specified.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Missing argument: Notification type must be specified."));
Notification::Ptr notification = arguments[0]; Notification::Ptr notification = arguments[0];
Dictionary::Ptr macros = arguments[1]; User::Ptr user = arguments[1];
NotificationType type = static_cast<NotificationType>(static_cast<int>(arguments[2])); Dictionary::Ptr cr = arguments[2];
NotificationType type = static_cast<NotificationType>(static_cast<int>(arguments[3]));
Value raw_command = notification->GetNotificationCommand(); Value raw_command = notification->GetNotificationCommand();
@ -57,18 +63,37 @@ void PluginNotificationTask::ScriptFunc(const ScriptTask::Ptr& task, const std::
if (service) if (service)
service_name = service->GetName(); service_name = service->GetName();
Dictionary::Ptr notificationMacros = boost::make_shared<Dictionary>(); StaticMacroResolver::Ptr notificationMacroResolver = boost::make_shared<StaticMacroResolver>();
notificationMacros->Set("NOTIFICATIONTYPE", Notification::NotificationTypeToString(type)); notificationMacroResolver->Add("NOTIFICATIONTYPE", Notification::NotificationTypeToString(type));
std::vector<Dictionary::Ptr> macroDicts; std::vector<MacroResolver::Ptr> resolvers;
macroDicts.push_back(notificationMacros); resolvers.push_back(user);
macroDicts.push_back(macros); resolvers.push_back(notificationMacroResolver);
resolvers.push_back(notification);
resolvers.push_back(service);
resolvers.push_back(service->GetHost());
resolvers.push_back(IcingaApplication::GetInstance());
Dictionary::Ptr allMacros = MacroProcessor::MergeMacroDicts(macroDicts); Value command = MacroProcessor::ResolveMacros(raw_command, resolvers, cr, Utility::EscapeShellCmd);
Value command = MacroProcessor::ResolveMacros(raw_command, allMacros, Utility::EscapeShellCmd); Dictionary::Ptr envMacros = boost::make_shared<Dictionary>();
Process::Ptr process = boost::make_shared<Process>(Process::SplitCommand(command), macros); Array::Ptr export_macros = notification->GetExportMacros();
if (export_macros) {
BOOST_FOREACH(const String& macro, export_macros) {
String value;
if (!MacroProcessor::ResolveMacro(macro, resolvers, cr, &value)) {
Log(LogWarning, "icinga", "export_macros for notification '" + notification->GetName() + "' refers to unknown macro '" + macro + "'");
continue;
}
envMacros->Set(macro, value);
}
}
Process::Ptr process = boost::make_shared<Process>(Process::SplitCommand(command), envMacros);
PluginNotificationTask ct(task, process, service_name, command); PluginNotificationTask ct(task, process, service_name, command);

View File

@ -429,9 +429,6 @@ void Service::ProcessCheckResult(const Dictionary::Ptr& cr)
cr->Set("vars_after", vars_after); cr->Set("vars_after", vars_after);
/* Update macros - these are used by event handlers and notifications. */
cr->Set("macros", CalculateAllMacros(cr));
cr->Seal(); cr->Seal();
olock.Lock(); olock.Lock();
@ -556,14 +553,10 @@ void Service::BeginExecuteCheck(const boost::function<void (void)>& callback)
checkInfo->Set("schedule_start", GetNextCheck()); checkInfo->Set("schedule_start", GetNextCheck());
checkInfo->Set("execution_start", Utility::GetTime()); checkInfo->Set("execution_start", Utility::GetTime());
Dictionary::Ptr macros = CalculateAllMacros();
checkInfo->Set("macros", macros);
Service::Ptr self = GetSelf(); Service::Ptr self = GetSelf();
std::vector<Value> arguments; std::vector<Value> arguments;
arguments.push_back(self); arguments.push_back(self);
arguments.push_back(macros);
ScriptTask::Ptr task = MakeMethodTask("check", arguments); ScriptTask::Ptr task = MakeMethodTask("check", arguments);

View File

@ -243,6 +243,7 @@ void Service::UpdateSlaveNotifications(void)
keys.insert("groups"); keys.insert("groups");
keys.insert("notification_interval"); keys.insert("notification_interval");
keys.insert("notification_period"); keys.insert("notification_period");
keys.insert("export_macros");
ExpressionList::Ptr svc_exprl = boost::make_shared<ExpressionList>(); ExpressionList::Ptr svc_exprl = boost::make_shared<ExpressionList>();
item->GetLinkedExpressionList()->ExtractFiltered(keys, svc_exprl); item->GetLinkedExpressionList()->ExtractFiltered(keys, svc_exprl);

View File

@ -21,9 +21,10 @@
#include "icinga/servicegroup.h" #include "icinga/servicegroup.h"
#include "icinga/icingaapplication.h" #include "icinga/icingaapplication.h"
#include "icinga/macroprocessor.h" #include "icinga/macroprocessor.h"
#include "config/configitembuilder.h"
#include "base/dynamictype.h" #include "base/dynamictype.h"
#include "base/objectlock.h" #include "base/objectlock.h"
#include "config/configitembuilder.h" #include "base/convert.h"
#include <boost/smart_ptr/make_shared.hpp> #include <boost/smart_ptr/make_shared.hpp>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
@ -37,6 +38,7 @@ Service::Service(const Dictionary::Ptr& serializedObject)
RegisterAttribute("display_name", Attribute_Config, &m_DisplayName); RegisterAttribute("display_name", Attribute_Config, &m_DisplayName);
RegisterAttribute("macros", Attribute_Config, &m_Macros); RegisterAttribute("macros", Attribute_Config, &m_Macros);
RegisterAttribute("export_macros", Attribute_Config, &m_ExportMacros);
RegisterAttribute("hostdependencies", Attribute_Config, &m_HostDependencies); RegisterAttribute("hostdependencies", Attribute_Config, &m_HostDependencies);
RegisterAttribute("servicedependencies", Attribute_Config, &m_ServiceDependencies); RegisterAttribute("servicedependencies", Attribute_Config, &m_ServiceDependencies);
RegisterAttribute("servicegroups", Attribute_Config, &m_ServiceGroups); RegisterAttribute("servicegroups", Attribute_Config, &m_ServiceGroups);
@ -136,6 +138,11 @@ Dictionary::Ptr Service::GetMacros(void) const
return m_Macros; return m_Macros;
} }
Array::Ptr Service::GetExportMacros(void) const
{
return m_ExportMacros;
}
Array::Ptr Service::GetHostDependencies(void) const Array::Ptr Service::GetHostDependencies(void) const
{ {
return m_HostDependencies; return m_HostDependencies;
@ -369,68 +376,73 @@ std::set<Service::Ptr> Service::GetParentServices(void) const
return parents; return parents;
} }
Dictionary::Ptr Service::CalculateDynamicMacros(const Dictionary::Ptr& crOverride) const bool Service::ResolveMacro(const String& macro, const Dictionary::Ptr& cr, String *result) const
{ {
Dictionary::Ptr macros = boost::make_shared<Dictionary>(); if (macro == "SERVICEDESC") {
*result = GetShortName();
Dictionary::Ptr cr; return true;
} else if (macro == "SERVICEDISPLAYNAME") {
{ *result = GetDisplayName();
ObjectLock olock(this); return true;
macros->Set("SERVICEDESC", GetShortName()); } else if (macro == "SERVICECHECKCOMMAND") {
macros->Set("SERVICEDISPLAYNAME", GetDisplayName()); *result = "check_i2";
macros->Set("SERVICESTATE", StateToString(GetState())); return true;
macros->Set("SERVICESTATEID", GetState());
macros->Set("SERVICESTATETYPE", StateTypeToString(GetStateType()));
macros->Set("SERVICEATTEMPT", GetCurrentCheckAttempt());
macros->Set("MAXSERVICEATTEMPT", GetMaxCheckAttempts());
macros->Set("SERVICECHECKCOMMAND", "check_i2");
macros->Set("LASTSERVICESTATE", StateToString(GetLastState()));
macros->Set("LASTSERVICESTATEID", GetLastState());
macros->Set("LASTSERVICESTATETYPE", StateTypeToString(GetLastStateType()));
macros->Set("LASTSERVICESTATECHANGE", (long)GetLastStateChange());
cr = GetLastCheckResult();
} }
if (crOverride) if (macro == "SERVICESTATE") {
cr = crOverride; *result = StateToString(GetState());
return true;
} else if (macro == "SERVICESTATEID") {
*result = Convert::ToString(GetState());
return true;
} else if (macro == "SERVICESTATETYPE") {
*result = StateTypeToString(GetStateType());
return true;
} else if (macro == "SERVICEATTEMPT") {
*result = Convert::ToString(GetCurrentCheckAttempt());
return true;
} else if (macro == "MAXSERVICEATTEMPT") {
*result = Convert::ToString(GetMaxCheckAttempts());
return true;
} else if (macro == "LASTSERVICESTATE") {
*result = StateToString(GetLastState());
return true;
} else if (macro == "LASTSERVICESTATEID") {
*result = Convert::ToString(GetLastState());
return true;
} else if (macro == "LASTSERVICESTATETYPE") {
*result = StateTypeToString(GetLastStateType());
return true;
} else if (macro == "LASTSERVICESTATECHANGE") {
*result = Convert::ToString((long)GetLastStateChange());
return true;
}
if (cr) { if (cr) {
ASSERT(crOverride || cr->IsSealed()); if (macro == "SERVICELATENCY") {
*result = Convert::ToString(Service::CalculateLatency(cr));
macros->Set("SERVICELATENCY", Service::CalculateLatency(cr)); return true;
macros->Set("SERVICEEXECUTIONTIME", Service::CalculateExecutionTime(cr)); } else if (macro == "SERVICEEXECUTIONTIME") {
*result = Convert::ToString(Service::CalculateExecutionTime(cr));
macros->Set("SERVICEOUTPUT", cr->Get("output")); return true;
macros->Set("SERVICEPERFDATA", cr->Get("performance_data_raw")); } else if (macro == "SERVICEOUTPUT") {
*result = cr->Get("output");
macros->Set("LASTSERVICECHECK", (long)cr->Get("execution_end")); return true;
} else if (macro == "SERVICEPERFDATA") {
*result = cr->Get("performance_data_raw");
return true;
} else if (macro == "LASTSERVICECHECK") {
*result = Convert::ToString((long)cr->Get("execution_end"));
return true;
}
} }
macros->Seal(); Dictionary::Ptr macros = GetMacros();
return macros; if (macros && macros->Contains(macro)) {
} *result = macros->Get(macro);
return true;
Dictionary::Ptr Service::CalculateAllMacros(const Dictionary::Ptr& crOverride) const
{
std::vector<Dictionary::Ptr> macroDicts;
macroDicts.push_back(GetMacros());
Host::Ptr host = GetHost();
macroDicts.push_back(CalculateDynamicMacros(crOverride));
if (host) {
macroDicts.push_back(host->GetMacros());
macroDicts.push_back(host->CalculateDynamicMacros());
} }
IcingaApplication::Ptr app = IcingaApplication::GetInstance(); return false;
macroDicts.push_back(app->GetMacros());
macroDicts.push_back(IcingaApplication::CalculateDynamicMacros());
return MacroProcessor::MergeMacroDicts(macroDicts);
} }

View File

@ -21,6 +21,7 @@
#define SERVICE_H #define SERVICE_H
#include "icinga/i2-icinga.h" #include "icinga/i2-icinga.h"
#include "icinga/macroresolver.h"
#include "icinga/host.h" #include "icinga/host.h"
#include "icinga/timeperiod.h" #include "icinga/timeperiod.h"
#include "icinga/notification.h" #include "icinga/notification.h"
@ -63,7 +64,7 @@ class CheckResultMessage;
* *
* @ingroup icinga * @ingroup icinga
*/ */
class I2_ICINGA_API Service : public DynamicObject class I2_ICINGA_API Service : public DynamicObject, public MacroResolver
{ {
public: public:
typedef shared_ptr<Service> Ptr; typedef shared_ptr<Service> Ptr;
@ -83,15 +84,13 @@ public:
String GetDisplayName(void) const; String GetDisplayName(void) const;
Host::Ptr GetHost(void) const; Host::Ptr GetHost(void) const;
Dictionary::Ptr GetMacros(void) const; Dictionary::Ptr GetMacros(void) const;
Array::Ptr GetExportMacros(void) const;
Array::Ptr GetHostDependencies(void) const; Array::Ptr GetHostDependencies(void) const;
Array::Ptr GetServiceDependencies(void) const; Array::Ptr GetServiceDependencies(void) const;
Array::Ptr GetGroups(void) const; Array::Ptr GetGroups(void) const;
String GetHostName(void) const; String GetHostName(void) const;
String GetShortName(void) const; String GetShortName(void) const;
Dictionary::Ptr CalculateDynamicMacros(const Dictionary::Ptr& crOverride = Dictionary::Ptr()) const;
Dictionary::Ptr CalculateAllMacros(const Dictionary::Ptr& crOverride = Dictionary::Ptr()) const;
std::set<Host::Ptr> GetParentHosts(void) const; std::set<Host::Ptr> GetParentHosts(void) const;
std::set<Service::Ptr> GetParentServices(void) const; std::set<Service::Ptr> GetParentServices(void) const;
@ -179,6 +178,8 @@ public:
static boost::signals2::signal<void (const Service::Ptr&)> OnCheckerChanged; static boost::signals2::signal<void (const Service::Ptr&)> OnCheckerChanged;
static boost::signals2::signal<void (const Service::Ptr&)> OnNextCheckChanged; static boost::signals2::signal<void (const Service::Ptr&)> OnNextCheckChanged;
virtual bool ResolveMacro(const String& macro, const Dictionary::Ptr& cr, String *result) const;
/* Downtimes */ /* Downtimes */
static int GetNextDowntimeID(void); static int GetNextDowntimeID(void);
@ -249,6 +250,7 @@ private:
Attribute<String> m_DisplayName; Attribute<String> m_DisplayName;
Attribute<Dictionary::Ptr> m_Macros; Attribute<Dictionary::Ptr> m_Macros;
Attribute<Array::Ptr> m_ExportMacros;
Attribute<Array::Ptr> m_HostDependencies; Attribute<Array::Ptr> m_HostDependencies;
Attribute<Array::Ptr> m_ServiceDependencies; Attribute<Array::Ptr> m_ServiceDependencies;
Attribute<Array::Ptr> m_ServiceGroups; Attribute<Array::Ptr> m_ServiceGroups;

View File

@ -78,14 +78,22 @@ TimePeriod::Ptr User::GetNotificationPeriod(void) const
return TimePeriod::GetByName(m_NotificationPeriod); return TimePeriod::GetByName(m_NotificationPeriod);
} }
Dictionary::Ptr User::CalculateDynamicMacros(void) const bool User::ResolveMacro(const String& macro, const Dictionary::Ptr& cr, String *result) const
{ {
Dictionary::Ptr macros = boost::make_shared<Dictionary>(); if (macro == "CONTACTNAME") {
*result = GetName();
return true;
} else if (macro == "CONTACTALIAS") {
*result = GetName();
return true;
} else {
Dictionary::Ptr macros = GetMacros();
macros->Set("CONTACTNAME", GetName()); if (macros && macros->Contains(macro)) {
macros->Set("CONTACTALIAS", GetName()); *result = macros->Get(macro);
return true;
}
macros->Seal(); return false;
}
return macros;
} }

View File

@ -21,6 +21,7 @@
#define USER_H #define USER_H
#include "icinga/i2-icinga.h" #include "icinga/i2-icinga.h"
#include "icinga/macroresolver.h"
#include "icinga/timeperiod.h" #include "icinga/timeperiod.h"
#include "base/dynamicobject.h" #include "base/dynamicobject.h"
#include "base/array.h" #include "base/array.h"
@ -33,7 +34,7 @@ namespace icinga
* *
* @ingroup icinga * @ingroup icinga
*/ */
class I2_ICINGA_API User : public DynamicObject class I2_ICINGA_API User : public DynamicObject, public MacroResolver
{ {
public: public:
typedef shared_ptr<User> Ptr; typedef shared_ptr<User> Ptr;
@ -49,7 +50,8 @@ public:
TimePeriod::Ptr GetNotificationPeriod(void) const; TimePeriod::Ptr GetNotificationPeriod(void) const;
Dictionary::Ptr GetMacros(void) const; Dictionary::Ptr GetMacros(void) const;
Dictionary::Ptr CalculateDynamicMacros(void) const;
virtual bool ResolveMacro(const String& macro, const Dictionary::Ptr& cr, String *result) const;
protected: protected:
virtual void OnAttributeChanged(const String& name); virtual void OnAttributeChanged(const String& name);