diff --git a/provider/bootc_image_builder/bootc_image_build_utils.py b/provider/bootc_image_builder/bootc_image_build_utils.py index 5d369fbd46..932807cff2 100644 --- a/provider/bootc_image_builder/bootc_image_build_utils.py +++ b/provider/bootc_image_builder/bootc_image_build_utils.py @@ -14,6 +14,7 @@ import os import random import shutil +import subprocess import time import textwrap import pathlib @@ -65,13 +66,16 @@ def podman_command_build(bib_image_url, disk_image_type, image_ref, config=None, os.makedirs("/var/lib/libvirt/images/output") cmd = "sudo podman run --rm -it --privileged --pull=newer --security-opt label=type:unconfined_t -v /var/lib/libvirt/images/output:/output" if config: - cmd += " -v %s:/config.json " % config + if "toml" in config: + cmd += " -v %s:/config.toml " % config + else: + cmd += " -v %s:/config.json " % config if local_container: cmd += " -v /var/lib/containers/storage:/var/lib/containers/storage " if options is not None: - cmd += " -v %s:/run/containers/0/auth.json " % options + cmd += " %s " % options if key_store_mounted: cmd += " -v %s " % key_store_mounted @@ -83,7 +87,10 @@ def podman_command_build(bib_image_url, disk_image_type, image_ref, config=None, " --type %s --tls-verify=%s " % (bib_image_url, disk_image_type, tls_verify) if config: - cmd += " --config /config.json " + if "toml" in config: + cmd += " --config /config.toml " + else: + cmd += " --config /config.json " if target_arch: cmd += " --target-arch=%s " % target_arch @@ -173,6 +180,19 @@ def create_config_json_file(params): password = params.get("os_password") kickstart = "yes" == params.get("kickstart") public_key_path = os.path.join(os.path.expanduser("~/.ssh/"), "id_rsa.pub") + filesystem_size_set = "yes" == params.get("filesystem_size_set") + + filesystem_dict = {"filesystem": [ + { + "mountpoint": "/", + "minsize": "10 GiB" + }, + { + "mountpoint": "/var/data", + "minsize": "15 GiB" + } + ] + } if not os.path.exists(public_key_path): LOG.debug("public key doesn't exist, will help create one") key_gen_cmd = "ssh-keygen -q -t rsa -N '' <<< $'\ny' >/dev/null 2>&1" @@ -222,12 +242,93 @@ def create_config_json_file(params): } } + if filesystem_size_set: + cfg['blueprint']['customizations'].update(filesystem_dict) + LOG.debug("what is cfg:%s", cfg) config_json_path = pathlib.Path(folder) / "config.json" config_json_path.write_text(json.dumps(cfg), encoding="utf-8") return os.path.join(folder, "config.json") +def create_config_toml_file(params): + """ + create toml configuration file + + :param params: one dictionary to pass in configuration + """ + folder = params.get("config_file_path") + username = params.get("os_username") + password = params.get("os_password") + kickstart = "yes" == params.get("kickstart") + public_key_path = os.path.join(os.path.expanduser("~/.ssh/"), "id_rsa.pub") + filesystem_size_set = "yes" == params.get("filesystem_size_set") + filesystem_size_str = "" + fips_content = "" + + if not os.path.exists(public_key_path): + LOG.debug("public key doesn't exist, will help create one") + key_gen_cmd = "ssh-keygen -q -t rsa -N '' <<< $'\ny' >/dev/null 2>&1" + process.run(key_gen_cmd, shell=True, ignore_status=False) + + with open(public_key_path, 'r') as ssh: + key_value = ssh.read().rstrip() + + if filesystem_size_set: + filesystem_size_str = f""" + [[customizations.filesystem]] + mountpoint = "/" + minsize = "10 GiB" + + [[customizations.filesystem]] + mountpoint = "/var/data" + minsize = "20 GiB" + """ + if not kickstart: + container_file_content = f"""\n + [[customizations.user]] + name = "{username}" + password = "{password}" + key = "{key_value}" + groups = ["wheel"] + {filesystem_size_str} + [customizations.kernel] + append = "mitigations=auto,nosmt" + """ + else: + kick_start = {"contents": "user --name %s --password %s --groups wheel\n" + "rootpw --lock --iscrypted locked\n" + "sshkey --username %s \"%s\"\ntext --non-interactive\nzerombr\n" + "clearpart --all --initlabel --disklabel=gpt\nautopart --noswap --type=lvm\n" + "network --bootproto=dhcp --device=eno1 --activate --onboot=on\n reboot" % (username, password, username, key_value) + } + if params.get("fips_enable") == "yes": + fips_content = f""" + [customizations] + fips = true + """ + + container_file_content = f"""\n + [customizations.kernel] + append = "mitigations=auto,nosmt" + {fips_content} + [customizations.installer.modules] + enable = [ + "org.fedoraproject.Anaconda.Modules.Localization" + ] + disable = [ + "org.fedoraproject.Anaconda.Modules.Timezone" + ] + {filesystem_size_str} + [customizations.installer.kickstart] + contents = \"""{kick_start.get("contents")}\""" + """ + LOG.debug("what is toml content:%s", container_file_content) + config_toml_path = pathlib.Path(folder) / "config.toml" + config_toml_path.write_text(textwrap.dedent(container_file_content), encoding="utf8") + return os.path.join(folder, "config.toml") + + def create_auth_json_file(params): """ create authentication json configuration file @@ -235,18 +336,18 @@ def create_auth_json_file(params): :param params: one dictionary to pass in configuration """ folder = params.get("config_file_path") - redhat_registry = params.get("redhat_registry") - registry_key = params.get("registry_key") + redhat_stage_registry = params.get("redhat_stage_registry") + registry_stage_key = params.get("registry_stage_key") cfg = { "auths": { - "%s" % redhat_registry: { - "auth": "%s" % registry_key + "%s" % redhat_stage_registry: { + "auth": "%s" % registry_stage_key } } } - LOG.debug("what is auth cfg:%s", cfg) + LOG.debug("what is auth json:%s", cfg) config_json_path = pathlib.Path(folder) / "auth.json" config_json_path.write_text(json.dumps(cfg), encoding="utf-8") final_config_file = os.path.join(folder, "auth.json") @@ -279,9 +380,12 @@ def create_and_build_container_file(params): folder = params.get("container_base_folder") build_container = params.get("build_container") container_tag = params.get("container_url") + manifest = params.get("manifest") # clean up existed image clean_image_cmd = "sudo podman rmi %s" % container_tag + if manifest: + clean_image_cmd = "sudo podman manifest rm %s" % container_tag process.run(clean_image_cmd, shell=True, ignore_status=True) etc_config = '' dnf_vmware_tool = '' @@ -299,7 +403,7 @@ def create_and_build_container_file(params): "examples/-/raw/main/vmware/etc/vmware-tools/tools.conf > %s/tools.conf" % vmware_tool_path process.run(download_vmware_config_cmd, shell=True, verbose=True, ignore_status=True) - if params.get("fips_enable") == "yes": + if params.get("fips_enable") == "yes" and params.get("enable_fips_enable_repo") == "yes": dnf_fips_install = "RUN cat > /usr/lib/bootc/kargs.d/01-fips.toml <<'EOF'\n" \ "kargs = ['fips=1']\n" \ "match-architectures = ['x86_64']\n" \ @@ -308,8 +412,10 @@ def create_and_build_container_file(params): "update-crypto-policies --no-reload --set FIPS " container_path = pathlib.Path(folder) / "Containerfile_tmp" - shutil.copy("/etc/yum.repos.d/beaker-BaseOS.repo", folder) - shutil.copy("/etc/yum.repos.d/beaker-AppStream.repo", folder) + if os.path.exists("/etc/yum.repos.d/beaker-BaseOS.repo"): + shutil.copy("/etc/yum.repos.d/beaker-BaseOS.repo", folder) + if os.path.exists("/etc/yum.repos.d/beaker-AppStream.repo"): + shutil.copy("/etc/yum.repos.d/beaker-AppStream.repo", folder) create_sudo_file = "RUN echo '%wheel ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/wheel-passwordless-sudo" enable_root_ssh = "RUN echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config.d/01-permitrootlogin.conf" @@ -332,6 +438,9 @@ def create_and_build_container_file(params): if "rhel-9.5" in custom_repo: repo_path = pathlib.Path(folder) / "rhel-9.5.repo" repo_prefix = "rhel-9.5" + if "rhel-9.6" in custom_repo: + repo_path = pathlib.Path(folder) / "rhel-9.6.repo" + repo_prefix = "rhel-9.6" if "rhel-10.0" in custom_repo: repo_path = pathlib.Path(folder) / "rhel-10.0.repo" repo_prefix = "rhel-10.0" @@ -382,9 +491,16 @@ def create_and_build_container_file(params): {dnf_fips_install} Run dnf clean all """ + build_cmd = "sudo podman build -t %s -f %s" % (container_tag, str(container_path)) + if manifest: + container_file_content = f"""\n + FROM {build_container} + {create_sudo_file} + {enable_root_ssh} + """ + build_cmd = "sudo podman build --platform linux/arm64,linux/amd64 --manifest %s -f %s" % (manifest, str(container_path)) container_path.write_text(textwrap.dedent(container_file_content), encoding="utf8") - build_cmd = "sudo podman build -t %s -f %s" % (container_tag, str(container_path)) process.run(build_cmd, shell=True, ignore_status=False) @@ -774,7 +890,12 @@ def create_qemu_vm(params, env, test): vm = env.get_vm(vm_name) if vm.is_dead(): LOG.debug("VM is dead, starting") - vm.start() + # workaround VM can not start in the first time on rhel10 + try: + vm.start() + except Exception as ex: + LOG.debug("start vm in retries") + vm.start() ip_address = vm.wait_for_get_address(nic_index=0) params.update({"ip_address": ip_address.strip()}) remote_vm_obj = verify_ssh_login_vm(params) @@ -814,7 +935,9 @@ def prepare_aws_env(params): create_aws_secret_file(aws_secret_folder, aws_access_key_id, aws_access_key) aws_utils.create_aws_credentials_file(aws_access_key_id, aws_access_key) aws_utils.create_aws_config_file(aws_region) - aws_utils.install_aws_cli_tool(params) + vm_arch_name = params.get("vm_arch_name", "x86_64") + if "s390x" not in vm_arch_name: + aws_utils.install_aws_cli_tool(params) def cleanup_aws_env(params): @@ -838,6 +961,249 @@ def cleanup_aws_ami_and_snapshot(params): aws_utils.delete_aws_ami_snapshot_id(params) +def convert_vhd_to_qcow2(params): + """ + Convert vhd disk format into qcow2 + + @param params: one dictionary wrapping various parameter + :return: Converted image path + """ + original_image_path = params.get('vm_disk_image_path') + converted_image_path = original_image_path.replace("vhd", "qcow2") + LOG.debug(f"converted vhd to qcow2 output is : {converted_image_path}") + + convert_cmd = f"qemu-img convert -p -f vpc -O qcow2 {original_image_path} {converted_image_path}" + process.run(convert_cmd, shell=True, verbose=True, ignore_status=False) + return converted_image_path + + +def untar_tgz_to_raw(params): + """ + extract image.tgz for GCP format to raw format:disk.raw + + @param params: one dictionary wrapping various parameter + """ + original_image_path = params.get('vm_disk_image_path') + tar_image_folder = os.path.dirname(original_image_path) + untar_image_path = os.path.join(tar_image_folder, "disk.raw") + LOG.debug(f"untar image.tgz to gce output is : {tar_image_folder}") + + tar_cmd = f"tar -xvzf {original_image_path} -C {tar_image_folder}" + process.run(tar_cmd, shell=True, verbose=True, ignore_status=False) + return untar_image_path + + +def check_bootc_image_version_id(params): + """ + check bootc image version id + + @param params: one dictionary wrapping various parameter + """ + expected_redhat_version_id = params.get("redhat_version_id") + if expected_redhat_version_id is None: + LOG.debug("don't need to check redhat version id") + else: + bootc_meta_info_dict = get_bootc_image_meta_info(params) + redhat_version_id = bootc_meta_info_dict.get("redhat.version-id") + compose_id = bootc_meta_info_dict.get("redhat.compose-id") + expected_compose_id = "RHEL-{}".format(expected_redhat_version_id) + if "-beta" in expected_compose_id: + expected_compose_id = expected_compose_id[0:expected_compose_id.index("-beta")] + if expected_redhat_version_id != redhat_version_id: + raise exceptions.TestFail(f"Expected redhat version id :{expected_redhat_version_id}, real version id is: {redhat_version_id}") + if expected_compose_id not in compose_id: + raise exceptions.TestFail(f"Expected compose id :{expected_compose_id}, real compose id is: {compose_id}") + + +def get_bootc_image_meta_info(params): + """ + get bootc image meta information + + @param params: one dictionary wrapping various parameter + """ + container_url = params.get('container_url') + cmd = "sudo skopeo inspect --retry-times=5 --tls-verify=false docker://%s |jq -r '.Labels'" % container_url + ret = process.run(cmd, timeout=40, verbose=True, ignore_status=True, shell=True).stdout_text + LOG.debug(f"skopeo inspect bootc image output is : {ret}") + + bootc_meta_info_dict = eval(ret) + return bootc_meta_info_dict + + +def create_registry_policy_file(params): + """ + create registry policy file + + @param params: one dictionary wrapping various parameter + """ + base_dir = params.get("config_file_path") + policy_file = os.path.join(base_dir, "policy.json") + pub_key_file = os.path.join(base_dir, "key.gpg") + local_registry = "localhost:5000" + + registry_policy = { + "default": [{"type": "insecureAcceptAnything"}], + "transports": { + "docker": { + f"{local_registry}": [ + { + "type": "signedBy", + "keyType": "GPGKeys", + "keyPath": f"{pub_key_file}" + } + ] + }, + "docker-daemon": { + "": [{"type": "insecureAcceptAnything"}] + } + } + } + + with open(policy_file, mode="w", encoding="utf-8") as f: + f.write(json.dumps(registry_policy)) + + +def create_lookaside_config_file(params): + """ + create look aside config file + + @param params: one dictionary wrapping various parameter + """ + base_dir = params.get("config_file_path") + lookaside_file = os.path.join(base_dir, "bib_lookaside.yaml") + lookaside_file_config = """ + docker: + localhost:5000: + lookaside: file:///var/lib/containers/sigstore + """ + with open(lookaside_file, mode="w", encoding="utf-8") as f: + f.write(lookaside_file_config) + + +def gpg_gen_key(params): + """ + generate gpg key + + @param params: one dictionary wrapping various parameter + """ + base_dir = params.get("config_file_path") + home_dir = f"{base_dir}/.gnupg" + pub_key_file = os.path.join(base_dir, "key.gpg") + if os.path.exists(home_dir): + return + + os.makedirs(home_dir, mode=0o700, exist_ok=False) + key_params = """ + %no-protection + Key-Type: RSA + Key-Length: 3072 + Key-Usage: sign + Name-Real: Bootc Image Builder Test usage + Name-Email: bib_test@redhat.com + Expire-Date: 0 + """ + email = "bib_test@redhat.com" + + subprocess.run( + ["gpg", "--gen-key", "--batch"], + check=True, capture_output=True, + env={"GNUPGHOME": home_dir}, + input=key_params, + text=True) + + subprocess.run( + ["gpg", "--output", pub_key_file, + "--armor", "--export", email], + check=True, capture_output=True, + env={"GNUPGHOME": home_dir}) + + +def retag_container_image_to_local_registry(params): + """ + re-tag the image to point it to our local registry + + @param params: one dictionary wrapping various parameter + """ + container_url = params.get('container_url') + pull_image_cmd = f"podman pull {container_url}" + process.run(pull_image_cmd, timeout=600, verbose=True, ignore_status=False, shell=True) + + index = container_url.index(":") + 1 + image_name = container_url[index:] + + delete_img_cmd = f"podman rmi localhost:5000/{image_name} -f " + process.run(delete_img_cmd, timeout=60, verbose=True, ignore_status=True, shell=True) + + cmd = f"podman tag {container_url} localhost:5000/{image_name}" + ret = process.run(cmd, timeout=40, verbose=True, ignore_status=False, shell=True).stdout_text + + list_image = "podman images localhost:5000/{image_name}" + ret = process.run(cmd, timeout=40, verbose=True, ignore_status=True, shell=True).stdout_text + LOG.debug(f"pomdman list image output is : {ret}") + return f"localhost:5000/{image_name}" + + +def ensure_registry(params): + """ + ensure registry is running + + @param params: one dictionary wrapping various parameter + """ + registry_container_name = subprocess.run([ + "podman", "ps", "-a", "--filter", "name=registry", "--format", "{{.Names}}" + ], check=True, capture_output=True).stdout.decode("utf-8").strip() + + if registry_container_name != "registry": + subprocess.run([ + "podman", "run", "-d", "-p", "5000:5000", "--restart", "always", "--name", "registry", "registry:2" + ], check=True, capture_output=True) + + registry_container_state = subprocess.run([ + "podman", "ps", "-a", "--filter", "name=registry", "--format", "{{.State}}" + ], check=True, capture_output=True).stdout.decode("utf-8").strip() + + if registry_container_state in ("paused", "exited"): + subprocess.run([ + "podman", "start", "registry" + ], check=True, capture_output=True) + time.sleep(20) + cmd = "podman ps" + output = process.run(cmd, timeout=40, verbose=True, ignore_status=True, shell=True).stdout_text + LOG.debug(f"pomdman list running container output is : {output}") + + +def sign_image(params): + """ + sign container image + + @param params: one dictionary wrapping various parameter + """ + gpg_gen_key(params) + ensure_registry(params) + local_registry_url = retag_container_image_to_local_registry(params) + create_registry_policy_file(params) + create_lookaside_config_file(params) + base_dir = params.get("config_file_path") + home_dir = f"{base_dir}/.gnupg" + email = "bib_test@redhat.com" + base_dir = params.get("config_file_path") + lookaside_file = os.path.join(base_dir, "bib_lookaside.yaml") + system_lookaside_conf_file = os.path.join( + "/etc/containers/registries.d", + os.path.basename(lookaside_file) + ) + shutil.copy(lookaside_file, system_lookaside_conf_file) + + subprocess.run([ + "podman", "push", + "--tls-verify=false", + "--sign-by", email, + f"{local_registry_url}", + ], check=True, capture_output=True, env={"GNUPGHOME": home_dir}) + os.unlink(system_lookaside_conf_file) + return local_registry_url + + def get_baseurl_from_repo_file(repo_file_path): """ One method to get compose url from current repository file diff --git a/virttools/tests/cfg/bootc_image_builder/bootc_disk_image_build.cfg b/virttools/tests/cfg/bootc_image_builder/bootc_disk_image_build.cfg index 5bd0b929cd..3e16faf5dc 100644 --- a/virttools/tests/cfg/bootc_image_builder/bootc_disk_image_build.cfg +++ b/virttools/tests/cfg/bootc_image_builder/bootc_disk_image_build.cfg @@ -1,6 +1,6 @@ - bootc_image_builder.bib.disk_image_generation: type = bootc_disk_image_build - only x86_64, aarch64 + only x86_64, aarch64, s390x, ppc64le start_vm = False take_regular_screendumps = "no" start_vm = "no" @@ -23,10 +23,14 @@ - use_config_json: os_username = "alice" os_password = "bob" + qcow..upstream_bib: + filesystem_size_set = "yes" anaconda-iso..upstream_bib..fedora_40: kickstart = "yes" - anaconda-iso..rhel_9.5_nightly_bib..local_image: + use_toml_config = "yes" + anaconda-iso..rhel_9.5_nightly_bib..local_image, anaconda-iso..rhel_9.6_nightly_bib..local_image: kickstart = "yes" + filesystem_size_set = "yes" - unuse_config_json: variants image_ref: - centos: @@ -34,15 +38,20 @@ - centos9: container_url = "quay.io/centos-bootc/centos-bootc:stream9" only use_config_json..tls_verify_disable + x86_64, aarch64: + anaconda-iso.upstream_bib: + signed_container = "yes" + local_container = "yes" - centos10: container_url = "quay.io/centos-bootc/centos-bootc:stream10" - only upstream_bib..use_config_json..tls_verify_enable, rhel_9.5_nightly_bib..use_config_json..tls_verify_enable, rhel_9.4_nightly_bib..use_config_json..tls_verify_enable + only upstream_bib..use_config_json..tls_verify_enable, rhel_9.5_nightly_bib..use_config_json..tls_verify_enable, rhel_9.6_nightly_bib..use_config_json..tls_verify_enable, rhel_9.4_nightly_bib..use_config_json..tls_verify_enable roofs = "xfs" rhel_9.4_nightly_bib..use_config_json..tls_verify_enable: roofs = "" - fedora: variants fedora_bootc_image: - fedora_40: + no s390-virtio only upstream_bib..tls_verify_enable ownership ="107:107" container_url = "quay.io/fedora/fedora-bootc:40" @@ -55,36 +64,56 @@ roofs = "xfs" raw..upstream_bib: roofs = "ext4" + s390-virtio: + container_url = "quay.io/fedora/fedora-bootc:41" - local_image: container_base_folder = "/var/lib/libvirt/images" container_url = "localhost/bootc:eln" local_container = "yes" build_container = "registry.stage.redhat.io/rhel9/rhel-bootc:rhel-9.4" rhel_9.5_nightly_bib: - build_container = "registry.stage.redhat.io/rhel9/rhel-bootc:rhel-9.5" + build_container = "registry.stage.redhat.io/rhel9/rhel-bootc:9.5" + rhel_9.6_nightly_bib, upstream_bib: + build_container = "registry.stage.redhat.io/rhel9/rhel-bootc:9.6" rhel_10.0_bib: - build_container = "registry.stage.redhat.io/rhel10-beta/rhel-bootc:rhel-10.0-beta" + build_container = "registry.stage.redhat.io/rhel10-beta/rhel-bootc:10.0-beta" - rhel_9.4: build_container = "registry.redhat.io/rhel9/rhel-bootc:9.4" container_url = "quay.io/wenbaoxin/rhel9test" only rhel_9.4_bib + - rhel_9.5: + build_container = "registry.redhat.io/rhel9/rhel-bootc:9.5" + container_url = "quay.io/wenbaoxin/rhel9-rhel_bootc" + only rhel_9.5_bib - rhel_9.5_nightly: - container_url = "registry.stage.redhat.io/rhel9/rhel-bootc:rhel-9.5" + container_url = "registry.stage.redhat.io/rhel9/rhel-bootc:9.5" only rhel_9.5_nightly_bib + redhat_version_id = "9.5" + no anaconda-iso + - rhel_9.6_nightly: + container_url = "registry.stage.redhat.io/rhel9/rhel-bootc:9.6" + only rhel_9.6_nightly_bib + redhat_version_id = "9.6" no anaconda-iso - rhel_10.0_nightly: - container_url = "registry.stage.redhat.io/rhel10-beta/rhel-bootc:rhel-10.0-beta" + container_url = "registry.stage.redhat.io/rhel10-beta/rhel-bootc:10.0-beta" enable_tls_verify = "false" + redhat_version_id = "10.0-beta" only rhel_10.0_bib no anaconda-iso - cross_build: - container_url = "quay.io/centos-bootc/centos-bootc:stream9" + local_container = "yes" + manifest = "manifest-test" + container_base_folder = "/var/lib/libvirt/images" + build_container = "quay.io/centos-bootc/centos-bootc-dev:stream9" + container_url = "localhost/manifest-test" target_arch = "aarch64" + roofs = "btrfs" only qcow..upstream_bib..use_config_json..tls_verify_enable variants bib_ref: - upstream_bib: - registry_key = "example_stage_key" - redhat_registry = "registry.stage.redhat.io" + registry_stage_key = "example_stage_key" + redhat_stage_registry = "registry.stage.redhat.io" bib_image_url = "quay.io/centos-bootc/bootc-image-builder:latest" podman_stage_username = "11009103|stage" podman_stage_password = "example_stage_password" @@ -100,9 +129,9 @@ anaconda-iso..rhel_9.4: custom_repo = "rhel-9.4.repo" - rhel_9.4_nightly_bib: - registry_key = "example_stage_key" - redhat_registry = "registry.stage.redhat.io" - bib_image_url = "registry.stage.redhat.io/rhel9/bootc-image-builder:rhel-9.4" + registry_stage_key = "example_stage_key" + redhat_stage_registry = "registry.stage.redhat.io" + bib_image_url = "registry.stage.redhat.io/rhel9/bootc-image-builder:9.4" key_store_mounted = "/etc/pki:/etc/pki" podman_stage_username = "11009103|stage" podman_stage_password = "example_stage_password" @@ -110,20 +139,41 @@ custom_repo = "rhel-9.4.repo" compose_url = "example_compose_url" no cross_build + - rhel_9.5_bib: + podman_redhat_username = "podman_redhat_username" + podman_redhat_password = "podman_redhat_password" + redhat_registry = "registry.redhat.io" + container_base_folder = "/var/lib/libvirt/images" + bib_image_url = "registry.redhat.io/rhel9/bootc-image-builder:9.5" + podman_quay_username = "podman_quay_username" + podman_quay_password = "podman_quay_password" + only rhel_9.5..use_config_json..tls_verify_enable + anaconda-iso..rhel_9.5: + custom_repo = "rhel-9.5.repo" - rhel_9.5_nightly_bib: - registry_key = "example_stage_key" - redhat_registry = "registry.stage.redhat.io" - bib_image_url = "registry.stage.redhat.io/rhel9/bootc-image-builder:rhel-9.5" + registry_stage_key = "example_stage_key" + redhat_stage_registry = "registry.stage.redhat.io" + bib_image_url = "registry.stage.redhat.io/rhel9/bootc-image-builder:9.5" key_store_mounted = "/etc/pki:/etc/pki" podman_stage_username = "11009103|stage" podman_stage_password = "example_stage_password" anaconda-iso..local_image: custom_repo = "rhel-9.5.repo" compose_url = "example_compose_url" + - rhel_9.6_nightly_bib: + registry_stage_key = "example_stage_key" + redhat_stage_registry = "registry.stage.redhat.io" + bib_image_url = "registry.stage.redhat.io/rhel9/bootc-image-builder:9.6" + key_store_mounted = "/etc/pki:/etc/pki" + podman_stage_username = "11009103|stage" + podman_stage_password = "example_stage_password" + anaconda-iso..local_image: + custom_repo = "rhel-9.6.repo" + compose_url = "example_compose_url" - rhel_10.0_bib: - registry_key = "example_stage_key" - redhat_registry = "registry.stage.redhat.io" - bib_image_url = "registry.stage.redhat.io/rhel10-beta/bootc-image-builder:rhel-10.0-beta" + registry_stage_key = "example_stage_key" + redhat_stage_registry = "registry.stage.redhat.io" + bib_image_url = "registry.stage.redhat.io/rhel10-beta/bootc-image-builder:10.0-beta" key_store_mounted = "/etc/pki:/etc/pki" podman_stage_username = "11009103|stage" podman_stage_password = "example_stage_password" @@ -133,6 +183,7 @@ variants: - ami: disk_image_type = "ami" + no s390-virtio output_sub_folder = "image" output_name = "disk.raw" aws_secret_folder = "/var/lib/libvirt/images" @@ -140,7 +191,7 @@ aws_access_key = "example_aws_access_key" aws_region = "us-east-1" aws_ami_name = "build_${bib_ref}-${image_ref}-component-bootc-${disk_image_type}" - use_config_json..tls_verify_enable: + rhel_9.5_nightly_bib..use_config_json..tls_verify_enable, rhel_9.5_nightly_bib..use_config_json..tls_verify_enable, upstream_bib.centos.centos10.use_config_json.tls_verify_enable: aws_config_dict = "{'aws.secrets':'${aws_secret_folder}/aws.secrets','aws_ami_name':'${aws_ami_name}','aws_bucket':'bib-component-test','aws_region':'${aws_region}'}" - qcow: disk_image_type = "qcow2" @@ -150,6 +201,7 @@ disk_image_type = "vmdk" output_sub_folder = "vmdk" output_name = "disk.vmdk" + no s390-virtio - anaconda-iso: disk_image_type = "anaconda-iso" output_sub_folder = "bootiso" @@ -158,3 +210,15 @@ disk_image_type = "raw" output_sub_folder = "image" output_name = "disk.raw" + - vhd: + disk_image_type = "vhd" + output_sub_folder = "vpc" + output_name = "disk.vhd" + no s390-virtio + only upstream_bib + - gce: + disk_image_type = "gce" + output_sub_folder = "gce" + output_name = "image.tar.gz" + no s390-virtio + only upstream_bib diff --git a/virttools/tests/cfg/bootc_image_builder/bootc_disk_image_install.cfg b/virttools/tests/cfg/bootc_image_builder/bootc_disk_image_install.cfg index 800f6f1fad..36f4936f0f 100644 --- a/virttools/tests/cfg/bootc_image_builder/bootc_disk_image_install.cfg +++ b/virttools/tests/cfg/bootc_image_builder/bootc_disk_image_install.cfg @@ -1,6 +1,6 @@ - bootc_image_builder.bib.disk_image_install: type = bootc_disk_image_install - only x86_64, aarch64 + only x86_64, aarch64, s390x, ppc64le start_vm = False take_regular_screendumps = "no" start_vm = "no" @@ -36,9 +36,11 @@ variants centos_bootc_image: - centos9: container_url = "quay.io/centos-bootc/centos-bootc:stream9" + only bios - centos10: container_url = "quay.io/centos-bootc/centos-bootc:stream10" - only upstream_bib, rhel_9.5_nightly_bib, rhel_9.4_nightly_bib + only efi + only upstream_bib, rhel_9.5_nightly_bib, rhel_9.6_nightly_bib, rhel_9.4_nightly_bib roofs = "ext4" rhel_9.4_nightly_bib: roofs = "" @@ -46,18 +48,25 @@ variants fedora_bootc_image: - fedora_40: only upstream_bib + only bios container_url = "quay.io/fedora/fedora-bootc:40" roofs = "ext4" qcow..upstream_bib: roofs = "xfs" anaconda-iso..upstream_bib: kickstart = "yes" + raw..upstream_bib: + filesystem_size_set = "yes" + no s390-virtio - fedora_latest: only upstream_bib + only efi container_url = "quay.io/fedora/fedora-bootc:latest" roofs = "xfs" raw..upstream_bib: roofs = "ext4" + s390-virtio: + container_url = "quay.io/fedora/fedora-bootc:41" - rhel_9.4: build_container = "registry.redhat.io/rhel9/rhel-bootc:9.4" container_url = "quay.io/wenbaoxin/rhel9test" @@ -68,24 +77,43 @@ local_container = "yes" build_container = "registry.stage.redhat.io/rhel9/rhel-bootc:rhel-9.4" rhel_9.5_nightly_bib: - build_container = "registry.stage.redhat.io/rhel9/rhel-bootc:rhel-9.5" + build_container = "registry.stage.redhat.io/rhel9/rhel-bootc:9.5" + fips_enable = "yes" + enable_fips_enable_repo = "yes" + anaconda-iso..upstream_bib, anaconda-iso..rhel_9.5_nightly_bib: fips_enable = "yes" + use_toml_config = "yes" + kickstart = "yes" + enable_fips_enable_repo = "no" + rhel_9.6_nightly_bib, upstream_bib: + build_container = "registry.stage.redhat.io/rhel9/rhel-bootc:9.6" + fips_enable = "yes" + enable_fips_enable_repo = "yes" rhel_10.0_bib: - build_container = "registry.stage.redhat.io/rhel10-beta/rhel-bootc:rhel-10.0-beta" + build_container = "registry.stage.redhat.io/rhel10-beta/rhel-bootc:10.0-beta" + - rhel_9.5: + build_container = "registry.redhat.io/rhel9/rhel-bootc:9.5" + container_url = "quay.io/wenbaoxin/rhel9-rhel_bootc" + only rhel_9.5_bib - rhel_9.5_nightly: - container_url = "registry.stage.redhat.io/rhel9/rhel-bootc:rhel-9.5" + container_url = "registry.stage.redhat.io/rhel9/rhel-bootc:9.5" enable_tls_verify = "false" only rhel_9.5_nightly_bib no anaconda-iso + - rhel_9.6_nightly: + container_url = "registry.stage.redhat.io/rhel9/rhel-bootc:9.6" + enable_tls_verify = "false" + only rhel_9.6_nightly_bib + no anaconda-iso - rhel_10.0_nightly: - container_url = "registry.stage.redhat.io/rhel10-beta/rhel-bootc:rhel-10.0-beta" + container_url = "registry.stage.redhat.io/rhel10-beta/rhel-bootc:10.0-beta" enable_tls_verify = "false" only rhel_10.0_bib no anaconda-iso variants bib_ref: - upstream_bib: - registry_key = "example_stage_key" - redhat_registry = "registry.stage.redhat.io" + registry_stage_key = "example_stage_key" + redhat_stage_registry = "registry.stage.redhat.io" bib_image_url = "quay.io/centos-bootc/bootc-image-builder:latest" podman_stage_username = "11009103|stage" podman_stage_password = "example_stage_password" @@ -101,29 +129,50 @@ custom_repo = "rhel-9.4.repo" only rhel_9.4 - rhel_9.4_nightly_bib: - registry_key = "example_stage_key" - redhat_registry = "registry.stage.redhat.io" - bib_image_url = "registry.stage.redhat.io/rhel9/bootc-image-builder:rhel-9.4" + registry_stage_key = "example_stage_key" + redhat_stage_registry = "registry.stage.redhat.io" + bib_image_url = "registry.stage.redhat.io/rhel9/bootc-image-builder:9.4" key_store_mounted = "/etc/pki:/etc/pki" podman_stage_username = "11009103|stage" podman_stage_password = "example_stage_password" anaconda-iso..local_image: custom_repo = "rhel-9.4.repo" compose_url = "example_compose_url" + - rhel_9.5_bib: + podman_redhat_username = "11080659|chwen" + podman_redhat_password = "podman_redhat_password" + redhat_registry = "registry.redhat.io" + container_base_folder = "/var/lib/libvirt/images" + bib_image_url = "registry.redhat.io/rhel9/bootc-image-builder:9.5" + podman_quay_username = "wenbaoxin" + podman_quay_password = "doudou303" + anaconda-iso..rhel_9.5: + custom_repo = "rhel-9.5.repo" + only rhel_9.5 - rhel_9.5_nightly_bib: - registry_key = "example_stage_key" - redhat_registry = "registry.stage.redhat.io" - bib_image_url = "registry.stage.redhat.io/rhel9/bootc-image-builder:rhel-9.5" + registry_stage_key = "example_stage_key" + redhat_stage_registry = "registry.stage.redhat.io" + bib_image_url = "registry.stage.redhat.io/rhel9/bootc-image-builder:9.5" key_store_mounted = "/etc/pki:/etc/pki" podman_stage_username = "11009103|stage" podman_stage_password = "example_stage_password" anaconda-iso..local_image: custom_repo = "rhel-9.5.repo" compose_url = "example_compose_url" + - rhel_9.6_nightly_bib: + registry_stage_key = "example_stage_key" + redhat_stage_registry = "registry.stage.redhat.io" + bib_image_url = "registry.stage.redhat.io/rhel9/bootc-image-builder:9.6" + key_store_mounted = "/etc/pki:/etc/pki" + podman_stage_username = "11009103|stage" + podman_stage_password = "example_stage_password" + anaconda-iso..local_image: + custom_repo = "rhel-9.6.repo" + compose_url = "example_compose_url" - rhel_10.0_bib: - registry_key = "example_stage_key" - redhat_registry = "registry.stage.redhat.io" - bib_image_url = "registry.stage.redhat.io/rhel10-beta/bootc-image-builder:rhel-10.0-beta" + registry_stage_key = "example_stage_key" + redhat_stage_registry = "registry.stage.redhat.io" + bib_image_url = "registry.stage.redhat.io/rhel10-beta/bootc-image-builder:10.0-beta" key_store_mounted = "/etc/pki:/etc/pki" podman_stage_username = "11009103|stage" podman_stage_password = "example_stage_password" @@ -133,6 +182,7 @@ variants: - ami: disk_image_type = "ami" + no s390-virtio output_sub_folder = "image" output_name = "disk.raw" aws_secret_folder = "/var/lib/libvirt/images" @@ -145,7 +195,11 @@ aws_vpc_id = "example_vpc" aws_subnet_id = "example_subnet" aws_config_dict = "{'aws.secrets':'${aws_secret_folder}/aws.secrets','aws_ami_name':'${aws_ami_name}','aws_bucket':'bib-component-test','aws_region':'${aws_region}'}" - rhel_9.5_nightly_bib..centos.centos9, rhel_9.5_nightly_bib..fedora_eln, rhel_9.5_nightly_bib..local_image: + rhel_9.5_nightly_bib..centos.centos9, rhel_9.5_nightly_bib..local_image: + aws_config_dict = {} + rhel_9.6_nightly_bib..centos.centos9, rhel_9.6_nightly_bib..local_image: + aws_config_dict = {} + upstream_bib..centos, upstream_bib..local_image, upstream_bib..fedora.fedora_40: aws_config_dict = {} - qcow: disk_image_type = "qcow2" @@ -155,6 +209,7 @@ disk_image_type = "vmdk" output_sub_folder = "vmdk" output_name = "disk.vmdk" + no s390-virtio local_image: add_vmware_tool = "yes" rhel_9.4: @@ -168,3 +223,15 @@ disk_image_type = "raw" output_sub_folder = "image" output_name = "disk.raw" + - vhd: + disk_image_type = "vhd" + output_sub_folder = "vpc" + output_name = "disk.vhd" + no s390-virtio + only upstream_bib + - gce: + disk_image_type = "gce" + output_sub_folder = "gce" + output_name = "image.tar.gz" + no s390-virtio + only upstream_bib diff --git a/virttools/tests/src/bootc_image_builder/bootc_disk_image_build.py b/virttools/tests/src/bootc_image_builder/bootc_disk_image_build.py index 7fe6ebe5c3..17a9ad54a6 100644 --- a/virttools/tests/src/bootc_image_builder/bootc_disk_image_build.py +++ b/virttools/tests/src/bootc_image_builder/bootc_disk_image_build.py @@ -37,6 +37,8 @@ def validate_bib_output(params, test): if formatted_group_user != ownership: test.fail(f"The output folder:{base_folder} has wrong setting in group and user ids: {formatted_group_user}") + # bib_utils.check_bootc_image_version_id(params) + def prepare_env_and_execute_bib(params, test): """ @@ -52,10 +54,12 @@ def prepare_env_and_execute_bib(params, test): container_url = params.get("container_url") local_container = "yes" == params.get("local_container") build_container = params.get("build_container") + signed_container = "yes" == params.get("signed_container") enable_tls_verify = params.get("enable_tls_verify") config_json = params.get("config_json") config_json_file = None + use_toml_config = "yes" == params.get("use_toml_config") ownership = params.get("ownership") key_store_mounted = params.get("key_store_mounted") @@ -70,27 +74,42 @@ def prepare_env_and_execute_bib(params, test): bib_utils.install_bib_packages() if config_json == "use_config_json": - config_json_file = bib_utils.create_config_json_file(params) + if use_toml_config: + config_json_file = bib_utils.create_config_toml_file(params) + else: + config_json_file = bib_utils.create_config_json_file(params) if disk_image_type in ["ami"]: bib_utils.prepare_aws_env(params) - if bib_ref in ["upstream_bib", "rhel_9.4_nightly_bib", "rhel_9.5_nightly_bib", "rhel_10.0_bib"]: + if bib_ref in ["upstream_bib", "rhel_9.4_nightly_bib", "rhel_9.5_nightly_bib", "rhel_9.6_nightly_bib", "rhel_10.0_bib"]: auth_file = bib_utils.create_auth_json_file(params) - bib_utils.podman_login_with_auth(auth_file, params.get("redhat_registry")) - options = auth_file + bib_utils.podman_login_with_auth(auth_file, params.get("redhat_stage_registry")) + options = " -v %s:/run/containers/0/auth.json " % auth_file bib_utils.podman_login(params.get("podman_stage_username"), params.get("podman_stage_password"), - params.get("redhat_registry")) + params.get("redhat_stage_registry")) # pull base image and build local image after change if build_container: - if bib_ref == "rhel_9.4_bib": + if bib_ref in ["rhel_9.4_bib", "rhel_9.5_bib"]: bib_utils.podman_login(params.get("podman_redhat_username"), params.get("podman_redhat_password"), params.get("redhat_registry")) bib_utils.create_and_build_container_file(params) - if bib_ref == "rhel_9.4_bib": + + if bib_ref in ["rhel_9.4_bib", "rhel_9.5_bib"]: bib_utils.podman_push(params.get("podman_quay_username"), params.get("podman_quay_password"), params.get("registry"), container_url) + # sign the container image if needed + if signed_container: + LOG.debug(f"Begin sign container image: {container_url}") + container_url = bib_utils.sign_image(params) + LOG.debug(f"End sign container image: {container_url}") + if options is None: + options = " " + root_dir = params.get("config_file_path") + options += f" -v {root_dir}/policy.json:/etc/containers/policy.json -v {root_dir}/bib_lookaside.yaml:/etc/containers/registries.d/bib_lookaside.yaml " + options += f" -v /var/lib/containers/sigstore:/var/lib/containers/sigstore -v {root_dir}/key.gpg:{root_dir}key.gpg " + result = bib_utils.podman_command_build(bib_image_url, disk_image_type, container_url, config_json_file, local_container, enable_tls_verify, ownership, key_store_mounted, target_arch, roofs, options, **aws_config_dict) diff --git a/virttools/tests/src/bootc_image_builder/bootc_disk_image_install.py b/virttools/tests/src/bootc_image_builder/bootc_disk_image_install.py index 419555403a..143fba94b3 100644 --- a/virttools/tests/src/bootc_image_builder/bootc_disk_image_install.py +++ b/virttools/tests/src/bootc_image_builder/bootc_disk_image_install.py @@ -9,6 +9,7 @@ import logging import re import os +import platform import shutil from virttest import virsh @@ -35,7 +36,8 @@ def update_bib_env_info(params, test): full_path = os.path.join(base_folder, output_sub_folder, output_name) if not os.path.exists(full_path): test.fail("bootc image build fail to generate outputs for image type: %s" % params.get("disk_image_type")) - converted_disk_image = f"install_{bib_ref}_{firmware}_{bib_utils.convert_disk_image_name(params)}" + special_chars = re.sub(r'[.,-]+', '', platform.release()) + converted_disk_image = f"install_{special_chars}_{bib_ref}_{firmware}_{bib_utils.convert_disk_image_name(params)}" disk_name, _ = os.path.splitext(converted_disk_image) full_path_dest = os.path.join(libvirt_base_folder, converted_disk_image) shutil.move(full_path, full_path_dest) @@ -45,6 +47,15 @@ def update_bib_env_info(params, test): params.update({'vm_disk_image_path': full_path_dest}) params.update({'vm_name_bootc': disk_name}) + if params.get("disk_image_type") == "vhd": + converted_image_from_vhd_qcow2 = bib_utils.convert_vhd_to_qcow2(params) + params.update({'vm_disk_image_path': converted_image_from_vhd_qcow2}) + + if params.get("disk_image_type") == "gce": + untar_raw_image = bib_utils.untar_tgz_to_raw(params) + params.update({'vm_disk_image_path': untar_raw_image}) + cleanup_files.append(untar_raw_image) + iso_install_path = os.path.join(libvirt_base_folder, f"{disk_name}_{firmware}.qcow2") params.update({'iso_install_path': iso_install_path}) cleanup_files.append(iso_install_path) @@ -71,26 +82,31 @@ def prepare_env_and_execute_bib(params, test): roofs = params.get("roofs") aws_config_dict = eval(params.get("aws_config_dict", '{}')) options = None + config_json_file = None + use_toml_config = "yes" == params.get("use_toml_config") bib_utils.install_bib_packages() - config_json_file = bib_utils.create_config_json_file(params) + if use_toml_config: + config_json_file = bib_utils.create_config_toml_file(params) + else: + config_json_file = bib_utils.create_config_json_file(params) if disk_image_type in ["ami"]: bib_utils.prepare_aws_env(params) - if bib_ref in ["upstream_bib", "rhel_9.4_nightly_bib", "rhel_9.5_nightly_bib", "rhel_10.0_bib"]: + if bib_ref in ["upstream_bib", "rhel_9.4_nightly_bib", "rhel_9.5_nightly_bib", "rhel_9.6_nightly_bib", "rhel_10.0_bib"]: auth_file = bib_utils.create_auth_json_file(params) - bib_utils.podman_login_with_auth(auth_file, params.get("redhat_registry")) - options = auth_file + bib_utils.podman_login_with_auth(auth_file, params.get("redhat_stage_registry")) + options = " -v %s:/run/containers/0/auth.json " % auth_file bib_utils.podman_login(params.get("podman_stage_username"), params.get("podman_stage_password"), - params.get("redhat_registry")) + params.get("redhat_stage_registry")) # pull base image and build local image after change if build_container: - if bib_ref == "rhel_9.4_bib": + if bib_ref in ["rhel_9.4_bib", "rhel_9.5_bib"]: bib_utils.podman_login(params.get("podman_redhat_username"), params.get("podman_redhat_password"), params.get("redhat_registry")) bib_utils.create_and_build_container_file(params) - if bib_ref == "rhel_9.4_bib": + if bib_ref in ["rhel_9.4_bib", "rhel_9.5_bib"]: ownership = None bib_utils.podman_push(params.get("podman_quay_username"), params.get("podman_quay_password"), params.get("registry"), container_url) @@ -128,7 +144,11 @@ def run(test, params, env): update_bib_env_info(params, test) if disk_image_type in ["vmdk"]: bib_utils.create_and_start_vmware_vm(params) - elif disk_image_type in ["qcow2", "raw", "anaconda-iso"]: + elif disk_image_type in ["qcow2", "raw", "anaconda-iso", "vhd", "gce"]: + # clean up dirty VM if existed + vm_name = params.get("vm_name_bootc") + if vm_name and vm_name in virsh.dom_list().stdout_text: + virsh.undefine(vm_name, options="--nvram", ignore_status=True) bib_utils.create_qemu_vm(params, env, test) elif disk_image_type in ["ami"]: if len(aws_config_dict) != 0: