[icinga-checkins] icinga.org: icinga2/master: Implement complex 1.x timeperiod definitions.

git at icinga.org git at icinga.org
Wed Apr 17 14:26:15 CEST 2013


Module: icinga2
Branch: master
Commit: 8a1d24042dc037aa96a44f212fddc92130ec9474
URL:    https://git.icinga.org/?p=icinga2.git;a=commit;h=8a1d24042dc037aa96a44f212fddc92130ec9474

Author: Gunnar Beutner <gunnar.beutner at netways.de>
Date:   Wed Apr 17 14:26:04 2013 +0200

Implement complex 1.x timeperiod definitions.

---

 lib/base/qstring.cpp            |    5 +
 lib/base/qstring.h              |    1 +
 lib/icinga/legacytimeperiod.cpp |  282 ++++++++++++++++++++++++++++++++++++---
 lib/icinga/legacytimeperiod.h   |    6 +
 4 files changed, 273 insertions(+), 21 deletions(-)

diff --git a/lib/base/qstring.cpp b/lib/base/qstring.cpp
index 1ae6cff..c1ea8f3 100644
--- a/lib/base/qstring.cpp
+++ b/lib/base/qstring.cpp
@@ -122,6 +122,11 @@ size_t String::GetLength(void) const
 	return m_Data.size();
 }
 
