Beispiel #1
0
    def runTest(self):
        handler = KickstartHandler()
        self.assertEqual(str(handler), "")

        handler = KickstartHandler()
        handler.registerCommand('autopart', F23_AutoPart)
        handler.registerCommand('btrfs', F17_BTRFS)
        handler.registerData('BTRFSData', F23_BTRFSData)
        handler.registerData('ZFCPData', F14_ZFCPData)

        self.assertEqual(len(handler.commands.keys()), 2)
        self.assertTrue(isinstance(handler.commands['autopart'], F23_AutoPart))
        self.assertTrue(isinstance(handler.commands['btrfs'], F17_BTRFS))

        self.assertTrue(hasattr(handler, 'BTRFSData'))
        self.assertEqual(getattr(handler, 'BTRFSData'), F23_BTRFSData)
        self.assertTrue(hasattr(handler, 'ZFCPData'))
        self.assertEqual(getattr(handler, 'ZFCPData'), F14_ZFCPData)

        handler = KickstartHandler()
        handler.registerCommand('cdrom', FC3_Cdrom)
        handler.version = F25

        parser = KickstartParser(handler)
        parser.readKickstartFromString("cdrom")
        self.assertEqual(str(handler),
                         "# Use CDROM installation media\ncdrom\n")
Beispiel #2
0
def test_templates(dbo, share_dir):
    """ Try depsolving each of the the templates and report any errors

    :param dbo: dnf base object
    :type dbo: dnf.Base
    :returns: List of template types and errors
    :rtype: List of errors

    Return a list of templates and errors encountered or an empty list
    """
    template_errors = []
    for compose_type in compose_types(share_dir):
        # Read the kickstart template for this type
        ks_template_path = joinpaths(share_dir, "composer",
                                     compose_type) + ".ks"
        ks_template = open(ks_template_path, "r").read()

        # How much space will the packages in the default template take?
        ks_version = makeVersion()
        ks = KickstartParser(ks_version,
                             errorsAreFatal=False,
                             missingIncludeIsFatal=False)
        ks.readKickstartFromString(ks_template + "\n%end\n")
        pkgs = [(name, "*") for name in ks.handler.packages.packageList]
        grps = [grp.name for grp in ks.handler.packages.groupList]
        try:
            _ = projects_depsolve(dbo, pkgs, grps)
        except ProjectsError as e:
            template_errors.append("Error depsolving %s: %s" %
                                   (compose_type, str(e)))

    return template_errors
Beispiel #3
0
    def runTest(self):
        handler = KickstartHandler()
        self.assertEqual(str(handler), "")

        handler = KickstartHandler()
        handler.registerCommand('autopart', F23_AutoPart)
        handler.registerCommand('btrfs', F17_BTRFS)
        handler.registerData('BTRFSData', F23_BTRFSData)
        handler.registerData('ZFCPData', F14_ZFCPData)

        self.assertEqual(len(handler.commands.keys()), 2)
        self.assertTrue(isinstance(handler.commands['autopart'], F23_AutoPart))
        self.assertTrue(isinstance(handler.commands['btrfs'], F17_BTRFS))

        self.assertTrue(hasattr(handler, 'BTRFSData'))
        self.assertEqual(getattr(handler, 'BTRFSData'), F23_BTRFSData)
        self.assertTrue(hasattr(handler, 'ZFCPData'))
        self.assertEqual(getattr(handler, 'ZFCPData'), F14_ZFCPData)

        handler = KickstartHandler()
        handler.registerCommand('cdrom', FC3_Cdrom)
        handler.version = F25

        parser = KickstartParser(handler)
        parser.readKickstartFromString("cdrom")
        self.assertEqual(str(handler), "# Use CDROM installation media\ncdrom\n")
Beispiel #4
0
 def test_no_network(self):
     """Test a kickstart with missing network command"""
     opts = DataHolder(no_virt=True, make_fsimage=False, make_pxe_live=False)
     ks_version = makeVersion()
     ks = KickstartParser(ks_version, errorsAreFatal=False, missingIncludeIsFatal=False)
     ks.readKickstartFromString("url --url=http://dl.fedoraproject.com\n"
                                "part / --size=4096\n"
                                "shutdown\n")
     errors = check_kickstart(ks, opts)
     self.assertTrue("The kickstart must activate networking" in errors[0])
