]>
git.ipfire.org Git - people/jschlag/pbs.git/blob - src/buildservice/mirrors.py
8 import tornado
.httpclient
14 log
= logging
.getLogger("mirrors")
17 from .decorators
import lazy_property
19 class Mirrors(base
.Object
):
21 res
= self
.db
.query("SELECT * FROM mirrors \
22 WHERE deleted IS FALSE ORDER BY hostname")
26 mirror
= Mirror(self
.backend
, row
.id, data
=row
)
27 mirrors
.append(mirror
)
31 def _get_mirror(self
, query
, *args
):
32 res
= self
.db
.get(query
, *args
)
35 return Mirror(self
.backend
, res
.id, data
=res
)
37 def create(self
, hostname
, path
="", owner
=None, contact
=None, user
=None):
38 mirror
= self
._get
_mirror
("INSERT INTO mirrors(hostname, path, owner, contact) \
39 VALUES(%s, %s, %s, %s) RETURNING *", hostname
, path
, owner
, contact
)
42 mirror
.log("created", user
=user
)
46 def get_random(self
, limit
=None):
47 query
= "SELECT id FROM mirrors WHERE status = 'enabled' ORDER BY RAND()"
55 for mirror
in self
.db
.query(query
, *args
):
56 mirror
= Mirror(self
.pakfire
, mirror
.id)
57 mirrors
.append(mirror
)
61 def get_by_id(self
, id):
62 return self
._get
_mirror
("SELECT * FROM mirrors WHERE id = %s", id)
64 def get_by_hostname(self
, hostname
):
65 return self
._get
_mirror
("SELECT * FROM mirrors \
66 WHERE hostname = %s AND deleted IS FALSE", hostname
)
68 def get_for_location(self
, address
):
69 country_code
= self
.backend
.geoip
.guess_from_address(address
)
71 # Cannot return any good mirrors if location is unknown
77 # Walk through all mirrors
79 if mirror
.country_code
== country_code
:
80 mirrors
.append(mirror
)
82 # XXX needs to search for nearby countries
86 def get_history(self
, limit
=None, offset
=None, mirror
=None, user
=None):
87 query
= "SELECT * FROM mirrors_history"
93 conditions
.append("mirror_id = %s")
94 args
.append(mirror
.id)
97 conditions
.append("user_id = %s")
101 query
+= " WHERE %s" % " AND ".join(conditions
)
103 query
+= " ORDER BY time DESC"
107 query
+= " LIMIT %s,%s"
108 args
+= [offset
, limit
,]
114 for entry
in self
.db
.query(query
, *args
):
115 entry
= logs
.MirrorLogEntry(self
.pakfire
, entry
)
116 entries
.append(entry
)
120 def check(self
, **kwargs
):
122 Runs the mirror check for all mirrors
125 with self
.db
.transaction():
126 mirror
.check(**kwargs
)
129 class Mirror(base
.DataObject
):
132 def __eq__(self
, other
):
133 if isinstance(other
, self
.__class
__):
134 return self
.id == other
.id
136 def log(self
, action
, user
=None):
141 self
.db
.execute("INSERT INTO mirrors_history(mirror_id, action, user_id, time) \
142 VALUES(%s, %s, %s, NOW())", self
.id, action
, user_id
)
144 def set_hostname(self
, hostname
):
145 self
._set
_attribute
("hostname", hostname
)
147 hostname
= property(lambda self
: self
.data
.hostname
, set_hostname
)
151 return self
.data
.path
153 def set_path(self
, path
):
154 self
._set
_attribute
("path", path
)
156 path
= property(lambda self
: self
.data
.path
, set_path
)
160 return self
.make_url()
162 def make_url(self
, path
=""):
163 url
= "http://%s%s" % (self
.hostname
, self
.path
)
165 if path
.startswith("/"):
168 return urlparse
.urljoin(url
, path
)
170 def set_owner(self
, owner
):
171 self
._set
_attribute
("owner", owner
)
173 owner
= property(lambda self
: self
.data
.owner
or "", set_owner
)
175 def set_contact(self
, contact
):
176 self
._set
_attribute
("contact", contact
)
178 contact
= property(lambda self
: self
.data
.contact
or "", set_contact
)
180 def check(self
, connect_timeout
=10, request_timeout
=10):
181 log
.info("Running mirror check for %s" % self
.hostname
)
183 client
= tornado
.httpclient
.HTTPClient()
185 # Get URL for .timestamp
186 url
= self
.make_url(".timestamp")
187 log
.debug(" Fetching %s..." % url
)
190 time_start
= time
.time()
196 # XXX needs to catch connection resets, DNS errors, etc.
199 response
= client
.fetch(url
,
200 connect_timeout
=connect_timeout
,
201 request_timeout
=request_timeout
)
203 # We expect the response to be an integer
204 # which holds the timestamp of the last sync
205 # in seconds since epoch UTC
207 timestamp
= int(response
.body
)
211 # Convert to datetime
212 last_sync_at
= datetime
.datetime
.utcfromtimestamp(timestamp
)
214 # Must have synced within 24 hours
215 now
= datetime
.datetime
.utcnow()
216 if now
- last_sync_at
>= datetime
.timedelta(hours
=24):
219 except tornado
.httpclient
.HTTPError
as e
:
224 response_time
= time
.time() - time_start
227 self
.db
.execute("INSERT INTO mirrors_checks(mirror_id, response_time, \
228 http_status, last_sync_at, status) VALUES(%s, %s, %s, %s, %s)",
229 self
.id, response_time
, http_status
, last_sync_at
, status
)
232 def last_check(self
):
233 res
= self
.db
.get("SELECT * FROM mirrors_checks \
234 WHERE mirror_id = %s ORDER BY timestamp DESC LIMIT 1", self
.id)
241 return self
.last_check
.status
244 def average_response_time(self
):
245 res
= self
.db
.get("SELECT AVG(response_time) AS response_time \
246 FROM mirrors_checks WHERE mirror_id = %s \
247 AND timestamp >= NOW() - '24 hours'::interval", self
.id)
249 return res
.response_time
253 return socket
.gethostbyname(self
.hostname
)
256 def country_code(self
):
257 return self
.backend
.geoip
.guess_from_address(self
.address
) or "UNKNOWN"
259 def get_history(self
, *args
, **kwargs
):
260 kwargs
["mirror"] = self
262 return self
.pakfire
.mirrors
.get_history(*args
, **kwargs
)