From 8c6b00ffd80bf4542464a2415cce902d685e0fb5 Mon Sep 17 00:00:00 2001 From: Tulip Blossom Date: Wed, 8 Jan 2025 21:26:12 -0300 Subject: [PATCH] feat: add justfile pattern from M2's PRs to bluefin (#54) --- .gitignore | 1 + Justfile | 203 +++++++++++++++++++++++++++++++++++++++++++++++++++++ image.toml | 3 + iso.toml | 19 +++++ 4 files changed, 226 insertions(+) create mode 100644 Justfile create mode 100644 image.toml create mode 100644 iso.toml diff --git a/.gitignore b/.gitignore index 2f01194..bbc6166 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ cosign.key +_build_* diff --git a/Justfile b/Justfile new file mode 100644 index 0000000..6608d89 --- /dev/null +++ b/Justfile @@ -0,0 +1,203 @@ +export repo_organization := env("GITHUB_REPOSITORY_OWNER", "yourname") +export image_name := env("IMAGE_NAME", "yourimage") +export default_tag := env("DEFAULT_TAG", "latest") +export bib_image := env("BIB_IMAGE", "ghcr.io/osbuild/bootc-image-builder:latest") + +export SUDO_DISPLAY := if `if [ -n "${DISPLAY:-}" ] || [ -n "${WAYLAND_DISPLAY:-}" ]; then echo true; fi` == "true" { "true" } else { "false" } +export SUDOIF := if `id -u` == "0" { "" } else { if SUDO_DISPLAY == "true" { "sudo --askpass" } else { "sudo" } } +export PODMAN := if path_exists("/usr/bin/podman") == "true" { env("PODMAN", "/usr/bin/podman") } else { if path_exists("/usr/bin/docker") == "true" { env("PODMAN", "docker") } else { env("PODMAN", "exit 1 ; ") } } + +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 + +# Sudo Clean Repo +[group('Utility')] +[private] +sudo-clean: + ${SUDOIF} just clean + +build $target_image=image_name $tag=default_tag: + #!/usr/bin/env bash + + # Get Version + ver="${tag}-$(date +%Y%m%d)" + + BUILD_ARGS=() + BUILD_ARGS+=("--build-arg" "IMAGE_NAME=${image_name}") + BUILD_ARGS+=("--build-arg" "IMAGE_VENDOR=${repo_organization}") + 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 "${image_name}:${tag}" \ + . + +_rootful_load_image $target_image=image_name $tag=default_tag: + #!/usr/bin/bash + set -eoux pipefail + + if [[ -n "${SUDO_USER:-}" || "${UID}" -eq "0" ]]; then + echo "Already root or running under sudo, no need to load image from user ${PODMAN}." + exit 0 + fi + + set +e + resolved_tag=$(${PODMAN} inspect -t image "${target_image}:${tag}" | jq -r '.[].RepoTags.[0]') + return_code=$? + set -e + + if [[ $return_code -eq 0 ]]; then + # Load into Rootful ${PODMAN} + ID=$(${SUDOIF} ${PODMAN} images --filter reference="${target_image}:${tag}" --format "'{{ '{{.ID}}' }}'") + if [[ -z "$ID" ]]; then + COPYTMP=$(mktemp -p "${PWD}" -d -t _build_podman_scp.XXXXXXXXXX) + ${SUDOIF} TMPDIR=${COPYTMP} ${PODMAN} image scp ${UID}@localhost::"${target_image}:${tag}" root@localhost::"${target_image}:${tag}" + rm -rf "${COPYTMP}" + fi + else + # Make sure the image is present and/or up to date + ${SUDOIF} ${PODMAN} pull "${target_image}:${tag}" + fi + +_build-bib $target_image $tag $type $config: (_rootful_load_image target_image tag) + #!/usr/bin/env bash + set -euo pipefail + + mkdir -p "output" + + echo "Cleaning up previous build" + if [[ $type == iso ]]; then + sudo rm -rf "output/bootiso" || true + else + sudo rm -rf "output/${type}" || true + fi + + args="--type ${type}" + + if [[ $target_image == localhost/* ]]; then + args+=" --local" + fi + + sudo ${PODMAN} run \ + --rm \ + -it \ + --privileged \ + --pull=newer \ + --net=host \ + --security-opt label=type:unconfined_t \ + -v $(pwd)/${config}:/config.toml:ro \ + -v $(pwd)/output:/output \ + -v /var/lib/containers/storage:/var/lib/containers/storage \ + "${bib_image}" \ + ${args} \ + "${target_image}" + + sudo chown -R $USER:$USER output + +_rebuild-bib $target_image $tag $type $config: (build target_image tag) && (_build-bib target_image tag type config) + +[group('Build Virtual Machine Image')] +build-qcow2 $target_image=("localhost/" + image_name) $tag=default_tag: && (_build-bib target_image tag "qcow2" "image.toml") + +[group('Build Virtual Machine Image')] +build-raw $target_image=("localhost/" + image_name) $tag=default_tag: && (_build-bib target_image tag "raw" "image.toml") + +[group('Build Virtual Machine Image')] +build-iso $target_image=("localhost/" + image_name) $tag=default_tag: && (_build-bib target_image tag "iso" "iso.toml") + +[group('Build Virtual Machine Image')] +rebuild-qcow2 $target_image=("localhost/" + image_name) $tag=default_tag: && (_rebuild-bib target_image tag "qcow2" "image.toml") + +[group('Build Virtual Machine Image')] +rebuild-raw $target_image=("localhost/" + image_name) $tag=default_tag: && (_rebuild-bib target_image tag "raw" "image.toml") + +[group('Build Virtual Machine Image')] +rebuild-iso $target_image=("localhost/" + image_name) $tag=default_tag: && (_rebuild-bib target_image tag "iso" "iso.toml") + +_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 + + # Determine which port to use + 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 "BOOT_MODE=windows_secure") + 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-docker) + ${PODMAN} run "${run_args[@]}" & + xdg-open http://localhost:${port} + fg "%${PODMAN}" + +[group('Run Virtual Machine')] +run-vm-qcow2 $target_image=("localhost/" + image_name) $tag=default_tag: && (_run-vm target_image tag "qcow2" "image-builder.config.toml") + +[group('Run Virtual Machine')] +run-vm-raw $target_image=("localhost/" + image_name) $tag=default_tag: && (_run-vm target_image tag "raw" "image-builder.config.toml") + +[group('Run Virtual Machine')] +run-vm-iso $target_image=("localhost/" + image_name) $tag=default_tag: && (_run-vm target_image tag "iso" "image-builder-iso.config.toml") diff --git a/image.toml b/image.toml new file mode 100644 index 0000000..7478400 --- /dev/null +++ b/image.toml @@ -0,0 +1,3 @@ +[[customizations.filesystem]] +mountpoint = "/" +minsize = "20 GiB" diff --git a/iso.toml b/iso.toml new file mode 100644 index 0000000..1b3084d --- /dev/null +++ b/iso.toml @@ -0,0 +1,19 @@ +[customizations.installer.kickstart] +contents = """ +%post +bootc switch --mutate-in-place --transport registry ghcr.io/yourname/yourusername:latest +%end +""" + +[customizations.installer.modules] +enable = [ + "org.fedoraproject.Anaconda.Modules.Storage" +] +disable = [ + "org.fedoraproject.Anaconda.Modules.Network", + "org.fedoraproject.Anaconda.Modules.Security", + "org.fedoraproject.Anaconda.Modules.Services", + "org.fedoraproject.Anaconda.Modules.Users", + "org.fedoraproject.Anaconda.Modules.Subscription", + "org.fedoraproject.Anaconda.Modules.Timezone" +]