]>
Commit | Line | Data |
---|---|---|
5470bdf1 MT |
1 | #!/usr/bin/python |
2 | ||
3 | import logging | |
4 | import os | |
93feb275 | 5 | import re |
5470bdf1 MT |
6 | import tornado.httpserver |
7 | import tornado.ioloop | |
8 | import tornado.locale | |
9 | import tornado.options | |
10 | import tornado.web | |
93feb275 | 11 | import unicodedata |
5470bdf1 | 12 | |
124a8404 | 13 | from . import base |
93feb275 | 14 | from . import ui_modules |
9068dba1 | 15 | |
5470bdf1 MT |
16 | BASEDIR = os.path.dirname(__file__) |
17 | ||
0d71ac64 MT |
18 | LATEST_VERSION = "2.0" |
19 | ||
a9bf3cbe | 20 | def word_wrap(s, width=45): |
7261a759 MT |
21 | paragraphs = s.split('\n') |
22 | lines = [] | |
23 | for paragraph in paragraphs: | |
24 | while len(paragraph) > width: | |
25 | pos = paragraph.rfind(' ', 0, width) | |
26 | if not pos: | |
27 | pos = width | |
28 | lines.append(paragraph[:pos]) | |
29 | paragraph = paragraph[pos:] | |
a9bf3cbe | 30 | lines.append(paragraph.lstrip()) |
7261a759 | 31 | return '\n'.join(lines) |
5470bdf1 | 32 | |
124a8404 | 33 | class BootBaseHandler(base.BaseHandler): |
37b5c0cf MT |
34 | @property |
35 | def arch(self): | |
36 | arch = self.get_argument("arch", "i386") | |
37 | if not arch in ("x86_64", "i586", "i386"): | |
38 | raise tornado.web.HTTPError(400, "Invalid architecture") | |
39 | ||
40 | if arch == "i386": | |
41 | arch = "i586" | |
42 | ||
43 | return arch | |
44 | ||
45 | @property | |
46 | def platform(self): | |
47 | platform = self.get_argument("platform", "pcbios") | |
48 | if not platform in ("pcbios", "efi"): | |
49 | raise tornado.web.HTTPError(400, "Invalid platform") | |
50 | ||
51 | return platform | |
5470bdf1 MT |
52 | |
53 | ||
8e2e1261 | 54 | class MenuGPXEHandler(BootBaseHandler): |
5470bdf1 MT |
55 | """ |
56 | menu.gpxe | |
57 | """ | |
58 | def get(self): | |
a69e87a1 MT |
59 | version = self.get_argument("version", None) |
60 | if not version or version < LATEST_VERSION: | |
61 | return self.serve_update() | |
98133910 MT |
62 | |
63 | # Deliver content | |
5470bdf1 MT |
64 | self.set_header("Content-Type", "text/plain") |
65 | self.write("#!gpxe\n") | |
e847f85c | 66 | |
37b5c0cf MT |
67 | self.write("set 209:string premenu.cfg?arch=%s&platform=%s\n" \ |
68 | % (self.arch, self.platform)) | |
453c817c | 69 | self.write("set 210:string http://boot.ipfire.org/\n") |
e847f85c MT |
70 | self.write("chain pxelinux.0\n") |
71 | ||
72 | def serve_update(self): | |
73 | self.set_header("Content-Type", "text/plain") | |
74 | self.write("#!gpxe\n") | |
75 | ||
76 | # Small warning | |
77 | self.write("echo\necho Your copy of gPXE/iPXE is too old. ") | |
78 | self.write("Upgrade to avoid seeing this every boot!\n") | |
79 | ||
e48a74ea | 80 | self.write("chain static/netboot/ipxe.kpxe\n") |
5470bdf1 | 81 | |
98133910 | 82 | |
37b5c0cf MT |
83 | class PremenuCfgHandler(BootBaseHandler): |
84 | def get(self): | |
85 | self.set_header("Content-Type", "text/plain") | |
86 | ||
87 | self.render("netboot/premenu.cfg", arch=self.arch, platform=self.platform) | |
88 | ||
5470bdf1 | 89 | |
8e2e1261 | 90 | class MenuCfgHandler(BootBaseHandler): |
53211b33 MT |
91 | class NightlyBuildReleaseDummy(object): |
92 | id = 100 | |
93 | name = "Nightly Build" | |
94 | sname = "nightly-build" | |
95 | ||
37b5c0cf MT |
96 | def supports_arch(self, arch): |
97 | return arch in ("i586", "x86_64") | |
98 | ||
99 | def supports_platform(self, platform): | |
100 | return platform == "pcbios" | |
101 | ||
102 | def netboot_kernel_url(self, arch, platform): | |
4383298a | 103 | return "http://boot.ipfire.org/nightly/next/latest/%s/images/vmlinuz" % arch |
37b5c0cf MT |
104 | |
105 | def netboot_initrd_url(self, arch, platform): | |
4383298a | 106 | return "http://boot.ipfire.org/nightly/next/latest/%s/images/instroot" % arch |
37b5c0cf MT |
107 | |
108 | def netboot_args(self, arch, platform): | |
66b066ae | 109 | return "installer.download-url=https://nightly.ipfire.org/next/latest/%s/images/installer.iso" % arch |
53211b33 MT |
110 | |
111 | def is_netboot_capable(self): | |
112 | return True | |
113 | ||
114 | nightly_build = NightlyBuildReleaseDummy() | |
115 | ||
5470bdf1 MT |
116 | def get(self): |
117 | self.set_header("Content-Type", "text/plain") | |
118 | ||
9068dba1 | 119 | latest_release = self.releases.get_latest() |
37b5c0cf MT |
120 | if latest_release and not latest_release.supports_arch(self.arch): |
121 | latest_release = None | |
122 | ||
123 | stable_releases = [r for r in self.releases.get_stable() | |
124 | if r.supports_arch(self.arch) and r.supports_platform(self.platform)] | |
9068dba1 MT |
125 | try: |
126 | stable_releases.remove(latest_release) | |
127 | except ValueError: | |
128 | pass | |
129 | ||
37b5c0cf MT |
130 | development_releases = [r for r in self.releases.get_unstable() |
131 | if r.supports_arch(self.arch) and r.supports_platform(self.platform)] | |
53211b33 | 132 | development_releases.insert(0, self.nightly_build) |
5470bdf1 | 133 | |
9068dba1 | 134 | self.render("netboot/menu.cfg", latest_release=latest_release, |
37b5c0cf MT |
135 | stable_releases=stable_releases, development_releases=development_releases, |
136 | arch=self.arch, platform=self.platform) | |
93feb275 MT |
137 | |
138 | ||
139 | class MenuConfigModule(ui_modules.UIModule): | |
140 | def render(self, release, arch=None, platform=None): | |
141 | return self.render_string("netboot/menu-config.cfg", release=release, | |
142 | arch=arch, platform=platform) | |
143 | ||
144 | ||
145 | class MenuHeaderModule(ui_modules.UIModule): | |
146 | def render(self, title, releases, arch=None, platform=None): | |
147 | # Remove any non-ASCII characters | |
148 | try: | |
149 | slug = unicodedata.normalize("NFKD", title) | |
150 | except TypeError: | |
151 | pass | |
152 | ||
153 | # Remove excessive whitespace | |
154 | slug = re.sub(r"[^\w]+", " ", slug) | |
155 | ||
156 | slug = "-".join(slug.split()).lower() | |
157 | ||
158 | return self.render_string("netboot/menu-header.cfg", slug=slug, | |
159 | title=title, releases=releases, arch=arch, platform=platform) | |
160 | ||
161 | ||
162 | class MenuSeparatorModule(ui_modules.UIModule): | |
163 | def render(self): | |
164 | return self.render_string("netboot/menu-separator.cfg") |