Initial commit
This commit is contained in:
commit
04c0109baa
6 files changed
+295
No files matched your search
+13
@@ -0,0 +1,13 @@
|
|||||||
|
# Downloaded VM images are local assets and must never be committed.
|
||||||
|
*.iso
|
||||||
|
*.qcow2
|
||||||
|
*.img
|
||||||
|
*.vhd
|
||||||
|
*.vhdx
|
||||||
|
*.part
|
||||||
|
*.part.url
|
||||||
|
|
||||||
|
# Keep the intended directory layout in Git.
|
||||||
|
!base-qcow2/.gitkeep
|
||||||
|
!install-iso/.gitkeep
|
||||||
|
!tools-iso/.gitkeep
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# vm-images
|
||||||
|
|
||||||
|
Shared, locally cached virtual-machine installation media and base images.
|
||||||
|
Downloaded ISO, QCOW2, IMG, VHD, and VHDX files are intentionally excluded
|
||||||
|
from Git.
|
||||||
|
|
||||||
|
## Download images
|
||||||
|
|
||||||
|
Download every supported image:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./download-images.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Download or check selected targets:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./download-images.sh debian13
|
||||||
|
./download-images.sh almalinux10
|
||||||
|
./download-images.sh virtio-win
|
||||||
|
```
|
||||||
|
|
||||||
|
The Windows installation ISO is not downloaded because Microsoft's temporary
|
||||||
|
download URLs expire. Supply it manually at the path reported by
|
||||||
|
`./download-images.sh --print-path windows11 --iso`.
|
||||||
|
|
||||||
|
## Query image paths
|
||||||
|
|
||||||
|
The path interface prints one absolute path without downloading anything:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./download-images.sh --print-path debian13
|
||||||
|
./download-images.sh --print-path almalinux10
|
||||||
|
./download-images.sh --print-path virtio-win
|
||||||
|
./download-images.sh --print-path windows11
|
||||||
|
./download-images.sh --print-path windows11 --iso
|
||||||
|
```
|
||||||
|
|
||||||
|
The Windows target prints the QCOW2 path by default. Add `--iso` to print its
|
||||||
|
manually supplied installation ISO path.
|
||||||
|
|
||||||
|
Download URLs can be overridden with `DEBIAN_IMAGE_URL`, `ALMA_IMAGE_URL`,
|
||||||
|
and `VIRTIO_WIN_ISO_URL`.
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
Executable
+236
@@ -0,0 +1,236 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
images_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
base_qcow2_dir="${images_dir}/base-qcow2"
|
||||||
|
install_iso_dir="${images_dir}/install-iso"
|
||||||
|
tools_iso_dir="${images_dir}/tools-iso"
|
||||||
|
debian_image="${base_qcow2_dir}/debian-13-generic-amd64-20260810-2566.qcow2"
|
||||||
|
alma_image="${base_qcow2_dir}/AlmaLinux-10-GenericCloud-10.2-20260526.0.x86_64.qcow2"
|
||||||
|
virtio_image="${tools_iso_dir}/virtio-win.iso"
|
||||||
|
windows_qcow2_image="${base_qcow2_dir}/Win11_25H2_English_x64_v2.qcow2"
|
||||||
|
windows_iso_image="${install_iso_dir}/Win11_25H2_English_x64_v2.iso"
|
||||||
|
|
||||||
|
debian_url="${DEBIAN_IMAGE_URL:-https://cloud.debian.org/images/cloud/trixie/20260810-2566/debian-13-generic-amd64-20260810-2566.qcow2}"
|
||||||
|
alma_url="${ALMA_IMAGE_URL:-https://repo.almalinux.org/almalinux/10/cloud/x86_64/images/AlmaLinux-10-GenericCloud-10.2-20260526.0.x86_64.qcow2}"
|
||||||
|
virtio_url="${VIRTIO_WIN_ISO_URL:-https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso}"
|
||||||
|
debian_sha512="${DEBIAN_IMAGE_SHA512:-f6978100d8031c266d55d7815ceea7fcdeacf28e1e5834fdb9c94ac96880a054a6e6f8681c2d3b0584e0057eaf3ef7353856b85212d04134744faa9b3bb1f24f}"
|
||||||
|
alma_sha256="${ALMA_IMAGE_SHA256:-47f2218668dd4776be140dd92fa3bea700be1766e2c7d88bdfd6a4b50f477b4d}"
|
||||||
|
force_download=false
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF
|
||||||
|
Usage: $(basename "$0") [--force] [all|debian13|almalinux10|virtio-win] ...
|
||||||
|
$(basename "$0") --print-path TARGET [--iso]
|
||||||
|
|
||||||
|
Download one or more shared VM images. With no arguments, all targets are
|
||||||
|
processed.
|
||||||
|
|
||||||
|
--force removes existing files and partial downloads for the selected targets,
|
||||||
|
then downloads them again from the beginning.
|
||||||
|
--print-path prints only the absolute image path without downloading it.
|
||||||
|
For windows11 it prints the QCOW2 path by default; add --iso for the ISO path.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
print_image_path() {
|
||||||
|
local target="$1"
|
||||||
|
local media="${2:-qcow2}"
|
||||||
|
|
||||||
|
case "$target" in
|
||||||
|
debian13) printf '%s\n' "$debian_image" ;;
|
||||||
|
almalinux10) printf '%s\n' "$alma_image" ;;
|
||||||
|
virtio-win) printf '%s\n' "$virtio_image" ;;
|
||||||
|
windows11)
|
||||||
|
if [[ "$media" == iso ]]; then
|
||||||
|
printf '%s\n' "$windows_iso_image"
|
||||||
|
else
|
||||||
|
printf '%s\n' "$windows_qcow2_image"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf 'Error: path is unavailable for target: %s\n' "$1" >&2
|
||||||
|
usage >&2
|
||||||
|
return 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "${1:-}" == --print-path ]]; then
|
||||||
|
if (($# < 2 || $# > 3)); then
|
||||||
|
printf 'Error: --print-path requires one target and optionally --iso.\n' >&2
|
||||||
|
usage >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
if (($# == 3)) && [[ "$2" != windows11 || "$3" != --iso ]]; then
|
||||||
|
printf 'Error: --iso is only valid after the windows11 target.\n' >&2
|
||||||
|
usage >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
media_option="${3:-}"
|
||||||
|
print_image_path "$2" "${media_option#--}"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
targets=()
|
||||||
|
for argument in "$@"; do
|
||||||
|
if [[ "$argument" == --force ]]; then
|
||||||
|
force_download=true
|
||||||
|
else
|
||||||
|
targets+=("$argument")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if ((${#targets[@]} == 0)); then
|
||||||
|
targets=(all)
|
||||||
|
fi
|
||||||
|
|
||||||
|
for target in "${targets[@]}"; do
|
||||||
|
case "$target" in
|
||||||
|
all|debian13|almalinux10|virtio-win) ;;
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
*) printf 'Error: unknown download target: %s\n' "$target" >&2; usage >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
wants_target() {
|
||||||
|
local requested="$1"
|
||||||
|
local target
|
||||||
|
for target in "${targets[@]}"; do
|
||||||
|
[[ "$target" == all || "$target" == "$requested" ]] && return 0
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir -p "$base_qcow2_dir" "$install_iso_dir" "$tools_iso_dir"
|
||||||
|
|
||||||
|
verify_file() {
|
||||||
|
local label="$1"
|
||||||
|
local file="$2"
|
||||||
|
local algorithm="$3"
|
||||||
|
local expected="$4"
|
||||||
|
local command_name="${algorithm}sum"
|
||||||
|
local actual
|
||||||
|
|
||||||
|
if ! command -v "$command_name" >/dev/null 2>&1; then
|
||||||
|
printf 'Error: %s is required to verify %s.\n' "$command_name" "$label" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
actual="$("$command_name" "$file")"
|
||||||
|
actual="${actual%% *}"
|
||||||
|
if [[ "$actual" != "$expected" ]]; then
|
||||||
|
printf 'Error: %s checksum mismatch for %s.\nFile: %s\nExpected: %s\nActual: %s\n' \
|
||||||
|
"${algorithm^^}" "$label" "$file" "$expected" "$actual" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf 'Verified %s checksum for %s.\n' "${algorithm^^}" "$label"
|
||||||
|
}
|
||||||
|
|
||||||
|
download_file() {
|
||||||
|
local label="$1"
|
||||||
|
local url="$2"
|
||||||
|
local destination="$3"
|
||||||
|
local checksum_algorithm="${4:-}"
|
||||||
|
local expected_checksum="${5:-}"
|
||||||
|
local partial="${destination}.part"
|
||||||
|
local partial_url="${partial}.url"
|
||||||
|
local downloader
|
||||||
|
|
||||||
|
if [[ "$force_download" == true ]]; then
|
||||||
|
printf 'Forcing a fresh download of %s.\n' "$label"
|
||||||
|
rm -f -- "$destination" "$partial" "$partial_url"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -s "$destination" ]]; then
|
||||||
|
if [[ -n "$expected_checksum" ]]; then
|
||||||
|
verify_file "$label" "$destination" "$checksum_algorithm" "$expected_checksum" || return 1
|
||||||
|
fi
|
||||||
|
printf '%s already exists; skipping:\n%s\n' "$label" "$destination"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf 'Downloading %s from:\n%s\n' "$label" "$url"
|
||||||
|
printf 'Download destination:\n%s\n' "$destination"
|
||||||
|
|
||||||
|
if [[ -e "$partial" ]]; then
|
||||||
|
if [[ ! -f "$partial_url" ]] || [[ "$(<"$partial_url")" != "$url" ]]; then
|
||||||
|
printf 'Download URL changed; restarting partial download.\n'
|
||||||
|
rm -f -- "$partial" "$partial_url"
|
||||||
|
else
|
||||||
|
printf 'Resuming partial download:\n%s\n' "$partial"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
printf '%s' "$url" >"$partial_url"
|
||||||
|
|
||||||
|
if command -v curl >/dev/null 2>&1; then
|
||||||
|
downloader=curl
|
||||||
|
elif command -v wget >/dev/null 2>&1; then
|
||||||
|
downloader=wget
|
||||||
|
else
|
||||||
|
printf 'Error: curl or wget is required.\n' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$downloader" == curl ]]; then
|
||||||
|
if ! curl --fail --location --retry 3 --continue-at - --output "$partial" "$url"; then
|
||||||
|
if [[ -s "$partial" ]]; then
|
||||||
|
printf 'Resume failed; restarting download from the beginning.\n'
|
||||||
|
rm -f -- "$partial"
|
||||||
|
curl --fail --location --retry 3 --output "$partial" "$url"
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if ! wget --tries=3 --continue --output-document="$partial" "$url"; then
|
||||||
|
if [[ -s "$partial" ]]; then
|
||||||
|
printf 'Resume failed; restarting download from the beginning.\n'
|
||||||
|
rm -f -- "$partial"
|
||||||
|
wget --tries=3 --output-document="$partial" "$url"
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -s "$partial" ]]; then
|
||||||
|
printf 'Error: downloaded file is empty: %s\n' "$partial" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$expected_checksum" ]] && \
|
||||||
|
! verify_file "$label" "$partial" "$checksum_algorithm" "$expected_checksum"; then
|
||||||
|
rm -f -- "$partial" "$partial_url"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mv -- "$partial" "$destination"
|
||||||
|
rm -f -- "$partial_url"
|
||||||
|
printf 'Downloaded %s:\n%s\n' "$label" "$destination"
|
||||||
|
}
|
||||||
|
|
||||||
|
if wants_target debian13; then
|
||||||
|
download_file \
|
||||||
|
'Debian 13 cloud image' \
|
||||||
|
"$debian_url" \
|
||||||
|
"$debian_image" \
|
||||||
|
sha512 \
|
||||||
|
"$debian_sha512"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if wants_target almalinux10; then
|
||||||
|
download_file \
|
||||||
|
'AlmaLinux 10 cloud image' \
|
||||||
|
"$alma_url" \
|
||||||
|
"$alma_image" \
|
||||||
|
sha256 \
|
||||||
|
"$alma_sha256"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if wants_target virtio-win; then
|
||||||
|
download_file \
|
||||||
|
'VirtIO Windows tools ISO' \
|
||||||
|
"$virtio_url" \
|
||||||
|
"$virtio_image"
|
||||||
|
fi
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
Reference in new issue
Block a user