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 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 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_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_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_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 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_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))
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) # 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=0755) aarch64_menu = atomically_replaced_file(os.path.join(tftp_root, 'aarch64', 'beaker_menu.cfg'))
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)
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')) 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=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_efi_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=0755) aarch64_menu = atomically_replaced_file(os.path.join(tftp_root, 'aarch64', 'beaker_menu.cfg'))