def remove_single_system(self, name): bootloc = utils.tftpboot_location() system_record = self.systems.find(name=name) # delete contents of kickstarts_sys/$name in webdir system_record = self.systems.find(name=name) if self.settings.manage_dhcp: if self.settings.omapi_enabled: for (name,interface) in system_record.interfaces.iteritems(): self.sync.dhcp.remove_dhcp_lease( self.settings.omapi_port, interface["dns_name"] ) itanic = False profile = self.profiles.find(name=system_record.profile) if profile is not None: distro = self.distros.find(name=profile.distro) if distro is not None and distro in [ "ia64", "IA64"]: itanic = True for (name,interface) in system_record.interfaces.iteritems(): filename = utils.get_config_filename(system_record,interface=name) if not itanic: utils.rmfile(os.path.join(bootloc, "pxelinux.cfg", filename)) else: utils.rmfile(os.path.join(bootloc, filename))
def remove_single_system(self, name): bootloc = utils.tftpboot_location() system_record = self.systems.find(name=name) # delete contents of kickstarts_sys/$name in webdir system_record = self.systems.find(name=name) for (name, interface) in system_record.interfaces.iteritems(): filename = utils.get_config_filename(system_record, interface=name) utils.rmfile(os.path.join(bootloc, "pxelinux.cfg", filename)) utils.rmfile(os.path.join(bootloc, "grub", filename.upper()))
def main(): args = get_cli_arguments() config = get_config(args.config) app = get_app(config) @app.route('/upload/', methods=['POST']) def upload(): if 'client' in config and 'user' in config[ "client"] and 'pass' in config["client"]: auth_control = check_auth(config) if auth_control: return auth_control _file = request.files.get("file") if not _file: return "a file named as 'file' required", 400 if not allowed_file(_file.filename, config): return "invalid file type", 400 filename = secure_filename(_file.filename) full_filename = os.path.join(app.config['UPLOAD_FOLDER'], filename) try: full_filename = get_available_filename(full_filename) except ValueError as error: return error.message, 400 _file.save(full_filename) return os.path.split(full_filename)[1], 201 app.debug = True with indent(2): puts("{} starting at {}:{}".format(colored.magenta("server"), config.get("HOST"), config.get("PORT"))) puts("{} {}".format(colored.green("config"), get_config_filename(args.config))) http_server = WSGIServer(('', int(config.get("PORT"))), app) http_server.serve_forever()
def main(): args = get_cli_arguments() config = get_config(args.config) app = get_app(config) @app.route('/upload/', methods=['POST']) def upload(): if 'client' in config and 'user' in config["client"] and 'pass' in config["client"]: auth_control = check_auth(config) if auth_control: return auth_control _file = request.files.get("file") if not _file: return "a file named as 'file' required", 400 if not allowed_file(_file.filename, config): return "invalid file type", 400 filename = secure_filename(_file.filename) full_filename = os.path.join(app.config['UPLOAD_FOLDER'], filename) try: full_filename = get_available_filename(full_filename) except ValueError as error: return error.message, 400 _file.save(full_filename) return os.path.split(full_filename)[1], 201 app.debug = True with indent(2): puts("{} starting at {}:{}".format(colored.magenta("server"), config.get("HOST"), config.get("PORT"))) puts("{} {}".format(colored.green("config"), get_config_filename(args.config))) http_server = WSGIServer(('', int(config.get("PORT"))), app) http_server.serve_forever()
def remove_single_system(self, name): bootloc = utils.tftpboot_location() system_record = self.systems.find(name=name) # delete contents of kickstarts_sys/$name in webdir system_record = self.systems.find(name=name) itanic = False profile = self.profiles.find(name=system_record.profile) if profile is not None: distro = self.distros.find(name=profile.get_conceptual_parent().name) if distro is not None and distro in [ "ia64", "IA64"]: itanic = True for (name,interface) in system_record.interfaces.iteritems(): filename = utils.get_config_filename(system_record,interface=name) if not itanic: utils.rmfile(os.path.join(bootloc, "pxelinux.cfg", filename)) else: utils.rmfile(os.path.join(bootloc, filename))
def remove_single_system(self, name): bootloc = utils.tftpboot_location() system_record = self.systems.find(name=name) # delete contents of kickstarts_sys/$name in webdir system_record = self.systems.find(name=name) itanic = False profile = self.profiles.find(name=system_record.profile) if profile is not None: distro = self.distros.find(name=profile.get_conceptual_parent().name) if distro is not None and distro in [ "ia64", "IA64"]: itanic = True for (name,interface) in system_record.interfaces.iteritems(): filename = utils.get_config_filename(system_record,interface=name) if not itanic: utils.rmfile(os.path.join(bootloc, "pxelinux.cfg", filename)) utils.rmfile(os.path.join(bootloc, "grub", filename.upper())) else: utils.rmfile(os.path.join(bootloc, filename))
def write_pxe_file(self, filename, system, profile, distro, arch, image=None, include_header=True, metadata=None, format="pxe"): """ Write a configuration file for the boot loader(s). More system-specific configuration may come in later, if so that would appear inside the system object in api.py NOTE: relevant to tftp and pseudo-PXE (s390) only ia64 is mostly the same as syslinux stuff, s390 is a bit short-circuited and simpler. All of it goes through the templating engine, see the templates in /etc/cobbler for more details Can be used for different formats, "pxe" (default) and "grub". """ if arch is None: raise "missing arch" if image and not os.path.exists(image.file): return None # nfs:// URLs or something, can't use for TFTP if metadata is None: metadata = {} (rval,settings) = utils.input_string_or_hash(self.settings.to_datastruct()) if rval: for key in settings.keys(): metadata[key] = settings[key] # --- # just some random variables template = None buffer = "" # --- kickstart_path = None kernel_path = None initrd_path = None img_path = None if image is None: # not image based, it's something normalish img_path = os.path.join("/images",distro.name) kernel_path = os.path.join("/images",distro.name,os.path.basename(distro.kernel)) initrd_path = os.path.join("/images",distro.name,os.path.basename(distro.initrd)) # Find the kickstart if we inherit from another profile if system: blended = utils.blender(self.api, True, system) else: blended = utils.blender(self.api, True, profile) kickstart_path = blended.get("kickstart","") else: # this is an image we are making available, not kernel+initrd if image.image_type == "direct": kernel_path = os.path.join("/images2",image.name) elif image.image_type == "memdisk": kernel_path = "/memdisk" initrd_path = os.path.join("/images2",image.name) else: # CD-ROM ISO or virt-clone image? We can't PXE boot it. kernel_path = None initrd_path = None if img_path is not None and not metadata.has_key("img_path"): metadata["img_path"] = img_path if kernel_path is not None and not metadata.has_key("kernel_path"): metadata["kernel_path"] = kernel_path if initrd_path is not None and not metadata.has_key("initrd_path"): metadata["initrd_path"] = initrd_path # --- # choose a template if system: if format == "grub": template = os.path.join(self.settings.pxe_template_dir, "grubsystem.template") else: # pxe if system.netboot_enabled: template = os.path.join(self.settings.pxe_template_dir,"pxesystem.template") if arch.startswith("s390"): template = os.path.join(self.settings.pxe_template_dir,"pxesystem_s390x.template") elif arch == "ia64": template = os.path.join(self.settings.pxe_template_dir,"pxesystem_ia64.template") elif arch.startswith("ppc"): template = os.path.join(self.settings.pxe_template_dir,"pxesystem_ppc.template") elif arch.startswith("arm"): template = os.path.join(self.settings.pxe_template_dir,"pxesystem_arm.template") elif distro and distro.os_version.startswith("esxi"): # ESXi uses a very different pxe method, using more files than # a standard kickstart and different options - so giving it a dedicated # PXE template makes more sense than shoe-horning it into the existing # templates template = os.path.join(self.settings.pxe_template_dir,"pxesystem_esxi.template") else: # local booting on ppc requires removing the system-specific dhcpd.conf filename if arch is not None and arch.startswith("ppc"): # Disable yaboot network booting for all interfaces on the system for (name,interface) in system.interfaces.iteritems(): filename = "%s" % utils.get_config_filename(system, interface=name).lower() # Remove symlink to the yaboot binary f3 = os.path.join(self.bootloc, "ppc", filename) if os.path.lexists(f3): utils.rmfile(f3) # Remove the interface-specific config file f3 = os.path.join(self.bootloc, "etc", filename) if os.path.lexists(f3): utils.rmfile(f3) # Yaboot/OF doesn't support booting locally once you've # booted off the network, so nothing left to do return None elif arch is not None and arch.startswith("s390"): template = os.path.join(self.settings.pxe_template_dir,"pxelocal_s390x.template") elif arch is not None and arch.startswith("ia64"): template = os.path.join(self.settings.pxe_template_dir,"pxelocal_ia64.template") else: template = os.path.join(self.settings.pxe_template_dir,"pxelocal.template") else: # not a system record, so this is a profile record or an image if arch.startswith("s390"): template = os.path.join(self.settings.pxe_template_dir,"pxeprofile_s390x.template") if arch.startswith("arm"): template = os.path.join(self.settings.pxe_template_dir,"pxeprofile_arm.template") elif format == "grub": template = os.path.join(self.settings.pxe_template_dir,"grubprofile.template") elif distro and distro.os_version.startswith("esxi"): # ESXi uses a very different pxe method, see comment above in the system section template = os.path.join(self.settings.pxe_template_dir,"pxeprofile_esxi.template") else: template = os.path.join(self.settings.pxe_template_dir,"pxeprofile.template") if kernel_path is not None: metadata["kernel_path"] = kernel_path if initrd_path is not None: metadata["initrd_path"] = initrd_path # generate the kernel options and append line: kernel_options = self.build_kernel_options(system, profile, distro, image, arch, kickstart_path) metadata["kernel_options"] = kernel_options if distro and distro.os_version.startswith("esxi") and filename is not None: append_line = "BOOTIF=%s" % (os.path.basename(filename)) elif metadata.has_key("initrd_path") and (not arch or arch not in ["ia64", "ppc", "ppc64", "arm"]): append_line = "append initrd=%s" % (metadata["initrd_path"]) else: append_line = "append " append_line = "%s%s" % (append_line, kernel_options) if arch.startswith("ppc") or arch.startswith("s390"): # remove the prefix "append" # TODO: this looks like it's removing more than append, really # not sure what's up here... append_line = append_line[7:] metadata["append_line"] = append_line # store variables for templating metadata["menu_label"] = "" if profile: if not arch in [ "ia64", "ppc", "ppc64", "s390", "s390x" ]: metadata["menu_label"] = "MENU LABEL %s" % profile.name metadata["profile_name"] = profile.name elif image: metadata["menu_label"] = "MENU LABEL %s" % image.name metadata["profile_name"] = image.name if system: metadata["system_name"] = system.name # get the template if kernel_path is not None: template_fh = open(template) template_data = template_fh.read() template_fh.close() else: # this is something we can't PXE boot template_data = "\n" # save file and/or return results, depending on how called. buffer = self.templar.render(template_data, metadata, None) if filename is not None: self.logger.info("generating: %s" % filename) fd = open(filename, "w") fd.write(buffer) fd.close() return buffer
def write_all_system_files(self, system): profile = system.get_conceptual_parent() if profile is None: raise CX("system %(system)s references a missing profile %(profile)s" % { "system" : system.name, "profile" : system.profile}) distro = profile.get_conceptual_parent() image_based = False image = None if distro is None: if profile.COLLECTION_TYPE == "profile": raise CX("profile %(profile)s references a missing distro %(distro)s" % { "profile" : system.profile, "distro" : profile.distro}) else: image_based = True image = profile # hack: s390 generates files per system not per interface if not image_based and distro.arch.startswith("s390"): # Always write a system specific _conf and _parm file f2 = os.path.join(self.bootloc, "s390x", "s_%s" % system.name) cf = "%s_conf" % f2 pf = "%s_parm" % f2 template_cf = open("/etc/cobbler/pxe/s390x_conf.template") template_pf = open("/etc/cobbler/pxe/s390x_parm.template") blended = utils.blender(self.api, True, system) self.templar.render(template_cf, blended, cf) # FIXME: profiles also need this data! # FIXME: the _conf and _parm files are limited to 80 characters in length try: ipaddress = socket.gethostbyname_ex(blended["http_server"])[2][0] except socket.gaierror: ipaddress = blended["http_server"] kickstart_path = "http://%s/cblr/svc/op/ks/system/%s" % (ipaddress, system.name) # gather default kernel_options and default kernel_options_s390x kopts = blended.get("kernel_options","") hkopts = shlex.split(utils.hash_to_string(kopts)) blended["kickstart_expanded"] = "ks=%s" % kickstart_path blended["kernel_options"] = hkopts self.templar.render(template_pf, blended, pf) # Write system specific zPXE file if system.is_management_supported(): self.write_pxe_file(f2, system, profile, distro, distro.arch) else: # ensure the file doesn't exist utils.rmfile(f2) return pxe_metadata = {'pxe_menu_items': self.get_menu_items()['pxe'] } # generate one record for each described NIC .. for (name,interface) in system.interfaces.iteritems(): ip = interface["ip_address"] f1 = utils.get_config_filename(system, interface=name) if f1 is None: self.logger.warning("invalid interface recorded for system (%s,%s)" % (system.name,name)) continue; if image_based: working_arch = image.arch else: working_arch = distro.arch if working_arch is None: raise "internal error, invalid arch supplied" # for tftp only ... grub_path = None if working_arch in [ "i386", "x86", "x86_64", "arm", "standard"]: # pxelinux wants a file named $name under pxelinux.cfg f2 = os.path.join(self.bootloc, "pxelinux.cfg", f1) # Only generating grub menus for these arch's: grub_path = os.path.join(self.bootloc, "grub", f1.upper()) elif working_arch == "ia64": # elilo expects files to be named "$name.conf" in the root # and can not do files based on the MAC address if ip is not None and ip != "": self.logger.warning("Warning: Itanium system object (%s) needs an IP address to PXE" % system.name) filename = "%s.conf" % utils.get_config_filename(system,interface=name) f2 = os.path.join(self.bootloc, filename) elif working_arch.startswith("ppc"): # Determine filename for system-specific yaboot.conf filename = "%s" % utils.get_config_filename(system, interface=name).lower() f2 = os.path.join(self.bootloc, "etc", filename) # Link to the yaboot binary f3 = os.path.join(self.bootloc, "ppc", filename) if os.path.lexists(f3): utils.rmfile(f3) os.symlink("../yaboot", f3) else: continue if system.is_management_supported(): if not image_based: self.write_pxe_file(f2, system, profile, distro, working_arch, metadata=pxe_metadata) if grub_path: self.write_pxe_file(grub_path, system, profile, distro, working_arch, format="grub") else: self.write_pxe_file(f2, system, None, None, working_arch, image=profile, metadata=pxe_metadata) else: # ensure the file doesn't exist utils.rmfile(f2) if grub_path: utils.rmfile(grub_path)
def write_all_system_files(self, system, menu_items): profile = system.get_conceptual_parent() if profile is None: raise CX("system %(system)s references a missing profile %(profile)s" % {"system": system.name, "profile": system.profile}) distro = profile.get_conceptual_parent() image_based = False image = None if distro is None: if profile.COLLECTION_TYPE == "profile": raise CX("profile %(profile)s references a missing distro %(distro)s" % {"profile": system.profile, "distro": profile.distro}) else: image_based = True image = profile pxe_metadata = {'pxe_menu_items': menu_items} # generate one record for each described NIC .. for (name, interface) in system.interfaces.iteritems(): f1 = utils.get_config_filename(system, interface=name) if f1 is None: self.logger.warning("invalid interface recorded for system (%s,%s)" % (system.name, name)) continue if image_based: working_arch = image.arch else: working_arch = distro.arch if working_arch is None: raise "internal error, invalid arch supplied" # for tftp only ... grub_path = None if working_arch in ["i386", "x86", "x86_64", "arm", "standard"]: # pxelinux wants a file named $name under pxelinux.cfg f2 = os.path.join(self.bootloc, "pxelinux.cfg", f1) # Only generating grub menus for these arch's: grub_path = os.path.join(self.bootloc, "grub", f1.upper()) elif working_arch.startswith("ppc"): # Determine filename for system-specific yaboot.conf filename = "%s" % utils.get_config_filename(system, interface=name).lower() f2 = os.path.join(self.bootloc, "etc", filename) # Link to the yaboot binary f3 = os.path.join(self.bootloc, "ppc", filename) if os.path.lexists(f3): utils.rmfile(f3) os.symlink("../yaboot", f3) else: continue if system.is_management_supported(): if not image_based: self.write_pxe_file(f2, system, profile, distro, working_arch, metadata=pxe_metadata) if grub_path: self.write_pxe_file(grub_path, system, profile, distro, working_arch, format="grub") else: self.write_pxe_file(f2, system, None, None, working_arch, image=profile, metadata=pxe_metadata) else: # ensure the file doesn't exist utils.rmfile(f2) if grub_path: utils.rmfile(grub_path)
def write_pxe_file(self,filename,system,profile,distro,arch,image=None,include_header=True): """ Write a configuration file for the boot loader(s). More system-specific configuration may come in later, if so that would appear inside the system object in api.py NOTE: relevant to tftp and pseudo-PXE (s390) only ia64 is mostly the same as syslinux stuff, s390 is a bit short-circuited and simpler. All of it goes through the templating engine, see the templates in /etc/cobbler for more details """ if arch is None: raise "missing arch" if image and not os.path.exists(image.file): return None # nfs:// URLs or something, can't use for TFTP # --- # just some random variables template = None metadata = {} buffer = "" # --- kickstart_path = None kernel_path = None initrd_path = None if image is None: # not image based, it's something normalish kernel_path = os.path.join("/images",distro.name,os.path.basename(distro.kernel)) initrd_path = os.path.join("/images",distro.name,os.path.basename(distro.initrd)) # Find the kickstart if we inherit from another profile if system: blended = utils.blender(self.api, True, system) else: blended = utils.blender(self.api, True, profile) kickstart_path = blended.get("kickstart","") else: # this is an image we are making available, not kernel+initrd if image.image_type == "direct": kernel_path = os.path.join("/images2",image.name) elif image.image_type == "memdisk": kernel_path = "/memdisk" initrd_path = os.path.join("/images2",image.name) else: # CD-ROM ISO or virt-clone image? We can't PXE boot it. kernel_path = None initrd_path = None # --- # choose a template if system: if system.netboot_enabled: template = os.path.join(self.settings.pxe_template_dir,"pxesystem.template") if arch.startswith("s390"): template = os.path.join(self.settings.pxe_template_dir,"pxesystem_s390x.template") elif arch == "ia64": template = os.path.join(self.settings.pxe_template_dir,"pxesystem_ia64.template") elif arch.startswith("ppc"): template = os.path.join(self.settings.pxe_template_dir,"pxesystem_ppc.template") else: # local booting on ppc requires removing the system-specific dhcpd.conf filename if arch is not None and arch.startswith("ppc"): # Disable yaboot network booting for all interfaces on the system for (name,interface) in system.interfaces.iteritems(): filename = "%s" % utils.get_config_filename(system, interface=name).lower() # Remove symlink to the yaboot binary f3 = os.path.join(self.bootloc, "ppc", filename) if os.path.lexists(f3): utils.rmfile(f3) # Remove the interface-specific config file f3 = os.path.join(self.bootloc, "etc", filename) if os.path.lexists(f3): utils.rmfile(f3) # Yaboot/OF doesn't support booting locally once you've # booted off the network, so nothing left to do return None elif arch is not None and arch.startswith("s390"): template = os.path.join(self.settings.pxe_template_dir,"pxelocal_s390x.template") elif arch is not None and arch.startswith("ia64"): template = os.path.join(self.settings.pxe_template_dir,"pxelocal_ia64.template") else: template = os.path.join(self.settings.pxe_template_dir,"pxelocal.template") else: # not a system record, so this is a profile record if arch.startswith("s390"): template = os.path.join(self.settings.pxe_template_dir,"pxeprofile_s390x.template") else: template = os.path.join(self.settings.pxe_template_dir,"pxeprofile.template") # now build the kernel command line if system is not None: blended = utils.blender(self.api, True, system) elif profile is not None: blended = utils.blender(self.api, True, profile) else: blended = utils.blender(self.api, True, image) kopts = blended.get("kernel_options","") # generate the append line hkopts = utils.hash_to_string(kopts) if initrd_path and (not arch or arch not in ["ia64", "ppc", "ppc64"]): append_line = "append initrd=%s %s" % (initrd_path, hkopts) else: append_line = "append %s" % hkopts # FIXME - the append_line length limit is architecture specific if len(append_line) >= 255 + len("append "): self.logger.warning("warning: kernel option length exceeds 255") # kickstart path rewriting (get URLs for local files) if kickstart_path is not None and kickstart_path != "": # FIXME: need to make shorter rewrite rules for these URLs if system is not None and kickstart_path.startswith("/"): kickstart_path = "http://%s/cblr/svc/op/ks/system/%s" % (blended["http_server"], system.name) elif kickstart_path.startswith("/"): kickstart_path = "http://%s/cblr/svc/op/ks/profile/%s" % (blended["http_server"], profile.name) if distro.breed is None or distro.breed == "redhat": append_line = "%s ks=%s" % (append_line, kickstart_path) elif distro.breed == "suse": append_line = "%s autoyast=%s" % (append_line, kickstart_path) elif distro.breed == "debian" or distro.breed == "ubuntu": append_line = "%s auto url=%s" % (append_line, kickstart_path) # rework kernel options for debian distros translations = { 'ksdevice':"interface" , 'lang':"locale" } for k,v in translations.iteritems(): append_line = append_line.replace("%s="%k,"%s="%v) # interface=bootif causes a failure append_line = append_line.replace("interface=bootif","") elif distro.breed == "vmware": append_line = "%s vmkopts=debugLogToSerial:1 mem=512M ks=%s" % (append_line, kickstart_path) # interface=bootif causes a failure append_line = append_line.replace("ksdevice=bootif","") if distro is not None and (distro.breed in [ "debian", "ubuntu" ]): # Hostname is required as a parameter, the one in the preseed is # not respected, so calculate if we have one here. # We're trying: first part of FQDN in hostname field, then system # name, then profile name. # In Ubuntu, this is at least used for the volume group name when # using LVM. domain = "local.lan" if system is not None: if system.hostname is not None: # If this is a FQDN, grab the first bit hostname = system.hostname.split(".")[0] _domain = system.hostname.split(".")[1:] if _domain: domain = ".".join( _domain ) else: hostname = system.name else: hostname = profile.name # At least for debian deployments configured for DHCP networking # this values are not used, but specifying here avoids questions append_line = "%s hostname=%s" % (append_line, hostname) append_line = "%s domain=%s" % (append_line, domain) # A similar issue exists with suite name, as installer requires # the existence of "stable" in the dists directory append_line = "%s suite=%s" % (append_line, distro.os_version) if arch.startswith("ppc") or arch.startswith("s390"): # remove the prefix "append" append_line = append_line[7:] # store variables for templating metadata["menu_label"] = "" if profile: if not arch in [ "ia64", "ppc", "ppc64", "s390", "s390x" ]: metadata["menu_label"] = "MENU LABEL %s" % profile.name metadata["profile_name"] = profile.name elif image: metadata["menu_label"] = "MENU LABEL %s" % image.name metadata["profile_name"] = image.name if system: metadata["system_name"] = system.name if kernel_path is not None: metadata["kernel_path"] = kernel_path if initrd_path is not None: metadata["initrd_path"] = initrd_path metadata["append_line"] = append_line # get the template if kernel_path is not None: template_fh = open(template) template_data = template_fh.read() template_fh.close() else: # this is something we can't PXE boot template_data = "\n" # save file and/or return results, depending on how called. buffer = self.templar.render(template_data, metadata, None) if filename is not None: self.logger.info("generating: %s" % filename) fd = open(filename, "w") fd.write(buffer) fd.close() return buffer
def write_pxe_file(self, filename, system, profile, distro, arch, image=None, include_header=True, metadata=None, format="pxe"): """ Write a configuration file for the boot loader(s). More system-specific configuration may come in later, if so that would appear inside the system object in api.py Can be used for different formats, "pxe" (default) and "grub". """ if arch is None: raise "missing arch" if image and not os.path.exists(image.file): return None # nfs:// URLs or something, can't use for TFTP if metadata is None: metadata = {} (rval, settings) = utils.input_string_or_dict(self.settings.to_dict()) if rval: for key in settings.keys(): metadata[key] = settings[key] # --- # just some random variables template = None buffer = "" # --- autoinstall_path = None kernel_path = None initrd_path = None img_path = None if image is None: # not image based, it's something normalish img_path = os.path.join("/images", distro.name) if 'nexenta' == distro.breed: kernel_path = os.path.join("/images", distro.name, 'platform', 'i86pc', 'kernel', 'amd64', os.path.basename(distro.kernel)) initrd_path = os.path.join("/images", distro.name, 'platform', 'i86pc', 'amd64', os.path.basename(distro.initrd)) elif 'http' in distro.kernel and 'http' in distro.initrd: kernel_path = distro.kernel initrd_path = distro.initrd else: kernel_path = os.path.join("/images", distro.name, os.path.basename(distro.kernel)) initrd_path = os.path.join("/images", distro.name, os.path.basename(distro.initrd)) # Find the automatic installation file if we inherit from another profile if system: blended = utils.blender(self.api, True, system) else: blended = utils.blender(self.api, True, profile) autoinstall_path = blended.get("autoinstall", "") # update metadata with all known information # this allows for more powerful templating metadata.update(blended) else: # this is an image we are making available, not kernel+initrd if image.image_type == "direct": kernel_path = os.path.join("/images2", image.name) elif image.image_type == "memdisk": kernel_path = "/memdisk" initrd_path = os.path.join("/images2", image.name) else: # CD-ROM ISO or virt-clone image? We can't PXE boot it. kernel_path = None initrd_path = None if img_path is not None and "img_path" not in metadata: metadata["img_path"] = img_path if kernel_path is not None and "kernel_path" not in metadata: metadata["kernel_path"] = kernel_path if initrd_path is not None and "initrd_path" not in metadata: metadata["initrd_path"] = initrd_path # --- # choose a template if system: if format == "grub": if system.netboot_enabled: template = os.path.join(self.settings.boot_loader_conf_template_dir, "grubsystem.template") else: local = os.path.join(self.settings.boot_loader_conf_template_dir, "grublocal.template") if os.path.exists(local): template = local else: # pxe if system.netboot_enabled: template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxesystem.template") if arch.startswith("ppc"): # to inherit the distro and system's boot_loader values correctly blended_system = utils.blender(self.api, False, system) if blended_system["boot_loader"] == "pxelinux": template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxesystem_ppc.template") elif distro.boot_loader == "grub2" or blended_system["boot_loader"] == "grub2": template = os.path.join(self.settings.boot_loader_conf_template_dir, "grub2_ppc.template") else: template = os.path.join(self.settings.boot_loader_conf_template_dir, "yaboot_ppc.template") elif arch.startswith("arm"): template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxesystem_arm.template") elif distro and distro.os_version.startswith("esxi"): # ESXi uses a very different pxe method, using more files than # a standard automatic installation file and different options - # so giving it a dedicated PXE template makes more sense than # shoe-horning it into the existing templates template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxesystem_esxi.template") else: # local booting on ppc requires removing the system-specific dhcpd.conf filename if arch is not None and arch.startswith("ppc"): # Disable yaboot network booting for all interfaces on the system for (name, interface) in system.interfaces.iteritems(): filename = "%s" % utils.get_config_filename(system, interface=name).lower() # Remove symlink to the yaboot binary f3 = os.path.join(self.bootloc, "ppc", filename) if os.path.lexists(f3): utils.rmfile(f3) # Remove the interface-specific config file f3 = os.path.join(self.bootloc, "boot/grub", "grub.cfg-" + filename) if os.path.lexists(f3): utils.rmfile(f3) f3 = os.path.join(self.bootloc, "etc", filename) if os.path.lexists(f3): utils.rmfile(f3) # Yaboot/OF doesn't support booting locally once you've # booted off the network, so nothing left to do return None else: template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxelocal.template") else: # not a system record, so this is a profile record or an image if arch.startswith("arm"): template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxeprofile_arm.template") elif format == "grub": template = os.path.join(self.settings.boot_loader_conf_template_dir, "grubprofile.template") elif distro and distro.os_version.startswith("esxi"): # ESXi uses a very different pxe method, see comment above in the system section template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxeprofile_esxi.template") elif 'nexenta' == format: template = os.path.join(self.settings.boot_loader_conf_template_dir, 'nexenta_profile.template') else: template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxeprofile.template") if kernel_path is not None: metadata["kernel_path"] = kernel_path if initrd_path is not None: metadata["initrd_path"] = initrd_path # generate the kernel options and append line: kernel_options = self.build_kernel_options(system, profile, distro, image, arch, autoinstall_path) metadata["kernel_options"] = kernel_options if distro and distro.os_version.startswith("esxi") and filename is not None: append_line = "BOOTIF=%s" % (os.path.basename(filename)) elif "initrd_path" in metadata and (not arch or arch not in ["ppc", "ppc64", "arm"]): append_line = "append initrd=%s" % (metadata["initrd_path"]) else: append_line = "append " append_line = "%s%s" % (append_line, kernel_options) if arch.startswith("ppc"): # remove the prefix "append" # TODO: this looks like it's removing more than append, really # not sure what's up here... append_line = append_line[7:] if distro and distro.os_version.startswith("xenserver620"): append_line = "%s" % (kernel_options) metadata["append_line"] = append_line # store variables for templating metadata["menu_label"] = "" if profile: if arch not in ["ppc", "ppc64"]: metadata["menu_label"] = "MENU LABEL %s" % profile.name metadata["profile_name"] = profile.name elif image: metadata["menu_label"] = "MENU LABEL %s" % image.name metadata["profile_name"] = image.name if system: metadata["system_name"] = system.name # get the template if kernel_path is not None: template_fh = open(template) template_data = template_fh.read() template_fh.close() else: # this is something we can't PXE boot template_data = "\n" # save file and/or return results, depending on how called. buffer = self.templar.render(template_data, metadata, None) if filename is not None: self.logger.info("generating: %s" % filename) fd = open(filename, "w") fd.write(buffer) fd.close() return buffer
def write_pxe_file(self, filename, system, profile, distro, arch, image=None, include_header=True): """ Write a configuration file for the boot loader(s). More system-specific configuration may come in later, if so that would appear inside the system object in api.py NOTE: relevant to tftp and pseudo-PXE (s390) only ia64 is mostly the same as syslinux stuff, s390 is a bit short-circuited and simpler. All of it goes through the templating engine, see the templates in /etc/cobbler for more details """ if arch is None: raise "missing arch" if image and not os.path.exists(image.file): return None # nfs:// URLs or something, can't use for TFTP # --- # just some random variables template = None metadata = {} buffer = "" # --- kickstart_path = None kernel_path = None initrd_path = None if image is None: # not image based, it's something normalish kernel_path = os.path.join("/images", distro.name, os.path.basename(distro.kernel)) initrd_path = os.path.join("/images", distro.name, os.path.basename(distro.initrd)) # Find the kickstart if we inherit from another profile if system: blended = utils.blender(self.api, True, system) else: blended = utils.blender(self.api, True, profile) kickstart_path = blended.get("kickstart", "") else: # this is an image we are making available, not kernel+initrd if image.image_type == "direct": kernel_path = os.path.join("/images2", image.name) elif image.image_type == "memdisk": kernel_path = "/memdisk" initrd_path = os.path.join("/images2", image.name) else: # CD-ROM ISO or virt-clone image? We can't PXE boot it. kernel_path = None initrd_path = None # --- # choose a template if system: if system.netboot_enabled: template = os.path.join(self.settings.pxe_template_dir, "pxesystem.template") if arch.startswith("s390"): template = os.path.join(self.settings.pxe_template_dir, "pxesystem_s390x.template") elif arch == "ia64": template = os.path.join(self.settings.pxe_template_dir, "pxesystem_ia64.template") elif arch.startswith("ppc"): template = os.path.join(self.settings.pxe_template_dir, "pxesystem_ppc.template") else: # local booting on ppc requires removing the system-specific dhcpd.conf filename if arch is not None and arch.startswith("ppc"): # Disable yaboot network booting for all interfaces on the system for (name, interface) in system.interfaces.iteritems(): filename = "%s" % utils.get_config_filename( system, interface=name).lower() # Remove symlink to the yaboot binary f3 = os.path.join(self.bootloc, "ppc", filename) if os.path.lexists(f3): utils.rmfile(f3) # Remove the interface-specific config file f3 = os.path.join(self.bootloc, "etc", filename) if os.path.lexists(f3): utils.rmfile(f3) # Yaboot/OF doesn't support booting locally once you've # booted off the network, so nothing left to do return None elif arch is not None and arch.startswith("s390"): template = os.path.join(self.settings.pxe_template_dir, "pxelocal_s390x.template") elif arch is not None and arch.startswith("ia64"): template = os.path.join(self.settings.pxe_template_dir, "pxelocal_ia64.template") else: template = os.path.join(self.settings.pxe_template_dir, "pxelocal.template") else: # not a system record, so this is a profile record if arch.startswith("s390"): template = os.path.join(self.settings.pxe_template_dir, "pxeprofile_s390x.template") else: template = os.path.join(self.settings.pxe_template_dir, "pxeprofile.template") # now build the kernel command line if system is not None: blended = utils.blender(self.api, True, system) elif profile is not None: blended = utils.blender(self.api, True, profile) else: blended = utils.blender(self.api, True, image) kopts = blended.get("kernel_options", "") # generate the append line hkopts = utils.hash_to_string(kopts) if initrd_path and (not arch or arch not in ["ia64", "ppc", "ppc64"]): append_line = "append initrd=%s %s" % (initrd_path, hkopts) else: append_line = "append %s" % hkopts # FIXME - the append_line length limit is architecture specific if len(append_line) >= 255 + len("append "): self.logger.warning("warning: kernel option length exceeds 255") # kickstart path rewriting (get URLs for local files) if kickstart_path is not None and kickstart_path != "": # FIXME: need to make shorter rewrite rules for these URLs if system is not None and kickstart_path.startswith("/"): kickstart_path = "http://%s/cblr/svc/op/ks/system/%s" % ( blended["http_server"], system.name) elif kickstart_path.startswith("/"): kickstart_path = "http://%s/cblr/svc/op/ks/profile/%s" % ( blended["http_server"], profile.name) if distro.breed is None or distro.breed == "redhat": append_line = "%s ks=%s" % (append_line, kickstart_path) elif distro.breed == "suse": append_line = "%s autoyast=%s" % (append_line, kickstart_path) elif distro.breed == "debian" or distro.breed == "ubuntu": append_line = "%s auto url=%s" % (append_line, kickstart_path) # rework kernel options for debian distros translations = {'ksdevice': "interface", 'lang': "locale"} for k, v in translations.iteritems(): append_line = append_line.replace("%s=" % k, "%s=" % v) # interface=bootif causes a failure append_line = append_line.replace("interface=bootif", "") if distro is not None and (distro.breed in ["debian", "ubuntu"]): # Hostname is required as a parameter, the one in the preseed is # not respected, so calculate if we have one here. # We're trying: first part of FQDN in hostname field, then system # name, then profile name. # In Ubuntu, this is at least used for the volume group name when # using LVM. domain = "local.lan" if system is not None: if system.hostname is not None: # If this is a FQDN, grab the first bit hostname = system.hostname.split(".")[0] _domain = system.hostname.split(".")[1:] if _domain: domain = ".".join(_domain) else: hostname = system.name else: hostname = profile.name # At least for debian deployments configured for DHCP networking # this values are not used, but specifying here avoids questions append_line = "%s hostname=%s" % (append_line, hostname) append_line = "%s domain=%s" % (append_line, domain) # A similar issue exists with suite name, as installer requires # the existence of "stable" in the dists directory append_line = "%s suite=%s" % (append_line, distro.os_version) if arch.startswith("ppc") or arch.startswith("s390"): # remove the prefix "append" append_line = append_line[7:] # store variables for templating metadata["menu_label"] = "" if profile: if not arch in ["ia64", "ppc", "ppc64", "s390", "s390x"]: metadata["menu_label"] = "MENU LABEL %s" % profile.name metadata["profile_name"] = profile.name elif image: metadata["menu_label"] = "MENU LABEL %s" % image.name metadata["profile_name"] = image.name if system: metadata["system_name"] = system.name if kernel_path is not None: metadata["kernel_path"] = kernel_path if initrd_path is not None: metadata["initrd_path"] = initrd_path metadata["append_line"] = append_line # get the template if kernel_path is not None: template_fh = open(template) template_data = template_fh.read() template_fh.close() else: # this is something we can't PXE boot template_data = "\n" # save file and/or return results, depending on how called. buffer = self.templar.render(template_data, metadata, None) if filename is not None: self.logger.info("generating: %s" % filename) fd = open(filename, "w") fd.write(buffer) fd.close() return buffer