Beispiel #5
0
 def test_disk_size_align(self):
     """Test aligning the disk size"""
     opts = DataHolder(no_virt=True, make_fsimage=False, make_iso=False, make_pxe_live=False, image_size_align=1024)
     ks_version = makeVersion()
     ks = KickstartParser(ks_version, errorsAreFatal=False, missingIncludeIsFatal=False)
     ks.readKickstartFromString("url --url=http://dl.fedoraproject.com\n"
                                "network --bootproto=dhcp --activate\n"
                                "repo --name=other --baseurl=http://dl.fedoraproject.com\n"
                                "part / --size=4096\n"
                                "shutdown\n")
     self.assertEqual(calculate_disk_size(opts, ks), 5120)
Beispiel #6
0
 def test_good_ks_virt(self):
     """Test a good kickstart with virt"""
     opts = DataHolder(no_virt=False, make_fsimage=False, make_pxe_live=False)
     ks_version = makeVersion()
     ks = KickstartParser(ks_version, errorsAreFatal=False, missingIncludeIsFatal=False)
     ks.readKickstartFromString("url --url=http://dl.fedoraproject.com\n"
                                "network --bootproto=dhcp --activate\n"
                                "repo --name=other --baseurl=http://dl.fedoraproject.com\n"
                                "part / --size=4096\n"
                                "shutdown\n")
     self.assertEqual(check_kickstart(ks, opts), [])
Beispiel #7
0
    def runTest(self):

        # F33 has no warnings
        handler = makeVersion(version=F33)
        parser = KickstartParser(handler)
        with warnings.catch_warnings(record=True) as w:
            parser.readKickstartFromString(self.ks)
            self.assertEqual(len(w), 0)

        # F34 warns about deprecation
        with self.assertWarns(KickstartDeprecationWarning):
            self.parser.readKickstartFromString(self.ks)
Beispiel #8
0
 def test_shutdown_virt(self):
     """Test a kickstart with reboot instead of shutdown"""
     opts = DataHolder(no_virt=False, make_fsimage=True, make_pxe_live=False)
     ks_version = makeVersion()
     ks = KickstartParser(ks_version, errorsAreFatal=False, missingIncludeIsFatal=False)
     ks.readKickstartFromString("url --url=http://dl.fedoraproject.com\n"
                                "network --bootproto=dhcp --activate\n"
                                "repo --name=other --baseurl=http://dl.fedoraproject.com\n"
                                "part / --size=4096\n"
                                "reboot\n")
     errors = check_kickstart(ks, opts)
     self.assertTrue("must include shutdown when using virt" in errors[0])
Beispiel #9
0
 def test_autopart(self):
     """Test a kickstart with autopart"""
     opts = DataHolder(no_virt=True, make_fsimage=True, make_pxe_live=False)
     ks_version = makeVersion()
     ks = KickstartParser(ks_version, errorsAreFatal=False, missingIncludeIsFatal=False)
     ks.readKickstartFromString("url --url=http://dl.fedoraproject.com\n"
                                "network --bootproto=dhcp --activate\n"
                                "repo --name=other --baseurl=http://dl.fedoraproject.com\n"
                                "autopart\n"
                                "shutdown\n")
     errors = check_kickstart(ks, opts)
     self.assertTrue("Filesystem images must use a single" in errors[0])
Beispiel #10
0
 def test_nomethod_novirt(self):
     """Test a kickstart with repo and no url"""
     opts = DataHolder(no_virt=True, make_fsimage=False, make_pxe_live=False)
     ks_version = makeVersion()
     ks = KickstartParser(ks_version, errorsAreFatal=False, missingIncludeIsFatal=False)
     ks.readKickstartFromString("network --bootproto=dhcp --activate\n"
                                "repo --name=other --baseurl=http://dl.fedoraproject.com\n"
                                "part / --size=4096\n"
                                "shutdown\n")
     errors = check_kickstart(ks, opts)
     self.assertTrue("Only url, nfs and ostreesetup" in errors[0])
     self.assertTrue("repo can only be used with the url" in errors[1])
