Ejemplo n.º 1
0
    def test_deserialization(self):

        self.maxDiff = None

        aib = AssemblyInputBundle()
        aib.base.update(["package1", "package2"])
        aib.cache.update(["package3", "package4"])
        aib.system.add("package0")
        aib.kernel.path = "path/to/kernel"
        aib.kernel.args.update(["arg1", "arg2"])
        aib.kernel.clock_backstop = 1234
        aib.boot_args.update(["arg3", "arg4"])
        aib.bootfs_files.add(FileEntry("path/to/source", "path/to/destination"))
        aib.config_data["package1"] = set(
            [FileEntry("path/to/source.json", "config.json")])

        parsed_aib = AssemblyInputBundle.json_loads(
            raw_assembly_input_bundle_json)

        def assert_field_equal(parsed, expected, field_name):
            self.assertEqual(
                getattr(parsed, field_name), getattr(expected, field_name))

        assert_field_equal(parsed_aib, aib, "base")
        assert_field_equal(parsed_aib, aib, "cache")
        assert_field_equal(parsed_aib, aib, "system")
        assert_field_equal(parsed_aib, aib, "kernel")

        assert_field_equal(parsed_aib, aib, "boot_args")
        assert_field_equal(parsed_aib, aib, "bootfs_files")
        assert_field_equal(parsed_aib, aib, "config_data")

        self.assertEqual(parsed_aib, aib)
Ejemplo n.º 2
0
    def test_serialization(self):

        self.maxDiff = None

        aib = AssemblyInputBundle()
        aib.base.update(["package1", "package2"])
        aib.cache.update(["package3", "package4"])
        aib.system.add("package0")
        aib.kernel.path = "path/to/kernel"
        aib.kernel.args.update(["arg1", "arg2"])
        aib.kernel.clock_backstop = 1234
        aib.boot_args.update(["arg3", "arg4"])
        aib.bootfs_files.add(FileEntry("path/to/source", "path/to/destination"))
        aib.config_data["package1"] = set(
            [FileEntry("path/to/source.json", "config.json")])

        self.assertEqual(
            aib.json_dumps(indent=2), raw_assembly_input_bundle_json)
Ejemplo n.º 3
0
def main():
    parser = argparse.ArgumentParser(
        description=
        "Create an image assembly configuration that is what remains after removing the configs to 'subtract'"
    )
    parser.add_argument("--image-assembly-config",
                        type=argparse.FileType('r'),
                        required=True)
    parser.add_argument("--config-data-entries", type=argparse.FileType('r'))
    parser.add_argument("--subtract",
                        default=[],
                        nargs="*",
                        type=argparse.FileType('r'))
    parser.add_argument("--outdir", required=True)
    parser.add_argument("--depfile", type=argparse.FileType('w'))
    parser.add_argument("--export-manifest", type=argparse.FileType('w'))
    args = parser.parse_args()

    # Read in the legacy config and the others to subtract from it
    legacy: ImageAssemblyConfig = ImageAssemblyConfig.json_load(
        args.image_assembly_config)
    subtract = [
        ImageAssemblyConfig.json_load(other) for other in args.subtract
    ]

    # Subtract each from the legacy config, in the order given in args.
    for other in subtract:
        legacy = legacy.difference(other)

    # Read in the config_data entries if available.
    if args.config_data_entries:
        config_data_entries = [
            FileEntry.from_dict(entry)
            for entry in json.load(args.config_data_entries)
        ]
    else:
        config_data_entries = []

    # Create an Assembly Input Bundle from the remaining contents
    (assembly_input_bundle, assembly_config_manifest_path,
     deps) = copy_to_assembly_input_bundle(legacy, config_data_entries,
                                           args.outdir)

    # Write out a fini manifest of the files that have been copied, to create a
    # package or archive that contains all of the files in the bundle.
    if args.export_manifest:
        assembly_input_bundle.write_fini_manifest(args.export_manifest,
                                                  base_dir=args.outdir)

    # Write out a depfile.
    if args.depfile:
        dep_file = DepFile(assembly_config_manifest_path)
        dep_file.update(deps)
        dep_file.write_to(args.depfile)
