def __init__(self, collection_mgr, verbose=True, dhcp=None, dns=None, logger=None, tftpd=None): """ Constructor """ self.logger = logger if logger is None: self.logger = clogger.Logger() self.verbose = verbose self.collection_mgr = collection_mgr self.api = collection_mgr.api self.distros = collection_mgr.distros() self.profiles = collection_mgr.profiles() self.systems = collection_mgr.systems() self.settings = collection_mgr.settings() self.repos = collection_mgr.repos() self.templar = templar.Templar(collection_mgr, self.logger) self.tftpgen = tftpgen.TFTPGen(collection_mgr, self.logger) self.dns = dns self.dhcp = dhcp self.tftpd = tftpd self.bootloc = self.settings.tftpboot_location self.tftpgen.verbose = verbose self.dns.verbose = verbose self.dhcp.verbose = verbose self.pxelinux_dir = os.path.join(self.bootloc, "pxelinux.cfg") self.grub_dir = os.path.join(self.bootloc, "grub") self.images_dir = os.path.join(self.bootloc, "images") self.yaboot_bin_dir = os.path.join(self.bootloc, "ppc") self.yaboot_cfg_dir = os.path.join(self.bootloc, "etc") self.rendered_dir = os.path.join(self.settings.webdir, "rendered")
def test_copy_single_distro_files(create_kernel_initrd, fk_initrd, fk_kernel): # Arrange # Create fake files directory = create_kernel_initrd(fk_kernel, fk_initrd) # Create test API test_api = CobblerAPI() # Get Collection Manager used by the API test_collection_mgr = test_api._collection_mgr # Create a test Distro test_distro = Distro(test_api) test_distro.name = "test_copy_single_distro_files" test_distro.kernel = str(os.path.join(directory, fk_kernel)) test_distro.initrd = str(os.path.join(directory, fk_initrd)) # Add test distro to the API test_api.add_distro(test_distro) # Create class under test test_gen = tftpgen.TFTPGen(test_collection_mgr) # Act test_gen.copy_single_distro_files(test_distro, directory, False) # Assert that path created by function under test is actually there result_kernel = os.path.join(directory, "images", test_distro.name, fk_kernel) result_initrd = os.path.join(directory, "images", test_distro.name, fk_initrd) assert os.path.exists(result_kernel) assert os.path.exists(result_initrd)
def sync(self, verbose=True): """ Write out files to /tftpdboot. Mostly unused for the python server :param verbose: This parameter is unused. """ self.logger.info("copying bootloaders") tftpgen.TFTPGen(self.collection_mgr, self.logger).copy_bootloaders(self.bootloc)
def __init__(self, collection_mgr): """ Constructor :param collection_mgr: The collection manager to resolve all information with. """ self.logger = logging.getLogger() self.collection_mgr = collection_mgr self.templar = templar.Templar(collection_mgr) self.tftpgen = tftpgen.TFTPGen(collection_mgr) self.systems = collection_mgr.systems() self.bootloc = collection_mgr.settings().tftpboot_location
def __init__(self, collection_mgr, logger): """ Constructor """ self.logger = logger if self.logger is None: self.logger = clogger.Logger() self.collection_mgr = collection_mgr self.templar = templar.Templar(collection_mgr) self.settings_file = "/etc/xinetd.d/tftp" self.tftpgen = tftpgen.TFTPGen(collection_mgr, self.logger) self.systems = collection_mgr.systems() self.bootloc = utils.tftpboot_location()
def __init__(self, collection_mgr, logger): """ Constructor :param collection_mgr: The collection manager to resolve all information with. :param logger: The logger to audit all actions with. """ self.logger = logger if self.logger is None: self.logger = clogger.Logger() self.collection_mgr = collection_mgr self.templar = templar.Templar(collection_mgr) self.tftpgen = tftpgen.TFTPGen(collection_mgr, self.logger) self.systems = collection_mgr.systems() self.bootloc = collection_mgr.settings().tftpboot_location
def __init__(self, collection_mgr, verbose=True, dhcp=None, dns=None, logger=None, tftpd=None): """ Constructor :param collection_mgr: The collection manager instance which holds all information about cobbler. :param verbose: Whether to log the actions performed in this module verbose or not. :param dhcp: The DHCP manager which can update the DHCP config. :param dns: The DNS manager which can update the DNS config. :param logger: The logger to audit all action with. :param tftpd: The TFTP manager which can update the TFTP config. """ self.logger = logger if logger is None: self.logger = clogger.Logger() self.verbose = verbose self.collection_mgr = collection_mgr self.api = collection_mgr.api self.distros = collection_mgr.distros() self.profiles = collection_mgr.profiles() self.systems = collection_mgr.systems() self.settings = collection_mgr.settings() self.repos = collection_mgr.repos() self.templar = templar.Templar(collection_mgr, self.logger) self.tftpgen = tftpgen.TFTPGen(collection_mgr, self.logger) self.dns = dns self.dhcp = dhcp self.tftpd = tftpd self.bootloc = self.settings.tftpboot_location self.tftpgen.verbose = verbose self.dns.verbose = verbose self.dhcp.verbose = verbose self.pxelinux_dir = os.path.join(self.bootloc, "pxelinux.cfg") self.grub_dir = os.path.join(self.bootloc, "grub") self.images_dir = os.path.join(self.bootloc, "images") self.yaboot_bin_dir = os.path.join(self.bootloc, "ppc") self.yaboot_cfg_dir = os.path.join(self.bootloc, "etc") self.ipxe_dir = os.path.join(self.bootloc, "ipxe") self.rendered_dir = os.path.join(self.settings.webdir, "rendered")
def test_copy_single_distro_file(): # Instantiate TFTPGen class with collection_mgr parameter test_api = CobblerAPI() test_collection_mgr = CollectionManager(test_api) generator = tftpgen.TFTPGen(test_collection_mgr) # Arrange distro_file = "/code/tests/test_data/dummy_initramfs" distro_dir = "/srv/tftpboot/images/" symlink_ok = True initramfs_dst_path = "/srv/tftpboot/images/dummy_initramfs" # Act generator.copy_single_distro_file(distro_file, distro_dir, symlink_ok) # Assert assert os.path.isfile(initramfs_dst_path)
def __init__(self, collection_mgr, verbose: bool = True, dhcp=None, dns=None, tftpd=None): """ Constructor :param collection_mgr: The collection manager instance which holds all information about cobbler. :param verbose: Whether to log the actions performed in this module verbose or not. :param dhcp: The DHCP manager which can update the DHCP config. :param dns: The DNS manager which can update the DNS config. :param tftpd: The TFTP manager which can update the TFTP config. """ self.logger = logging.getLogger() self.verbose = verbose self.collection_mgr = collection_mgr self.api = collection_mgr.api self.distros = collection_mgr.distros() self.profiles = collection_mgr.profiles() self.systems = collection_mgr.systems() self.images = collection_mgr.images() self.settings = collection_mgr.settings() self.repos = collection_mgr.repos() self.templar = templar.Templar(collection_mgr) self.tftpgen = tftpgen.TFTPGen(collection_mgr) self.dns = dns self.dhcp = dhcp self.tftpd = tftpd self.bootloc = self.settings.tftpboot_location self.pxelinux_dir = os.path.join(self.bootloc, "pxelinux.cfg") self.grub_dir = os.path.join(self.bootloc, "grub") self.images_dir = os.path.join(self.bootloc, "images") self.ipxe_dir = os.path.join(self.bootloc, "ipxe") self.rendered_dir = os.path.join(self.settings.webdir, "rendered") self.links = os.path.join(self.settings.webdir, "links") self.distromirror_config = os.path.join(self.settings.webdir, "distro_mirror/config") # FIXME: See https://github.com/cobbler/cobbler/issues/2453 # Move __create_tftpboot_dirs() outside of sync.py. self.__create_tftpboot_dirs()
def test_copy_bootloaders(tmpdir): # Instantiate TFTPGen class with collection_mgr parameter test_api = CobblerAPI() test_collection_mgr = CollectionManager(test_api) generator = tftpgen.TFTPGen(test_collection_mgr) # Arrange ## Create temporary bootloader files using tmpdir fixture file_contents = "I am a bootloader" sub_path = tmpdir.mkdir("loaders") sub_path.join("bootloader1").write(file_contents) sub_path.join("bootloader2").write(file_contents) ## Copy temporary bootloader files from tmpdir to expected source directory for file in glob.glob(str(sub_path + "/*")): bootloader_src = "/var/lib/cobbler/loaders/" shutil.copy(file, bootloader_src + file.split("/")[-1]) # Act generator.copy_bootloaders("/srv/tftpboot") # Assert assert os.path.isfile("/srv/tftpboot/bootloader1") assert os.path.isfile("/srv/tftpboot/bootloader2")
def __init__(self, is_cobblerd=False): """ Constructor """ # FIXME: this should be switchable through some simple system self.__dict__ = CobblerAPI.__shared_state self.perms_ok = False if not CobblerAPI.__has_loaded: # NOTE: we do not log all API actions, because # a simple CLI invocation may call adds and such # to load the config, which would just fill up # the logs, so we'll do that logging at CLI # level (and remote.py web service level) instead. random.seed() self.is_cobblerd = is_cobblerd try: self.logger = clogger.Logger("/var/log/cobbler/cobbler.log") except CX: # return to CLI/other but perms are not valid # perms_ok is False return # FIXME: conslidate into 1 server instance self.selinux_enabled = utils.is_selinux_enabled() self.dist = utils.check_dist() self.os_version = utils.os_release() CobblerAPI.__has_loaded = True # load the modules first, or nothing else works... module_loader.load_modules() self._collection_mgr = collection_manager.CollectionManager(self) self.deserialize() # import signatures try: utils.load_signatures(self.settings().signature_path) except Exception as e: self.log("Failed to load signatures from %s: %s" % (self.settings().signature_path, e)) return self.log("%d breeds and %d OS versions read from the signature file" % ( len(utils.get_valid_breeds()), len(utils.get_valid_os_versions())) ) self.authn = self.get_module_from_file( "authentication", "module", "authn_configfile" ) self.authz = self.get_module_from_file( "authorization", "module", "authz_allowall" ) # FIXME: pass more loggers around, and also see that those # using things via tasks construct their own yumgen/tftpgen # versus reusing this one, which has the wrong logger # (most likely) for background tasks. self.yumgen = yumgen.YumGen(self._collection_mgr) self.tftpgen = tftpgen.TFTPGen(self._collection_mgr, logger=self.logger) self.power_mgr = power_manager.PowerManager(self, self._collection_mgr) self.logger.debug("API handle initialized") self.perms_ok = True
def __init__(self, collection_mgr): super().__init__(collection_mgr) self.tftpgen = tftpgen.TFTPGen(collection_mgr) self.bootloc = collection_mgr.settings().tftpboot_location self.webdir = collection_mgr.settings().webdir
def run(api, args): settings = api.settings() if not settings.windows_enabled: return 0 if not HAS_HIVEX: logger.info( "python3-hivex or python3-pefile not found. If you need Automatic Windows Installation support, " "please install.") return 0 profiles = api.profiles() systems = api.systems() templ = templar.Templar(api._collection_mgr) tgen = tftpgen.TFTPGen(api._collection_mgr) with open( os.path.join(settings.windows_template_dir, post_inst_cmd_template_name)) as template_win: post_tmpl_data = template_win.read() with open( os.path.join(settings.windows_template_dir, answerfile_template_name)) as template_win: tmpl_data = template_win.read() with open( os.path.join(settings.windows_template_dir, startnet_template_name)) as template_start: tmplstart_data = template_start.read() def gen_win_files(distro, meta): (kernel_path, kernel_name) = os.path.split(distro.kernel) distro_path = utils.find_distro_path(settings, distro) distro_dir = wim_file_name = os.path.join(settings.tftpboot_location, "images", distro.name) web_dir = os.path.join(settings.webdir, "images", distro.name) is_winpe = "winpe" in meta and meta['winpe'] != "" is_bcd = "bcd" in meta and meta['bcd'] != "" if "kernel" in meta: kernel_name = meta["kernel"] kernel_name = os.path.basename(kernel_name) is_wimboot = "wimboot" in kernel_name if is_wimboot: distro_path = os.path.join(settings.webdir, "distro_mirror", distro.name) kernel_path = os.path.join(distro_path, "Boot") if "kernel" in meta and "wimboot" not in distro.kernel: tgen.copy_single_distro_file( os.path.join(settings.tftpboot_location, kernel_name), distro_dir, False) tgen.copy_single_distro_file( os.path.join(distro_dir, kernel_name), web_dir, True) if "post_install_script" in meta: post_install_dir = distro_path if distro.os_version not in ("XP", "2003"): post_install_dir = os.path.join(post_install_dir, "sources") post_install_dir = os.path.join(post_install_dir, "$OEM$", "$1") if not os.path.exists(post_install_dir): utils.mkdir(post_install_dir) data = templ.render(post_tmpl_data, meta, None) post_install_script = os.path.join(post_install_dir, meta["post_install_script"]) logger.info('Build post install script: ' + post_install_script) with open(post_install_script, "w+") as pi_file: pi_file.write(data) if "answerfile" in meta: data = templ.render(tmpl_data, meta, None) answerfile_name = os.path.join(distro_dir, meta["answerfile"]) logger.info('Build answer file: ' + answerfile_name) with open(answerfile_name, "w+") as answerfile: answerfile.write(data) tgen.copy_single_distro_file(answerfile_name, distro_path, False) tgen.copy_single_distro_file(answerfile_name, web_dir, True) if "kernel" in meta and "bootmgr" in meta: wk_file_name = os.path.join(distro_dir, kernel_name) wl_file_name = os.path.join(distro_dir, meta["bootmgr"]) tl_file_name = os.path.join(kernel_path, "bootmgr.exe") if distro.os_version in ("XP", "2003") and not is_winpe: tl_file_name = os.path.join(kernel_path, "setupldr.exe") if len(meta["bootmgr"]) != 5: logger.error( "The loader name should be EXACTLY 5 character") return 1 pat1 = re.compile(br'NTLDR', re.IGNORECASE) pat2 = re.compile(br'winnt\.sif', re.IGNORECASE) with open(tl_file_name, 'rb') as file: out = data = file.read() if "answerfile" in meta: if len(meta["answerfile"]) != 9: logger.error( "The response file name should be EXACTLY 9 character" ) return 1 out = pat2.sub(bytes(meta["answerfile"], 'utf-8'), data) else: if len(meta["bootmgr"]) != 11: logger.error( "The Boot manager file name should be EXACTLY 11 character" ) return 1 bcd_name = "bcd" if is_bcd: bcd_name = meta["bcd"] if len(bcd_name) != 3: logger.error( "The BCD file name should be EXACTLY 3 character") return 1 if not os.path.isfile(tl_file_name): logger.error("File not found: %s" % tl_file_name) return 1 pat1 = re.compile(br'bootmgr\.exe', re.IGNORECASE) pat2 = re.compile(br'(\\.B.o.o.t.\\.)(B)(.)(C)(.)(D)', re.IGNORECASE) bcd_name = bytes( "\\g<1>" + bcd_name[0] + "\\g<3>" + bcd_name[1] + "\\g<5>" + bcd_name[2], 'utf-8') with open(tl_file_name, 'rb') as file: out = file.read() if not is_wimboot: logger.info('Patching build Loader: %s' % wl_file_name) out = pat2.sub(bcd_name, out) if tl_file_name != wl_file_name: logger.info('Build Loader: %s from %s' % (wl_file_name, tl_file_name)) with open(wl_file_name, 'wb+') as file: file.write(out) tgen.copy_single_distro_file(wl_file_name, web_dir, True) if not is_wimboot: if distro.os_version not in ("XP", "2003") or is_winpe: pe = pefile.PE(wl_file_name, fast_load=True) pe.OPTIONAL_HEADER.CheckSum = pe.generate_checksum() pe.write(filename=wl_file_name) with open(distro.kernel, 'rb') as file: data = file.read() out = pat1.sub(bytes(meta["bootmgr"], 'utf-8'), data) if wk_file_name != distro.kernel: logger.info("Build PXEBoot: %s from %s" % (wk_file_name, distro.kernel)) with open(wk_file_name, 'wb+') as file: file.write(out) tgen.copy_single_distro_file(wk_file_name, web_dir, True) if is_bcd: obcd_file_name = os.path.join(kernel_path, "bcd") bcd_file_name = os.path.join(distro_dir, meta["bcd"]) wim_file_name = 'winpe.wim' if not os.path.isfile(obcd_file_name): logger.error("File not found: %s" % obcd_file_name) return 1 if is_winpe: wim_file_name = meta["winpe"] if is_wimboot: wim_file_name = '\\Boot\\' + wim_file_name sdi_file_name = '\\Boot\\' + 'boot.sdi' else: wim_file_name = os.path.join("/images", distro.name, wim_file_name) sdi_file_name = os.path.join("/images", distro.name, os.path.basename(distro.initrd)) logger.info('Build BCD: %s from %s for %s' % (bcd_file_name, obcd_file_name, wim_file_name)) bcdedit(obcd_file_name, bcd_file_name, wim_file_name, sdi_file_name) tgen.copy_single_distro_file(bcd_file_name, web_dir, True) if is_winpe: ps_file_name = os.path.join(distro_dir, meta["winpe"]) wim_pl_name = os.path.join(kernel_path, "winpe.wim") cmd = ["/usr/bin/cp", "--reflink=auto", wim_pl_name, ps_file_name] utils.subprocess_call(logger, cmd, shell=False) tgen.copy_single_distro_file(ps_file_name, web_dir, True) if os.path.exists(wimupdate): data = templ.render(tmplstart_data, meta, None) pi_file = tempfile.NamedTemporaryFile() pi_file.write(bytes(data, 'utf-8')) pi_file.flush() cmd = [ wimupdate, ps_file_name, "--command=add " + pi_file.name + " /Windows/System32/startnet.cmd" ] utils.subprocess_call(cmd, shell=False) pi_file.close() for profile in profiles: distro = profile.get_conceptual_parent() if distro and distro.breed == "windows": logger.info('Profile: ' + profile.name) meta = utils.blender(api, False, profile) autoinstall_meta = meta.get("autoinstall_meta", {}) meta.update(autoinstall_meta) gen_win_files(distro, meta) for system in systems: profile = system.get_conceptual_parent() autoinstall_meta = system.autoinstall_meta if not profile or not autoinstall_meta or autoinstall_meta == {}: continue distro = profile.get_conceptual_parent() if distro and distro.breed == "windows": logger.info('System: ' + system.name) meta = utils.blender(api, False, system) gen_win_files(distro, autoinstall_meta) return 0