-
Notifications
You must be signed in to change notification settings - Fork 170
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
utilities and case scripts are provided, and cover Image type:ami vmdk qcow2 anaconda-iso raw container image reference: quay.io/centos-bootc/centos-bootc:stream9, quay.io/centos-bootc/fedora-bootc:eln, localhost/bootc:eln Signed-off-by: Chunfu Wen <[email protected]>
- Loading branch information
Showing
3 changed files
with
391 additions
and
0 deletions.
There are no files selected for viewing
237 changes: 237 additions & 0 deletions
237
provider/bootc_image_builder/bootc_image_build_utils.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,237 @@ | ||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
# | ||
# Copyright Red Hat | ||
# | ||
# SPDX-License-Identifier: GPL-2.0 | ||
# | ||
# Author: [email protected] | ||
# | ||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
"""Helper functions for bootc image builder""" | ||
|
||
import logging | ||
import json | ||
import os | ||
import shutil | ||
import textwrap | ||
import pathlib | ||
|
||
from avocado.utils import path, process | ||
from virttest import utils_package | ||
|
||
LOG = logging.getLogger('avocado.' + __name__) | ||
|
||
|
||
def install_bib_packages(): | ||
""" | ||
install necessary bootc image builder necessary packages | ||
""" | ||
package_list = ["podman", "skopeo", "virt-install", "curl", "virt-manager"] | ||
for pkg in package_list: | ||
try: | ||
path.find_command(pkg) | ||
except path.CmdNotFoundError: | ||
utils_package.package_install(pkg) | ||
|
||
|
||
def podman_command_build(bib_image_url, disk_image_type, image_ref, config=None, local_container=False, tls_verify="true", chownership=None, options=None, **dargs): | ||
""" | ||
Use podman run command to launch bootc image builder | ||
:param bib_image_url: bootc image builder url | ||
:param disk_image_type: image type to build [qcow2, ami] (default "qcow2") | ||
:param image_ref: image reference | ||
:param config: config file | ||
:param local_container: whether use local container image | ||
:param tls_verify: whether verify tls connection | ||
:param local_container: whether use local container image | ||
:param chownership: whether change output ownership | ||
:param options: additional options if needed | ||
:param dargs: standardized virsh function API keywords | ||
:return: CmdResult object | ||
""" | ||
if not os.path.exists("/var/lib/libvirt/images/output"): | ||
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 local_container: | ||
cmd += " -v /var/lib/containers/storage:/var/lib/containers/storage " | ||
|
||
cmd += " %s " \ | ||
" --type %s --tls-verify=%s " % (bib_image_url, disk_image_type, tls_verify) | ||
|
||
if config: | ||
cmd += " --config /config.json " | ||
|
||
if local_container: | ||
cmd += " --local %s " % image_ref | ||
else: | ||
cmd += " %s " % image_ref | ||
|
||
if chownership: | ||
cmd += " --chown %s " % chownership | ||
|
||
if options is not None: | ||
cmd += " %s" % options | ||
|
||
debug = dargs.get("debug", True) | ||
|
||
ignore_status = dargs.get("ignore_status", False) | ||
timeout = int(dargs.get("timeout", "1800")) | ||
LOG.debug("the whole podman command: %s\n" % cmd) | ||
|
||
ret = process.run( | ||
cmd, timeout=timeout, verbose=debug, ignore_status=ignore_status, shell=True) | ||
|
||
ret.stdout = ret.stdout_text | ||
ret.stderr = ret.stderr_text | ||
return ret | ||
|
||
|
||
def podman_login(podman_username, podman_password, registry): | ||
""" | ||
Use podman to login in registry | ||
:param podman_username: podman username | ||
:param podman_password: podman password | ||
:param registry: registry to login | ||
:return: CmdResult object | ||
""" | ||
command = "sudo podman login -u='%s' -p='%s' %s " % (podman_username, podman_password, registry) | ||
process.run( | ||
command, timeout=60, verbose=True, ignore_status=False, shell=True) | ||
|
||
|
||
def podman_push(podman_username, podman_password, registry, container_url): | ||
""" | ||
Use podman image to registry | ||
:param podman_username: podman username | ||
:param podman_password: podman password | ||
:param registry: registry to login | ||
:param container_url: image url | ||
:return: CmdResult object | ||
""" | ||
podman_login(podman_username, podman_password, registry) | ||
command = "sudo podman push %s " % container_url | ||
process.run( | ||
command, timeout=1200, verbose=True, ignore_status=False, shell=True) | ||
|
||
|
||
def create_config_json_file(folder, username, password): | ||
""" | ||
install necessary bootc image builder necessary packages | ||
:param folder: the folder that config.json reside in | ||
:param username: user name | ||
:param password: user password | ||
""" | ||
public_key_path = os.path.join(os.path.expanduser("~/.ssh/"), "id_rsa.pub") | ||
if not os.path.exists(public_key_path): | ||
LOG.debug("public key doesn't exist, please 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() | ||
cfg = { | ||
"blueprint": { | ||
"customizations": { | ||
"user": [ | ||
{ | ||
"name": username, | ||
"password": password, | ||
"groups": ["wheel"], | ||
"key": "%s" % key_value, | ||
}, | ||
], | ||
}, | ||
}, | ||
} | ||
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_and_build_container_file(folder, build_container, container_tag): | ||
""" | ||
Create container file and build container tag | ||
:param folder: the folder that config.json reside in | ||
:param build_container: the base container image | ||
:param container_tag: container tag | ||
""" | ||
# clean up existed image | ||
clean_image_cmd = "sudo podman rmi %s" % container_tag | ||
process.run(clean_image_cmd, shell=True, ignore_status=True) | ||
|
||
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) | ||
container_path.write_text(textwrap.dedent(f"""\n | ||
FROM {build_container} | ||
COPY beaker-BaseOS.repo /etc/yum.repos.d/ | ||
COPY beaker-AppStream.repo /etc/yum.repos.d/ | ||
RUN dnf install -y vim && dnf clean all | ||
"""), 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) | ||
|
||
|
||
def install_vmware_govc_tool(): | ||
""" | ||
Download VmWare govc tool and install it | ||
""" | ||
govc_install_cmd = "curl -L -o - 'https://github.com/vmware/govmomi/releases/latest/download/govc_Linux_x86_64.tar.gz' " \ | ||
"| tar -C /usr/local/bin -xvzf - govc" | ||
print(govc_install_cmd) | ||
if not os.path.exists("/usr/local/bin/govc"): | ||
process.run(govc_install_cmd, shell=True, ignore_status=False) | ||
|
||
|
||
def setup_vCenter_env(params): | ||
""" | ||
Download VmWare govc tool and install it | ||
@param params: one dictionary wrapping various parameter | ||
""" | ||
# vCenter information | ||
os.environ["GOVC_URL"] = params.get("GOVC_URL") | ||
os.environ["GOVC_USERNAME"] = params.get("GOVC_USERNAME") | ||
os.environ["GOVC_PASSWORD"] = params.get("GOVC_PASSWORD") | ||
os.environ["DATA_CENTER"] = params.get("DATA_CENTER") | ||
os.environ["DATA_STORE"] = params.get("DATA_STORE") | ||
os.environ["GOVC_INSECURE"] = "true" | ||
process.run("govc about", shell=True, ignore_status=False) | ||
|
||
|
||
def parse_container_url(params): | ||
""" | ||
Parse repository information from container url | ||
@param params: wrapped dictionary containing url | ||
""" | ||
container_url = params.get("container_url") | ||
repository_info = container_url.split('/')[-1] | ||
repository_name = repository_info.split(':')[0] | ||
if "localhost" in container_url: | ||
repository_name = "localhost-%s" % repository_name | ||
return repository_name | ||
|
||
|
||
def convert_disk_image_name(params): | ||
""" | ||
Convert disk type image name | ||
@param params: wrapped dictionary containing parameters | ||
""" | ||
repository_name = parse_container_url(params) | ||
origin_disk_name, extension = os.path.splitext(params.get("output_name")) | ||
dest_disk_name = "%s-%s%s" % (origin_disk_name, repository_name, extension) | ||
return dest_disk_name |
74 changes: 74 additions & 0 deletions
74
virttools/tests/cfg/bootc_image_builder/bootc_disk_image_build.cfg
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
- bootc_image_builder.bib.disk_image_generation: | ||
type = bootc_disk_image_build | ||
only x86_64 | ||
start_vm = False | ||
take_regular_screendumps = "no" | ||
start_vm = "no" | ||
output_base_folder = "/var/lib/libvirt/images/output" | ||
# vCenter information | ||
GOVC_URL = "example_url" | ||
GOVC_USERNAME = "username" | ||
GOVC_PASSWORD = "userpassword" | ||
DATA_CENTER = "example_datacenter" | ||
DATA_STORE = "example_datastore" | ||
bib_image_url = "quay.io/centos-bootc/bootc-image-builder:latest" | ||
registry = "quay.io" | ||
variants: | ||
- owner_change_enable: | ||
ownership ="107:107" | ||
- owner_change_disable: | ||
variants: | ||
- tls_verify_enable: | ||
enable_tls_verify="true" | ||
- tls_verify_disable: | ||
enable_tls_verify="false" | ||
variants config_json: | ||
- use_config_json: | ||
config_file_path = "/var/lib/libvirt/images" | ||
os_username = "alice" | ||
os_password = "bob" | ||
- unuse_config_json: | ||
variants image_ref: | ||
- centos: | ||
container_url = "quay.io/centos-bootc/centos-bootc:stream9" | ||
- fedora: | ||
container_url = "quay.io/centos-bootc/fedora-bootc:eln" | ||
- local_image: | ||
container_base_folder = "/var/lib/libvirt/images" | ||
container_url = "localhost/bootc:eln" | ||
local_container = "yes" | ||
build_container = "registry-proxy.engineering.redhat.com/rh-osbs/rhel9-rhel_bootc:rhel-9.4" | ||
- rhel: | ||
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-beta/bootc-image-builder:9.4" | ||
build_container = "registry.redhat.io/rhel9-beta/rhel-bootc:9.4" | ||
container_url = "quay.io/wenbaoxin/rhel9test" | ||
podman_quay_username = "podman_quay_username" | ||
podman_quay_password = "podman_quay_password" | ||
only use_config_json..tls_verify_enable..owner_change_disable | ||
no vmdk | ||
no anaconda-iso | ||
variants: | ||
- ami: | ||
disk_image_type = "ami" | ||
output_sub_folder = "image" | ||
output_name = "disk.raw" | ||
- qcow: | ||
disk_image_type = "qcow2" | ||
output_sub_folder = "qcow2" | ||
output_name = "disk.qcow2" | ||
- vmdk: | ||
disk_image_type = "vmdk" | ||
output_sub_folder = "vmdk" | ||
output_name = "disk.vmdk" | ||
- anaconda-iso: | ||
disk_image_type = "anaconda-iso" | ||
output_sub_folder = "bootiso" | ||
output_name = "install.iso" | ||
- raw: | ||
disk_image_type = "raw" | ||
output_sub_folder = "image" | ||
output_name = "disk.raw" |
80 changes: 80 additions & 0 deletions
80
virttools/tests/src/bootc_image_builder/bootc_disk_image_build.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
# | ||
# Copyright Red Hat | ||
# | ||
# SPDX-License-Identifier: GPL-2.0 | ||
|
||
# Author: Chunfu Wen <[email protected]> | ||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
import logging | ||
import os | ||
|
||
from provider.bootc_image_builder import bootc_image_build_utils as bib_utils | ||
|
||
LOG = logging.getLogger('avocado.' + __name__) | ||
cleanup_files = [] | ||
|
||
|
||
def validate_bib_output(params, test): | ||
""" | ||
Common method to check whether image build output exists | ||
:param params: one collective object representing wrapped parameters | ||
:param test: test object | ||
""" | ||
base_folder = params.get("output_base_folder") | ||
output_sub_folder = params.get("output_sub_folder") | ||
output_name = params.get("output_name") | ||
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")) | ||
|
||
|
||
def run(test, params, env): | ||
""" | ||
Test boot container image builder. | ||
""" | ||
disk_image_type = params.get("disk_image_type") | ||
bib_image_url = params.get("bib_image_url", "quay.io/centos-bootc/bootc-image-builder:latest") | ||
image_ref = params.get("image_ref") | ||
container_url = params.get("container_url") | ||
local_container = "yes" == params.get("local_container") | ||
build_container = params.get("build_container") | ||
|
||
enable_tls_verify = params.get("enable_tls_verify") | ||
config_json = params.get("config_json") | ||
config_json_file = None | ||
|
||
ownership = params.get("ownership") | ||
|
||
try: | ||
bib_utils.install_bib_packages() | ||
if config_json == "use_config_json": | ||
config_json_file = bib_utils.create_config_json_file(params.get("config_file_path"), | ||
params.get("os_username"), params.get("os_password")) | ||
# pull base image and build local image after change | ||
if build_container: | ||
if image_ref == "rhel": | ||
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.get("container_base_folder"), | ||
build_container, container_url) | ||
if image_ref == "rhel": | ||
bib_utils.podman_push(params.get("podman_quay_username"), params.get("podman_quay_password"), | ||
params.get("registry"), container_url) | ||
|
||
bib_utils.podman_command_build(bib_image_url, disk_image_type, container_url, config_json_file, | ||
local_container, enable_tls_verify, ownership, options=None) | ||
# validate build output | ||
validate_bib_output(params, test) | ||
if disk_image_type == "vmdk": | ||
bib_utils.install_vmware_govc_tool() | ||
bib_utils.setup_vCenter_env(params) | ||
except Exception as ex: | ||
raise ex | ||
finally: | ||
# Clean up files | ||
for file_path in cleanup_files: | ||
if os.path.exists(file_path): | ||
os.remove(file_path) |