332 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Makefile
		
	
	
	
	
	
			
		
		
	
	
			332 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Makefile
		
	
	
	
	
	
export repo_organization := env("GITHUB_REPOSITORY_OWNER", "cx")
 | 
						|
export image_name := env("IMAGE_NAME", "fedora-coreos-incus-image")
 | 
						|
export centos_version := env("CENTOS_VERSION", "stream10")
 | 
						|
export fedora_version := env("CENTOS_VERSION", "42")
 | 
						|
export default_tag := env("DEFAULT_TAG", "latest")
 | 
						|
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 -f 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 }}
 | 
						|
 | 
						|
# This Justfile recipe builds a container image using Podman.
 | 
						|
#
 | 
						|
# Arguments:
 | 
						|
#   $target_image - The tag you want to apply to the image (default: aurora).
 | 
						|
#   $tag - The tag for the image (default: lts).
 | 
						|
#   $dx - Enable DX (default: "0").
 | 
						|
#   $hwe - Enable HWE (default: "0").
 | 
						|
#   $gdx - Enable GDX (default: "0").
 | 
						|
#
 | 
						|
# DX:
 | 
						|
#   Developer Experience (DX) is a feature that allows you to install the latest developer tools for your system.
 | 
						|
#   Packages include VScode, Docker, Distrobox, and more.
 | 
						|
# HWE:
 | 
						|
#   Hardware Enablement (HWE) is a feature that allows you to install the latest hardware support for your system.
 | 
						|
#   Currently this install the Hyperscale SIG kernel which will stay ahead of the CentOS Stream kernel and enables btrfs
 | 
						|
# GDX: https://docs.projectaurora.io/gdx/
 | 
						|
#   GPU Developer Experience (GDX) creates a base as an AI and Graphics platform.
 | 
						|
#   Installs Nvidia drivers, CUDA, and other tools.
 | 
						|
#
 | 
						|
# The script constructs the version string using the tag and the current date.
 | 
						|
# If the git working directory is clean, it also includes the short SHA of the current HEAD.
 | 
						|
#
 | 
						|
# just build $target_image $tag $dx $hwe $gdx
 | 
						|
#
 | 
						|
# Example usage:
 | 
						|
#   just build aurora lts 1 0 1
 | 
						|
#
 | 
						|
# This will build an image 'aurora:lts' with DX and GDX enabled.
 | 
						|
#
 | 
						|
 | 
						|
# Build the image using the specified parameters
 | 
						|
build $target_image=image_name $tag=default_tag $dx="0" $hwe="0" $gdx="0":
 | 
						|
    #!/usr/bin/env bash
 | 
						|
 | 
						|
    # Get Version
 | 
						|
    ver="${tag}-${centos_version}.$(date +%Y%m%d)"
 | 
						|
 | 
						|
    BUILD_ARGS=()
 | 
						|
    BUILD_ARGS+=("--build-arg" "MAJOR_VERSION=${centos_version}")
 | 
						|
    BUILD_ARGS+=("--build-arg" "IMAGE_NAME=${target_image}")
 | 
						|
    BUILD_ARGS+=("--build-arg" "IMAGE_VENDOR=${repo_organization}")
 | 
						|
    BUILD_ARGS+=("--build-arg" "ENABLE_DX=${dx}")
 | 
						|
    BUILD_ARGS+=("--build-arg" "ENABLE_HWE=${hwe}")
 | 
						|
    BUILD_ARGS+=("--build-arg" "ENABLE_GDX=${gdx}")
 | 
						|
    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}" \
 | 
						|
        .
 | 
						|
 | 
						|
# Command: _rootful_load_image
 | 
						|
# Description: This script checks if the current user is root or running under sudo. If not, it attempts to resolve the image tag using podman inspect.
 | 
						|
#              If the image is found, it loads it into rootful podman. If the image is not found, it pulls it from the repository.
 | 
						|
#
 | 
						|
# Parameters:
 | 
						|
#   $target_image - The name of the target image to be loaded or pulled.
 | 
						|
#   $tag - The tag of the target image to be loaded or pulled. Default is 'default_tag'.
 | 
						|
#
 | 
						|
# Example usage:
 | 
						|
#   _rootful_load_image my_image latest
 | 
						|
#
 | 
						|
