Exemplo n.º 1
0
def main():
    parser = argparse.ArgumentParser(
        description="Build operating system images")
    parser.add_argument(
        "pipeline_path",
        metavar="PIPELINE",
        help="json file containing the pipeline that should be built")
    parser.add_argument(
        "--build-pipeline",
        metavar="PIPELINE",
        type=os.path.abspath,
        help="json file containing the pipeline to create a build environment")
    parser.add_argument(
        "--store",
        metavar="DIRECTORY",
        type=os.path.abspath,
        default=".osbuild/store",
        help="the directory where intermediary os trees are stored")
    parser.add_argument(
        "-l",
        "--libdir",
        metavar="DIRECTORY",
        type=os.path.abspath,
        help=
        "the directory containing stages, assemblers, and the osbuild library")
    requiredNamed = parser.add_argument_group('required named arguments')
    requiredNamed.add_argument(
        "-o",
        "--output",
        dest="output_dir",
        metavar="DIRECTORY",
        type=os.path.abspath,
        help="provide the empty DIRECTORY as output argument to the last stage",
        required=True)
    args = parser.parse_args()

    with open(args.pipeline_path) as f:
        pipeline = osbuild.load(json.load(f))

    if args.build_pipeline:
        with open(args.build_pipeline) as f:
            build = osbuild.load(json.load(f))
        pipeline.prepend_build_pipeline(build)

    try:
        pipeline.run(args.output_dir,
                     args.store,
                     interactive=True,
                     libdir=args.libdir)
    except KeyboardInterrupt:
        print()
        print(f"{RESET}{BOLD}{RED}Aborted{RESET}")
        sys.exit(130)
    except (osbuild.StageFailed, osbuild.AssemblerFailed) as error:
        print()
        print(
            f"{RESET}{BOLD}{RED}{error.name} failed with code {error.returncode}{RESET}"
        )
        sys.exit(1)
Exemplo n.º 2
0
def main():
    parser = argparse.ArgumentParser(description="Build operating system images")
    parser.add_argument("pipeline_path", metavar="PIPELINE",
                        help="json file containing the pipeline that should be built, or a '-' to read from stdin")
    parser.add_argument("--build-pipeline", metavar="PIPELINE", type=os.path.abspath,
                        help="json file containing the pipeline to create a build environment")
    parser.add_argument("--store", metavar="DIRECTORY", type=os.path.abspath,
                        default=".osbuild",
                        help="the directory where intermediary os trees are stored")
    parser.add_argument("-l", "--libdir", metavar="DIRECTORY", type=os.path.abspath,
                        help="the directory containing stages, assemblers, and the osbuild library")
    parser.add_argument("--json", action="store_true",
                        help="output results in JSON format")
    args = parser.parse_args()

    if args.pipeline_path == "-":
        f = sys.stdin
    else:
        f = open(args.pipeline_path)
    pipeline = osbuild.load(json.load(f))
    f.close()

    if args.build_pipeline:
        with open(args.build_pipeline) as f:
            build = osbuild.load(json.load(f))
        pipeline.prepend_build_pipeline(build)

    try:
        pipeline.run(args.store, interactive=not args.json, libdir=args.libdir)
    except KeyboardInterrupt:
        print()
        print(f"{RESET}{BOLD}{RED}Aborted{RESET}")
        return 130
    except (osbuild.StageFailed, osbuild.AssemblerFailed) as error:
        print()
        print(f"{RESET}{BOLD}{RED}{error.name} failed with code {error.returncode}{RESET}")
        if args.json:
            print(error.output)
        return 1

    if args.json:
        json.dump({
            "tree_id": pipeline.tree_id,
            "output_id": pipeline.output_id,
        }, sys.stdout)
        sys.stdout.write("\n")
    else:
        print("tree id:", pipeline.tree_id)
        print("output id:", pipeline.output_id)

    return 0
Exemplo n.º 3
0
    def test_canonical(self):
        """Degenerate case. Make sure we always return the same canonical
        description when passing empty or null values."""

        cases = [
            {},
            {"assembler": None},
            {"stages": []},
            {"build": {}},
            {"build": None}
        ]
        for pipeline in cases:
            with self.subTest(pipeline):
                self.assertEqual(osbuild.load(pipeline, {}).description(), {})
Exemplo n.º 4
0
    def treeid_from_manifest(manifest_data):
        """Calculate Tree ID

        This takes an in-memory manifest, inspects it, and returns the ID of
        the final tree of the stage-array. This returns `None` if no stages
        are defined.
        """

        manifest_json = json.loads(manifest_data)
        manifest_pipeline = manifest_json.get("pipeline", {})
        manifest_sources = manifest_json.get("sources", {})

        manifest_parsed = osbuild.load(manifest_pipeline, manifest_sources)
        return manifest_parsed.tree_id
Exemplo n.º 5
0
    def run_osbuild(self, pipeline, input=None):
        osbuild_cmd = ["python3", "-m", "osbuild", "--json", "--store", self.store, "--libdir", ".", pipeline]

        build_env = os.getenv("OSBUILD_TEST_BUILD_ENV", None)
        if build_env:
            osbuild_cmd.append("--build-env")
            osbuild_cmd.append(build_env)

        # Create a checkpoint at the last stage, i.e.
        # commit the final tree to the store, so that
        # tests can use it to compare against
        if input:
            manifest = json.loads(input)
        else:
            with open(pipeline, "r") as f:
                manifest = json.load(f)

        parsed = osbuild.load(manifest.get("pipeline", {}), manifest.get("sources", {}))
        if parsed.tree_id:
            osbuild_cmd.append("--checkpoint")
            osbuild_cmd.append(parsed.tree_id)

        stdin = subprocess.PIPE if input else None

        p = subprocess.Popen(osbuild_cmd, encoding="utf-8", stdin=stdin, stdout=subprocess.PIPE)
        try:
            output, _ = p.communicate(input)
            if p.returncode != 0:
                print(output)
            self.assertEqual(p.returncode, 0)
        except KeyboardInterrupt:
            # explicitly wait again to let osbuild clean up
            p.wait()
            raise

        result = json.loads(output)
        return result.get("tree_id"), result.get("output_id")
