446
447
"fingerprint", "host", "interval",
447
448
"last_approval_request", "last_checked_ok",
448
449
"last_enabled", "name", "timeout")
449
client_defaults = { "timeout": "5m",
450
"extended_timeout": "15m",
450
client_defaults = { "timeout": "PT5M",
451
"extended_timeout": "PT15M",
452
453
"checker": "fping -q -- %%(host)s",
454
"approval_delay": "0s",
455
"approval_duration": "1s",
455
"approval_delay": "PT0S",
456
"approval_duration": "PT1S",
456
457
"approved_by_default": "True",
457
458
"enabled": "True",
2094
def rfc3339_duration_to_delta(duration):
2095
"""Parse an RFC 3339 "duration" and return a datetime.timedelta
2097
>>> rfc3339_duration_to_delta("P7D")
2098
datetime.timedelta(7)
2099
>>> rfc3339_duration_to_delta("PT60S")
2100
datetime.timedelta(0, 60)
2101
>>> rfc3339_duration_to_delta("PT60M")
2102
datetime.timedelta(0, 3600)
2103
>>> rfc3339_duration_to_delta("PT24H")
2104
datetime.timedelta(1)
2105
>>> rfc3339_duration_to_delta("P1W")
2106
datetime.timedelta(7)
2107
>>> rfc3339_duration_to_delta("PT5M30S")
2108
datetime.timedelta(0, 330)
2109
>>> rfc3339_duration_to_delta("P1DT3M20S")
2110
datetime.timedelta(1, 200)
2113
# Parsing an RFC 3339 duration with regular expressions is not
2114
# possible - there would have to be multiple places for the same
2115
# values, like seconds. The current code, while more esoteric, is
2116
# cleaner without depending on a parsing library. If Python had a
2117
# built-in library for parsing we would use it, but we'd like to
2118
# avoid excessive use of external libraries.
2120
# New type for defining tokens, syntax, and semantics all-in-one
2121
Token = collections.namedtuple("Token",
2122
("regexp", # To match token; if
2123
# "value" is not None,
2124
# must have a "group"
2126
"value", # datetime.timedelta or
2128
"followers")) # Tokens valid after
2130
# RFC 3339 "duration" tokens, syntax, and semantics; taken from
2131
# the "duration" ABNF definition in RFC 3339, Appendix A.
2132
token_end = Token(re.compile(r"$"), None, frozenset())
2133
token_second = Token(re.compile(r"(\d+)S"),
2134
datetime.timedelta(seconds=1),
2135
frozenset((token_end,)))
2136
token_minute = Token(re.compile(r"(\d+)M"),
2137
datetime.timedelta(minutes=1),
2138
frozenset((token_second, token_end)))
2139
token_hour = Token(re.compile(r"(\d+)H"),
2140
datetime.timedelta(hours=1),
2141
frozenset((token_minute, token_end)))
2142
token_time = Token(re.compile(r"T"),
2144
frozenset((token_hour, token_minute,
2146
token_day = Token(re.compile(r"(\d+)D"),
2147
datetime.timedelta(days=1),
2148
frozenset((token_time, token_end)))
2149
token_month = Token(re.compile(r"(\d+)M"),
2150
datetime.timedelta(weeks=4),
2151
frozenset((token_day, token_end)))
2152
token_year = Token(re.compile(r"(\d+)Y"),
2153
datetime.timedelta(weeks=52),
2154
frozenset((token_month, token_end)))
2155
token_week = Token(re.compile(r"(\d+)W"),
2156
datetime.timedelta(weeks=1),
2157
frozenset((token_end,)))
2158
token_duration = Token(re.compile(r"P"), None,
2159
frozenset((token_year, token_month,
2160
token_day, token_time,
2162
# Define starting values
2163
value = datetime.timedelta() # Value so far
2165
followers = frozenset(token_duration,) # Following valid tokens
2166
s = duration # String left to parse
2167
# Loop until end token is found
2168
while found_token is not token_end:
2169
# Search for any currently valid tokens
2170
for token in followers:
2171
match = token.regexp.match(s)
2172
if match is not None:
2174
if token.value is not None:
2175
# Value found, parse digits
2176
factor = int(match.group(1), 10)
2177
# Add to value so far
2178
value += factor * token.value
2179
# Strip token from string
2180
s = token.regexp.sub("", s, 1)
2183
# Set valid next tokens
2184
followers = found_token.followers
2187
# No currently valid tokens were found
2188
raise ValueError("Invalid RFC 3339 duration")
2093
2193
def string_to_delta(interval):
2094
2194
"""Parse a string and return a datetime.timedelta