]> granicus.if.org Git - icinga2/blob - lib/icinga/icingaapplication.cpp
Correct current_concurrent_checks to actually running checks
[icinga2] / lib / icinga / icingaapplication.cpp
1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2
3 #include "icinga/icingaapplication.hpp"
4 #include "icinga/icingaapplication-ti.cpp"
5 #include "icinga/cib.hpp"
6 #include "icinga/macroprocessor.hpp"
7 #include "config/configcompiler.hpp"
8 #include "base/configwriter.hpp"
9 #include "base/configtype.hpp"
10 #include "base/logger.hpp"
11 #include "base/objectlock.hpp"
12 #include "base/convert.hpp"
13 #include "base/debug.hpp"
14 #include "base/utility.hpp"
15 #include "base/timer.hpp"
16 #include "base/scriptglobal.hpp"
17 #include "base/initialize.hpp"
18 #include "base/statsfunction.hpp"
19 #include "base/loader.hpp"
20 #include <fstream>
21
22 using namespace icinga;
23
24 static Timer::Ptr l_RetentionTimer;
25
26 REGISTER_TYPE(IcingaApplication);
27 /* Ensure that the priority is lower than the basic System namespace initialization in scriptframe.cpp. */
28 INITIALIZE_ONCE_WITH_PRIORITY(&IcingaApplication::StaticInitialize, 50);
29
30 void IcingaApplication::StaticInitialize()
31 {
32         /* Pre-fill global constants, can be overridden with user input later in icinga-app/icinga.cpp. */
33         String node_name = Utility::GetFQDN();
34
35         if (node_name.IsEmpty()) {
36                 Log(LogNotice, "IcingaApplication", "No FQDN available. Trying Hostname.");
37                 node_name = Utility::GetHostName();
38
39                 if (node_name.IsEmpty()) {
40                         Log(LogWarning, "IcingaApplication", "No FQDN nor Hostname available. Setting Nodename to 'localhost'.");
41                         node_name = "localhost";
42                 }
43         }
44
45         ScriptGlobal::Set("NodeName", node_name);
46
47         ScriptGlobal::Set("ReloadTimeout", 300);
48         ScriptGlobal::Set("MaxConcurrentChecks", 512);
49
50         Namespace::Ptr systemNS = ScriptGlobal::Get("System");
51         /* Ensure that the System namespace is already initialized. Otherwise this is a programming error. */
52         VERIFY(systemNS);
53
54         systemNS->Set("ApplicationType", "IcingaApplication", true);
55         systemNS->Set("ApplicationVersion", Application::GetAppVersion(), true);
56
57         Namespace::Ptr globalNS = ScriptGlobal::GetGlobals();
58         VERIFY(globalNS);
59
60         auto icingaNSBehavior = new ConstNamespaceBehavior();
61         icingaNSBehavior->Freeze();
62         Namespace::Ptr icingaNS = new Namespace(icingaNSBehavior);
63         globalNS->SetAttribute("Icinga", std::make_shared<ConstEmbeddedNamespaceValue>(icingaNS));
64 }
65
66 REGISTER_STATSFUNCTION(IcingaApplication, &IcingaApplication::StatsFunc);
67
68 void IcingaApplication::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata)
69 {
70         DictionaryData nodes;
71
72         for (const IcingaApplication::Ptr& icingaapplication : ConfigType::GetObjectsByType<IcingaApplication>()) {
73                 nodes.emplace_back(icingaapplication->GetName(), new Dictionary({
74                         { "node_name", icingaapplication->GetNodeName() },
75                         { "enable_notifications", icingaapplication->GetEnableNotifications() },
76                         { "enable_event_handlers", icingaapplication->GetEnableEventHandlers() },
77                         { "enable_flapping", icingaapplication->GetEnableFlapping() },
78                         { "enable_host_checks", icingaapplication->GetEnableHostChecks() },
79                         { "enable_service_checks", icingaapplication->GetEnableServiceChecks() },
80                         { "enable_perfdata", icingaapplication->GetEnablePerfdata() },
81                         { "environment", icingaapplication->GetEnvironment() },
82                         { "pid", Utility::GetPid() },
83                         { "program_start", Application::GetStartTime() },
84                         { "version", Application::GetAppVersion() }
85                 }));
86         }
87
88         status->Set("icingaapplication", new Dictionary(std::move(nodes)));
89 }
90
91 /**
92  * The entry point for the Icinga application.
93  *
94  * @returns An exit status.
95  */
96 int IcingaApplication::Main()
97 {
98         Log(LogDebug, "IcingaApplication", "In IcingaApplication::Main()");
99
100         /* periodically dump the program state */
101         l_RetentionTimer = new Timer();
102         l_RetentionTimer->SetInterval(300);
103         l_RetentionTimer->OnTimerExpired.connect(std::bind(&IcingaApplication::DumpProgramState, this));
104         l_RetentionTimer->Start();
105
106         RunEventLoop();
107
108         Log(LogInformation, "IcingaApplication", "Icinga has shut down.");
109
110         return EXIT_SUCCESS;
111 }
112
113 void IcingaApplication::OnShutdown()
114 {
115         {
116                 ObjectLock olock(this);
117                 l_RetentionTimer->Stop();
118         }
119
120         DumpProgramState();
121 }
122
123 static void PersistModAttrHelper(std::fstream& fp, ConfigObject::Ptr& previousObject, const ConfigObject::Ptr& object, const String& attr, const Value& value)
124 {
125         if (object != previousObject) {
126                 if (previousObject) {
127                         ConfigWriter::EmitRaw(fp, "\tobj.version = ");
128                         ConfigWriter::EmitValue(fp, 0, previousObject->GetVersion());
129                         ConfigWriter::EmitRaw(fp, "\n}\n\n");
130                 }
131
132                 ConfigWriter::EmitRaw(fp, "var obj = ");
133
134                 Array::Ptr args1 = new Array({
135                         object->GetReflectionType()->GetName(),
136                         object->GetName()
137                 });
138                 ConfigWriter::EmitFunctionCall(fp, "get_object", args1);
139
140                 ConfigWriter::EmitRaw(fp, "\nif (obj) {\n");
141         }
142
143         ConfigWriter::EmitRaw(fp, "\tobj.");
144
145         Array::Ptr args2 = new Array({
146                 attr,
147                 value
148         });
149         ConfigWriter::EmitFunctionCall(fp, "modify_attribute", args2);
150
151         ConfigWriter::EmitRaw(fp, "\n");
152
153         previousObject = object;
154 }
155
156 void IcingaApplication::DumpProgramState()
157 {
158         ConfigObject::DumpObjects(Configuration::StatePath);
159         DumpModifiedAttributes();
160 }
161
162 void IcingaApplication::DumpModifiedAttributes()
163 {
164         String path = Configuration::ModAttrPath;
165
166         std::fstream fp;
167         String tempFilename = Utility::CreateTempFile(path + ".XXXXXX", 0644, fp);
168         fp.exceptions(std::ofstream::failbit | std::ofstream::badbit);
169
170         ConfigObject::Ptr previousObject;
171         ConfigObject::DumpModifiedAttributes(std::bind(&PersistModAttrHelper, std::ref(fp), std::ref(previousObject), _1, _2, _3));
172
173         if (previousObject) {
174                 ConfigWriter::EmitRaw(fp, "\tobj.version = ");
175                 ConfigWriter::EmitValue(fp, 0, previousObject->GetVersion());
176                 ConfigWriter::EmitRaw(fp, "\n}\n");
177         }
178
179         fp.close();
180
181         Utility::RenameFile(tempFilename, path);
182 }
183
184 IcingaApplication::Ptr IcingaApplication::GetInstance()
185 {
186         return static_pointer_cast<IcingaApplication>(Application::GetInstance());
187 }
188
189 bool IcingaApplication::ResolveMacro(const String& macro, const CheckResult::Ptr&, Value *result) const
190 {
191         double now = Utility::GetTime();
192
193         if (macro == "timet") {
194                 *result = static_cast<long>(now);
195                 return true;
196         } else if (macro == "long_date_time") {
197                 *result = Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", now);
198                 return true;
199         } else if (macro == "short_date_time") {
200                 *result = Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", now);
201                 return true;
202         } else if (macro == "date") {
203                 *result = Utility::FormatDateTime("%Y-%m-%d", now);
204                 return true;
205         } else if (macro == "time") {
206                 *result = Utility::FormatDateTime("%H:%M:%S %z", now);
207                 return true;
208         } else if (macro == "uptime") {
209                 *result = Utility::FormatDuration(Utility::GetTime() - Application::GetStartTime());
210                 return true;
211         }
212
213         Dictionary::Ptr vars = GetVars();
214
215         if (vars && vars->Contains(macro)) {
216                 *result = vars->Get(macro);
217                 return true;
218         }
219
220         if (macro.Contains("num_services")) {
221                 ServiceStatistics ss = CIB::CalculateServiceStats();
222
223                 if (macro == "num_services_ok") {
224                         *result = ss.services_ok;
225                         return true;
226                 } else if (macro == "num_services_warning") {
227                         *result = ss.services_warning;
228                         return true;
229                 } else if (macro == "num_services_critical") {
230                         *result = ss.services_critical;
231                         return true;
232                 } else if (macro == "num_services_unknown") {
233                         *result = ss.services_unknown;
234                         return true;
235                 } else if (macro == "num_services_pending") {
236                         *result = ss.services_pending;
237                         return true;
238                 } else if (macro == "num_services_unreachable") {
239                         *result = ss.services_unreachable;
240                         return true;
241                 } else if (macro == "num_services_flapping") {
242                         *result = ss.services_flapping;
243                         return true;
244                 } else if (macro == "num_services_in_downtime") {
245                         *result = ss.services_in_downtime;
246                         return true;
247                 } else if (macro == "num_services_acknowledged") {
248                         *result = ss.services_acknowledged;
249                         return true;
250                 }
251         }
252         else if (macro.Contains("num_hosts")) {
253                 HostStatistics hs = CIB::CalculateHostStats();
254
255                 if (macro == "num_hosts_up") {
256                         *result = hs.hosts_up;
257                         return true;
258                 } else if (macro == "num_hosts_down") {
259                         *result = hs.hosts_down;
260                         return true;
261                 } else if (macro == "num_hosts_pending") {
262                         *result = hs.hosts_pending;
263                         return true;
264                 } else if (macro == "num_hosts_unreachable") {
265                         *result = hs.hosts_unreachable;
266                         return true;
267                 } else if (macro == "num_hosts_flapping") {
268                         *result = hs.hosts_flapping;
269                         return true;
270                 } else if (macro == "num_hosts_in_downtime") {
271                         *result = hs.hosts_in_downtime;
272                         return true;
273                 } else if (macro == "num_hosts_acknowledged") {
274                         *result = hs.hosts_acknowledged;
275                         return true;
276                 }
277         }
278
279         return false;
280 }
281
282 String IcingaApplication::GetNodeName() const
283 {
284         return ScriptGlobal::Get("NodeName");
285 }
286
287 /* Intentionally kept here, since an agent may not have the CheckerComponent loaded. */
288 int IcingaApplication::GetMaxConcurrentChecks() const
289 {
290         return ScriptGlobal::Get("MaxConcurrentChecks");
291 }
292
293 String IcingaApplication::GetEnvironment() const
294 {
295         return Application::GetAppEnvironment();
296 }
297
298 void IcingaApplication::SetEnvironment(const String& value, bool suppress_events, const Value& cookie)
299 {
300         Application::SetAppEnvironment(value);
301 }
302
303 void IcingaApplication::ValidateVars(const Lazy<Dictionary::Ptr>& lvalue, const ValidationUtils& utils)
304 {
305         MacroProcessor::ValidateCustomVars(this, lvalue());
306 }