Beispiel #11
0
    def runTest(self):
        for version, command_map in control.commandMap.items():

            handler = makeVersion(version)
            parser = KickstartParser(handler)

            for command_name, command_class in command_map.items():
                if not issubclass(command_class, RemovedCommand):
                    continue

                # Make sure that using the removed command raises an error
                with self.assertRaises(KickstartParseError):
                    parser.readKickstartFromString(command_name)
Beispiel #12
0
    def runTest(self):
        for version, command_map in control.commandMap.items():

            handler = makeVersion(version)
            parser = KickstartParser(handler)

            for command_name, command_class in command_map.items():
                if not issubclass(command_class, DeprecatedCommand):
                    continue

                with warnings.catch_warnings(record=True):
                    # The deprecated commands should be ignored with
                    # a warning when they are parsed. Make sure that
                    # they will not cause any errors.
                    parser.readKickstartFromString(command_name)
Beispiel #13
0
    def runTest(self):
        for version, command_map in control.commandMap.items():

            handler = makeVersion(version)
            parser = KickstartParser(handler)

            for command_name, command_class in command_map.items():
                if not issubclass(command_class, DeprecatedCommand):
                    continue

                with warnings.catch_warnings(record=True):
                    # The deprecated commands should be ignored with
                    # a warning when they are parsed. Make sure that
                    # they will not cause any errors.
                    parser.readKickstartFromString(command_name)
Beispiel #14
0
 def displaymode_test(self):
     """Test a kickstart with displaymode set"""
     opts = DataHolder(no_virt=True,
                       make_fsimage=False,
                       make_pxe_live=False)
     ks_version = makeVersion()
     ks = KickstartParser(ks_version,
                          errorsAreFatal=False,
                          missingIncludeIsFatal=False)
     ks.readKickstartFromString(
         "url --url=http://dl.fedoraproject.com\n"
         "network --bootproto=dhcp --activate\n"
         "repo --name=other --baseurl=http://dl.fedoraproject.com\n"
         "part / --size=4096\n"
         "shutdown\n"
         "graphical\n")
     errors = check_kickstart(ks, opts)
     self.assertTrue("must not set a display mode" in errors[0])
Beispiel #15
0
    def runTest(self):
        for version, command_map in control.commandMap.items():

            handler = makeVersion(version)
            parser = KickstartParser(handler)

            for command_name, command_class in command_map.items():
                if not issubclass(command_class, DeprecatedCommand):
                    continue
                if issubclass(command_class, RemovedCommand):
                    continue

                with warnings.catch_warnings(record=True):
                    # The deprecated commands should be ignored with
                    # a warning when they are parsed. Make sure that
                    # they will not cause any errors.
                    with self.assertWarns(KickstartDeprecationWarning) as cm:
                        parser.readKickstartFromString(command_name)

                    # Check the warning message.
                    expected = " {} command has been deprecated ".format(
                        command_name)
                    self.assertIn(expected, str(cm.warning))
Beispiel #16
0
def bootloader_append(line, kernel_append):
    """ Insert the kernel_append string into the --append argument

    :param line: The bootloader ... line
    :type line: str
    :param kernel_append: The arguments to append to the --append section
    :type kernel_append: str

    Using pykickstart to process the line is the best way to make sure it
    is parsed correctly, and re-assembled for inclusion into the final kickstart
    """
    ks_version = makeVersion()
    ks = KickstartParser(ks_version,
                         errorsAreFatal=False,
                         missingIncludeIsFatal=False)
    ks.readKickstartFromString(line)

    if ks.handler.bootloader.appendLine:
        ks.handler.bootloader.appendLine += " %s" % kernel_append
    else:
        ks.handler.bootloader.appendLine = kernel_append

    # Converting back to a string includes a comment, return just the bootloader line
    return str(ks.handler.bootloader).splitlines()[-1]