# Steps:
 | 
						|
# 1. Check if the script is already running as root or under sudo.
 | 
						|
# 2. Check if target image is in the non-root podman container storage)
 | 
						|
# 3. If the image is found, load it into rootful podman using podman scp.
 | 
						|
# 4. If the image is not found, pull it from the remote repository into reootful podman.
 | 
						|
 | 
						|
_rootful_load_image $target_image=image_name $tag=default_tag:
 | 
						|
    #!/usr/bin/bash
 | 
						|
    set -eoux pipefail
 | 
						|
 | 
						|
    # Check if already running as root or under sudo
 | 
						|
    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
 | 
						|
 | 
						|
    # Try to resolve the image tag using podman inspect
 | 
						|
    set +e
 | 
						|
    resolved_tag=$(podman inspect -t image "${target_image}:${tag}" | jq -r '.[].RepoTags.[0]')
 | 
						|
    return_code=$?
 | 
						|
    set -e
 | 
						|
 | 
						|
    USER_IMG_ID=$(podman images --filter reference="${target_image}:${tag}" --format "'{{ '{{.ID}}' }}'")
 | 
						|
 | 
						|
    if [[ $return_code -eq 0 ]]; then
 | 
						|
        # If the image is found, load it into rootful podman
 | 
						|
        ID=$(just sudoif podman images --filter reference="${target_image}:${tag}" --format "'{{ '{{.ID}}' }}'")
 | 
						|
        if [[ "$ID" != "$USER_IMG_ID" ]]; then
 | 
						|
            # If the image ID is not found or different from user, copy the image from user podman to root podman
 | 
						|
            COPYTMP=$(mktemp -p "${PWD}" -d -t _build_podman_scp.XXXXXXXXXX)
 | 
						|
            just sudoif TMPDIR=${COPYTMP} podman image scp ${UID}@localhost::"${target_image}:${tag}" root@localhost::"${target_image}:${tag}"
 | 
						|
            rm -rf "${COPYTMP}"
 | 
						|
        fi
 | 
						|
    else
 | 
						|
        # If the image is not found, pull it from the repository
 | 
						|
        just sudoif podman pull "${target_image}:${tag}"
 | 
						|
    fi
 | 
						|
 | 
						|
# Build a bootc bootable image using Bootc Image Builder (BIB)
 | 
						|
# Converts a container image to a bootable image
 | 
						|
# Parameters:
 | 
						|
#   target_image: The name of the image to build (ex. localhost/fedora)
 | 
						|
#   tag: The tag of the image to build (ex. latest)
 | 
						|
#   type: The type of image to build (ex. qcow2, raw, iso)
 | 
						|
#   config: The configuration file to use for the build (default: image.toml)
 | 
						|
 | 
						|
# Example: just _rebuild-bib localhost/fedora latest qcow2 image.toml
 | 
						|
