]>
Commit | Line | Data |
---|---|---|
3ea4b156 MM |
1 | import sys |
2 | import os | |
3 | import atexit | |
4 | import time | |
5 | import urllib | |
6 | ||
7 | from config import config, init_conf | |
8 | from bqueue import B_Queue | |
9 | from acl import acl | |
10 | import lock | |
11 | import util | |
12 | import path | |
13 | import status | |
14 | import log | |
15 | import chroot | |
16 | import ftp | |
17 | import buildlogs | |
18 | ||
19 | # this code is duplicated in srpm_builder, but we | |
20 | # might want to handle some cases differently here | |
21 | def pick_request(q): | |
22 | def mycmp(r1, r2): | |
23 | if r1.kind != 'group' or r2.kind != 'group': | |
24 | raise "non-group requests" | |
25 | pri_diff = cmp(r1.priority, r2.priority) | |
26 | if pri_diff == 0: | |
27 | return cmp(r1.time, r2.time) | |
28 | else: | |
29 | return pri_diff | |
30 | q.requests.sort(mycmp) | |
31 | ret = q.requests[0] | |
32 | q.requests = q.requests[1:] | |
33 | return ret | |
34 | ||
35 | def handle_request(r): | |
36 | def log_line(l): | |
37 | log.notice(l) | |
38 | util.append_to(spec_log, l) | |
39 | ||
40 | def fetch_src(b): | |
41 | src_url = config.control_url + "/srpms/" + r.id + "/" + b.src_rpm | |
42 | log_line("fetching %s" % src_url) | |
43 | start = time.time() | |
44 | f = urllib.urlopen(src_url) | |
45 | o = chroot.popen("cat > %s" % b.src_rpm, mode = "w") | |
46 | bytes = util.sendfile(f, o) | |
47 | f.close() | |
48 | o.close() | |
49 | t = time.time() - start | |
50 | if t == 0: | |
51 | log_line("fetched %d bytes" % bytes) | |
52 | else: | |
53 | log_line("fetched %d bytes, %.1f K/s" % (bytes, bytes / 1024.0 / t)) | |
54 | ||
55 | def build_rpm(b): | |
56 | global spec_log | |
57 | spec_log = tmp + b.spec + ".log" | |
58 | status.push("building %s" % b.spec) | |
59 | fetch_src(b) | |
60 | res = chroot.run("rpm -U %s && rm -f %s" % (b.src_rpm, b.src_rpm), | |
61 | logfile = spec_log) | |
62 | if res: | |
63 | log_line("error: installing src rpm failed") | |
64 | else: | |
65 | cmd = "cd rpm/SPECS; rpmbuild -bb %s" % b.spec | |
66 | log_line("Building RPM using: %s" % cmd) | |
67 | res = chroot.run(cmd, logfile = spec_log) | |
68 | files = util.collect_files(spec_log) | |
69 | if len(files) > 0: | |
70 | all_files.extend(files) | |
71 | else: | |
72 | # FIXME: is it error? | |
73 | log_line("error: No files produced.") | |
74 | res = 1 | |
75 | buildlogs.add(logfile = spec_log, failed = res) | |
76 | status.pop() | |
77 | return res | |
78 | ||
79 | tmp = path.spool_dir + r.id + "/" | |
80 | os.mkdir(tmp) | |
81 | atexit.register(util.clean_tmp, tmp) | |
82 | user = acl.user(r.requester) | |
83 | log.notice("started processing %s" % r.id) | |
84 | all_files = [] | |
85 | for batch in r.batches: | |
86 | log.notice("building %s" % batch.spec) | |
87 | if build_rpm(batch): | |
88 | # clean up | |
89 | log.notice("building %s failed" % batch.spec) | |
90 | chroot.run("rm -f %s" % string.join(all_files)) | |
91 | m = user.message_to() | |
92 | m.set_headers(subject = "Binary: %s failed" % batch.spec) | |
93 | # FIXME: write about other specs from group | |
94 | m.write("Building RPM failed for %s.\nAttached log:\n" % batch.spec) | |
95 | m.append_log(spec_log) | |
96 | m.send() | |
97 | buildlogs.flush() | |
98 | return | |
99 | log.notice("building %s finished" % batch.spec) | |
100 | for f in all_files: | |
101 | local = tmp + os.path.basename(f) | |
102 | chroot.run("cat %s; rm -f %s" % (f, f), logfile = local) | |
103 | ftp.add(local) | |
104 | ||
105 | # FIXME: send notification? | |
106 | buildlogs.flush() | |
107 | ftp.flush() | |
108 | ||
109 | def check_load(): | |
110 | try: | |
111 | f = open("/proc/loadavg") | |
112 | if float(string.split(f.readline())[2]) > config.max_load: | |
113 | sys.exit(0) | |
114 | except: | |
115 | pass | |
116 | ||
117 | def main(): | |
118 | if len(sys.argv) < 2: | |
119 | raise "fatal: need to have builder name as first arg" | |
120 | init_conf(sys.argv[1]) | |
121 | # allow only one build in given builder at once | |
122 | if not lock.lock("building-rpm-for-%s" % config.builder, non_block = 1): | |
123 | return | |
124 | # don't kill server | |
125 | check_load() | |
126 | # not more then job_slots builds at once | |
127 | locked = 0 | |
128 | for slot in range(config.job_slots): | |
129 | if lock.lock("building-rpm-slot-%d" % slot, non_block = 1): | |
130 | locked = 1 | |
131 | break | |
132 | if not locked: | |
133 | return | |
134 | ||
135 | status.push("picking request for %s" % config.builder) | |
136 | q = B_Queue(path.queue_file + "-" + config.builder) | |
137 | q.lock(0) | |
138 | q.read() | |
139 | if q.requests == []: | |
140 | return | |
141 | r = pick_request(q) | |
142 | q.write() | |
143 | q.unlock() | |
144 | status.pop() | |
145 | ||
146 | # record fact that we got lock for this builder, load balancer | |
147 | # will use it for fair-queuing | |
148 | l = lock.lock("got-lock") | |
149 | f = open(path.got_lock_file, "a") | |
150 | f.write(config.builder + "\n") | |
151 | f.close() | |
152 | l.close() | |
153 | ||
154 | msg = "handling request %s (%d) for %s from %s" \ | |
155 | % (r.id, r.no, config.builder, r.requester) | |
156 | log.notice(msg) | |
157 | status.push(msg) | |
158 | handle_request(r) | |
159 | status.pop() | |
160 | ||
161 | util.wrap(main) |