]> git.ipfire.org Git - people/shoehn/ipfire.org.git/blobdiff - webapp/handlers_boot.py
netboot: Allow booting multiple architectures
[people/shoehn/ipfire.org.git] / webapp / handlers_boot.py
index 22acce5a5ad90f06ca354b8d9bff474dfbf713ec..bccf5865f3403f494eb6d5620aae13e729b391b7 100644 (file)
@@ -10,6 +10,8 @@ import tornado.web
 
 import backend
 
+from handlers_base import BaseHandler
+
 BASEDIR = os.path.dirname(__file__)
 
 def word_wrap(s, width=45):
@@ -25,10 +27,25 @@ def word_wrap(s, width=45):
                lines.append(paragraph.lstrip())
        return '\n'.join(lines)
 
-class BootBaseHandler(tornado.web.RequestHandler):
+class BootBaseHandler(BaseHandler):
+       @property
+       def arch(self):
+               arch = self.get_argument("arch", "i386")
+               if not arch in ("x86_64", "i586", "i386"):
+                       raise tornado.web.HTTPError(400, "Invalid architecture")
+
+               if arch == "i386":
+                       arch = "i586"
+
+               return arch
+
        @property
-       def netboot(self):
-               return backend.NetBoot()
+       def platform(self):
+               platform = self.get_argument("platform", "pcbios")
+               if not platform in ("pcbios", "efi"):
+                       raise tornado.web.HTTPError(400, "Invalid platform")
+
+               return platform
 
 
 class MenuGPXEHandler(BootBaseHandler):
@@ -36,82 +53,94 @@ class MenuGPXEHandler(BootBaseHandler):
                menu.gpxe
        """
        def get(self):
-               # XXX Check if version of the bootloader is allright
+               # Check if version of the bootloader is recent enough.
+               # Otherwise send the latest version of the PXE loader.
+               user_agent = self.request.headers.get("User-Agent", None)
+               if user_agent:
+                       try:
+                               client, version = user_agent.split("/")
+                       except:
+                               pass
+                       else:
+                               # We replaced gPXE by iPXE.
+                               if client == "gPXE":
+                                       return self.serve_update()
+
+                               # Everything under version 1.0.0 should be
+                               # updated.
+                               if version < "1.0.0":
+                                       return self.serve_update()
 
                # Devliver content
                self.set_header("Content-Type", "text/plain")
                self.write("#!gpxe\n")
-               self.write("chain menu.c32 premenu.cfg\n")
-
-
-class MenuCfgHandler(BootBaseHandler):
-       def _menu_string(self, menu, level=0):
-               s = ""
 
-               for entry in menu:
-                       s += self._menu_entry(entry, level=level)
+               self.write("set 209:string premenu.cfg?arch=%s&platform=%s\n" \
+                       % (self.arch, self.platform))
+               self.write("set 210:string http://boot.dev.ipfire.org/\n")
+               self.write("chain pxelinux.0\n")
 
-               return s
+       def serve_update(self):
+               self.set_header("Content-Type", "text/plain")
+               self.write("#!gpxe\n")
 
-       def _menu_entry(self, entry, level=0):
-               lines = []
+               # Small warning
+               self.write("echo\necho Your copy of gPXE/iPXE is too old. ")
+               self.write("Upgrade to avoid seeing this every boot!\n")
 
-               ident = "\t" * level
+               self.write("chain http://mirror0.ipfire.org/releases/ipfire-boot/latest/ipxe.kpxe\n")
 
-               if entry.type == "seperator":
-                       lines.append(ident + "menu separator")
+class PremenuCfgHandler(BootBaseHandler):
+       def get(self):
+               self.set_header("Content-Type", "text/plain")
 
-               elif entry.type == "header":
-                       lines.append(ident + "menu begin %d" % entry.id)
-                       lines.append(ident + "\tmenu title %s" % entry.title)
+               self.render("netboot/premenu.cfg", arch=self.arch, platform=self.platform)
 
-                       # Add "Back..." entry
-                       lines.append(ident + "\tlabel %d.back" % entry.id)
-                       lines.append(ident + "\t\tmenu label Back...")
-                       lines.append(ident + "\t\tmenu exit")
-                       lines.append(ident + "\tmenu separator")
 
-                       lines.append("%s" % self._menu_string(entry.submenu, level=level+1))
-                       lines.append(ident + "menu end")
+class MenuCfgHandler(BootBaseHandler):
+       class NightlyBuildReleaseDummy(object):
+               id = 100
+               name = "Nightly Build"
+               sname = "nightly-build"
 
-               elif entry.type == "config":
-                       lines.append(ident + "label %d" % entry.id)
-                       lines.append(ident + "\tmenu label %s" % entry.title)
-                       if entry.description:
-                               lines.append(ident + "\ttext help")
-                               lines.append(word_wrap(entry.description))
-                               lines.append(ident + "\tendtext")
-                       lines.append(ident + "\tkernel /config/%s/boot.gpxe" % entry.item)
+               def supports_arch(self, arch):
+                       return arch in ("i586", "x86_64")
 
-               return "\n".join(lines + [""])
+               def supports_platform(self, platform):
+                       return platform == "pcbios"
 
-       def get(self):
-               self.set_header("Content-Type", "text/plain")
+               def netboot_kernel_url(self, arch, platform):
+                       return "http://nightly.ipfire.org/next/latest/%s/images/vmlinuz" % arch
 
-               menu = self._menu_string(self.netboot.get_menu(1))
+               def netboot_initrd_url(self, arch, platform):
+                       return "http://nightly.ipfire.org/next/latest/%s/images/instroot" % arch
 
-               self.render("menu.cfg", menu=menu)
+               def netboot_args(self, arch, platform):
+                       return "installer.download-url=http://nightly.ipfire.org/next/latest/%s/images/installer.iso" % arch
 
+               def is_netboot_capable(self):
+                       return True
 
-class BootGPXEHandler(BootBaseHandler):
-       def get(self, id):
-               config = self.netboot.get_config(id)
-               if not config:
-                       raise tornado.web.HTTPError(404, "Configuration with ID '%s' was not found" % id)
+       nightly_build = NightlyBuildReleaseDummy()
 
-               lines = ["#!gpxe", "imgfree",]
+       def get(self):
+               self.set_header("Content-Type", "text/plain")
 
-               line = "kernel -n img %s" % config.image1
-               if line.endswith(".iso"):
-                       line += " iso"
-               if config.args:
-                       line += " %s" % config.args
-               lines.append(line)
+               latest_release = self.releases.get_latest()
+               if latest_release and not latest_release.supports_arch(self.arch):
+                       latest_release = None
 
-               if config.image2:
-                       lines.append("initrd -n img %s" % config.image2)
+               stable_releases = [r for r in self.releases.get_stable()
+                       if r.supports_arch(self.arch) and r.supports_platform(self.platform)]
+               try:
+                       stable_releases.remove(latest_release)
+               except ValueError:
+                       pass
 
-               lines.append("boot img")
+               development_releases = [r for r in self.releases.get_unstable()
+                       if r.supports_arch(self.arch) and r.supports_platform(self.platform)]
+               development_releases.insert(0, self.nightly_build)
 
-               for line in lines:
-                       self.write("%s\n" % line)
+               self.render("netboot/menu.cfg", latest_release=latest_release,
+                       stable_releases=stable_releases, development_releases=development_releases,
+                       arch=self.arch, platform=self.platform)