]> git.pld-linux.org Git - projects/pld-builder.new.git/blame - PLD_Builder/rpm_builder.py
- log url that failed
[projects/pld-builder.new.git] / PLD_Builder / rpm_builder.py
CommitLineData
dfff8bd5
MM
1# vi: encoding=utf-8 ts=8 sts=4 sw=4 et
2
3ea4b156
MM
3import sys
4import os
5import atexit
6import time
8152253f 7import datetime
deda9a51 8import string
10764658 9import urllib2
3ea4b156
MM
10
11from config import config, init_conf
12from bqueue import B_Queue
3ea4b156
MM
13import lock
14import util
3f446d8f 15import loop
3ea4b156
MM
16import path
17import status
18import log
19import chroot
20import ftp
e2cad913 21import buildlogs
59ce7cd6 22import notify
17f23d66
MM
23import build
24import report
73bdb36b 25import install
3ea4b156 26
53989cf3
MM
27# *HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*
28import socket
29
30socket.myorigsocket=socket.socket
31
32def mysocket(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0):
dfff8bd5
MM
33 s=socket.myorigsocket(family, type, proto)
34 s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
35 return s
53989cf3
MM
36
37socket.socket=mysocket
38# *HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*
39
3ea4b156
MM
40# this code is duplicated in srpm_builder, but we
41# might want to handle some cases differently here
42def pick_request(q):
dfff8bd5
MM
43 def mycmp(r1, r2):
44 if r1.kind != 'group' or r2.kind != 'group':
939af6d7 45 raise Exception, "non-group requests"
dfff8bd5
MM
46 pri_diff = cmp(r1.priority, r2.priority)
47 if pri_diff == 0:
48 return cmp(r1.time, r2.time)
49 else:
bbed4c4d 50 return pri_diff
dfff8bd5
MM
51 q.requests.sort(mycmp)
52 ret = q.requests[0]
53 return ret
3ea4b156 54
5c91097f 55def check_skip_build(r, b):
6ce49c66 56 src_url = config.control_url + "/srpms/" + r.id + "/skipme"
79141e52 57 good = False
9143deab 58 b.log_line("checking if we should skip the build")
6ce49c66
AM
59 while not good:
60 try:
aa90a502
AM
61 headers = { 'Cache-Control': 'no-cache', 'Pragma': 'no-cache' }
62 req = urllib2.Request(url=src_url, headers=headers)
63 f = urllib2.urlopen(req)
29526c54 64 good = True
f1d6a788 65 except urllib2.HTTPError, error:
f1d6a788 66 return False
10764658
AM
67 except urllib2.URLError, error:
68 # see errno.h
b8660ef8 69 if error.errno in [-3, 60, 61, 110, 111]:
6ce49c66
AM
70 b.log_line("unable to connect... trying again")
71 continue
72 else:
73 return False
29526c54 74 f.close()
b8acd415 75 return True
6ce49c66
AM
76 return False
77
17f23d66 78def fetch_src(r, b):
dfff8bd5
MM
79 src_url = config.control_url + "/srpms/" + r.id + "/" + b.src_rpm
80 b.log_line("fetching %s" % src_url)
81 start = time.time()
29526c54 82 good = False
dfff8bd5
MM
83 while not good:
84 try:
aa90a502
AM
85 headers = { 'Cache-Control': 'no-cache', 'Pragma': 'no-cache' }
86 req = urllib2.Request(url=src_url, headers=headers)
87 f = urllib2.urlopen(req)
29526c54 88 good = True
f1d6a788
AM
89 except urllib2.HTTPError, error:
90 # fail in a way where cron job will retry
deddea65 91 msg = "unable to fetch url %s, http code: %d" % (src_url, error.code)
f1d6a788 92 b.log_line(msg)
2a7e772f
AM
93 queue_time = time.time() - r.time
94 # 6 hours
02bb30ae 95 if error.code != 404 or (queue_time >= 0 and queue_time < (6 * 60 * 60)):
2a7e772f
AM
96 raise IOError, msg
97 else:
ec3ee349 98 msg = "in queue for more than 6 hours, download failing"
2a7e772f
AM
99 b.log_line(msg)
100 return False
10764658
AM
101 except urllib2.URLError, error:
102 # see errno.h
b8660ef8 103 if error.errno in [-3, 60, 61, 110, 111]:
deddea65 104 b.log_line("unable to connect to %s... trying again" % (src_url))
e0226a74 105 continue
dfff8bd5 106 else:
85d03545 107 raise
dfff8bd5
MM
108
109 o = chroot.popen("cat > %s" % b.src_rpm, mode = "w")
9e89ce60
AM
110
111 try:
112 bytes = util.sendfile(f, o)
113 except IOError, e:
00a1db68 114 b.log_line("error: unable to write to `%s': %s" % (b.src_rpm, e))
9e89ce60
AM
115 raise
116
dfff8bd5
MM
117 f.close()
118 o.close()
119 t = time.time() - start
120 if t == 0:
121 b.log_line("fetched %d bytes" % bytes)
122 else:
123 b.log_line("fetched %d bytes, %.1f K/s" % (bytes, bytes / 1024.0 / t))
3ea4b156 124
84c6175b 125def prepare_env():
3cf6c853 126 chroot.run("""
efb9c5f7 127 test ! -f /proc/uptime && mount /proc 2>/dev/null
3cf6c853
ER
128 test ! -c /dev/full && rm -f /dev/full && mknod -m 666 /dev/full c 1 7
129 test ! -c /dev/null && rm -f /dev/null && mknod -m 666 /dev/null c 1 3
130 test ! -c /dev/random && rm -f /dev/random && mknod -m 644 /dev/random c 1 8
131 test ! -c /dev/urandom && rm -f /dev/urandom && mknod -m 644 /dev/urandom c 1 9
132 test ! -c /dev/zero && rm -f /dev/zero && mknod -m 666 /dev/zero c 1 5
133
134 # make neccessary files readable for builder user
135 # TODO: see if they really aren't readable for builder
136 for db in Packages Name Basenames Providename Pubkeys; do
137 db=/var/lib/rpm/$db
138 test -f $db && chmod a+r $db
139 done
140
141 # try to limit network access for builder account
142 /bin/setfacl -m u:builder:--- /etc/resolv.conf
143 """, 'root')
84c6175b 144
17f23d66 145def build_rpm(r, b):
dfff8bd5
MM
146 status.push("building %s" % b.spec)
147 b.log_line("request from: %s" % r.requester)
6ce49c66 148
5c91097f 149 if check_skip_build(r, b):
6ce49c66
AM
150 b.log_line("build skipped due to src builder request")
151 res = "SKIP_REQUESTED"
152 return res
153
dfff8bd5
MM
154 b.log_line("started at: %s" % time.asctime())
155 fetch_src(r, b)
156 b.log_line("installing srpm: %s" % b.src_rpm)
ffc633c5
ER
157 res = chroot.run("""
158 install -d rpm/SPECS rpm/SOURCES
159 rpm -Uhv %s
160 """ % b.src_rpm, logfile = b.logfile)
dfff8bd5
MM
161 chroot.run("rm -f %s" % b.src_rpm, logfile = b.logfile)
162 b.files = []
163 tmpdir = "/tmp/B." + b.b_id[0:6]
164 if res:
165 b.log_line("error: installing src rpm failed")
511ece79 166 res = "FAIL_SRPM_INSTALL"
deda9a51 167 else:
84c6175b 168 prepare_env()
dfff8bd5 169 chroot.run("install -m 700 -d %s" % tmpdir)
be264f26
ER
170
171 b.default_target(config.arch)
2e5736d2 172 rpmbuild_opt = "%s %s %s" % (b.target_string(), b.kernel_string(), b.bconds_string())
81c135f6 173 # check for build arch before filling BR
0dded0a1 174 cmd = "cd rpm/SPECS; TMPDIR=%s exec nice -n %s rpmbuild -bp --short-circuit --nodeps --define 'prep exit 0' %s %s" % \
81c135f6
ER
175 (tmpdir, config.nice, rpmbuild_opt, b.spec)
176 res = chroot.run(cmd, logfile = b.logfile)
4f2d26fb 177 if res:
511ece79 178 res = "UNSUPP"
a957e64f 179 b.log_line("error: build arch check (%s) failed" % cmd)
81c135f6
ER
180
181 if not res:
feb26777 182 if ("no-install-br" not in r.flags) and not install.uninstall_self_conflict(b):
511ece79 183 res = "FAIL_DEPS_UNINSTALL"
feb26777 184 if ("no-install-br" not in r.flags) and not install.install_br(r, b):
511ece79 185 res = "FAIL_DEPS_INSTALL"
73bdb36b 186 if not res:
1de1342f 187 max_jobs = max(min(int(os.sysconf('SC_NPROCESSORS_ONLN') + 1), config.max_jobs), 1)
85303822 188 if r.max_jobs > 0:
a1b28a50 189 max_jobs = max(min(config.max_jobs, r.max_jobs), 1)
0dded0a1 190 cmd = "echo build-id: %s; cd rpm/SPECS; TMPDIR=%s exec nice -n %s rpmbuild -bb --define '_smp_mflags -j%d' %s %s" % \
0e8fbf23 191 (r.id, tmpdir, config.nice, max_jobs, rpmbuild_opt, b.spec)
81c135f6 192 b.log_line("building RPM using: %s" % cmd)
efb3621d 193 begin_time = time.time()
81c135f6 194 res = chroot.run(cmd, logfile = b.logfile)
efb3621d 195 end_time = time.time()
8152253f 196 b.log_line("ended at: %s, done in %s" % (time.asctime(), datetime.timedelta(0, end_time - begin_time)))
4f2d26fb
AM
197 if res:
198 res = "FAIL"
81c135f6
ER
199 files = util.collect_files(b.logfile)
200 if len(files) > 0:
201 r.chroot_files.extend(files)
202 else:
203 b.log_line("error: No files produced.")
2b9e7381
AM
204 last_section = util.find_last_section(b.logfile)
205 if last_section == None:
206 res = "FAIL"
207 else:
208 res = "FAIL_%s" % last_section.upper()
81c135f6
ER
209 b.files = files
210
dfff8bd5
MM
211 chroot.run("rm -rf %s; cd rpm/SPECS; rpmbuild --nodeps --nobuild " \
212 "--clean --rmspec --rmsource %s" % \
213 (tmpdir, b.spec), logfile = b.logfile)
4e9e9dee 214 chroot.run("chmod -R u+rwX rpm/BUILD/*; rm -rf rpm/BUILD/*", logfile = b.logfile)
dfff8bd5
MM
215
216 def ll(l):
217 util.append_to(b.logfile, l)
deda9a51 218
dfff8bd5 219 if b.files != []:
fd499dc1 220 rpm_cache_dir = config.rpm_cache_dir
e936beda 221 if "test-build" not in r.flags:
adc1235e 222 # NOTE: copying to cache dir doesn't mean that build failed, so ignore result
90d9480e 223 b.log_line("copy rpm files to cache_dir: %s" % rpm_cache_dir)
adc1235e 224 chroot.run(
fd499dc1
ER
225 "cp -f %s %s && poldek --mo=nodiff --mkidxz -s %s/" % \
226 (string.join(b.files), rpm_cache_dir, rpm_cache_dir),
227 logfile = b.logfile, user = "root"
228 )
e936beda 229 else:
fd499dc1 230 ll("test-build: not copying to " + rpm_cache_dir)
dfff8bd5
MM
231 ll("Begin-PLD-Builder-Info")
232 if "upgrade" in r.flags:
73bdb36b 233 b.upgraded = install.upgrade_from_batch(r, b)
dfff8bd5
MM
234 else:
235 ll("not upgrading")
236 ll("End-PLD-Builder-Info")
deda9a51 237
1051562e 238 for f in b.files:
dfff8bd5 239 local = r.tmp_dir + os.path.basename(f)
3e689257 240 chroot.cp(f, outfile = local, rm = True)
dfff8bd5 241 ftp.add(local)
1051562e 242
dfff8bd5
MM
243 def uploadinfo(b):
244 c="file:SRPMS:%s\n" % b.src_rpm
245 for f in b.files:
246 c=c + "file:ARCH:%s\n" % os.path.basename(f)
247 c=c + "END\n"
248 return c
3ea4b156 249
71a06b82 250 if config.gen_upinfo and b.files != [] and 'test-build' not in r.flags:
dfff8bd5
MM
251 fname = r.tmp_dir + b.src_rpm + ".uploadinfo"
252 f = open(fname, "w")
253 f.write(uploadinfo(b))
254 f.close()
255 ftp.add(fname, "uploadinfo")
256
257 status.pop()
258
259 return res
3ea4b156 260
17f23d66 261def handle_request(r):
dfff8bd5
MM
262 ftp.init(r)
263 buildlogs.init(r)
264 build.build_all(r, build_rpm)
265 report.send_report(r, is_src = False)
266 ftp.flush()
63319e0a 267 notify.send(r)
3ea4b156
MM
268
269def check_load():
dfff8bd5
MM
270 do_exit = 0
271 try:
272 f = open("/proc/loadavg")
273 if float(string.split(f.readline())[2]) > config.max_load:
274 do_exit = 1
275 except:
276 pass
277 if do_exit:
278 sys.exit(0)
3ea4b156 279
e8ee9db8 280def main_for(builder):
b8ec18af
AM
281 msg = ""
282
dfff8bd5 283 init_conf(builder)
dfff8bd5 284
dfff8bd5
MM
285 q = B_Queue(path.queue_file + "-" + config.builder)
286 q.lock(0)
287 q.read()
288 if q.requests == []:
289 q.unlock()
290 return
291 req = pick_request(q)
7b16924c 292 q.unlock()
dfff8bd5 293
91112237
AM
294 # high priority tasks have priority < 0, normal tasks >= 0
295 if req.priority >= 0:
b8ec18af
AM
296
297 # allow only one build in given builder at once
298 if not lock.lock("building-rpm-for-%s" % config.builder, non_block = 1):
299 return
300 # don't kill server
301 check_load()
302 # not more then job_slots builds at once
303 locked = 0
304 for slot in range(config.job_slots):
305 if lock.lock("building-rpm-slot-%d" % slot, non_block = 1):
306 locked = 1
307 break
308 if not locked:
309 return
310
311 # record fact that we got lock for this builder, load balancer
312 # will use it for fair-queuing
313 l = lock.lock("got-lock")
314 f = open(path.got_lock_file, "a")
315 f.write(config.builder + "\n")
316 f.close()
317 l.close()
318 else:
319 msg = "HIGH PRIORITY: "
dfff8bd5 320
b8ec18af
AM
321 msg += "handling request %s (%d) for %s from %s, priority %s" \
322 % (req.id, req.no, config.builder, req.requester, req.priority)
dfff8bd5
MM
323 log.notice(msg)
324 status.push(msg)
325 handle_request(req)
326 status.pop()
327
328 def otherreqs(r):
329 if r.no==req.no:
330 return False
331 else:
332 return True
333
334 q = B_Queue(path.queue_file + "-" + config.builder)
335 q.lock(0)
336 q.read()
337 previouslen=len(q.requests)
338 q.requests=filter(otherreqs, q.requests)
339 if len(q.requests)<previouslen:
340 q.write()
341 q.unlock()
342
e8ee9db8 343def main():
dfff8bd5 344 if len(sys.argv) < 2:
939af6d7 345 raise Exception, "fatal: need to have builder name as first arg"
dfff8bd5
MM
346 return main_for(sys.argv[1])
347
e8ee9db8 348if __name__ == '__main__':
dfff8bd5 349 loop.run_loop(main)
This page took 1.04701 seconds and 4 git commands to generate.