]>
Commit | Line | Data |
---|---|---|
2b60fce9 MT |
1 | #!/usr/bin/python |
2 | ############################################################################### | |
3 | # # | |
4 | # IPFire.org - A linux based firewall # | |
5 | # Copyright (C) 2008 Michael Tremer & Christian Schmidt # | |
6 | # # | |
7 | # This program is free software: you can redistribute it and/or modify # | |
8 | # it under the terms of the GNU General Public License as published by # | |
9 | # the Free Software Foundation, either version 3 of the License, or # | |
10 | # (at your option) any later version. # | |
11 | # # | |
12 | # This program is distributed in the hope that it will be useful, # | |
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # | |
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # | |
15 | # GNU General Public License for more details. # | |
16 | # # | |
17 | # You should have received a copy of the GNU General Public License # | |
18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. # | |
19 | # # | |
20 | ############################################################################### | |
21 | ||
22 | import os | |
23 | import sys | |
24 | import time | |
25 | import socket | |
10da7ad4 | 26 | import base64 |
2b60fce9 MT |
27 | from pysqlite2 import dbapi2 as sqlite |
28 | ||
29 | sys.path.append(".") | |
30 | ||
31 | from constants import config | |
32 | ||
33 | class Database: | |
34 | def __init__(self, path): | |
35 | self.db = sqlite.connect(os.path.join(path, config["db_name"])) | |
36 | c = self.cursor() | |
37 | c.executescript(""" | |
38 | create table if not exists config(key, value, date); | |
39 | create table if not exists durations(duration); | |
40 | """) | |
41 | c.close() | |
42 | ||
43 | def __call__(self): | |
44 | return self.cursor() | |
45 | ||
46 | def __del__(self): | |
47 | self.commit() | |
48 | self.db.close() | |
49 | ||
50 | def cursor(self): | |
51 | return self.db.cursor() | |
52 | ||
53 | def commit(self): | |
54 | self.db.commit() | |
55 | ||
56 | class DatabaseConfig: | |
57 | def __init__(self, db, key): | |
58 | self.db = db | |
59 | self.key = key | |
60 | self.data = None | |
61 | self.date = None | |
62 | ||
63 | def get(self): | |
64 | if not self.data: | |
65 | c = self.db.cursor() | |
66 | c.execute("SELECT value FROM %(table)s WHERE key = '%(key)s'" \ | |
67 | % { "table" : "config", | |
68 | "key" : self.key, }) | |
69 | try: | |
70 | self.data = c.fetchone()[0] | |
71 | except TypeError: | |
72 | self.data = None | |
73 | c.close() | |
74 | return self.data | |
75 | ||
76 | __call__ = get | |
77 | ||
78 | def time(self): | |
79 | if not self.date: | |
80 | c = self.db.cursor() | |
81 | c.execute("SELECT date FROM %(table)s WHERE key = '%(key)s'" \ | |
82 | % { "table" : "config", | |
83 | "key" : self.key, }) | |
84 | try: | |
85 | self.date = float("%s" % c.fetchone()[0]) | |
86 | except TypeError: | |
87 | self.date = None | |
88 | c.close() | |
89 | return self.date or float(0) | |
90 | ||
91 | def set(self, value): | |
92 | #value = (value,) | |
93 | c = self.db.cursor() | |
94 | if not self.get(): | |
95 | sql = "INSERT INTO %(table)s(key, value, date) VALUES('%(key)s', '%(value)s', '%(date)s')" \ | |
96 | % { "table" : "config", | |
97 | "key" : self.key, | |
98 | "value" : value, | |
99 | "date" : time.time(), } | |
100 | ||
101 | else: | |
102 | sql = "UPDATE %(table)s SET value='%(value)s', date='%(date)s' WHERE key='%(key)s'" \ | |
103 | % { "table" : "config", | |
104 | "key" : self.key, | |
105 | "value" : value, | |
106 | "date" : time.time(), } | |
107 | c.execute(sql) | |
108 | c.close() | |
109 | self.data = value | |
110 | self.db.commit() | |
111 | ||
112 | class DurationsConfig: | |
113 | def __init__(self, db): | |
114 | self.db = db | |
115 | ||
116 | def get(self, sort=0): | |
117 | c = self.db.cursor() | |
118 | c.execute("SELECT duration FROM durations") | |
1e0061eb MT |
119 | ret = [] |
120 | for value in c.fetchall(): | |
121 | value = int("%s" % value) | |
122 | if value < 5400: # 1,5h | |
123 | continue | |
124 | ret.append(value) | |
2b60fce9 MT |
125 | c.close() |
126 | if sort: ret.sort() | |
127 | return ret | |
128 | ||
129 | def set(self, value): | |
130 | #value = (value,) | |
131 | c = self.db.cursor() | |
132 | c.execute("INSERT INTO %(table)s(duration) VALUES('%(value)s')" \ | |
133 | % { "table" : "durations", | |
134 | "value" : value, }) | |
135 | c.close() | |
136 | self.db.commit() | |
137 | ||
138 | def get_avg(self): | |
139 | sum = 0 | |
140 | durations = self.get() | |
141 | if not len(durations): | |
142 | return None | |
143 | for value in durations: | |
1e0061eb | 144 | sum += value |
2b60fce9 MT |
145 | avg = sum / len(durations) |
146 | return avg | |
147 | ||
148 | def get_eta(self, timestamp): | |
149 | avg = self.get_avg() | |
150 | if not avg: | |
151 | return "N/A" | |
152 | eta = int(timestamp) + avg | |
153 | return time.ctime(eta) | |
154 | ||
155 | class DistccConfig(DatabaseConfig): | |
10da7ad4 | 156 | def __init__(self, db, key, hostname, jobs): |
2b60fce9 MT |
157 | DatabaseConfig.__init__(self, db, key) |
158 | self.hostname = hostname | |
10da7ad4 | 159 | self.jobs = jobs |
2b60fce9 MT |
160 | |
161 | def __str__(self): | |
fda98c60 | 162 | if not self.ping() or self.get() == "0": |
2b60fce9 | 163 | return "" |
10da7ad4 MT |
164 | return "%s:%s/%s,lzo \t# %s" % \ |
165 | (socket.gethostbyname(self.hostname), self.get(), self.jobs or "4", self.hostname) | |
2b60fce9 MT |
166 | |
167 | def ping(self): | |
168 | if not self.hostname: | |
169 | return False | |
170 | return not os.system("ping -c1 -w1 %s &>/dev/null" % self.hostname) | |
171 | ||
172 | def version(self): | |
173 | return os.popen("distcc --version").readlines() | |
174 | ||
10da7ad4 MT |
175 | class FileConfig: |
176 | def __init__(self, path, filetype): | |
177 | self.filename = os.path.join(path, config["path"][filetype]) | |
178 | ||
179 | # Create the file if not existant | |
180 | if not os.access(self.filename, os.R_OK): | |
181 | f = open(self.filename, "w") | |
182 | f.close() | |
183 | ||
184 | def get(self): | |
185 | ret = [] | |
186 | try: | |
187 | f = open(self.filename) | |
188 | ret = f.readlines() | |
189 | f.close() | |
190 | except: | |
191 | pass | |
192 | return ret or ["Log is empty."] | |
193 | ||
194 | __call__ = get | |
195 | ||
196 | def set(self, lines): | |
197 | f = open(self.filename, "w") | |
198 | for line in base64.b64decode(lines).split("\n"): | |
199 | f.write("%s\n" % line.rstrip("\n")) | |
200 | f.close() | |
201 | ||
2b60fce9 MT |
202 | class Builder: |
203 | def __init__(self, config, uuid): | |
204 | self.uuid = uuid | |
205 | self.config = config | |
206 | self.path = os.path.join(self.config['path']['db'], self.uuid) | |
207 | ||
208 | if not os.access(self.path, os.R_OK): | |
209 | try: | |
210 | os.mkdir(self.path) | |
211 | except: | |
212 | pass | |
213 | ||
214 | self.db = Database(self.path) | |
10da7ad4 | 215 | |
2b60fce9 MT |
216 | self.hostname = DatabaseConfig(self.db, "hostname") |
217 | self.state = DatabaseConfig(self.db, "state") | |
218 | self.package = DatabaseConfig(self.db, "package") | |
10da7ad4 | 219 | |
2b60fce9 | 220 | self.duration = DurationsConfig(self.db) |
10da7ad4 MT |
221 | self.jobs = DatabaseConfig(self.db, "jobs") |
222 | self.distcc = DistccConfig(self.db, "distcc", self.hostname(), self.jobs()) | |
223 | ||
224 | self.log = FileConfig(self.path, "log") | |
2b60fce9 MT |
225 | |
226 | def set(self, key, value): | |
227 | eval("self.%s.set(\"%s\")" % (key, value,)) | |
228 | ||
229 | def get(self, key): | |
230 | return eval("self.%s.get()" % (key,)) | |
231 | ||
205adcfe | 232 | def getAllBuilders(age=0): |
2b60fce9 MT |
233 | builders = [] |
234 | for uuid in os.listdir(config["path"]["db"]): | |
235 | if uuid == "empty.txt": continue | |
236 | builder = Builder(config, uuid) | |
205adcfe MT |
237 | # If there was no activity since "age" days -> continue... |
238 | if age and (time.time() - builder.state.time()) > age*24*60*60: | |
239 | continue | |
2b60fce9 MT |
240 | builders.append(builder) |
241 | return builders |