Validate configured TimePeriod ranges

Requires re-throwing the hidden exceptions inside the existing
timeperiod code and validating the configured time range
strings then.

fixes #7576
This commit is contained in:
Michael Friedrich 2015-02-12 09:12:55 +01:00
parent 1f05cc23d1
commit 2ed78e82a8
4 changed files with 68 additions and 5 deletions

View File

@ -179,6 +179,8 @@
}
%type TimePeriod %inherits CustomVarObject {
%validator "ValidateTimePeriodRanges",
%attribute %string "display_name",
%require "update",

View File

@ -289,7 +289,11 @@ void LegacyTimePeriod::ParseTimeRange(const String& timerange, tm *begin, tm *en
String second = def.SubStr(pos + 1);
second.Trim();
try {
ParseTimeSpec(first, begin, NULL, reference);
} catch (std::exception&) {
throw;
}
/* If the second definition starts with a number we need
* to add the first word from the first definition, e.g.:
@ -310,9 +314,17 @@ void LegacyTimePeriod::ParseTimeRange(const String& timerange, tm *begin, tm *en
second = first.SubStr(0, xpos + 1) + second;
}
try {
ParseTimeSpec(second, NULL, end, reference);
} catch (std::exception&) {
throw;
}
} else {
try {
ParseTimeSpec(def, begin, end, reference);
} catch (std::exception&) {
throw;
}
}
}
@ -364,7 +376,13 @@ void LegacyTimePeriod::ProcessTimeRangeRaw(const String& timerange, tm *referenc
Dictionary::Ptr LegacyTimePeriod::ProcessTimeRange(const String& timestamp, tm *reference)
{
tm begin, end;
try {
ProcessTimeRangeRaw(timestamp, reference, &begin, &end);
} catch (std::exception&) {
throw;
}
Dictionary::Ptr segment = new Dictionary();
segment->Set("begin", (long)mktime(&begin));
segment->Set("end", (long)mktime(&end));
@ -378,7 +396,13 @@ void LegacyTimePeriod::ProcessTimeRanges(const String& timeranges, tm *reference
boost::algorithm::split(ranges, timeranges, boost::is_any_of(","));
BOOST_FOREACH(const String& range, ranges) {
Dictionary::Ptr segment = ProcessTimeRange(range, reference);
Dictionary::Ptr segment;
try {
segment = ProcessTimeRange(range, reference);
} catch (std::exception&) {
throw;
}
if (segment->Get("begin") >= segment->Get("end"))
BOOST_THROW_EXCEPTION(std::invalid_argument("Time period segment ends before it begins"));

View File

@ -18,8 +18,10 @@
******************************************************************************/
#include "icinga/timeperiod.hpp"
#include "icinga/legacytimeperiod.hpp"
#include "base/dynamictype.hpp"
#include "base/objectlock.hpp"
#include "base/exception.hpp"
#include "base/logger.hpp"
#include "base/timer.hpp"
#include "base/utility.hpp"
@ -28,6 +30,7 @@
using namespace icinga;
REGISTER_TYPE(TimePeriod);
REGISTER_SCRIPTFUNCTION(ValidateTimePeriodRanges, &TimePeriod::ValidateRanges);
static Timer::Ptr l_UpdateTimer;
@ -297,3 +300,35 @@ void TimePeriod::Dump(void)
Log(LogDebug, "TimePeriod", "---");
}
void TimePeriod::ValidateRanges(const String& location, const TimePeriod::Ptr& object)
{
Dictionary::Ptr ranges = object->GetRanges();
if (!ranges)
return;
/* create a fake time environment to validate the definitions */
time_t begin = Utility::GetTime();
time_t end = begin + 24 * 60 * 60;
tm reference = Utility::LocalTime(end);
tm begin_tm, end_tm;
Array::Ptr segments = new Array();
ObjectLock olock(ranges);
BOOST_FOREACH(const Dictionary::Pair& kv, ranges) {
try {
LegacyTimePeriod::ParseTimeSpec(kv.first, &begin_tm, &end_tm, &reference);
} catch (std::exception&) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Invalid time specification.", object->GetDebugInfo()));
}
try {
LegacyTimePeriod::ProcessTimeRanges(kv.second, &reference, segments);
} catch (std::exception&) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Invalid time range definition.", object->GetDebugInfo()));
}
}
}

View File

@ -46,6 +46,8 @@ public:
bool IsInside(double ts) const;
double FindNextTransition(double begin);
static void ValidateRanges(const String& location, const TimePeriod::Ptr& object);
private:
void AddSegment(double s, double end);
void AddSegment(const Dictionary::Ptr& segment);