]> granicus.if.org Git - icinga2/commitdiff
Implement timeperiods.
authorGunnar Beutner <gunnar.beutner@netways.de>
Wed, 13 Mar 2013 15:04:53 +0000 (16:04 +0100)
committerGunnar Beutner <gunnar.beutner@netways.de>
Wed, 13 Mar 2013 15:04:53 +0000 (16:04 +0100)
19 files changed:
components/checker/checkercomponent.cpp
lib/base/dynamictype.h
lib/base/scriptfunction.h
lib/base/utility.h
lib/icinga/Makefile.am
lib/icinga/api.cpp
lib/icinga/host.cpp
lib/icinga/i2-icinga.h
lib/icinga/icinga-type.conf
lib/icinga/icinga.vcxproj
lib/icinga/notification.cpp
lib/icinga/nullchecktask.cpp
lib/icinga/pluginchecktask.cpp
lib/icinga/pluginnotificationtask.cpp
lib/icinga/service-check.cpp
lib/icinga/service.cpp
lib/icinga/service.h
lib/icinga/timeperiod.cpp [new file with mode: 0644]
lib/icinga/timeperiod.h [new file with mode: 0644]

index f35fcca44d031a620cd610ac2e7ede1212e24225..c65ca89254b13db0ae77b0d4bcd542a153e00a8a 100644 (file)
@@ -98,11 +98,24 @@ void CheckerComponent::CheckThreadProc(void)
 
                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;
index 4d10d0fbd5044c636cad3a6cd6800039bd5ffd85..abae276604bf960e38fa5739f12153a0258878b7 100644 (file)
@@ -95,7 +95,7 @@ shared_ptr<T> DynamicObjectFactory(const Dictionary::Ptr& serializedUpdate)
 }
 
 #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)
index 50bffc6e7c0d5a96d03a7674e806e680e83af6bd..049bee52baeb7d4725bea86854b422a77135c2a9 100644 (file)
@@ -78,7 +78,9 @@ public:
 };
 
 #define REGISTER_SCRIPTFUNCTION(name, callback) \
-       static icinga::RegisterFunctionHelper g_RegisterSF_ ## type(name, callback)
+       static icinga::RegisterFunctionHelper g_RegisterSF_ ## name(#name, callback)
+
+#undef MKSYMBOL
 
 }
 
index 37827f0653437d5745b64819d2f6324959e23089..b8bafbb0654b77e61eede6961bc9e2474738aaf7 100644 (file)
@@ -90,4 +90,6 @@ private:
 #      define ASSERT(expr)
 #endif /* _DEBUG */
 
+#define CONCAT(a, b) a ## b
+
 #endif /* UTILITY_H */
index 242f64db9018e3dd2e400fd3d0a80e76c1ce9a53..6698cfb21a7921e42e1782995b3a51a51f520bf8 100644 (file)
@@ -50,6 +50,8 @@ libicinga_la_SOURCES =  \
        service.h \
        servicegroup.cpp \
        servicegroup.h \
+       timeperiod.cpp \
+       timeperiod.h \
        user.cpp \
        user.h \
        usergroup.cpp \
index 4317969064f8830cd654c8763902ea8a565730bc..837efc4f375d76d5cb7ddf473ce245f430b3d0cd 100644 (file)
@@ -21,7 +21,7 @@
 
 using namespace icinga;
 
-REGISTER_SCRIPTFUNCTION("GetAnswerToEverything", &API::GetAnswerToEverything);
+REGISTER_SCRIPTFUNCTION(GetAnswerToEverything, &API::GetAnswerToEverything);
 
 /**
  * @threadsafety Always.
index 408d69f61c4f5b0f86698c23c942ad6990d67b39..c02136a62232b3784396a8402256b3959e948730 100644 (file)
@@ -26,7 +26,7 @@ map<String, map<String, Service::WeakPtr> > Host::m_ServicesCache;
 bool Host::m_ServicesCacheNeedsUpdate = false;
 Timer::Ptr Host::m_ServicesCacheTimer;
 
-REGISTER_SCRIPTFUNCTION("ValidateServiceDictionary", &Host::ValidateServiceDictionary);
+REGISTER_SCRIPTFUNCTION(ValidateServiceDictionary, &Host::ValidateServiceDictionary);
 
 REGISTER_TYPE(Host);
 
@@ -191,6 +191,10 @@ static void CopyServiceAttributes(TDict serviceDesc, const ConfigItemBuilder::Pt
        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())
index 393198820c08af6b154e8777396f1aa643a419ea..608ee821179751f00a2fd1a6bad1862218245d94 100644 (file)
@@ -42,10 +42,10 @@ using boost::algorithm::is_any_of;
 
 #include "externalcommandprocessor.h"
 
-#include "endpoint.h"
-#include "endpointmanager.h"
 #include "icingaapplication.h"
 
+#include "timeperiod.h"
+
 #include "user.h"
 #include "usergroup.h"
 
index 2418e6fd48977f713b6a2760cdbd00d3bf8c61d3..7aaeac355bbf122dc5a49c5c4944bc9bfc05ceef 100644 (file)
@@ -51,6 +51,7 @@ type Host {
                                %attribute string "*"
                        },
 
+                       %attribute string "check_period",
                        %attribute number "check_interval",
                        %attribute number "retry_interval",
 
@@ -99,6 +100,7 @@ type Host {
 
        /* service attributes */
        %attribute number "max_check_attempts",