Beispiel #17
0
def start_build(cfg,
                dnflock,
                gitlock,
                branch,
                recipe_name,
                compose_type,
                test_mode=0):
    """ Start the build

    :param cfg: Configuration object
    :type cfg: ComposerConfig
    :param dnflock: Lock and YumBase for depsolving
    :type dnflock: YumLock
    :param recipe: The recipe to build
    :type recipe: str
    :param compose_type: The type of output to create from the recipe
    :type compose_type: str
    :returns: Unique ID for the build that can be used to track its status
    :rtype: str
    """
    share_dir = cfg.get("composer", "share_dir")
    lib_dir = cfg.get("composer", "lib_dir")

    # Make sure compose_type is valid
    if compose_type not in compose_types(share_dir):
        raise RuntimeError("Invalid compose type (%s), must be one of %s" %
                           (compose_type, compose_types(share_dir)))

    # Some image types (live-iso) need extra packages for composer to execute the output template
    with dnflock.lock:
        extra_pkgs = get_extra_pkgs(dnflock.dbo, share_dir, compose_type)
    log.debug("Extra packages needed for %s: %s", compose_type, extra_pkgs)

    with gitlock.lock:
        (commit_id, recipe) = read_recipe_and_id(gitlock.repo, branch,
                                                 recipe_name)

    # Combine modules and packages and depsolve the list
    module_nver = recipe.module_nver
    package_nver = recipe.package_nver
    package_nver.extend([(name, '*') for name in extra_pkgs])

    projects = sorted(set(module_nver + package_nver),
                      key=lambda p: p[0].lower())
    deps = []
    log.info("depsolving %s", recipe["name"])
    try:
        # This can possibly update repodata and reset the YumBase object.
        with dnflock.lock_check:
            (installed_size,
             deps) = projects_depsolve_with_size(dnflock.dbo,
                                                 projects,
                                                 recipe.group_names,
                                                 with_core=False)
    except ProjectsError as e:
        log.error("start_build depsolve: %s", str(e))
        raise RuntimeError("Problem depsolving %s: %s" %
                           (recipe["name"], str(e)))

    # Read the kickstart template for this type
    ks_template_path = joinpaths(share_dir, "composer", compose_type) + ".ks"
    ks_template = open(ks_template_path, "r").read()

    # How much space will the packages in the default template take?
    ks_version = makeVersion()
    ks = KickstartParser(ks_version,
                         errorsAreFatal=False,
                         missingIncludeIsFatal=False)
    ks.readKickstartFromString(ks_template + "\n%end\n")
    pkgs = [(name, "*") for name in ks.handler.packages.packageList]
    grps = [grp.name for grp in ks.handler.packages.groupList]
    try:
        with dnflock.lock:
            (template_size, _) = projects_depsolve_with_size(
                dnflock.dbo,
                pkgs,
                grps,
                with_core=not ks.handler.packages.nocore)
    except ProjectsError as e:
        log.error("start_build depsolve: %s", str(e))
        raise RuntimeError("Problem depsolving %s: %s" %
                           (recipe["name"], str(e)))
    log.debug("installed_size = %d, template_size=%d", installed_size,
              template_size)

    # Minimum LMC disk size is 1GiB, and anaconda bumps the estimated size up by 10% (which doesn't always work).
    installed_size = int((installed_size + template_size)) * 1.2
    log.debug("/ partition size = %d", installed_size)

    # Create the results directory
    build_id = str(uuid4())
    results_dir = joinpaths(lib_dir, "results", build_id)
    os.makedirs(results_dir)

    # Write the recipe commit hash
    commit_path = joinpaths(results_dir, "COMMIT")
    with open(commit_path, "w") as f:
        f.write(commit_id)

    # Write the original recipe
    recipe_path = joinpaths(results_dir, "blueprint.toml")
    with open(recipe_path, "w") as f:
        f.write(recipe.toml())

    # Write the frozen recipe
    frozen_recipe = recipe.freeze(deps)
    recipe_path = joinpaths(results_dir, "frozen.toml")
    with open(recipe_path, "w") as f:
        f.write(frozen_recipe.toml())

    # Write out the dependencies to the results dir
    deps_path = joinpaths(results_dir, "deps.toml")
    with open(deps_path, "w") as f:
        f.write(toml.dumps({"packages": deps}))

    # Save a copy of the original kickstart
    shutil.copy(ks_template_path, results_dir)

    with dnflock.lock:
        repos = list(dnflock.dbo.repos.iter_enabled())
    if not repos:
        raise RuntimeError("No enabled repos, canceling build.")

    # Create the git rpms, if any, and return the path to the repo under results_dir
    gitrpm_repo = create_gitrpm_repo(results_dir, recipe)

    # Create the final kickstart with repos and package list
    ks_path = joinpaths(results_dir, "final-kickstart.ks")
    with open(ks_path, "w") as f:
        ks_url = repo_to_ks(repos[0], "url")
        log.debug("url = %s", ks_url)
        f.write('url %s\n' % ks_url)
        for idx, r in enumerate(repos[1:]):
            ks_repo = repo_to_ks(r, "baseurl")
            log.debug("repo composer-%s = %s", idx, ks_repo)
            f.write('repo --name="composer-%s" %s\n' % (idx, ks_repo))

        if gitrpm_repo:
            log.debug("repo gitrpms = %s", gitrpm_repo)
            f.write('repo --name="gitrpms" --baseurl="file://%s"\n' %
                    gitrpm_repo)

        # Setup the disk for booting
        # TODO Add GPT and UEFI boot support
        f.write('clearpart --all --initlabel\n')

        # Write the root partition and it's size in MB (rounded up)
        f.write('part / --size=%d\n' % ceil(installed_size / 1024**2))

        # Some customizations modify the template before writing it
        f.write(customize_ks_template(ks_template, recipe))

        for d in deps:
            f.write(dep_nevra(d) + "\n")

        # Include the rpms from the gitrpm repo directory
        if gitrpm_repo:
            for rpm in glob(os.path.join(gitrpm_repo, "*.rpm")):
                f.write(os.path.basename(rpm)[:-4] + "\n")

        f.write("%end\n")

        # Other customizations can be appended to the kickstart
        add_customizations(f, recipe)

    # Setup the config to pass to novirt_install
    log_dir = joinpaths(results_dir, "logs/")
    cfg_args = compose_args(compose_type)

    # Get the title, project, and release version from the host
    if not os.path.exists("/etc/os-release"):
        log.error(
            "/etc/os-release is missing, cannot determine product or release version"
        )
    os_release = flatconfig("/etc/os-release")

    log.debug("os_release = %s", dict(os_release.items()))

    cfg_args["title"] = os_release.get("PRETTY_NAME", "")
    cfg_args["project"] = os_release.get("NAME", "")
    cfg_args["releasever"] = os_release.get("VERSION_ID", "")
    cfg_args["volid"] = ""
    cfg_args["extra_boot_args"] = get_kernel_append(recipe)

    cfg_args.update({
        "compression": "xz",
        "compress_args": [],
        "ks": [ks_path],
        "logfile": log_dir,
        "timeout": 60,  # 60 minute timeout
    })
    with open(joinpaths(results_dir, "config.toml"), "w") as f:
        f.write(toml.dumps(cfg_args))

    # Set the initial status
    open(joinpaths(results_dir, "STATUS"), "w").write("WAITING")

    # Set the test mode, if requested
    if test_mode > 0:
        open(joinpaths(results_dir, "TEST"), "w").write("%s" % test_mode)

    write_timestamp(results_dir, TS_CREATED)
    log.info("Adding %s (%s %s) to compose queue", build_id, recipe["name"],
             compose_type)
    os.symlink(results_dir, joinpaths(lib_dir, "queue/new/", build_id))

    return build_id
