m_IdleServices.erase(service);
- /* reschedule the service if checks are currently disabled
- * for it and this is not a forced check */
- if (!service->GetEnableActiveChecks() && !service->GetForceNextCheck()) {
- Logger::Write(LogDebug, "checker", "Ignoring service check for disabled service: " + service->GetName());
+ bool check = true;
+ if (!service->GetForceNextCheck()) {
+ if (!service->GetEnableActiveChecks()) {
+ Logger::Write(LogDebug, "checker", "Skipping check for service '" + service->GetName() + "': active checks are disabled");
+ check = false;
+ }
+
+ TimePeriod::Ptr tp = service->GetCheckPeriod();
+
+ if (tp && !tp->IsInside(Utility::GetTime())) {
+ Logger::Write(LogDebug, "checker", "Skipping check for service '" + service->GetName() + "': not in check_period");
+ check = false;
+ }
+ }
+
+ /* reschedule the service if checks are disabled */
+ if (!check) {
service->UpdateNextCheck();
typedef nth_index<ServiceSet, 1>::type CheckTimeView;
}
#define REGISTER_TYPE_ALIAS(type, alias) \
- static icinga::RegisterTypeHelper g_RegisterDT_ ## type(alias, DynamicObjectFactory<type>)
+ static icinga::RegisterTypeHelper g_RegisterDT_ ## type(alias, DynamicObjectFactory<type>);
#define REGISTER_TYPE(type) \
REGISTER_TYPE_ALIAS(type, #type)
};
#define REGISTER_SCRIPTFUNCTION(name, callback) \
- static icinga::RegisterFunctionHelper g_RegisterSF_ ## type(name, callback)
+ static icinga::RegisterFunctionHelper g_RegisterSF_ ## name(#name, callback)
+
+#undef MKSYMBOL
}
# define ASSERT(expr)
#endif /* _DEBUG */
+#define CONCAT(a, b) a ## b
+
#endif /* UTILITY_H */
service.h \
servicegroup.cpp \
servicegroup.h \
+ timeperiod.cpp \
+ timeperiod.h \
user.cpp \
user.h \
usergroup.cpp \
using namespace icinga;
-REGISTER_SCRIPTFUNCTION("GetAnswerToEverything", &API::GetAnswerToEverything);
+REGISTER_SCRIPTFUNCTION(GetAnswerToEverything, &API::GetAnswerToEverything);
/**
* @threadsafety Always.
bool Host::m_ServicesCacheNeedsUpdate = false;
Timer::Ptr Host::m_ServicesCacheTimer;
-REGISTER_SCRIPTFUNCTION("ValidateServiceDictionary", &Host::ValidateServiceDictionary);
+REGISTER_SCRIPTFUNCTION(ValidateServiceDictionary, &Host::ValidateServiceDictionary);
REGISTER_TYPE(Host);
if (!notification_interval.IsEmpty())
builder->AddExpression("notification_interval", OperatorSet, notification_interval);
+ Value check_period = serviceDesc->Get("check_period");
+ if (!check_period.IsEmpty())
+ builder->AddExpression("check_period", OperatorSet, check_period);
+
if (copyServiceAttrs) {
Value servicedependencies = serviceDesc->Get("servicedependencies");
if (!servicedependencies.IsEmpty())
#include "externalcommandprocessor.h"
-#include "endpoint.h"
-#include "endpointmanager.h"
#include "icingaapplication.h"
+#include "timeperiod.h"
+
#include "user.h"
#include "usergroup.h"
%attribute string "*"
},
+ %attribute string "check_period",
%attribute number "check_interval",
%attribute number "retry_interval",
/* service attributes */
%attribute number "max_check_attempts",
+ %attribute string "check_period",
%attribute number "check_interval",
%attribute number "retry_interval",
%attribute number "notification_interval",
},
%attribute string "check_command",
%attribute number "max_check_attempts",
+ %attribute string "check_period",
%attribute number "check_interval",
%attribute number "retry_interval",
%attribute dictionary "hostdependencies" {
%attribute string "action_url",
%attribute string "notes_url"
}
+
+type TimePeriod {
+ %require "methods",
+ %attribute dictionary "methods" {
+ %require "update",
+ %attribute string "update"
+ },
+}
<ClCompile Include="service-comment.cpp" />
<ClCompile Include="service-downtime.cpp" />
<ClCompile Include="servicegroup.cpp" />
+ <ClCompile Include="timeperiod.cpp" />
<ClCompile Include="user.cpp" />
<ClCompile Include="usergroup.cpp" />
</ItemGroup>
<ClInclude Include="pluginnotificationtask.h" />
<ClInclude Include="service.h" />
<ClInclude Include="servicegroup.h" />
+ <ClInclude Include="timeperiod.h" />
<ClInclude Include="user.h" />
<ClInclude Include="usergroup.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project>
\ No newline at end of file
+</Project>
arguments.push_back(macros);
arguments.push_back(type);
- ScriptTask::Ptr task;
- task = MakeMethodTask("notify", arguments);
+ ScriptTask::Ptr task = MakeMethodTask("notify", arguments);
if (!task) {
Logger::Write(LogWarning, "icinga", "Notification object '" + GetName() + "' doesn't have a 'notify' method.");
using namespace icinga;
-REGISTER_SCRIPTFUNCTION("NullCheck", &NullCheckTask::ScriptFunc);
+REGISTER_SCRIPTFUNCTION(NullCheck, &NullCheckTask::ScriptFunc);
/**
* @threadsafety Always.
using namespace icinga;
-REGISTER_SCRIPTFUNCTION("PluginCheck", &PluginCheckTask::ScriptFunc);
+REGISTER_SCRIPTFUNCTION(PluginCheck, &PluginCheckTask::ScriptFunc);
PluginCheckTask::PluginCheckTask(const ScriptTask::Ptr& task, const Process::Ptr& process, const Value& command)
: m_Task(task), m_Process(process), m_Command(command)
using namespace icinga;
-REGISTER_SCRIPTFUNCTION("PluginNotification", &PluginNotificationTask::ScriptFunc);
+REGISTER_SCRIPTFUNCTION(PluginNotification, &PluginNotificationTask::ScriptFunc);
PluginNotificationTask::PluginNotificationTask(const ScriptTask::Ptr& task, const Process::Ptr& process,
const String& service, const String& command)
return m_MaxCheckAttempts;
}
+/**
+ * @threadsafety Always.
+ */
+TimePeriod::Ptr Service::GetCheckPeriod(void) const
+{
+ return TimePeriod::GetByName(m_CheckPeriod);
+}
+
/**
* @threadsafety Always.
*/
RegisterAttribute("check_command", Attribute_Config, &m_CheckCommand);
RegisterAttribute("max_check_attempts", Attribute_Config, &m_MaxCheckAttempts);
+ RegisterAttribute("check_period", Attribute_Config, &m_CheckPeriod);
RegisterAttribute("check_interval", Attribute_Config, &m_CheckInterval);
RegisterAttribute("retry_interval", Attribute_Config, &m_RetryInterval);
RegisterAttribute("checkers", Attribute_Config, &m_Checkers);
Dictionary::Ptr GetCheckers(void) const;
Value GetCheckCommand(void) const;
long GetMaxCheckAttempts(void) const;
+ TimePeriod::Ptr GetCheckPeriod(void) const;
double GetCheckInterval(void) const;
double GetRetryInterval(void) const;
/* Checks */
Attribute<Value> m_CheckCommand;
Attribute<long> m_MaxCheckAttempts;
+ Attribute<String> m_CheckPeriod;
Attribute<double> m_CheckInterval;
Attribute<double> m_RetryInterval;
Attribute<double> m_NextCheck;
--- /dev/null
+/******************************************************************************
+ * Icinga 2 *
+ * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License *
+ * as published by the Free Software Foundation; either version 2 *
+ * of the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the Free Software Foundation *
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ******************************************************************************/
+
+#include "i2-icinga.h"
+
+using namespace icinga;
+
+REGISTER_TYPE(TimePeriod);
+REGISTER_SCRIPTFUNCTION(EmptyTimePeriod, &TimePeriod::EmptyTimePeriodUpdate);
+REGISTER_SCRIPTFUNCTION(EvenMinutesTimePeriod, &TimePeriod::EvenMinutesTimePeriodUpdate);
+
+Timer::Ptr TimePeriod::m_UpdateTimer;
+
+TimePeriod::TimePeriod(const Dictionary::Ptr& serializedUpdate)
+ : DynamicObject(serializedUpdate)
+{
+ RegisterAttribute("valid_begin", Attribute_Replicated, &m_ValidBegin);
+ RegisterAttribute("valid_end", Attribute_Replicated, &m_ValidEnd);
+ RegisterAttribute("segments", Attribute_Replicated, &m_Segments);
+
+ if (!m_UpdateTimer) {
+ m_UpdateTimer = boost::make_shared<Timer>();
+ m_UpdateTimer->SetInterval(300);
+ m_UpdateTimer->OnTimerExpired.connect(boost::bind(&TimePeriod::UpdateTimerHandler));
+ m_UpdateTimer->Start();
+ }
+}
+
+void TimePeriod::Start(void)
+{
+ /* Pre-fill the time period for the next 24 hours. */
+ double now = Utility::GetTime();
+ UpdateRegion(now, now + 24 * 3600);
+}
+
+/**
+ * @threadsafety Always.
+ */
+TimePeriod::Ptr TimePeriod::GetByName(const String& name)
+{
+ DynamicObject::Ptr configObject = DynamicObject::GetObject("TimePeriod", name);
+
+ return dynamic_pointer_cast<TimePeriod>(configObject);
+}
+
+void TimePeriod::AddSegment(double begin, double end)
+{
+ ASSERT(OwnsLock());
+
+ if (m_ValidBegin.IsEmpty() || begin < m_ValidBegin)
+ m_ValidBegin = begin;
+
+ if (m_ValidEnd.IsEmpty() || end > m_ValidEnd)
+ m_ValidEnd = end;
+
+ Array::Ptr segments = m_Segments;
+
+ if (segments) {
+ /* Try to merge the new segment into an existing segment. */
+ ObjectLock dlock(segments);
+ BOOST_FOREACH(const Dictionary::Ptr& segment, segments) {
+ if (segment->Get("begin") <= begin && segment->Get("end") >= end)
+ return; /* New segment is fully contained in this segment. */
+
+ if (segment->Get("begin") < begin && segment->Get("end") > begin) {
+ segment->Set("end", end); /* Extend an existing segment. */
+ return;
+ }
+
+ if (segment->Get("begin") > begin && segment->Get("begin") < end) {
+ segment->Set("begin", begin); /* Extend an existing segment. */
+ return;
+ }
+ }
+ }
+
+ /* Create new segment if we weren't able to merge this into an existing segment. */
+ Dictionary::Ptr segment = boost::make_shared<Dictionary>();
+ segment->Set("begin", begin);
+ segment->Set("end", end);
+
+ if (!segments) {
+ segments = boost::make_shared<Array>();
+ m_Segments = segments;
+ }
+
+ segments->Add(segment);
+ Touch("segments");
+}
+
+void TimePeriod::RemoveSegment(double begin, double end)
+{
+ ASSERT(OwnsLock());
+
+ if (m_ValidBegin.IsEmpty() || begin < m_ValidBegin)
+ m_ValidBegin = begin;
+
+ if (m_ValidEnd.IsEmpty() || end > m_ValidEnd)
+ m_ValidEnd = end;
+
+ Array::Ptr segments = m_Segments;
+
+ if (!segments)
+ return;
+
+ /* Try to split or adjust an existing segment. */
+ ObjectLock dlock(segments);
+ BOOST_FOREACH(const Dictionary::Ptr& segment, segments) {
+ BOOST_THROW_EXCEPTION(runtime_error("Not implemented."));
+ }
+
+ Touch("segments");
+}
+
+void TimePeriod::PurgeSegments(double end)
+{
+ ASSERT(OwnsLock());
+
+ if (m_ValidBegin.IsEmpty() || end < m_ValidBegin)
+ return;
+
+ m_ValidBegin = end;
+
+ Array::Ptr segments = m_Segments;
+
+ if (!segments)
+ return;
+
+ Array::Ptr newSegments = boost::make_shared<Array>();
+
+ /* Remove old segments. */
+ ObjectLock dlock(segments);
+ BOOST_FOREACH(const Dictionary::Ptr& segment, segments) {
+ if (segment->Get("end") >= end)
+ newSegments->Add(segment);
+ }
+
+ m_Segments = newSegments;
+ Touch("segments");
+}
+
+void TimePeriod::UpdateRegion(double begin, double end)
+{
+ if (begin < m_ValidEnd)
+ begin = m_ValidEnd;
+
+ if (end < m_ValidEnd)
+ return;
+
+ TimePeriod::Ptr self = GetSelf();
+
+ vector<Value> arguments;
+ arguments.push_back(self);
+ arguments.push_back(begin);
+ arguments.push_back(end);
+ ScriptTask::Ptr task = MakeMethodTask("update", arguments);
+
+ if (!task) {
+ Logger::Write(LogWarning, "icinga", "TimePeriod object '" + GetName() + "' doesn't have an 'update' method.");
+
+ return;
+ }
+
+ task->Start();
+ task->GetResult();
+}
+
+bool TimePeriod::IsInside(double ts) const
+{
+ ObjectLock olock(this);
+
+ if (m_ValidBegin.IsEmpty() || ts < m_ValidBegin || m_ValidEnd.IsEmpty() || ts > m_ValidEnd)
+ return true; /* Assume that all invalid regions are "inside". */
+
+ Array::Ptr segments = m_Segments;
+
+ if (segments) {
+ ObjectLock dlock(segments);
+ BOOST_FOREACH(const Dictionary::Ptr& segment, segments) {
+ if (ts > segment->Get("begin") && ts < segment->Get("end"))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+double TimePeriod::FindNextTransition(double begin)
+{
+ ObjectLock olock(this);
+
+ Array::Ptr segments = m_Segments;
+
+ double closestTransition = -1;
+
+ if (segments) {
+ ObjectLock dlock(segments);
+ BOOST_FOREACH(const Dictionary::Ptr& segment, segments) {
+ if (segment->Get("begin") > begin && (segment->Get("begin") < closestTransition || closestTransition == -1))
+ closestTransition = segment->Get("begin");
+
+ if (segment->Get("end") > begin && (segment->Get("end") < closestTransition || closestTransition == -1))
+ closestTransition = segment->Get("end");
+ }
+ }
+
+ return closestTransition;
+}
+
+void TimePeriod::UpdateTimerHandler(void)
+{
+ double now = Utility::GetTime();
+
+ BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("TimePeriod")) {
+ TimePeriod::Ptr tp = static_pointer_cast<TimePeriod>(object);
+
+ /* Only update time periods that have been defined on this node. */
+ if (!ConfigItem::GetObject("TimePeriod", tp->GetName()))
+ continue;
+
+ tp->PurgeSegments(now - 3600);
+
+ if (tp->m_ValidEnd < now + 3 * 3600)
+ tp->UpdateRegion(tp->m_ValidEnd, tp->m_ValidEnd + 24 * 3600);
+ }
+}
+
+void TimePeriod::EmptyTimePeriodUpdate(const ScriptTask::Ptr& task, const vector<Value>& arguments)
+{
+ if (arguments.size() < 3)
+ BOOST_THROW_EXCEPTION(runtime_error("Expected 3 arguments."));
+
+ TimePeriod::Ptr tp = arguments[0];
+ double begin = arguments[1];
+ double end = arguments[2];
+
+ ObjectLock olock(tp);
+ tp->RemoveSegment(begin, end);
+
+ task->FinishResult(Empty);
+}
+
+void TimePeriod::EvenMinutesTimePeriodUpdate(const ScriptTask::Ptr& task, const vector<Value>& arguments)
+{
+ if (arguments.size() < 3)
+ BOOST_THROW_EXCEPTION(runtime_error("Expected 3 arguments."));
+
+ TimePeriod::Ptr tp = arguments[0];
+ double begin = arguments[1];
+ double end = arguments[2];
+
+ {
+ ObjectLock olock(tp);
+
+ tp->RemoveSegment(begin, end);
+
+ for (long t = begin; t < end; t += 60) {
+ if ((t / 60) % 2 == 0)
+ tp->AddSegment(t, t + 60);
+ }
+ }
+
+ task->FinishResult(Empty);
+}
--- /dev/null
+/******************************************************************************
+ * Icinga 2 *
+ * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License *
+ * as published by the Free Software Foundation; either version 2 *
+ * of the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the Free Software Foundation *
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ******************************************************************************/
+
+#ifndef TIMEPERIOD_H
+#define TIMEPERIOD_H
+
+namespace icinga
+{
+
+/**
+ * A time period.
+ *
+ * @ingroup icinga
+ */
+class I2_ICINGA_API TimePeriod : public DynamicObject
+{
+public:
+ typedef shared_ptr<TimePeriod> Ptr;
+ typedef weak_ptr<TimePeriod> WeakPtr;
+
+ TimePeriod(const Dictionary::Ptr& serializedUpdate);
+
+ static TimePeriod::Ptr GetByName(const String& name);
+
+ virtual void Start(void);
+
+ void AddSegment(double s, double end);
+ void RemoveSegment(double begin, double end);
+ void PurgeSegments(double end);
+
+ void UpdateRegion(double begin, double end);
+
+ bool IsInside(double ts) const;
+ double FindNextTransition(double begin);
+
+ static void EmptyTimePeriodUpdate(const ScriptTask::Ptr& task, const vector<Value>& arguments);
+ static void EvenMinutesTimePeriodUpdate(const ScriptTask::Ptr& task, const vector<Value>& arguments);
+
+private:
+ Attribute<double> m_ValidBegin;
+ Attribute<double> m_ValidEnd;
+ Attribute<Array::Ptr> m_Segments;
+
+ static Timer::Ptr m_UpdateTimer;
+ static void UpdateTimerHandler(void);
+};
+
+}
+
+#endif /* TIMEPERIOD_H */