diff --git a/doc/03-monitoring-basics.md b/doc/03-monitoring-basics.md
index 672c026ff..79ef8cc5d 100644
--- a/doc/03-monitoring-basics.md
+++ b/doc/03-monitoring-basics.md
@@ -664,6 +664,13 @@ The following macros provide global statistics:
icinga.num\_hosts\_in\_downtime | Current number of hosts in downtime.
icinga.num\_hosts\_acknowledged | Current number of acknowledged host problems.
+### Environment Variable Runtime Macros
+
+All environment variables of the Icinga process are available as runtime macros
+named `env.`. E.g. `$env.ProgramFiles$` for ProgramFiles which is
+especially useful on Windows. In contrast to the other runtime macros env vars
+require the `env.` prefix.
+
## Apply Rules
diff --git a/lib/db_ido/idochecktask.cpp b/lib/db_ido/idochecktask.cpp
index 6a7f0d363..d3b456963 100644
--- a/lib/db_ido/idochecktask.cpp
+++ b/lib/db_ido/idochecktask.cpp
@@ -1,6 +1,7 @@
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
#include "db_ido/idochecktask.hpp"
+#include "icinga/envresolver.hpp"
#include "icinga/host.hpp"
#include "icinga/checkcommand.hpp"
#include "icinga/macroprocessor.hpp"
@@ -61,6 +62,7 @@ void IdoCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult
resolvers.emplace_back("host", host);
resolvers.emplace_back("command", commandObj);
resolvers.emplace_back("icinga", IcingaApplication::GetInstance());
+ resolvers.emplace_back("env", new EnvResolver(), false);
String idoType = MacroProcessor::ResolveMacros("$ido_type$", resolvers, checkable->GetLastCheckResult(),
nullptr, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
diff --git a/lib/icinga/apiactions.cpp b/lib/icinga/apiactions.cpp
index ff3c6506d..2b9de044d 100644
--- a/lib/icinga/apiactions.cpp
+++ b/lib/icinga/apiactions.cpp
@@ -2,6 +2,7 @@
#include "icinga/apiactions.hpp"
#include "icinga/checkable.hpp"
+#include "icinga/envresolver.hpp"
#include "icinga/service.hpp"
#include "icinga/servicegroup.hpp"
#include "icinga/hostgroup.hpp"
@@ -668,6 +669,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, cons
resolvers.emplace_back("host", host);
resolvers.emplace_back("icinga", IcingaApplication::GetInstance());
+ resolvers.emplace_back("env", new EnvResolver(), false);
String resolved_endpoint = MacroProcessor::ResolveMacros(
endpoint, resolvers, checkable->GetLastCheckResult(),
diff --git a/lib/icingadb/icingadbchecktask.cpp b/lib/icingadb/icingadbchecktask.cpp
index c2f1a3699..4e2bb5f16 100644
--- a/lib/icingadb/icingadbchecktask.cpp
+++ b/lib/icingadb/icingadbchecktask.cpp
@@ -1,6 +1,7 @@
/* Icinga 2 | (c) 2022 Icinga GmbH | GPLv2+ */
#include "icingadb/icingadbchecktask.hpp"
+#include "icinga/envresolver.hpp"
#include "icinga/host.hpp"
#include "icinga/checkcommand.hpp"
#include "icinga/macroprocessor.hpp"
@@ -62,6 +63,7 @@ void IcingadbCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckR
resolvers.emplace_back("host", host);
resolvers.emplace_back("command", commandObj);
resolvers.emplace_back("icinga", IcingaApplication::GetInstance());
+ resolvers.emplace_back("env", new EnvResolver(), false);
auto resolve ([&](const String& macro) {
return MacroProcessor::ResolveMacros(macro, resolvers, checkable->GetLastCheckResult(),
diff --git a/lib/livestatus/hoststable.cpp b/lib/livestatus/hoststable.cpp
index ad049edbe..edf921c72 100644
--- a/lib/livestatus/hoststable.cpp
+++ b/lib/livestatus/hoststable.cpp
@@ -3,6 +3,7 @@
#include "livestatus/hoststable.hpp"
#include "livestatus/hostgroupstable.hpp"
#include "livestatus/endpointstable.hpp"
+#include "icinga/envresolver.hpp"
#include "icinga/host.hpp"
#include "icinga/service.hpp"
#include "icinga/hostgroup.hpp"
@@ -315,7 +316,8 @@ Value HostsTable::NotesExpandedAccessor(const Value& row)
MacroProcessor::ResolverList resolvers {
{ "host", host },
- { "icinga", IcingaApplication::GetInstance() }
+ { "icinga", IcingaApplication::GetInstance() },
+ { "env", new EnvResolver(), false }
};
return MacroProcessor::ResolveMacros(host->GetNotes(), resolvers);
@@ -340,7 +342,8 @@ Value HostsTable::NotesUrlExpandedAccessor(const Value& row)
MacroProcessor::ResolverList resolvers {
{ "host", host },
- { "icinga", IcingaApplication::GetInstance() }
+ { "icinga", IcingaApplication::GetInstance() },
+ { "env", new EnvResolver(), false }
};
return MacroProcessor::ResolveMacros(host->GetNotesUrl(), resolvers);
@@ -365,7 +368,8 @@ Value HostsTable::ActionUrlExpandedAccessor(const Value& row)
MacroProcessor::ResolverList resolvers {
{ "host", host },
- { "icinga", IcingaApplication::GetInstance() }
+ { "icinga", IcingaApplication::GetInstance() },
+ { "env", new EnvResolver(), false }
};
return MacroProcessor::ResolveMacros(host->GetActionUrl(), resolvers);
@@ -422,7 +426,8 @@ Value HostsTable::IconImageExpandedAccessor(const Value& row)
MacroProcessor::ResolverList resolvers {
{ "host", host },
- { "icinga", IcingaApplication::GetInstance() }
+ { "icinga", IcingaApplication::GetInstance() },
+ { "env", new EnvResolver(), false }
};
return MacroProcessor::ResolveMacros(host->GetIconImage(), resolvers);
diff --git a/lib/livestatus/servicestable.cpp b/lib/livestatus/servicestable.cpp
index bb5d4fb81..f472e0ff0 100644
--- a/lib/livestatus/servicestable.cpp
+++ b/lib/livestatus/servicestable.cpp
@@ -9,6 +9,7 @@
#include "icinga/servicegroup.hpp"
#include "icinga/hostgroup.hpp"
#include "icinga/checkcommand.hpp"
+#include "icinga/envresolver.hpp"
#include "icinga/eventcommand.hpp"
#include "icinga/timeperiod.hpp"
#include "icinga/macroprocessor.hpp"
@@ -372,7 +373,8 @@ Value ServicesTable::NotesExpandedAccessor(const Value& row)
MacroProcessor::ResolverList resolvers {
{ "service", service },
{ "host", service->GetHost() },
- { "icinga", IcingaApplication::GetInstance() }
+ { "icinga", IcingaApplication::GetInstance() },
+ { "env", new EnvResolver(), false }
};
return MacroProcessor::ResolveMacros(service->GetNotes(), resolvers);
@@ -398,7 +400,8 @@ Value ServicesTable::NotesUrlExpandedAccessor(const Value& row)
MacroProcessor::ResolverList resolvers {
{ "service", service },
{ "host", service->GetHost() },
- { "icinga", IcingaApplication::GetInstance() }
+ { "icinga", IcingaApplication::GetInstance() },
+ { "env", new EnvResolver(), false }
};
return MacroProcessor::ResolveMacros(service->GetNotesUrl(), resolvers);
@@ -424,7 +427,8 @@ Value ServicesTable::ActionUrlExpandedAccessor(const Value& row)
MacroProcessor::ResolverList resolvers {
{ "service", service },
{ "host", service->GetHost() },
- { "icinga", IcingaApplication::GetInstance() }
+ { "icinga", IcingaApplication::GetInstance() },
+ { "env", new EnvResolver(), false }
};
return MacroProcessor::ResolveMacros(service->GetActionUrl(), resolvers);
@@ -450,7 +454,8 @@ Value ServicesTable::IconImageExpandedAccessor(const Value& row)
MacroProcessor::ResolverList resolvers {
{ "service", service },
{ "host", service->GetHost() },
- { "icinga", IcingaApplication::GetInstance() }
+ { "icinga", IcingaApplication::GetInstance() },
+ { "env", new EnvResolver(), false }
};
return MacroProcessor::ResolveMacros(service->GetIconImage(), resolvers);
diff --git a/lib/methods/clusterzonechecktask.cpp b/lib/methods/clusterzonechecktask.cpp
index 983719795..838d94422 100644
--- a/lib/methods/clusterzonechecktask.cpp
+++ b/lib/methods/clusterzonechecktask.cpp
@@ -2,6 +2,7 @@
#include "methods/clusterzonechecktask.hpp"
#include "icinga/checkcommand.hpp"
+#include "icinga/envresolver.hpp"
#include "icinga/macroprocessor.hpp"
#include "remote/apilistener.hpp"
#include "remote/endpoint.hpp"
@@ -64,6 +65,7 @@ void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const Che
resolvers.emplace_back("host", host);
resolvers.emplace_back("command", command);
resolvers.emplace_back("icinga", IcingaApplication::GetInstance());
+ resolvers.emplace_back("env", new EnvResolver(), false);
String zoneName = MacroProcessor::ResolveMacros("$cluster_zone$", resolvers, checkable->GetLastCheckResult(),
nullptr, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
diff --git a/lib/methods/dummychecktask.cpp b/lib/methods/dummychecktask.cpp
index 561415c64..2f9a27286 100644
--- a/lib/methods/dummychecktask.cpp
+++ b/lib/methods/dummychecktask.cpp
@@ -4,6 +4,7 @@
# include
#endif /* _WIN32 */
#include "methods/dummychecktask.hpp"
+#include "icinga/envresolver.hpp"
#include "icinga/icingaapplication.hpp"
#include "icinga/pluginutility.hpp"
#include "base/utility.hpp"
@@ -38,6 +39,7 @@ void DummyCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResu
resolvers.emplace_back("host", host);
resolvers.emplace_back("command", command);
resolvers.emplace_back("icinga", IcingaApplication::GetInstance());
+ resolvers.emplace_back("env", new EnvResolver(), false);
int dummyState = MacroProcessor::ResolveMacros("$dummy_state$", resolvers, checkable->GetLastCheckResult(),
nullptr, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
diff --git a/lib/methods/icingachecktask.cpp b/lib/methods/icingachecktask.cpp
index 40795495d..5662f9cbd 100644
--- a/lib/methods/icingachecktask.cpp
+++ b/lib/methods/icingachecktask.cpp
@@ -2,6 +2,7 @@
#include "methods/icingachecktask.hpp"
#include "icinga/cib.hpp"
+#include "icinga/envresolver.hpp"
#include "icinga/service.hpp"
#include "icinga/checkcommand.hpp"
#include "icinga/macroprocessor.hpp"
@@ -42,6 +43,7 @@ void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes
resolvers.emplace_back("host", host);
resolvers.emplace_back("command", command);
resolvers.emplace_back("icinga", IcingaApplication::GetInstance());
+ resolvers.emplace_back("env", new EnvResolver(), false);
String missingIcingaMinVersion;
diff --git a/lib/methods/pluginchecktask.cpp b/lib/methods/pluginchecktask.cpp
index 9bfa72203..2710c01c1 100644
--- a/lib/methods/pluginchecktask.cpp
+++ b/lib/methods/pluginchecktask.cpp
@@ -1,6 +1,7 @@
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
#include "methods/pluginchecktask.hpp"
+#include "icinga/envresolver.hpp"
#include "icinga/pluginutility.hpp"
#include "icinga/checkcommand.hpp"
#include "icinga/macroprocessor.hpp"
@@ -38,6 +39,7 @@ void PluginCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes
resolvers.emplace_back("host", host);
resolvers.emplace_back("command", commandObj);
resolvers.emplace_back("icinga", IcingaApplication::GetInstance());
+ resolvers.emplace_back("env", new EnvResolver(), false);
int timeout = commandObj->GetTimeout();
diff --git a/lib/methods/plugineventtask.cpp b/lib/methods/plugineventtask.cpp
index 8b2fc44ac..76204d6ec 100644
--- a/lib/methods/plugineventtask.cpp
+++ b/lib/methods/plugineventtask.cpp
@@ -1,6 +1,7 @@
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
#include "methods/plugineventtask.hpp"
+#include "icinga/envresolver.hpp"
#include "icinga/eventcommand.hpp"
#include "icinga/macroprocessor.hpp"
#include "icinga/pluginutility.hpp"
@@ -37,6 +38,7 @@ void PluginEventTask::ScriptFunc(const Checkable::Ptr& checkable,
resolvers.emplace_back("host", host);
resolvers.emplace_back("command", commandObj);
resolvers.emplace_back("icinga", IcingaApplication::GetInstance());
+ resolvers.emplace_back("env", new EnvResolver(), false);
int timeout = commandObj->GetTimeout();
std::function callback;
diff --git a/lib/methods/pluginnotificationtask.cpp b/lib/methods/pluginnotificationtask.cpp
index 17f34cda8..09880e973 100644
--- a/lib/methods/pluginnotificationtask.cpp
+++ b/lib/methods/pluginnotificationtask.cpp
@@ -1,6 +1,7 @@
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
#include "methods/pluginnotificationtask.hpp"
+#include "icinga/envresolver.hpp"
#include "icinga/notification.hpp"
#include "icinga/notificationcommand.hpp"
#include "icinga/pluginutility.hpp"
@@ -54,6 +55,7 @@ void PluginNotificationTask::ScriptFunc(const Notification::Ptr& notification,
resolvers.emplace_back("host", host);
resolvers.emplace_back("command", commandObj);
resolvers.emplace_back("icinga", IcingaApplication::GetInstance());
+ resolvers.emplace_back("env", new EnvResolver(), false);
int timeout = commandObj->GetTimeout();
std::function callback;
diff --git a/lib/methods/sleepchecktask.cpp b/lib/methods/sleepchecktask.cpp
index a018de46b..61bb91794 100644
--- a/lib/methods/sleepchecktask.cpp
+++ b/lib/methods/sleepchecktask.cpp
@@ -1,6 +1,7 @@
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
#include "methods/sleepchecktask.hpp"
+#include "icinga/envresolver.hpp"
#include "icinga/icingaapplication.hpp"
#include "icinga/pluginutility.hpp"
#include "base/utility.hpp"
@@ -34,6 +35,7 @@ void SleepCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResu
resolvers.emplace_back("host", host);
resolvers.emplace_back("command", commandObj);
resolvers.emplace_back("icinga", IcingaApplication::GetInstance());
+ resolvers.emplace_back("env", new EnvResolver(), false);
double sleepTime = MacroProcessor::ResolveMacros("$sleep_time$", resolvers, checkable->GetLastCheckResult(),
nullptr, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
diff --git a/lib/perfdata/graphitewriter.cpp b/lib/perfdata/graphitewriter.cpp
index 4b9424e80..4ea12dcdf 100644
--- a/lib/perfdata/graphitewriter.cpp
+++ b/lib/perfdata/graphitewriter.cpp
@@ -2,6 +2,7 @@
#include "perfdata/graphitewriter.hpp"
#include "perfdata/graphitewriter-ti.cpp"
+#include "icinga/envresolver.hpp"
#include "icinga/service.hpp"
#include "icinga/checkcommand.hpp"
#include "icinga/macroprocessor.hpp"
@@ -294,6 +295,7 @@ void GraphiteWriter::CheckResultHandlerInternal(const Checkable::Ptr& checkable,
resolvers.emplace_back("service", service);
resolvers.emplace_back("host", host);
resolvers.emplace_back("icinga", IcingaApplication::GetInstance());
+ resolvers.emplace_back("env", new EnvResolver(), false);
String prefix;
diff --git a/lib/perfdata/influxdbcommonwriter.cpp b/lib/perfdata/influxdbcommonwriter.cpp
index 42b7f02b7..1490ffb10 100644
--- a/lib/perfdata/influxdbcommonwriter.cpp
+++ b/lib/perfdata/influxdbcommonwriter.cpp
@@ -3,6 +3,7 @@
#include "perfdata/influxdbcommonwriter.hpp"
#include "perfdata/influxdbcommonwriter-ti.cpp"
#include "remote/url.hpp"
+#include "icinga/envresolver.hpp"
#include "icinga/service.hpp"
#include "icinga/macroprocessor.hpp"
#include "icinga/icingaapplication.hpp"
@@ -225,6 +226,7 @@ void InfluxdbCommonWriter::CheckResultHandlerWQ(const Checkable::Ptr& checkable,
resolvers.emplace_back("service", service);
resolvers.emplace_back("host", host);
resolvers.emplace_back("icinga", IcingaApplication::GetInstance());
+ resolvers.emplace_back("env", new EnvResolver(), false);
String prefix;
diff --git a/lib/perfdata/opentsdbwriter.cpp b/lib/perfdata/opentsdbwriter.cpp
index 066377ab1..4291a4fe5 100644
--- a/lib/perfdata/opentsdbwriter.cpp
+++ b/lib/perfdata/opentsdbwriter.cpp
@@ -2,6 +2,7 @@
#include "perfdata/opentsdbwriter.hpp"
#include "perfdata/opentsdbwriter-ti.cpp"
+#include "icinga/envresolver.hpp"
#include "icinga/service.hpp"
#include "icinga/checkcommand.hpp"
#include "icinga/macroprocessor.hpp"
@@ -196,6 +197,7 @@ void OpenTsdbWriter::CheckResultHandler(const Checkable::Ptr& checkable, const C
resolvers.emplace_back("service", service);
resolvers.emplace_back("host", host);
resolvers.emplace_back("icinga", IcingaApplication::GetInstance());
+ resolvers.emplace_back("env", new EnvResolver(), false);
// Resolve macros for the service and host template config line
if (config_tmpl_tags) {
diff --git a/lib/perfdata/perfdatawriter.cpp b/lib/perfdata/perfdatawriter.cpp
index 77652b1da..711f9e193 100644
--- a/lib/perfdata/perfdatawriter.cpp
+++ b/lib/perfdata/perfdatawriter.cpp
@@ -2,6 +2,7 @@
#include "perfdata/perfdatawriter.hpp"
#include "perfdata/perfdatawriter-ti.cpp"
+#include "icinga/envresolver.hpp"
#include "icinga/service.hpp"
#include "icinga/macroprocessor.hpp"
#include "icinga/icingaapplication.hpp"
@@ -117,6 +118,7 @@ void PerfdataWriter::CheckResultHandler(const Checkable::Ptr& checkable, const C
resolvers.emplace_back("service", service);
resolvers.emplace_back("host", host);
resolvers.emplace_back("icinga", IcingaApplication::GetInstance());
+ resolvers.emplace_back("env", new EnvResolver(), false);
if (service) {
String line = MacroProcessor::ResolveMacros(GetServiceFormatTemplate(), resolvers, cr, nullptr, &PerfdataWriter::EscapeMacroMetric);