def calc_kernel_args(self, pd, replace_self=False): kickstart = self.safe_load(pd,'kickstart') options = self.safe_load(pd,'kernel_options',default='') breed = self.safe_load(pd,'breed') kextra = "" if kickstart is not None and kickstart != "": if breed is not None and breed == "suse": kextra = "autoyast=" + kickstart else: kextra = "ks=" + kickstart if options !="": kextra = kextra + " " + options # parser issues? lang needs a trailing = and somehow doesn't have it. # convert the from-cobbler options back to a hash # so that we can override it in a way that works as intended hashv = utils.input_string_or_hash(kextra) if replace_self: hashv["ks"] = "file:ks.cfg" if self.kopts_override is not None: hash2 = utils.input_string_or_hash(self.kopts_override) hashv.update(hash2) options = "" for x in hashv.keys(): if hashv[x] is None: options = options + "%s " % x else: options = options + "%s=%s " % (x, hashv[x]) options = options.replace("lang ","lang= ") return options
def __setattr__(self,name,value): if DEFAULTS.has_key(name): try: if DEFAULTS[name][1] == "str": value = str(value) elif DEFAULTS[name][1] == "int": value = int(value) elif DEFAULTS[name][1] == "bool": if utils.input_boolean(value): value = 1 else: value = 0 elif DEFAULTS[name][1] == "float": value = float(value) elif DEFAULTS[name][1] == "list": value = utils.input_string_or_list(value) elif DEFAULTS[name][1] == "dict": value = utils.input_string_or_hash(value)[1] except: raise AttributeError, "failed to set %s to %s" % (name,str(value)) self.__dict__[name] = value if not utils.update_settings_file(self.to_datastruct()): raise AttributeError, "failed to save the settings file!" return 0 else: raise AttributeError, name
def __setattr__(self, name, value): if name in DEFAULTS: try: if DEFAULTS[name][1] == "str": value = str(value) elif DEFAULTS[name][1] == "int": value = int(value) elif DEFAULTS[name][1] == "bool": if utils.input_boolean(value): value = 1 else: value = 0 elif DEFAULTS[name][1] == "float": value = float(value) elif DEFAULTS[name][1] == "list": value = utils.input_string_or_list(value) elif DEFAULTS[name][1] == "dict": value = utils.input_string_or_hash(value)[1] except: raise AttributeError self.__dict__[name] = value if not utils.update_settings_file(self.to_datastruct()): raise AttributeError return 0 else: raise AttributeError
def __setattr__(self, name, value): if DEFAULTS.has_key(name): try: if DEFAULTS[name][1] == "str": value = str(value) elif DEFAULTS[name][1] == "int": value = int(value) elif DEFAULTS[name][1] == "bool": if utils.input_boolean(value): value = 1 else: value = 0 elif DEFAULTS[name][1] == "float": value = float(value) elif DEFAULTS[name][1] == "list": value = utils.input_string_or_list(value) elif DEFAULTS[name][1] == "dict": value = utils.input_string_or_hash(value)[1] except: raise AttributeError, "failed to set %s to %s" % (name, str(value)) self.__dict__[name] = value utils.update_settings_file(name, value) return 0 else: raise AttributeError, name
def set_params(self, params, inplace=False): (success, value) = utils.input_string_or_hash(params, allow_multiples=True) if not success: raise CX(_("invalid parameters")) else: if inplace: for key in value.keys(): if key.startswith("~"): del self.params[key[1:]] else: self.params[key] = value[key] else: self.params = value return True
def set_params(self,params,inplace=False): (success, value) = utils.input_string_or_hash(params,allow_multiples=True) if not success: raise CX(_("invalid parameters")) else: if inplace: for key in value.keys(): if key.startswith("~"): del self.params[key[1:]] else: self.params[key] = value[key] else: self.params = value return True
def __getattr__(self,name): if self._attributes.has_key(name): if name == "kernel_options": # backwards compatibility -- convert possible string value to hash (success, result) = utils.input_string_or_hash(self._attributes[name], " ",allow_multiples=False) self._attributes[name] = result return result return self._attributes[name] elif DEFAULTS.has_key(name): lookup = DEFAULTS[name] self._attributes[name] = lookup return lookup else: raise AttributeError, name
def set_environment(self,options,inplace=False): """ Yum can take options from the environment. This puts them there before each reposync. """ (success, value) = utils.input_string_or_hash(options,allow_multiples=False) if not success: raise CX(_("invalid environment options")) else: if inplace: for key in value.keys(): self.environment[key] = value[key] else: self.environment = value return True
def set_yumopts(self,options,inplace=False): """ Kernel options are a space delimited list, like 'a=b c=d e=f g h i=j' or a hash. """ (success, value) = utils.input_string_or_hash(options,allow_multiples=False) if not success: raise CX(_("invalid yum options")) else: if inplace: for key in value.keys(): self.yumopts[key] = value[key] else: self.yumopts = value return True
def __getattr__(self, name): try: if name == "kernel_options": # backwards compatibility -- convert possible string value to hash (success, result) = utils.input_string_or_hash(self.__dict__[name], allow_multiples=False) self.__dict__[name] = result return result return self.__dict__[name] except: if name in DEFAULTS: lookup = DEFAULTS[name][0] self.__dict__[name] = lookup return lookup else: raise AttributeError
def __getattr__(self,name): try: if name == "kernel_options": # backwards compatibility -- convert possible string value to hash (success, result) = utils.input_string_or_hash(self.__dict__[name], " ",allow_multiples=False) self.__dict__[name] = result return result return self.__dict__[name] except: if DEFAULTS.has_key(name): lookup = DEFAULTS[name][0] self.__dict__[name] = lookup return lookup else: raise AttributeError, name
def set_environment(self,options,inplace=False): """ Yum can take options from the environment. This puts them there before each reposync. """ (success, value) = utils.input_string_or_hash(options,None,allow_multiples=False) if not success: raise CX(_("invalid environment options")) else: if inplace: for key in value.keys(): self.environment[key] = value[key] else: self.environment = value return True
def set_yumopts(self,options,inplace=False): """ Kernel options are a space delimited list, like 'a=b c=d e=f g h i=j' or a hash. """ (success, value) = utils.input_string_or_hash(options,None,allow_multiples=False) if not success: raise CX(_("invalid yum options")) else: if inplace: for key in value.keys(): self.yumopts[key] = value[key] else: self.yumopts = value return True
def set_fetchable_files(self, fetchable_files, inplace=False): """ A comma seperated list of virt_name=path_to_template that should be fetchable via tftp or a webserver """ (success, value) = utils.input_string_or_hash(fetchable_files, allow_multiples=False) if not success: return False else: if inplace: for key in value.keys(): if key.startswith("~"): del self.fetchable_files[key[1:]] else: self.fetchable_files[key] = value[key] else: self.fetchable_files = value return True
def set_boot_files(self,boot_files,inplace=False): """ A comma seperated list of req_name=source_file_path that should be fetchable via tftp """ (success, value) = utils.input_string_or_hash(boot_files,allow_multiples=inplace) if not success: return False else: if inplace: for key in value.keys(): if key.startswith("~"): del self.boot_files[key[1:]] else: self.boot_files[key] = value[key] else: self.boot_files= value return True
def set_template_files(self,template_files,inplace=False): """ A comma seperated list of source=destination templates that should be generated during a sync. """ (success, value) = utils.input_string_or_hash(template_files,allow_multiples=False) if not success: return False else: if inplace: for key in value.keys(): if key.startswith("~"): del self.template_files[key[1:]] else: self.template_files[key] = value[key] else: self.template_files = value return True
def set_fetchable_files(self,fetchable_files,inplace=False): """ A comma seperated list of virt_name=path_to_template that should be fetchable via tftp or a webserver """ (success, value) = utils.input_string_or_hash(fetchable_files,allow_multiples=inplace) if not success: return False else: if inplace: for key in value.keys(): if key.startswith("~"): del self.fetchable_files[key[1:]] else: self.fetchable_files[key] = value[key] else: self.fetchable_files= value return True
def set_kernel_options_post(self,options,inplace=False): """ Post kernel options are a space delimited list, like 'a=b c=d e=f g h i=j' or a hash. """ (success, value) = utils.input_string_or_hash(options) if not success: raise CX(_("invalid post kernel options")) else: if inplace: for key in value.keys(): if key.startswith("~"): del self.self.kernel_options_post[key[1:]] else: self.kernel_options_post[key] = value[key] else: self.kernel_options_post = value return True
def set_template_files(self,template_files,inplace=False): """ A comma seperated list of source=destination templates that should be generated during a sync. """ (success, value) = utils.input_string_or_hash(template_files,allow_multiples=inplace) if not success: return False else: if inplace: for key in value.keys(): if key.startswith("~"): del self.template_files[key[1:]] else: self.template_files[key] = value[key] else: self.template_files = value return True
def set_kernel_options_post(self,options,inplace=False): """ Post kernel options are a space delimited list, like 'a=b c=d e=f g h i=j' or a hash. """ (success, value) = utils.input_string_or_hash(options,allow_multiples=inplace) if not success: raise CX(_("invalid post kernel options")) else: if inplace: for key in value.keys(): if key.startswith("~"): del self.self.kernel_options_post[key[1:]] else: self.kernel_options_post[key] = value[key] else: self.kernel_options_post = value return True
def set_boot_files(self, boot_files, inplace=False): """ A comma seperated list of req_name=source_file_path that should be fetchable via tftp """ (success, value) = utils.input_string_or_hash(boot_files, allow_multiples=False) if not success: return False else: if inplace: for key in value.keys(): if key.startswith("~"): del self.boot_files[key[1:]] else: self.boot_files[key] = value[key] else: self.boot_files = value return True
def set_ks_meta(self,options,inplace=False): """ A comma delimited list of key value pairs, like 'a=b,c=d,e=f' or a hash. The meta tags are used as input to the templating system to preprocess kickstart files """ (success, value) = utils.input_string_or_hash(options,allow_multiples=False) if not success: return False else: if inplace: for key in value.keys(): if key.startswith("~"): del self.ks_meta[key[1:]] else: self.ks_meta[key] = value[key] else: self.ks_meta = value return True
def set_ks_meta(self,options,inplace=False): """ A comma delimited list of key value pairs, like 'a=b,c=d,e=f' or a hash. The meta tags are used as input to the templating system to preprocess kickstart files """ (success, value) = utils.input_string_or_hash(options,allow_multiples=inplace) if not success: return False else: if inplace: for key in value.keys(): if key.startswith("~"): del self.ks_meta[key[1:]] else: self.ks_meta[key] = value[key] else: self.ks_meta = value return True
def __find_compare(self, from_search, from_obj): if isinstance(from_obj, basestring): # FIXME: fnmatch is only used for string to string comparisions # which should cover most major usage, if not, this deserves fixing if fnmatch.fnmatch(from_obj.lower(), from_search.lower()): return True else: return False else: if isinstance(from_search, basestring): if isinstance(from_obj, list): from_search = utils.input_string_or_list(from_search) for x in from_search: if x not in from_obj: return False return True if isinstance(from_obj, dict): (junk, from_search) = utils.input_string_or_hash( from_search, allow_multiples=True) for x in from_search.keys(): y = from_search[x] if x not in from_obj: return False if not (y == from_obj[x]): # XXX return False return True if isinstance(from_obj, bool): if from_search.lower() in ["true", "1", "y", "yes"]: inp = True else: inp = False if inp == from_obj: return True return False raise CX(_("find cannot compare type: %s") % type(from_obj))
def __find_compare(self, from_search, from_obj): if isinstance(from_obj, basestring): # FIXME: fnmatch is only used for string to string comparisions # which should cover most major usage, if not, this deserves fixing if fnmatch.fnmatch(from_obj.lower(), from_search.lower()): return True else: return False else: if isinstance(from_search, basestring): if type(from_obj) == type([]): from_search = utils.input_string_or_list(from_search) for x in from_search: if x not in from_obj: return False return True if type(from_obj) == type({}): (junk, from_search) = utils.input_string_or_hash(from_search,allow_multiples=True) for x in from_search.keys(): y = from_search[x] if not from_obj.has_key(x): return False if not (y == from_obj[x]): return False return True if type(from_obj) == type(True): if from_search.lower() in [ "true", "1", "y", "yes" ]: inp = True else: inp = False if inp == from_obj: return True return False raise CX(_("find cannot compare type: %s") % type(from_obj))
def write_templates(self,obj,write_file=False,path=None): """ A semi-generic function that will take an object with a template_files hash {source:destiation}, and generate a rendered file. The write_file option allows for generating of the rendered output without actually creating any files. The return value is a hash of the destination file names (after variable substitution is done) and the data in the file. """ self.logger.info("Writing template files for %s" % obj.name) results = {} try: templates = obj.template_files except: return results blended = utils.blender(self.api, False, obj) ksmeta = blended.get("ks_meta",{}) try: del blended["ks_meta"] except: pass blended.update(ksmeta) # make available at top level templates = blended.get("template_files",{}) try: del blended["template_files"] except: pass blended.update(templates) # make available at top level (success, templates) = utils.input_string_or_hash(templates) if not success: return results blended['img_path'] = os.path.join("/images",blended["distro_name"]) blended['local_img_path'] = os.path.join(utils.tftpboot_location(),"images",blended["distro_name"]) for template in templates.keys(): dest = templates[template] if dest is None: continue # Run the source and destination files through # templar first to allow for variables in the path template = self.templar.render(template, blended, None).strip() dest = os.path.normpath(self.templar.render(dest, blended, None).strip()) # Get the path for the destination output dest_dir = os.path.normpath(os.path.dirname(dest)) # If we're looking for a single template, skip if this ones # destination is not it. if not path is None and path != dest: continue # If we are writing output to a file, we allow files tobe # written into the tftpboot directory, otherwise force all # templated configs into the rendered directory to ensure that # a user granted cobbler privileges via sudo can't overwrite # arbitrary system files (This also makes cleanup easier). if os.path.isabs(dest_dir) and write_file: if dest_dir.find(utils.tftpboot_location()) != 0: raise CX(" warning: template destination (%s) is outside %s, skipping." % (dest_dir,utils.tftpboot_location())) continue else: dest_dir = os.path.join(self.settings.webdir, "rendered", dest_dir) dest = os.path.join(dest_dir, os.path.basename(dest)) if not os.path.exists(dest_dir): utils.mkdir(dest_dir) # Check for problems if not os.path.exists(template): raise CX("template source %s does not exist" % template) continue elif write_file and not os.path.isdir(dest_dir): raise CX("template destination (%s) is invalid" % dest_dir) continue elif write_file and os.path.exists(dest): raise CX("template destination (%s) already exists" % dest) continue elif write_file and os.path.isdir(dest): raise CX("template destination (%s) is a directory" % dest) continue elif template == "" or dest == "": raise CX("either the template source or destination was blank (unknown variable used?)" % dest) continue template_fh = open(template) template_data = template_fh.read() template_fh.close() buffer = self.templar.render(template_data, blended, None) results[dest] = buffer if write_file: self.logger.info("generating: %s" % dest) fd = open(dest, "w") fd.write(buffer) fd.close() return results
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