_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"
 | 
						|
 | 
						|
    if [[ $target_image == localhost/* ]]; then
 | 
						|
        args+=" --local"
 | 
						|
    fi
 | 
						|
 | 
						|
    BUILDTMP=$(mktemp -p "${PWD}" -d -t _build-bib.XXXXXXXXXX)
 | 
						|
 | 
						|
    sudo podman run \
 | 
						|
      --rm \
 | 
						|
      -it \
 | 
						|
      --privileged \
 | 
						|
      --pull=newer \
 | 
						|
      --net=host \
 | 
						|
      --security-opt label=type:unconfined_t \
 | 
						|
      -v $(pwd)/${config}:/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
 | 
						|
    sudo chown -R $USER:$USER output/
 | 
						|
 | 
						|
# Podman builds the image from the Containerfile and creates a bootable image
 | 
						|
# Parameters:
 | 
						|
#   target_image: The name of the image to build (ex. localhost/fedora)
 | 
						|
#   tag: The tag of the image to build (ex. latest)
 | 
						|
#   type: The type of image to build (ex. qcow2, raw, iso)
 | 
						|
#   config: The configuration file to use for the build (deafult: image.toml)
 | 
						|
 | 
						|
# Example: just _rebuild-bib localhost/fedora latest qcow2 image.toml
 | 
						|
_rebuild-bib $target_image $tag $type $config: (build target_image tag) && (_build-bib target_image tag type config)
 | 
						|
 | 
						|
# Build a QCOW2 virtual machine image
 | 
						|
[group('Build Virtal Machine Image')]
 | 
						|
build-qcow2 $target_image=("localhost/" + image_name) $tag=default_tag: && (_build-bib target_image tag "qcow2" "image.toml")
 | 
						|
 | 
						|
# Build a RAW virtual machine image
 | 
						|
[group('Build Virtal Machine Image')]
 | 
						|
build-raw $target_image=("localhost/" + image_name) $tag=default_tag: && (_build-bib target_image tag "raw" "image.toml")
 | 
						|
 | 
						|
# Build an ISO virtual machine image
 | 
						|
[group('Build Virtal Machine Image')]
 | 
						|
build-iso $target_image=("localhost/" + image_name) $tag=default_tag: && (_build-bib target_image tag "iso" "iso.toml")
 | 
						|
 | 
						|
# Rebuild a QCOW2 virtual machine image
 | 
						|
[group('Build Virtal Machine Image')]
 | 
						|
rebuild-qcow2 $target_image=("localhost/" + image_name) $tag=default_tag: && (_rebuild-bib target_image tag "qcow2" "image.toml")
 | 
						|
 | 
						|
# Rebuild a RAW virtual machine image
 | 
						|
[group('Build Virtal Machine Image')]
 | 
						|
rebuild-raw $target_image=("localhost/" + image_name) $tag=default_tag: && (_rebuild-bib target_image tag "raw" "image.toml")
 | 
						|
 | 
						|
# Rebuild an ISO virtual machine image
 | 
						|
[group('Build Virtal Machine Image')]
 | 
						|
rebuild-iso $target_image=("localhost/" + image_name) $tag=default_tag: && (_rebuild-bib target_image tag "iso" "iso.toml")
 | 
						|
 | 
						|
# Run a virtual machine with the specified image type and configuration
 | 
						|
_run-vm $target_image $tag $type $config:
 | 
						|
    #!/usr/bin/bash
 | 
						|
    set -eoux pipefail
 | 
						|
 | 
						|
    # Determine the image file based on the type
 | 
						|
    image_file="output/${type}/disk.${type}"
 | 
						|
    if [[ $type == iso ]]; then
 | 
						|
        image_file="output/bootiso/install.iso"
 | 
						|
    fi
 | 
						|
 | 
						|
    # Build the image if it does not exist
 | 
						|
    if [[ ! -f "${image_file}" ]]; then
 | 
						|
        just "build-${type}" "$target_image" "$tag"
 | 
						|
    fi
 | 
						|
 | 
						|
    # Determine an available 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}"
 | 
						|
 | 
						|
    # Set up the arguments for running the VM
 | 
						|
    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-docker)
 | 
						|
 | 
						|
    # Run the VM and open the browser to connect
 | 
						|
    (sleep 30 && xdg-open http://localhost:"$port") &
 | 
						|
    podman run "${run_args[@]}"
 | 
						|
 | 
						|
# Run a virtual machine from a QCOW2 image
 | 
						|
[group('Run Virtal Machine')]
 | 
						|
run-vm-qcow2 $target_image=("localhost/" + image_name) $tag=default_tag: && (_run-vm target_image tag "qcow2" "image.toml")
 | 
						|
 | 
						|
# Run a virtual machine from a RAW image
 | 
						|
[group('Run Virtal Machine')]
 | 
						|
run-vm-raw $target_image=("localhost/" + image_name) $tag=default_tag: && (_run-vm target_image tag "raw" "image.toml")
 | 
						|
 | 
						|
# Run a virtual machine from an ISO
 | 
						|
[group('Run Virtal Machine')]
 | 
						|
run-vm-iso $target_image=("localhost/" + image_name) $tag=default_tag: && (_run-vm target_image tag "iso" "iso.toml")
 | 
						|
 | 
						|
# Run a virtual machine using systemd-vmspawn
 | 
						|
[group('Run Virtal 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/find . -iname "*.sh" -type f -exec shellcheck "{}" ';'
 | 
						|
 | 
						|
# Runs shfmt on all Bash scripts
 | 
						|
format:
 | 
						|
    /usr/bin/find . -iname "*.sh" -type f -exec shfmt --write "{}" ';'
 |