def generate_kickstart(self, profile=None, system=None): obj = system if system is None: obj = profile meta = utils.blender(self.api, False, obj) kickstart_path = utils.find_kickstart(meta["kickstart"]) if not kickstart_path: return "# kickstart is missing or invalid: %s" % meta["kickstart"] ksmeta = meta["ks_meta"] del meta["ks_meta"] meta.update(ksmeta) # make available at top level meta["yum_repo_stanza"] = self.generate_repo_stanza(obj, (system is None)) meta["yum_config_stanza"] = self.generate_config_stanza(obj, (system is None)) meta["kernel_options"] = utils.hash_to_string(meta["kernel_options"]) # meta["config_template_files"] = self.generate_template_files_stanza(g, False) try: raw_data = utils.read_file_contents(kickstart_path, self.api.logger, self.settings.template_remote_kickstarts) if raw_data is None: return "# kickstart is sourced externally: %s" % meta["kickstart"] data = self.templar.render(raw_data, meta, None, obj) return data except FileNotFoundException: self.api.logger.warning("kickstart not found: %s" % meta["kickstart"]) return "# kickstart not found: %s" % meta["kickstart"]
def generate_kickstart(self, profile=None, system=None): obj = system if system is None: obj = profile meta = utils.blender(self.api, False, obj) kickstart_path = utils.find_kickstart(meta["kickstart"]) if not kickstart_path: return "# kickstart is missing or invalid: %s" % meta["kickstart"] ksmeta = meta["ks_meta"] del meta["ks_meta"] meta.update(ksmeta) # make available at top level meta["yum_repo_stanza"] = self.generate_repo_stanza( obj, (system is None)) meta["yum_config_stanza"] = self.generate_config_stanza( obj, (system is None)) meta["kernel_options"] = utils.hash_to_string(meta["kernel_options"]) # meta["config_template_files"] = self.generate_template_files_stanza(g, False) try: raw_data = utils.read_file_contents( kickstart_path, self.api.logger, self.settings.template_remote_kickstarts) if raw_data is None: return "# kickstart is sourced externally: %s" % meta[ "kickstart"] data = self.templar.render(raw_data, meta, None, obj) return data except FileNotFoundException: self.api.logger.warning("kickstart not found: %s" % meta["kickstart"]) return "# kickstart not found: %s" % meta["kickstart"]
def generate_kickstart_for_profile(self,g): g = self.api.find_profile(name=g) if g is None: return "# profile not found" distro = g.get_conceptual_parent() meta = utils.blender(self.api, False, g) if distro is None: raise CX(_("profile %(profile)s references missing distro %(distro)s") % { "profile" : g.name, "distro" : g.distro }) kickstart_path = utils.find_kickstart(meta["kickstart"]) if kickstart_path is not None and os.path.exists(kickstart_path): # the input is an *actual* file, hence we have to copy it try: meta = utils.blender(self.api, False, g) ksmeta = meta["ks_meta"] del meta["ks_meta"] meta.update(ksmeta) # make available at top level meta["yum_repo_stanza"] = self.generate_repo_stanza(g,True) meta["yum_config_stanza"] = self.generate_config_stanza(g,True) meta["kickstart_done"] = self.generate_kickstart_signal(0, g, None) meta["kickstart_start"] = self.generate_kickstart_signal(1, g, None) meta["kernel_options"] = utils.hash_to_string(meta["kernel_options"]) kfile = open(kickstart_path) data = self.templar.render(kfile, meta, None, g) kfile.close() return data except: utils.log_exc(self.api.logger) raise elif kickstart_path is not None and not os.path.exists(kickstart_path): if kickstart_path.find("http://") == -1 and kickstart_path.find("ftp://") == -1 and kickstart_path.find("nfs:") == -1: return "# Error, cannot find %s" % kickstart_path return "# kickstart is sourced externally, or is missing, and cannot be displayed here: %s" % meta["kickstart"]
def generate_kickstart(self, profile=None, system=None): obj = system if system is None: obj = profile meta = utils.blender(self.api, False, obj) kickstart_path = utils.find_kickstart(meta["kickstart"]) if not kickstart_path: return "# kickstart is missing or invalid: %s" % meta["kickstart"] ksmeta = meta["ks_meta"] del meta["ks_meta"] meta.update(ksmeta) # make available at top level meta["yum_repo_stanza"] = self.generate_repo_stanza( obj, (system is None)) meta["yum_config_stanza"] = self.generate_config_stanza( obj, (system is None)) meta["kernel_options"] = utils.hash_to_string(meta["kernel_options"]) # meta["config_template_files"] = self.generate_template_files_stanza(g, False) # add extra variables for other distro types if "tree" in meta: urlparts = urlparse.urlsplit(meta["tree"]) meta["install_source_directory"] = urlparts[2] try: raw_data = utils.read_file_contents( kickstart_path, self.api.logger, self.settings.template_remote_kickstarts) if raw_data is None: return "# kickstart is sourced externally: %s" % meta[ "kickstart"] distro = profile.get_conceptual_parent() if system is not None: distro = system.get_conceptual_parent().get_conceptual_parent() data = self.templar.render(raw_data, meta, None, obj) if distro.breed == "suse": # AutoYaST profile data = self.generate_autoyast(profile, system, data) return data except FileNotFoundException: self.api.logger.warning("kickstart not found: %s" % meta["kickstart"]) return "# kickstart not found: %s" % meta["kickstart"]
def start(self): self.create_backups() # fill up the knowledge piece array self.read_input() # iterate through all the knowledge pieces langs = [] for lang, cat, subcat, desc, code in self.knowledge_piece_array: # handle cheatsheet retrieval (load or create) cht = self.handle_cheatsheet(lang) # handle the case if the category does not exist in the cheatsheet cat, exists = self.handle_category(cat, cht) if not exists: cht[cat] = [] piece = self.create_current_knowledge_piece( cht, lang, cat, desc, code) # skip this knowledge piece if its already conteined in the cheatsheet if ''.join(cht[cat]).find(piece) != -1: self.add_msg( "Knowledge piece already contained in cheatsheet!") continue # append the knowledge piece to the cheatsheet... cht[cat].append(piece) # ...and store it to disk! str_full = utils.hash_to_string(cht) a = open(self.wrapdir(lang), 'w') a.write(str_full) a.close() langs.append(lang) # compile the latex for lang in langs: self.compile_latex_docs(lang) self.add_msg( 'All new knowledge has been intergrated. You may exit the program.' )
def make_s390_pseudo_pxe_menu(self): s390path = os.path.join(self.bootloc, "s390x") if not os.path.exists(s390path): utils.mkdir(s390path) profile_list = [profile for profile in self.profiles] image_list = [image for image in self.images] def sort_name(a, b): return cmp(a.name, b.name) profile_list.sort(sort_name) image_list.sort(sort_name) listfile = open(os.path.join(s390path, "profile_list"), "w+") for profile in profile_list: distro = profile.get_conceptual_parent() if distro is None: raise CX("profile is missing distribution: %s, %s" % (profile.name, profile.distro)) if distro.arch.startswith("s390"): listfile.write("%s\n" % profile.name) f2 = os.path.join(self.bootloc, "s390x", "p_%s" % profile.name) self.write_pxe_file(f2, None, profile, distro, distro.arch) 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, profile) 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/profile/%s" % ( ipaddress, profile.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) listfile.close()
def generate_kickstart(self, profile=None, system=None): obj = system if system is None: obj = profile meta = utils.blender(self.api, False, obj) kickstart_path = utils.find_kickstart(meta["kickstart"]) if not kickstart_path: return "# kickstart is missing or invalid: %s" % meta["kickstart"] ksmeta = meta["ks_meta"] del meta["ks_meta"] meta.update(ksmeta) # make available at top level meta["yum_repo_stanza"] = self.generate_repo_stanza(obj, (system is None)) meta["yum_config_stanza"] = self.generate_config_stanza(obj, (system is None)) meta["kernel_options"] = utils.hash_to_string(meta["kernel_options"]) # add extra variables for other distro types if "tree" in meta: urlparts = urlparse.urlsplit(meta["tree"]) meta["install_source_directory"] = urlparts[2] try: raw_data = utils.read_file_contents( kickstart_path, self.api.logger, self.settings.template_remote_kickstarts) if raw_data is None: return "# kickstart is sourced externally: %s" % meta["kickstart"] distro = profile.get_conceptual_parent() if system is not None: distro = system.get_conceptual_parent().get_conceptual_parent() data = self.templar.render(raw_data, meta, None, obj) if distro.breed == "suse": # AutoYaST profile data = self.generate_autoyast(profile, system, data) return data except FileNotFoundException: self.api.logger.warning("kickstart not found: %s" % meta["kickstart"]) return "# kickstart not found: %s" % meta["kickstart"]
def make_s390_pseudo_pxe_menu(self): s390path = os.path.join(self.bootloc, "s390x") if not os.path.exists(s390path): utils.mkdir(s390path) profile_list = [profile for profile in self.profiles] image_list = [image for image in self.images] def sort_name(a, b): return cmp(a.name, b.name) profile_list.sort(sort_name) image_list.sort(sort_name) listfile = open(os.path.join(s390path, "profile_list"), "w+") for profile in profile_list: distro = profile.get_conceptual_parent() if distro is None: raise CX("profile is missing distribution: %s, %s" % (profile.name, profile.distro)) if distro.arch.startswith("s390"): listfile.write("%s\n" % profile.name) f2 = os.path.join(self.bootloc, "s390x", "p_%s" % profile.name) self.write_pxe_file(f2, None, profile, distro, distro.arch) 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, profile) 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/profile/%s" % (ipaddress, profile.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) listfile.close()
def generate_kickstart_for_system(self,s): s = self.api.find_system(name=s) if s is None: return "# system not found" profile = s.get_conceptual_parent() if profile is None: raise CX(_("system %(system)s references missing profile %(profile)s") % { "system" : s.name, "profile" : s.profile }) distro = profile.get_conceptual_parent() if distro is None: # this is an image parented system, no kickstart available return "# image based systems do not have kickstarts" meta = utils.blender(self.api, False, s) kickstart_path = utils.find_kickstart(meta["kickstart"]) if kickstart_path and os.path.exists(kickstart_path): try: ksmeta = meta["ks_meta"] del meta["ks_meta"] meta.update(ksmeta) # make available at top level meta["yum_repo_stanza"] = self.generate_repo_stanza(s, False) meta["yum_config_stanza"] = self.generate_config_stanza(s, False) meta["kickstart_done"] = self.generate_kickstart_signal(0, profile, s) meta["kickstart_start"] = self.generate_kickstart_signal(1, profile, s) meta["kernel_options"] = utils.hash_to_string(meta["kernel_options"]) # meta["config_template_files"] = self.generate_template_files_stanza(g, False) kfile = open(kickstart_path) data = self.templar.render(kfile, meta, None, s) kfile.close() return data except: traceback.print_exc() raise CX(_("Error templating file")) elif kickstart_path is not None and not os.path.exists(kickstart_path): if kickstart_path.find("http://") == -1 and kickstart_path.find("ftp://") == -1 and kickstart_path.find("nfs:") == -1: return "# Error, cannot find %s" % kickstart_path return "# kickstart is sourced externally: %s" % meta["kickstart"]
def build_kernel_options(self, system, profile, distro, image, arch, kickstart_path): """ Builds the full kernel options line. """ if system is not None: blended = utils.blender(self.api, False, system) elif profile is not None: blended = utils.blender(self.api, False, profile) else: blended = utils.blender(self.api, False, image) append_line = "" kopts = blended.get("kernel_options", dict()) # support additional initrd= entries in kernel options. if "initrd" in kopts: append_line = ",%s" % kopts.pop("initrd") hkopts = utils.hash_to_string(kopts) append_line = "%s %s" % (append_line, hkopts) # 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 try: ipaddress = socket.gethostbyname_ex(blended["http_server"])[2][0] except socket.gaierror: ipaddress = blended["http_server"] if system is not None and kickstart_path.startswith("/"): kickstart_path = "http://%s/cblr/svc/op/ks/system/%s" % (ipaddress, system.name) elif kickstart_path.startswith("/"): kickstart_path = "http://%s/cblr/svc/op/ks/profile/%s" % (ipaddress, profile.name) if distro.breed is None or distro.breed == "redhat": append_line = "%s ks=%s" % (append_line, kickstart_path) gpxe = blended["enable_gpxe"] if gpxe: append_line = append_line.replace('ksdevice=bootif','ksdevice=${net0/mac}') 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-install/enable=true priority=critical url=%s" % (append_line, kickstart_path) elif distro.breed == "freebsd": append_line = "%s ks=%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": if distro.os_version.find("esxi") != -1: # ESXi is very picky, it's easier just to redo the # entire append line here since append_line = " ks=%s %s" % (kickstart_path, hkopts) # ESXi likes even fewer options, so we remove them too append_line = append_line.replace("kssendmac","") else: 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 and system.hostname != "": # 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: # ubuntu at the very least does not like having underscores # in the hostname. # FIXME: Really this should remove all characters that are # forbidden in hostnames hostname = profile.name.replace("_","") # 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) # append necessary kernel args for arm architectures if arch is not None and arch.startswith("arm"): append_line = "%s fixrtc vram=48M omapfb.vram=0:24M" % append_line # do variable substitution on the append line # FIXME: should we just promote all of the ksmeta # variables instead of just the tree? if blended.has_key("ks_meta") and blended["ks_meta"].has_key("tree"): blended["tree"] = blended["ks_meta"]["tree"] append_line = self.templar.render(append_line,utils.flatten(blended),None) # FIXME - the append_line length limit is architecture specific if len(append_line) >= 255: self.logger.warning("warning: kernel option length exceeds 255") return append_line
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_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 build_kernel_options(self, system, profile, distro, image, arch, kickstart_path): """ Builds the full kernel options line. """ management_interface = None if system is not None: blended = utils.blender(self.api, False, system) # find the first management interface try: for intf in system.interfaces.keys(): if system.interfaces[intf]["management"]: management_interface = intf break except: # just skip this then pass elif profile is not None: blended = utils.blender(self.api, False, profile) else: blended = utils.blender(self.api, False, image) append_line = "" kopts = blended.get("kernel_options", dict()) # since network needs to be configured again (it was already in netboot) when kernel boots # and we choose to do it dinamically, we need to set 'ksdevice' to one of # the interfaces' MAC addresses in ppc systems. # ksdevice=bootif is not useful in yaboot, as the "ipappend" line is a pxe feature. if system and arch and "ppc" in arch: for intf in system.interfaces.keys(): # use first interface with defined IP and MAC, since these are required # fields in a DHCP entry mac_address = system.interfaces[intf]['mac_address'] ip_address = system.interfaces[intf]['ip_address'] if mac_address and ip_address: kopts['ksdevice'] = mac_address break # support additional initrd= entries in kernel options. if "initrd" in kopts: append_line = ",%s" % kopts.pop("initrd") hkopts = utils.hash_to_string(kopts) append_line = "%s %s" % (append_line, hkopts) # 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 try: ipaddress = socket.gethostbyname_ex(blended["http_server"])[2][0] except socket.gaierror: ipaddress = blended["http_server"] if system is not None and kickstart_path.startswith("/"): kickstart_path = "http://%s/cblr/svc/op/ks/system/%s" % (ipaddress, system.name) elif kickstart_path.startswith("/"): kickstart_path = "http://%s/cblr/svc/op/ks/profile/%s" % (ipaddress, profile.name) if distro.breed is None or distro.breed == "redhat": append_line = "%s ks=%s" % (append_line, kickstart_path) gpxe = blended["enable_gpxe"] if gpxe: append_line = append_line.replace('ksdevice=bootif', 'ksdevice=${net0/mac}') 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-install/enable=true priority=critical url=%s" % (append_line, kickstart_path) if management_interface: append_line += " netcfg/choose_interface=%s" % management_interface elif distro.breed == "freebsd": append_line = "%s ks=%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": if distro.os_version.find("esxi") != -1: # ESXi is very picky, it's easier just to redo the # entire append line here since append_line = " ks=%s %s" % (kickstart_path, hkopts) # ESXi likes even fewer options, so we remove them too append_line = append_line.replace("kssendmac", "") else: 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", "") elif distro.breed == "xen": if distro.os_version.find("xenserver620") != -1: img_path = os.path.join("/images", distro.name) append_line = "append %s/xen.gz dom0_max_vcpus=2 dom0_mem=752M com1=115200,8n1 console=com1,vga --- %s/vmlinuz xencons=hvc console=hvc0 console=tty0 install answerfile=%s --- %s/install.img" % (img_path, img_path, kickstart_path, img_path) return append_line 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 and system.hostname != "": # 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: # ubuntu at the very least does not like having underscores # in the hostname. # FIXME: Really this should remove all characters that are # forbidden in hostnames hostname = profile.name.replace("_", "") # 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) elif distro is not None and distro.breed == 'nexenta': append_line = "-B iso_nfs_path=%s:/var/www/cobbler/links/%s,auto_install=1" % (blended['next_server'], distro.name) # append necessary kernel args for arm architectures if arch is not None and arch.startswith("arm"): append_line = "%s fixrtc vram=48M omapfb.vram=0:24M" % append_line # do variable substitution on the append line # promote all of the ksmeta variables if "ks_meta" in blended: blended.update(blended["ks_meta"]) append_line = self.templar.render(append_line, utils.flatten(blended), None) # FIXME - the append_line length limit is architecture specific if len(append_line) >= 255: self.logger.warning("warning: kernel option length exceeds 255") return append_line
def build_kernel_options(self, system, profile, distro, image, arch, kickstart_path): """ Builds the full kernel options line. """ if system is not None: blended = utils.blender(self.api, False, system) elif profile is not None: blended = utils.blender(self.api, False, profile) else: blended = utils.blender(self.api, False, image) append_line = "" kopts = blended.get("kernel_options", dict()) # support additional initrd= entries in kernel options. if "initrd" in kopts: append_line = ",%s" % kopts.pop("initrd") hkopts = utils.hash_to_string(kopts) append_line = "%s %s" % (append_line, hkopts) # FIXME - the append_line length limit is architecture specific # TODO: why is this checked here, before we finish adding everything? if len(append_line) >= 255: 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 ipaddress = socket.gethostbyname_ex(blended["http_server"])[2][0] if system is not None and kickstart_path.startswith("/"): kickstart_path = "http://%s/cblr/svc/op/ks/system/%s" % ( ipaddress, system.name) elif kickstart_path.startswith("/"): kickstart_path = "http://%s/cblr/svc/op/ks/profile/%s" % ( ipaddress, 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) return append_line
def build_kernel_options(self, system, profile, distro, image, arch, kickstart_path): """ Builds the full kernel options line. """ if system is not None: blended = utils.blender(self.api, False, system) elif profile is not None: blended = utils.blender(self.api, False, profile) else: blended = utils.blender(self.api, False, image) append_line = "" kopts = blended.get("kernel_options", dict()) # support additional initrd= entries in kernel options. if "initrd" in kopts: append_line = ",%s" % kopts.pop("initrd") hkopts = utils.hash_to_string(kopts) append_line = "%s %s" % (append_line, hkopts) # FIXME - the append_line length limit is architecture specific # TODO: why is this checked here, before we finish adding everything? if len(append_line) >= 255: 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 ipaddress = socket.gethostbyname_ex(blended["http_server"])[2][0] if system is not None and kickstart_path.startswith("/"): kickstart_path = "http://%s/cblr/svc/op/ks/system/%s" % (ipaddress, system.name) elif kickstart_path.startswith("/"): kickstart_path = "http://%s/cblr/svc/op/ks/profile/%s" % (ipaddress, 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": if distro.os_version.find("esxi") != -1: # ESXi is very picky, it's easier just to redo the # entire append line here since append_line = " ks=%s %s" % (kickstart_path, hkopts) # ESXi likes even fewer options, so we remove them too append_line = append_line.replace("kssendmac","") else: 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) return append_line
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