]> granicus.if.org Git - icinga2/blob - lib/icinga/scheduleddowntime.cpp
Remove unused includes
[icinga2] / lib / icinga / scheduleddowntime.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/)  *
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/scheduleddowntime.hpp"
21 #include "icinga/scheduleddowntime-ti.cpp"
22 #include "icinga/legacytimeperiod.hpp"
23 #include "icinga/downtime.hpp"
24 #include "icinga/service.hpp"
25 #include "base/timer.hpp"
26 #include "base/configtype.hpp"
27 #include "base/utility.hpp"
28 #include "base/objectlock.hpp"
29 #include "base/convert.hpp"
30 #include "base/logger.hpp"
31 #include "base/exception.hpp"
32 #include <boost/thread/once.hpp>
33
34 using namespace icinga;
35
36 REGISTER_TYPE(ScheduledDowntime);
37
38 static Timer::Ptr l_Timer;
39
40 String ScheduledDowntimeNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const
41 {
42         ScheduledDowntime::Ptr downtime = dynamic_pointer_cast<ScheduledDowntime>(context);
43
44         if (!downtime)
45                 return "";
46
47         String name = downtime->GetHostName();
48
49         if (!downtime->GetServiceName().IsEmpty())
50                 name += "!" + downtime->GetServiceName();
51
52         name += "!" + shortName;
53
54         return name;
55 }
56
57 Dictionary::Ptr ScheduledDowntimeNameComposer::ParseName(const String& name) const
58 {
59         std::vector<String> tokens = name.Split("!");
60
61         if (tokens.size() < 2)
62                 BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid ScheduledDowntime name."));
63
64         Dictionary::Ptr result = new Dictionary();
65         result->Set("host_name", tokens[0]);
66
67         if (tokens.size() > 2) {
68                 result->Set("service_name", tokens[1]);
69                 result->Set("name", tokens[2]);
70         } else {
71                 result->Set("name", tokens[1]);
72         }
73
74         return result;
75 }
76
77 void ScheduledDowntime::OnAllConfigLoaded()
78 {
79         ObjectImpl<ScheduledDowntime>::OnAllConfigLoaded();
80
81         if (!GetCheckable())
82                 BOOST_THROW_EXCEPTION(ScriptError("ScheduledDowntime '" + GetName() + "' references a host/service which doesn't exist.", GetDebugInfo()));
83 }
84
85 void ScheduledDowntime::Start(bool runtimeCreated)
86 {
87         ObjectImpl<ScheduledDowntime>::Start(runtimeCreated);
88
89         static boost::once_flag once = BOOST_ONCE_INIT;
90
91         boost::call_once(once, [this]() {
92                 l_Timer = new Timer();
93                 l_Timer->SetInterval(60);
94                 l_Timer->OnTimerExpired.connect(std::bind(&ScheduledDowntime::TimerProc));
95                 l_Timer->Start();
96         });
97
98         Utility::QueueAsyncCallback(std::bind(&ScheduledDowntime::CreateNextDowntime, this));
99 }
100
101 void ScheduledDowntime::TimerProc()
102 {
103         for (const ScheduledDowntime::Ptr& sd : ConfigType::GetObjectsByType<ScheduledDowntime>()) {
104                 if (sd->IsActive())
105                         sd->CreateNextDowntime();
106         }
107 }
108
109 Checkable::Ptr ScheduledDowntime::GetCheckable() const
110 {
111         Host::Ptr host = Host::GetByName(GetHostName());
112
113         if (GetServiceName().IsEmpty())
114                 return host;
115         else
116                 return host->GetServiceByShortName(GetServiceName());
117 }
118
119 std::pair<double, double> ScheduledDowntime::FindNextSegment()
120 {
121         time_t refts = Utility::GetTime();
122         tm reference = Utility::LocalTime(refts);
123
124         Log(LogDebug, "ScheduledDowntime")
125                 << "Finding next scheduled downtime segment for time " << refts;
126
127         Dictionary::Ptr ranges = GetRanges();
128
129         if (!ranges)
130                 return std::make_pair(0, 0);
131
132         Array::Ptr segments = new Array();
133
134         Dictionary::Ptr bestSegment;
135         double bestBegin;
136         double now = Utility::GetTime();
137
138         ObjectLock olock(ranges);
139         for (const Dictionary::Pair& kv : ranges) {
140                 Log(LogDebug, "ScheduledDowntime")
141                         << "Evaluating segment: " << kv.first << ": " << kv.second << " at ";
142
143                 Dictionary::Ptr segment = LegacyTimePeriod::FindNextSegment(kv.first, kv.second, &reference);
144
145                 if (!segment)
146                         continue;
147
148                 Log(LogDebug, "ScheduledDowntime")
149                         << "Considering segment: " << Utility::FormatDateTime("%c", segment->Get("begin")) << " -> " << Utility::FormatDateTime("%c", segment->Get("end"));
150
151                 double begin = segment->Get("begin");
152
153                 if (begin < now)
154                         continue;
155
156                 if (!bestSegment || begin < bestBegin) {
157                         bestSegment = segment;
158                         bestBegin = begin;
159                 }
160         }
161
162         if (bestSegment)
163                 return std::make_pair(bestSegment->Get("begin"), bestSegment->Get("end"));
164         else
165                 return std::make_pair(0, 0);
166 }
167
168 void ScheduledDowntime::CreateNextDowntime()
169 {
170         for (const Downtime::Ptr& downtime : GetCheckable()->GetDowntimes()) {
171                 if (downtime->GetScheduledBy() != GetName() ||
172                         downtime->GetStartTime() < Utility::GetTime())
173                         continue;
174
175                 /* We've found a downtime that is owned by us and that hasn't started yet - we're done. */
176                 return;
177         }
178
179         std::pair<double, double> segment = FindNextSegment();
180
181         if (segment.first == 0 && segment.second == 0) {
182                 tm reference = Utility::LocalTime(Utility::GetTime());
183                 reference.tm_mday++;
184                 reference.tm_hour = 0;
185                 reference.tm_min = 0;
186                 reference.tm_sec = 0;
187
188                 return;
189         }
190
191         Downtime::AddDowntime(GetCheckable(), GetAuthor(), GetComment(),
192                 segment.first, segment.second,
193                 GetFixed(), String(), GetDuration(), GetName(), GetName());
194 }
195
196 void ScheduledDowntime::ValidateRanges(const Lazy<Dictionary::Ptr>& lvalue, const ValidationUtils& utils)
197 {
198         ObjectImpl<ScheduledDowntime>::ValidateRanges(lvalue, utils);
199
200         if (!lvalue())
201                 return;
202
203         /* create a fake time environment to validate the definitions */
204         time_t refts = Utility::GetTime();
205         tm reference = Utility::LocalTime(refts);
206         Array::Ptr segments = new Array();
207
208         ObjectLock olock(lvalue());
209         for (const Dictionary::Pair& kv : lvalue()) {
210                 try {
211                         tm begin_tm, end_tm;
212                         int stride;
213                         LegacyTimePeriod::ParseTimeRange(kv.first, &begin_tm, &end_tm, &stride, &reference);
214                 } catch (const std::exception& ex) {
215                         BOOST_THROW_EXCEPTION(ValidationError(this, { "ranges" }, "Invalid time specification '" + kv.first + "': " + ex.what()));
216                 }
217
218                 try {
219                         LegacyTimePeriod::ProcessTimeRanges(kv.second, &reference, segments);
220                 } catch (const std::exception& ex) {
221                         BOOST_THROW_EXCEPTION(ValidationError(this, { "ranges" }, "Invalid time range definition '" + kv.second + "': " + ex.what()));
222                 }
223         }
224 }
225