]> git.ipfire.org Git - people/jschlag/pbs.git/blob - src/buildservice/mirrors.py
Use autotools
[people/jschlag/pbs.git] / src / buildservice / mirrors.py
1 #!/usr/bin/python
2
3 import logging
4 import math
5 import socket
6
7 import base
8 import logs
9
10 class GeoIP(object):
11 def __init__(self, pakfire):
12 self.pakfire = pakfire
13
14 self.db = self.pakfire.geoip_db
15
16 def __encode_ip(self, addr):
17 # We get a tuple if there were proxy headers.
18 addr = addr.split(", ")
19 if addr:
20 addr = addr[-1]
21
22 # ip is calculated as described in http://dev.maxmind.com/geoip/csv
23 try:
24 a1, a2, a3, a4 = addr.split(".")
25
26 a1 = int(a1)
27 a2 = int(a2)
28 a3 = int(a3)
29 a4 = int(a4)
30 except:
31 return 0
32
33 return (16777216 * a1) + (65536 * a2) + (256 * a3) + a4
34
35 def get_all(self, addr):
36 addr = self.__encode_ip(addr)
37
38 ret = self.db.get("\
39 SELECT * FROM locations \
40 JOIN addresses ON addresses.location = locations.id \
41 WHERE \
42 %s BETWEEN addresses.start_ip_num AND addresses.end_ip_num \
43 LIMIT 1", addr)
44
45 # If location was not determinable
46 if ret and ret.latitude == 0 and ret.longitude == 0:
47 return None
48
49 return ret
50
51
52 class Mirrors(base.Object):
53 def get_all(self):
54 mirrors = []
55
56 for mirror in self.db.query("SELECT id FROM mirrors \
57 WHERE NOT status = 'deleted' ORDER BY hostname"):
58 mirror = Mirror(self.pakfire, mirror.id)
59 mirrors.append(mirror)
60
61 return mirrors
62
63 def count(self, status=None):
64 query = "SELECT COUNT(*) AS count FROM mirrors"
65 args = []
66
67 if status:
68 query += " WHERE status = %s"
69 args.append(status)
70
71 query = self.db.get(query, *args)
72
73 return query.count
74
75 def get_random(self, limit=None):
76 query = "SELECT id FROM mirrors WHERE status = 'enabled' ORDER BY RAND()"
77 args = []
78
79 if limit:
80 query += " LIMIT %s"
81 args.append(limit)
82
83 mirrors = []
84 for mirror in self.db.query(query, *args):
85 mirror = Mirror(self.pakfire, mirror.id)
86 mirrors.append(mirror)
87
88 return mirrors
89
90 def get_by_id(self, id):
91 mirror = self.db.get("SELECT id FROM mirrors WHERE id = %s", id)
92 if not mirror:
93 return
94
95 return Mirror(self.pakfire, mirror.id)
96
97 def get_by_hostname(self, hostname):
98 mirror = self.db.get("SELECT id FROM mirrors WHERE NOT status = 'deleted' \
99 AND hostname = %s", hostname)
100
101 if not mirror:
102 return
103
104 return Mirror(self.pakfire, mirror.id)
105
106 def get_for_location(self, addr):
107 distance = 10
108
109 # Get all mirrors in here.
110 _mirrors = self.get_all()
111
112 mirrors = []
113 while len(mirrors) <= 2 and distance <= 270:
114 for mirror in _mirrors:
115 if not mirror.enabled:
116 continue
117
118 if mirror in mirrors:
119 continue
120
121 # Cannot calc the distance for mirrors when their location is unknown.
122 if mirror.location is None:
123 continue
124
125 if mirror.distance_to(addr) <= distance:
126 mirrors.append(mirror)
127
128 distance *= 1.2
129
130 return mirrors
131
132 def get_history(self, limit=None, offset=None, mirror=None, user=None):
133 query = "SELECT * FROM mirrors_history"
134 args = []
135
136 conditions = []
137
138 if mirror:
139 conditions.append("mirror_id = %s")
140 args.append(mirror.id)
141
142 if user:
143 conditions.append("user_id = %s")
144 args.append(user.id)
145
146 if conditions:
147 query += " WHERE %s" % " AND ".join(conditions)
148
149 query += " ORDER BY time DESC"
150
151 if limit:
152 if offset:
153 query += " LIMIT %s,%s"
154 args += [offset, limit,]
155 else:
156 query += " LIMIT %s"
157 args += [limit,]
158
159 entries = []
160 for entry in self.db.query(query, *args):
161 entry = logs.MirrorLogEntry(self.pakfire, entry)
162 entries.append(entry)
163
164 return entries
165
166
167 class Mirror(base.Object):
168 def __init__(self, pakfire, id):
169 base.Object.__init__(self, pakfire)
170
171 self.id = id
172
173 # Cache.
174 self._data = None
175 self._location = None
176
177 def __cmp__(self, other):
178 return cmp(self.id, other.id)
179
180 @classmethod
181 def create(cls, pakfire, hostname, path="", owner=None, contact=None, user=None):
182 id = pakfire.db.execute("INSERT INTO mirrors(hostname, path, owner, contact) \
183 VALUES(%s, %s, %s, %s)", hostname, path, owner, contact)
184
185 mirror = cls(pakfire, id)
186 mirror.log("created", user=user)
187
188 return mirror
189
190 def log(self, action, user=None):
191 user_id = None
192 if user:
193 user_id = user.id
194
195 self.db.execute("INSERT INTO mirrors_history(mirror_id, action, user_id, time) \
196 VALUES(%s, %s, %s, NOW())", self.id, action, user_id)
197
198 @property
199 def data(self):
200 if self._data is None:
201 self._data = \
202 self.db.get("SELECT * FROM mirrors WHERE id = %s", self.id)
203
204 return self._data
205
206 def set_status(self, status, user=None):
207 assert status in ("enabled", "disabled", "deleted")
208
209 if self.status == status:
210 return
211
212 self.db.execute("UPDATE mirrors SET status = %s WHERE id = %s",
213 status, self.id)
214
215 if self._data:
216 self._data["status"] = status
217
218 # Log the status change.
219 self.log(status, user=user)
220
221 def set_hostname(self, hostname):
222 if self.hostname == hostname:
223 return
224
225 self.db.execute("UPDATE mirrors SET hostname = %s WHERE id = %s",
226 hostname, self.id)
227
228 if self._data:
229 self._data["hostname"] = hostname
230
231 hostname = property(lambda self: self.data.hostname, set_hostname)
232
233 @property
234 def path(self):
235 return self.data.path
236
237 def set_path(self, path):
238 if self.path == path:
239 return
240
241 self.db.execute("UPDATE mirrors SET path = %s WHERE id = %s",
242 path, self.id)
243
244 if self._data:
245 self._data["path"] = path
246
247 path = property(lambda self: self.data.path, set_path)
248
249 @property
250 def url(self):
251 ret = "http://%s" % self.hostname
252
253 if self.path:
254 path = self.path
255
256 if not self.path.startswith("/"):
257 path = "/%s" % path
258
259 if self.path.endswith("/"):
260 path = path[:-1]
261
262 ret += path
263
264 return ret
265
266 def set_owner(self, owner):
267 if self.owner == owner:
268 return
269
270 self.db.execute("UPDATE mirrors SET owner = %s WHERE id = %s",
271 owner, self.id)
272
273 if self._data:
274 self._data["owner"] = owner
275
276 owner = property(lambda self: self.data.owner or "", set_owner)
277
278 def set_contact(self, contact):
279 if self.contact == contact:
280 return
281
282 self.db.execute("UPDATE mirrors SET contact = %s WHERE id = %s",
283 contact, self.id)
284
285 if self._data:
286 self._data["contact"] = contact
287
288 contact = property(lambda self: self.data.contact or "", set_contact)
289
290 @property
291 def status(self):
292 return self.data.status
293
294 @property
295 def enabled(self):
296 return self.status == "enabled"
297
298 @property
299 def check_status(self):
300 return self.data.check_status
301
302 @property
303 def last_check(self):
304 return self.data.last_check
305
306 @property
307 def address(self):
308 return socket.gethostbyname(self.hostname)
309
310 @property
311 def location(self):
312 if self._location is None:
313 self._location = self.geoip.get_all(self.address)
314
315 return self._location
316
317 @property
318 def country_code(self):
319 if self.location:
320 return self.location.country_code
321
322 return "UNKNOWN"
323
324 @property
325 def latitude(self):
326 if self.location:
327 return self.location.latitude
328
329 return 0
330
331 @property
332 def longitude(self):
333 if self.location:
334 return self.location.longitude
335
336 return 0
337
338 def distance_to(self, addr):
339 location = self.geoip.get_all(addr)
340 if not location:
341 return 0
342
343 #if location.country_code.lower() in self.prefer_for_countries:
344 # return 0
345
346 distance_vector = (
347 self.latitude - location.latitude,
348 self.longitude - location.longitude
349 )
350
351 distance = 0
352 for i in distance_vector:
353 distance += i**2
354
355 return math.sqrt(distance)
356
357 def get_history(self, *args, **kwargs):
358 kwargs["mirror"] = self
359
360 return self.pakfire.mirrors.get_history(*args, **kwargs)