Skip to content

Commit

Permalink
Add other disk formats support for building bootable bootc image.
Browse files Browse the repository at this point in the history
  • Loading branch information
linl-rh committed Oct 16, 2024
1 parent 1f451a0 commit 965ba97
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 65 deletions.
6 changes: 4 additions & 2 deletions os_tests/libs/utils_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,15 @@ def init_args():
parser.add_argument('--quay_io_data', dest='quay_io_data', default=None, action='store',
help='specify the login data for quay.io, e.g., username,password,quay.io', required=False)
parser.add_argument('--bootc_io_data', dest='bootc_io_data', default=None, action='store',
help='specify the login data for bootc repo, e.g., e.g., username,password,bootc io name', required=False)
help='specify the login data for bootc repo, e.g., username,password,bootc io name', required=False)
parser.add_argument('--bootc_base_image_digest', dest='bootc_base_image_digest', default=None, action='store',
help='specify the previous bootc_base_image_digest', required=False)
parser.add_argument('--config_toml_file', dest='config_toml_file', default=None, action='store',
help='specify the config_toml for login info of the custom container disk image', required=False)
parser.add_argument('--config_toml_info', dest='config_toml_info', default=None, action='store',
help='specify login info of the custom container disk image', required=False)
parser.add_argument('--aws_info', dest='aws_info', default=None, action='store',
help='specify the aws configure information, e.g., AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,aws-region,aws-bucket', required=False)
args = parser.parse_args()
return args

