export registry := env("REGISTRY", "humocs-man.duckdns.org/humocs-man") export image_name := env("IMAGE_NAME", "fluffy-pancake") export default_tag := env("DEFAULT_TAG", "stable") export bib_image := env("BIB_IMAGE", "quay.io/centos-bootc/bootc-image-builder:latest") alias build-vm := build-qcow2 alias rebuild-vm := rebuild-qcow2 alias run-vm := run-vm-qcow2 [private] default: @just --list # Check Just Syntax [group('Just')] check: #!/usr/bin/bash find . -type f -name "*.just" | while read -r file; do echo "Checking syntax: $file" just --unstable --fmt --check -f "$file" done echo "Checking syntax: Justfile" just --unstable --fmt --check -f Justfile # Fix Just Syntax [group('Just')] fix: #!/usr/bin/bash find . -type f -name "*.just" | while read -r file; do echo "Checking syntax: $file" just --unstable --fmt -f "$file" done echo "Checking syntax: Justfile" just --unstable --fmt -f Justfile || { exit 1; } # Clean Repo [group('Utility')] clean: #!/usr/bin/bash set -eoux pipefail touch _build find *_build* -exec rm -rf {} \; rm -f previous.manifest.json rm -f changelog.md rm -f output.env rm -rf output/ # Sudo Clean Repo [group('Utility')] [private] sudo-clean: just sudoif just clean # sudoif bash function [group('Utility')] [private] sudoif command *args: #!/usr/bin/bash function sudoif(){ if [[ "${UID}" -eq 0 ]]; then "$@" elif [[ "$(command -v sudo)" && -n "${SSH_ASKPASS:-}" ]] && [[ -n "${DISPLAY:-}" || -n "${WAYLAND_DISPLAY:-}" ]]; then /usr/bin/sudo --askpass "$@" || exit 1 elif [[ "$(command -v sudo)" ]]; then /usr/bin/sudo "$@" || exit 1 else exit 1 fi } sudoif {{ command }} {{ args }} # Build the local image using Podman from Containerfile build $target_image=image_name $tag=default_tag: #!/usr/bin/env bash BUILD_ARGS=() if [[ -z "$(git status -s)" ]]; then BUILD_ARGS+=("--build-arg" "SHA_HEAD_SHORT=$(git rev-parse --short HEAD)") fi podman build \ "${BUILD_ARGS[@]}" \ --pull=newer \ --tag "${target_image}:${tag}" \ . # Pulls remote image or loads local image into rootful podman storage for BIB _rootful_load_image $target_image $tag=default_tag: #!/usr/bin/bash set -eoux pipefail FULL_IMAGE="${target_image}:${tag}" # Target ist Remote-Image -> Direkt via Rootful Podman pullen if [[ "${target_image}" != localhost/* ]]; then echo "==> Pulle Remote-Image: ${FULL_IMAGE}" just sudoif podman pull "${FULL_IMAGE}" exit 0 fi # Target ist lokales Image -> In Rootful Storage kopieren if [[ -n "${SUDO_USER:-}" || "${UID}" -eq "0" ]]; then echo "Bereits als root aktiv." exit 0 fi set +e podman inspect -t image "${FULL_IMAGE}" > /dev/null 2>&1 return_code=$? set -e USER_IMG_ID=$(podman images -q "${FULL_IMAGE}") if [[ $return_code -eq 0 ]]; then ID=$(just sudoif podman images -q "${FULL_IMAGE}") if [[ "$ID" != "$USER_IMG_ID" ]]; then COPYTMP=$(mktemp -p "${PWD}" -d -t _build_podman_load.XXXXXXXXXX) podman save "${FULL_IMAGE}" -o "${COPYTMP}/image.tar" just sudoif podman load -i "${COPYTMP}/image.tar" rm -rf "${COPYTMP}" fi else just sudoif podman pull "${FULL_IMAGE}" fi # Build a bootc bootable image using Bootc Image Builder (BIB) # HINWEIS: Bei Typ "iso" wird die Image-Referenz im Kickstart (iso/iso.toml) # automatisch auf $target_image:$tag umgeschrieben. So installiert eine lokal # gebaute Test-ISO auch das Test-Image und nicht :stable. _build-bib $target_image $tag $type $config: (_rootful_load_image target_image tag) #!/usr/bin/env bash set -euo pipefail args="--type ${type} " args+="--use-librepo=True " args+="--rootfs=btrfs" BUILDTMP=$(mktemp -p "${PWD}" -d -t _build-bib.XXXXXXXXXX) CONFIG_ABS="$(pwd)/${config}" CONFIGTMP="" if [[ "${type}" == "iso" ]]; then CONFIGTMP=$(mktemp -p "${PWD}" -d -t _build-bib-config.XXXXXXXXXX) sed "s|humocs-man.duckdns.org/humocs-man/fluffy-pancake:stable|{{ target_image }}:{{ tag }}|g" \ "${CONFIG_ABS}" > "$CONFIGTMP/config.toml" CONFIG_ABS="$CONFIGTMP/config.toml" echo "==> ISO-Kickstart zeigt auf {{ target_image }}:{{ tag }}" fi sudo podman run \ --rm \ -it \ --privileged \ --pull=newer \ --net=host \ --security-opt label=type:unconfined_t \ -v "${CONFIG_ABS}":/config.toml:ro \ -v "$BUILDTMP":/output \ -v /var/lib/containers/storage:/var/lib/containers/storage \ "${bib_image}" \ ${args} \ "${target_image}:${tag}" mkdir -p output sudo mv -f $BUILDTMP/* output/ sudo rmdir $BUILDTMP if [[ -n "$CONFIGTMP" ]]; then rm -rf "$CONFIGTMP"; fi sudo chown -R $USER:$USER output/ # Rebuild-Schritt: Führt vor BIB ein lokales 'podman build' aus _rebuild-bib $target_image $tag $type $config: (build target_image tag) && (_build-bib target_image tag type config) # ============================================================================== # BUILD TARGETS (Pullen aus Remote-Registry) # ============================================================================== # Build a QCOW2 virtual machine image from Registry [group('Build Virtual Machine Image')] build-qcow2 $target_image=(registry + "/" + image_name) $tag=default_tag: && (_build-bib target_image tag "qcow2" "iso/disk.toml") # Build a RAW virtual machine image from Registry [group('Build Virtual Machine Image')] build-raw $target_image=(registry + "/" + image_name) $tag=default_tag: && (_build-bib target_image tag "raw" "iso/disk.toml") # Build an ISO virtual machine image from Registry [group('Build Virtual Machine Image')] build-iso $target_image=(registry + "/" + image_name) $tag=default_tag: && (_build-bib target_image tag "iso" "iso/iso.toml") # ============================================================================== # REBUILD TARGETS (Lokaler Build via Containerfile + Image Builder) # ============================================================================== # Rebuild a QCOW2 virtual machine image locally [group('Build Virtual Machine Image')] rebuild-qcow2 $target_image=("localhost/" + image_name) $tag=default_tag: && (_rebuild-bib target_image tag "qcow2" "iso/disk.toml") # Rebuild a RAW virtual machine image locally [group('Build Virtual Machine Image')] rebuild-raw $target_image=("localhost/" + image_name) $tag=default_tag: && (_rebuild-bib target_image tag "raw" "iso/disk.toml") # Rebuild an ISO virtual machine image locally [group('Build Virtual Machine Image')] rebuild-iso $target_image=("localhost/" + image_name) $tag=default_tag: && (_rebuild-bib target_image tag "iso" "iso/iso.toml") # ============================================================================== # TEST TARGETS (nur lokale Test-Disks, Image bleibt sauber) # ============================================================================== # Injiziert einen Test-User in ein gebautes Plattenabbild (qcow2/raw). # Das Container-Image wird NICHT veraendert - nur die lokale Test-Disk. # ISO braucht das nicht (Anaconda legt den User bei Installation an). # Passwort: keine ':' und keine Shell-Sonderzeichen ($, `, !, \). [group('Test')] seed-testuser type="qcow2" user="test" password="test123": #!/usr/bin/env bash set -euo pipefail if [[ "{{ type }}" == "iso" ]]; then echo "FEHLER: Bei ISO den User im Anaconda-Installer anlegen, kein Seed noetig." exit 1 fi if [[ "{{ password }}" == *:* ]]; then echo "FEHLER: Passwort darf kein ':' enthalten (chpasswd-Format)." exit 1 fi image_file="output/{{ type }}/disk.{{ type }}" if [[ ! -f "${image_file}" ]]; then echo "FEHLER: ${image_file} nicht gefunden. Erst 'just build-{{ type }} ...' ausfuehren." exit 1 fi if ! command -v virt-customize >/dev/null; then echo "FEHLER: virt-customize fehlt. Installieren mit: sudo dnf install -y guestfs-tools" exit 1 fi echo "==> Injiziere Test-User '{{ user }}' in ${image_file} (nur Test-Disk)" sudo virt-customize -a "${image_file}" \ --selinux-relabel \ --run-command "useradd -m -G wheel '{{ user }}' && echo '{{ user }}:{{ password }}' | chpasswd" echo "==> Fertig. Login als '{{ user }}', sudo via wheel-Gruppe." # ============================================================================== # RUN TARGETS # ============================================================================== # Run a virtual machine with the specified image type and configuration _run-vm $target_image $tag $type $config: #!/usr/bin/bash set -eoux pipefail image_file="output/${type}/disk.${type}" if [[ $type == iso ]]; then image_file="output/bootiso/install.iso" fi if [[ ! -f "${image_file}" ]]; then just "build-${type}" "$target_image" "$tag" fi port=8006 while grep -q :${port} <<< $(ss -tunalp); do port=$(( port + 1 )) done echo "Using Port: ${port}" echo "Connect to http://localhost:${port}" run_args=() run_args+=(--rm --privileged) run_args+=(--pull=newer) run_args+=(--publish "127.0.0.1:${port}:8006") run_args+=(--env "CPU_CORES=4") run_args+=(--env "RAM_SIZE=8G") run_args+=(--env "DISK_SIZE=64G") run_args+=(--env "TPM=Y") run_args+=(--env "GPU=Y") run_args+=(--device=/dev/kvm) run_args+=(--volume "${PWD}/${image_file}":"/boot.${type}") run_args+=(docker.io/qemux/qemu) (sleep 30 && xdg-open http://localhost:"$port") & podman run "${run_args[@]}" # Run a virtual machine from a QCOW2 image [group('Run Virtual Machine')] run-vm-qcow2 $target_image=(registry + "/" + image_name) $tag=default_tag: && (_run-vm target_image tag "qcow2" "iso/disk.toml") # Run a virtual machine from a RAW image [group('Run Virtual Machine')] run-vm-raw $target_image=(registry + "/" + image_name) $tag=default_tag: && (_run-vm target_image tag "raw" "iso/disk.toml") # Run a virtual machine from an ISO [group('Run Virtual Machine')] run-vm-iso $target_image=(registry + "/" + image_name) $tag=default_tag: && (_run-vm target_image tag "iso" "iso/iso.toml") # Run a virtual machine using systemd-vmspawn [group('Run Virtual Machine')] spawn-vm rebuild="0" type="qcow2" ram="6G": #!/usr/bin/env bash set -euo pipefail [ "{{ rebuild }}" -eq 1 ] && echo "Rebuilding the ISO" && just build-vm {{ rebuild }} {{ type }} systemd-vmspawn \ -M "bootc-image" \ --console=gui \ --cpus=2 \ --ram=$(echo {{ ram }}| /usr/bin/numfmt --from=iec) \ --network-user-mode \ --vsock=false --pass-ssh-key=false \ -i ./output/**/*.{{ type }} # Runs shell check on all Bash scripts lint: #!/usr/bin/env bash set -eoux pipefail if ! command -v shellcheck &> /dev/null; then echo "shellcheck could not be found. Please install it." exit 1 fi /usr/bin/find . -iname "*.sh" -type f -exec shellcheck "{}" ';' # Runs shfmt on all Bash scripts format: #!/usr/bin/env bash set -eoux pipefail if ! command -v shfmt &> /dev/null; then echo "shfmt could not be found. Please install it." exit 1 fi /usr/bin/find . -iname "*.sh" -type f -exec shfmt --write "{}" ';'