mirror of
https://github.com/techno-tim/k3s-ansible.git
synced 2026-08-09 07:23:19 +02:00
fix(ci): make Vagrant box cache version-aware
- key immutable caches from a pinned box manifest instead of scenario YAML - skip producer restoration and downloads on exact cache hits - validate lock drift, exact versions, architectures, and missing boxes
This commit is contained in:
committed by
Techno Tim
parent
fb9a0bebd1
commit
57f234c8da
+70
-19
@@ -1,40 +1,91 @@
|
||||
#!/bin/bash
|
||||
|
||||
# download-boxes.sh
|
||||
# Check all molecule.yml files for required Vagrant boxes and download the ones that are not
|
||||
# already present on the system.
|
||||
# Validate the pinned Vagrant box set and download exact versions that are not
|
||||
# already present in VAGRANT_HOME.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
GIT_ROOT=$(git rev-parse --show-toplevel)
|
||||
PROVIDER=virtualbox
|
||||
LOCK_FILE="${VAGRANT_BOX_LOCK_FILE:-${GIT_ROOT}/.github/vagrant-boxes.lock}"
|
||||
|
||||
# Define the path to the molecule.yml files
|
||||
MOLECULE_YML_PATH=("${GIT_ROOT}"/molecule/*/molecule.yml)
|
||||
|
||||
# Extract and sort unique boxes from all molecule.yml files
|
||||
all_boxes=$(for file in "${MOLECULE_YML_PATH[@]}"; do
|
||||
# Extract the unique boxes referenced by the scenarios.
|
||||
declared_boxes=$(for file in "${MOLECULE_YML_PATH[@]}"; do
|
||||
yq -r '.platforms[].box' "$file"
|
||||
done | sort -u)
|
||||
|
||||
echo all_boxes: "$all_boxes"
|
||||
if [[ ! -r "$LOCK_FILE" ]]; then
|
||||
printf 'Vagrant box lock file is missing or unreadable: %s\n' "$LOCK_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Read the boxes that are currently present on the system (for the current provider)
|
||||
lock_entries=$(awk '
|
||||
/^[[:space:]]*#/ || NF == 0 { next }
|
||||
NF != 3 {
|
||||
printf "Invalid lock entry on line %d: expected box, version, architecture\n", NR > "/dev/stderr"
|
||||
invalid = 1
|
||||
next
|
||||
}
|
||||
{ print $1 " " $2 " " $3 }
|
||||
END { exit invalid }
|
||||
' "$LOCK_FILE")
|
||||
|
||||
duplicate_boxes=$(printf '%s\n' "$lock_entries" | awk '{ print $1 }' | sort | uniq -d)
|
||||
if [[ -n "$duplicate_boxes" ]]; then
|
||||
printf 'Duplicate Vagrant box lock entries:\n%s\n' "$duplicate_boxes" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
locked_boxes=$(printf '%s\n' "$lock_entries" | sort)
|
||||
locked_names=$(printf '%s\n' "$locked_boxes" | awk '{ print $1 }')
|
||||
missing_locks=$(comm -23 <(printf '%s\n' "$declared_boxes") <(printf '%s\n' "$locked_names"))
|
||||
unused_locks=$(comm -13 <(printf '%s\n' "$declared_boxes") <(printf '%s\n' "$locked_names"))
|
||||
|
||||
if [[ -n "$missing_locks" || -n "$unused_locks" ]]; then
|
||||
if [[ -n "$missing_locks" ]]; then
|
||||
printf 'Scenario boxes missing from the lock file:\n%s\n' "$missing_locks" >&2
|
||||
fi
|
||||
if [[ -n "$unused_locks" ]]; then
|
||||
printf 'Lock entries not referenced by a scenario:\n%s\n' "$unused_locks" >&2
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf 'Pinned Vagrant boxes:\n%s\n' "$locked_boxes"
|
||||
|
||||
# Read exact box, provider, version, and architecture tuples already present.
|
||||
present_boxes=$(
|
||||
(vagrant box list |
|
||||
grep "${PROVIDER}" | # Filter by boxes available for the current provider
|
||||
awk '{print $1;}' | # The box name is the first word in each line
|
||||
sort |
|
||||
uniq) ||
|
||||
echo "" # In case any of these commands fails, just use an empty list
|
||||
vagrant box list --machine-readable |
|
||||
awk -F, -v expected_provider="$PROVIDER" '
|
||||
$3 == "box-name" { name = $4; next }
|
||||
$3 == "box-provider" { provider = $4; next }
|
||||
$3 == "box-version" { version = $4; next }
|
||||
$3 == "box-architecture" {
|
||||
architecture = $4
|
||||
if (provider == expected_provider) {
|
||||
print name " " version " " architecture
|
||||
}
|
||||
name = provider = version = architecture = ""
|
||||
}
|
||||
' |
|
||||
sort -u
|
||||
)
|
||||
|
||||
# The boxes that we need to download are the ones present in $all_boxes, but not $present_boxes.
|
||||
download_boxes=$(comm -2 -3 <(echo "${all_boxes}") <(echo "${present_boxes}"))
|
||||
download_boxes=$(comm -23 \
|
||||
<(printf '%s\n' "$locked_boxes") \
|
||||
<(printf '%s\n' "$present_boxes"))
|
||||
|
||||
# Actually download the necessary boxes
|
||||
if [ -n "${download_boxes}" ]; then
|
||||
echo "${download_boxes}" | while IFS= read -r box; do
|
||||
vagrant box add --provider "${PROVIDER}" "${box}"
|
||||
if [[ -n "$download_boxes" ]]; then
|
||||
printf '%s\n' "$download_boxes" | while read -r box version architecture; do
|
||||
vagrant box add \
|
||||
--provider "$PROVIDER" \
|
||||
--box-version "$version" \
|
||||
--architecture "$architecture" \
|
||||
"$box"
|
||||
done
|
||||
else
|
||||
printf 'All pinned Vagrant boxes are already present.\n'
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user