Expand Down Expand Up @@ -397,7 +399,7 @@ def init_case(test_instance):
test_instance.log.info("Case Doc: {}".format(eval(test_instance.id()).__doc__))
test_instance.log.info("Case Params:")
for key in test_instance.params.keys():
if key in ['password', 'subscription_username', 'subscription_password', 'quay_io_data', 'bootc_io_data', 'config_toml_info'] or 'password' in key:
if key in ['password', 'subscription_username', 'subscription_password', 'quay_io_data', 'bootc_io_data', 'config_toml_info', 'aws_info'] or 'password' in key:
test_instance.log.info("key:{}, val:*******".format(key))
else:
test_instance.log.info("key:{}, val:{}".format(key, test_instance.params[key]))
Expand Down
199 changes: 136 additions & 63 deletions os_tests/tests/test_image_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def _prepare_containerfile(self,containerfile,bootc_base_image_url,pkgs):
From $bootc_base_image_url
ADD ./rhel.repo /etc/yum.repos.d/rhel.repo
RUN echo $pkgs
RUN dnf install -y $pkgs && dnf clean all && rm -f /etc/yum.repos.d/rhel.repo
RUN dnf install -y $pkgs && dnf clean all
''')
fh, tmp_containerfile_file = tempfile.mkstemp(suffix='_containerfile', dir='/tmp', text=False)
with open(tmp_containerfile_file, 'a') as fh:
Expand Down Expand Up @@ -111,7 +111,8 @@ def test_build_rhel_bootc_image(self):
disk_image_format = self.params.get('disk_image_format')
containerfile = self.params.get('containerfile')
pkgs = self.params.get('pkgs')
pkgs = pkgs.replace(",", " ")
if pkgs:
pkgs = pkgs.replace(",", " ")
bootc_base_image_url = self.params.get('bootc_base_image_url')

#prepare containerfile
Expand All @@ -131,7 +132,10 @@ def test_build_rhel_bootc_image(self):
default_pkgs = "hyperv-daemons"
if disk_image_format == 'vhd':
default_pkgs = "cloud-init,hyperv-daemons"
pkgs = default_pkgs.replace(',',' ') + " " + pkgs
if pkgs:
pkgs = default_pkgs.replace(',',' ') + " " + pkgs
else:
pkgs = default_pkgs
self.log.info("print %s" % pkgs)
self._prepare_containerfile(containerfile, bootc_base_image_url, pkgs)
dnf_repo_url = self.params.get('dnf_repo_url')
Expand All @@ -156,7 +160,7 @@ def test_build_rhel_bootc_image(self):
cmd = "sudo podman rmi {} -f".format(bootc_base_image)
utils_lib.run_cmd(self, cmd, expect_ret=0, msg="remove old bootc base image")
cmd = "sudo podman pull {}".format(bootc_base_image)
utils_lib.run_cmd(self, cmd, expect_ret=0, msg="pull bootc base image")
utils_lib.run_cmd(self, cmd, expect_ret=0, timeout = 1200, msg="pull bootc base image")
cmd = "sudo podman images"
utils_lib.run_cmd(self, cmd, expect_ret=0, msg="Check all container images")
cmd = "sudo podman inspect {} --format '{{{{.ID}}}}' | tr -d '\n'".format(bootc_base_image)
Expand All @@ -171,6 +175,8 @@ def test_build_rhel_bootc_image(self):
utils_lib.run_cmd(self, cmd, expect_ret=0, msg="check bootc base image info")
cmd = "sudo podman inspect {} --format '{{{{.Architecture}}}}' | tr -d '\n'".format(bootc_base_image)
bootc_image_arch = utils_lib.run_cmd(self, cmd, expect_ret=0, msg="check bootc base image Architecture")
if bootc_image_arch == 'amd64':
bootc_image_arch = 'x86_64'
cmd = "sudo jq -r .[].Config.Labels.\\\"redhat.compose-id\\\" {} | tr -d '\n'".format(inspect_json_name)
bootc_base_image_compose_id = utils_lib.run_cmd(self, cmd, expect_ret=0, msg="check bootc base image compose-id")
bootc_custom_image_name = '{}_{}_{}_{}'.format(bootc_base_image_name,
Expand All @@ -181,30 +187,76 @@ def test_build_rhel_bootc_image(self):
if bootc_base_image_digest == self.params.get('bootc_base_image_digest'):
self.skipTest("Custom bootc image based bootc image {} Digest:{} was already built. Skip this case."
.format(bootc_base_image_name, bootc_base_image_digest))
bootc_custom_image_tag = bootc_base_image_digest
bootc_custom_image = "quay.io/{}/{}:{}".format(quay_io_data.split(',')[0], bootc_custom_image_name, bootc_custom_image_tag)
if quay_io_data:
bootc_custom_image = "quay.io/{}/{}:{}".format(quay_io_data.split(',')[0], bootc_custom_image_name, bootc_custom_image_tag)
else:
bootc_custom_image = "localhost/{}:{}".format(bootc_custom_image_name, bootc_custom_image_tag)
cmd = "sudo podman build -t {} .".format(bootc_custom_image)
utils_lib.run_cmd(self, cmd, expect_ret=0, msg="Build bootc custom image")
utils_lib.run_cmd(self, cmd, expect_ret=0, timeout = 1200, msg="Build bootc custom image")

#Create directory for converted disk images
output_dir = 'output_{}_{}'.format(bootc_custom_image_name, bootc_custom_image_tag)
cmd = "sudo rm {} -rf && sudo mkdir {}".format(output_dir, output_dir)
utils_lib.run_cmd(self, cmd, expect_ret=0, msg="Create output directory")
#Create bootable disks with custom bootc images
bootc_image_builder = self.params.get('bootc_image_builder') or bootc_base_image.replace('rhel-bootc','bootc-image-builder')

if disk_image_format == 'ami':
utils_lib.is_pkg_installed(self, pkg_name='awscli2', is_install=True, cancel_case=True)
ami_name = '{}_{}_{}'.format(bootc_custom_image_name, bootc_custom_image_tag, bootc_base_image_compose_id)
aws_info = self.params.get('aws_info')
if aws_info and aws_info.split(',')[3]:
aws_bucket = aws_info.split(',')[3]
else:
aws_bucket = 'rh-image-files'
if aws_info and aws_info.split(',')[0] and aws_info.split(',')[1]:
cmd = "sudo podman run --rm -it --privileged --pull=newer --tls-verify=false \
--security-opt label=type:unconfined_t -v /var/lib/containers/storage:/var/lib/containers/storage \
--env AWS_ACCESS_KEY_ID={} --env AWS_SECRET_ACCESS_KEY={} {} --type ami --target-arch {} --local --aws-ami-name {} \
--aws-region {} --aws-bucket {} {}".format(
aws_info.split(',')[0],
aws_info.split(',')[1],
bootc_image_builder,
bootc_image_arch,
ami_name,
aws-bucket,
aws_info.split(',')[2],
bootc_custom_image)
utils_lib.run_cmd(self, cmd, timeout=3600, is_log_cmd=False, msg='Create ami for image mode testing based on {}'.format(bootc_base_image_compose_id))

#Build custom bootc images
bootc_image_builder = bootc_base_image.replace('rhel-bootc','bootc-image-builder')
config_toml_file = self.params.get('config_toml_file')
config_toml_info = self.params.get('config_toml_info')
if config_toml_file:
tmp_config_toml = '/tmp/config_toml'
self.SSH.put_file(local_file=config_toml_file, rmt_file=tmp_config_toml)
cmd = "sudo cp {} ./config.toml".format(tmp_config_toml)
utils_lib.run_cmd(self, cmd, msg='copy {}'.format(config_toml_file))
if os.path.exists(tmp_config_toml):
os.unlink(tmp_config_toml)
self.log.info("delete temp config.toml file")
elif config_toml_info:
utils_lib.run_cmd(self, """
else:
cmd = "sudo grep region .aws/config | awk '{print $(3)}'| tr -d '\n'"
aws_region = utils_lib.run_cmd(self, cmd, msg='Check aws region')
if not aws_region:
FailTest('Please configure awscli')
else:
cmd = "sudo podman run --rm -it --privileged --pull=newer -v /root/.aws:/root/.aws:ro \
--env AWS_PROFILE=default -v /var/lib/containers/storage:/var/lib/containers/storage {} --local --type ami \
--target-arch {} --aws-ami-name {} --aws-region {} --aws-bucket {} {}".format(
bootc_image_builder,
bootc_image_arch,
ami_name,
aws_region,
aws_bucket,
bootc_custom_image)
utils_lib.run_cmd(self, cmd, timeout=3600, msg='Create ami for image mode testing based on {}'.format(bootc_base_image_compose_id))
cmd = "aws ec2 describe-images --filters 'Name=name,Values={}' --query 'Images[*].ImageId' --output text | tr -d '\n'".format(ami_name)
ami_id = utils_lib.run_cmd(self, cmd, msg='check ami id')
if ami_id:
self.log.info("AMI name:{} ID:{} based on bootc image {} compose-id:{} Digest:{} is uploaded \
to AWS {}".format(ami_name, ami_id, bootc_base_image, bootc_base_image_compose_id, bootc_base_image_digest, aws_region))
else:
FailTest('Failed to upload AMI')
else:
config_toml_file = self.params.get('config_toml_file')
config_toml_info = self.params.get('config_toml_info')
if config_toml_file:
tmp_config_toml = '/tmp/config_toml'
self.SSH.put_file(local_file=config_toml_file, rmt_file=tmp_config_toml)
cmd = "sudo cp {} ./config.toml".format(tmp_config_toml)
utils_lib.run_cmd(self, cmd, msg='copy {}'.format(config_toml_file))
if os.path.exists(tmp_config_toml):
os.unlink(tmp_config_toml)
self.log.info("delete temp config.toml file")
elif config_toml_info:
#Note the key will display in the disk convert log if you specify it.
utils_lib.run_cmd(self, """
sudo cat << EOF | sudo tee ./config.toml
[[customizations.user]]
name = "{}"
Expand All @@ -213,47 +265,68 @@ def test_build_rhel_bootc_image(self):
groups = ["wheel"]
EOF
""".format(config_toml_info.split(',')[0], config_toml_info.split(',')[1], config_toml_info.split(',')[2]),
is_log_cmd=False,
msg='create config_toml file')

#Convert custom bootc container image to disk image
disk_image_type = disk_image_format
if disk_image_format in ['vhdx', 'vhd']:
disk_image_type = 'qcow2'
cmd = "sudo podman run --rm -it --privileged --pull=newer --security-opt \
label=type:unconfined_t -v ./config.toml:/config.toml -v ./{}:/output -v \
/var/lib/containers/storage:/var/lib/containers/storage {} --type {} \
--config /config.toml --local {}".format(output_dir, bootc_image_builder, disk_image_type, bootc_custom_image)
utils_lib.run_cmd(self,
cmd,
expect_ret=0,
timeout = 1200,
msg="Create container disk image {} for image mode testing based on {}".format(bootc_custom_image, bootc_base_image_compose_id))

manifest_file = 'manifest{}'.format(output_dir.replace('output',''))
cmd = "sudo mv {}/manifest-{}.json {}".format(output_dir, disk_image_type, manifest_file)
utils_lib.run_cmd(self, cmd, expect_ret=0, msg='move manifest-{}.json to {}'.format(disk_image_type, manifest_file))
disk_file = 'disk{}'.format(output_dir.replace('output',''), disk_image_type)
cmd = "sudo mv {}/{}/disk.{} {}".format(output_dir, disk_image_type, disk_image_type, disk_file)
utils_lib.run_cmd(self, cmd, expect_ret=0, msg='copy disk.{} to {}'.format(disk_image_type, disk_file))

#uploade the output to attachment
workdir = utils_lib.run_cmd(self, "sudo pwd | tr -d '\n'", expect_ret=0)
utils_lib.save_file(self, file_dir=workdir, file_name=manifest_file)
utils_lib.save_file(self, file_dir=workdir, file_name=disk_file)
is_log_cmd=False,
msg='create config_toml file')

#Create directory for converted disk images
output_dir = 'output_{}_{}'.format(bootc_custom_image_name, bootc_custom_image_tag)
cmd = "sudo rm {} -rf && sudo mkdir {}".format(output_dir, output_dir)
utils_lib.run_cmd(self, cmd, expect_ret=0, msg="Create output directory")

self.log.info("Disk image {} based on bootc image {} \
compose-id:{} Digest:{} is saved to attachments.".format(disk_file,
bootc_base_image,
bootc_base_image_compose_id,
bootc_base_image_digest))
for image in ['bootc_base_image', 'bootc_custom_image']:
cmd = "sudo podman rmi {} -f".format(image)
utils_lib.run_cmd(self, cmd, expect_ret=0, msg='remove container image')
#Convert custom bootc container image to disk image
disk_image_type = disk_image_format
if disk_image_format in ['vhdx', 'vhd']:
disk_image_type = 'qcow2'
cmd = "sudo podman run --rm -it --privileged --pull=newer --security-opt \
label=type:unconfined_t -v ./config.toml:/config.toml -v ./{}:/output -v \
/var/lib/containers/storage:/var/lib/containers/storage {} --type {} --target-arch {} \
--config /config.toml --local {}".format(output_dir, bootc_image_builder, disk_image_type, bootc_image_arch, bootc_custom_image)
utils_lib.run_cmd(self,
cmd,
expect_ret=0,
timeout = 3600,
msg="Create container disk image {} for image mode testing based on {}".format(bootc_custom_image, bootc_base_image_compose_id))

cmd = "sudo podman rmi {} -f".format(bootc_custom_image)
utils_lib.run_cmd(self, cmd, expect_ret=0, msg='remove bootc_custom_image')
manifest_file = 'manifest{}'.format(output_dir.replace('output',''))
cmd = "sudo mv {}/manifest-{}.json {}".format(output_dir, disk_image_type, manifest_file)
utils_lib.run_cmd(self, cmd, expect_ret=0, msg='move manifest-{}.json to {}'.format(disk_image_type, manifest_file))
#qcow2_disk = 'disk.qcow2'.format(output_dir.replace('output',''), disk_image_type)
#qcow2_disk = 'disk.qcow2'
#iso_disk = 'install.iso'
utils_lib.is_cmd_exist(self,"qemu-img")
if disk_image_format == 'vhdx':
cmd = "sudo qemu-img convert -O vhdx {}/qcow2/disk.qcow2 {}/qcow2/disk.vhdx".format(output_dir, output_dir)
utils_lib.run_cmd(self, cmd, expect_ret=0, msg='convert qcow2 disk to vhdx disk')
if disk_image_format == 'vhd':
cmd = "sudo qemu-img convert -f qcow2 -o subformat=fixed,force_size -O vpc {}/qcow2/disk.qcow2 {}/qcow2/disk.vhd".format(output_dir, output_dir)
utils_lib.run_cmd(self, cmd, expect_ret=0, msg='convert qcow2 disk to vhd disk')
disk_dir = disk_image_type
disk_file = 'disk.{}'.format(disk_image_format)
if disk_image_type == 'iso':
disk_file = 'install.iso'
disk_dir = 'bootiso'
cmd = "sudo mv {}/{}/{} {}.{}".format(output_dir, disk_dir, disk_file, output_dir.replace('output_',''), disk_file.split('.')[1])
utils_lib.run_cmd(self, cmd, expect_ret=0, msg='move {} to workdir'.format(disk_file))
#uploade the output to attachment
workdir = utils_lib.run_cmd(self, "sudo pwd | tr -d '\n'", expect_ret=0)
utils_lib.save_file(self, file_dir=workdir, file_name=inspect_json_name)
utils_lib.save_file(self, file_dir=workdir, file_name=manifest_file)
#Copy the disk file to your test environment by manual,
#Or comment out below line to save it to attachments in log.
utils_lib.save_file(self, file_dir=workdir, file_name='{}.{}'.format(output_dir.replace('output_',''), disk_image_format))

self.log.info("Please copy Disk image ./{}.{} based on bootc image {} \
compose-id:{} Digest:{} to your test environment.".format(
output_dir.replace('output_',''),
disk_image_format,
bootc_base_image,
bootc_base_image_compose_id,
bootc_base_image_digest))
#delete container images
for image in [bootc_base_image, bootc_custom_image, bootc_image_builder]:
cmd = "sudo podman rmi {} -f".format(image)
utils_lib.run_cmd(self, cmd, expect_ret=0, msg='remove container image {}'.format(image))

def tearDown(self):
utils_lib.finish_case(self)
pass
Expand Down

0 comments on commit 965ba97

Please sign in to comment.