Blame tools/test-case-generators/generate-test-cases

Packit 63bb0d
#!/usr/bin/python3
Packit 63bb0d
Packit 63bb0d
import argparse
Packit 63bb0d
import subprocess
Packit 63bb0d
import json
Packit 63bb0d
import os
Packit 63bb0d
import sys
Packit 63bb0d
import tempfile
Packit 63bb0d
Packit 63bb0d
Packit 63bb0d
def get_subprocess_stdout(*args, **kwargs):
Packit 63bb0d
    sp = subprocess.run(*args, **kwargs, stdout=subprocess.PIPE)
Packit 63bb0d
    if sp.returncode != 0:
Packit 63bb0d
        sys.stderr.write(sp.stdout)
Packit 63bb0d
        sys.exit(1)
Packit 63bb0d
Packit 63bb0d
    return sp.stdout
Packit 63bb0d
Packit 63bb0d
Packit Service 15f37d
def run_osbuild(manifest, store, output, export):
Packit 63bb0d
    with tempfile.TemporaryFile(dir="/tmp", prefix="osbuild-test-case-generator-", suffix=".log") as log:
Packit 63bb0d
        try:
Packit 63bb0d
            subprocess.run(["osbuild",
Packit 63bb0d
                            "--store", store,
Packit 63bb0d
                            "--output-directory", output,
Packit Service 15f37d
                            "--checkpoint", "build"
Packit Service 15f37d
                            "--export", export,
Packit 63bb0d
                            "-"],
Packit 63bb0d
                            stdout=log,
Packit 63bb0d
                            stderr=subprocess.STDOUT,
Packit 63bb0d
                            check=True,
Packit 63bb0d
                            encoding="utf-8",
Packit 63bb0d
                            input=json.dumps(manifest))
Packit 63bb0d
        except:
Packit 63bb0d
            log.seek(0)
Packit 63bb0d
            print(log.read())
Packit 63bb0d
            raise
Packit 63bb0d
Packit 63bb0d
Packit 63bb0d
class TestCaseGenerator:
Packit 63bb0d
    '''
Packit 63bb0d
    This class generates a json test case. It accepts a test_case_request as input to the constructor:
Packit 63bb0d
Packit 63bb0d
    {
Packit 63bb0d
        "boot": {
Packit 63bb0d
            "type": "qemu"
Packit 63bb0d
        },
Packit 63bb0d
        "compose-request": {
Packit 63bb0d
            "distro": "fedora-30",
Packit 63bb0d
            "arch": "x86_64",
Packit 63bb0d
            "image-type": "qcow2",
Packit 63bb0d
            "filename": "disk.qcow2",
Packit 63bb0d
            "blueprint": {}
Packit 63bb0d
        }
Packit 63bb0d
    }
Packit 63bb0d
Packit 63bb0d
    It then outputs a json test case from the get_test_case() method.
Packit 63bb0d
    '''
Packit 63bb0d
Packit 63bb0d
    def __init__(self, test_case_request):
Packit 63bb0d
        self.test_case = test_case_request
Packit 63bb0d
Packit 63bb0d
    def get_test_case(self, no_image_info, store):
Packit 63bb0d
        compose_request = json.dumps(self.test_case["compose-request"])
Packit 63bb0d
Packit 63bb0d
        pipeline_command = ["go", "run", "./cmd/osbuild-pipeline", "-"]
Packit 63bb0d
        self.test_case["manifest"] = json.loads(get_subprocess_stdout(pipeline_command, input=compose_request, encoding="utf-8"))
Packit 63bb0d
Packit 63bb0d
        pipeline_command = ["go", "run", "./cmd/osbuild-pipeline", "-rpmmd", "-"]
Packit 63bb0d
        self.test_case["rpmmd"] = json.loads(get_subprocess_stdout(pipeline_command, input=compose_request, encoding="utf-8"))
Packit 63bb0d
Packit 63bb0d
        if no_image_info == False:
