1 |
apollock |
1 |
#!/usr/bin/python |
2 |
|
|
|
3 |
|
|
import urllib2 |
4 |
|
|
import sys |
5 |
|
|
import time |
6 |
|
|
import stat |
7 |
|
|
import os |
8 |
|
|
from optparse import OptionParser |
9 |
|
|
|
10 |
|
|
### |
11 |
|
|
# Script to check if a local mirror is in sync with an HTTP-accessible remote |
12 |
|
|
# mirror (based on the /debian/project/trace file) |
13 |
|
|
# |
14 |
|
|
# Copyright (c) 2006 Andrew Pollock <me@andrew.net.au> |
15 |
|
|
# |
16 |
|
|
# Permission to use granted under the GNU General Public License v2 |
17 |
|
|
|
18 |
|
|
class DefaultErrorHandler(urllib2.HTTPDefaultErrorHandler): |
19 |
|
|
"""The class you need to have to get useful IMS functionality""" |
20 |
|
|
|
21 |
|
|
def http_error_default(self, req, fp, code, msg, headers): |
22 |
|
|
"""Returns the result code of the transaction""" |
23 |
|
|
|
24 |
|
|
result = urllib2.HTTPError( |
25 |
|
|
req.get_full_url(), code, msg, headers, fp) |
26 |
|
|
result.status = code |
27 |
|
|
return result |
28 |
|
|
|
29 |
|
|
|
30 |
|
|
def getLastModifiedTime(url): |
31 |
|
|
"""Makes a request for url and returns the Last-Modified header""" |
32 |
|
|
|
33 |
|
|
request = urllib2.Request(url) |
34 |
|
|
opener = urllib2.build_opener() |
35 |
|
|
data = opener.open(request) |
36 |
|
|
return(data.headers.dict["last-modified"]) |
37 |
|
|
|
38 |
|
|
|
39 |
|
|
def URLisNewerThan(url, epoch): |
40 |
|
|
"""Makes an IMS request for url with epoch as the modification time and returns if URL has changed""" |
41 |
|
|
|
42 |
|
|
request = urllib2.Request(url) |
43 |
|
|
request.add_header('If-Modified-Since', time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(epoch))) |
44 |
|
|
opener = urllib2.build_opener(DefaultErrorHandler()) |
45 |
|
|
data = opener.open(request) |
46 |
|
|
if (hasattr(data, 'status') and data.status == 304): |
47 |
|
|
return False |
48 |
|
|
else: |
49 |
|
|
return True |
50 |
|
|
|
51 |
|
|
|
52 |
|
|
def main(): |
53 |
|
|
parser = OptionParser() |
54 |
|
|
|
55 |
|
|
parser.set_description("Program to check if a local Debian mirror is out of sync with a remote Debian mirror") |
56 |
|
|
parser.add_option("-w", "--wait-time", dest="wait", default=300, type="int", |
57 |
|
|
help="Seconds to wait between checks for") |
58 |
|
|
parser.add_option("-m", "--max-retry", dest="maxretries", default=0, type="int", |
59 |
|
|
help="Maximum number of interations before giving up") |
60 |
|
|
parser.add_option("-v", "--verbose", action="store_true", |
61 |
|
|
dest="verbose", default=False, |
62 |
|
|
help="Print additional information about behaviour") |
63 |
|
|
|
64 |
|
|
(options, args) = parser.parse_args() |
65 |
|
|
|
66 |
|
|
if len(args) != 2: |
67 |
|
|
parser.print_usage() |
68 |
|
|
else: |
69 |
|
|
|
70 |
|
|
UPSTREAM=args[0] |
71 |
|
|
MIRROR_ROOT=args[1] |
72 |
|
|
upstream_trace = "".join(['http://', UPSTREAM, '/debian/project/trace/', UPSTREAM]) |
73 |
|
|
local_trace = os.path.join(MIRROR_ROOT, "debian", "project", "trace", UPSTREAM) |
74 |
|
|
|
75 |
|
|
#upstream_timestamp = calendar.timegm(time.strptime(getLastModifiedTime(upstream_trace), "%a, %d %b %Y %H:%M:%S %Z")) |
76 |
|
|
upstream_timestamp = getLastModifiedTime(upstream_trace) |
77 |
|
|
|
78 |
|
|
if options.verbose: |
79 |
|
|
print "Upstream trace file last modified on", upstream_timestamp |
80 |
|
|
|
81 |
|
|
local_trace_timestamp = os.stat(local_trace)[stat.ST_MTIME] |
82 |
|
|
|
83 |
|
|
if options.verbose: |
84 |
|
|
print "Our copy of trace file last modified on", time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(local_trace_timestamp)) |
85 |
|
|
|
86 |
|
|
if URLisNewerThan(upstream_trace, local_trace_timestamp): |
87 |
|
|
if options.verbose: |
88 |
|
|
print "Because the upstream trace file is newer than what is on the mirror, I think it's time to resync the mirror" |
89 |
|
|
sys.exit(0) |
90 |
|
|
else: |
91 |
|
|
if options.verbose: |
92 |
|
|
print "I believe our mirror to be in sync with the upstream" |
93 |
|
|
iterations = 0 |
94 |
|
|
while iterations < options.maxretries: |
95 |
|
|
if options.verbose: |
96 |
|
|
print "Sleeping for %d seconds" % options.wait |
97 |
|
|
time.sleep(options.wait) |
98 |
|
|
if URLisNewerThan(upstream_trace, local_trace_timestamp): |
99 |
|
|
upstream_timestamp = getLastModifiedTime(upstream_trace) |
100 |
|
|
break |
101 |
|
|
else: |
102 |
|
|
if options.verbose: |
103 |
|
|
print "Upstream trace file last modified on", upstream_timestamp |
104 |
|
|
iterations += 1 |
105 |
|
|
else: |
106 |
|
|
if options.verbose and iterations > 0: |
107 |
|
|
print "Giving up" |
108 |
|
|
sys.exit(1) |
109 |
|
|
if options.verbose: |
110 |
|
|
print "Upstream trace file last modified on", upstream_timestamp |
111 |
|
|
print "Because the upstream trace file is newer than what is on the mirror, I think it's time to resync the mirror" |
112 |
|
|
sys.exit(0) |
113 |
|
|
|
114 |
|
|
if __name__ == '__main__': |
115 |
|
|
main() |