Beispiel #18
0
        break

    # All internal commands start with a ., so if that's the beginning of the
    # line, we need to dispatch ourselves.
    if line.startswith("."):
        words = line.split()
        if words[0] in internalCommands:
            try:
                internalCommands[words[0]].execute(ksparser)
            except EOFError:
                # ".quit" was typed, time to quit.
                break
        else:
            print(_("Internal command %s not recognized.") % words[0])

        continue

    # Now process the line of input as if it were a kickstart file - just an
    # extremely short one.
    try:
        ksparser.readKickstartFromString(line)
    except KickstartError as e:
        print(e)

# And finally, print the output kickstart file.
if opts.output:
    with open(opts.output, "w") as fd:
        fd.write(str(ksparser.handler))
else:
    print("\n" + str(ksparser.handler))
Beispiel #19
0
def main():

    ##
    ## OPTION PROCESSING
    ##

    op = argparse.ArgumentParser()
    op.add_argument("-i", "--input", dest="input",
                    help=_("a basis file to use for seeding the kickstart data (optional)"))
    op.add_argument("-o", "--output", dest="output",
                    help=_("the location to write the finished kickstart file, or stdout if not given"))
    op.add_argument("-v", "--version", dest="version", default=DEVEL,
                    help=_("version of kickstart syntax to validate against"))

    opts = op.parse_args(sys.argv[1:])

    ##
    ## SETTING UP PYKICKSTART
    ##

    try:
        kshandler = makeVersion(opts.version)
    except KickstartVersionError:
        print(_("The version %s is not supported by pykickstart") % opts.version)
        sys.exit(1)

    ksparser = KickstartParser(kshandler, followIncludes=True, errorsAreFatal=False)

    if opts.input:
        try:
            processedFile = preprocessKickstart(opts.input)
            ksparser.readKickstart(processedFile)
            os.remove(processedFile)
        except KickstartError as e:
            # Errors should just dump you to the prompt anyway.
            print(_("Warning:  The following error occurred when processing the input file:\n%s\n") % e)

    internalCommands = {".clear": ClearCommand(),
                        ".show": ShowCommand(),
                        ".quit": QuitCommand()}

    ##
    ## SETTING UP READLINE
    ##

    readline.parse_and_bind("tab: complete")
    readline.set_completer(KickstartCompleter(kshandler, internalCommands).complete)

    # Since everything in kickstart looks like a command line arg, we need to
    # remove '-' from the delimiter string.
    delims = readline.get_completer_delims()
    readline.set_completer_delims(delims.replace('-', ''))

    ##
    ## REPL
    ##

    print("Press ^D to exit.")

    while True:
        try:
            line = six.moves.input("ks> ")  # pylint: disable=no-member
        except EOFError:
            # ^D was hit, time to quit.
            break
        except KeyboardInterrupt:
            # ^C was hit, time to quit.  Don't be like other programs.
            break

        # All internal commands start with a ., so if that's the beginning of the
        # line, we need to dispatch ourselves.
        if line.startswith("."):
            words = line.split()
            if words[0] in internalCommands:
                try:
                    internalCommands[words[0]].execute(ksparser)
                except EOFError:
                    # ".quit" was typed, time to quit.
                    break
            else:
                print(_("Internal command %s not recognized.") % words[0])

            continue

        # Now process the line of input as if it were a kickstart file - just an
        # extremely short one.
        try:
            ksparser.readKickstartFromString(line)
        except KickstartError as e:
            print(e)

    # And finally, print the output kickstart file.
    if opts.output:
        with open(opts.output, "w") as fd:
            fd.write(str(ksparser.handler))
    else:
        print("\n" + str(ksparser.handler))