Packit 63bb0d
            with tempfile.TemporaryDirectory(dir=store, prefix="test-case-output-") as output:
Packit Service 15f37d
                manifest = self.test_case["manifest"]
Packit Service 15f37d
                version = manifest.get("version", "1")
Packit Service 15f37d
                if version == "1":
Packit Service 15f37d
                    export = "assembler"
Packit Service 15f37d
                elif version == "2":
Packit Service 15f37d
                    export = manifest["pipelines"][-1]["name"]
Packit Service 15f37d
                else:
Packit Service 15f37d
                    print(f"Unknown manifest format version {version}")
Packit Service 15f37d
                    sys.exit(1)
Packit Service 15f37d
                run_osbuild(manifest, store, output, export)
Packit Service 15f37d
                image_file = os.path.join(output, export, self.test_case["compose-request"]["filename"])
Packit 63bb0d
                image_info = get_subprocess_stdout(["tools/image-info", image_file], encoding="utf-8")
Packit 63bb0d
                self.test_case["image-info"] = json.loads(image_info)
Packit 63bb0d
Packit 63bb0d
        return self.test_case
Packit 63bb0d
Packit 63bb0d
Packit 63bb0d
def generate_test_case(test_type, distro, arch, output_format, test_case_request, keep_image_info, store, output):
Packit 63bb0d
    print(f"generating test case for {output_format}")
Packit 63bb0d
    generator = TestCaseGenerator(test_case_request)
Packit 63bb0d
    test_case = generator.get_test_case(keep_image_info, store)
Packit 63bb0d
    name = distro.replace("-", "_") + "-" + arch + "-" + output_format.replace("-", "_") + "-" + test_type + ".json"
Packit 63bb0d
    file_name = output + "/" + name
Packit 63bb0d
    if keep_image_info:
Packit 63bb0d
        try:
Packit 63bb0d
            with open(file_name, 'r') as case_file:
Packit 63bb0d
                old_test_case = json.load(case_file)
Packit 63bb0d
                image_info = old_test_case.get("image-info")
Packit 63bb0d
                if image_info:
Packit 63bb0d
                    test_case["image-info"] = image_info
Packit 63bb0d
        except:
Packit 63bb0d
            pass
Packit 63bb0d
    with open(file_name, 'w') as case_file:
Packit 63bb0d
        json.dump(test_case, case_file, indent=2)
Packit Service 15f37d
        case_file.write("\n")
