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