+       %attribute string "check_period",
        %attribute number "check_interval",
        %attribute number "retry_interval",
        %attribute number "notification_interval",
@@ -144,6 +146,7 @@ type Service {
        },
        %attribute string "check_command",
        %attribute number "max_check_attempts",
+       %attribute string "check_period",
        %attribute number "check_interval",
        %attribute number "retry_interval",
        %attribute dictionary "hostdependencies" {
@@ -248,3 +251,11 @@ type UserGroup {
        %attribute string "action_url",
        %attribute string "notes_url"
 }
+
+type TimePeriod {
+       %require "methods",
+       %attribute dictionary "methods" {
+               %require "update",
+               %attribute string "update"
+       },
+}
index d91d2bfc50cfa0eef15ee3acf4d9d6f3b87f1b24..52b5341e6328ad7f23c254189c4e1aa739550376 100644 (file)
@@ -50,6 +50,7 @@
     <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>
@@ -70,6 +71,7 @@
     <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>
index 11d92ef3c5c4f7411fc72346691dad04159de9e3..075f5aefffa3abacdaed91d381d23f8b1ab5ac4c 100644 (file)
@@ -213,8 +213,7 @@ void Notification::BeginExecuteNotificationHelper(const Dictionary::Ptr& notific
        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.");
index fef26eeaea624c1ddf21c458ff3c676ed2edcf5b..f413ba896b1ff97b845816258f62f20f2f97cf90 100644 (file)
@@ -21,7 +21,7 @@
 
 using namespace icinga;
 
-REGISTER_SCRIPTFUNCTION("NullCheck",  &NullCheckTask::ScriptFunc);
+REGISTER_SCRIPTFUNCTION(NullCheck,  &NullCheckTask::ScriptFunc);
 
 /**
  * @threadsafety Always.
index 814a1ce82c3a3ed9e7c502462843df2de8eb2da8..88e0855f209dfe1e1caac35a32ea36f68b92868e 100644 (file)
@@ -21,7 +21,7 @@
 
 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)
index 305b974263bcf6b36b5fc17b4e1b0d9febcde752..74d1f7e6ced0672217b6a2867e7b096eb390d711 100644 (file)
@@ -21,7 +21,7 @@
 
 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)
index d20bf44a827923f4fc08df74a00c0c75dd4f85c4..f4315a14061785b94fe0e3682dd8041210e9615f 100644 (file)
@@ -47,6 +47,14 @@ long Service::GetMaxCheckAttempts(void) const
        return m_MaxCheckAttempts;
 }
 
+/**
+ * @threadsafety Always.
+ */
+TimePeriod::Ptr Service::GetCheckPeriod(void) const
+{
+       return TimePeriod::GetByName(m_CheckPeriod);
+}
+
 /**
  * @threadsafety Always.
  */
index 3be6ac0ca4d8e48ec8f425ff832dab79999f9c10..37a14d79d2984322dc2ac43a1eb4a8eccb49db12 100644 (file)
@@ -35,6 +35,7 @@ Service::Service(const Dictionary::Ptr& serializedObject)
 
        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);
index 9400e0f46c8635cf13d51b0a502a78abc49dbd8f..1666d9dfd8e8c55e4028ccc3f802bca5e848f2ec 100644 (file)
@@ -110,6 +110,7 @@ public:
        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;
 
@@ -264,6 +265,7 @@ private:
        /* 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;
diff --git a/lib/icinga/timeperiod.cpp b/lib/icinga/timeperiod.cpp
new file mode 100644 (file)
index 0000000..467869a
--- /dev/null
@@ -0,0 +1,280 @@
+/******************************************************************************
+ * 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);
+}
diff --git a/lib/icinga/timeperiod.h b/lib/icinga/timeperiod.h
new file mode 100644 (file)
index 0000000..50b1d1f
--- /dev/null
@@ -0,0 +1,66 @@
+/******************************************************************************
+ * 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 */