Packit 63bb0d
Packit 63bb0d
Packit 63bb0d
CUSTOMIZATIONS_BLUEPRINT =  {
Packit 63bb0d
    "packages": [
Packit 63bb0d
        {
Packit 63bb0d
            "name": "bash",
Packit 63bb0d
            "version": "*"
Packit 63bb0d
        }
Packit 63bb0d
    ],
Packit 63bb0d
    "groups": [
Packit 63bb0d
        {
Packit 63bb0d
            "name": "core"
Packit 63bb0d
        }
Packit 63bb0d
    ],
Packit 63bb0d
    "customizations": {
Packit Service bcdfb1
        "hostname": "my-host",
Packit 63bb0d
        "kernel": {
Packit 63bb0d
            "append": "debug"
Packit 63bb0d
        },
Packit 63bb0d
        "sshkey": [
Packit 63bb0d
            {
Packit 63bb0d
                "user": "user1",
Packit 63bb0d
                "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC61wMCjOSHwbVb4VfVyl5sn497qW4PsdQ7Ty7aD6wDNZ/QjjULkDV/yW5WjDlDQ7UqFH0Sr7vywjqDizUAqK7zM5FsUKsUXWHWwg/ehKg8j9xKcMv11AkFoUoujtfAujnKODkk58XSA9whPr7qcw3vPrmog680pnMSzf9LC7J6kXfs6lkoKfBh9VnlxusCrw2yg0qI1fHAZBLPx7mW6+me71QZsS6sVz8v8KXyrXsKTdnF50FjzHcK9HXDBtSJS5wA3fkcRYymJe0o6WMWNdgSRVpoSiWaHHmFgdMUJaYoCfhXzyl7LtNb3Q+Sveg+tJK7JaRXBLMUllOlJ6ll5Hod root@localhost"
Packit 63bb0d
            }
Packit 63bb0d
        ],
Packit 63bb0d
        "user": [
Packit 63bb0d
            {
Packit 63bb0d
                "name": "user2",
Packit 63bb0d
                "description": "description 2",
Packit 63bb0d
                "password": "$6$BhyxFBgrEFh0VrPJ$MllG8auiU26x2pmzL4.1maHzPHrA.4gTdCvlATFp8HJU9UPee4zCS9BVl2HOzKaUYD/zEm8r/OF05F2icWB0K/",
Packit 63bb0d
                "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC61wMCjOSHwbVb4VfVyl5sn497qW4PsdQ7Ty7aD6wDNZ/QjjULkDV/yW5WjDlDQ7UqFH0Sr7vywjqDizUAqK7zM5FsUKsUXWHWwg/ehKg8j9xKcMv11AkFoUoujtfAujnKODkk58XSA9whPr7qcw3vPrmog680pnMSzf9LC7J6kXfs6lkoKfBh9VnlxusCrw2yg0qI1fHAZBLPx7mW6+me71QZsS6sVz8v8KXyrXsKTdnF50FjzHcK9HXDBtSJS5wA3fkcRYymJe0o6WMWNdgSRVpoSiWaHHmFgdMUJaYoCfhXzyl7LtNb3Q+Sveg+tJK7JaRXBLMUllOlJ6ll5Hod root@localhost",
Packit 63bb0d
                "home": "/home/home2",
Packit 63bb0d
                "shell": "/bin/sh",
Packit 63bb0d
                "groups": [
Packit 63bb0d
                    "group1"
Packit 63bb0d
                ],
Packit 63bb0d
                "uid": 1020,
Packit 63bb0d
                "gid": 1050,
Packit 63bb0d
            }
Packit 63bb0d
        ],
Packit 63bb0d
        "group": [
Packit 63bb0d
            {
Packit 63bb0d
                "name": "group1",
Packit 63bb0d
                "gid": 1030
Packit 63bb0d
            },
Packit 63bb0d
            {
Packit 63bb0d
                "name": "group2",
Packit 63bb0d
                "gid": 1050
Packit 63bb0d
            }
Packit 63bb0d
        ],
Packit 63bb0d
        "timezone": {
Packit 63bb0d
            "timezone": "Europe/London",
Packit 63bb0d
            "ntpservers": [
Packit 63bb0d
                "time.example.com"
Packit 63bb0d
            ]
Packit 63bb0d
        },
Packit 63bb0d
        "locale": {
Packit 63bb0d
            "languages": [
Packit Service 15f37d
                "el_CY.UTF-8"
Packit 63bb0d
            ],
Packit 63bb0d
            "keyboard": "dvorak"
Packit 63bb0d
        },
Packit 63bb0d
#       "firewall": {
Packit 63bb0d
#           "ports": [
Packit 63bb0d
#               "25:tcp"
Packit 63bb0d
#           ],
Packit 63bb0d
#           "services": {
Packit 63bb0d
#               "enabled": [
Packit 63bb0d
#                   "cockpit"
Packit 63bb0d
#               ],
Packit 63bb0d
#               "disabled": [
Packit 63bb0d
#                   "ssh"
Packit 63bb0d
#               ]
Packit 63bb0d
#           }
Packit 63bb0d
#       },
Packit 63bb0d
        "services": {
Packit 63bb0d
            "enabled": [
Packit 63bb0d
                "sshd.socket"
Packit 63bb0d
            ],
Packit 63bb0d
            "disabled": [
Packit 63bb0d
                "bluetooth.service"
Packit 63bb0d
            ]
Packit 63bb0d
        }
Packit 63bb0d
    }
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
Packit 63bb0d
def main(distro, arch, image_types, keep_image_info, store, output, with_customizations):
Packit 63bb0d
    with open("tools/test-case-generators/format-request-map.json") as format_request_json:
Packit 63bb0d
        format_request_dict = json.load(format_request_json)
Packit 63bb0d
    with open("tools/test-case-generators/repos.json") as repos_json:
Packit 63bb0d
        repos_dict = json.load(repos_json)
Packit 63bb0d
Packit 63bb0d
    # Apply all customizations from the CUSTOMIZATIONS_BLUEPRINT dictionary
Packit 63bb0d
    if with_customizations:
Packit 63bb0d
        if len(image_types) > 1 or image_types[0] != "qcow2":
Packit 63bb0d
            print("Customizations are only available for qcow2 image type")
Packit 63bb0d
            sys.exit(1)
Packit 63bb0d
Packit 63bb0d
        test_case_request = {
Packit 63bb0d
            "compose-request": {
Packit 63bb0d
                "distro": distro,
Packit 63bb0d
                "arch": arch,
Packit 63bb0d
                "repositories": repos_dict[distro][arch],
Packit 63bb0d
                "image-type": "qcow2",
Packit 63bb0d
                "filename": "disk.qcow2",
Packit 63bb0d
                "blueprint": CUSTOMIZATIONS_BLUEPRINT,
Packit 63bb0d
            }
Packit 63bb0d
        }
Packit 63bb0d
        generate_test_case("customize", distro, arch, "qcow2", test_case_request, keep_image_info, store, output)
Packit 63bb0d
        return
Packit 63bb0d
Packit 63bb0d
    for output_format, test_case_request in format_request_dict.items():
Packit Service 509fd4
        filtered_request = dict(filter(lambda i: i[0] != "overrides", test_case_request.items()))
Packit Service 509fd4
        if filtered_request["compose-request"]["image-type"] not in image_types:
Packit 63bb0d
                continue
Packit Service 509fd4
        filtered_request["compose-request"]["distro"] = distro
Packit Service 509fd4
        filtered_request["compose-request"]["arch"] = arch
Packit Service 509fd4
        filtered_request["compose-request"]["repositories"] = repos_dict[distro][arch]
Packit Service 509fd4
Packit Service 509fd4
        if distro in test_case_request["overrides"]:
Packit Service 3a6627
            filtered_request["compose-request"].update(test_case_request["overrides"][distro])
Packit Service 509fd4
Packit Service 509fd4
        generate_test_case("boot", distro, arch, output_format, filtered_request, keep_image_info, store, output)
Packit Service 509fd4
Packit 63bb0d
    return
Packit 63bb0d
Packit 63bb0d
Packit 63bb0d
if __name__ == '__main__':
Packit 63bb0d
    parser = argparse.ArgumentParser(description="Generate test cases")
Packit 63bb0d
    parser.add_argument("--distro", help="distribution for test cases", required=True)
Packit 63bb0d
    parser.add_argument("--arch", help="architecture for test cases", required=True)
Packit 63bb0d
    parser.add_argument("--image-types", help="image types for test cases", required=True, nargs='+')
Packit 63bb0d
    parser.add_argument("--keep-image-info", action='store_true', help="skip image info (re)generation, but keep the one found in the existing test case")
Packit 63bb0d
    parser.add_argument("--store", metavar="STORE_DIRECTORY", type=os.path.abspath, help="path to the osbuild store", required=True)
Packit 63bb0d
    parser.add_argument("--output", metavar="OUTPUT_DIRECTORY", type=os.path.abspath, help="path to the output directory", required=True)
Packit 63bb0d
    parser.add_argument("--with-customizations", action='store_true', help="apply all currently supported customizations to the image (qcow2 only)")
Packit 63bb0d
    args = parser.parse_args()
Packit 63bb0d
Packit 63bb0d
    main(args.distro, args.arch, args.image_types, args.keep_image_info, args.store, args.output, args.with_customizations)
Packit 63bb0d
    sys.exit()