def _generate_netboot_profile(self, profile, cfglines: List[str]): """ Generates the ISOLINUX cfg configuration for any profiles included in the image. :param profile: The profile which the configuration should be generated for. :param cfglines: The already existing lines of the configuration. """ self.logger.info('Processing profile: "%s"', profile.name) dist = profile.get_conceptual_parent() distname = self.make_shorter(dist.name) self.copy_boot_files(dist, self.isolinuxdir, distname) cfglines.append("") cfglines.append("LABEL %s" % profile.name) cfglines.append(" MENU LABEL %s" % profile.name) cfglines.append(" kernel %s.krn" % distname) data = utils.blender(self.api, False, profile) # SUSE is not using 'text'. Instead 'textmode' is used as kernel option. if dist is not None: utils.kopts_overwrite(data["kernel_options"], self.api.settings().server, dist.breed) if not re.match(r"[a-z]+://.*", data["autoinstall"]): data[ "autoinstall"] = "http://%s:%s/cblr/svc/op/autoinstall/profile/%s" % ( data["server"], data["http_port"], profile.name, ) append_builder = AppendLineBuilder(distro_name=distname, data=data) append_line = append_builder.generate_profile(dist.breed) cfglines.append(append_line)
def test_kopts_overwrite(): # Arrange distro_breed = "suse" system_name = "kopts_test_system" kopts = {"textmode": False, "text": True} # Act utils.kopts_overwrite(kopts, "servername", distro_breed, system_name) # Assert assert "textmode" in kopts assert "info" in kopts
def _generate_descendant( self, descendant, cfglines: List[str], distro, airgapped: bool, repo_names_to_copy: dict, ): """ Generate the ISOLINUX cfg configuration file for the descendant. :param descendant: The descendant to generate the config file for. Must be a profile or system object. :param cfglines: The content of the file which has already been generated. :param distro: The parent distro. :param airgapped: Whether the generated ISO should be bootable in an airgapped environment or not. :param repo_names_to_copy: The repository names to copy in the case of an airgapped environment. """ menu_indent = 0 if descendant.COLLECTION_TYPE == "system": menu_indent = 4 data = utils.blender(self.api, False, descendant) # SUSE is not using 'text'. Instead 'textmode' is used as kernel option. if distro is not None: utils.kopts_overwrite(data["kernel_options"], self.api.settings().server, distro.breed) cfglines.append("") cfglines.append("LABEL %s" % descendant.name) if menu_indent: cfglines.append(" MENU INDENT %d" % menu_indent) cfglines.append(" MENU LABEL %s" % descendant.name) cfglines.append(" kernel %s" % os.path.basename(distro.kernel)) cfglines.append( _generate_append_line_standalone(data, distro, descendant)) autoinstall_data = self._generate_autoinstall_data( descendant, distro, airgapped, data, repo_names_to_copy) autoinstall_name = os.path.join(self.isolinuxdir, "%s.cfg" % descendant.name) with open(autoinstall_name, "w+") as autoinstall_file: autoinstall_file.write(autoinstall_data)
def test_kopts_overwrite(): # Arrange test_api = CobblerAPI() test_manager = CollectionManager(test_api) test_distro = Distro(test_manager) test_distro.set_breed("suse") test_distro.name = "kopts_test_distro" test_profile = Profile(test_manager) test_profile.distro = test_distro.name test_system = System(test_manager) test_system.name = "kopts_test_system" kopts = {"textmode": False, "text": True} # Act utils.kopts_overwrite(test_system, test_distro, kopts, test_api.settings()) # Assert assert "textmode" in kopts assert "info" in kopts
def generate_standalone_iso(self, imagesdir, isolinuxdir, distname, filesource, airgapped: bool, profiles): """ Create bootable CD image to be used for handsoff CD installtions :param imagesdir: Unused Parameter. :param isolinuxdir: The parent directory where the file isolinux.cfg is located at. :param distname: The name of the Cobbler distribution. :param filesource: Not clear what this exactly does :param airgapped: Whether the repositories have to be locally available or the internet is reachable. :param profiles: The list of profiles to include. """ # Get the distro object for the requested distro and then get all of its descendants (profiles/sub-profiles/ # systems) with sort=True for profile/system heirarchy to allow menu indenting distro = self.api.find_distro(distname) if distro is None: utils.die("distro %s was not found, aborting" % distname) descendants = distro.get_descendants(sort=True) profiles = utils.input_string_or_list(profiles) if filesource is None: # Try to determine the source from the distro kernel path self.logger.debug("trying to locate source for distro") found_source = False (source_head, source_tail) = os.path.split(distro.kernel) while source_tail != '': if source_head == os.path.join(self.api.settings().webdir, "distro_mirror"): filesource = os.path.join(source_head, source_tail) found_source = True self.logger.debug("found source in %s" % filesource) break (source_head, source_tail) = os.path.split(source_head) # Can't find the source, raise an error if not found_source: utils.die("Error, no installation source found. When building a standalone ISO, you must specify a " "--source if the distro install tree is not hosted locally") self.logger.info("copying kernels and initrds for standalone distro") self.copy_boot_files(distro, isolinuxdir, None) self.logger.info("generating an isolinux.cfg") isolinuxcfg = os.path.join(isolinuxdir, "isolinux.cfg") cfg = open(isolinuxcfg, "w+") cfg.write(self.iso_template) if airgapped: repo_names_to_copy = {} for descendant in descendants: # if a list of profiles was given, skip any others and their systems if profiles and ((descendant.COLLECTION_TYPE == 'profile' and descendant.name not in profiles) or (descendant.COLLECTION_TYPE == 'system' and descendant.profile not in profiles)): continue menu_indent = 0 if descendant.COLLECTION_TYPE == 'system': menu_indent = 4 data = utils.blender(self.api, False, descendant) # SUSE is not using 'text'. Instead 'textmode' is used as kernel option. if distro is not None: utils.kopts_overwrite(data['kernel_options'], self.settings.server, distro.breed) cfg.write("\n") cfg.write("LABEL %s\n" % descendant.name) if menu_indent: cfg.write(" MENU INDENT %d\n" % menu_indent) cfg.write(" MENU LABEL %s\n" % descendant.name) cfg.write(" kernel %s\n" % os.path.basename(distro.kernel)) append_line = " append initrd=%s" % os.path.basename(distro.initrd) if distro.breed == "redhat": append_line += " inst.ks=cdrom:/isolinux/%s.cfg" % descendant.name if distro.breed == "suse": append_line += " autoyast=file:///isolinux/%s.cfg install=cdrom:///" % descendant.name if "install" in data["kernel_options"]: del data["kernel_options"]["install"] if distro.breed in ["ubuntu", "debian"]: append_line += " auto-install/enable=true preseed/file=/cdrom/isolinux/%s.cfg" % descendant.name # add remaining kernel_options to append_line append_line += self.add_remaining_kopts(data["kernel_options"]) cfg.write(append_line) if descendant.COLLECTION_TYPE == 'profile': autoinstall_data = self.api.autoinstallgen.generate_autoinstall_for_profile(descendant.name) elif descendant.COLLECTION_TYPE == 'system': autoinstall_data = self.api.autoinstallgen.generate_autoinstall_for_system(descendant.name) if distro.breed == "redhat": cdregex = re.compile(r"^\s*url .*\n", re.IGNORECASE | re.MULTILINE) autoinstall_data = cdregex.sub("cdrom\n", autoinstall_data, count=1) if airgapped: descendant_repos = data['repos'] for repo_name in descendant_repos: repo_obj = self.api.find_repo(repo_name) error_fmt = (descendant.COLLECTION_TYPE + " " + descendant.name + " refers to repo " + repo_name + ", which %%s; cannot build airgapped ISO") if repo_obj is None: utils.die(error_fmt % "does not exist") if not repo_obj.mirror_locally: utils.die(error_fmt % "is not configured for local mirroring") # FIXME: don't hardcode mirrordir = os.path.join(self.settings.webdir, "repo_mirror", repo_obj.name) if not os.path.exists(mirrordir): utils.die(error_fmt % "has a missing local mirror directory") repo_names_to_copy[repo_obj.name] = mirrordir # update the baseurl in autoinstall_data to use the cdrom copy of this repo reporegex = re.compile(r"^(\s*repo --name=" + repo_obj.name + " --baseurl=).*", re.MULTILINE) autoinstall_data = reporegex.sub(r"\1" + "file:///mnt/source/repo_mirror/" + repo_obj.name, autoinstall_data) # rewrite any split-tree repos, such as in redhat, to use cdrom srcreporegex = re.compile(r"^(\s*repo --name=\S+ --baseurl=).*/cobbler/distro_mirror/" + distro.name + r"/?(.*)", re.MULTILINE) autoinstall_data = srcreporegex.sub(r"\1" + "file:///mnt/source" + r"\2", autoinstall_data) autoinstall_name = os.path.join(isolinuxdir, "%s.cfg" % descendant.name) with open(autoinstall_name, "w+") as autoinstall_file: autoinstall_file.write(autoinstall_data) self.logger.info("done writing config") cfg.write("\n") cfg.write("MENU END\n") cfg.close() if airgapped: # copy any repos found in profiles or systems to the iso build repodir = os.path.abspath(os.path.join(isolinuxdir, "..", "repo_mirror")) if not os.path.exists(repodir): os.makedirs(repodir) for repo_name in repo_names_to_copy: src = repo_names_to_copy[repo_name] dst = os.path.join(repodir, repo_name) self.logger.info(" - copying repo '" + repo_name + "' for airgapped ISO") ok = utils.rsync_files(src, dst, "--exclude=TRANS.TBL --exclude=cache/ --no-g", quiet=True) if not ok: utils.die("rsync of repo '" + repo_name + "' failed") # copy distro files last, since they take the most time cmd = "rsync -rlptgu --exclude=boot.cat --exclude=TRANS.TBL --exclude=isolinux/ %s/ %s/../"\ % (filesource, isolinuxdir) self.logger.info("- copying distro %s files (%s)" % (distname, cmd)) rc = utils.subprocess_call(cmd, shell=True) if rc: utils.die("rsync of distro files failed")
def generate_netboot_iso(self, imagesdir, isolinuxdir, profiles=None, systems=None, exclude_dns: Optional[bool] = None): """ Create bootable CD image to be used for network installations :param imagesdir: Currently unused parameter. :param isolinuxdir: The parent directory where the isolinux.cfg is located. :param profiles: The filter to generate a netboot iso for. You may specify multiple profiles on the CLI space separated. :param systems: The filter to generate a netboot iso for. You may specify multiple systems on the CLI space separated. :param exclude_dns: If this is True then the dns server is skipped. None or False will set it. """ which_profiles = self.filter_systems_or_profiles(profiles, 'profile') which_systems = self.filter_systems_or_profiles(systems, 'system') # setup isolinux.cfg isolinuxcfg = os.path.join(isolinuxdir, "isolinux.cfg") cfg = open(isolinuxcfg, "w+") cfg.write(self.iso_template) # iterate through selected profiles for profile in which_profiles: self.logger.info("processing profile: %s" % profile.name) dist = profile.get_conceptual_parent() distname = self.make_shorter(dist.name) self.copy_boot_files(dist, isolinuxdir, distname) cfg.write("\n") cfg.write("LABEL %s\n" % profile.name) cfg.write(" MENU LABEL %s\n" % profile.name) cfg.write(" kernel %s.krn\n" % distname) data = utils.blender(self.api, False, profile) # SUSE is not using 'text'. Instead 'textmode' is used as kernel option. if dist is not None: utils.kopts_overwrite(data['kernel_options'], self.api.settings().server, dist.breed) if not re.match(r"[a-z]+://.*", data["autoinstall"]): data["autoinstall"] = "http://%s:%s/cblr/svc/op/autoinstall/profile/%s" % ( data["server"], self.api.settings().http_port, profile.name ) append_line = " append initrd=%s.img" % distname if dist.breed == "suse": if "proxy" in data and data["proxy"] != "": append_line += " proxy=%s" % data["proxy"] if "install" in data["kernel_options"] and data["kernel_options"]["install"] != "": v = data["kernel_options"]["install"] if isinstance(v, list): v = v[0] append_line += " install=%s" % v del data["kernel_options"]["install"] else: append_line += " install=http://%s:%s/cblr/links/%s" % ( data["server"], self.api.settings().http_port, dist.name ) if "autoyast" in data["kernel_options"] and data["kernel_options"]["autoyast"] != "": append_line += " autoyast=%s" % data["kernel_options"]["autoyast"] del data["kernel_options"]["autoyast"] else: append_line += " autoyast=%s" % data["autoinstall"] if dist.breed == "redhat": if "proxy" in data and data["proxy"] != "": append_line += " proxy=%s http_proxy=%s" % (data["proxy"], data["proxy"]) append_line += " inst.ks=%s" % data["autoinstall"] if dist.breed in ["ubuntu", "debian"]: append_line += " auto-install/enable=true url=%s" % data["autoinstall"] if "proxy" in data and data["proxy"] != "": append_line += " mirror/http/proxy=%s" % data["proxy"] append_line += self.add_remaining_kopts(data["kernel_options"]) cfg.write(append_line) cfg.write("\nMENU SEPARATOR\n") # iterate through all selected systems for system in which_systems: self.logger.info("processing system: %s" % system.name) profile = system.get_conceptual_parent() dist = profile.get_conceptual_parent() distname = self.make_shorter(dist.name) self.copy_boot_files(dist, isolinuxdir, distname) cfg.write("\n") cfg.write("LABEL %s\n" % system.name) cfg.write(" MENU LABEL %s\n" % system.name) cfg.write(" kernel %s.krn\n" % distname) data = utils.blender(self.api, False, system) if not re.match(r"[a-z]+://.*", data["autoinstall"]): data["autoinstall"] = "http://%s:%s/cblr/svc/op/autoinstall/system/%s" % ( data["server"], self.api.settings().http_port, system.name ) append_line = " append initrd=%s.img" % distname if dist.breed == "suse": if "proxy" in data and data["proxy"] != "": append_line += " proxy=%s" % data["proxy"] if "install" in data["kernel_options"] and data["kernel_options"]["install"] != "": append_line += " install=%s" % data["kernel_options"]["install"] del data["kernel_options"]["install"] else: append_line += " install=http://%s:%s/cblr/links/%s" % ( data["server"], self.api.settings().http_port, dist.name ) if "autoyast" in data["kernel_options"] and data["kernel_options"]["autoyast"] != "": append_line += " autoyast=%s" % data["kernel_options"]["autoyast"] del data["kernel_options"]["autoyast"] else: append_line += " autoyast=%s" % data["autoinstall"] if dist.breed == "redhat": if "proxy" in data and data["proxy"] != "": append_line += " proxy=%s http_proxy=%s" % (data["proxy"], data["proxy"]) append_line += " inst.ks=%s" % data["autoinstall"] if dist.breed in ["ubuntu", "debian"]: append_line += " auto-install/enable=true url=%s netcfg/disable_autoconfig=true" % data["autoinstall"] if "proxy" in data and data["proxy"] != "": append_line += " mirror/http/proxy=%s" % data["proxy"] # hostname is required as a parameter, the one in the preseed is not respected my_domain = "local.lan" if system.hostname != "": # if this is a FQDN, grab the first bit my_hostname = system.hostname.split(".")[0] _domain = system.hostname.split(".")[1:] if _domain: my_domain = ".".join(_domain) else: my_hostname = system.name.split(".")[0] _domain = system.name.split(".")[1:] if _domain: my_domain = ".".join(_domain) # At least for debian deployments configured for DHCP networking this values are not used, but # specifying here avoids questions append_line += " hostname=%s domain=%s" % (my_hostname, my_domain) # A similar issue exists with suite name, as installer requires the existence of "stable" in the dists # directory append_line += " suite=%s" % dist.os_version # Try to add static ip boot options to avoid DHCP (interface/ip/netmask/gw/dns) # Check for overrides first and clear them from kernel_options my_int = None my_ip = None my_mask = None my_gw = None my_dns = None if dist.breed in ["suse", "redhat"]: if "netmask" in data["kernel_options"] and data["kernel_options"]["netmask"] != "": my_mask = data["kernel_options"]["netmask"] del data["kernel_options"]["netmask"] if "gateway" in data["kernel_options"] and data["kernel_options"]["gateway"] != "": my_gw = data["kernel_options"]["gateway"] del data["kernel_options"]["gateway"] if dist.breed == "redhat": if "ksdevice" in data["kernel_options"] and data["kernel_options"]["ksdevice"] != "": my_int = data["kernel_options"]["ksdevice"] if my_int == "bootif": my_int = None del data["kernel_options"]["ksdevice"] if "ip" in data["kernel_options"] and data["kernel_options"]["ip"] != "": my_ip = data["kernel_options"]["ip"] del data["kernel_options"]["ip"] if "dns" in data["kernel_options"] and data["kernel_options"]["dns"] != "": my_dns = data["kernel_options"]["dns"] del data["kernel_options"]["dns"] if dist.breed == "suse": if "netdevice" in data["kernel_options"] and data["kernel_options"]["netdevice"] != "": my_int = data["kernel_options"]["netdevice"] del data["kernel_options"]["netdevice"] if "hostip" in data["kernel_options"] and data["kernel_options"]["hostip"] != "": my_ip = data["kernel_options"]["hostip"] del data["kernel_options"]["hostip"] if "nameserver" in data["kernel_options"] and data["kernel_options"]["nameserver"] != "": my_dns = data["kernel_options"]["nameserver"] del data["kernel_options"]["nameserver"] if dist.breed in ["ubuntu", "debian"]: if "netcfg/choose_interface" in data["kernel_options"] and data["kernel_options"]["netcfg/choose_interface"] != "": my_int = data["kernel_options"]["netcfg/choose_interface"] del data["kernel_options"]["netcfg/choose_interface"] if "netcfg/get_ipaddress" in data["kernel_options"] and data["kernel_options"]["netcfg/get_ipaddress"] != "": my_ip = data["kernel_options"]["netcfg/get_ipaddress"] del data["kernel_options"]["netcfg/get_ipaddress"] if "netcfg/get_netmask" in data["kernel_options"] and data["kernel_options"]["netcfg/get_netmask"] != "": my_mask = data["kernel_options"]["netcfg/get_netmask"] del data["kernel_options"]["netcfg/get_netmask"] if "netcfg/get_gateway" in data["kernel_options"] and data["kernel_options"]["netcfg/get_gateway"] != "": my_gw = data["kernel_options"]["netcfg/get_gateway"] del data["kernel_options"]["netcfg/get_gateway"] if "netcfg/get_nameservers" in data["kernel_options"] and data["kernel_options"]["netcfg/get_nameservers"] != "": my_dns = data["kernel_options"]["netcfg/get_nameservers"] del data["kernel_options"]["netcfg/get_nameservers"] # If no kernel_options overrides are present find the management interface do nothing when zero or multiple # management interfaces are found if my_int is None: mgmt_ints = [] mgmt_ints_multi = [] slave_ints = [] if len(list(data["interfaces"].keys())) >= 1: for (iname, idata) in list(data["interfaces"].items()): if idata["management"] and idata["interface_type"] in ["bond", "bridge"]: # bonded/bridged management interface mgmt_ints_multi.append(iname) if idata["management"] and idata["interface_type"] not in ["bond", "bridge", "bond_slave", "bridge_slave", "bonded_bridge_slave"]: # single management interface mgmt_ints.append(iname) if len(mgmt_ints_multi) == 1 and len(mgmt_ints) == 0: # Bonded/bridged management interface, find a slave interface if eth0 is a slave use that (it's what # people expect) for (iname, idata) in list(data["interfaces"].items()): if idata["interface_type"] in ["bond_slave", "bridge_slave", "bonded_bridge_slave"] and idata["interface_master"] == mgmt_ints_multi[0]: slave_ints.append(iname) if "eth0" in slave_ints: my_int = "eth0" else: my_int = slave_ints[0] # Set my_ip from the bonded/bridged interface here my_ip = data["ip_address_" + data["interface_master_" + my_int]] my_mask = data["netmask_" + data["interface_master_" + my_int]] if len(mgmt_ints) == 1 and len(mgmt_ints_multi) == 0: # Single management interface my_int = mgmt_ints[0] # Lookup tcp/ip configuration data if my_ip is None and my_int is not None: intip = "ip_address_" + my_int if intip in data and data[intip] != "": my_ip = data["ip_address_" + my_int] if my_mask is None and my_int is not None: intmask = "netmask_" + my_int if intmask in data and data[intmask] != "": my_mask = data["netmask_" + my_int] if my_gw is None: if "gateway" in data and data["gateway"] != "": my_gw = data["gateway"] if my_dns is None: if "name_servers" in data and data["name_servers"] != "": my_dns = data["name_servers"] # Add information to the append_line if my_int is not None: intmac = "mac_address_" + my_int if dist.breed == "suse": if intmac in data and data[intmac] != "": append_line += " netdevice=%s" % data["mac_address_" + my_int].lower() else: append_line += " netdevice=%s" % my_int if dist.breed == "redhat": if intmac in data and data[intmac] != "": append_line += " ksdevice=%s" % data["mac_address_" + my_int] else: append_line += " ksdevice=%s" % my_int if dist.breed in ["ubuntu", "debian"]: append_line += " netcfg/choose_interface=%s" % my_int if my_ip is not None: if dist.breed == "suse": append_line += " hostip=%s" % my_ip if dist.breed == "redhat": append_line += " ip=%s" % my_ip if dist.breed in ["ubuntu", "debian"]: append_line += " netcfg/get_ipaddress=%s" % my_ip if my_mask is not None: if dist.breed in ["suse", "redhat"]: append_line += " netmask=%s" % my_mask if dist.breed in ["ubuntu", "debian"]: append_line += " netcfg/get_netmask=%s" % my_mask if my_gw is not None: if dist.breed in ["suse", "redhat"]: append_line += " gateway=%s" % my_gw if dist.breed in ["ubuntu", "debian"]: append_line += " netcfg/get_gateway=%s" % my_gw if exclude_dns is None or my_dns is not None: if dist.breed == "suse": if type(my_dns) == list: append_line += " nameserver=%s" % ",".join(my_dns) else: append_line += " nameserver=%s" % my_dns if dist.breed == "redhat": if type(my_dns) == list: append_line += " dns=%s" % ",".join(my_dns) else: append_line += " dns=%s" % my_dns if dist.breed in ["ubuntu", "debian"]: if type(my_dns) == list: append_line += " netcfg/get_nameservers=%s" % ",".join(my_dns) else: append_line += " netcfg/get_nameservers=%s" % my_dns # Add remaining kernel_options to append_line append_line += self.add_remaining_kopts(data["kernel_options"]) cfg.write(append_line) cfg.write("\n") cfg.write("MENU END\n") cfg.close()
def build_kernel_options(self, system, profile, distro, image, arch, autoinstall_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 list(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()) kopts = utils.revert_strip_none(kopts) # SUSE and other distro specific kernel additions or modificatins utils.kopts_overwrite(system, distro, kopts, self.settings) # 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 (arch == "ppc" or arch == "ppc64"): for intf in list(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['BOOTIF'] = '01-' + mac_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.dict_to_string(kopts) append_line = "%s %s" % (append_line, hkopts) # automatic installation file path rewriting (get URLs for local files) if autoinstall_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"] URL_REGEX = "[a-zA-Z]*://.*" local_autoinstall_file = not re.match(URL_REGEX, autoinstall_path) if local_autoinstall_file: if system is not None: autoinstall_path = "http://%s/cblr/svc/op/autoinstall/system/%s" % (ipaddress, system.name) else: autoinstall_path = "http://%s/cblr/svc/op/autoinstall/profile/%s" % (ipaddress, profile.name) if distro.breed is None or distro.breed == "redhat": append_line += " kssendmac" append_line = "%s ks=%s" % (append_line, autoinstall_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, autoinstall_path) if management_interface: append_line += "netdevice=%s" % management_interface elif distro.breed == "debian" or distro.breed == "ubuntu": append_line = "%s auto-install/enable=true priority=critical netcfg/choose_interface=auto url=%s" % (append_line, autoinstall_path) if management_interface: append_line += " netcfg/choose_interface=%s" % management_interface elif distro.breed == "freebsd": append_line = "%s ks=%s" % (append_line, autoinstall_path) # rework kernel options for debian distros translations = {'ksdevice': "interface", 'lang': "locale"} for k, v in list(translations.items()): 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" % (autoinstall_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, autoinstall_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, autoinstall_path, img_path) return append_line elif distro.breed == "powerkvm": append_line += " kssendmac" append_line = "%s kvmp.inst.auto=%s" % (append_line, autoinstall_path) 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 # promote all of the autoinstall_meta variables if "autoinstall_meta" in blended: blended.update(blended["autoinstall_meta"]) append_line = self.templar.render(append_line, utils.flatten(blended), None) # For now console=ttySx,BAUDRATE are only set for systems # This could get enhanced for profile/distro via utils.blender (inheritance) # This also is architecture specific. E.g: Some ARM consoles need: console=ttyAMAx,BAUDRATE # I guess we need a serial_kernel_dev = param, that can be set to "ttyAMA" if needed. if system: if (system.serial_device is not None) or (system.serial_baud_rate is not None): if system.serial_device: serial_device = system.serial_device else: serial_device = 0 if system.serial_baud_rate: serial_baud_rate = system.serial_baud_rate else: serial_baud_rate = 115200 append_line = "%s console=ttyS%s,%s" % (append_line, serial_device, serial_baud_rate) # FIXME - the append_line length limit is architecture specific if len(append_line) >= 1023: self.logger.warning("warning: kernel option length exceeds 1023") return append_line