Ejemplo n.º 4
0
    def test_aib_creator_file_copy_and_package_manifest_relative_paths(self):
        """This tests that the AIBCreator will correctly copy the blobs/* files
           and create the package manifests in the correct location within the
           AIB structure, with package-manifest relative paths to the blobs.

           It also tests that the fini manifest and dep-files contain the
           correct paths.
        """
        # Diffs can be very large for some of these lists, so show the whole
        # thing.
        self.maxDiff = None

        # Mock out the copy routine so it doesn't fail, but we can see the ops
        # it would have made.
        (_, copies) = mock_fast_copy_in(assembly.assembly_input_bundle)

        outdir = tempfile.TemporaryDirectory()

        # save off the current cwd so that it can be restored later.
        curr_cwd = os.getcwd()
        try:
            # Switch into the tempdir to simulate a build environment.
            os.chdir(outdir.name)

            assembly_dir = "my_assembly"
            inputs_dir = "inputs"
            os.mkdir(assembly_dir)
            os.mkdir(inputs_dir)

            # Create two package manifests to use as base packages.  These will
            # be used to validate that blobs are copied to the right places, and
            # that the manifests are re-written correctly in a portable manner.
            some_package_manifest_path = "inputs/some_package_manifest.json"
            some_package_manifest = PackageManifestBuilder(
                "some_package"
            ).manifest_path(some_package_manifest_path).blob(
                path="meta/",
                merkle=
                "0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCDEF",
                source="some/meta.far").fake_blob(11).fake_blob(12).fake_blob(
                    13).build()

            another_package_manifest_path = "inputs/another_package_manifest.json"
            another_package_manifest = PackageManifestBuilder(
                "another_package"
            ).manifest_path(another_package_manifest_path).blob(
                path="meta/",
                merkle=
                "123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCDEF0",
                source="another/meta.far").fake_blob(26).fake_blob(27).build()
            created_manifests = [
                some_package_manifest, another_package_manifest
            ]

            # These are the files, and their sources, that we expect to find
            # copied into the AIB.  The destination paths here are the paths
            # used within the AIB, as that can then be used to compute the path
            # as seen from the cwd (which is what needs to be in the copy and
            # fini manifest operations).
            expected_files = [
                # some_package files
                FileEntry(
                    "some/meta.far",
                    "blobs/0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCDEF"
                ),
                FileEntry(
                    "source/path/for/input_11", f"blobs/{format_merkle(11)}"),
                FileEntry(
                    "source/path/for/input_12", f"blobs/{format_merkle(12)}"),
                FileEntry(
                    "source/path/for/input_13", f"blobs/{format_merkle(13)}"),

                # another_package files
                FileEntry(
                    "another/meta.far",
                    "blobs/123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCDEF0"
                ),
                FileEntry(
                    "source/path/for/input_26", f"blobs/{format_merkle(26)}"),
                FileEntry(
                    "source/path/for/input_27", f"blobs/{format_merkle(27)}")
            ]
            source_package_manifests = [
                some_package_manifest_path, another_package_manifest_path
            ]
            expected_package_manifests = [
                "packages/base/some_package", "packages/base/another_package"
            ]

            # Create the AIBCreator and perform the operation that's under test.
            aib_creator = AIBCreator(assembly_dir)
            aib_creator.base.update(
                [some_package_manifest_path, another_package_manifest_path])
            bundle, bundle_path, deps = aib_creator.build()

            # Verify that the bundle was written to the correct location (and it
            # matches the returned bundle).
            self.assertEqual(
                bundle_path, os.path.join(assembly_dir, "assembly_config.json"))
            with open(bundle_path) as bundle_file:
                parsed_bundle = AssemblyInputBundle.json_load(bundle_file)
                self.assertEqual(parsed_bundle, bundle)

            # Verify that resultant AIB contains the correct base packages.
            self.assertEqual(bundle.base, set(expected_package_manifests))

            # Verify that the package manfiests have been rewritten to use file-
            # relative blob paths into the correct directory.
            def validate_rewritten_package_manifest(
                    path: FilePath, expected: PackageManifest):
                """Parses the PackageManifest at the given path, and compares it
                with the `expected` one.
                """
                with open(path) as package_manifest_file:
                    parsed_manifest = serialization.json_load(
                        PackageManifest, package_manifest_file)

                self.assertEqual(parsed_manifest.package, expected.package)
                self.assertEqual(parsed_manifest.blob_sources_relative, "file")

                # The expected blobs are the passed-in set, but with the source
                # path set to be by merkle in the blobs/ dir of the AIB.
                expected_blobs = [
                    BlobEntry(
                        blob.path, blob.merkle, blob.size,
                        f"../../blobs/{blob.merkle}") for blob in expected.blobs
                ]
                self.assertEqual(parsed_manifest.blobs, expected_blobs)

            for (path, manifest) in zip(expected_package_manifests,
                                        created_manifests):
                validate_rewritten_package_manifest(
                    os.path.join(assembly_dir, path), manifest)

            # Verify that the copies that were performed by the mocked
            # `fast_copy()` fn are correct.
            #
            # The expected copies are the the expected_files, but the
            # destination path is rebased to the cwd (prepending `assembly_dir`)
            #
            expected_copies = [
                rebase_destination(entry, assembly_dir)
                for entry in expected_files
            ]
            self.assertEqual(sorted(copies), sorted(expected_copies))

            # Verify that the deps are correctly reported.
            #
            # All the source paths that files were copied from should be listed,
            # as well as the package manifest paths that were read to create the
            # in-AIB version of the manifests.
            expected_deps = [entry.source for entry in expected_files]
            expected_deps.extend(source_package_manifests)
            self.assertEqual(
                sorted(deps), sorted(expected_deps))  # type: ignore

            # Verify that the fini manifest created (used to create archives of
            # the AIB is correct).
            #
            # The fini manifest contains all the destination paths from
            # expected_files, for both source and destination, but assembly_dir
            # is prepended to all source paths to make them relative to the cwd.

            # Verify that all_file_paths() returns the correct (AIB-relative)
            # files.
            expected_paths = [entry.destination for entry in expected_files]
            expected_paths.extend(expected_package_manifests)
            self.assertEqual(
                sorted(bundle.all_file_paths()),
                sorted(expected_paths))  # type: ignore

            # Created the expected entries from the expected_paths by pre-
            # pending the assembly_dir to create the source path.
            expected_paths.append("assembly_config.json")
            expected_fini_contents = sorted(
                [f"{path}={assembly_dir}/{path}" for path in expected_paths])

            # Write the fini manifest to a string buffer
            fini_file = io.StringIO()
            bundle.write_fini_manifest(fini_file, base_dir=assembly_dir)

            # Parse the written buffer into lines to compare with the expected
            # entries.
            fini_entries = sorted(fini_file.getvalue().splitlines())
            self.assertEqual(fini_entries, expected_fini_contents)

        finally:
            os.chdir(curr_cwd)

            # Clean up the tempdir
            outdir.cleanup()
