]>
git.ipfire.org Git - people/jschlag/pbs.git/blob - src/buildservice/mirrors.py
5b6f76b7299305074b9a36a5306cda3b5e435371
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
)
149 def set_deleted(self
, deleted
):
150 self
._set
_attribute
("deleted", deleted
)
152 deleted
= property(lambda s
: s
.data
.deleted
, set_deleted
)
156 return self
.data
.path
158 def set_path(self
, path
):
159 self
._set
_attribute
("path", path
)
161 path
= property(lambda self
: self
.data
.path
, set_path
)
165 return self
.make_url()
167 def make_url(self
, path
=""):
168 url
= "%s://%s%s" % (
169 "https" if self
.supports_https
else "http",
174 if path
.startswith("/"):
177 return urlparse
.urljoin(url
, path
)
179 def set_supports_https(self
, supports_https
):
180 self
._set
_attribute
("supports_https", supports_https
)
182 supports_https
= property(lambda s
: s
.data
.supports_https
, set_supports_https
)
184 def set_owner(self
, owner
):
185 self
._set
_attribute
("owner", owner
)
187 owner
= property(lambda self
: self
.data
.owner
or "", set_owner
)
189 def set_contact(self
, contact
):
190 self
._set
_attribute
("contact", contact
)
192 contact
= property(lambda self
: self
.data
.contact
or "", set_contact
)
194 def check(self
, connect_timeout
=10, request_timeout
=10):
195 log
.info("Running mirror check for %s" % self
.hostname
)
197 client
= tornado
.httpclient
.HTTPClient()
199 # Get URL for .timestamp
200 url
= self
.make_url(".timestamp")
201 log
.debug(" Fetching %s..." % url
)
204 time_start
= time
.time()
210 # XXX needs to catch connection resets, DNS errors, etc.
213 response
= client
.fetch(url
,
214 connect_timeout
=connect_timeout
,
215 request_timeout
=request_timeout
)
217 # We expect the response to be an integer
218 # which holds the timestamp of the last sync
219 # in seconds since epoch UTC
221 timestamp
= int(response
.body
)
225 # Convert to datetime
226 last_sync_at
= datetime
.datetime
.utcfromtimestamp(timestamp
)
228 # Must have synced within 24 hours
229 now
= datetime
.datetime
.utcnow()
230 if now
- last_sync_at
>= datetime
.timedelta(hours
=24):
233 except tornado
.httpclient
.HTTPError
as e
:
238 response_time
= time
.time() - time_start
241 self
.db
.execute("INSERT INTO mirrors_checks(mirror_id, response_time, \
242 http_status, last_sync_at, status) VALUES(%s, %s, %s, %s, %s)",
243 self
.id, response_time
, http_status
, last_sync_at
, status
)
246 def last_check(self
):
247 res
= self
.db
.get("SELECT * FROM mirrors_checks \
248 WHERE mirror_id = %s ORDER BY timestamp DESC LIMIT 1", self
.id)
255 return self
.last_check
.status
258 def average_response_time(self
):
259 res
= self
.db
.get("SELECT AVG(response_time) AS response_time \
260 FROM mirrors_checks WHERE mirror_id = %s \
261 AND timestamp >= NOW() - '24 hours'::interval", self
.id)
263 return res
.response_time
267 return socket
.gethostbyname(self
.hostname
)
270 def country_code(self
):
271 return self
.backend
.geoip
.guess_from_address(self
.address
) or "UNKNOWN"
273 def get_history(self
, *args
, **kwargs
):
274 kwargs
["mirror"] = self
276 return self
.pakfire
.mirrors
.get_history(*args
, **kwargs
)