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_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 _download(self, task_url): task_rpm_name = os.path.split(task_url)[1] rpm_file = os.path.join(self.task_dir, task_rpm_name) if not os.path.exists(rpm_file): try: with atomically_replaced_file(rpm_file) as f: siphon(urllib2.urlopen(task_url), f) f.flush() except urllib2.HTTPError as err: self.logger.critical(err) #unlink_ignore(rpm_file) except Exception as err: self.logger.critical(err) unlink_ignore(rpm_file) else: self.logger.debug('Downloaded %s' % task_rpm_name) self.tasks_added.append(task_rpm_name) self.t_downloaded = self.t_downloaded + 1 else: self.logger.debug('Already downloaded %s' % task_rpm_name) self.tasks_added.append(task_rpm_name) self.t_downloaded = self.t_downloaded + 1 return
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_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_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_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=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_grub2(fqdn, default_config_loc, config_file, kernel_options, devicetree=''): config = """\ linux /images/%s/kernel %s netboot_method=grub2 initrd /images/%s/initrd %s boot """ % (fqdn, kernel_options, fqdn, devicetree) with atomically_replaced_file(config_file) as f: f.write(config) # We also ensure a default config exists that exits write_ignore(os.path.join(default_config_loc, 'grub.cfg'), 'exit\n')
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 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 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 configure_elilo(fqdn, kernel_options, basedir): """ Creates bootloader file for ELILO <get_tftp_root()>/<pxe_basename(fqdn)>.conf """ basename = '%s.conf' % pxe_basename(fqdn) # XXX I don't think multiple initrds are supported? config = '''relocatable image=/images/%s/kernel label=netinstall append="%s netboot_method=elilo" initrd=/images/%s/initrd read-only root=/dev/ram ''' % (fqdn, kernel_options, fqdn) logger.debug('Writing elilo config for %s as %s', fqdn, basename) with atomically_replaced_file(os.path.join(basedir, basename)) as f: f.write(config)
def configure_elilo(fqdn, kernel_options): """ Creates bootloader file for ELILO <get_tftp_root()>/<pxe_basename(fqdn)>.conf """ basename = '%s.conf' % pxe_basename(fqdn) # XXX I don't think multiple initrds are supported? config = '''relocatable image=/images/%s/kernel label=netinstall append="%s netboot_method=elilo" initrd=/images/%s/initrd read-only root=/dev/ram ''' % (fqdn, kernel_options, fqdn) logger.debug('Writing elilo config for %s as %s', fqdn, basename) with atomically_replaced_file(os.path.join(get_tftp_root(), basename)) as f: f.write(config)
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 clear_zpxe(fqdn, basedir): """ If this system is configured for zpxe, reconfigures for local boot Kept (set to 'local'): <get_tftp_root()>/s390x/s_<fqdn> Removed: <get_tftp_root()>/s390x/s_<fqdn>_parm Removed: <get_tftp_root()>/s390x/s_<fqdn>_conf """ zpxe_dir = os.path.join(basedir, 's390x') configname = os.path.join(zpxe_dir, 's_%s' % fqdn) if not os.path.exists(configname): # Don't create a default zpxe config if we didn't create # a zpxe config for this system return logger.debug('Writing "local" zpxe index file for %s', fqdn) with atomically_replaced_file(configname) as f: f.write('local\n') # XXX or should we just delete it?? logger.debug('Removing zpxe parm file for %s', fqdn) unlink_ignore(os.path.join(zpxe_dir, 's_%s_parm' % fqdn)) logger.debug('Removing zpxe conf file for %s', fqdn) unlink_ignore(os.path.join(zpxe_dir, 's_%s_conf' % fqdn))
def clear_zpxe(fqdn): """ If this system is configured for zpxe, reconfigures for local boot Kept (set to 'local'): <get_tftp_root()>/s390x/s_<fqdn> Removed: <get_tftp_root()>/s390x/s_<fqdn>_parm Removed: <get_tftp_root()>/s390x/s_<fqdn>_conf """ zpxe_dir = os.path.join(get_tftp_root(), 's390x') configname = os.path.join(zpxe_dir, 's_%s' % fqdn) if not os.path.exists(configname): # Don't create a default zpxe config if we didn't create # a zpxe config for this system return logger.debug('Writing "local" zpxe index file for %s', fqdn) with atomically_replaced_file(configname) as f: f.write('local\n') # XXX or should we just delete it?? logger.debug('Removing zpxe parm file for %s', fqdn) unlink_ignore(os.path.join(zpxe_dir, 's_%s_parm' % fqdn)) logger.debug('Removing zpxe conf file for %s', fqdn) unlink_ignore(os.path.join(zpxe_dir, 's_%s_conf' % fqdn))
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 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)
}) 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) # XXX: would be nice if we can find a good time to move this into boot/grub2
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 ''')
try: atomic_link( os.path.join(cached_images_dir, cached_filename(kernel_url)), os.path.join(images_dir, "kernel") ) atomic_link( os.path.join(cached_images_dir, cached_filename(initrd_url)), os.path.join(images_dir, "initrd") ) logger.debug("Using cached images for %s", fqdn) 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))
# 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 # No luck there, so try something else... 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) def have_images(fqdn): return os.path.exists(os.path.join(get_tftp_root(), 'images', fqdn)) def clear_images(fqdn): """Removes kernel and initrd images """ images_dir = os.path.join(get_tftp_root(), 'images', fqdn) logger.debug('Removing images for %s', fqdn) shutil.rmtree(images_dir, ignore_errors=True) def pxe_basename(fqdn):
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 # 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 have_images(fqdn): return os.path.exists(os.path.join(get_tftp_root(), 'images', fqdn))
}) 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')) write_menu(efi_grub_menu, u'efi-grub-menu', x86_efi_distrotrees)