Ejemplo n.º 5
0
def rebase_destination(entry: FileEntry, path: str) -> FileEntry:
    return FileEntry(entry.source, os.path.join(path, entry.destination))
Ejemplo n.º 6
0
    def test_make_legacy_config(self):
        self.maxDiff = None

        # Patch in a mock for the fast_copy() fn
        fast_copy_mock_fn, copies = mock_fast_copy_in(
            assembly.assembly_input_bundle)

        with tempfile.TemporaryDirectory() as temp_dir_path:
            os.chdir(temp_dir_path)

            source_dir = "source"
            os.mkdir(source_dir)

            # Create an ImageAssembly configuration
            image_assembly = ImageAssemblyConfig()

            # Write out package manifests which are part of the package.
            for package_set in ["base", "cache", "system"]:
                for suffix in ["a", "b"]:
                    package_name = f"{package_set}_{suffix}"
                    manifest = PackageManifest(PackageMetaData(package_name),
                                               [])

                    # Create a few blob entries (that don't need to fully exist)
                    for blob_suffix in ["1", "2", "3"]:
                        blob_name = f"internal/path/file_{suffix}_{blob_suffix}"
                        entry = BlobEntry(
                            blob_name, make_merkle(package_name + blob_name),
                            None,
                            os.path.join(source_dir, package_name, blob_name))
                        manifest.blobs.append(entry)

                    # Write the manifest out to the temp dir
                    manifest_path = os.path.join(source_dir,
                                                 f"{package_name}.json")
                    with open(manifest_path, 'w') as manifest_file:
                        serialization.json_dump(manifest,
                                                manifest_file,
                                                indent=2)

                    # Add to the ImageAssembly in the correct package set.
                    getattr(image_assembly, package_set).add(manifest_path)

            # Add the rest of the fields we expect to see in an image_assembly
            # config.
            image_assembly.boot_args.update(["boot-arg-1", "boot-arg-2"])
            image_assembly.kernel.path = os.path.join(source_dir, "kernel.bin")
            image_assembly.kernel.args.update(["arg1", "arg2"])
            image_assembly.kernel.clock_backstop = 123456
            image_assembly.bootfs_files.update([
                FileEntry(os.path.join(source_dir, "some/file"), "some/file"),
                FileEntry(os.path.join(source_dir, "another/file"),
                          "another/file"),
            ])

            # Create the outdir path, and perform the "copying" into the
            # AssemblyInputBundle.
            outdir = "outdir"
            aib, assembly_config, deps = make_legacy_config.copy_to_assembly_input_bundle(
                image_assembly, [], outdir)

            # Validate the contents of the AssemblyInputBundle itself
            self.assertEqual(
                aib.base, set(["packages/base/base_a",
                               "packages/base/base_b"]))
            self.assertEqual(
                aib.cache,
                set(["packages/cache/cache_a", "packages/cache/cache_b"]))
            self.assertEqual(
                aib.system,
                set(["packages/system/system_a", "packages/system/system_b"]))
            self.assertEqual(aib.boot_args, set(["boot-arg-1", "boot-arg-2"]))
            self.assertEqual(aib.kernel.path, "kernel/kernel.bin")
            self.assertEqual(aib.kernel.args, set(["arg1", "arg2"]))
            self.assertEqual(aib.kernel.clock_backstop, 123456)
            self.assertEqual(
                aib.bootfs_files,
                set([
                    FileEntry(source="bootfs/some/file",
                              destination="some/file"),
                    FileEntry(source="bootfs/another/file",
                              destination="another/file"),
                ]))

            # Make sure all the manifests were created in the correct location.
            for package_set in ["base", "cache", "system"]:
                for suffix in ["a", "b"]:
                    package_name = f"{package_set}_{suffix}"
                    with open(f"outdir/packages/{package_set}/{package_name}"
                              ) as manifest_file:
                        manifest = serialization.json_load(
                            PackageManifest, manifest_file)
                        self.assertEqual(manifest.package.name, package_name)
                        self.assertEqual(
                            set(manifest.blobs_by_path().keys()),
                            set([
                                f'internal/path/file_{suffix}_1',
                                f'internal/path/file_{suffix}_2',
                                f'internal/path/file_{suffix}_3',
                            ]))

            # Spot-check one of the manifests, that it contains the correct
            # source paths to the blobs.
            with open("outdir/packages/base/base_a") as manifest_file:
                manifest = serialization.json_load(PackageManifest,
                                                   manifest_file)
                self.assertEqual(manifest.package.name, "base_a")
                self.assertEqual(len(manifest.blobs), 3)
                blobs = manifest.blobs_by_path()
                self.assertEqual(
                    blobs['internal/path/file_a_1'].source_path,
                    '../../blobs/efac096092f7cf879c72ac51d23d9f142e97405dec7dd9c69aeee81de083f794'
                )
                self.assertEqual(
                    blobs['internal/path/file_a_1'].merkle,
                    'efac096092f7cf879c72ac51d23d9f142e97405dec7dd9c69aeee81de083f794'
                )
                self.assertEqual(
                    blobs['internal/path/file_a_2'].source_path,
                    '../../blobs/bf0c3ae1356b5863258f73a37d555cf878007b8bfe4fd780d74466ec62fe062d'
                )
                self.assertEqual(
                    blobs['internal/path/file_a_2'].merkle,
                    'bf0c3ae1356b5863258f73a37d555cf878007b8bfe4fd780d74466ec62fe062d'
                )
                self.assertEqual(
                    blobs['internal/path/file_a_3'].source_path,
                    '../../blobs/a2e574ccd55c815f0a87c4f27e7a3115fe8e46d41a2e0caf2a91096a41421f78'
                )
                self.assertEqual(
                    blobs['internal/path/file_a_3'].merkle,
                    'a2e574ccd55c815f0a87c4f27e7a3115fe8e46d41a2e0caf2a91096a41421f78'
                )

            # Validate that the deps were correctly identified (all package
            # manifest paths, the blob source paths, the bootfs source paths,
            # and the kernel source path)
            self.assertEqual(
                deps,
                set([
                    'source/base_a.json',
                    'source/base_a/internal/path/file_a_1',
                    'source/base_a/internal/path/file_a_2',
                    'source/base_a/internal/path/file_a_3',
                    'source/base_b.json',
                    'source/base_b/internal/path/file_b_1',
                    'source/base_b/internal/path/file_b_2',
                    'source/base_b/internal/path/file_b_3',
                    'source/cache_a.json',
                    'source/cache_a/internal/path/file_a_1',
                    'source/cache_a/internal/path/file_a_2',
                    'source/cache_a/internal/path/file_a_3',
                    'source/cache_b.json',
                    'source/cache_b/internal/path/file_b_1',
                    'source/cache_b/internal/path/file_b_2',
                    'source/cache_b/internal/path/file_b_3',
                    'source/system_a.json',
                    'source/system_a/internal/path/file_a_1',
                    'source/system_a/internal/path/file_a_2',
                    'source/system_a/internal/path/file_a_3',
                    'source/system_b.json',
                    'source/system_b/internal/path/file_b_1',
                    'source/system_b/internal/path/file_b_2',
                    'source/system_b/internal/path/file_b_3',
                    'source/kernel.bin', 'source/some/file',
                    'source/another/file'
                ]))

            # Validate that all the files were correctly copied to the
            # correct paths in the AIB.
            self.assertEqual(
                set(copies),
                set([
                    FileEntry(
                        source='source/base_a/internal/path/file_a_1',
                        destination=
                        'outdir/blobs/efac096092f7cf879c72ac51d23d9f142e97405dec7dd9c69aeee81de083f794'
                    ),
                    FileEntry(
                        source='source/base_a/internal/path/file_a_1',
                        destination=
                        'outdir/blobs/efac096092f7cf879c72ac51d23d9f142e97405dec7dd9c69aeee81de083f794'
                    ),
                    FileEntry(
                        source='source/base_a/internal/path/file_a_2',
                        destination=
                        'outdir/blobs/bf0c3ae1356b5863258f73a37d555cf878007b8bfe4fd780d74466ec62fe062d'
                    ),
                    FileEntry(
                        source='source/base_a/internal/path/file_a_3',
                        destination=
                        'outdir/blobs/a2e574ccd55c815f0a87c4f27e7a3115fe8e46d41a2e0caf2a91096a41421f78'
                    ),
                    FileEntry(
                        source='source/base_b/internal/path/file_b_1',
                        destination=
                        'outdir/blobs/ae9fd81e1c2fd1b084ec2c362737e812c5ef9b3aa8cb0538ec8e2269ea7fbe1a'
                    ),
                    FileEntry(
                        source='source/base_b/internal/path/file_b_2',
                        destination=
                        'outdir/blobs/d3cd38c4881c3bc31f1e2e397a548d431a6430299785446f28be10cc5b76d92b'
                    ),
                    FileEntry(
                        source='source/base_b/internal/path/file_b_3',
                        destination=
                        'outdir/blobs/6468d9d6761c8afcc97744dfd9e066f29bb697a9a0c8248b5e6eec989134a048'
                    ),
                    FileEntry(
                        source='source/cache_a/internal/path/file_a_1',
                        destination=
                        'outdir/blobs/f0601d51be1ec8c11d825b756841937706eb2805ce9b924b67b4b0dc14caba29'
                    ),
                    FileEntry(
                        source='source/cache_a/internal/path/file_a_2',
                        destination=
                        'outdir/blobs/1834109a42a5ff6501fbe05216475b2b0acc44e0d9c94924469a485d6f45dc86'
                    ),
                    FileEntry(
                        source='source/cache_a/internal/path/file_a_3',
                        destination=
                        'outdir/blobs/0f32059964674afd810001c76c2a5d783a2ce012c41303685ec1adfdb83290fd'
                    ),
                    FileEntry(
                        source='source/cache_b/internal/path/file_b_1',
                        destination=
                        'outdir/blobs/301e8584305e63f0b764daf52dcf312eecb6378b201663fcc77d7ad68aab1f23'
                    ),
                    FileEntry(
                        source='source/cache_b/internal/path/file_b_2',
                        destination=
                        'outdir/blobs/8135016519df51d386efaea9b02f50cb454b6c7afe69c77895c1d4d844c3584d'
                    ),
                    FileEntry(
                        source='source/cache_b/internal/path/file_b_3',
                        destination=
                        'outdir/blobs/b548948fd2dc40574775308a92a8330e5c5d84ddf31513d1fe69964b458479e7'
                    ),
                    FileEntry(
                        source='source/system_a/internal/path/file_a_1',
                        destination=
                        'outdir/blobs/8ca898b1389c58b6cd9a6a777e320f2756ab3437b402c61d774dd2758ad9cf06'
                    ),
                    FileEntry(
                        source='source/system_a/internal/path/file_a_2',
                        destination=
                        'outdir/blobs/ef84c6711eaba482164fe4eb08a6c45f18fe62d493e5a31a631c32937bf7229d'
                    ),
                    FileEntry(
                        source='source/system_a/internal/path/file_a_3',
                        destination=
                        'outdir/blobs/d66cb673257e25393a319fb2c3e9745ef6e0f1cfa4fb89c5576df73cd3eba586'
                    ),
                    FileEntry(
                        source='source/system_b/internal/path/file_b_1',
                        destination=
                        'outdir/blobs/fd0891d15ce65d7682f7437e441e917b8ed4bde4db07a11dc100104f25056051'
                    ),
                    FileEntry(
                        source='source/system_b/internal/path/file_b_2',
                        destination=
                        'outdir/blobs/c244c7c6ebf40a9a4c9d59e7b08a1cf54ae3d60404d1cecb417a7b55cc308d91'
                    ),
                    FileEntry(
                        source='source/system_b/internal/path/file_b_3',
                        destination=
                        'outdir/blobs/0cdbf3e4f1246ce7522e78c21bcf1c3aef2d41ac2b4de3f0ee98fc6273f62eb9'
                    ),
                    FileEntry(source='source/kernel.bin',
                              destination='outdir/kernel/kernel.bin'),
                    FileEntry(source='source/some/file',
                              destination='outdir/bootfs/some/file'),
                    FileEntry(source='source/another/file',
                              destination='outdir/bootfs/another/file'),
                ]))