Beispiel #20
0
def start_build(cfg,
                dnflock,
                gitlock,
                branch,
                recipe_name,
                compose_type,
                test_mode=0):
    """ Start the build

    :param cfg: Configuration object
    :type cfg: ComposerConfig
    :param dnflock: Lock and YumBase for depsolving
    :type dnflock: YumLock
    :param recipe: The recipe to build
    :type recipe: str
    :param compose_type: The type of output to create from the recipe
    :type compose_type: str
    :returns: Unique ID for the build that can be used to track its status
    :rtype: str
    """
    share_dir = cfg.get("composer", "share_dir")
    lib_dir = cfg.get("composer", "lib_dir")

    # Make sure compose_type is valid
    if compose_type not in compose_types(share_dir):
        raise RuntimeError("Invalid compose type (%s), must be one of %s" %
                           (compose_type, compose_types(share_dir)))

    with gitlock.lock:
        (commit_id, recipe) = read_recipe_and_id(gitlock.repo, branch,
                                                 recipe_name)

    # Combine modules and packages and depsolve the list
    # TODO include the version/glob in the depsolving
    module_nver = recipe.module_nver
    package_nver = recipe.package_nver
    projects = sorted(set(module_nver + package_nver),
                      key=lambda p: p[0].lower())
    deps = []
    try:
        with dnflock.lock:
            (installed_size,
             deps) = projects_depsolve_with_size(dnflock.dbo,
                                                 projects,
                                                 with_core=False)
    except ProjectsError as e:
        log.error("start_build depsolve: %s", str(e))
        raise RuntimeError("Problem depsolving %s: %s" %
                           (recipe["name"], str(e)))

    # Read the kickstart template for this type
    ks_template_path = joinpaths(share_dir, "composer", compose_type) + ".ks"
    ks_template = open(ks_template_path, "r").read()

    # How much space will the packages in the default template take?
    ks_version = makeVersion()
    ks = KickstartParser(ks_version,
                         errorsAreFatal=False,
                         missingIncludeIsFatal=False)
    ks.readKickstartFromString(ks_template + "\n%end\n")
    ks_projects = [(name, "*") for name in ks.handler.packages.packageList]
    try:
        with dnflock.lock:
            (template_size, _) = projects_depsolve_with_size(
                dnflock.dbo,
                ks_projects,
                with_core=not ks.handler.packages.nocore)
    except ProjectsError as e:
        log.error("start_build depsolve: %s", str(e))
        raise RuntimeError("Problem depsolving %s: %s" %
                           (recipe["name"], str(e)))
    log.debug("installed_size = %d, template_size=%d", installed_size,
              template_size)

    # Minimum LMC disk size is 1GiB, and anaconda bumps the estimated size up by 10% (which doesn't always work).
    # XXX BUT Anaconda has a bug, it won't execute a kickstart on a disk smaller than 3000 MB
    # XXX There is an upstream patch pending, but until then, use that as the minimum
    installed_size = max(3e9, int((installed_size + template_size))) * 1.2
    log.debug("/ partition size = %d", installed_size)

    # Create the results directory
    build_id = str(uuid4())
    results_dir = joinpaths(lib_dir, "results", build_id)
    os.makedirs(results_dir)

    # Write the recipe commit hash
    commit_path = joinpaths(results_dir, "COMMIT")
    with open(commit_path, "w") as f:
        f.write(commit_id)

    # Write the original recipe
    recipe_path = joinpaths(results_dir, "blueprint.toml")
    with open(recipe_path, "w") as f:
        f.write(recipe.toml())

    # Write the frozen recipe
    frozen_recipe = recipe.freeze(deps)
    recipe_path = joinpaths(results_dir, "frozen.toml")
    with open(recipe_path, "w") as f:
        f.write(frozen_recipe.toml())

    # Write out the dependencies to the results dir
    deps_path = joinpaths(results_dir, "deps.toml")
    with open(deps_path, "w") as f:
        f.write(toml.dumps({"packages": deps}))

    # Save a copy of the original kickstart
    shutil.copy(ks_template_path, results_dir)

    with dnflock.lock:
        repos = list(dnflock.dbo.repos.iter_enabled())
    if not repos:
        raise RuntimeError("No enabled repos, canceling build.")

    # Create the final kickstart with repos and package list
    ks_path = joinpaths(results_dir, "final-kickstart.ks")
    with open(ks_path, "w") as f:
        ks_url = repo_to_ks(repos[0], "url")
        log.debug("url = %s", ks_url)
        f.write('url %s\n' % ks_url)
        for idx, r in enumerate(repos[1:]):
            ks_repo = repo_to_ks(r, "baseurl")
            log.debug("repo composer-%s = %s", idx, ks_repo)
            f.write('repo --name="composer-%s" %s\n' % (idx, ks_repo))

        # Write the root partition and it's size in MB (rounded up)
        f.write('part / --fstype="ext4" --size=%d\n' %
                ceil(installed_size / 1024**2))

        f.write(ks_template)

        for d in deps:
            f.write(dep_nevra(d) + "\n")
        f.write("%end\n")

        add_customizations(f, recipe)

    # Setup the config to pass to novirt_install
    log_dir = joinpaths(results_dir, "logs/")
    cfg_args = compose_args(compose_type)

    # Get the title, project, and release version from the host
    if not os.path.exists("/etc/os-release"):
        log.error(
            "/etc/os-release is missing, cannot determine product or release version"
        )
    os_release = SimpleConfigFile("/etc/os-release")
    os_release.read()

    log.debug("os_release = %s", os_release)

    cfg_args["title"] = os_release.get("PRETTY_NAME")
    cfg_args["project"] = os_release.get("NAME")
    cfg_args["releasever"] = os_release.get("VERSION_ID")
    cfg_args["volid"] = ""

    cfg_args.update({
        "compression": "xz",
        "compress_args": [],
        "ks": [ks_path],
        "logfile": log_dir,
        "timeout": 60,  # 60 minute timeout
    })
    with open(joinpaths(results_dir, "config.toml"), "w") as f:
        f.write(toml.dumps(cfg_args))

    # Set the initial status
    open(joinpaths(results_dir, "STATUS"), "w").write("WAITING")

    # Set the test mode, if requested
    if test_mode > 0:
        open(joinpaths(results_dir, "TEST"), "w").write("%s" % test_mode)

    log.info("Adding %s (%s %s) to compose queue", build_id, recipe["name"],
             compose_type)
    os.symlink(results_dir, joinpaths(lib_dir, "queue/new/", build_id))

    return build_id
