1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
#!/usr/bin/python
import logging
import urllib2
import time
import rfc822
import re
class GardCheck:
# Base class which provides some helper functions
def __init__(self, url, log=True):
self.url = url
if log:
self.logger = logging.getLogger('')
else:
self.logger = None
def log_info(self, msg):
if self.logger is not None:
self.logger.info(msg)
def log_error(self, msg):
if self.logger is not None:
self.logger.error(msg)
def check_file_exists(self, url):
ret = True
try:
f = urllib2.urlopen(url)
if len(f.read()) == 0:
raise IOError
except:
ret = False
return ret
# Takes the URL to a timestamp.{chk|x} file and returns the
# corresponding time stamp in seconds
def _get_timestamp_from_url(self, url):
try:
# TODO: Add a timeout
f = urllib2.urlopen(url)
date = f.read()
f.close()
if date is None or len(date) == 0:
raise ValueError
try:
# timestamp.chk format
ts = self.timestamp_to_secs(date)
except:
# timestamp.x format?
ts = float(date.split(' ')[0])
except:
return None
return ts
def get_lag(self, path):
ts = self._get_timestamp_from_url(self.url + path)
now = time.mktime(time.gmtime())
if ts is None or now < ts:
return None
return now - ts
def humanize_time(self, secs):
mins, secs = divmod(secs, 60)
hours, mins = divmod(mins, 60)
days, hours = divmod(hours, 24)
return '%02dd %02dh %02dm %02ds' % (days, hours, mins, secs)
def timestamp_to_secs(self, ts):
return rfc822.mktime_tz(rfc822.parsedate_tz(ts))
# OPTIONAL: Override or supplement these in child classes if desired.
def check_name(self):
return re.sub('.*\.|(Check$)', '', str(self.__class__))
def check(self, maxlag):
lag = self.lag()
if lag is None:
self.log_error('Could not get %s timestamp for %s' % (self.check_name(), self.url))
ret = False
elif lag > maxlag:
self.log_error('%s at %s is lagging (delta is %s)' \
% (self.check_name(), self.url, self.humanize_time(lag)))
ret = False
else:
ret = True
return ret
# REQUIRED: You must override these in child classes
def lag(self):
return None
# Check distfiles mirrors
class DistfilesCheck(GardCheck):
def lag(self):
path = '/distfiles/timestamp.chk'
return self.get_lag(path)
# Check experimental mirrors
class ExperimentalCheck(GardCheck):
def lag(self):
path = '/experimental/.timestamp-experimental.x'
return self.get_lag(path)
# Check snapshot mirrors
class SnapshotsCheck(GardCheck):
def lag(self):
path = '/snapshots/.timestamp-snapshots.x'
return self.get_lag(path)
# Check releases mirrors
class ReleasesCheck(GardCheck):
def lag(self):
path = '/releases/.test/timestamp.x'
return self.get_lag(path)
def check(self, maxlag):
# Call the superclass first if exists
try: fun = getattr(GardCheck, 'check')
except AttributeError: pass
else: ret = fun(self, maxlag)
# Verify that releases/.test/THIS-FILE-SHOULD-NOT-BE-PUBLIC.txt
# is not world readable
if self.check_file_exists(self.url+'releases/.test/THIS-FILE-SHOULD-NOT-BE-PUBLIC.txt'):
self.log_error('ERROR: releases permission check failed on %s' % self.url)
ret = False
return ret
|