diff --git a/.github/workflows/build-all-matrix.yaml b/.github/workflows/build-all-matrix.yaml index 652e46d9..131d97e0 100644 --- a/.github/workflows/build-all-matrix.yaml +++ b/.github/workflows/build-all-matrix.yaml @@ -51,6 +51,10 @@ jobs: id: date_prep run: echo "created=$(date -u +'%Y%m%d-%H%M')" >> "${GITHUB_OUTPUT}" + - name: Run shellcheck # so fail fast in case of bash errors/warnings + id: shellcheck + run: bash build.sh shellcheck + - name: Run the matrix JSON preparation bash script id: prepare-matrix run: bash build.sh gha-matrix # This sets the output "kernels_json" & "lkcontainers_json" & "lk_hooks_json" internally @@ -166,7 +170,7 @@ jobs: run: bash build.sh build "${{ matrix.kernel }}" - name: "Build Hook ISO with Kernel ${{matrix.kernel}} (${{ matrix.arch }}) - cache: ${{matrix.gha_cache}}" - if: ${{ matrix.kernel == 'hook-latest-lts-amd64' || matrix.kernel == 'hook-default-amd64' || matrix.kernel == 'hook-latest-lts-arm64' || matrix.kernel == 'hook-default-arm64' }} + if: ${{ matrix.build_iso == 'yes' }} # Set via inventory.sh and SUPPORTS_ISO='yes' for each flavor env: DO_BUILD_LK_CONTAINERS: "no" # already built them; this is only for hook/linuxkit. run: bash build.sh build "${{ matrix.kernel }}" LINUXKIT_ISO=yes diff --git a/bash/hook-lk-containers.sh b/bash/hook-lk-containers.sh index 33280727..c5d812d4 100644 --- a/bash/hook-lk-containers.sh +++ b/bash/hook-lk-containers.sh @@ -7,17 +7,17 @@ function build_all_hook_linuxkit_containers() { # when adding new container builds here you'll also want to add them to the # `linuxkit_build` function in the linuxkit.sh file. # # NOTE: linuxkit containers must be in the images/ directory - build_hook_linuxkit_container hook-bootkit HOOK_CONTAINER_BOOTKIT_IMAGE - build_hook_linuxkit_container hook-docker HOOK_CONTAINER_DOCKER_IMAGE - build_hook_linuxkit_container hook-mdev HOOK_CONTAINER_MDEV_IMAGE - build_hook_linuxkit_container hook-containerd HOOK_CONTAINER_CONTAINERD_IMAGE - build_hook_linuxkit_container hook-runc HOOK_CONTAINER_RUNC_IMAGE - build_hook_linuxkit_container hook-embedded HOOK_CONTAINER_EMBEDDED_IMAGE + build_hook_linuxkit_container hook-bootkit "HOOK_CONTAINER_BOOTKIT_IMAGE" + build_hook_linuxkit_container hook-docker "HOOK_CONTAINER_DOCKER_IMAGE" + build_hook_linuxkit_container hook-mdev "HOOK_CONTAINER_MDEV_IMAGE" + build_hook_linuxkit_container hook-containerd "HOOK_CONTAINER_CONTAINERD_IMAGE" + build_hook_linuxkit_container hook-runc "HOOK_CONTAINER_RUNC_IMAGE" + build_hook_linuxkit_container hook-embedded "HOOK_CONTAINER_EMBEDDED_IMAGE" } function build_hook_linuxkit_container() { declare container_dir="${1}" - declare -n output_var="${2}" # bash name reference, kind of an output var but weird + declare template_var="${2}" # bash name reference, kind of an output var but weird declare container_base_dir="images" # Lets hash the contents of the directory and use that as a tag @@ -28,8 +28,7 @@ function build_hook_linuxkit_container() { declare container_oci_ref="${HOOK_LK_CONTAINERS_OCI_BASE}${container_dir}:${container_files_hash_short}-${DOCKER_ARCH}" log info "Consider building LK container ${container_oci_ref} from ${container_base_dir}/${container_dir} for platform ${DOCKER_ARCH}" - output_var="${container_oci_ref}" # the the name reference - echo "${output_var}" > /dev/null # no-op; just to avoid shellcheck SC2034 (unused var; but it is actually a bash nameref) + hook_template_vars["${template_var}"]="${container_oci_ref}" # set the template var for envsubst # If the image is in the local docker cache, skip building log debug "Checking if image ${container_oci_ref} exists in local registry" diff --git a/bash/inventory.sh b/bash/inventory.sh index b5039ac4..adfd26ac 100644 --- a/bash/inventory.sh +++ b/bash/inventory.sh @@ -5,9 +5,9 @@ function produce_kernels_flavours_inventory() { ##### METHOD=default; Hook's own kernel, in kernel/ directory ## Hook default kernel, source code stored in `kernel` dir in this repo -- currently 5.10.y - define_id "hook-default-amd64" METHOD='default' ARCH='x86_64' TAG='standard' \ + define_id "hook-default-amd64" METHOD='default' ARCH='x86_64' TAG='standard' SUPPORTS_ISO='yes' \ KERNEL_MAJOR='5' KERNEL_MINOR='10' KCONFIG='generic' - define_id "hook-default-arm64" METHOD='default' ARCH='aarch64' TAG='standard' \ + define_id "hook-default-arm64" METHOD='default' ARCH='aarch64' TAG='standard' SUPPORTS_ISO='yes' \ KERNEL_MAJOR='5' KERNEL_MINOR='10' KCONFIG='generic' ## A 'peg' is not really a 'hook': for development purposes; testing new LK version and simpler LK configurations, using the default kernel @@ -16,9 +16,9 @@ function produce_kernels_flavours_inventory() { KERNEL_MAJOR='5' KERNEL_MINOR='10' KCONFIG='generic' ## development purposes: trying out kernel 6.6.y - define_id "hook-latest-lts-amd64" METHOD='default' ARCH='x86_64' TAG='lts' \ + define_id "hook-latest-lts-amd64" METHOD='default' ARCH='x86_64' TAG='lts' SUPPORTS_ISO='yes' \ KERNEL_MAJOR='6' KERNEL_MINOR='6' KCONFIG='generic' FORCE_OUTPUT_ID='latest-lts' - define_id "hook-latest-lts-arm64" METHOD='default' ARCH='aarch64' TAG='lts' \ + define_id "hook-latest-lts-arm64" METHOD='default' ARCH='aarch64' TAG='lts' SUPPORTS_ISO='yes' \ KERNEL_MAJOR='6' KERNEL_MINOR='6' KCONFIG='generic' FORCE_OUTPUT_ID='latest-lts' ##### METHOD=armbian; Foreign kernels, taken from Armbian's OCI repos. Those are "exotic" kernels for certain SoC's. @@ -36,18 +36,15 @@ function produce_kernels_flavours_inventory() { ## Armbian bcm2711 (Broadcom) current, from RaspberryPi Foundation with many CNCF-landscape fixes and patches; for the RaspberryPi 3b+/4b/5 define_id "armbian-bcm2711-current" METHOD='armbian' ARCH='aarch64' TAG='armbian-sbc' ARMBIAN_KERNEL_ARTIFACT='kernel-bcm2711-current' - ## Armbian rockchip64 (Rockchip) edge, for many rk356x/3399 SoCs. Not for rk3588! + ## Armbian rockchip64 (Rockchip) edge, for many rk356x/3399 SoCs. As of late December 2024, also for rk3588. define_id "armbian-rockchip64-edge" METHOD='armbian' ARCH='aarch64' TAG='armbian-sbc' ARMBIAN_KERNEL_ARTIFACT='kernel-rockchip64-edge' - ## Armbian rk35xx (Rockchip) mainline bleeding edge for rk3588, rk3588s SoCs - define_id "armbian-rk3588-edge" METHOD='armbian' ARCH='aarch64' TAG='armbian-sbc' ARMBIAN_KERNEL_ARTIFACT='kernel-rockchip-rk3588-edge' - - ## Armbian rk35xx (Rockchip) vendor, for rk3566, rk3568, rk3588, rk3588s SoCs -- 6.1-rkr1 - BSP / vendor kernel + ## Armbian rk35xx (Rockchip) vendor, for rk3566, rk3568, rk3588, rk3588s SoCs -- 6.1-rkr4.1 - BSP / vendor kernel, roughly equivalent to Android's 6.1.84 # Use with edk2 (v0.9.1+) or mainline u-boot + EFI: matches the DT included in https://github.com/edk2-porting/edk2-rk3588 _after_ v0.9.1 define_id "armbian-rk35xx-vendor" METHOD='armbian' ARCH='aarch64' TAG='armbian-sbc' ARMBIAN_KERNEL_ARTIFACT='kernel-rk35xx-vendor' ### Armbian mainline Generic UEFI kernels, for EFI capable machines might use those: - ## Armbian generic edge UEFI kernel (Armbian calls it x86) + ## Armbian generic edge UEFI kernel for arm64 define_id "armbian-uefi-arm64-edge" METHOD='armbian' ARCH='aarch64' TAG='standard armbian-uefi' ARMBIAN_KERNEL_ARTIFACT='kernel-arm64-edge' ## Armbian generic edge UEFI kernel (Armbian calls it x86) diff --git a/bash/json-matrix.sh b/bash/json-matrix.sh index e300c50e..11a1b281 100644 --- a/bash/json-matrix.sh +++ b/bash/json-matrix.sh @@ -84,7 +84,7 @@ function prepare_json_matrix() { declare gha_cache="yes" # always use GH cache; hitting DockerHub for linuxkit images is prone to rate limiting all_arches["${kernel_info[DOCKER_ARCH]}"]=1 - json_items+=("{\"kernel\":\"${kernel}\",\"arch\":\"${kernel_info[ARCH]}\",\"docker_arch\":\"${kernel_info[DOCKER_ARCH]}\",\"runner\":${runner},\"gha_cache\":\"${gha_cache}\"}") + json_items+=("{\"kernel\":\"${kernel}\",\"arch\":\"${kernel_info[ARCH]}\",\"docker_arch\":\"${kernel_info[DOCKER_ARCH]}\",\"build_iso\":\"${kernel_info[SUPPORTS_ISO]}\",\"runner\":${runner},\"gha_cache\":\"${gha_cache}\"}") fi done diff --git a/bash/kernel.sh b/bash/kernel.sh index 1a8169b0..0baf30a0 100644 --- a/bash/kernel.sh +++ b/bash/kernel.sh @@ -60,8 +60,8 @@ function resolve_latest_kernel_version_lts() { # Produces KERNEL_POINT_RELEASE # HookOS using an existing kernel container image from the registry. This only works with # unauthenticated registries. if [[ -n "${USE_LATEST_BUILT_KERNEL}" ]]; then - reg="$(echo ${HOOK_KERNEL_OCI_BASE} | cut -d'/' -f1)" - repo="$(echo ${HOOK_KERNEL_OCI_BASE} | cut -d'/' -f2-)" + reg="$(echo "${HOOK_KERNEL_OCI_BASE}" | cut -d'/' -f1)" + repo="$(echo "${HOOK_KERNEL_OCI_BASE}" | cut -d'/' -f2-)" # expected format is: 6.6.32-14b8be17 (major.minor.point-hash) latest_point_release="$(curl -sL "https://${reg}/v2/${repo}/tags/list" | jq -r ".tags[]" | grep -e "^${KERNEL_MAJOR}.${KERNEL_MINOR}" | sort -V | tail -n1 | cut -d"-" -f1 | cut -d"." -f3)" log info "Using latest point release from registry ${HOOK_KERNEL_OCI_BASE} for kernel ${KERNEL_MAJOR}.${KERNEL_MINOR}: ${latest_point_release}" @@ -121,7 +121,7 @@ function get_kernel_info_dict() { # convert ARCH (x86_64, aarch64) to docker-ARCH (amd64, arm64) case "${kernel_info['ARCH']}" in "x86_64") kernel_info['DOCKER_ARCH']="amd64" ;; - "aarch64") kernel_info['DOCKER_ARCH']="arm64" ;; + "aarch64" | "arm64") kernel_info['DOCKER_ARCH']="arm64" ;; *) log error "ARCH ${kernel_info['ARCH']} not supported" && exit 1 ;; esac } @@ -139,7 +139,7 @@ function get_host_docker_arch() { # convert ARCH (x86_64, aarch64) to docker-ARCH (amd64, arm64) case "$(uname -m)" in "x86_64") host_docker_arch="amd64" ;; - "aarch64") host_docker_arch="arm64" ;; + "aarch64" | "arm64") host_docker_arch="arm64" ;; *) log error "ARCH $(uname -m) not supported" && exit 1 ;; esac return 0 diff --git a/bash/kernel/kernel_armbian.sh b/bash/kernel/kernel_armbian.sh index 5fc55209..495b1b8e 100644 --- a/bash/kernel/kernel_armbian.sh +++ b/bash/kernel/kernel_armbian.sh @@ -50,7 +50,7 @@ function calculate_kernel_version_armbian() { declare oras_arch="unknown" case "$(uname -m)" in "x86_64") oras_arch="amd64" ;; - "aarch64") oras_arch="arm64" ;; + "aarch64" | "arm64") oras_arch="arm64" ;; *) log error "ERROR: ARCH $(uname -m) not supported by ORAS? check https://github.com/oras-project/oras/releases" && exit 1 ;; esac declare oras_down_url="https://github.com/oras-project/oras/releases/download/v${oras_version}/oras_${oras_version}_linux_${oras_arch}.tar.gz" diff --git a/bash/kernel/kernel_default.sh b/bash/kernel/kernel_default.sh index 9b53d0d1..8c8d7bb2 100644 --- a/bash/kernel/kernel_default.sh +++ b/bash/kernel/kernel_default.sh @@ -36,7 +36,7 @@ function calculate_kernel_version_default() { KERNEL_CROSS_COMPILE="x86_64-linux-gnu-" KERNEL_OUTPUT_IMAGE="arch/x86_64/boot/bzImage" ;; - "aarch64") + "aarch64" | "arm64") KERNEL_ARCH="arm64" KERNEL_CROSS_COMPILE_PKGS="crossbuild-essential-arm64" KERNEL_CROSS_COMPILE="aarch64-linux-gnu-" @@ -55,13 +55,6 @@ function calculate_kernel_version_default() { input_hash="$(cat "kernel/configs/${INPUT_DEFCONFIG}" "kernel/Dockerfile" | sha256sum - | cut -d ' ' -f 1)" short_input_hash="${input_hash:0:8}" kernel_oci_version="${KERNEL_MAJOR}.${KERNEL_MINOR}.${KERNEL_POINT_RELEASE}-${short_input_hash}" - - kernel_id_to_use="${inventory_id}" - if [[ -n "${USE_KERNEL_ID}" ]]; then - log warn "USE_KERNEL_ID is set to '${USE_KERNEL_ID}'; using it instead of the default inventory_id '${inventory_id}'." - kernel_id_to_use="${USE_KERNEL_ID}" - fi - kernel_oci_image="${HOOK_KERNEL_OCI_BASE}:${kernel_oci_version}" # Log the obtained version & images to stderr diff --git a/bash/linuxkit.sh b/bash/linuxkit.sh index 4e8fa19a..aa3836d9 100644 --- a/bash/linuxkit.sh +++ b/bash/linuxkit.sh @@ -3,16 +3,19 @@ function obtain_linuxkit_binary_cached() { # Grab linuxkit from official GitHub releases; account for arm64/amd64 differences + declare linuxkit_os="linux" + [[ "$(uname -s)" == "Darwin" ]] && linuxkit_os="darwin" + declare linuxkit_arch="" # determine the arch to download from current arch case "$(uname -m)" in "x86_64") linuxkit_arch="amd64" ;; - "aarch64") linuxkit_arch="arm64" ;; + "aarch64" | "arm64") linuxkit_arch="arm64" ;; *) log error "ERROR: ARCH $(uname -m) not supported by linuxkit? check https://github.com/linuxkit/linuxkit/releases" && exit 1 ;; esac - declare linuxkit_down_url="https://github.com/linuxkit/linuxkit/releases/download/v${LINUXKIT_VERSION}/linuxkit-linux-${linuxkit_arch}" - declare -g linuxkit_bin="${CACHE_DIR}/linuxkit-linux-${linuxkit_arch}-${LINUXKIT_VERSION}" + declare linuxkit_down_url="https://github.com/linuxkit/linuxkit/releases/download/v${LINUXKIT_VERSION}/linuxkit-${linuxkit_os}-${linuxkit_arch}" + declare -g linuxkit_bin="${CACHE_DIR}/linuxkit-${linuxkit_os}-${linuxkit_arch}-${LINUXKIT_VERSION}" # Download using curl if not already present if [[ ! -f "${linuxkit_bin}" ]]; then @@ -22,7 +25,7 @@ function obtain_linuxkit_binary_cached() { fi # Show the binary's version - log info "LinuxKit binary version: ('0.8+' reported for 1.2.0, bug?): $("${linuxkit_bin}" version | xargs echo -n)" + log info "LinuxKit binary version: $("${linuxkit_bin}" version | xargs echo -n)" } @@ -49,29 +52,37 @@ function linuxkit_build() { fi fi + # A dictionary (bash associative array) with variables and their values, for templating using envsubst. + declare -A -g hook_template_vars=( + ["HOOK_VERSION"]="${HOOK_VERSION}" + ["HOOK_KERNEL_IMAGE"]="${kernel_oci_image}" + ["HOOK_KERNEL_ID"]="${inventory_id}" + ["HOOK_KERNEL_VERSION"]="${kernel_oci_version}" + ) + # Build the containers in this repo used in the LinuxKit YAML; - build_all_hook_linuxkit_containers # sets HOOK_CONTAINER_BOOTKIT_IMAGE, HOOK_CONTAINER_DOCKER_IMAGE, HOOK_CONTAINER_MDEV_IMAGE, HOOK_CONTAINER_CONTAINERD_IMAGE + build_all_hook_linuxkit_containers # sets HOOK_CONTAINER_BOOTKIT_IMAGE, HOOK_CONTAINER_DOCKER_IMAGE and others in the hook_template_vars dict # Template the linuxkit configuration file. # - You'd think linuxkit would take --build-args or something by now, but no. # - Linuxkit does have @pkg but that's only useful in its own repo (with pkgs/ dir) # - envsubst doesn't offer a good way to escape $ in the input, so we pass the exact list of vars to consider, so escaping is not needed - log info "Using Linuxkit template '${kernel_info['TEMPLATE']}'..." - # HOOK_VERSION is read-only & already exported so is not listed in the env vars here, but is included in the dollar-sign list for envsubst to process - # shellcheck disable=SC2002 # Again, no, I love my cat, leave me alone - # shellcheck disable=SC2016 # I'm using single quotes to avoid shell expansion, envsubst wants the dollar signs. - cat "linuxkit-templates/${kernel_info['TEMPLATE']}.template.yaml" | - HOOK_KERNEL_IMAGE="${kernel_oci_image}" HOOK_KERNEL_ID="${inventory_id}" HOOK_KERNEL_VERSION="${kernel_oci_version}" \ - HOOK_CONTAINER_BOOTKIT_IMAGE="${HOOK_CONTAINER_BOOTKIT_IMAGE}" \ - HOOK_CONTAINER_DOCKER_IMAGE="${HOOK_CONTAINER_DOCKER_IMAGE}" \ - HOOK_CONTAINER_MDEV_IMAGE="${HOOK_CONTAINER_MDEV_IMAGE}" \ - HOOK_CONTAINER_CONTAINERD_IMAGE="${HOOK_CONTAINER_CONTAINERD_IMAGE}" \ - HOOK_CONTAINER_RUNC_IMAGE="${HOOK_CONTAINER_RUNC_IMAGE}" \ - HOOK_CONTAINER_EMBEDDED_IMAGE="${HOOK_CONTAINER_EMBEDDED_IMAGE}" \ - envsubst '$HOOK_VERSION $HOOK_KERNEL_IMAGE $HOOK_KERNEL_ID $HOOK_KERNEL_VERSION $HOOK_CONTAINER_BOOTKIT_IMAGE $HOOK_CONTAINER_DOCKER_IMAGE $HOOK_CONTAINER_MDEV_IMAGE $HOOK_CONTAINER_CONTAINERD_IMAGE $HOOK_CONTAINER_RUNC_IMAGE $HOOK_CONTAINER_EMBEDDED_IMAGE' \ - > "hook.${inventory_id}.yaml" + # Calculate, from hook_template_vars dictionary: + # envsubst_arg_string: a space separated list of dollar-prefixed variables name to be substituted + # envusbst_env: the environment variables to be passed to envsubst (array of KEY=var) to be used via 'env' + declare envsubst_arg_string="" + declare -a envsubst_envs=() + for key in "${!hook_template_vars[@]}"; do + envsubst_arg_string+="\$${key} " # extra space at the end doesn't hurt + envsubst_envs+=("${key}=${hook_template_vars["${key}"]}") + done + log debug "envsubst_arg_string: ${envsubst_arg_string}" + log debug "envsubst_envs: ${envsubst_envs[*]}" + + # Run envsubst on the template file, output to a new file; pass the envs and the arg string + env "${envsubst_envs[@]}" envsubst "${envsubst_arg_string}" < "linuxkit-templates/${kernel_info['TEMPLATE']}.template.yaml" > "hook.${inventory_id}.yaml" declare -g linuxkit_bin="" obtain_linuxkit_binary_cached # sets "${linuxkit_bin}" @@ -101,7 +112,7 @@ function linuxkit_build() { "${linuxkit_bin}" build "${lk_iso_args[@]}" return 0 fi - + declare -a lk_args=( "--docker" "--arch" "${kernel_info['DOCKER_ARCH']}" diff --git a/build.sh b/build.sh index 4df377dc..d771956d 100755 --- a/build.sh +++ b/build.sh @@ -29,7 +29,7 @@ declare -g HOOK_LK_CONTAINERS_OCI_BASE="${HOOK_LK_CONTAINERS_OCI_BASE:-"quay.io/ declare -g SKOPEO_IMAGE="${SKOPEO_IMAGE:-"quay.io/skopeo/stable:latest"}" # See https://github.com/linuxkit/linuxkit/releases -declare -g -r LINUXKIT_VERSION_DEFAULT="1.5.0" # LinuxKit version to use by default; each flavor can set its own too +declare -g -r LINUXKIT_VERSION_DEFAULT="1.5.2" # LinuxKit version to use by default; each flavor can set its own too # Directory to use for storing downloaded artifacts: LinuxKit binary, shellcheck binary, etc. declare -g -r CACHE_DIR="${CACHE_DIR:-"cache"}"