]> git.ipfire.org Git - people/shoehn/ipfire.org.git/blame - www/boot.py
Add netboot feature.
[people/shoehn/ipfire.org.git] / www / boot.py
CommitLineData
5470bdf1
MT
1#!/usr/bin/python
2
3import logging
4import os
5import tornado.httpserver
6import tornado.ioloop
7import tornado.locale
8import tornado.options
9import tornado.web
10
11from webapp import backend
12
13BASEDIR = os.path.dirname(__file__)
14
15# Enable logging
16tornado.options.enable_pretty_logging()
17tornado.options.parse_command_line()
18
19
20class BaseHandler(tornado.web.RequestHandler):
21 @property
22 def netboot(self):
23 return backend.NetBoot()
24
25
26class MenuGPXEHandler(BaseHandler):
27 """
28 menu.gpxe
29 """
30 def get(self):
31 # XXX Check if version of the bootloader is allright
32
33 # Devliver content
34 self.set_header("Content-Type", "text/plain")
35 self.write("#!gpxe\n")
36 self.write("chain menu.c32 premenu.cfg\n")
37
38
39class MenuCfgHandler(BaseHandler):
40 def _menu_string(self, menu, level=0):
41 s = ""
42
43 for entry in menu:
44 s += self._menu_entry(entry, level=level)
45
46 return s
47
48 def _menu_entry(self, entry, level=0):
49 lines = []
50
51 ident = "\t" * level
52
53 if entry.type == "seperator":
54 lines.append(ident + "menu seperator")
55 lines.append("")
56
57 elif entry.type == "header":
58 lines.append(ident + "menu begin %d" % entry.id)
59 lines.append(ident + "\tmenu title %s" % entry.title)
60
61 # Add "Back..." entry
62 lines.append(ident + "\tlabel %d.back" % entry.id)
63 lines.append(ident + "\t\tmenu label Back...")
64 lines.append(ident + "\t\tmenu exit")
65 lines.append(ident + "\tmenu seperator")
66
67 lines.append(ident + "%s" % self._menu_string(entry.submenu, level=level+1))
68 lines.append(ident + "menu end")
69 lines.append("")
70
71 elif entry.type == "config":
72 lines.append(ident + "label %d" % entry.id)
73 lines.append(ident + "\tmenu label %s" % entry.title)
74 if entry.description:
75 lines.append(ident + "\ttext help")
76 lines.append(entry.description)
77 lines.append(ident + "\tendtext")
78 lines.append(ident + "\tkernel /config/%s/boot.gpxe" % entry.item)
79 lines.append("")
80
81 return "\n".join(lines)
82
83 def get(self):
84 self.set_header("Content-Type", "text/plain")
85
86 menu = self._menu_string(self.netboot.get_menu(1))
87
88 self.render("menu.cfg", menu=menu)
89
90
91class BootGPXEHandler(BaseHandler):
92 def get(self, id):
93 config = self.netboot.get_config(id)
94 if not config:
95 raise tornado.web.HTTPError(404, "Configuration with ID '%s' was not found" % id)
96
97 lines = ["#!gpxe", "imgfree",]
98
99 line = "kernel -n img %s" % config.image1
100 if line.endswith(".iso"):
101 line += " iso"
102 lines.append(line)
103
104 if config.image2:
105 lines.append("initrd -n img %s" % config.image2)
106
107 lines.append("boot img")
108
109 for line in lines:
110 self.write("%s\n" % line)
111
112
113class Application(tornado.web.Application):
114 def __init__(self):
115 settings = dict(
116 debug = True,
117 gzip = True,
118 static_path = os.path.join(BASEDIR, "static/netboot"),
119 template_path = os.path.join(BASEDIR, "templates/netboot"),
120 )
121
122 tornado.web.Application.__init__(self, **settings)
123
124 self.add_handlers(r"boot.ipfire.org", [
125 # Configurations
126 (r"/files/menu.gpxe", MenuGPXEHandler),
127 (r"/files/menu.cfg", MenuCfgHandler),
128 (r"/config/([0-9]+)/boot.gpxe", BootGPXEHandler),
129
130 # Static files
131 (r"/files/(boot.png|premenu.cfg|vesamenu.c32|menu.c32)",
132 tornado.web.StaticFileHandler, { "path" : self.settings["static_path"] }),
133 ])
134
135 @property
136 def ioloop(self):
137 return tornado.ioloop.IOLoop.instance()
138
139 def shutdown(self, *args):
140 logging.debug("Caught shutdown signal")
141 self.ioloop.stop()
142
143 def run(self, port=8002):
144 logging.debug("Going to background")
145
146 # All requests should be done after 30 seconds or they will be killed.
147 self.ioloop.set_blocking_log_threshold(30)
148
149 http_server = tornado.httpserver.HTTPServer(self, xheaders=True)
150
151 # If we are not running in debug mode, we can actually run multiple
152 # frontends to get best performance out of our service.
153 if not self.settings["debug"]:
154 http_server.bind(port)
155 http_server.start(num_processes=4)
156 else:
157 http_server.listen(port)
158
159 self.ioloop.start()
160
161if __name__ == "__main__":
162 a = Application()
163
164 a.run()
165