def test_find_distro_path(): # Arrange test_api = CobblerAPI() test_manager = CollectionManager(test_api) test_distro = Distro(test_manager) test_distro.kernel = "/dev/shm/fakekernelfile" # Act result = utils.find_distro_path(test_manager.settings(), test_distro) # Assert assert result == "/dev/shm"
def test_find_distro_path(create_testfile, tmp_path): # Arrange test_api = CobblerAPI() fk_kernel = "vmlinuz1" create_testfile(fk_kernel) test_distro = Distro(test_api) test_distro.kernel = os.path.join(tmp_path, fk_kernel) # Act result = utils.find_distro_path(Settings(), test_distro) # Assert assert result == tmp_path.as_posix()
def add_single_distro(self, name): """ Sync adding a single distro. :param name: The name of the distribution. """ # get the distro record distro = self.distros.find(name=name) if distro is None: return # copy image files to images/$name in webdir & tftpboot: self.sync.tftpgen.copy_single_distro_files(distro, self.settings.webdir, True) self.tftpd.add_single_distro(distro) # create the symlink for this distro src_dir = utils.find_distro_path(self.settings, distro) dst_dir = os.path.join(self.settings.webdir, "links", name) if os.path.exists(dst_dir): self.logger.warning("skipping symlink, destination (%s) exists" % dst_dir) elif utils.path_tail( os.path.join(self.settings.webdir, "distro_mirror"), src_dir) == "": self.logger.warning( "skipping symlink, the source (%s) is not in %s" % (src_dir, os.path.join(self.settings.webdir, "distro_mirror"))) else: try: self.logger.info("trying symlink %s -> %s" % (src_dir, dst_dir)) os.symlink(src_dir, dst_dir) except (IOError, OSError): self.logger.error("symlink failed (%s -> %s)" % (src_dir, dst_dir)) # generate any templates listed in the distro self.sync.tftpgen.write_templates(distro, write_file=True) # cascade sync kids = distro.get_children() for k in kids: self.add_single_profile(k.name, rebuild_menu=False) self.sync.tftpgen.make_pxe_menu()
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()
def rename(self, ref: item_base.Item, newname, with_sync: bool = True, with_triggers: bool = True): """ Allows an object "ref" to be given a new name without affecting the rest of the object tree. :param ref: The reference to the object which should be renamed. :param newname: The new name for the object. :param with_sync: If a sync should be triggered when the object is renamed. :param with_triggers: If triggers should be run when the object is renamed. """ # Nothing to do when it is the same name if newname == ref.name: return # make a copy of the object, but give it a new name. oldname = ref.name newref = ref.make_clone() newref.name = newname self.add(newref, with_triggers=with_triggers, save=True) # for mgmt classes, update all objects that use it if ref.COLLECTION_TYPE == "mgmtclass": for what in ["distro", "profile", "system"]: items = self.api.find_items(what, {"mgmt_classes": oldname}) for item in items: for i in range(0, len(item.mgmt_classes)): if item.mgmt_classes[i] == oldname: item.mgmt_classes[i] = newname self.api.add_item(what, item, save=True) # for menus, update all objects that use it if ref.COLLECTION_TYPE == "menu": for what in ["profile", "image"]: items = self.api.find_items(what, {"menu": oldname}) for item in items: item.menu = newname self.api.add_item(what, item, save=True) # for a repo, rename the mirror directory if ref.COLLECTION_TYPE == "repo": path = "/var/www/cobbler/repo_mirror/%s" % ref.name if os.path.exists(path): newpath = "/var/www/cobbler/repo_mirror/%s" % newref.name os.renames(path, newpath) # for a distro, rename the mirror and references to it if ref.COLLECTION_TYPE == 'distro': path = utils.find_distro_path(self.api.settings(), ref) # create a symlink for the new distro name utils.link_distro(self.api.settings(), newref) # Test to see if the distro path is based directly on the name of the distro. If it is, things need to # updated accordingly. if os.path.exists( path ) and path == "/var/www/cobbler/distro_mirror/%s" % ref.name: newpath = "/var/www/cobbler/distro_mirror/%s" % newref.name os.renames(path, newpath) # update any reference to this path ... distros = self.api.distros() for d in distros: if d.kernel.find(path) == 0: d.kernel = d.kernel.replace(path, newpath) d.initrd = d.initrd.replace(path, newpath) self.collection_mgr.serialize_item(self, d) # Now descend to any direct ancestors and point them at the new object allowing the original object to be # removed without orphanage. Direct ancestors will either be profiles or systems. Note that we do have to # care as setting the parent is only really meaningful for subprofiles. We ideally want a more generic parent # setter. kids = ref.get_children() for k in kids: if self.api.find_profile(name=k) is not None: k = self.api.find_profile(name=k) if k.parent != "": k.parent = newname else: k.distro = newname self.api.profiles().add(k, save=True, with_sync=with_sync, with_triggers=with_triggers) elif self.api.find_menu(name=k) is not None: k = self.api.find_menu(name=k) k.parent = newname self.api.menus().add(k, save=True, with_sync=with_sync, with_triggers=with_triggers) elif self.api.find_system(name=k) is not None: k = self.api.find_system(name=k) k.profile = newname self.api.systems().add(k, save=True, with_sync=with_sync, with_triggers=with_triggers) else: raise CX( "Internal error, unknown child type for child \"%s\"!" % k) # now delete the old version self.remove(oldname, with_delete=True, with_triggers=with_triggers) return
def rename(self, ref, newname, with_sync=True, with_triggers=True, logger=None): """ Allows an object "ref" to be given a newname without affecting the rest of the object tree. """ # Nothing to do when it is the same name if newname == ref.name: return # make a copy of the object, but give it a new name. oldname = ref.name newref = ref.make_clone() newref.set_name(newname) self.add(newref, with_triggers=with_triggers, save=True) # for mgmt classes, update all objects that use it if ref.COLLECTION_TYPE == "mgmtclass": for what in ["distro", "profile", "system"]: items = self.api.find_items(what, {"mgmt_classes": oldname}) for item in items: for i in range(0, len(item.mgmt_classes)): if item.mgmt_classes[i] == oldname: item.mgmt_classes[i] = newname self.api.add_item(what, item, save=True) # for a repo, rename the mirror directory if ref.COLLECTION_TYPE == "repo": path = "/var/www/cobbler/repo_mirror/%s" % ref.name if os.path.exists(path): newpath = "/var/www/cobbler/repo_mirror/%s" % newref.name os.renames(path, newpath) # for a distro, rename the mirror and references to it if ref.COLLECTION_TYPE == 'distro': path = utils.find_distro_path(self.api.settings(), ref) # create a symlink for the new distro name utils.link_distro(self.api.settings(), newref) # test to see if the distro path is based directly # on the name of the distro. If it is, things need # to updated accordingly if os.path.exists( path ) and path == "/var/www/cobbler/distro_mirror/%s" % ref.name: newpath = "/var/www/cobbler/distro_mirror/%s" % newref.name os.renames(path, newpath) # update any reference to this path ... distros = self.api.distros() for d in distros: if d.kernel.find(path) == 0: d.set_kernel(d.kernel.replace(path, newpath)) d.set_initrd(d.initrd.replace(path, newpath)) self.collection_mgr.serialize_item(self, d) # now descend to any direct ancestors and point them at the new object allowing # the original object to be removed without orphanage. Direct ancestors # will either be profiles or systems. Note that we do have to care as # set_parent is only really meaningful for subprofiles. We ideally want a more # generic set_parent. kids = ref.get_children() for k in kids: if k.COLLECTION_TYPE == "distro": raise CX( _("internal error, not expected to have distro child objects" )) elif k.COLLECTION_TYPE == "profile": if k.parent != "": k.set_parent(newname) else: k.set_distro(newname) self.api.profiles().add(k, save=True, with_sync=with_sync, with_triggers=with_triggers) elif k.COLLECTION_TYPE == "system": k.set_profile(newname) self.api.systems().add(k, save=True, with_sync=with_sync, with_triggers=with_triggers) elif k.COLLECTION_TYPE == "repo": raise CX( _("internal error, not expected to have repo child objects" )) else: raise CX( _("internal error, unknown child type (%s), cannot finish rename" % k.COLLECTION_TYPE)) # now delete the old version self.remove(oldname, with_delete=True, with_triggers=with_triggers) return