Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
lima-vm
GitHub Repository: lima-vm/lima
Path: blob/master/hack/update-template-almalinux-kitten.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 almalinux_kitten_print_help() {
16
cat <<HELP
17
$(basename "${BASH_SOURCE[0]}"): Update the AlmaLinux Kitten image location in the specified templates
18
19
Usage:
20
$(basename "${BASH_SOURCE[0]}") [--version-major <major version>] <template.yaml>...
21
22
Description:
23
This script updates the AlmaLinux Kitten image location in the specified templates.
24
If the image location in the template contains a minor version and release date in the URL,
25
the script replaces it with the latest available minor version and date.
26
27
Image location basename format:
28
29
AlmaLinux-Kitten-GenericCloud-<major version>-[latest|<date>.<release>].<arch>.qcow2
30
31
Published AlmaLinux Kitten image information is fetched from the following URLs:
32
33
https://kitten.repo.almalinux.org/<major version>-kitten/cloud/<arch>/images/
34
35
To parsing html, this script requires 'htmlq' or 'pup' command.
36
The downloaded files will be cached in the Lima cache directory.
37
38
Examples:
39
Update the AlmaLinux Kitten image location in templates/**.yaml:
40
$ $(basename "${BASH_SOURCE[0]}") templates/**.yaml
41
42
Update the AlmaLinux Kitten image location in ~/.lima/almalinux-kitten/lima.yaml:
43
$ $(basename "${BASH_SOURCE[0]}") ~/.lima/almalinux-kitten/lima.yaml
44
$ limactl factory-reset almalinux-kitten
45
46
Update the AlmaLinux Kitten image location to major version 10 in ~/.lima/almalinux-kitten/lima.yaml:
47
$ $(basename "${BASH_SOURCE[0]}") --version-major 10 ~/.lima/almalinux-kitten/lima.yaml
48
$ limactl factory-reset almalinux-kitten
49
50
Flags:
51
--version-major <version> Use the specified version. The version must be 10 or later.
52
-h, --help Print this help message
53
HELP
54
}
55
56
# print the URL spec for the given location
57
function almalinux_kitten_url_spec_from_location() {
58
local location=$1 jq_filter url_spec
59
jq_filter='capture(
60
"^https://kitten\\.repo\\.almalinux\\.org/(?<path_version>\\d+)-kitten/cloud/(?<path_arch>[^/]+)/images/" +
61
"AlmaLinux-Kitten-(?<target_vendor>.*)-(?<major_version>\\d+)-" +
62
"(latest|(?<date>\\d{8}(\\\\d+)?))\\.(?<release>\\d+)\\.(?<arch>[^.]+).(?<file_extension>.*)$"
63
;"x")
64
'
65
url_spec=$(jq -e -r "${jq_filter}" <<<"\"${location}\"")
66
67
jq -e '.path_arch == .arch' <<<"${url_spec}" >/dev/null ||
68
error_exit "Validation failed: .path_arch != .arch: ${location}"
69
echo "${url_spec}"
70
}
71
72
readonly almalinux_kitten_jq_filter_directory='"https://kitten.repo.almalinux.org/\(.path_version)-kitten/cloud/\(.path_arch)/images/"'
73
readonly almalinux_kitten_jq_filter_filename='"AlmaLinux-Kitten-\(.target_vendor)-\(.major_version)-\(if .date then .date + ".0" else "latest" end).\(.arch).\(.file_extension)"'
74
75
# print the location for the given URL spec
76
function almalinux_kitten_location_from_url_spec() {
77
local -r url_spec=$1
78
jq -e -r "${almalinux_kitten_jq_filter_directory} + ${almalinux_kitten_jq_filter_filename}" <<<"${url_spec}" ||
79
error_exit "Failed to get the location for ${url_spec}"
80
}
81
82
function almalinux_kitten_image_directory_from_url_spec() {
83
local -r url_spec=$1
84
jq -e -r "${almalinux_kitten_jq_filter_directory}" <<<"${url_spec}" ||
85
error_exit "Failed to get the image directory for ${url_spec}"
86
}
87
88
function almalinux_kitten_image_filename_from_url_spec() {
89
local -r url_spec=$1
90
jq -e -r "${almalinux_kitten_jq_filter_filename}" <<<"${url_spec}" ||
91
error_exit "Failed to get the image filename for ${url_spec}"
92
}
93
94
#
95
function almalinux_kitten_latest_image_entry_for_url_spec() {
96
local url_spec=$1 arch major_version_url_spec major_version_image_directory downloaded_page links_in_page latest_minor_version_info
97
arch=$(jq -r '.arch' <<<"${url_spec}")
98
# to detect minor version updates, we need to get the major version URL
99
major_version_url_spec=$(jq -e -r '.path_version = .major_version' <<<"${url_spec}")
100
major_version_image_directory=$(almalinux_kitten_image_directory_from_url_spec "${major_version_url_spec}")
101
downloaded_page=$(download_to_cache "${major_version_image_directory}")
102
if command -v htmlq >/dev/null; then
103
links_in_page=$(htmlq 'pre a' --attribute href <"${downloaded_page}")
104
elif command -v pup >/dev/null; then
105
links_in_page=$(pup 'pre a attr{href}' <"${downloaded_page}")
106
else
107
error_exit "Please install 'htmlq' or 'pup' to list images from ${major_version_image_directory}"
108
fi
109
latest_minor_version_info=$(jq -e -Rrs --argjson spec "${url_spec}" '
110
[
111
split("\n").[] |
112
capture(
113
"^AlmaLinux-Kitten-\($spec.target_vendor)-" +
114
"(?<major_minor_version>\($spec.major_version))-" +
115
"(?<date>\\d{8})\\.(?<release>\\d)+\\.\($spec.arch)\\.\($spec.file_extension)$"
116
;"x"
117
) |
118
.version_number_array = ([.major_minor_version | scan("\\d+") | tonumber])
119
] | sort_by(.version_number_array, .date_and_ci_job_id) | last
120
' <<<"${links_in_page}")
121
[[ -n ${latest_minor_version_info} ]] || return
122
local newer_url_spec location directory checksum_location downloaded_sha256sum filename digest
123
# prefer the major_minor_version in the path
124
newer_url_spec=$(jq -e -r ". + ${latest_minor_version_info} | .path_version = .major_minor_version" <<<"${url_spec}")
125
location=$(almalinux_kitten_location_from_url_spec "${newer_url_spec}")
126
directory=$(almalinux_kitten_image_directory_from_url_spec "${newer_url_spec}")
127
checksum_location="${directory}CHECKSUM"
128
downloaded_sha256sum=$(download_to_cache "${checksum_location}")
129
filename=$(almalinux_kitten_image_filename_from_url_spec "${newer_url_spec}")
130
digest=$(awk "/${filename}/{print \"sha256:\"\$1}" "${downloaded_sha256sum}")
131
[[ -n ${digest} ]] || error_exit "Failed to get the SHA256 digest for ${filename}"
132
json_vars location arch digest
133
}
134
135
function almalinux_kitten_cache_key_for_image_kernel() {
136
local location=$1 url_spec
137
url_spec=$(almalinux_kitten_url_spec_from_location "${location}")
138
jq -r '["almalinux-kitten", .major_minor_version // .major_version, .target_vendor,
139
if .date then "timestamped" else "latest" end,
140
.arch, .file_extension] | join(":")' <<<"${url_spec}"
141
}
142
143
function almalinux_kitten_image_entry_for_image_kernel() {
144
local location=$1 kernel_is_not_supported=$2 overriding=${3:-"{}"} url_spec image_entry=''
145
[[ ${kernel_is_not_supported} == "null" ]] || echo "Updating kernel information is not supported on AlmaLinux Kitten" >&2
146
url_spec=$(almalinux_kitten_url_spec_from_location "${location}" | jq -r ". + ${overriding}")
147
if jq -e '.date' <<<"${url_spec}" >/dev/null; then
148
image_entry=$(almalinux_kitten_latest_image_entry_for_url_spec "${url_spec}")
149
else
150
image_entry=$(
151
# shellcheck disable=SC2030
152
location=$(almalinux_kitten_location_from_url_spec "${url_spec}")
153
location=$(validate_url_without_redirect "${location}")
154
arch=$(jq -r '.path_arch' <<<"${url_spec}")
155
json_vars location arch
156
)
157
fi
158
# shellcheck disable=SC2031
159
if [[ -z ${image_entry} ]]; then
160
error_exit "Failed to get the ${url_spec} image location for ${location}"
161
elif jq -e ".location == \"${location}\"" <<<"${image_entry}" >/dev/null; then
162
echo "Image location is up-to-date: ${location}" >&2
163
else
164
echo "${image_entry}"
165
fi
166
}
167
168
# check if the script is executed or sourced
169
# shellcheck disable=SC1091
170
if [[ ${BASH_SOURCE[0]} == "${0}" ]]; then
171
scriptdir=$(dirname "${BASH_SOURCE[0]}")
172
# shellcheck source=./cache-common-inc.sh
173
. "${scriptdir}/cache-common-inc.sh"
174
175
if ! command -v htmlq >/dev/null && ! command -v pup >/dev/null; then
176
error_exit "Please install 'htmlq' or 'pup' to list images from https://kitten.repo.almalinux.org/<version>-kitten/cloud/<arch>/images/"
177
fi
178
# shellcheck source=/dev/null # avoid shellcheck hangs on source looping
179
. "${scriptdir}/update-template.sh"
180
else
181
# this script is sourced
182
if ! command -v htmlq >/dev/null && ! command -v pup >/dev/null; then
183
echo "Please install 'htmlq' or 'pup' to list images from https://kitten.repo.almalinux.org/<version>-kitten/cloud/<arch>/images/" >&2
184
elif [[ -v SUPPORTED_DISTRIBUTIONS ]]; then
185
SUPPORTED_DISTRIBUTIONS+=("almalinux-kitten")
186
else
187
declare -a SUPPORTED_DISTRIBUTIONS=("almalinux-kitten")
188
fi
189
return 0
190
fi
191
192
declare -a templates=()
193
declare overriding="{}"
194
while [[ $# -gt 0 ]]; do
195
case "$1" in
196
-h | --help)
197
almalinux_kitten_print_help
198
exit 0
199
;;
200
-d | --debug) set -x ;;
201
--version-major)
202
if [[ -n $2 && $2 != -* ]]; then
203
overriding=$(
204
major_version="${2%%.*}"
205
[[ ${major_version} -ge 10 ]] || error_exit "AlmaLinux Kitten major version must be 8 or later"
206
# shellcheck disable=2034
207
path_version="${major_version}"
208
json_vars path_version major_version <<<"${overriding}"
209
)
210
shift
211
else
212
error_exit "--version-major requires a value"
213
fi
214
;;
215
--version-major=*)
216
overriding=$(
217
major_version="${1#*=}"
218
major_version="${major_version%%.*}"
219
[[ ${major_version} -ge 10 ]] || error_exit "AlmaLinux Kitten major version must be 8 or later"
220
# shellcheck disable=2034
221
path_version="${major_version}"
222
json_vars path_version major_version <<<"${overriding}"
223
)
224
;;
225
*.yaml) templates+=("$1") ;;
226
*)
227
error_exit "Unknown argument: $1"
228
;;
229
esac
230
shift
231
[[ -z ${overriding} ]] && overriding="{}"
232
done
233
234
if [[ ${#templates[@]} -eq 0 ]]; then
235
almalinux_kitten_print_help
236
exit 0
237
fi
238
239
declare -A image_entry_cache=()
240
241
for template in "${templates[@]}"; do
242
echo "Processing ${template}"
243
# 1. extract location by parsing template using arch
244
yq_filter="
245
.images[] | [.location, .kernel.location, .kernel.cmdline] | @tsv
246
"
247
parsed=$(yq eval "${yq_filter}" "${template}")
248
249
# 3. get the image location
250
arr=()
251
while IFS= read -r line; do arr+=("${line}"); done <<<"${parsed}"
252
locations=("${arr[@]}")
253
for ((index = 0; index < ${#locations[@]}; index++)); do
254
[[ ${locations[index]} != "null" ]] || continue
255
set -e
256
IFS=$'\t' read -r location kernel_location kernel_cmdline <<<"${locations[index]}"
257
set +e # Disable 'set -e' to avoid exiting on error for the next assignment.
258
cache_key=$(
259
set -e # Enable 'set -e' for the next command.
260
almalinux_kitten_cache_key_for_image_kernel "${location}" "${kernel_location}"
261
) # Check exit status separately to prevent disabling 'set -e' by using the function call in the condition.
262
# shellcheck disable=2181
263
[[ $? -eq 0 ]] || continue
264
image_entry=$(
265
set -e # Enable 'set -e' for the next command.
266
if [[ -v image_entry_cache[${cache_key}] ]]; then
267
echo "${image_entry_cache[${cache_key}]}"
268
else
269
almalinux_kitten_image_entry_for_image_kernel "${location}" "${kernel_location}" "${overriding}"
270
fi
271
) # Check exit status separately to prevent disabling 'set -e' by using the function call in the condition.
272
# shellcheck disable=2181
273
[[ $? -eq 0 ]] || continue
274
set -e
275
image_entry_cache[${cache_key}]="${image_entry}"
276
if [[ -n ${image_entry} ]]; then
277
[[ ${kernel_cmdline} != "null" ]] &&
278
jq -e 'has("kernel")' <<<"${image_entry}" >/dev/null &&
279
image_entry=$(jq ".kernel.cmdline = \"${kernel_cmdline}\"" <<<"${image_entry}")
280
echo "${image_entry}" | jq
281
limactl edit --log-level error --set "
282
.images[${index}] = ${image_entry}|
283
(.images[${index}] | ..) style = \"double\"
284
" "${template}"
285
fi
286
done
287
done
288
289