]> granicus.if.org Git - icinga2/blob - lib/icinga/icingaapplication.cpp
36543e725c6fdc22825ac512388ed87a96f32c8a
[icinga2] / lib / icinga / icingaapplication.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org)    *
4  *                                                                            *
5  * This program is free software; you can redistribute it and/or              *
6  * modify it under the terms of the GNU General Public License                *
7  * as published by the Free Software Foundation; either version 2             *
8  * of the License, or (at your option) any later version.                     *
9  *                                                                            *
10  * This program is distributed in the hope that it will be useful,            *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
13  * GNU General Public License for more details.                               *
14  *                                                                            *
15  * You should have received a copy of the GNU General Public License          *
16  * along with this program; if not, write to the Free Software Foundation     *
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
18  ******************************************************************************/
19
20 #include "icinga/icingaapplication.hpp"
21 #include "icinga/icingaapplication.tcpp"
22 #include "icinga/cib.hpp"
23 #include "icinga/macroprocessor.hpp"
24 #include "config/configcompiler.hpp"
25 #include "base/configwriter.hpp"
26 #include "base/configtype.hpp"
27 #include "base/logger.hpp"
28 #include "base/objectlock.hpp"
29 #include "base/convert.hpp"
30 #include "base/debug.hpp"
31 #include "base/utility.hpp"
32 #include "base/timer.hpp"
33 #include "base/scriptglobal.hpp"
34 #include "base/initialize.hpp"
35 #include "base/statsfunction.hpp"
36
37 using namespace icinga;
38
39 static Timer::Ptr l_RetentionTimer;
40
41 REGISTER_TYPE(IcingaApplication);
42 INITIALIZE_ONCE(&IcingaApplication::StaticInitialize);
43
44 void IcingaApplication::StaticInitialize(void)
45 {
46         String node_name = Utility::GetFQDN();
47
48         if (node_name.IsEmpty()) {
49                 Log(LogNotice, "IcingaApplication", "No FQDN available. Trying Hostname.");
50                 node_name = Utility::GetHostName();
51
52                 if (node_name.IsEmpty()) {
53                         Log(LogWarning, "IcingaApplication", "No FQDN nor Hostname available. Setting Nodename to 'localhost'.");
54                         node_name = "localhost";
55                 }
56         }
57
58         ScriptGlobal::Set("NodeName", node_name);
59
60         ScriptGlobal::Set("ApplicationType", "IcingaApplication");
61 }
62
63 REGISTER_STATSFUNCTION(IcingaApplication, &IcingaApplication::StatsFunc);
64
65 void IcingaApplication::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata)
66 {
67         Dictionary::Ptr nodes = new Dictionary();
68
69         BOOST_FOREACH(const IcingaApplication::Ptr& icingaapplication, ConfigType::GetObjectsByType<IcingaApplication>()) {
70                 Dictionary::Ptr stats = new Dictionary();
71                 stats->Set("node_name", icingaapplication->GetNodeName());
72                 stats->Set("enable_notifications", icingaapplication->GetEnableNotifications());
73                 stats->Set("enable_event_handlers", icingaapplication->GetEnableEventHandlers());
74                 stats->Set("enable_flapping", icingaapplication->GetEnableFlapping());
75                 stats->Set("enable_host_checks", icingaapplication->GetEnableHostChecks());
76                 stats->Set("enable_service_checks", icingaapplication->GetEnableServiceChecks());
77                 stats->Set("enable_perfdata", icingaapplication->GetEnablePerfdata());
78                 stats->Set("pid", Utility::GetPid());
79                 stats->Set("program_start", Application::GetStartTime());
80                 stats->Set("version", Application::GetAppVersion());
81
82                 nodes->Set(icingaapplication->GetName(), stats);
83         }
84
85         status->Set("icingaapplication", nodes);
86 }
87
88 /**
89  * The entry point for the Icinga application.
90  *
91  * @returns An exit status.
92  */
93 int IcingaApplication::Main(void)
94 {
95         Log(LogDebug, "IcingaApplication", "In IcingaApplication::Main()");
96
97         /* periodically dump the program state */
98         l_RetentionTimer = new Timer();
99         l_RetentionTimer->SetInterval(300);
100         l_RetentionTimer->OnTimerExpired.connect(boost::bind(&IcingaApplication::DumpProgramState, this));
101         l_RetentionTimer->Start();
102
103         /* restore modified attributes */
104         if (Utility::PathExists(GetModAttrPath())) {
105                 Expression *expression = ConfigCompiler::CompileFile(GetModAttrPath());
106
107                 if (expression) {
108                         try {
109                                 ScriptFrame frame;
110                                 expression->Evaluate(frame);
111                         } catch (const std::exception& ex) {
112                                 Log(LogCritical, "config", DiagnosticInformation(ex));
113                         }
114                 }
115
116                 delete expression;
117         }
118
119         RunEventLoop();
120
121         Log(LogInformation, "IcingaApplication", "Icinga has shut down.");
122
123         return EXIT_SUCCESS;
124 }
125
126 void IcingaApplication::OnShutdown(void)
127 {
128         {
129                 ObjectLock olock(this);
130                 l_RetentionTimer->Stop();
131         }
132
133         DumpProgramState();
134 }
135
136 static void PersistModAttrHelper(std::ofstream& fp, ConfigObject::Ptr& previousObject, const ConfigObject::Ptr& object, const String& attr, const Value& value)
137 {
138         if (object != previousObject) {
139                 if (previousObject) {
140                         ConfigWriter::EmitRaw(fp, "\tobj.version = ");
141                         ConfigWriter::EmitValue(fp, 0, previousObject->GetVersion());
142                         ConfigWriter::EmitRaw(fp, "\n}\n\n");
143                 }
144
145                 ConfigWriter::EmitRaw(fp, "var obj = ");
146
147                 Array::Ptr args1 = new Array();
148                 args1->Add(object->GetReflectionType()->GetName());
149                 args1->Add(object->GetName());
150                 ConfigWriter::EmitFunctionCall(fp, "get_object", args1);
151
152                 ConfigWriter::EmitRaw(fp, "\nif (obj) {\n");
153         }
154
155         ConfigWriter::EmitRaw(fp, "\tobj.");
156
157         Array::Ptr args2 = new Array();
158         args2->Add(attr);
159         args2->Add(value);
160         ConfigWriter::EmitFunctionCall(fp, "modify_attribute", args2);
161
162         ConfigWriter::EmitRaw(fp, "\n");
163
164         previousObject = object;
165 }
166
167 void IcingaApplication::DumpProgramState(void)
168 {
169         ConfigObject::DumpObjects(GetStatePath());
170         DumpModifiedAttributes();
171 }
172
173 void IcingaApplication::DumpModifiedAttributes(void)
174 {
175         String path = GetModAttrPath();
176         String pathtmp = path + ".tmp";
177
178         std::ofstream fp;
179         fp.open(pathtmp.CStr(), std::ofstream::out | std::ofstream::trunc);
180
181         ConfigObject::Ptr previousObject;
182         ConfigObject::DumpModifiedAttributes(boost::bind(&PersistModAttrHelper, boost::ref(fp), boost::ref(previousObject), _1, _2, _3));
183
184         if (previousObject) {
185                 ConfigWriter::EmitRaw(fp, "\tobj.version = ");
186                 ConfigWriter::EmitValue(fp, 0, previousObject->GetVersion());
187                 ConfigWriter::EmitRaw(fp, "\n}\n");
188         }
189
190         fp.close();
191
192 #ifdef _WIN32
193         _unlink(path.CStr());
194 #endif /* _WIN32 */
195
196         if (rename(pathtmp.CStr(), path.CStr()) < 0) {
197                 BOOST_THROW_EXCEPTION(posix_error()
198                     << boost::errinfo_api_function("rename")
199                     << boost::errinfo_errno(errno)
200                     << boost::errinfo_file_name(pathtmp));
201         }
202 }
203
204 IcingaApplication::Ptr IcingaApplication::GetInstance(void)
205 {
206         return static_pointer_cast<IcingaApplication>(Application::GetInstance());
207 }
208
209 bool IcingaApplication::ResolveMacro(const String& macro, const CheckResult::Ptr&, Value *result) const
210 {
211         double now = Utility::GetTime();
212
213         if (macro == "timet") {
214                 *result = Convert::ToString((long)now);
215                 return true;
216         } else if (macro == "long_date_time") {
217                 *result = Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", now);
218                 return true;
219         } else if (macro == "short_date_time") {
220                 *result = Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", now);
221                 return true;
222         } else if (macro == "date") {
223                 *result = Utility::FormatDateTime("%Y-%m-%d", now);
224                 return true;
225         } else if (macro == "time") {
226                 *result = Utility::FormatDateTime("%H:%M:%S %z", now);
227                 return true;
228         } else if (macro == "uptime") {
229                 *result = Utility::FormatDuration(Utility::GetTime() - Application::GetStartTime());
230                 return true;
231         }
232
233         Dictionary::Ptr vars = GetVars();
234
235         if (vars && vars->Contains(macro)) {
236                 *result = vars->Get(macro);
237                 return true;
238         }
239
240         if (macro.Contains("num_services")) {
241                 ServiceStatistics ss = CIB::CalculateServiceStats();
242
243                 if (macro == "num_services_ok") {
244                         *result = Convert::ToString(ss.services_ok);
245                         return true;
246                 } else if (macro == "num_services_warning") {
247                         *result = Convert::ToString(ss.services_warning);
248                         return true;
249                 } else if (macro == "num_services_critical") {
250                         *result = Convert::ToString(ss.services_critical);
251                         return true;
252                 } else if (macro == "num_services_unknown") {
253                         *result = Convert::ToString(ss.services_unknown);
254                         return true;
255                 } else if (macro == "num_services_pending") {
256                         *result = Convert::ToString(ss.services_pending);
257                         return true;
258                 } else if (macro == "num_services_unreachable") {
259                         *result = Convert::ToString(ss.services_unreachable);
260                         return true;
261                 } else if (macro == "num_services_flapping") {
262                         *result = Convert::ToString(ss.services_flapping);
263                         return true;
264                 } else if (macro == "num_services_in_downtime") {
265                         *result = Convert::ToString(ss.services_in_downtime);
266                         return true;
267                 } else if (macro == "num_services_acknowledged") {
268                         *result = Convert::ToString(ss.services_acknowledged);
269                         return true;
270                 }
271         }
272         else if (macro.Contains("num_hosts")) {
273                 HostStatistics hs = CIB::CalculateHostStats();
274
275                 if (macro == "num_hosts_up") {
276                         *result = Convert::ToString(hs.hosts_up);
277                         return true;
278                 } else if (macro == "num_hosts_down") {
279                         *result = Convert::ToString(hs.hosts_down);
280                         return true;
281                 } else if (macro == "num_hosts_unreachable") {
282                         *result = Convert::ToString(hs.hosts_unreachable);
283                         return true;
284                 } else if (macro == "num_hosts_flapping") {
285                         *result = Convert::ToString(hs.hosts_flapping);
286                         return true;
287                 } else if (macro == "num_hosts_in_downtime") {
288                         *result = Convert::ToString(hs.hosts_in_downtime);
289                         return true;
290                 } else if (macro == "num_hosts_acknowledged") {
291                         *result = Convert::ToString(hs.hosts_acknowledged);
292                         return true;
293                 }
294         }
295
296         return false;
297 }
298
299 String IcingaApplication::GetNodeName(void) const
300 {
301         return ScriptGlobal::Get("NodeName");
302 }
303
304 void IcingaApplication::ValidateVars(const Dictionary::Ptr& value, const ValidationUtils& utils)
305 {
306         MacroProcessor::ValidateCustomVars(this, value);
307 }