]> granicus.if.org Git - icinga2/blob - lib/icinga/dependency.cpp
Service: be handled while host is down
[icinga2] / lib / icinga / dependency.cpp
1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2
3 #include "icinga/dependency.hpp"
4 #include "icinga/dependency-ti.cpp"
5 #include "icinga/service.hpp"
6 #include "base/logger.hpp"
7 #include "base/exception.hpp"
8
9 using namespace icinga;
10
11 REGISTER_TYPE(Dependency);
12
13 String DependencyNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const
14 {
15         Dependency::Ptr dependency = dynamic_pointer_cast<Dependency>(context);
16
17         if (!dependency)
18                 return "";
19
20         String name = dependency->GetChildHostName();
21
22         if (!dependency->GetChildServiceName().IsEmpty())
23                 name += "!" + dependency->GetChildServiceName();
24
25         name += "!" + shortName;
26
27         return name;
28 }
29
30 Dictionary::Ptr DependencyNameComposer::ParseName(const String& name) const
31 {
32         std::vector<String> tokens = name.Split("!");
33
34         if (tokens.size() < 2)
35                 BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid Dependency name."));
36
37         Dictionary::Ptr result = new Dictionary();
38         result->Set("child_host_name", tokens[0]);
39
40         if (tokens.size() > 2) {
41                 result->Set("child_service_name", tokens[1]);
42                 result->Set("name", tokens[2]);
43         } else {
44                 result->Set("name", tokens[1]);
45         }
46
47         return result;
48 }
49
50 void Dependency::OnConfigLoaded()
51 {
52         Value defaultFilter;
53
54         if (GetParentServiceName().IsEmpty())
55                 defaultFilter = StateFilterUp;
56         else
57                 defaultFilter = StateFilterOK | StateFilterWarning;
58
59         SetStateFilter(FilterArrayToInt(GetStates(), Notification::GetStateFilterMap(), defaultFilter));
60 }
61
62 void Dependency::OnAllConfigLoaded()
63 {
64         ObjectImpl<Dependency>::OnAllConfigLoaded();
65
66         Host::Ptr childHost = Host::GetByName(GetChildHostName());
67
68         if (childHost) {
69                 if (GetChildServiceName().IsEmpty())
70                         m_Child = childHost;
71                 else
72                         m_Child = childHost->GetServiceByShortName(GetChildServiceName());
73         }
74
75         if (!m_Child)
76                 BOOST_THROW_EXCEPTION(ScriptError("Dependency '" + GetName() + "' references a child host/service which doesn't exist.", GetDebugInfo()));
77
78         m_Child->AddDependency(this);
79
80         Host::Ptr parentHost = Host::GetByName(GetParentHostName());
81
82         if (parentHost) {
83                 if (GetParentServiceName().IsEmpty())
84                         m_Parent = parentHost;
85                 else
86                         m_Parent = parentHost->GetServiceByShortName(GetParentServiceName());
87         }
88
89         if (!m_Parent)
90                 BOOST_THROW_EXCEPTION(ScriptError("Dependency '" + GetName() + "' references a parent host/service which doesn't exist.", GetDebugInfo()));
91
92         m_Parent->AddReverseDependency(this);
93 }
94
95 void Dependency::Stop(bool runtimeRemoved)
96 {
97         ObjectImpl<Dependency>::Stop(runtimeRemoved);
98
99         GetChild()->RemoveDependency(this);
100         GetParent()->RemoveReverseDependency(this);
101 }
102
103 bool Dependency::IsAvailable(DependencyType dt) const
104 {
105         Checkable::Ptr parent = GetParent();
106
107         Host::Ptr parentHost;
108         Service::Ptr parentService;
109         tie(parentHost, parentService) = GetHostService(parent);
110
111         /* ignore if it's the same checkable object */
112         if (parent == GetChild()) {
113                 Log(LogNotice, "Dependency")
114                         << "Dependency '" << GetName() << "' passed: Parent and child " << (parentService ? "service" : "host") << " are identical.";
115                 return true;
116         }
117
118         /* ignore pending  */
119         if (!parent->GetLastCheckResult()) {
120                 Log(LogNotice, "Dependency")
121                         << "Dependency '" << GetName() << "' passed: Parent " << (parentService ? "service" : "host") << " '" << parent->GetName() << "' hasn't been checked yet.";
122                 return true;
123         }
124
125         if (GetIgnoreSoftStates()) {
126                 /* ignore soft states */
127                 if (parent->GetStateType() == StateTypeSoft) {
128                         Log(LogNotice, "Dependency")
129                                 << "Dependency '" << GetName() << "' passed: Parent " << (parentService ? "service" : "host") << " '" << parent->GetName() << "' is in a soft state.";
130                         return true;
131                 }
132         } else {
133                 Log(LogNotice, "Dependency")
134                         << "Dependency '" << GetName() << "' failed: Parent " << (parentService ? "service" : "host") << " '" << parent->GetName() << "' is in a soft state.";
135         }
136
137         int state;
138
139         if (parentService)
140                 state = ServiceStateToFilter(parentService->GetState());
141         else
142                 state = HostStateToFilter(parentHost->GetState());
143
144         /* check state */
145         if (state & GetStateFilter()) {
146                 Log(LogNotice, "Dependency")
147                         << "Dependency '" << GetName() << "' passed: Parent " << (parentService ? "service" : "host") << " '" << parent->GetName() << "' matches state filter.";
148                 return true;
149         }
150
151         /* ignore if not in time period */
152         TimePeriod::Ptr tp = GetPeriod();
153         if (tp && !tp->IsInside(Utility::GetTime())) {
154                 Log(LogNotice, "Dependency")
155                         << "Dependency '" << GetName() << "' passed: Outside time period.";
156                 return true;
157         }
158
159         if (dt == DependencyCheckExecution && !GetDisableChecks()) {
160                 Log(LogNotice, "Dependency")
161                         << "Dependency '" << GetName() << "' passed: Checks are not disabled.";
162                 return true;
163         } else if (dt == DependencyNotification && !GetDisableNotifications()) {
164                 Log(LogNotice, "Dependency")
165                         << "Dependency '" << GetName() << "' passed: Notifications are not disabled";
166                 return true;
167         }
168
169         Log(LogNotice, "Dependency")
170                 << "Dependency '" << GetName() << "' failed. Parent "
171                 << (parentService ? "service" : "host") << " '" << parent->GetName() << "' is "
172                 << (parentService ? Service::StateToString(parentService->GetState()) : Host::StateToString(parentHost->GetState()));
173
174         return false;
175 }
176
177 Checkable::Ptr Dependency::GetChild() const
178 {
179         return m_Child;
180 }
181
182 Checkable::Ptr Dependency::GetParent() const
183 {
184         return m_Parent;
185 }
186
187 TimePeriod::Ptr Dependency::GetPeriod() const
188 {
189         return TimePeriod::GetByName(GetPeriodRaw());
190 }
191
192 void Dependency::ValidateStates(const Lazy<Array::Ptr>& lvalue, const ValidationUtils& utils)
193 {
194         ObjectImpl<Dependency>::ValidateStates(lvalue, utils);
195
196         int sfilter = FilterArrayToInt(lvalue(), Notification::GetStateFilterMap(), 0);
197
198         if (GetParentServiceName().IsEmpty() && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0)
199                 BOOST_THROW_EXCEPTION(ValidationError(this, { "states" }, "State filter is invalid for host dependency."));
200
201         if (!GetParentServiceName().IsEmpty() && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0)
202                 BOOST_THROW_EXCEPTION(ValidationError(this, { "states" }, "State filter is invalid for service dependency."));
203 }
204