330 lines
11 KiB
Makefile
330 lines
11 KiB
Makefile
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 "{}" ';'
|