From a463554fc7258ef952417a35df18d19de689b0b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Mass=C3=A9?= Date: Tue, 16 Sep 2025 11:09:50 -0400 Subject: [PATCH] wip --- bootc/{scenario3a => }/config.toml | 0 bootc/scenario2/Containerfile | 8 +++ .../etc/default/migrate-vm-printserver.env | 10 ++++ .../check/required.d/30_printserver_check.sh | 18 ++++++ .../qemu/networks/autostart/default.xml | 1 + .../etc/libvirt/qemu/networks/default.xml | 19 +++++++ .../etc/systemd/system/migrate-vm@.service | 19 +++++++ .../root/usr/local/bin/migrate-vm.sh | 56 +++++++++++++++++++ .../etc/default/bootstrap-vm-nextcloud.env | 1 + .../etc/systemd/system/bootstrap-vm@.service | 4 +- .../root/usr/local/bin/bootstrap-vm.sh | 16 +++++- .../local/libvirt/images/nextcloud/.gitignore | 2 - bootc/scripts/build.sh | 40 ++++++++++++- flightctl/fleets.yaml | 6 +- 14 files changed, 193 insertions(+), 7 deletions(-) rename bootc/{scenario3a => }/config.toml (100%) create mode 100644 bootc/scenario2/Containerfile create mode 100644 bootc/scenario2/root/etc/default/migrate-vm-printserver.env create mode 100755 bootc/scenario2/root/etc/greenboot/check/required.d/30_printserver_check.sh create mode 120000 bootc/scenario2/root/etc/libvirt/qemu/networks/autostart/default.xml create mode 100644 bootc/scenario2/root/etc/libvirt/qemu/networks/default.xml create mode 100644 bootc/scenario2/root/etc/systemd/system/migrate-vm@.service create mode 100755 bootc/scenario2/root/usr/local/bin/migrate-vm.sh delete mode 100644 bootc/scenario3a/root/usr/local/libvirt/images/nextcloud/.gitignore diff --git a/bootc/scenario3a/config.toml b/bootc/config.toml similarity index 100% rename from bootc/scenario3a/config.toml rename to bootc/config.toml diff --git a/bootc/scenario2/Containerfile b/bootc/scenario2/Containerfile new file mode 100644 index 0000000..0c06694 --- /dev/null +++ b/bootc/scenario2/Containerfile @@ -0,0 +1,8 @@ +FROM edge-registry.itix.fr/demo-edge-retail/base:latest + +ADD --chown=root:root root / + +RUN < + default + + + + + + host + + + + + + + + + + + diff --git a/bootc/scenario2/root/etc/systemd/system/migrate-vm@.service b/bootc/scenario2/root/etc/systemd/system/migrate-vm@.service new file mode 100644 index 0000000..c6f87f4 --- /dev/null +++ b/bootc/scenario2/root/etc/systemd/system/migrate-vm@.service @@ -0,0 +1,19 @@ +[Unit] +Description=RHDE VM Migration Service +Documentation=man:systemd.service(5) +After=network-online.target +Wants=network-online.target + +# Only start if the VM root disk does not exist +ConditionPathExists=!/var/lib/libvirt/images/%i/root.qcow2 + +# Remain started to avoid race conditions +Persistent=true + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/migrate-vm.sh %i +EnvironmentFile=/etc/default/migrate-vm-%i.env + +[Install] +WantedBy=multi-user.target diff --git a/bootc/scenario2/root/usr/local/bin/migrate-vm.sh b/bootc/scenario2/root/usr/local/bin/migrate-vm.sh new file mode 100755 index 0000000..d50b1d2 --- /dev/null +++ b/bootc/scenario2/root/usr/local/bin/migrate-vm.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +set -Eeuo pipefail + +if [[ $# -ne 1 ]]; then + echo "Usage: $0 " + exit 1 +fi + +VM="${1}" +if [ -d "/var/lib/libvirt/images/${VM}/" ]; then + echo "VM ${VM} already exists. Please remove it first." + exit 1 +fi + +temp_dir=$(mktemp -d) +cleanup() { + local exit_code=$? + rm -rf "$temp_dir" + if [ $exit_code -ne 0 ]; then + echo "An error occurred. Cleaning up..." + virsh destroy "${VM}" || true + virsh undefine "${VM}" --nvram || true + rm -rf "/var/lib/libvirt/images/${VM}/" + fi +} +trap cleanup EXIT + +# Create a temporary directory to hold the VM image and copy the base image there +install -m 0710 -o root -g qemu --context=system_u:object_r:virt_image_t:s0 -d "$temp_dir" +install -m 0710 -o root -g qemu -Z -d "/var/lib/libvirt/images/${VM}" + +# Migrate the VM disk from Hyper-V to KVM +echo "Copying the VM disk from Hyper-V..." +rclone copy "$DOMAIN_HYPERV_DISK_LOCATION" "$temp_dir" +echo "Converting the VM disk to qcow2 format..." +qemu-img convert -O qcow2 "$temp_dir/$DOMAIN_HYPERV_DISK_NAME" "/var/lib/libvirt/images/${VM}/root.qcow2" +restorecon -F "/var/lib/libvirt/images/${VM}/root.qcow2" + +# Create and start the VM using virt-install +echo "Creating and starting the VM ${VM}..." +virt-install --name "${VM}" \ + --autostart \ + --cpu=host-passthrough \ + --vcpus=${DOMAIN_VCPUS} \ + --ram=${DOMAIN_RAM} \ + --os-variant=${DOMAIN_OS_VARIANT} \ + --disk=path=/var/lib/libvirt/images/${VM}/root.qcow2,bus=sata,format=qcow2 \ + --disk=path=/usr/share/virtio-win/virtio-win.iso,device=cdrom,bus=sata \ + --boot uefi \ + --import \ + --network=network=default,mac=${DOMAIN_MAC_ADDRESS} \ + --noautoconsole + +echo "VM ${VM} has been created and started." +exit 0 diff --git a/bootc/scenario3a/root/etc/default/bootstrap-vm-nextcloud.env b/bootc/scenario3a/root/etc/default/bootstrap-vm-nextcloud.env index 2df58d9..c17f9e5 100644 --- a/bootc/scenario3a/root/etc/default/bootstrap-vm-nextcloud.env +++ b/bootc/scenario3a/root/etc/default/bootstrap-vm-nextcloud.env @@ -4,3 +4,4 @@ DOMAIN_DISK_SIZE=100 DOMAIN_OS_VARIANT=rhel9.6 DOMAIN_MAC_ADDRESS=04:00:00:00:00:01 FLIGHTCTL_LABELS_OVERRIDE={ "type": "virtualmachine", "vm.name": "nextcloud", "scenario": "scenario1" } +DOMAIN_DISK_SOURCE=edge-registry.itix.fr/demo-edge-retail/scenario1:latest diff --git a/bootc/scenario3a/root/etc/systemd/system/bootstrap-vm@.service b/bootc/scenario3a/root/etc/systemd/system/bootstrap-vm@.service index 508b19e..6bd41e1 100644 --- a/bootc/scenario3a/root/etc/systemd/system/bootstrap-vm@.service +++ b/bootc/scenario3a/root/etc/systemd/system/bootstrap-vm@.service @@ -5,9 +5,11 @@ Documentation=man:systemd.service(5) # Only start if the VM root disk does not exist ConditionPathExists=!/var/lib/libvirt/images/%i/root.qcow2 +# Remain started to avoid race conditions +Persistent=true + [Service] Type=oneshot -Persistent=true ExecStart=/usr/local/bin/bootstrap-vm.sh %i EnvironmentFile=/etc/default/bootstrap-vm-%i.env diff --git a/bootc/scenario3a/root/usr/local/bin/bootstrap-vm.sh b/bootc/scenario3a/root/usr/local/bin/bootstrap-vm.sh index 0512d18..b5b5467 100755 --- a/bootc/scenario3a/root/usr/local/bin/bootstrap-vm.sh +++ b/bootc/scenario3a/root/usr/local/bin/bootstrap-vm.sh @@ -28,7 +28,13 @@ trap cleanup EXIT # Create a temporary directory to hold the VM image and copy the base image there install -m 0710 -o root -g qemu --context=system_u:object_r:virt_image_t:s0 -d "$temp_dir" -install -m 0770 -o root -g qemu --context=system_u:object_r:virt_image_t:s0 "/usr/local/libvirt/images/${VM}/qcow2/disk.qcow2" "$temp_dir/root.qcow2" + +# Pull the base image defined in the environment file +podman artifact pull "${DOMAIN_DISK_SOURCE}" +podman artifact extract "${DOMAIN_DISK_SOURCE}" "$temp_dir/root.qcow2" +chown root:qemu "$temp_dir/root.qcow2" +chmod 0660 "$temp_dir/root.qcow2" +chcon system_u:object_r:virt_image_t:s0 "$temp_dir/root.qcow2" # Inject the Flightctl configuration file (w/ enrollment certificates) into the VM image # Note: The injected config file will be moved to the right place in the VM by a systemd override in the base image @@ -39,6 +45,7 @@ if [ -f /etc/flightctl/config.yaml ]; then else cp /etc/flightctl/config.yaml "$temp_dir/config.yaml" fi + echo "Injecting Flightctl configuration into the VM image..." guestfish --add "$temp_dir/root.qcow2" -m /dev/sda4 <" +if [ "$#" -lt 1 ]; then + echo "Usage: $0 [qcow2-target-image]" exit 1 fi TARGET_IMAGE="$1" +QCOW2_TARGET_IMAGE="${2:-}" + +# Parses the target image to get the tag and registry +# Example: myregistry.com/myimage:tag -> (myregistry.com/myimage + tag) +if [[ "$TARGET_IMAGE" == *":"* ]]; then + TARGET_IMAGE_NAME="${TARGET_IMAGE%%:*}" + TARGET_IMAGE_TAG="${TARGET_IMAGE##*:}" +else + TARGET_IMAGE_NAME="$TARGET_IMAGE" + TARGET_IMAGE_TAG="latest" + TARGET_IMAGE="${IMAGE_NAME}:latest" +fi + +# Compute the qcow2 target image if not provided +if [ -z "$QCOW2_TARGET_IMAGE" ]; then + QCOW2_TARGET_IMAGE="${TARGET_IMAGE_NAME}-qcow2:${TARGET_IMAGE_TAG}" +fi + OCI_REGISTRY="${TARGET_IMAGE%%/*}" SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" @@ -48,5 +66,23 @@ if [ -x "$PWD/custom.sh" ]; then "$PWD/custom.sh" fi +echo "Building and pushing image $TARGET_IMAGE..." podman build --no-cache -t "${TARGET_IMAGE}" . podman push --sign-by-sigstore-private-key "$PROJECT_DIR/signing-key.private" --sign-passphrase-file "$PROJECT_DIR/signing-key.pass" "${TARGET_IMAGE}" + +echo "Building and pushing image $QCOW2_TARGET_IMAGE..." +temp_dir="$(mktemp -d)" +trap 'rm -rf "$temp_dir"' EXIT + +function bootc_image_builder () { + local config="$1" + shift + podman run --rm -it --privileged --pull=newer --security-opt label=type:unconfined_t -v "$config:/$(basename $config):ro" \ + -v $temp_dir:/output -v /var/lib/containers/storage:/var/lib/containers/storage \ + registry.redhat.io/rhel10/bootc-image-builder:latest --config "/$(basename $config)" "$@" +} + +bootc_image_builder "$PROJECT_DIR/config.toml" --type qcow2 "$TARGET_IMAGE" +podman artifact add "$QCOW2_TARGET_IMAGE" "$temp_dir/qcow2/disk.qcow2" +podman artifact push --sign-by-sigstore-private-key "$PROJECT_DIR/signing-key.private" --sign-passphrase-file "$PROJECT_DIR/signing-key.pass" "$QCOW2_TARGET_IMAGE" +podman artifact rm "$QCOW2_TARGET_IMAGE" diff --git a/flightctl/fleets.yaml b/flightctl/fleets.yaml index 1b68377..1f340b2 100644 --- a/flightctl/fleets.yaml +++ b/flightctl/fleets.yaml @@ -19,7 +19,8 @@ spec: os: image: edge-registry.itix.fr/demo-edge-retail/base:latest systemd: - matchPatterns: [] + matchPatterns: + - greenboot-healthcheck.service --- apiVersion: flightctl.io/v1alpha1 kind: Fleet @@ -53,6 +54,7 @@ spec: - nextcloud-db.service - nextcloud-nginx.service - nextcloud-redis.service + - greenboot-healthcheck.service --- apiVersion: flightctl.io/v1alpha1 kind: Fleet @@ -80,6 +82,7 @@ spec: - bootstrap-vm@nextcloud.service - libvirtd.service - nftables.service + - greenboot-healthcheck.service --- apiVersion: flightctl.io/v1alpha1 kind: Fleet @@ -112,3 +115,4 @@ spec: - odoo-app.service - odoo-db.service - odoo-init.service + - greenboot-healthcheck.service