Skip to content

Commit

Permalink
Merge pull request #171 from yih-redhat/add-iso-case
Browse files Browse the repository at this point in the history
ci: add test case of bootc anaconda iso
  • Loading branch information
yih-redhat authored Nov 20, 2024
2 parents 7d5a5aa + 17ca946 commit 50329b2
Show file tree
Hide file tree
Showing 4 changed files with 369 additions and 2 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/greenboot-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ jobs:
git_ref: ${{ fromJson(steps.pr-api.outputs.data).head.ref }}
github_token: ${{ secrets.PAT }}
update_pull_request_status: true
pull_request_status_name: "f41-bootc-qcow2"
pull_request_status_name: "f41-bootc"
tmt_context: "arch=x86_64;distro=fedora-41"
tmt_plan_regex: bootc-qcow2
tmt_plan_regex: bootc
tf_scope: private
secrets: "QUAY_USERNAME=${{ secrets.QUAY_USERNAME }};QUAY_PASSWORD=${{ secrets.QUAY_PASSWORD }};STAGE_REDHAT_IO_USERNAME=${{ secrets.STAGE_REDHAT_IO_USERNAME }};STAGE_REDHAT_IO_TOKEN=${{ secrets.STAGE_REDHAT_IO_TOKEN }}"
variables: "ARCH=x86_64"
timeout: 90

359 changes: 359 additions & 0 deletions tests/greenboot-bootc-anaconda-iso.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,359 @@
#!/bin/bash
set -euox pipefail

# Dumps details about the instance running the CI job.
echo -e "\033[0;36m"
cat << EOF
------------------------------------------------------------------------------
CI MACHINE SPECS
------------------------------------------------------------------------------
Hostname: $(uname -n)
User: $(whoami)
CPUs: $(nproc)
RAM: $(free -m | grep -oP '\d+' | head -n 1) MB
DISK: $(df --output=size -h / | sed '1d;s/[^0-9]//g') GB
ARCH: $(uname -m)
KERNEL: $(uname -r)
------------------------------------------------------------------------------
EOF
echo -e "\033[0m"

# Get OS info
source /etc/os-release

# Setup variables
TEST_UUID=anaconda-$((1 + RANDOM % 1000000))
TEMPDIR=$(mktemp -d)
GUEST_ADDRESS=192.168.100.50
SSH_OPTIONS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=5)
SSH_KEY=key/ostree_key
SSH_KEY_PUB=$(cat "${SSH_KEY}".pub)
EDGE_USER=core
EDGE_USER_PASSWORD=foobar

case "${ID}-${VERSION_ID}" in
"fedora-41")
OS_VARIANT="fedora-unknown"
BASE_IMAGE_URL="quay.io/fedora/fedora-bootc:41"
BIB_URL="quay.io/centos-bootc/bootc-image-builder:latest"
;;
"centos-9")
OS_VARIANT="centos-stream9"
BASE_IMAGE_URL="quay.io/centos-bootc/centos-bootc:stream9"
BIB_URL="quay.io/centos-bootc/bootc-image-builder:latest"
;;
"rhel-9.6")
OS_VARIANT="rhel9-unknown"
BASE_IMAGE_URL="registry.stage.redhat.io/rhel9/rhel-bootc:9.6"
BIB_URL="registry.stage.redhat.io/rhel9/bootc-image-builder:9.6"
;;
*)
echo "unsupported distro: ${ID}-${VERSION_ID}"
exit 1;;
esac

# Colorful output.
function greenprint {
echo -e "\033[1;32m${1}\033[0m"
}

check_result () {
greenprint "🎏 Checking for test result"
if [[ $RESULTS == 1 ]]; then
greenprint "💚 Success"
else
greenprint "❌ Failed"
exit 1
fi
}

# Wait for the ssh server up to be.
wait_for_ssh_up () {
SSH_STATUS=$(sudo ssh "${SSH_OPTIONS[@]}" -i "${SSH_KEY}" ${EDGE_USER}@"${1}" '/bin/bash -c "echo -n READY"')
if [[ $SSH_STATUS == READY ]]; then
echo 1
else
echo 0
fi
}

