+++ /dev/null
-#!/usr/bin/python
-
-import os
-import time
-import cgi
-
-from stat import ST_MTIME
-from rhpl.simpleconfig import SimpleConfigFile
-
-DB_DIR = "db"
-
-def format_time(seconds, use_hours=1):
- if seconds is None or seconds < 0:
- if use_hours: return '--:--:--'
- else: return '--:--'
- else:
- seconds = int(seconds)
- minutes = seconds / 60
- seconds = seconds % 60
- if use_hours:
- hours = minutes / 60
- minutes = minutes % 60
- return '%02i:%02i:%02i' % (hours, minutes, seconds)
- else:
- return '%02i:%02i' % (minutes, seconds)
-
-def format_number(number, SI=0, space=' '):
- """Turn numbers into human-readable metric-like numbers"""
- symbols = ['', # (none)
- 'k', # kilo
- 'M', # mega
- 'G', # giga
- 'T', # tera
- 'P', # peta
- 'E', # exa
- 'Z', # zetta
- 'Y'] # yotta
-
- if SI: step = 1000.0
- else: step = 1024.0
-
- thresh = 999
- depth = 0
- max_depth = len(symbols) - 1
-
- # we want numbers between 0 and thresh, but don't exceed the length
- # of our list. In that event, the formatting will be screwed up,
- # but it'll still show the right number.
- while number > thresh and depth < max_depth:
- depth = depth + 1
- number = number / step
-
- if type(number) == type(1) or type(number) == type(1L):
- # it's an int or a long, which means it didn't get divided,
- # which means it's already short enough
- format = '%i%s%s'
- elif number < 9.95:
- # must use 9.95 for proper sizing. For example, 9.99 will be
- # rounded to 10.0 with the .1f format string (which is too long)
- format = '%.1f%s%s'
- else:
- format = '%.0f%s%s'
-
- return(format % (float(number or 0), space, symbols[depth]))
-
-stage2desc = {
- "unknown" : "Dunno what the host is doing at the moment...",
- "compiling" : "The host is really hard working at the moment...",
- "error" : "Oops! The host had an error...",
- "idle" : "The host is idle at the moment...",
-}
-
-sys2desc = {
- "CPU_NAME" : "CPU model",
- "CPU_MIPS" : "Bogomips",
- "CPU_MHZ" : "CPU MHz",
- "CPU_CNT" : "CPU cores",
- "MEM_SIZE" : "Memory size",
-}
-
-class Site:
- def __init__(self):
- print "Content-type: text/html"
- print
-
- def __call__(self):
- print '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
- <head>
- <title>IPFire - Builder</title>
- <style type="text/css">
- body { font-family: Verdana; font-size: 9pt; background-color:#f0f0f0; }
- a:link { color: black; text-decoration: none; }
- a:visited { color: black; text-decoration: none; }
- table { font-family: Verdana; font-size: 8pt; border: 1px solid; }
- td.header { background-color: #a0a0a0; text-align: left; color: white;
- font-size: 11pt; }
- td.date { text-align: center; }
- font.installed { color: green; }
- font.deleted { color: red; }
- font.update { color: blue; }
- font.error { color: red; }
- td.log { background: pink; }
- td.update { background: darkgrey; }
- /* td.distcc { background: darkgrey; } */
- td.online { background: green; color: white; text-align: center; }
- td.offline { background: red; color: white; text-align: center; }
- </style>
- <meta http-equiv="refresh" content="90; URL=%s" />
- </head>
- <body>
- <h1>IPFire Builder</h1>
- <p>This site is for monitoring the build machines...</p>
- <p>Made: %s</p>''' % (os.environ['SCRIPT_NAME'], time.ctime())
-
- self.content()
-
- print "\t\t</body>\n</html>"
-
- def content(self):
- for builder in builders:
- builder()
-
-
-class Builder:
- def __init__(self, uuid=None):
- self.uuid = uuid
- self.db = os.path.join(DB_DIR, self.uuid)
-
- if not os.path.isdir(self.db):
- os.mkdir(self.db)
-
- self.fn = {
- 'state' : os.path.join(self.db, "state"),
- 'distcc' : os.path.join(self.db, "distcc"),
- 'hostname' : os.path.join(self.db, "hostname"),
- 'build_durations' : os.path.join(self.db, "build_durations"),
- 'log' : os.path.join(self.db, "log"),
- 'profile' : os.path.join(self.db, "profile"),
- }
-
- self.sys = SimpleConfigFile()
- self.sys.read(self.fn['profile'])
-
- self.state = self._state()
-
- def _state(self, state="unknown"):
- """State says what the host is doing at the moment.
- This can be:
- - unknown - Didn't talk with host for more than two hours.
- - compiling - Host is working
- - error - Host had an error
- - idle - Host is idle
- - hidden - Host was idle or unknown for more than 12 hours"""
-
- if not state == "unknown":
- f = open(self.fn['state'], "w")
- f.write("%s\n" % state)
- f.close()
-
- if not os.access(self.fn['state'], os.R_OK):
- return state
-
- six_h_ago = int(time.time()) - (3600 * 6)
- twelve_h_ago = int(time.time()) - (3600 * 12)
- mtime = os.stat(self.fn['state'])[ST_MTIME]
-
- if mtime > six_h_ago:
- try:
- f = open(self.fn['state'])
- state = f.readline().rstrip("\n")
- f.close()
- except:
- pass
- elif mtime > twelve_h_ago:
- state = "hidden"
-
- return state
-
- def _build_durations(self, duration=None):
- """This returns a 4x-tupel:
- First value is best build duration.
- Second value is average build duration.
- Third value is worst build duration.
- Fourth value is the whole build duration."""
-
- ## set duration
- if duration:
- f = open(self.fn['build_durations'], "a")
- f.write("%s\n" % int(duration))
- f.close()
- return
-
- ## get duration
- durations = []
- all_build_duration = 0
- try:
- f = open(self.fn['build_durations'])
- except IOError:
- return (None, None, None, None)
- else:
- while True:
- duration = f.readline().rstrip("\n")
- if not duration:
- break # EOF
- durations.append(int(duration))
- f.close()
- durations.sort()
- for duration in durations:
- if duration < 3600: continue
- all_build_duration += duration
-
- avg = all_build_duration / len(durations)
-
- return (durations[0], avg, durations[-1], all_build_duration)
-
- def _log(self, log=[]):
-
- if log:
- f = open(self.fn['log'], "w")
- f.write("%s\n" % log)
- f.close()
- return
-
- try:
- f = open(self.fn['log'])
- log = f.readlines()
- f.close()
- except:
- pass
-
- return log
-
- def _last_update(self):
- if not os.access(self.fn['state'], os.R_OK):
- return
-
- return os.stat(self.fn['state'])[ST_MTIME]
-
- def _profile_get(self, what=None):
- data = self.sys.get(what)
- if data and what.endswith("_SIZE"):
- data = format_number(int(data))
- return data or None
-
- def _profile_set(self, what):
- self.sys.set(what)
- self.sys.write(self.fn['profile'])
-
- def __repr__(self):
- return "<Builder %s>" % self.uuid
-
- def __call__(self):
- if self.state == "hidden":
- return
-
- self.hostname = self._profile_get("HOSTNAME")
- self.distcc = self._profile_get("DISTCC")
- self.build_durations = self._build_durations()
- self.last_update = self._last_update()
-
- print "<table width='66%'>"
-
- ## give hostname or uuid
- print "\t<tr>"
- print "\t\t<td class='header' colspan='3' width='100%'>",
- if self.hostname:
- print self.hostname,
- else:
- print self.uuid,
- print "</td>"
- print "\t</tr>"
-
- ## give state
- print "\t<tr>"
- print "\t\t<td class='state' colspan='2' width='80%'><b>",
- print stage2desc[self.state],
- print "</b></td>"
- print "\t\t<td class='state' rowspan='8' width='20%'>",
- print "<img alt='%s' width='128px' height='128px' src='/images/%s.png' />" % (self.state, self.state,),
- print "</td>"
- print "\t</tr>"
-
- ## give sys info
- for key in ["CPU_NAME", "CPU_MHZ", "CPU_CNT", "CPU_MIPS", "MEM_SIZE"]:
- print "\t<tr>"
- print "\t\t<td class='sys' width='60%'><b>",
- print sys2desc[key]
- print "</b></td>"
- print "\t\t<td class='durations' width='40%'>",
- print self._profile_get(key) or "N/A"
- print "</td>"
- print "\t</tr>"
-
- ## give durations
- (min, avg, max, all) = self.build_durations
- print "\t<tr>"
- print "\t\t<td class='durations' width='60%'>",
- print "<b>Build durations</b>",
- print "</td>"
- print "\t\t<td class='durations' width='40%'>",
- if avg:
- print "<b>Average:</b> %s h<br />" % format_time(avg),
- if min:
- print "<b>Minimum:</b> %s h<br />" % format_time(min),
- if max:
- print "<b>Maximum:</b> %s h<br />" % format_time(max),
- if all:
- print "<b>As a whole:</b> %s h" % format_time(all),
-
- if not avg and not min and not max and not all:
- print "N/A",
-
- print "</td>"
- print "\t</tr>"
-
- ## give distcc
- print "\t<tr>"
- print "\t\t<td class='distcc' width='60%'>",
- print "<b>Distcc capable</b>",
- print "</td>"
- print "\t\t<td class='distcc' width='40%'>",
- if self.distcc == None or self.distcc == "0":
- print "No",
- else:
- print "Yes (port: %s)" \
- % (self.distcc),
- print "</td>"
- print "\t</tr>"
-
- ## give log
- if self.state == "error":
- print "\t<tr>"
- print "\t\t<td class='log' colspan='3' width='100%'>",
- for line in self._log():
- print "%s<br/>" % (line,)
- print "</td>"
- print "\t</tr>"
-
- ## give lastupdate
- if self.last_update:
- print "\t<tr>"
- print "\t\t<td class='update' colspan='3' width='100%'>",
- print "Last update:",
- print time.strftime("%Y-%b-%d %I:%M %p", time.localtime(self.last_update)),
- print " - ",
- print format_time(int(time.time() - self.last_update)),
- print "ago </td>"
- print "\t</tr>"
-
- print "</table>"
-
- print "<br />"
-
-form = cgi.FieldStorage()
-action = form.getfirst('action')
-
-if action in [ "compiling", "error", "idle", "set" ]:
- builder = Builder(form.getfirst('uuid'))
- if not action == "set":
- builder._state(action)
- if action == "set":
- key = form.getfirst('key')
- val = form.getfirst('val')
- if key == "duration":
- builder._build_durations(val)
- else:
- builder._profile_set((key, val))
- elif action == "error":
- log = form.getfirst('log')
- builder._log(log)
-else:
- builders = []
- for uuid in os.listdir(DB_DIR):
- if not os.path.isdir(os.path.join(DB_DIR, uuid)): continue
- builders.append(Builder(uuid))
-
- site = Site()
- site()
--- /dev/null
+#!/usr/bin/python
+###############################################################################
+# #
+# IPFire.org - A linux based firewall #
+# Copyright (C) 2008 Michael Tremer & Christian Schmidt #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+###############################################################################
+
+import os
+import sys
+import time
+import socket
+from pysqlite2 import dbapi2 as sqlite
+
+sys.path.append(".")
+
+from constants import config
+
+class Database:
+ def __init__(self, path):
+ self.db = sqlite.connect(os.path.join(path, config["db_name"]))
+ c = self.cursor()
+ c.executescript("""
+ create table if not exists config(key, value, date);
+ create table if not exists durations(duration);
+ """)
+ c.close()
+
+ def __call__(self):
+ return self.cursor()
+
+ def __del__(self):
+ self.commit()
+ self.db.close()
+
+ def cursor(self):
+ return self.db.cursor()
+
+ def commit(self):
+ self.db.commit()
+
+class DatabaseConfig:
+ def __init__(self, db, key):
+ self.db = db
+ self.key = key
+ self.data = None
+ self.date = None
+
+ def get(self):
+ if not self.data:
+ c = self.db.cursor()
+ c.execute("SELECT value FROM %(table)s WHERE key = '%(key)s'" \
+ % { "table" : "config",
+ "key" : self.key, })
+ try:
+ self.data = c.fetchone()[0]
+ except TypeError:
+ self.data = None
+ c.close()
+ return self.data
+
+ __call__ = get
+
+ def time(self):
+ if not self.date:
+ c = self.db.cursor()
+ c.execute("SELECT date FROM %(table)s WHERE key = '%(key)s'" \
+ % { "table" : "config",
+ "key" : self.key, })
+ try:
+ self.date = float("%s" % c.fetchone()[0])
+ except TypeError:
+ self.date = None
+ c.close()
+ return self.date or float(0)
+
+ def set(self, value):
+ #value = (value,)
+ c = self.db.cursor()
+ if not self.get():
+ sql = "INSERT INTO %(table)s(key, value, date) VALUES('%(key)s', '%(value)s', '%(date)s')" \
+ % { "table" : "config",
+ "key" : self.key,
+ "value" : value,
+ "date" : time.time(), }
+
+ else:
+ sql = "UPDATE %(table)s SET value='%(value)s', date='%(date)s' WHERE key='%(key)s'" \
+ % { "table" : "config",
+ "key" : self.key,
+ "value" : value,
+ "date" : time.time(), }
+ c.execute(sql)
+ c.close()
+ self.data = value
+ self.db.commit()
+
+class DurationsConfig:
+ def __init__(self, db):
+ self.db = db
+
+ def get(self, sort=0):
+ c = self.db.cursor()
+ c.execute("SELECT duration FROM durations")
+ ret = c.fetchall()
+ c.close()
+ if sort: ret.sort()
+ return ret
+
+ def set(self, value):
+ #value = (value,)
+ c = self.db.cursor()
+ c.execute("INSERT INTO %(table)s(duration) VALUES('%(value)s')" \
+ % { "table" : "durations",
+ "value" : value, })
+ c.close()
+ self.db.commit()
+
+ def get_avg(self):
+ sum = 0
+ durations = self.get()
+ if not len(durations):
+ return None
+ for value in durations:
+ sum += int("%s" % value)
+ avg = sum / len(durations)
+ return avg
+
+ def get_eta(self, timestamp):
+ avg = self.get_avg()
+ if not avg:
+ return "N/A"
+ eta = int(timestamp) + avg
+ return time.ctime(eta)
+
+class DistccConfig(DatabaseConfig):
+ def __init__(self, db, key, hostname):
+ DatabaseConfig.__init__(self, db, key)
+ self.hostname = hostname
+
+ def __str__(self):
+ if not self.hostname:
+ return ""
+ return "%s:%s/4,lzo" % \
+ (socket.gethostbyname(self.hostname), self.get(),)
+
+ def ping(self):
+ if not self.hostname:
+ return False
+ return not os.system("ping -c1 -w1 %s &>/dev/null" % self.hostname)
+
+ def version(self):
+ return os.popen("distcc --version").readlines()
+
+class Builder:
+ def __init__(self, config, uuid):
+ self.uuid = uuid
+ self.config = config
+ self.path = os.path.join(self.config['path']['db'], self.uuid)
+
+ if not os.access(self.path, os.R_OK):
+ try:
+ os.mkdir(self.path)
+ except:
+ pass
+
+ self.db = Database(self.path)
+
+ self.hostname = DatabaseConfig(self.db, "hostname")
+ self.state = DatabaseConfig(self.db, "state")
+ self.package = DatabaseConfig(self.db, "package")
+
+ self.duration = DurationsConfig(self.db)
+ self.distcc = DistccConfig(self.db, "distcc", self.hostname.get())
+
+ def set(self, key, value):
+ eval("self.%s.set(\"%s\")" % (key, value,))
+
+ def get(self, key):
+ return eval("self.%s.get()" % (key,))
+
+def getAllBuilders():
+ builders = []
+ for uuid in os.listdir(config["path"]["db"]):
+ if uuid == "empty.txt": continue
+ builder = Builder(config, uuid)
+ builders.append(builder)
+ return builders
--- /dev/null
+#!/usr/bin/python
+
+import os
+import time
+
+config = {
+ "title" : "IPFire - Builder",
+ "nightly_url" : "ftp://ftp.ipfire.org/pub/nightly-builds",
+ "path" : { "db" : "db", },
+ "script" : os.environ['SCRIPT_NAME'],
+ "time" : time.ctime(),
+ "db_name" : "builder.db",
+}
--- /dev/null
+#!/usr/bin/python
+###############################################################################
+# #
+# IPFire.org - A linux based firewall #
+# Copyright (C) 2008 Michael Tremer & Christian Schmidt #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+###############################################################################
+
+import os
+import time
+
+config = {
+ "title" : "IPFire - Builder",
+ "nightly_url" : ("ftp://ftp.ipfire.org/pub/nightly-builds/", "http://www.rowie.at/ipfire/builds/",),
+ "path" : { "db" : "db", },
+ "script" : os.environ['SCRIPT_NAME'],
+ "db_name" : "builder.db",
+}
+
+statedesc = {
+ None : "",
+ "unknown" : "Dunno what the host is doing at the moment...",
+ "compiling" : "The host is really hard working at the moment...",
+ "error" : "Oops! The host had an error...",
+ "idle" : "The host is idle at the moment...",
+}
+
+ping2class = {
+ True : "online",
+ False : "offline",
+}
+
+state2style = {
+ None : "",
+ "compiling" : "background: #8C8; border: 1px solid #0e0;",
+ "error" : "background: #c33; border: 1px solid #e00;",
+ "idle" : "height: 60px; background: #ddd; border: 1px solid #eee;",
+}
+++ /dev/null
-#!/usr/bin/python
-
-import cgitb, os, time, cgi, re, random, socket, DNS
-cgitb.enable()
-
-def print_http_header():
- print "Content-type: text/html"
- print
-
-def print_header():
- print_http_header()
- print '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
- <head>
- <title>IPFire - DistccWatch</title>
- <style type="text/css">
- body { font-family: Verdana; font-size: 9pt; background-color:#f0f0f0; }
- a:link { color: black; text-decoration: none; }
- a:visited { color: black; text-decoration: none; }
- table { font-family: Verdana; font-size: 8pt; border: 1px solid; }
- td.header { background-color: #a0a0a0; text-align: center; color: white; }
- td.date { text-align: center; }
- font.installed { color: green; }
- font.deleted { color: red; }
- font.update { color: blue; }
- font.error { color: red; }
- td.online { background: green; color: white; text-align: center; }
- td.offline { background: red; color: white; text-align: center; }
- </style>
- <meta http-equiv="refresh" content="60; URL=%s" />
- </head>
- <body>
- <h1>IPFire DistccWatch</h1>
- <p>Made: %s</p>''' % (os.environ['SCRIPT_NAME'], time.ctime())
-
-def print_footer():
- print "\t</body>\n</html>"
-
-def print_dcc_info():
- print "<pre>",
- print os.popen("distcc --version").read(),
- print "</pre>"
-
-def read_hosts():
- f = open("hosts")
- hosts = []
- while True:
- line = f.readline()
- if len(line) == 0:
- hosts.sort()
- return hosts
- break #EOF
-
- if not line.startswith("#"):
- hosts.append(line.rstrip("\n"))
-
-def process_hosts(hosts=""):
- if not hosts:
- print "You need to specify the hosts you want to check in the config file."
- return
-
- print '''<table width='66%'>
- <tr>
- <td class='header' width='68%'>Host</td>
- <td class='header' width='16%'>State</td>
- <td class='header' width='16%'>Probe</td>
- </tr>'''
-
- for hostname in hosts:
-
- state = "DOWN"
- time = " "
- command = "HOME=tmp DISTCC_HOSTS=\"%s\" DISTCC_VERBOSE=1 distcc probe.c -S -o /dev/null 2>&1" % hostname
- state_pattern = re.compile("on %s completed ok" % hostname)
- time_pattern = re.compile("elapsed compilation time ")
-
- for line in os.popen(command).readlines():
- state_result = re.search(state_pattern, line)
- time_result = re.search(time_pattern, line)
- if not state_result == None:
- state = "UP"
- if not time_result == None:
- if state == "UP":
- time = time_result.string[-10:]
-
- print "<tr><td><pre>%s</pre></td><td>%s</td><td>%s</td></tr>" % (hostname, state, time)
-
- print "</table>"
-
-def mixup_hosts(hosts=""):
- string = ""
- while True:
- if len(hosts) == 0:
- break
-
- rand = random.randint(0, len(hosts)-1)
- host, options = re.split(re.compile(':'),hosts[rand])
- string += socket.gethostbyname(host) + ":" + options + " "
- hosts.pop(rand)
-
- print string
-
-form = cgi.FieldStorage()
-action = form.getfirst('action')
-
-if action == "raw":
- print_http_header()
-
- hosts = read_hosts()
-
- mixup_hosts(hosts)
-
-else:
-
- print_header()
- print_dcc_info()
-
- hosts = read_hosts()
-
- process_hosts(hosts)
-
- print_footer()
+++ /dev/null
-#mirror1.ipfire.org:3632,lzo
-#mirror2.ipfire.org:3632,lzo
-#mirror3.ipfire.org:3632,lzo
-compiler02.ipfire.org:3630/10,lzo
-compiler02.ipfire.org:3631/10,lzo
--- /dev/null
+#!/usr/bin/python
+###############################################################################
+# #
+# IPFire.org - A linux based firewall #
+# Copyright (C) 2008 Michael Tremer & Christian Schmidt #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+###############################################################################
+
+import os
+import sys
+import time
+
+sys.path.append(".")
+
+from builder import Builder, getAllBuilders
+from constants import *
+
+def format_time(seconds, use_hours=1):
+ if seconds is None or seconds < 0:
+ if use_hours: return '--:--:--'
+ else: return '--:--'
+ else:
+ seconds = int(seconds)
+ minutes = seconds / 60
+ seconds = seconds % 60
+ if use_hours:
+ hours = minutes / 60
+ minutes = minutes % 60
+ return '%02i:%02i:%02i' % (hours, minutes, seconds)
+ else:
+ return '%02i:%02i' % (minutes, seconds)
+
+class Site:
+ def __init__(self, config):
+ self.builders = None
+ self.config = config
+ print "Content-type: text/html"
+ print
+
+ def __call__(self, builders=None):
+ self.builders = builders
+ print """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+ <head>
+ <title>%(title)s</title>
+ <style type="text/css">
+ * {
+ margin: auto;
+ padding: 0;
+ text-decoration: none;
+ outline: none;
+ }
+ body {
+ font-family: Verdana;
+ font-size: 90%%;
+ background-color:#f9f9f9;
+ }
+ h1 {
+ text-decoration: underline;
+ }
+ #header {
+ width: 800px;
+ height: 100px;
+ text-align: center;
+ background: #E0E0E0;
+ border: 1px solid #999;
+ padding-top: 10px;
+ }
+ #content {
+ padding-top: 10px;
+ width: 800px;
+ }
+ div.box {
+ padding: 5px;
+ margin: 10px 0 10px 0;
+ height: 80px;
+ border: 1px solid;
+ }
+ div.infobox {
+ float: right;
+ width: 240px;
+ }
+ p {
+ margin: 2px;
+ }
+ p.boxheader {
+ font-weight: bold;
+ }
+ p.online {
+ color: green;
+ }
+ p.offline {
+ color: red;
+ }
+ p.package {
+ font: bold;
+ font-size: 150%%;
+ }
+ img.right {
+ float: right;
+ }
+ p.desc {
+ text-decoration: bold;
+ }
+ a:link {
+ color: black; text-decoration: none;
+ }
+ a:visited {
+ color: black; text-decoration: none;
+ }
+ </style>
+ <meta http-equiv="refresh" content="90; URL=%(script)s" />
+ </head>
+ <body>
+ <div id="header">
+ <h1>IPFire Builder</h1>""" % self.config
+ if self.builders:
+ print """\
+ <p>
+ """,
+ for builder in self.builders:
+ print builder,
+ print """
+ </p>"""
+ for i in self.config["nightly_url"]:
+ print """\
+ <p><a href="%s" target="_blank">%s</a></p>""" % (i, i,)
+ print """\
+ </div>"""
+
+ self.content()
+
+ print "\t\t</body>\n</html>"
+
+ def content(self):
+ if self.builders:
+ count = 0
+ print """\
+ <div id="content">"""
+ for builder in self.builders:
+ builder(count)
+ count += 1
+ print """\
+ </div>"""
+
+class Box:
+ def __init__(self, builder):
+ self.builder = builder
+
+ def __call__(self, count):
+ print """\
+ <a name="%s"></a>
+ <div class="box" style="%s">"""\
+ % (self.builder.hostname(), state2style[self.builder.state()],)
+ print """\
+ <div class="infobox">"""
+ self.distccinfo()
+ self.package()
+ self.time()
+ print """\
+ </div>"""
+ self.header()
+ self.stateinfo()
+ self.durations()
+ print """\
+ </div>"""
+
+ def __str__(self):
+ return """<a href="#%(hostname)s">%(hostname)s</a>""" % { "hostname" : self.builder.hostname(), }
+
+ def header(self):
+ print """\
+ <p class="boxheader">
+ %(hostname)s <span>[%(uuid)s]</span>
+ </p>
+ <!-- <img class="right" src="/images/%(state)s.png" /> -->""" \
+ % { "hostname" : self.builder.hostname(),
+ "state" : self.builder.state(),
+ "uuid" : self.builder.uuid, }
+
+ def package(self):
+ if self.builder.state() in [ "compiling", "error", ]:
+ print """\
+ <p class="package">%s</p>"""\
+ % self.builder.package()
+
+ def time(self):
+ print """\
+ <p>%s</p>""" \
+ % time.ctime(float(self.builder.state.time()))
+
+ def stateinfo(self):
+ if self.builder.state() in [ "compiling", "error", "idle", ]:
+ print """\
+ <p class="desc">%s</p>""" \
+ % statedesc[self.builder.state()]
+
+ def durations(self):
+ print """\
+ <p>Average Build Duration: %s</p>""" \
+ % format_time(self.builder.duration.get_avg())
+ if self.builder.state() == "compiling":
+ print """\
+ <p>ETA: %s</p>""" \
+ % self.builder.duration.get_eta(self.builder.state.time())
+
+ def distccinfo(self):
+ state = self.builder.distcc.ping()
+ print """\
+ <p class="%s">Distcc: %s</p>""" \
+ % (ping2class[state], self.builder.distcc.get(),)
+
+site = Site(config)
+
+boxes = []
+for builder in getAllBuilders():
+ boxes.append(Box(builder))
+
+site(boxes)
+++ /dev/null
-int main () {
- return 0;
-}
--- /dev/null
+#!/usr/bin/python
+###############################################################################
+# #
+# IPFire.org - A linux based firewall #
+# Copyright (C) 2008 Michael Tremer & Christian Schmidt #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+###############################################################################
+
+import os
+import sys
+import cgi
+import time
+import random
+
+sys.path.append(".")
+
+from builder import Builder, getAllBuilders
+from constants import config
+
+class Response:
+ def __init__(self, config):
+ self.config = config
+
+ self.code = "200"
+ self.mesg = "OK"
+
+ def __call__(self, exit=0):
+ print "Status: %s" % self.code
+ print "Content-type: text/plain"
+ print
+ print "%s" % self.mesg
+ if exit:
+ os._exit(0)
+
+ def set_code(self, code):
+ self.code = code
+
+ def set_mesg(self, mesg):
+ self.mesg = mesg
+
+response = Response(config)
+
+data = cgi.FieldStorage()
+
+action = data.getvalue('action')
+if action == "set":
+ uuid = data.getfirst("uuid")
+ if not uuid:
+ response.set_code("406")
+ response.set_mesg("UUID is not valid!")
+ response(1)
+
+ builder = Builder(config, uuid)
+
+ key = None
+ for key in [ "distcc", "duration", "hostname", "state", "package", ]:
+ for value in data.getlist(key):
+ builder.set(key, value)
+elif action == "get":
+ for key in [ "distcc", ]:
+ if key == "distcc":
+ for value in data.getlist(key):
+ if value == "raw":
+ builders = []
+ for builder in getAllBuilders():
+ builders.append("%s" % builder.distcc)
+ string = ""
+ while True:
+ if not builders: break
+ rand = random.randint(0, len(builders)-1)
+ string += "%s\n" % builders[rand]
+ builders.pop(rand)
+ response.set_mesg(string)
+
+else:
+ response.set_code("501")
+ response.set_mesg("Don't know what to do with command \"%s\"" % action)
+ response(1)
+
+response()