Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
190 changes: 190 additions & 0 deletions hack/update-template-amazonlinux.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
#!/usr/bin/env bash

# SPDX-FileCopyrightText: Copyright The Lima Authors
# SPDX-License-Identifier: Apache-2.0

set -eu -o pipefail

# Functions in this script assume error handling with 'set -e'.
# To ensure 'set -e' works correctly:
# - Use 'set +e' before assignments and '$(set -e; <function>)' to capture output without exiting on errors.
# - Avoid calling functions directly in conditions to prevent disabling 'set -e'.
# - Use 'shopt -s inherit_errexit' (Bash 4.4+) to avoid repeated 'set -e' in all '$(...)'.
shopt -s inherit_errexit || error_exit "inherit_errexit not supported. Please use bash 4.4 or later."

function amazonlinux_print_help() {
cat <<HELP
$(basename "${BASH_SOURCE[0]}"): Update the Amazon Linux 2023 image location in the specified templates

Usage:
$(basename "${BASH_SOURCE[0]}") <template.yaml>...

Description:
This script updates the Amazon Linux 2023 image location in the specified templates.
Image location format:
https://cdn.amazonlinux.com/al2023/os-images/<version>/<folder>/<filename>

Latest version information is fetched from:
https://cdn.amazonlinux.com/al2023/os-images/latest/

Examples:
Update the Amazon Linux 2023 image location in templates/**.yaml:
$ $(basename "${BASH_SOURCE[0]}") templates/**.yaml

Flags:
-h, --help Print this help message
HELP
}

function amazonlinux_cache_key_for_image_kernel() {
local location=$1
case "${location}" in
https://cdn.amazonlinux.com/al2023/os-images/*) ;;
*) return 1 ;;
esac
# Cache key based on architecture and variant derived from location
# We use a simple heuristic: file path components.
# The URL structure is .../os-images/<version>/<folder>/...
# We want a key that represents "amazonlinux:al2023:<folder>"
local folder
if [[ ${location} == *"/kvm-arm64/"* ]]; then
folder="kvm-arm64"
elif [[ ${location} == *"/kvm/"* ]]; then
folder="kvm"
else
return 1
fi
echo "amazonlinux:al2023:${folder}"
}

function amazonlinux_image_entry_for_image_kernel() {
local location=$1
case "${location}" in
https://cdn.amazonlinux.com/al2023/os-images/*) ;;
*) return 1 ;;
esac

local latest_url
# Get the redirect URL to find the latest version
latest_url=$(curl -Ls -o /dev/null -w '%{url_effective}' https://cdn.amazonlinux.com/al2023/os-images/latest/)
local version
version=$(basename "${latest_url}")

local arch folder
if [[ ${location} == *"x86_64"* ]]; then
# shellcheck disable=SC2034
arch="x86_64"
folder="kvm"
elif [[ ${location} == *"arm64"* ]] || [[ ${location} == *"aarch64"* ]]; then
# shellcheck disable=SC2034
arch="aarch64"
folder="kvm-arm64"
else
error_exit "Unknown arch for amazonlinux location: ${location}"
fi

local base_url="https://cdn.amazonlinux.com/al2023/os-images/${version}/${folder}"
local checksums
checksums=$(download_to_cache "${base_url}/SHA256SUMS")

local filename digest line
# Find the qcow2 file in SHA256SUMS
line=$(grep "\.qcow2$" "${checksums}" | head -n 1)
[[ -n ${line} ]] || error_exit "No qcow2 image found in ${base_url}/SHA256SUMS"

# shellcheck disable=SC2034
digest=$(echo "${line}" | awk '{print "sha256:"$1}')
filename=$(echo "${line}" | awk '{print $2}')

# shellcheck disable=SC2034
local location="${base_url}/${filename}"

json_vars location arch digest
}

# check if the script is executed or sourced
# shellcheck disable=SC1091
if [[ ${BASH_SOURCE[0]} == "${0}" ]]; then
scriptdir=$(dirname "${BASH_SOURCE[0]}")
# shellcheck source=./cache-common-inc.sh
. "${scriptdir}/cache-common-inc.sh"

# shellcheck source=/dev/null # avoid shellcheck hangs on source looping
. "${scriptdir}/update-template.sh"
else
# this script is sourced
if [[ -v SUPPORTED_DISTRIBUTIONS ]]; then
SUPPORTED_DISTRIBUTIONS+=("amazonlinux")
else
declare -a SUPPORTED_DISTRIBUTIONS=("amazonlinux")
fi
return 0
fi

declare -a templates=()
while [[ $# -gt 0 ]]; do
case "$1" in
-h | --help)
amazonlinux_print_help
exit 0
;;
-d | --debug) set -x ;;
*.yaml) templates+=("$1") ;;
*)
error_exit "Unknown argument: $1"
;;
esac
shift
done

if [[ ${#templates[@]} -eq 0 ]]; then
amazonlinux_print_help
exit 0
fi

declare -A image_entry_cache=()

for template in "${templates[@]}"; do
echo "Processing ${template}"
# 1. extract location by parsing template
yq_filter="
.images[] | [.location, .kernel.location, .kernel.cmdline] | @tsv
"
parsed=$(yq eval "${yq_filter}" "${template}")

# 2. get the image location
arr=()
while IFS= read -r line; do arr+=("${line}"); done <<<"${parsed}"
locations=("${arr[@]}")
for ((index = 0; index < ${#locations[@]}; index++)); do
[[ ${locations[index]} != "null" ]] || continue
set -e
IFS=$'\t' read -r location _kernel_location _kernel_cmdline <<<"${locations[index]}"
set +e # Disable 'set -e' to avoid exiting on error for the next assignment.
cache_key=$(
set -e # Enable 'set -e' for the next command.
amazonlinux_cache_key_for_image_kernel "${location}"
) # Check exit status separately to prevent disabling 'set -e' by using the function call in the condition.
# shellcheck disable=2181
[[ $? -eq 0 ]] || continue
image_entry=$(
set -e # Enable 'set -e' for the next command.
if [[ -v image_entry_cache[${cache_key}] ]]; then
echo "${image_entry_cache[${cache_key}]}"
else
amazonlinux_image_entry_for_image_kernel "${location}"
fi
) # Check exit status separately to prevent disabling 'set -e' by using the function call in the condition.
# shellcheck disable=2181
[[ $? -eq 0 ]] || continue
set -e
image_entry_cache[${cache_key}]="${image_entry}"
if [[ -n ${image_entry} ]]; then
echo "${image_entry}" | jq
limactl edit --log-level error --set "
.images[${index}] = ${image_entry}|
(.images[${index}] | ..) style = \"double\"
" "${template}"
fi
done
done
2 changes: 2 additions & 0 deletions hack/update-template.sh
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ if [[ ${BASH_SOURCE[0]} == "${0}" ]]; then
. "${scriptdir}/update-template-freebsd.sh"
# shellcheck source=./update-template-macos.sh
. "${scriptdir}/update-template-macos.sh"
# shellcheck source=./update-template-amazonlinux.sh
. "${scriptdir}/update-template-amazonlinux.sh"
else
# this script is sourced
return 0
Expand Down
38 changes: 38 additions & 0 deletions pkg/cidata/cidata.TEMPLATE.d/boot.Linux/04-amazonlinux-virtiofs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/bin/bash

# SPDX-FileCopyrightText: Copyright The Lima Authors
# SPDX-License-Identifier: Apache-2.0

set -eux -o pipefail

# Workaround for Amazon Linux 2023
if [ -f /etc/os-release ] && grep -q "Amazon Linux" /etc/os-release; then
# 1. Create missing mount.virtiofs helper
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to just fix this issue in the Amazon Linux upstream?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious why this issue happens specifically with Amazon Linux. I thought it was very similar to Fedora?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can cut a ticket to the team, but I think it should not be the concern of this PR. We can go with the current upstream approach, and when the fix is there, remove the patch here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should not be the concern of this PR

Why not.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this helper needed in the first place when we have to execute the mount command by ourselves?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The helper doesn't even seem to exist on other distros, such as almalinux-9

if [ ! -e /sbin/mount.virtiofs ]; then
cat >/sbin/mount.virtiofs <<'EOF'
#!/bin/sh
exec mount -i -t virtiofs "$@"
EOF
chmod +x /sbin/mount.virtiofs
fi

# Amazon Linux 2023 requires a workaround for virtiofs mounts.
# The mount.virtiofs helper script is missing, and cloud-init
# may fail to mount the filesystems. This creates the helper
# and manually mounts them.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it still produce the valid /etc/fstab? If so, just running mount -a might be fine here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I start a new AL2023 KVM to check and it seems that the fstab does not have the virtiofs configs. Therefore, mount -a does not work and we need to parse them from cloud init config's user-data. That was a nice catch by the way. I'm not super into OSes, thanks for the advice!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doesn't it generate fstab?

/var/log/cloud-init.log:

2026-04-16 07:52:01,442 - util.py[DEBUG]: Cloud-init v. 22.2.2 running 'init-local' at Thu, 16 Apr 2026 07:52:01 +0000. Up 1.95 seconds.
[...]
2026-04-16 07:52:04,763 - cc_mounts.py[DEBUG]: mounts configuration is [['lima-648190f135cc8172', '/Users/suda', 'virtiofs', 'ro,nofail', '0', '0']]
2026-04-16 07:52:04,763 - util.py[DEBUG]: Reading from /etc/fstab (quiet=False)
2026-04-16 07:52:04,763 - util.py[DEBUG]: Read 217 bytes from /etc/fstab
2026-04-16 07:52:04,764 - cc_mounts.py[DEBUG]: Attempting to determine the real name of lima-648190f135cc8172
2026-04-16 07:52:04,764 - cc_mounts.py[DEBUG]: changed lima-648190f135cc8172 => None
2026-04-16 07:52:04,764 - cc_mounts.py[DEBUG]: Ignoring nonexistent named mount lima-648190f135cc8172
2026-04-16 07:52:04,764 - cc_mounts.py[DEBUG]: Attempting to determine the real name of ephemeral0
2026-04-16 07:52:04,764 - cc_mounts.py[DEBUG]: changed default device ephemeral0 => None
2026-04-16 07:52:04,764 - cc_mounts.py[DEBUG]: Ignoring nonexistent default named mount ephemeral0
2026-04-16 07:52:04,764 - cc_mounts.py[DEBUG]: Attempting to determine the real name of swap
2026-04-16 07:52:04,764 - cc_mounts.py[DEBUG]: changed default device swap => None
2026-04-16 07:52:04,764 - cc_mounts.py[DEBUG]: Ignoring nonexistent default named mount swap
2026-04-16 07:52:04,764 - cc_mounts.py[DEBUG]: Skipping nonexistent device named None
2026-04-16 07:52:04,764 - cc_mounts.py[DEBUG]: no need to setup swap
2026-04-16 07:52:04,764 - cc_mounts.py[DEBUG]: No modifications to fstab needed
2026-04-16 07:52:04,764 - handlers.py[DEBUG]: finish: init-network/config-mounts: SUCCESS: config-mounts ran successfully

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe related to "AL2023 contains a customized version of cloud-init."

https://docs.aws.amazon.com/linux/al2023/ug/cloud-init.html

USER_DATA="/var/lib/cloud/instance/user-data.txt"
if [ -f "${USER_DATA}" ]; then
# Parse all mount entries from user-data (mount0, mount1, ...)
MOUNT_ENTRIES=$(grep -E '^\s*-\s+\[mount[0-9]+,' "${USER_DATA}" || true)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This grep didn't work for me

[root@lima-amazonlinux ~]# head  /var/lib/cloud/instance/user-data.txt
#cloud-config
# vim:syntax=yaml

growpart:
  mode: auto
  devices: ['/']
mounts:
- [lima-648190f135cc8172, /Users/suda, virtiofs, "ro,nofail", "0", "0"]
timezone: Asia/Tokyo

[root@lima-amazonlinux ~]# grep -E '^\s*-\s+\[mount[0-9]+,' /var/lib/cloud/instance/user-data.txt

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@electricalgorithm

How did you test your PR?
In what condition user-data can have mounts named mount0, mount1, etc.?

if [ -n "${MOUNT_ENTRIES}" ]; then
echo "${MOUNT_ENTRIES}" | while IFS= read -r entry; do
MOUNT_TAG=$(echo "${entry}" | grep -oP 'mount\K[0-9]+')
MOUNT_POINT=$(echo "${entry}" | awk -F, '{print $2}' | tr -d '[:space:]')
if [ -n "${MOUNT_TAG}" ] && [ -n "${MOUNT_POINT}" ] && ! mountpoint -q "${MOUNT_POINT}"; then
mkdir -p "${MOUNT_POINT}"
mount -t virtiofs "mount${MOUNT_TAG}" "${MOUNT_POINT}" || true
fi
done
fi
fi
fi
1 change: 1 addition & 0 deletions templates/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ lima
- [`almalinux-kitten-10`](./almalinux-kitten-10.yaml), `almalinux-kitten`: AlmaLinux Kitten 10
- [`alpine`](./alpine.yaml): ☆Alpine Linux
- [`alpine-iso`](./alpine-iso.yaml): ☆Alpine Linux (ISO9660 image). Compatible with the `alpine` template used in Lima prior to v1.0.
- [`amazonlinux-2023`](./amazonlinux-2023.yaml): Amazon Linux 2023
- [`archlinux`](./archlinux.yaml): ☆Arch Linux
- [`centos-stream-9`](./centos-stream-9.yaml), `centos-stream`: CentOS Stream 9
- [`centos-stream-10`](./centos-stream-10.yaml): CentOS Stream 10
Expand Down
9 changes: 9 additions & 0 deletions templates/_images/amazonlinux-2023.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# More information: https://docs.aws.amazon.com/linux/al2023/ug/outside-ec2-download.html

images:
- location: "https://cdn.amazonlinux.com/al2023/os-images/2023.11.20260406.2/kvm/al2023-kvm-2023.11.20260406.2-kernel-6.1-x86_64.xfs.gpt.qcow2"
arch: "x86_64"
digest: "sha256:72e10d974e832d9b56b84e71fe6f2e22589c9c539cc38e6d00cd84177839e2e8"
- location: "https://cdn.amazonlinux.com/al2023/os-images/2023.11.20260406.2/kvm-arm64/al2023-kvm-2023.11.20260406.2-kernel-6.1-arm64.xfs.gpt.qcow2"
arch: "aarch64"
digest: "sha256:c012f9ecb88f377c49e4338c2c6f5702ca885a37e96118119ce67266d0a7524d"
5 changes: 5 additions & 0 deletions templates/amazonlinux-2023.yaml
Comment thread
electricalgorithm marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
minimumLimaVersion: 2.1.2

base:
- template:_images/amazonlinux-2023
- template:_default/mounts
1 change: 1 addition & 0 deletions templates/amazonlinux.yaml
Loading