コード例 #1
0
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"
コード例 #2
0
ファイル: utils_test.py プロジェクト: openSUSE/cobbler
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()
コード例 #3
0
    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()
コード例 #4
0
    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()
コード例 #5
0
ファイル: collection.py プロジェクト: openSUSE/cobbler
    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
コード例 #6
0
    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