def configure_petitboot(fqdn, ko, basedir): """ Creates bootloader file for petitboot basedir/bootloader/<fqdn>petitboot.cfg """ config = """default Beaker scheduled job for %s label Beaker scheduled job for %s kernel ::/images/%s/kernel initrd ::/images/%s/initrd append %s netboot_method=petitboot """ % ( fqdn, fqdn, fqdn, fqdn, ko, ) if not basedir: basedir = get_tftp_root() petitboot_conf_dir = os.path.join(basedir, "bootloader", fqdn) makedirs_ignore(petitboot_conf_dir, mode=0755) logger.debug("Writing petitboot config for %s as %s", fqdn, os.path.join(petitboot_conf_dir, "petitboot.cfg")) with atomically_replaced_file(os.path.join(petitboot_conf_dir, "petitboot.cfg")) as f: f.write(config)
def configure_efigrub(fqdn, kernel_options): """ Creates bootloader file for EFI GRUB <get_tftp_root()>/grub/<pxe_basename(fqdn)> Also ensures images symlink exists: <get_tftp_root()>/grub/images -> <get_tftp_root()>/images """ grub_dir = os.path.join(get_tftp_root(), 'grub') makedirs_ignore(grub_dir, mode=0755) atomic_symlink('../images', os.path.join(grub_dir, 'images')) basename = pxe_basename(fqdn) initrd, kernel_options = extract_initrd_arg(kernel_options) if initrd: initrd = ' '.join(['/images/%s/initrd' % fqdn] + initrd.split(',')) else: initrd = '/images/%s/initrd' % fqdn config = '''default 0 timeout 10 title Beaker scheduled job for %s root (nd) kernel /images/%s/kernel %s netboot_method=efigrub initrd %s ''' % (fqdn, fqdn, kernel_options, initrd) logger.debug('Writing grub config for %s as %s', fqdn, basename) with atomically_replaced_file(os.path.join(grub_dir, basename)) as f: f.write(config)
def configure_efigrub(fqdn, kernel_options, basedir): """ Creates bootloader file for EFI GRUB <get_tftp_root()>/grub/<pxe_basename(fqdn)> Also ensures images symlink exists: <get_tftp_root()>/grub/images -> <get_tftp_root()>/images """ grub_dir = os.path.join(basedir, 'grub') makedirs_ignore(grub_dir, mode=0o755) atomic_symlink('../images', os.path.join(grub_dir, 'images')) basename = pxe_basename(fqdn) # Unfortunately the initrd kernel arg needs some special handling. It can be # supplied from the Beaker side (e.g. a system-specific driver disk) but we # also supply the main initrd here which we have fetched from the distro. initrd, kernel_options = extract_arg('initrd=', kernel_options) if initrd: initrd = ' '.join(['/images/%s/initrd' % fqdn] + initrd.split(',')) else: initrd = '/images/%s/initrd' % fqdn config = '''default 0 timeout 10 title Beaker scheduled job for %s root (nd) kernel /images/%s/kernel %s netboot_method=efigrub initrd %s ''' % (fqdn, fqdn, kernel_options, initrd) logger.debug('Writing grub config for %s as %s', fqdn, basename) with atomically_replaced_file(os.path.join(grub_dir, basename)) as f: f.write(config)
def configure_yaboot(fqdn, kernel_options, basedir, yaboot_symlink=True): """ Creates bootloader files for Yaboot <get_tftp_root()>/etc/<pxe_basename(fqdn).lower()> <get_tftp_root()>/ppc/<pxe_basename(fqdn).lower()> -> ../yaboot """ yaboot_conf_dir = os.path.join(basedir, 'etc') makedirs_ignore(yaboot_conf_dir, mode=0o755) basename = pxe_basename(fqdn).lower() # XXX I don't think multiple initrds are supported? config = '''init-message="Beaker scheduled job for %s" timeout=80 delay=10 default=linux image=/images/%s/kernel label=linux initrd=/images/%s/initrd append="%s netboot_method=yaboot" ''' % (fqdn, fqdn, fqdn, kernel_options) logger.debug('Writing yaboot config for %s as %s', fqdn, basename) with atomically_replaced_file(os.path.join(yaboot_conf_dir, basename)) as f: f.write(config) if yaboot_symlink: ppc_dir = os.path.join(basedir, 'ppc') makedirs_ignore(ppc_dir, mode=0o755) logger.debug('Creating yaboot symlink for %s as %s', fqdn, basename) atomic_symlink('../yaboot', os.path.join(ppc_dir, basename))
def fetch_images(distro_tree_id, kernel_url, initrd_url, fqdn): """ Creates references to kernel and initrd files at: <get_tftp_root()>/images/<fqdn>/kernel <get_tftp_root()>/images/<fqdn>/initrd """ images_dir = os.path.join(get_tftp_root(), 'images', fqdn) makedirs_ignore(images_dir, 0755) # Only look for fetched images if distro_tree is registered if distro_tree_id is not None: distrotree_dir = os.path.join(get_tftp_root(), 'distrotrees', str(distro_tree_id)) # beaker-pxemenu might have already fetched the images, so let's try there # before anywhere else. try: atomic_link(os.path.join(distrotree_dir, 'kernel'), os.path.join(images_dir, 'kernel')) atomic_link(os.path.join(distrotree_dir, 'initrd'), os.path.join(images_dir, 'initrd')) logger.debug('Using images from distro tree %s for %s', distro_tree_id, fqdn) return except OSError, e: if e.errno != errno.ENOENT: raise
def configure_pxelinux(fqdn, kernel_options, basedir, symlink=False): """ Creates PXE bootloader files for PXE Linux <get_tftp_root()>/pxelinux.cfg/<pxe_basename(fqdn)> Also ensures default (localboot) config exists: <get_tftp_root()>/pxelinux.cfg/default """ pxe_dir = os.path.join(basedir, 'pxelinux.cfg') makedirs_ignore(pxe_dir, mode=0o755) basename = pxe_basename(fqdn) initrd, kernel_options = extract_arg('initrd=', kernel_options) config = _configure_pxelinux_config(basedir, fqdn, initrd, kernel_options, symlink) logger.debug('Writing pxelinux config for %s as %s', fqdn, basename) with atomically_replaced_file(os.path.join(pxe_dir, basename)) as f: f.write(config) # We also ensure a default config exists that falls back to local boot write_ignore( os.path.join(pxe_dir, 'default'), '''default local prompt 0 timeout 0 label local localboot 0 ''')
def configure_zpxe(fqdn, kernel_url, initrd_url, kernel_options, basedir): """ Creates bootloader files for ZPXE <get_tftp_root()>/s390x/s_<fqdn> <get_tftp_root()>/s390x/s_<fqdn>_parm <get_tftp_root()>/s390x/s_<fqdn>_conf """ zpxe_dir = os.path.join(basedir, 's390x') makedirs_ignore(zpxe_dir, mode=0755) kernel_options = "%s netboot_method=zpxe" % kernel_options # The structure of these files is dictated by zpxe.rexx, # Cobbler's "pseudo-PXE" for zVM on s390(x). # XXX I don't think multiple initrds are supported? logger.debug('Writing zpxe index file for %s', fqdn) with atomically_replaced_file(os.path.join(zpxe_dir, 's_%s' % fqdn)) as f: if get_conf().get('ZPXE_USE_FTP', True): if not kernel_url.startswith('ftp://') or not initrd_url.startswith('ftp://'): raise ValueError('zPXE only supports FTP for downloading images') f.write('%s\n%s\n\n' % (kernel_url, initrd_url)) else: f.write('/images/%s/kernel\n/images/%s/initrd\n\n' % (fqdn, fqdn)) logger.debug('Writing zpxe parm file for %s', fqdn) with atomically_replaced_file(os.path.join(zpxe_dir, 's_%s_parm' % fqdn)) as f: # must be wrapped at 80 columns rest = kernel_options while rest: f.write(rest[:80] + '\n') rest = rest[80:] logger.debug('Writing zpxe conf file for %s', fqdn) with atomically_replaced_file(os.path.join(zpxe_dir, 's_%s_conf' % fqdn)) as f: pass # unused, but zpxe.rexx fetches it anyway
def configure_zpxe(fqdn, kernel_options, basedir): """ Creates bootloader files for ZPXE <get_tftp_root()>/s390x/s_<fqdn> <get_tftp_root()>/s390x/s_<fqdn>_parm <get_tftp_root()>/s390x/s_<fqdn>_conf """ zpxe_dir = os.path.join(basedir, 's390x') makedirs_ignore(zpxe_dir, mode=0755) kernel_options = "%s netboot_method=zpxe" % kernel_options # The structure of these files is dictated by zpxe.rexx, # Cobbler's "pseudo-PXE" for zVM on s390(x). # XXX I don't think multiple initrds are supported? logger.debug('Writing zpxe index file for %s', fqdn) with atomically_replaced_file(os.path.join(zpxe_dir, 's_%s' % fqdn)) as f: f.write('/images/%s/kernel\n/images/%s/initrd\n\n' % (fqdn, fqdn)) logger.debug('Writing zpxe parm file for %s', fqdn) with atomically_replaced_file(os.path.join(zpxe_dir, 's_%s_parm' % fqdn)) as f: # must be wrapped at 80 columns rest = kernel_options while rest: f.write(rest[:80] + '\n') rest = rest[80:] logger.debug('Writing zpxe conf file for %s', fqdn) with atomically_replaced_file(os.path.join(zpxe_dir, 's_%s_conf' % fqdn)) as f: pass # unused, but zpxe.rexx fetches it anyway
def _link_rpms(self, dst): """Hardlink the task rpms into dst""" makedirs_ignore(dst, 0755) for srcpath, name in self._all_rpms(): dstpath = os.path.join(dst, name) unlink_ignore(dstpath) os.link(srcpath, dstpath)
def configure_efigrub(fqdn, kernel_options, basedir): """ Creates bootloader file for EFI GRUB <get_tftp_root()>/grub/<pxe_basename(fqdn)> Also ensures images symlink exists: <get_tftp_root()>/grub/images -> <get_tftp_root()>/images """ grub_dir = os.path.join(basedir, 'grub') makedirs_ignore(grub_dir, mode=0755) atomic_symlink('../images', os.path.join(grub_dir, 'images')) basename = pxe_basename(fqdn) # Unfortunately the initrd kernel arg needs some special handling. It can be # supplied from the Beaker side (e.g. a system-specific driver disk) but we # also supply the main initrd here which we have fetched from the distro. initrd, kernel_options = extract_arg('initrd=', kernel_options) if initrd: initrd = ' '.join(['/images/%s/initrd' % fqdn] + initrd.split(',')) else: initrd = '/images/%s/initrd' % fqdn config = '''default 0 timeout 10 title Beaker scheduled job for %s root (nd) kernel /images/%s/kernel %s netboot_method=efigrub initrd %s ''' % (fqdn, fqdn, kernel_options, initrd) logger.debug('Writing grub config for %s as %s', fqdn, basename) with atomically_replaced_file(os.path.join(grub_dir, basename)) as f: f.write(config)
def configure_armlinux(fqdn, kernel_options, basedir): """ Creates PXE bootloader files for ARM Linux <get_tftp_root()>/arm/pxelinux.cfg/<pxe_basename(fqdn)> Also ensures empty config file exists: <get_tftp_root()>/arm/empty Specify filename "arm/empty"; in your dhcpd.conf file This is needed to set a path prefix of arm so that we don't conflict with x86 pxelinux.cfg files. """ pxe_base = os.path.join(basedir, 'arm') makedirs_ignore(pxe_base, mode=0o755) write_ignore(os.path.join(pxe_base, 'empty'), '') pxe_dir = os.path.join(pxe_base, 'pxelinux.cfg') makedirs_ignore(pxe_dir, mode=0o755) basename = pxe_basename(fqdn) config = '''default linux prompt 0 timeout 100 label linux kernel ../images/%s/kernel initrd ../images/%s/initrd append %s netboot_method=armpxe ''' % (fqdn, fqdn, kernel_options) logger.debug('Writing armlinux config for %s as %s', fqdn, basename) with atomically_replaced_file(os.path.join(pxe_dir, basename)) as f: f.write(config)
def configure_armlinux(fqdn, kernel_options): """ Creates PXE bootloader files for ARM Linux <get_tftp_root()>/arm/pxelinux.cfg/<pxe_basename(fqdn)> Also ensures empty config file exists: <get_tftp_root()>/arm/empty Specify filename "arm/empty"; in your dhcpd.conf file This is needed to set a path prefix of arm so that we don't conflict with x86 pxelinux.cfg files. """ pxe_base = os.path.join(get_tftp_root(), 'arm') makedirs_ignore(pxe_base, mode=0755) write_ignore(os.path.join(pxe_base, 'empty'), '') pxe_dir = os.path.join(pxe_base, 'pxelinux.cfg') makedirs_ignore(pxe_dir, mode=0755) basename = pxe_basename(fqdn) config = '''default linux prompt 0 timeout 100 label linux kernel ../images/%s/kernel initrd ../images/%s/initrd append %s netboot_method=armpxe ''' % (fqdn, fqdn, kernel_options) logger.debug('Writing armlinux config for %s as %s', fqdn, basename) with atomically_replaced_file(os.path.join(pxe_dir, basename)) as f: f.write(config)
def configure_x86_64(fqdn, kernel_options, basedir): """ Calls configure_grub2() to create the machine config files to GRUB2 boot loader. <get_tftp_root()>/x86_64/grub.cfg-<pxe_basename(fqdn)> <get_tftp_root()>/x86_64/grub.cfg <get_tftp_root()>/boot/grub2/grub.cfg-<pxe_basename(fqdn)> <get_tftp_root()>/boot/grub2/grub.cfg """ x86_64_dir = os.path.join(basedir, 'x86_64') makedirs_ignore(x86_64_dir, mode=0o755) grub2_conf = "grub.cfg-%s" % pxe_basename(fqdn) grub_cfg_file = os.path.join(x86_64_dir, grub2_conf) logger.debug('Writing grub2/x86_64 config for %s as %s', fqdn, grub_cfg_file) configure_grub2(fqdn, x86_64_dir, grub_cfg_file, kernel_options) # Location can be used as fallback # Mostly old GRUB2 relying on this location grub2_conf_dir = os.path.join(basedir, 'boot', 'grub2') makedirs_ignore(grub2_conf_dir, mode=0o755) grub_cfg_file = os.path.join(grub2_conf_dir, grub2_conf) logger.debug('Writing grub2/x86_64 config for %s as %s', fqdn, grub_cfg_file) configure_grub2(fqdn, grub2_conf_dir, grub_cfg_file, kernel_options)
def configure_zpxe(fqdn, kernel_options): """ Creates bootloader files for ZPXE <get_tftp_root()>/s390x/s_<fqdn> <get_tftp_root()>/s390x/s_<fqdn>_parm <get_tftp_root()>/s390x/s_<fqdn>_conf """ zpxe_dir = os.path.join(get_tftp_root(), 's390x') makedirs_ignore(zpxe_dir, mode=0755) kernel_options = "%s netboot_method=zpxe" % kernel_options # The structure of these files is dictated by zpxe.rexx, # Cobbler's "pseudo-PXE" for zVM on s390(x). # XXX I don't think multiple initrds are supported? logger.debug('Writing zpxe index file for %s', fqdn) with atomically_replaced_file(os.path.join(zpxe_dir, 's_%s' % fqdn)) as f: f.write('/images/%s/kernel\n/images/%s/initrd\n\n' % (fqdn, fqdn)) logger.debug('Writing zpxe parm file for %s', fqdn) with atomically_replaced_file(os.path.join(zpxe_dir, 's_%s_parm' % fqdn)) as f: # must be wrapped at 80 columns rest = kernel_options while rest: f.write(rest[:80] + '\n') rest = rest[80:] logger.debug('Writing zpxe conf file for %s', fqdn) with atomically_replaced_file(os.path.join(zpxe_dir, 's_%s_conf' % fqdn)) as f: pass # unused, but zpxe.rexx fetches it anyway
def configure_yaboot(fqdn, kernel_options): """ Creates bootloader files for Yaboot <get_tftp_root()>/etc/<pxe_basename(fqdn).lower()> <get_tftp_root()>/ppc/<pxe_basename(fqdn).lower()> -> ../yaboot """ yaboot_conf_dir = os.path.join(get_tftp_root(), 'etc') makedirs_ignore(yaboot_conf_dir, mode=0755) ppc_dir = os.path.join(get_tftp_root(), 'ppc') makedirs_ignore(ppc_dir, mode=0755) basename = pxe_basename(fqdn).lower() # XXX I don't think multiple initrds are supported? config = '''init-message="Beaker scheduled job for %s" timeout=80 delay=10 default=linux image=/images/%s/kernel label=linux initrd=/images/%s/initrd append="%s netboot_method=yaboot" ''' % (fqdn, fqdn, fqdn, kernel_options) logger.debug('Writing yaboot config for %s as %s', fqdn, basename) with atomically_replaced_file(os.path.join(yaboot_conf_dir, basename)) as f: f.write(config) logger.debug('Creating yaboot symlink for %s as %s', fqdn, basename) atomic_symlink('../yaboot', os.path.join(ppc_dir, basename))
def __enter__(self): makedirs_ignore(os.path.dirname(self.path), 0755) created = False if self.create: try: # stdio does not have any mode string which corresponds to this # combination of flags, so we have to use raw os.open :-( fd = os.open(self.path, os.O_RDWR | os.O_CREAT | os.O_EXCL, 0644) created = True except (OSError, IOError), e: if e.errno != errno.EEXIST: raise fd = os.open(self.path, os.O_RDWR)
def _get_images(tftp_root, distro_tree_id, url, images): dest_dir = os.path.join(tftp_root, 'distrotrees', str(distro_tree_id)) makedirs_ignore(dest_dir, mode=0o755) for image_type, path in images: if image_type in ('kernel', 'initrd'): dest_path = os.path.join(dest_dir, image_type) if os.path.isfile(dest_path): print('Skipping existing %s for distro tree %s' % (image_type, distro_tree_id)) else: image_url = urlparse.urljoin(url, path) print('Fetching %s %s for distro tree %s' % (image_type, image_url, distro_tree_id)) with atomically_replaced_file(dest_path) as dest: siphon(urllib2.urlopen(image_url), dest)
def _get_images(tftp_root, distro_tree_id, url, images): dest_dir = os.path.join(tftp_root, 'distrotrees', str(distro_tree_id)) makedirs_ignore(dest_dir, mode=0755) for image_type, path in images: if image_type in ('kernel', 'initrd'): dest_path = os.path.join(dest_dir, image_type) if os.path.isfile(dest_path): print 'Skipping existing %s for distro tree %s' % (image_type, distro_tree_id) else: image_url = urlparse.urljoin(url, path) print 'Fetching %s %s for distro tree %s' % (image_type, image_url, distro_tree_id) with atomically_replaced_file(dest_path) as dest: siphon(urllib2.urlopen(image_url), dest)
def test_doesnt_overwrite_existing_default_config(self): ipxe_dir = os.path.join(self.tftp_root, 'ipxe') makedirs_ignore(ipxe_dir, mode=0755) ipxe_default_path = os.path.join(ipxe_dir, 'default') # in reality it will probably be a menu custom = '''#!ipxe chain /ipxe/beaker_menu exit 1 ''' open(ipxe_default_path, 'wx').write(custom) netboot.configure_ipxe(TEST_FQDN, 'console=ttyS0,115200 ks=http://lol/', self.tftp_root) self.assertEquals(open(ipxe_default_path).read(), custom)
def configure_ppc64(fqdn, kernel_options): """ Calls configure_grub2() to create the machine config files and symlink to the grub2 boot loader: <get_tftp_root()>/ppc/grub.cfg-<pxe_basename(fqdn)> <get_tftp_root()>/ppc/grub.cfg <get_tftp_root()>/ppc/<pxe_basename(fqdn).lower()-grub2> -> ../boot/grub2/powerpc-ieee1275/core.elf # Hacks, see the note below <get_tftp_root()>grub.cfg-<pxe_basename(fqdn)> <get_tftp_root()>boot/grub2/grub.cfg-<pxe_basename(fqdn)> """ ppc_dir = os.path.join(get_tftp_root(), 'ppc') makedirs_ignore(ppc_dir, mode=0755) grub_cfg_file = os.path.join(ppc_dir, "grub.cfg-%s" % pxe_basename(fqdn)) logger.debug('Writing grub2/ppc64 config for %s as %s', fqdn, grub_cfg_file) configure_grub2(fqdn, ppc_dir, grub_cfg_file, kernel_options) # The following two hacks are to accommodate the differences in behavior # among various power configurations and grub2 versions # Remove them once they are sorted out (also see the relevant # code in clear_ppc64()) # Ref: https://bugzilla.redhat.com/show_bug.cgi?id=1144106 # hack for older grub grub2_conf_dir = os.path.join(get_tftp_root(), 'boot', 'grub2') makedirs_ignore(grub2_conf_dir, mode=0755) grub_cfg_file = os.path.join(grub2_conf_dir, "grub.cfg-%s" % pxe_basename(fqdn)) logger.debug('Writing grub2/ppc64 config for %s as %s', fqdn, grub_cfg_file) configure_grub2(fqdn, grub2_conf_dir, grub_cfg_file, kernel_options) # hack for power VMs grub_cfg_file = os.path.join(get_tftp_root(), "grub.cfg-%s" % pxe_basename(fqdn)) logger.debug('Writing grub2/ppc64 config for %s as %s', fqdn, grub_cfg_file) configure_grub2(fqdn, ppc_dir, grub_cfg_file, kernel_options) grub2_symlink = '%s-grub2' % pxe_basename(fqdn).lower() logger.debug('Creating grub2 symlink for %s as %s', fqdn, grub2_symlink) atomic_symlink('../boot/grub2/powerpc-ieee1275/core.elf', os.path.join(ppc_dir, grub2_symlink))
def configure_netbootloader_directory(fqdn, kernel_options, netbootloader): tftp_root = get_tftp_root() if netbootloader: fqdn_dir = os.path.join(tftp_root, 'bootloader', fqdn) logger.debug('Creating custom netbootloader tree for %s in %s', fqdn, fqdn_dir) makedirs_ignore(fqdn_dir, mode=0755) grub2_cfg_file = os.path.join(fqdn_dir, 'grub.cfg-%s'%pxe_basename(fqdn)) configure_grub2(fqdn, fqdn_dir, grub2_cfg_file, kernel_options) configure_pxelinux(fqdn, kernel_options, fqdn_dir) configure_yaboot(fqdn, kernel_options, fqdn_dir, yaboot_symlink=False) # create the symlink to the specified bootloader w.r.t the tftp_root if netbootloader.startswith('/'): netbootloader = netbootloader.lstrip('/') atomic_symlink(os.path.join('../../', netbootloader), os.path.join(fqdn_dir, 'image'))
def copy_default_loader_images(): """ Populates default boot loader images, where possible. Ultimately it is up to the administrator to make sure that their desired boot loader images are available and match their DHCP configuration. However we can copy in some common loader images to their default locations as a convenience. """ # We could also copy EFI GRUB, on RHEL6 it's located at /boot/efi/EFI/redhat/grub.efi # ... the problem is that is either the ia32 version or the x64 version # depending on the architecture of the server, blerg. makedirs_ignore(get_tftp_root(), mode=0755) copy_path_ignore(os.path.join(get_tftp_root(), "pxelinux.0"), "/usr/share/syslinux/pxelinux.0") copy_path_ignore(os.path.join(get_tftp_root(), "menu.c32"), "/usr/share/syslinux/menu.c32")
def test_doesnt_overwrite_existing_default_config(self): pxelinux_dir = os.path.join(self.tftp_root, "pxelinux.cfg") makedirs_ignore(pxelinux_dir, mode=0755) pxelinux_default_path = os.path.join(pxelinux_dir, "default") # in reality it will probably be a menu custom = """ default local prompt 10 timeout 200 label local localboot 0 label jabberwocky boot the thing""" open(pxelinux_default_path, "wx").write(custom) netboot.configure_pxelinux(TEST_FQDN, "console=ttyS0,115200 ks=http://lol/") self.assertEquals(open(pxelinux_default_path).read(), custom)
def configure_pxelinux(fqdn, kernel_options, basedir): """ Creates PXE bootloader files for PXE Linux <get_tftp_root()>/pxelinux.cfg/<pxe_basename(fqdn)> Also ensures default (localboot) config exists: <get_tftp_root()>/pxelinux.cfg/default """ pxe_dir = os.path.join(basedir, "pxelinux.cfg") makedirs_ignore(pxe_dir, mode=0755) basename = pxe_basename(fqdn) # Unfortunately the initrd kernel arg needs some special handling. It can be # supplied from the Beaker side (e.g. a system-specific driver disk) but we # also supply the main initrd here which we have fetched from the distro. initrd, kernel_options = extract_arg("initrd=", kernel_options) if initrd: initrd = "/images/%s/initrd,%s" % (fqdn, initrd) else: initrd = "/images/%s/initrd" % fqdn config = """default linux prompt 0 timeout 100 label linux kernel /images/%s/kernel ipappend 2 append initrd=%s %s netboot_method=pxe """ % ( fqdn, initrd, kernel_options, ) logger.debug("Writing pxelinux config for %s as %s", fqdn, basename) with atomically_replaced_file(os.path.join(pxe_dir, basename)) as f: f.write(config) # We also ensure a default config exists that falls back to local boot write_ignore( os.path.join(pxe_dir, "default"), """default local prompt 0 timeout 0 label local localboot 0 """, )
def copy_default_loader_images(): """ Populates default boot loader images, where possible. Ultimately it is up to the administrator to make sure that their desired boot loader images are available and match their DHCP configuration. However we can copy in some common loader images to their default locations as a convenience. """ # We could also copy EFI GRUB, on RHEL6 it's located at /boot/efi/EFI/redhat/grub.efi # ... the problem is that is either the ia32 version or the x64 version # depending on the architecture of the server, blerg. makedirs_ignore(get_tftp_root(), mode=0o755) copy_path_ignore(os.path.join(get_tftp_root(), 'pxelinux.0'), '/usr/share/syslinux/pxelinux.0') copy_path_ignore(os.path.join(get_tftp_root(), 'menu.c32'), '/usr/share/syslinux/menu.c32')
def configure_aarch64(fqdn, kernel_options, basedir): """ Creates PXE bootloader files for aarch64 Linux <get_tftp_root()>/aarch64/grub.cfg-<pxe_basename(fqdn)> """ pxe_base = os.path.join(basedir, 'aarch64') makedirs_ignore(pxe_base, mode=0755) devicetree, kernel_options = extract_arg('devicetree=', kernel_options) if devicetree: devicetree = 'devicetree %s' % devicetree else: devicetree = '' basename = "grub.cfg-%s" % pxe_basename(fqdn) logger.debug('Writing aarch64 config for %s as %s', fqdn, basename) grub_cfg_file = os.path.join(pxe_base, basename) configure_grub2(fqdn, pxe_base, grub_cfg_file, kernel_options, devicetree)
def configure_aarch64(fqdn, kernel_options, basedir): """ Creates PXE bootloader files for aarch64 Linux <get_tftp_root()>/aarch64/grub.cfg-<pxe_basename(fqdn)> """ pxe_base = os.path.join(basedir, 'aarch64') makedirs_ignore(pxe_base, mode=0o755) devicetree, kernel_options = extract_arg('devicetree=', kernel_options) if devicetree: devicetree = 'devicetree %s' % devicetree else: devicetree = '' basename = "grub.cfg-%s" % pxe_basename(fqdn) logger.debug('Writing aarch64 config for %s as %s', fqdn, basename) grub_cfg_file = os.path.join(pxe_base, basename) configure_grub2(fqdn, pxe_base, grub_cfg_file, kernel_options, devicetree)
def test_doesnt_overwrite_existing_default_config(self): pxelinux_dir = os.path.join(self.tftp_root, 'pxelinux.cfg') makedirs_ignore(pxelinux_dir, mode=0755) pxelinux_default_path = os.path.join(pxelinux_dir, 'default') # in reality it will probably be a menu custom = ''' default local prompt 10 timeout 200 label local localboot 0 label jabberwocky boot the thing''' open(pxelinux_default_path, 'wx').write(custom) netboot.configure_pxelinux(TEST_FQDN, 'console=ttyS0,115200 ks=http://lol/') self.assertEquals(open(pxelinux_default_path).read(), custom)
def configure_netbootloader_directory(fqdn, kernel_options, netbootloader): tftp_root = get_tftp_root() if netbootloader: fqdn_dir = os.path.join(tftp_root, 'bootloader', fqdn) logger.debug('Creating custom netbootloader tree for %s in %s', fqdn, fqdn_dir) makedirs_ignore(fqdn_dir, mode=0755) grub2_cfg_file = os.path.join(fqdn_dir, 'grub.cfg-%s' % pxe_basename(fqdn)) configure_grub2(fqdn, fqdn_dir, grub2_cfg_file, kernel_options) configure_pxelinux(fqdn, kernel_options, fqdn_dir) configure_yaboot(fqdn, kernel_options, fqdn_dir, yaboot_symlink=False) # create the symlink to the specified bootloader w.r.t the tftp_root if netbootloader.startswith('/'): netbootloader = netbootloader.lstrip('/') atomic_symlink(os.path.join('../../', netbootloader), os.path.join(fqdn_dir, 'image'))
def configure_ppc64(fqdn, kernel_options, basedir): """ Calls configure_grub2() to create the machine config files and symlink to the grub2 boot loader: <get_tftp_root()>/ppc/grub.cfg-<pxe_basename(fqdn)> <get_tftp_root()>/ppc/grub.cfg <get_tftp_root()>/ppc/<pxe_basename(fqdn).lower()-grub2> -> ../boot/grub2/powerpc-ieee1275/core.elf # Hacks, see the note below <get_tftp_root()>grub.cfg-<pxe_basename(fqdn)> <get_tftp_root()>boot/grub2/grub.cfg-<pxe_basename(fqdn)> """ ppc_dir = os.path.join(basedir, 'ppc') makedirs_ignore(ppc_dir, mode=0755) grub_cfg_file = os.path.join(ppc_dir, "grub.cfg-%s" % pxe_basename(fqdn)) logger.debug('Writing grub2/ppc64 config for %s as %s', fqdn, grub_cfg_file) configure_grub2(fqdn, ppc_dir, grub_cfg_file, kernel_options) # The following two hacks are to accommodate the differences in behavior # among various power configurations and grub2 versions # Remove them once they are sorted out (also see the relevant # code in clear_ppc64()) # Ref: https://bugzilla.redhat.com/show_bug.cgi?id=1144106 # hack for older grub grub2_conf_dir = os.path.join(basedir, 'boot', 'grub2') makedirs_ignore(grub2_conf_dir, mode=0755) grub_cfg_file = os.path.join(grub2_conf_dir, "grub.cfg-%s" % pxe_basename(fqdn)) logger.debug('Writing grub2/ppc64 config for %s as %s', fqdn, grub_cfg_file) configure_grub2(fqdn, grub2_conf_dir, grub_cfg_file, kernel_options) # hack for power VMs grub_cfg_file = os.path.join(basedir, "grub.cfg-%s" % pxe_basename(fqdn)) logger.debug('Writing grub2/ppc64 config for %s as %s', fqdn, grub_cfg_file) configure_grub2(fqdn, ppc_dir, grub_cfg_file, kernel_options) grub2_symlink = '%s-grub2' % pxe_basename(fqdn).lower() logger.debug('Creating grub2 symlink for %s as %s', fqdn, grub2_symlink) atomic_symlink('../boot/grub2/powerpc-ieee1275/core.elf', os.path.join(ppc_dir, grub2_symlink))
def configure_pxelinux(fqdn, kernel_options): """ Creates PXE bootloader files for PXE Linux <get_tftp_root()>/pxelinux.cfg/<pxe_basename(fqdn)> Also ensures default (localboot) config exists: <get_tftp_root()>/pxelinux.cfg/default """ pxe_dir = os.path.join(get_tftp_root(), "pxelinux.cfg") makedirs_ignore(pxe_dir, mode=0755) basename = pxe_basename(fqdn) initrd, kernel_options = extract_initrd_arg(kernel_options) if initrd: initrd = "/images/%s/initrd,%s" % (fqdn, initrd) else: initrd = "/images/%s/initrd" % fqdn config = """default linux prompt 0 timeout 100 label linux kernel /images/%s/kernel ipappend 2 append initrd=%s %s netboot_method=pxe """ % ( fqdn, initrd, kernel_options, ) logger.debug("Writing pxelinux config for %s as %s", fqdn, basename) with atomically_replaced_file(os.path.join(pxe_dir, basename)) as f: f.write(config) # We also ensure a default config exists that falls back to local boot write_ignore( os.path.join(pxe_dir, "default"), """default local prompt 0 timeout 0 label local localboot 0 """, )
def configure_petitboot(fqdn, ko): """ Creates bootloader file for petitboot <get_tftp_root()>/bootloader/<fqdn>petitboot.cfg """ config = '''default Beaker scheduled job for %s label Beaker scheduled job for %s kernel ::/images/%s/kernel initrd ::/images/%s/initrd append %s netboot_method=petitboot ''' % (fqdn, fqdn, fqdn, fqdn, ko) petitboot_conf_dir = os.path.join(get_tftp_root(), 'bootloader', fqdn) makedirs_ignore(petitboot_conf_dir, mode=0755) logger.debug('Writing petitboot config for %s as %s', fqdn, os.path.join(petitboot_conf_dir, 'petitboot.cfg')) with atomically_replaced_file( os.path.join(petitboot_conf_dir, 'petitboot.cfg')) as f: f.write(config)
def fetch_images(distro_tree_id, kernel_url, initrd_url, fqdn): """ Creates references to kernel and initrd files at: <get_tftp_root()>/images/<fqdn>/kernel <get_tftp_root()>/images/<fqdn>/initrd """ images_dir = os.path.join(get_tftp_root(), 'images', fqdn) makedirs_ignore(images_dir, 0o755) # Only look for fetched images if distro_tree is registered if distro_tree_id is not None: distrotree_dir = os.path.join(get_tftp_root(), 'distrotrees', str(distro_tree_id)) # beaker-pxemenu might have already fetched the images, so let's try there # before anywhere else. try: atomic_link(os.path.join(distrotree_dir, 'kernel'), os.path.join(images_dir, 'kernel')) atomic_link(os.path.join(distrotree_dir, 'initrd'), os.path.join(images_dir, 'initrd')) logger.debug('Using images from distro tree %s for %s', distro_tree_id, fqdn) return except OSError as e: if e.errno != errno.ENOENT: raise # No luck there, so try something else... timeout = get_conf().get('IMAGE_FETCH_TIMEOUT') logger.debug('Fetching kernel %s for %s', kernel_url, fqdn) with atomically_replaced_file(os.path.join(images_dir, 'kernel')) as dest: try: siphon(urllib2.urlopen(kernel_url, timeout=timeout), dest) except Exception as e: raise ImageFetchingError(kernel_url, distro_tree_id, e) logger.debug('Fetching initrd %s for %s', initrd_url, fqdn) with atomically_replaced_file(os.path.join(images_dir, 'initrd')) as dest: try: siphon(urllib2.urlopen(initrd_url, timeout=timeout), dest) except Exception as e: raise ImageFetchingError(initrd_url, distro_tree_id, e)
def configure_pxelinux(fqdn, kernel_options, basedir): """ Creates PXE bootloader files for PXE Linux <get_tftp_root()>/pxelinux.cfg/<pxe_basename(fqdn)> Also ensures default (localboot) config exists: <get_tftp_root()>/pxelinux.cfg/default """ pxe_dir = os.path.join(basedir, 'pxelinux.cfg') makedirs_ignore(pxe_dir, mode=0755) basename = pxe_basename(fqdn) # Unfortunately the initrd kernel arg needs some special handling. It can be # supplied from the Beaker side (e.g. a system-specific driver disk) but we # also supply the main initrd here which we have fetched from the distro. initrd, kernel_options = extract_arg('initrd=', kernel_options) if initrd: initrd = '/images/%s/initrd,%s' % (fqdn, initrd) else: initrd = '/images/%s/initrd' % fqdn config = '''default linux prompt 0 timeout 100 label linux kernel /images/%s/kernel ipappend 2 append initrd=%s %s netboot_method=pxe ''' % (fqdn, initrd, kernel_options) logger.debug('Writing pxelinux config for %s as %s', fqdn, basename) with atomically_replaced_file(os.path.join(pxe_dir, basename)) as f: f.write(config) # We also ensure a default config exists that falls back to local boot write_ignore( os.path.join(pxe_dir, 'default'), '''default local prompt 0 timeout 0 label local localboot 0 ''')
def fetch_images(distro_tree_id, kernel_url, initrd_url, fqdn): """ Creates references to kernel and initrd files at: <get_tftp_root()>/images/<fqdn>/kernel <get_tftp_root()>/images/<fqdn>/initrd """ images_dir = os.path.join(get_tftp_root(), "images", fqdn) makedirs_ignore(images_dir, 0755) distrotree_dir = os.path.join(get_tftp_root(), "distrotrees", str(distro_tree_id)) # beaker-pxemenu might have already fetched the images, so let's try there # before anywhere else. try: atomic_link(os.path.join(distrotree_dir, "kernel"), os.path.join(images_dir, "kernel")) atomic_link(os.path.join(distrotree_dir, "initrd"), os.path.join(images_dir, "initrd")) logger.debug("Using images from distro tree %s for %s", distro_tree_id, fqdn) return except OSError, e: if e.errno != errno.ENOENT: raise
def configure_zpxe(fqdn, kernel_url, initrd_url, kernel_options, basedir): """ Creates bootloader files for ZPXE <get_tftp_root()>/s390x/s_<fqdn> <get_tftp_root()>/s390x/s_<fqdn>_parm <get_tftp_root()>/s390x/s_<fqdn>_conf """ zpxe_dir = os.path.join(basedir, 's390x') makedirs_ignore(zpxe_dir, mode=0o755) kernel_options = "%s netboot_method=zpxe" % kernel_options # The structure of these files is dictated by zpxe.rexx, # Cobbler's "pseudo-PXE" for zVM on s390(x). # XXX I don't think multiple initrds are supported? logger.debug('Writing zpxe index file for %s', fqdn) with atomically_replaced_file(os.path.join(zpxe_dir, 's_%s' % fqdn)) as f: if get_conf().get('ZPXE_USE_FTP', True): if not kernel_url.startswith( 'ftp://') or not initrd_url.startswith('ftp://'): raise ValueError( 'zPXE only supports FTP for downloading images') f.write('%s\n%s\n\n' % (kernel_url, initrd_url)) else: f.write('/images/%s/kernel\n/images/%s/initrd\n\n' % (fqdn, fqdn)) logger.debug('Writing zpxe parm file for %s', fqdn) with atomically_replaced_file(os.path.join(zpxe_dir, 's_%s_parm' % fqdn)) as f: # must be wrapped at 80 columns rest = kernel_options while rest: f.write(rest[:80] + '\n') rest = rest[80:] logger.debug('Writing zpxe conf file for %s', fqdn) with atomically_replaced_file(os.path.join(zpxe_dir, 's_%s_conf' % fqdn)) as f: pass # unused, but zpxe.rexx fetches it anyway
def configure_ipxe(fqdn, kernel_options, basedir): """ Creates iPXE bootloader files <get_tftp_root()>/ipxe/<pxe_basename(fqdn).lower()> Also ensures default (localboot) config exists: <get_tftp_root()>/ipxe/default """ ipxe_dir = os.path.join(basedir, 'ipxe') makedirs_ignore(ipxe_dir, mode=0755) basename = pxe_basename(fqdn).lower() # Unfortunately the initrd kernel arg needs some special handling. It can be # supplied from the Beaker side (e.g. a system-specific driver disk) but we # also supply the main initrd here which we have fetched from the distro. initrd, kernel_options = extract_arg('initrd=', kernel_options) if initrd: initrd = '/images/%s/initrd\ninitrd %s' % (fqdn, initrd) else: initrd = '/images/%s/initrd' % fqdn config = '''#!ipxe kernel /images/%s/kernel initrd %s imgargs kernel initrd=initrd %s netboot_method=ipxe BOOTIF=01-${netX/mac:hexhyp} boot || exit 1 ''' % (fqdn, initrd, kernel_options) logger.debug('Writing ipxe config for %s as %s', fqdn, basename) with atomically_replaced_file(os.path.join(ipxe_dir, basename)) as f: f.write(config) # We also ensure a default config exists that falls back to local boot write_ignore( os.path.join(ipxe_dir, 'default'), '''#!ipxe iseq ${builtin/platform} pcbios && sanboot --no-describe --drive 0x80 || exit 1 ''')
def configure_aarch64(fqdn, kernel_options): """ Creates PXE bootloader files for aarch64 Linux <get_tftp_root()>/pxelinux/grub.cfg-<pxe_basename(fqdn)> Also ensures <fqdn>.efi is symlinked to bootaa64.efi Specify filename "pxelinux/<fqdn>.efi"; in your dhcpd.conf file We remove this when the install is done. This allows efi to fall through to the next boot entry. """ pxe_base = os.path.join(get_tftp_root(), 'pxelinux') makedirs_ignore(pxe_base, mode=0755) basename = "grub.cfg-%s" % pxe_basename(fqdn) config = ''' linux ../images/%s/kernel %s initrd ../images/%s/initrd devicetree /pxelinux/apm-mustang.dtb boot ''' % (fqdn, kernel_options, fqdn) logger.debug('Writing aarch64 config for %s as %s', fqdn, basename) with atomically_replaced_file(os.path.join(pxe_base, basename)) as f: f.write(config) atomic_symlink('bootaa64.efi', os.path.join(pxe_base, "%s.efi" % fqdn))
def setUpClass(cls): makedirs_ignore(get_conf().get('CONSOLE_LOGS'), 0755)
proxy = xmlrpclib.ServerProxy('http://localhost:8000', allow_none=True) distrotrees = proxy.get_distro_trees({ 'arch': ['x86_64', 'i386'], 'tags': opts.tags, 'xml': opts.xml_filter, }) obsolete_tree_ids = set(existing_tree_ids).difference( str(dt['distro_tree_id']) for dt in distrotrees) print 'Removing images for %s obsolete distro trees' % len(obsolete_tree_ids) for obs in obsolete_tree_ids: shutil.rmtree(os.path.join(opts.tftp_root, 'distrotrees', obs), ignore_errors=True) print 'Generating menu for %s distro trees' % len(distrotrees) osmajors = _group_distro_trees(distrotrees) makedirs_ignore(os.path.join(opts.tftp_root, 'pxelinux.cfg'), mode=0755) pxe_menu = atomically_replaced_file(os.path.join(opts.tftp_root, 'pxelinux.cfg', 'beaker_menu')) makedirs_ignore(os.path.join(opts.tftp_root, 'grub'), mode=0755) atomic_symlink('../distrotrees', os.path.join(opts.tftp_root, 'grub', 'distrotrees')) efi_menu = atomically_replaced_file(os.path.join(opts.tftp_root, 'grub', 'efidefault')) with contextlib.nested(pxe_menu, efi_menu) as (pxe_menu, efi_menu): pxe_menu.write('''default menu prompt 0 timeout 6000 ontimeout local menu title Beaker label local menu label (local) menu default localboot 0 ''')
'xml': xml_filter, }) current_tree_ids = set(str(dt['distro_tree_id']) for dt in distro_trees) obsolete_tree_ids = set(existing_tree_ids).difference(current_tree_ids) print 'Removing images for %s obsolete distro trees' % len(obsolete_tree_ids) for obs in obsolete_tree_ids: shutil.rmtree(os.path.join(tftp_root, 'distrotrees', obs), ignore_errors=True) # Fetch images for all the distro trees first. print 'Fetching images for all the distro trees' distro_trees = _get_all_images(tftp_root, distro_trees) x86_distrotrees = [distro for distro in distro_trees if distro['arch'] in ['x86_64', 'i386']] print 'Generating PXELINUX menus for %s distro trees' % len(x86_distrotrees) makedirs_ignore(os.path.join(tftp_root, 'pxelinux.cfg'), mode=0755) pxe_menu = atomically_replaced_file(os.path.join(tftp_root, 'pxelinux.cfg', 'beaker_menu')) write_menu(pxe_menu, u'pxelinux-menu', x86_distrotrees) print 'Generating EFI GRUB menus for %s distro trees' % len(x86_distrotrees) makedirs_ignore(os.path.join(tftp_root, 'grub'), mode=0755) atomic_symlink('../distrotrees', os.path.join(tftp_root, 'grub', 'distrotrees')) efi_grub_menu = atomically_replaced_file(os.path.join(tftp_root, 'grub', 'efidefault')) write_menu(efi_grub_menu, u'efi-grub-menu', x86_distrotrees) print 'Generating GRUB2 menus for x86 EFI for %s distro trees' % len(x86_distrotrees) makedirs_ignore(os.path.join(tftp_root, 'boot', 'grub2'), mode=0755) x86_grub2_menu = atomically_replaced_file(os.path.join(tftp_root, 'boot', 'grub2', 'beaker_menu_x86.cfg')) write_menu(x86_grub2_menu, u'grub2-menu', x86_distrotrees)
return except OSError, e: if e.errno != errno.ENOENT: raise # Okay, fall back to fetching... logger.debug("Fetching kernel %s for %s", kernel_url, fqdn) with atomically_replaced_file(os.path.join(images_dir, "kernel")) as dest: siphon(urllib2.urlopen(kernel_url), dest) logger.debug("Fetching initrd %s for %s", initrd_url, fqdn) with atomically_replaced_file(os.path.join(images_dir, "initrd")) as dest: siphon(urllib2.urlopen(initrd_url), dest) if get_conf().get("IMAGE_CACHE", False): logger.debug("Linking fetched images for %s to cache", fqdn) makedirs_ignore(cached_images_dir, 0755) try: # Do them in the opposite order to above atomic_link( os.path.join(images_dir, "initrd"), os.path.join(cached_images_dir, cached_filename(initrd_url)) ) atomic_link( os.path.join(images_dir, "kernel"), os.path.join(cached_images_dir, cached_filename(kernel_url)) ) except OSError, e: if e.errno != errno.EEXIST: raise clean_image_cache() def have_images(fqdn):
'xml': xml_filter, }) current_tree_ids = set(str(dt['distro_tree_id']) for dt in distro_trees) obsolete_tree_ids = set(existing_tree_ids).difference(current_tree_ids) print 'Removing images for %s obsolete distro trees' % len(obsolete_tree_ids) for obs in obsolete_tree_ids: shutil.rmtree(os.path.join(tftp_root, 'distrotrees', obs), ignore_errors=True) # Fetch images for all the distro trees first. print 'Fetching images for all the distro trees' distro_trees = _get_all_images(tftp_root, distro_trees) x86_distrotrees = [distro for distro in distro_trees if distro['arch'] in ['x86_64', 'i386']] print 'Generating PXELINUX menus for %s distro trees' % len(x86_distrotrees) makedirs_ignore(os.path.join(tftp_root, 'pxelinux.cfg'), mode=0755) pxe_menu = atomically_replaced_file(os.path.join(tftp_root, 'pxelinux.cfg', 'beaker_menu')) write_menu(pxe_menu, u'pxelinux-menu', x86_distrotrees) x86_efi_distrotrees = [distro for distro in distro_trees if distro['arch'] == 'x86_64'] # Regardless of any filtering options selected by the admin, we always # filter out certain distros which are known not to have EFI support. This # is a space saving measure for the EFI GRUB menu, which can't be nested so # we try to keep it as small possible. x86_efi_distrotrees = [distro for distro in x86_efi_distrotrees if not re.match(conf['EFI_EXCLUDED_OSMAJORS_REGEX'], distro['distro_osmajor'])] print 'Generating EFI GRUB menus for %s distro trees' % len(x86_efi_distrotrees) makedirs_ignore(os.path.join(tftp_root, 'grub'), mode=0755) atomic_symlink('../distrotrees', os.path.join(tftp_root, 'grub', 'distrotrees')) efi_grub_menu = atomically_replaced_file(os.path.join(tftp_root, 'grub', 'efidefault'))
def write_menus(tftp_root, tags, xml_filter): conf = get_conf() # The order of steps for cleaning images is important, # to avoid races and to avoid deleting stuff we shouldn't: # first read the directory, # then fetch the list of trees, # and then remove any which aren't in the list. try: existing_tree_ids = os.listdir(os.path.join(tftp_root, 'distrotrees')) except OSError as e: if e.errno != errno.ENOENT: raise existing_tree_ids = [] proxy = xmlrpclib.ServerProxy('http://localhost:8000', allow_none=True) distro_trees = proxy.get_distro_trees({ 'arch': ['x86_64', 'i386', 'aarch64', 'ppc64', 'ppc64le'], 'tags': tags, 'xml': xml_filter, }) current_tree_ids = set(str(dt['distro_tree_id']) for dt in distro_trees) obsolete_tree_ids = set(existing_tree_ids).difference(current_tree_ids) print('Removing images for %s obsolete distro trees' % len(obsolete_tree_ids)) for obs in obsolete_tree_ids: shutil.rmtree(os.path.join(tftp_root, 'distrotrees', obs), ignore_errors=True) # Fetch images for all the distro trees first. print('Fetching images for all the distro trees') distro_trees = _get_all_images(tftp_root, distro_trees) x86_distrotrees = [distro for distro in distro_trees if distro['arch'] in ['x86_64', 'i386']] print('Generating PXELINUX menus for %s distro trees' % len(x86_distrotrees)) makedirs_ignore(os.path.join(tftp_root, 'pxelinux.cfg'), mode=0o755) pxe_menu = atomically_replaced_file(os.path.join(tftp_root, 'pxelinux.cfg', 'beaker_menu')) write_menu(pxe_menu, u'pxelinux-menu', x86_distrotrees) x86_efi_distrotrees = [distro for distro in distro_trees if distro['arch'] == 'x86_64'] # Regardless of any filtering options selected by the admin, we always # filter out certain distros which are known not to have EFI support. This # is a space saving measure for the EFI GRUB menu, which can't be nested so # we try to keep it as small possible. x86_efi_distrotrees = [distro for distro in x86_efi_distrotrees if not re.match(conf['EFI_EXCLUDED_OSMAJORS_REGEX'], distro['distro_osmajor'])] print('Generating EFI GRUB menus for %s distro trees' % len(x86_efi_distrotrees)) makedirs_ignore(os.path.join(tftp_root, 'grub'), mode=0o755) atomic_symlink('../distrotrees', os.path.join(tftp_root, 'grub', 'distrotrees')) efi_grub_menu = atomically_replaced_file(os.path.join(tftp_root, 'grub', 'efidefault')) write_menu(efi_grub_menu, u'efi-grub-menu', x86_efi_distrotrees) print('Generating GRUB2 menus for x86 EFI for %s distro trees' % len(x86_efi_distrotrees)) makedirs_ignore(os.path.join(tftp_root, 'boot', 'grub2'), mode=0o755) x86_grub2_menu = atomically_replaced_file(os.path.join(tftp_root, 'boot', 'grub2', 'beaker_menu_x86.cfg')) write_menu(x86_grub2_menu, u'grub2-menu', x86_efi_distrotrees) ppc64_distrotrees = [distro for distro in distro_trees if distro['arch'] == 'ppc64'] if ppc64_distrotrees: print('Generating GRUB2 menus for PPC64 EFI for %s distro trees' % len(ppc64_distrotrees)) makedirs_ignore(os.path.join(tftp_root, 'boot', 'grub2'), mode=0o755) ppc64_grub2_menu = atomically_replaced_file(os.path.join(tftp_root, 'boot', 'grub2', 'beaker_menu_ppc64.cfg')) write_menu(ppc64_grub2_menu, u'grub2-menu', ppc64_distrotrees) ppc64le_distrotrees = [distro for distro in distro_trees if distro['arch'] == 'ppc64le'] if ppc64le_distrotrees: print('Generating GRUB2 menus for PPC64LE EFI for %s distro trees' % len(ppc64_distrotrees)) makedirs_ignore(os.path.join(tftp_root, 'boot', 'grub2'), mode=0o755) ppc64le_grub2_menu = atomically_replaced_file(os.path.join(tftp_root, 'boot', 'grub2', 'beaker_menu_ppc64le.cfg')) write_menu(ppc64le_grub2_menu, u'grub2-menu', ppc64le_distrotrees) # XXX: would be nice if we can find a good time to move this into boot/grub2 aarch64_distrotrees = [distro for distro in distro_trees if distro['arch'] == 'aarch64'] if aarch64_distrotrees: print('Generating GRUB2 menus for aarch64 for %s distro trees' % len(aarch64_distrotrees)) makedirs_ignore(os.path.join(tftp_root, 'aarch64'), mode=0o755) aarch64_menu = atomically_replaced_file( os.path.join(tftp_root, 'aarch64', 'beaker_menu.cfg')) write_menu(aarch64_menu, u'grub2-menu', aarch64_distrotrees)
def setUpClass(cls): makedirs_ignore(get_conf().get('CONSOLE_LOGS'), 0o755)