Beispiel #21
0
        break

    # All internal commands start with a ., so if that's the beginning of the
    # line, we need to dispatch ourselves.
    if line.startswith("."):
        words = line.split()
        if words[0] in internalCommands:
            try:
                internalCommands[words[0]].execute(ksparser)
            except EOFError:
                # ".quit" was typed, time to quit.
                break
        else:
            print(_("Internal command %s not recognized.") % words[0])

        continue

    # Now process the line of input as if it were a kickstart file - just an
    # extremely short one.
    try:
        ksparser.readKickstartFromString(line)
    except KickstartError as e:
        print(e)

# And finally, print the output kickstart file.
if opts.output:
    with open(opts.output, "w") as fd:
        fd.write(str(ksparser.handler))
else:
    print("\n" + str(ksparser.handler))
Beispiel #22
0
def main(argv=None):

    ##
    ## OPTION PROCESSING
    ##

    op = argparse.ArgumentParser()
    op.add_argument("-i", "--input", dest="input",
                    help=_("a basis file to use for seeding the kickstart data (optional)"))
    op.add_argument("-o", "--output", dest="output",
                    help=_("the location to write the finished kickstart file, or stdout if not given"))
    op.add_argument("-v", "--version", dest="version", default=DEVEL,
                    help=_("version of kickstart syntax to validate against"))

    opts = op.parse_args(argv)

    ##
    ## SETTING UP PYKICKSTART
    ##

    try:
        kshandler = makeVersion(opts.version)
    except KickstartVersionError:
        print(_("The version %s is not supported by pykickstart") % opts.version)
        return 1

    ksparser = KickstartParser(kshandler, followIncludes=True, errorsAreFatal=False)

    if opts.input:
        try:
            processedFile = preprocessKickstart(opts.input)
            ksparser.readKickstart(processedFile)
            os.remove(processedFile)
        except KickstartError as e:
            # Errors should just dump you to the prompt anyway.
            print(_("Warning:  The following error occurred when processing the input file:\n%s\n") % e)

    internalCommands = {".clear": ClearCommand(),
                        ".show": ShowCommand(),
                        ".quit": QuitCommand()}

    ##
    ## SETTING UP READLINE
    ##

    readline.parse_and_bind("tab: complete")
    readline.set_completer(KickstartCompleter(kshandler, internalCommands).complete)

    # Since everything in kickstart looks like a command line arg, we need to
    # remove '-' from the delimiter string.
    delims = readline.get_completer_delims()
    readline.set_completer_delims(delims.replace('-', ''))

    ##
    ## REPL
    ##

    print("Press ^D to exit.")

    while True:
        try:
            line = six.moves.input("ks> ")  # pylint: disable=no-member
        except EOFError:
            # ^D was hit, time to quit.
            break
        except KeyboardInterrupt:
            # ^C was hit, time to quit.  Don't be like other programs.
            break

        # All internal commands start with a ., so if that's the beginning of the
        # line, we need to dispatch ourselves.
        if line.startswith("."):
            words = line.split()
            if words[0] in internalCommands:
                try:
                    internalCommands[words[0]].execute(ksparser)
                except EOFError:
                    # ".quit" was typed, time to quit.
                    break
            else:
                print(_("Internal command %s not recognized.") % words[0])

            continue

        # Now process the line of input as if it were a kickstart file - just an
        # extremely short one.
        try:
            ksparser.readKickstartFromString(line)
        except KickstartError as e:
            print(e)

    # And finally, print the output kickstart file.
    if opts.output:
        with open(opts.output, "w") as fd:
            fd.write(str(ksparser.handler))
    else:
        print("\n" + str(ksparser.handler))

    return 0