###########################################################
##
## Prepare before run test
##
###########################################################
greenprint "Installing required packages"
sudo dnf install -y podman qemu-img firewalld qemu-kvm libvirt-client libvirt-daemon-kvm libvirt-daemon virt-install rpmdevtools ansible-core
ansible-galaxy collection install community.general

# Start firewalld
greenprint "Start firewalld"
sudo systemctl enable --now firewalld

# Check ostree_key permissions
KEY_PERMISSION_PRE=$(stat -L -c "%a %G %U" key/ostree_key | grep -oP '\d+' | head -n 1)
echo -e "${KEY_PERMISSION_PRE}"
if [[ "${KEY_PERMISSION_PRE}" != "600" ]]; then
greenprint "💡 File permissions too open...Changing to 600"
chmod 600 ./key/ostree_key
fi

# Setup libvirt
greenprint "Starting libvirt service and configure libvirt network"
sudo tee /etc/polkit-1/rules.d/50-libvirt.rules > /dev/null << EOF
polkit.addRule(function(action, subject) {
if (action.id == "org.libvirt.unix.manage" &&
subject.isInGroup("adm")) {
return polkit.Result.YES;
}
});
EOF
sudo systemctl start libvirtd
sudo virsh list --all > /dev/null
sudo tee /tmp/integration.xml > /dev/null << EOF
<network xmlns:dnsmasq='http://libvirt.org/schemas/network/dnsmasq/1.0'>
<name>integration</name>
<uuid>1c8fe98c-b53a-4ca4-bbdb-deb0f26b3579</uuid>
<forward mode='nat'>
<nat>
<port start='1024' end='65535'/>
</nat>
</forward>
<bridge name='integration' zone='trusted' stp='on' delay='0'/>
<mac address='52:54:00:36:46:ef'/>
<ip address='192.168.100.1' netmask='255.255.255.0'>
<dhcp>
<range start='192.168.100.2' end='192.168.100.254'/>
<host mac='34:49:22:B0:83:30' name='vm-1' ip='192.168.100.50'/>
<host mac='34:49:22:B0:83:31' name='vm-2' ip='192.168.100.51'/>
<host mac='34:49:22:B0:83:32' name='vm-3' ip='192.168.100.52'/>
</dhcp>
</ip>
<dnsmasq:options>
<dnsmasq:option value='dhcp-vendorclass=set:efi-http,HTTPClient:Arch:00016'/>
<dnsmasq:option value='dhcp-option-force=tag:efi-http,60,HTTPClient'/>
<dnsmasq:option value='dhcp-boot=tag:efi-http,&quot;http://192.168.100.1/httpboot/EFI/BOOT/BOOTX64.EFI&quot;'/>
</dnsmasq:options>
</network>
EOF
if ! sudo virsh net-info integration > /dev/null 2>&1; then
sudo virsh net-define /tmp/integration.xml
fi
if [[ $(sudo virsh net-info integration | grep 'Active' | awk '{print $2}') == 'no' ]]; then
sudo virsh net-start integration
fi