Exemplo n.º 6
0
def osbuild_cli():
    args = parse_arguments(sys.argv)
    manifest = parse_manifest(args.manifest_path)

    # first thing after parsing is validation of the input
    index = osbuild.meta.Index(args.libdir)
    res = osbuild.meta.validate(manifest, index)
    if not res:
        if args.json or args.inspect:
            json.dump(res.as_dict(), sys.stdout)
            sys.stdout.write("\n")
        else:
            show_validation(res, args.manifest_path)
        return 2

    pipeline = manifest.get("pipeline", {})
    sources_options = manifest.get("sources", {})

    if args.sources:
        with open(args.sources) as f:
            sources_options = json.load(f)

    pipeline = osbuild.load(pipeline, sources_options)

    if args.checkpoint:
        missed = mark_checkpoints(pipeline, args.checkpoint)
        if missed:
            for checkpoint in missed:
                print(f"Checkpoint {BOLD}{checkpoint}{RESET} not found!")
            print(f"{RESET}{BOLD}{RED}Failed{RESET}")
            return 1

    if args.inspect:
        result = {"pipeline": pipeline.description(with_id=True)}
        if sources_options:
            result["sources"] = sources_options
        json.dump(result, sys.stdout)
        sys.stdout.write("\n")
        return 0

    if not args.output_directory and not args.checkpoint:
        print("No output directory or checkpoints specified, exited without building.")
        return 0

    monitor_name = "NullMonitor" if args.json else "LogMonitor"
    monitor = osbuild.monitor.make(monitor_name, sys.stdout.fileno())

    try:
        r = pipeline.run(
            args.store,
            monitor,
            args.libdir,
            output_directory=args.output_directory
        )
    except KeyboardInterrupt:
        print()
        print(f"{RESET}{BOLD}{RED}Aborted{RESET}")
        return 130

    if args.json:
        json.dump(r, sys.stdout)
        sys.stdout.write("\n")
    else:
        if r["success"]:
            print("tree id:", pipeline.tree_id)
            print("output id:", pipeline.output_id)
        else:
            print()
            print(f"{RESET}{BOLD}{RED}Failed{RESET}")

    sys.exit(0 if r["success"] else 1)
Exemplo n.º 7
0
def main():
    parser = argparse.ArgumentParser(description="Build operating system images")
    parser.add_argument("pipeline_path", metavar="PIPELINE",
                        help="json file containing the pipeline that should be built, or a '-' to read from stdin")
    parser.add_argument("--build-env", metavar="FILE", type=os.path.abspath,
                        help="json file containing a description of the build environment")
    parser.add_argument("--store", metavar="DIRECTORY", type=os.path.abspath,
                        default=".osbuild",
                        help="directory where intermediary os trees are stored")
    parser.add_argument("--sources", metavar="FILE", type=os.path.abspath,
                        help="json file containing a dictionary of source configuration")
    parser.add_argument("--secrets", metavar="FILE", type=os.path.abspath,
                        help="json file containing a dictionary of secrets that are passed to sources")
    parser.add_argument("-l", "--libdir", metavar="DIRECTORY", type=os.path.abspath,
                        help="the directory containing stages, assemblers, and the osbuild library")
    parser.add_argument("--checkpoint", metavar="ID", action="append", type=str, default=None,
                        help="stage to commit to the object store during build (can be passed multiple times)")
    parser.add_argument("--json", action="store_true",
                        help="output results in JSON format")
    args = parser.parse_args()

    if args.pipeline_path == "-":
        f = sys.stdin
    else:
        f = open(args.pipeline_path)
    manifest = json.load(f)
    f.close()

    if "pipeline" in manifest:
        pipeline = manifest["pipeline"]
        sources_options = manifest.get("sources", {})
    else:
        # backwards compatibility
        pipeline = manifest
        sources_options = {}

    if args.sources:
        with open(args.sources) as f:
            sources_options = json.load(f)

    pipeline = osbuild.load(pipeline, sources_options)

    if args.build_env:
        with open(args.build_env) as f:
            build_pipeline, runner = osbuild.load_build(json.load(f), sources_options)
        pipeline.prepend_build_env(build_pipeline, runner)

    secrets = {}
    if args.secrets:
        with open(args.secrets) as f:
            secrets = json.load(f)

    if args.checkpoint:
        missed = mark_checkpoints(pipeline, args.checkpoint)
        if missed:
            for checkpoint in missed:
                print(f"Checkpoint {BOLD}{checkpoint}{RESET} not found!")
            print(f"{RESET}{BOLD}{RED}Failed{RESET}")
            return 1

    try:
        r = pipeline.run(
            args.store,
            interactive=not args.json,
            libdir=args.libdir,
            secrets=secrets
        )
    except KeyboardInterrupt:
        print()
        print(f"{RESET}{BOLD}{RED}Aborted{RESET}")
        return 130

    if args.json:
        json.dump(r, sys.stdout)
        sys.stdout.write("\n")
    else:
        if r["success"]:
            print("tree id:", pipeline.tree_id)
            print("output id:", pipeline.output_id)
        else:
            print()
            print(f"{RESET}{BOLD}{RED}Failed{RESET}")

    return 0 if r["success"] else 1