+size_t String::Find(const String& str, size_t pos) const
+{
+	return m_Data.find(str, pos);
+}
+
 size_t String::FindFirstOf(const char *s, size_t pos) const
 {
 	return m_Data.find_first_of(s, pos);
diff --git a/lib/base/qstring.h b/lib/base/qstring.h
index 5c7628e..e085045 100644
--- a/lib/base/qstring.h
+++ b/lib/base/qstring.h
@@ -75,6 +75,7 @@ public:
 	void Clear(void);
 	size_t GetLength(void) const;
 
+	size_t Find(const String& str, size_t pos = 0) const;
 	size_t FindFirstOf(const char *s, size_t pos = 0) const;
 	size_t FindFirstOf(char ch, size_t pos = 0) const;
 	String SubStr(size_t first, size_t len = NPos) const;
diff --git a/lib/icinga/legacytimeperiod.cpp b/lib/icinga/legacytimeperiod.cpp
index 8d9dae9..262c473 100644
--- a/lib/icinga/legacytimeperiod.cpp
+++ b/lib/icinga/legacytimeperiod.cpp
@@ -33,32 +33,272 @@ using namespace icinga;
 
 REGISTER_SCRIPTFUNCTION(LegacyTimePeriod, &LegacyTimePeriod::ScriptFunc);
 
+bool LegacyTimePeriod::IsInTimeRange(tm *begin, tm *end, int stride, tm *reference)
+{
+	time_t tsbegin, tsend, tsref;
+	tsbegin = mktime(begin);
+	tsend = mktime(end);
+	tsref = mktime(reference);
+
+	if (tsref < tsbegin || tsref > tsend)
+		return false;
+
+	int daynumber = (tsref - tsbegin) / (24 * 60 * 60);
+
+	if (daynumber % stride == 0)
+		return false;
+
+	return true;
+}
+
+void LegacyTimePeriod::FindNthWeekday(int wday, int n, tm *reference)
+{
+	int seen = 0;
+
+	ASSERT(n > 0);
+
+	reference->tm_mday = 1;
+
+	for (;;) {
+		mktime(reference);
+
+		if (reference->tm_wday == wday) {
+			seen++;
+
+			if (seen == n)
+				return;
+		}
+
+		reference->tm_mday++;
+	}
+}
+
+int LegacyTimePeriod::WeekdayFromString(const String& daydef)
+{
+	if (daydef == "sunday")
+		return 0;
+	else if (daydef == "monday")
+		return 1;
+	else if (daydef == "tuesday")
+		return 2;
+	else if (daydef == "wednesday")
+		return 3;
+	else if (daydef == "thursday")
+		return 4;
+	else if (daydef == "friday")
+		return 5;
+	else if (daydef == "saturday")
+		return 6;
+	else
+		return -1;
+}
+
+int LegacyTimePeriod::MonthFromString(const String& monthdef)
+{
+	if (monthdef == "january")
+		return 0;
+	else if (monthdef == "february")
+		return 1;
+	else if (monthdef == "march")
+		return 2;
+	else if (monthdef == "april")
+		return 3;
+	else if (monthdef == "may")
+		return 4;
+	else if (monthdef == "june")
+		return 5;
+	else if (monthdef == "july")
+		return 6;
+	else if (monthdef == "august")
+		return 7;
+	else if (monthdef == "september")
+		return 8;
+	else if (monthdef == "october")
+		return 9;
+	else if (monthdef == "november")
+		return 10;
+	else if (monthdef == "december")
+		return 11;
+	else
+		return -1;
+}
+
+void LegacyTimePeriod::ParseTimeSpec(const String& timespec, tm *begin, tm *end, tm *reference)
+{
+	/* YYYY-MM-DD */
+	if (timespec.GetLength() == 10 && timespec[4] == '-' && timespec[7] == '-') {
+		int year = Convert::ToLong(timespec.SubStr(0, 4));
+		int month = Convert::ToLong(timespec.SubStr(5, 2));
+		int day = Convert::ToLong(timespec.SubStr(7, 2));
+
+		if (begin) {
+			begin->tm_year = year - 1900;
+			begin->tm_mon = month;
+			begin->tm_mday = day;
+			begin->tm_hour = 0;
+			begin->tm_min = 0;
+			begin->tm_sec = 0;
+		}
+
+		if (end) {
+			end->tm_year = year - 1900;
+			end->tm_mon = month;
+			end->tm_mday = day;
+			end->tm_hour = 24;
+			end->tm_min = 0;
+			end->tm_sec = 0;
+		}
+
+		return;
+	}
+
+	std::vector<String> tokens;
+	boost::algorithm::split(tokens, timespec, boost::is_any_of(" "));
+
+	if (tokens.size() > 1 && tokens[0] == "day") {
+		int mday = Convert::ToLong(tokens[1]);
+
+		if (begin) {
+			*begin = *reference;
+			begin->tm_mday = mday;
+			begin->tm_hour = 0;
+			begin->tm_min = 0;
+			begin->tm_sec = 0;
+
+			/* Negative days are relative to the next month. */
+			if (mday < 0) {
+				end->tm_mday--;
+				begin->tm_mon++;
+			}
+		}
+
+		if (end) {
+			*end = *reference;
+			end->tm_mday = mday;
+			end->tm_hour = 24;
+			end->tm_min = 0;
+			end->tm_sec = 0;
+
+			/* Negative days are relative to the next month. */
+			if (mday < 0) {
+				end->tm_mday--;
+				end->tm_mon++;
+			}
+		}
+
+		return;
+	}
+
+	int wday;
+
+	if (tokens.size() > 1 && (wday = WeekdayFromString(tokens[0])) != -1) {
+		tm myref = *reference;
+
+		if (tokens.size() > 2) {
+			int mon = MonthFromString(tokens[2]);
+
+			if (mon == -1)
+				BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid month in time specification: " + timespec));
+
+			myref.tm_mon = mon;
+		}
+
+		int n = Convert::ToLong(tokens[1]);
+
+		if (begin) {
+			*begin = myref;
+			FindNthWeekday(wday, n, begin);
+			begin->tm_hour = 0;
+			begin->tm_min = 0;
+			begin->tm_sec = 0;
+		}
+
+		if (end) {
+			*end = myref;
+			FindNthWeekday(wday, n, end);
+			end->tm_hour = 0;
+			end->tm_min = 0;
+			end->tm_sec = 0;
+			end->tm_mday++;
+		}
+
+		return;
+	}
+
+	BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid time specification: " + timespec));
+}
+
+void LegacyTimePeriod::ParseTimeRange(const String& timerange, tm *begin, tm *end, int *stride, tm *reference)
+{
+	String def = timerange;
+
+	/* Figure out the stride. */
+	size_t pos = def.FindFirstOf('/');
+
+	if (pos != String::NPos) {
+		String strStride = def.SubStr(pos + 1);
+		strStride.Trim();
+		*stride = Convert::ToLong(strStride);
+
+		/* Remove the stride parameter from the definition. */
+		def = def.SubStr(0, pos);
+	} else {
+		*stride = 1; /* User didn't specify anything, assume default. */
+	}
+
+	/* Figure out whether the user has specified two dates. */
+	pos = def.Find("- ");
+
+	std::cout << "XXX: " << def << std::endl;
+
+	if (pos != String::NPos) {
+		String first = def.SubStr(0, pos);
+		first.Trim();
+
+		String second = def.SubStr(pos + 1);
+		second.Trim();
+
+		ParseTimeSpec(first, begin, NULL, reference);
+
+		/* If the second definition starts with a number we need
+		 * to add the first word from the first definition, e.g.:
+		 * day 1 - 15 --> "day 15" */
+		bool is_number = true;
+		size_t xpos = second.FindFirstOf(' ');
+		String fword = second.SubStr(0, xpos);
+
+		try {
+			Convert::ToLong(fword);
+		} catch (...) {
+			is_number = false;
+		}
+
+		if (is_number) {
+			xpos = first.FindFirstOf(' ');
+			ASSERT(xpos != String::NPos);
+			second = first.SubStr(0, xpos + 1) + second;
+		}
+
+		ParseTimeSpec(second, NULL, end, reference);
+	} else {
+		ParseTimeSpec(def, begin, end, reference);
+	}
+}
+
 bool LegacyTimePeriod::IsInDayDefinition(const String& daydef, tm *reference)
 {
-	if (daydef == "sunday" || daydef == "monday" || daydef == "tuesday" ||
-	    daydef == "wednesday" || daydef == "thursday" || daydef == "friday" ||
-	    daydef == "saturday") {
-		int wday;
-
-		if (daydef == "sunday")
-			wday = 0;
-		else if (daydef == "monday")
-			wday = 1;
-		else if (daydef == "tuesday")
-			wday = 2;
-		else if (daydef == "wednesday")
-			wday = 3;
-		else if (daydef == "thursday")
-			wday = 4;
-		else if (daydef == "friday")
-			wday = 5;
-		else if (daydef == "saturday")
-			wday = 6;
+	/* Week specifications are special in that they don't have a reference frame. */
+	int wday = WeekdayFromString(daydef);
 
+	if (wday != -1)
 		return reference->tm_wday == wday;
-	}
 
-	BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid day definition: " + daydef));
+	tm begin, end;
+	int stride;
+
+	ParseTimeRange(daydef, &begin, &end, &stride, reference);
+
+	return IsInTimeRange(&begin, &end, stride, reference);
 }
 
 Dictionary::Ptr LegacyTimePeriod::ProcessTimeRange(const String& timerange, tm *reference)
diff --git a/lib/icinga/legacytimeperiod.h b/lib/icinga/legacytimeperiod.h
index 818f450..131961f 100644
--- a/lib/icinga/legacytimeperiod.h
+++ b/lib/icinga/legacytimeperiod.h
@@ -37,6 +37,12 @@ class I2_ICINGA_API LegacyTimePeriod
 public:
 	static Array::Ptr ScriptFunc(const TimePeriod::Ptr& tp, double start, double end);
 
+	static bool IsInTimeRange(tm *begin, tm *end, int stride, tm *reference);
+	static void FindNthWeekday(int wday, int n, tm *reference);
+	static int WeekdayFromString(const String& daydef);
+	static int MonthFromString(const String& monthdef);
+	static void ParseTimeSpec(const String& timespec, tm *begin, tm *end, tm *reference);
+	static void ParseTimeRange(const String& timerange, tm *begin, tm *end, int *stride, tm *reference);
 	static bool IsInDayDefinition(const String& daydef, tm *reference);
 	static Dictionary::Ptr ProcessTimeRange(const String& timerange, tm *reference);
 	static void ProcessTimeRanges(const String& timeranges, tm *reference, const Array::Ptr& result);





More information about the icinga-checkins mailing list