###########################################################
##
## Build greenboot rpm packages
##
###########################################################
greenprint "Building greenboot packages"
pushd .. && \
shopt -s extglob
version=$(cat greenboot.spec |grep Version|awk '{print $2}')
rm -rf greenboot-${version}/ rpmbuild/
mkdir -p rpmbuild/BUILD rpmbuild/RPMS rpmbuild/SOURCES rpmbuild/SPECS rpmbuild/SRPMS
mkdir greenboot-${version}
cp -r !(rpmbuild|greenboot-${version}|build.sh) greenboot-${version}/
tar -cvf v${version}.tar.gz greenboot-${version}/
mv v${version}.tar.gz rpmbuild/SOURCES/
rpmbuild -bb --define="_topdir ${PWD}/rpmbuild" greenboot.spec
chmod +x rpmbuild/RPMS/x86_64/*.rpm && \
cp rpmbuild/RPMS/x86_64/*.rpm tests/ && popd

###########################################################
##
## Build bootc container with greenboot installed
##
###########################################################
greenprint "Building rhel-edge-bootc container"
podman login quay.io -u ${QUAY_USERNAME} -p ${QUAY_PASSWORD}
podman login registry.stage.redhat.io -u ${STAGE_REDHAT_IO_USERNAME} -p ${STAGE_REDHAT_IO_TOKEN}
tee Containerfile > /dev/null << EOF
FROM ${BASE_IMAGE_URL}
# Copy the local RPM files into the container
COPY greenboot-*.rpm /tmp/
RUN dnf install -y \
/tmp/greenboot-*.rpm && \
systemctl enable greenboot-grub2-set-counter \
greenboot-grub2-set-success.service greenboot-healthcheck.service \
greenboot-loading-message.service greenboot-rpm-ostree-grub2-check-fallback.service \
redboot-auto-reboot.service redboot-task-runner.service redboot.target
# Clean up by removing the local RPMs if desired
RUN rm -f /tmp/greenboot-*.rpm
EOF
podman build --retry=5 --retry-delay=10 -t quay.io/${QUAY_USERNAME}/greenboot-bootc:${TEST_UUID} -f Containerfile .
greenprint "Pushing greenboot-bootc container to quay.io"
podman push quay.io/${QUAY_USERNAME}/greenboot-bootc:${TEST_UUID}

###########################################################
##
## BIB to convert bootc container to qcow2/iso images
##
###########################################################
greenprint "Using BIB to convert container to anaconda iso"
tee config.json > /dev/null << EOF
{
"blueprint": {
"customizations": {
"user": [
{
"name": "${EDGE_USER}",
"password": "${EDGE_USER_PASSWORD}",
"key": "${SSH_KEY_PUB}",
"groups": [
"wheel"
]
}
]
}
}
}
EOF
sudo rm -fr output && mkdir -p output
podman run \
--rm \
-it \
--privileged \
--pull=newer \
--security-opt label=type:unconfined_t \
-v $(pwd)/config.json:/config.json \
-v $(pwd)/output:/output \
-v /var/lib/containers/storage:/var/lib/containers/storage \
${BIB_URL} \
--type anaconda-iso \
--config /config.json \
--rootfs xfs \
quay.io/${QUAY_USERNAME}/greenboot-bootc:${TEST_UUID}

###########################################################
##
## Generate kickstart file and mkksiso
##
###########################################################
ISOMOUNT=$(mktemp -d)
greenprint "Mounting install.iso -> $ISOMOUNT"
sudo mount -v -o ro "output/bootiso/install.iso" "$ISOMOUNT"
NEW_KS_FILE="${TEMPDIR}/bib.ks"
greenprint "Default osbuild-base.ks"
cat "${ISOMOUNT}/osbuild-base.ks"
greenprint "Default osbuild.ks"
cat "${ISOMOUNT}/osbuild.ks"

greenprint "Preparing modified kickstart file"
cat > "$NEW_KS_FILE" << EOFKS
text
$(cat "${ISOMOUNT}/osbuild-base.ks")
$(cat "${ISOMOUNT}/osbuild.ks")
EOFKS
sed -i '/%include/d' "$NEW_KS_FILE"

greenprint "Writing new ISO"
sudo mkksiso -c "console=ttyS0,115200" --ks "$NEW_KS_FILE" "output/bootiso/install.iso" "/var/lib/libvirt/images/install.iso"

greenprint "==== NEW KICKSTART FILE ===="
cat "$NEW_KS_FILE"
greenprint "============================"

greenprint "Clean up ISO building environment"
sudo umount -v "$ISOMOUNT"
rm -rf "$ISOMOUNT"

###########################################################
##
## Provision vm with qcow2/iso artifacts
##
###########################################################
greenprint "Installing vm with bootc anaconda iso image"
greenprint "💾 Create vm qcow2 files for ISO installation"
LIBVIRT_IMAGE_PATH_UEFI=/var/lib/libvirt/images/${TEST_UUID}-disk.qcow2
sudo qemu-img create -f qcow2 "/var/lib/libvirt/images/${TEST_UUID}-disk.qcow2" 10G
sudo restorecon -Rv /var/lib/libvirt/images/
sudo virt-install --name="${TEST_UUID}-uefi"\
--disk path="${LIBVIRT_IMAGE_PATH_UEFI}",format=qcow2 \
--ram 3072 \
--vcpus 2 \
--network network=integration,mac=34:49:22:B0:83:30 \
--os-type linux \
--os-variant ${OS_VARIANT} \
--cdrom "/var/lib/libvirt/images/install.iso" \
--boot uefi \
--nographics \
--noautoconsole \
--wait=-1 \
--noreboot
greenprint "Starting UEFI VM"
sudo virsh start "${TEST_UUID}-uefi"

# Check for ssh ready to go.
greenprint "🛃 Checking for SSH is ready to go"
for _ in $(seq 0 30); do
RESULTS="$(wait_for_ssh_up $GUEST_ADDRESS)"
if [[ $RESULTS == 1 ]]; then
echo "SSH is ready now! 🥳"
break
fi
sleep 10
done
check_result

###########################################################
##
## Build upgrade container with failing-unit installed
##
###########################################################
greenprint "Building upgrade container"
tee Containerfile > /dev/null << EOF
FROM quay.io/${QUAY_USERNAME}/greenboot-bootc:${TEST_UUID}
RUN dnf install -y https://kite-webhook-prod.s3.amazonaws.com/greenboot-failing-unit-1.0-1.el8.noarch.rpm
EOF
podman build --retry=5 --retry-delay=10 -t quay.io/${QUAY_USERNAME}/greenboot-bootc:${TEST_UUID} -f Containerfile .
greenprint "Pushing upgrade container to quay.io"
podman push quay.io/${QUAY_USERNAME}/greenboot-bootc:${TEST_UUID}

###########################################################
##
## Bootc upgrade and check if greenboot can rollback
##
###########################################################
greenprint "Bootc upgrade and reboot"
sudo ssh "${SSH_OPTIONS[@]}" -i "${SSH_KEY}" ${EDGE_USER}@${GUEST_ADDRESS} "echo ${EDGE_USER_PASSWORD} |sudo -S bootc upgrade"
sudo ssh "${SSH_OPTIONS[@]}" -i "${SSH_KEY}" ${EDGE_USER}@${GUEST_ADDRESS} "echo ${EDGE_USER_PASSWORD} |nohup sudo -S systemctl reboot &>/dev/null & exit"

# Wait vm to finish the fallback
sleep 240

# Check for ssh ready to go.
greenprint "🛃 Checking for SSH is ready to go"
for _ in $(seq 0 30); do
RESULTS="$(wait_for_ssh_up $GUEST_ADDRESS)"
if [[ $RESULTS == 1 ]]; then
echo "SSH is ready now! 🥳"
break
fi
sleep 10
done
check_result

# Add instance IP address into /etc/ansible/hosts
tee ${TEMPDIR}/inventory > /dev/null << EOF
[greenboot_guest]
${GUEST_ADDRESS}
[greenboot_guest:vars]
ansible_python_interpreter=/usr/bin/python3
ansible_user=${EDGE_USER}
ansible_private_key_file=${SSH_KEY}
ansible_ssh_common_args="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
ansible_become=yes
ansible_become_method=sudo
ansible_become_pass=${EDGE_USER_PASSWORD}
EOF

# Test greenboot functionality
ansible-playbook -v -i /${TEMPDIR}/inventory greenboot-bootc.yaml || RESULTS=0

# Test result checking
check_result
exit 0
5 changes: 5 additions & 0 deletions tmt/plans/greenboot-test.fmf
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,8 @@ provision:
summary: Test greenboot with bootc qcow2 image
environment+:
TEST_CASE: bootc-qcow2

/bootc-anaconda-iso:
summary: Test greenboot with bootc anaconda iso
environment+:
TEST_CASE: bootc-anaconda-iso
2 changes: 2 additions & 0 deletions tmt/tests/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ cd ../../tests || exit 1
function run_tests() {
if [ "$TEST_CASE" = "bootc-qcow2" ]; then
./greenboot-bootc-qcow2.sh
elif [ "$TEST_CASE" = "bootc-anaconda-iso" ]; then
./greenboot-bootc-anaconda-iso.sh
else
echo "Error: Test case $TEST_CASE not found!"
exit 1
Expand Down

0 comments on commit 50329b2

Please sign in to comment.