Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
lima-vm
GitHub Repository: lima-vm/lima
Path: blob/master/hack/update-template.sh
1637 views
1
#!/usr/bin/env bash
2
3
# SPDX-FileCopyrightText: Copyright The Lima Authors
4
# SPDX-License-Identifier: Apache-2.0
5
6
set -eu -o pipefail
7
8
# Functions in this script assume error handling with 'set -e'.
9
# To ensure 'set -e' works correctly:
10
# - Use 'set +e' before assignments and '$(set -e; <function>)' to capture output without exiting on errors.
11
# - Avoid calling functions directly in conditions to prevent disabling 'set -e'.
12
# - Use 'shopt -s inherit_errexit' (Bash 4.4+) to avoid repeated 'set -e' in all '$(...)'.
13
shopt -s inherit_errexit || error_exit "inherit_errexit not supported. Please use bash 4.4 or later."
14
15
function print_help() {
16
cat <<HELP
17
$(basename "${BASH_SOURCE[0]}"): Update the image location in the specified templates
18
19
Usage:
20
$(basename "${BASH_SOURCE[0]}") <template.yaml>...
21
22
Description:
23
This script updates the image location in the specified templates.
24
If the image location in the template contains a release date in the URL, the script replaces it with the latest available date.
25
26
Examples:
27
Update the Ubuntu image location in templates/**.yaml:
28
$ $(basename "${BASH_SOURCE[0]}") templates/**.yaml
29
30
Update the Ubuntu image location in ~/.lima/ubuntu/lima.yaml:
31
$ $(basename "${BASH_SOURCE[0]}") ~/.lima/ubuntu/lima.yaml
32
$ limactl factory-reset ubuntu
33
34
Flags:
35
-h, --help Print this help message
36
HELP
37
}
38
39
# json prints the JSON object with the given arguments.
40
# json [key value ...]
41
# if the value is empty, both key and value are omitted.
42
# e.g.
43
# ```console
44
# json location https://cloud-images.ubuntu.com/minimal/releases/24.04/release-20210914/ubuntu-24.04-minimal-cloudimg-amd64.img arch amd64 digest sha256:...
45
# {"location":"https://cloud-images.ubuntu.com/minimal/releases/24.04/release-20210914/ubuntu-24.04-minimal-cloudimg-amd64.img","arch":"amd64","digest":"sha256:..."}
46
# ```
47
function json() {
48
local args=() pattern='^(\[.*\]|\{.*\}|true|false|[0-9]+)$' value
49
[[ ! -p /dev/stdin ]] && args+=(--null-input)
50
while [[ $# -gt 0 ]]; do
51
value="${2-}"
52
if [[ ${value} =~ ${pattern} ]]; then
53
args+=(--argjson "${1}" "${value}")
54
elif [[ -n ${value} ]]; then
55
args+=(--arg "${1}" "${value}")
56
fi # omit empty values
57
shift
58
shift # shift 2 does not work when $# is 1
59
done
60
jq -c "${args[@]}" '. + $ARGS.named | if . == {} then empty else . end'
61
}
62
63
# json_vars prints the JSON object with the given variable names.
64
# e.g.
65
# ```console
66
# location=https://cloud-images.ubuntu.com/minimal/releases/24.04/release-20210914/ubuntu-24.04-minimal-cloudimg-amd64.img
67
# arch=amd64
68
# digest=sha256:...
69
# json_vars location arch digest
70
# {"location":"https://cloud-images.ubuntu.com/minimal/releases/24.04/release-20210914/ubuntu-24.04-minimal-cloudimg-amd64.img","arch":"amd64","digest":"sha256:..."}
71
# ```
72
function json_vars() {
73
local args=() var
74
for var in "$@"; do
75
[[ -v ${var} ]] || error_exit "${var} is not set"
76
args+=("${var}" "${!var}")
77
done
78
json "${args[@]}"
79
}
80
81
# limayaml_arch prints the arch in the lima.yaml format
82
function limayaml_arch() {
83
local arch=$1
84
arch=${arch/amd64/x86_64}
85
arch=${arch/arm64/aarch64}
86
arch=${arch/armhf/armv7l}
87
arch=${arch/ppc64el/ppc64le}
88
echo "${arch}"
89
}
90
91
function validate_boolean() {
92
local value=$1
93
case "${value}" in
94
'') ;;
95
true | 1) echo true ;;
96
false | 0) echo false ;;
97
*) error_exit "Invalid boolean value: ${value}" ;;
98
esac
99
}
100
101
# validate_url checks if the URL is valid and prints the location if it is.
102
# If the URL is redirected, it prints the redirected location.
103
# e.g.
104
# ```console
105
# validate_url https://cloud-images.ubuntu.com/server/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img
106
# https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img
107
# ```
108
function validate_url() {
109
local url=$1
110
code_location=$(curl -sSL -o /dev/null -I -w "%{http_code}\t%{url_effective}" "${url}")
111
read -r code location <<<"${code_location}"
112
[[ ${code} -eq 200 ]] || error_exit "[${code}]: The image is not available for download from ${location}"
113
echo "${location}"
114
}
115
116
# validate_url_without_redirect checks if the URL is valid and prints the location if it is.
117
# If the URL is redirected, it prints the URL before the redirection.
118
# e.g.
119
# ```console
120
# validate_url_without_redirect https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-arm64.qcow2
121
# https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-arm64.qcow2
122
# ```
123
# cloud.debian.org may be redirected to other domains(e.g. chuangtzu.ftp.acc.umu.se), but we want to use the original URL.
124
function validate_url_without_redirect() {
125
local url=$1 location
126
location=$(validate_url "${url}")
127
[[ -n ${location} ]] || error_exit "The image is not available for download from ${url}"
128
echo "${url}"
129
}
130
131
# check if the script is executed or sourced
132
# shellcheck disable=SC1091
133
if [[ ${BASH_SOURCE[0]} == "${0}" ]]; then
134
scriptdir=$(dirname "${BASH_SOURCE[0]}")
135
# shellcheck source=./cache-common-inc.sh
136
. "${scriptdir}/cache-common-inc.sh"
137
138
# Scripts for each distribution are expected to:
139
# - Add their identifier to the SUPPORTED_DISTRIBUTIONS array.
140
# - Register the following functions:
141
# - ${distribution}_cache_key_for_image_kernel
142
# - Arguments: location, kernel_location
143
# - Returns: cache_key (string)
144
# - Exits with an error if the image location is not supported.
145
# - ${distribution}_image_entry_for_image_kernel
146
# - Arguments: location, kernel_location
147
# - Returns: image_entry (JSON object)
148
# - Exits with an error if the image location is not supported.
149
declare -a SUPPORTED_DISTRIBUTIONS=()
150
151
# shellcheck source=./update-template-ubuntu.sh
152
. "${scriptdir}/update-template-ubuntu.sh"
153
# shellcheck source=./update-template-debian.sh
154
. "${scriptdir}/update-template-debian.sh"
155
# shellcheck source=./update-template-archlinux.sh
156
. "${scriptdir}/update-template-archlinux.sh"
157
# shellcheck source=./update-template-centos-stream.sh
158
. "${scriptdir}/update-template-centos-stream.sh"
159
# shellcheck source=./update-template-almalinux.sh
160
. "${scriptdir}/update-template-almalinux.sh"
161
# shellcheck source=./update-template-almalinux-kitten.sh
162
. "${scriptdir}/update-template-almalinux-kitten.sh"
163
# shellcheck source=./update-template-rocky.sh
164
. "${scriptdir}/update-template-rocky.sh"
165
# shellcheck source=./update-template-alpine.sh
166
. "${scriptdir}/update-template-alpine.sh"
167
# shellcheck source=./update-template-oraclelinux.sh
168
. "${scriptdir}/update-template-oraclelinux.sh"
169
# shellcheck source=./update-template-fedora.sh
170
. "${scriptdir}/update-template-fedora.sh"
171
# shellcheck source=./update-template-opensuse.sh
172
. "${scriptdir}/update-template-opensuse.sh"
173
else
174
# this script is sourced
175
return 0
176
fi
177
178
declare -a templates=()
179
while [[ $# -gt 0 ]]; do
180
case "$1" in
181
-h | --help)
182
print_help
183
exit 0
184
;;
185
-d | --debug) set -x ;;
186
*.yaml) templates+=("$1") ;;
187
*)
188
error_exit "Unknown argument: $1"
189
;;
190
esac
191
shift
192
done
193
194
if [[ ${#templates[@]} -eq 0 ]]; then
195
print_help
196
exit 0
197
fi
198
199
declare -a distributions=()
200
# Check if the distribution has the required functions
201
for distribution in "${SUPPORTED_DISTRIBUTIONS[@]}"; do
202
if declare -f "${distribution}_cache_key_for_image_kernel" >/dev/null &&
203
declare -f "${distribution}_image_entry_for_image_kernel" >/dev/null; then
204
distributions+=("${distribution}")
205
fi
206
done
207
[[ ${#distributions[@]} -gt 0 ]] || error_exit "No supported distributions found"
208
209
declare -A image_entry_cache=()
210
211
for template in "${templates[@]}"; do
212
echo "Processing ${template}"
213
# 1. extract location by parsing template using arch
214
yq_filter="
215
.images[] | [.location, .kernel.location, .kernel.cmdline] | @tsv
216
"
217
parsed=$(yq eval "${yq_filter}" "${template}")
218
219
# 3. get the image location
220
arr=()
221
while IFS= read -r line; do arr+=("${line}"); done <<<"${parsed}"
222
locations=("${arr[@]}")
223
for ((index = 0; index < ${#locations[@]}; index++)); do
224
[[ ${locations[index]} != "null" ]] || continue
225
set -e
226
IFS=$'\t' read -r location kernel_location kernel_cmdline <<<"${locations[index]}"
227
for distribution in "${distributions[@]}"; do
228
set +e # Disable 'set -e' to avoid exiting on error for the next assignment.
229
cache_key=$(
230
set -e # Enable 'set -e' for the next command.
231
"${distribution}_cache_key_for_image_kernel" "${location}" "${kernel_location}"
232
) # Check exit status separately to prevent disabling 'set -e' by using the function call in the condition.
233
# shellcheck disable=2181
234
[[ $? -eq 0 ]] || continue
235
image_entry=$(
236
set -e # Enable 'set -e' for the next command.
237
if [[ -v image_entry_cache[${cache_key}] ]]; then
238
echo "${image_entry_cache[${cache_key}]}"
239
else
240
"${distribution}_image_entry_for_image_kernel" "${location}" "${kernel_location}"
241
fi
242
) # Check exit status separately to prevent disabling 'set -e' by using the function call in the condition.
243
# shellcheck disable=2181
244
[[ $? -eq 0 ]] || continue
245
set -e
246
image_entry_cache[${cache_key}]="${image_entry}"
247
if [[ -n ${image_entry} ]]; then
248
[[ ${kernel_cmdline} != "null" ]] &&
249
jq -e 'has("kernel")' <<<"${image_entry}" >/dev/null &&
250
image_entry=$(jq ".kernel.cmdline = \"${kernel_cmdline}\"" <<<"${image_entry}")
251
echo "${image_entry}" | jq
252
limactl edit --log-level error --set "
253
.images[${index}] = ${image_entry}|
254
(.images[${index}] | ..) style = \"double\"
255
" "${template}"
256
fi
257
done
258
done
259
done
260
261