Skip to content

Commit ad2d779

Browse files
committed
packer: Simplify apt mirror fallback
It turns out that most of the code deleted here was actually not doing anything useful. For example, switch_mirror modifies /etc/apt/sources.list in place but the file doesn't have any mirrors configured there so it's really a no-op! Here's the contents from an instance I just fired up[^1]: ubuntu@ip-172-31-26-227:~$ tail -n+1 /etc/apt/sources.list /etc/apt/sources.list.d/* ==> /etc/apt/sources.list <== # Ubuntu sources have moved to the /etc/apt/sources.list.d/ubuntu.sources # file, which uses the deb822 format. Use deb822-formatted .sources files # to manage package sources in the /etc/apt/sources.list.d/ directory. # See the sources.list(5) manual page for details. ==> /etc/apt/sources.list.d/ubuntu.sources <== ## Note, this file is written by cloud-init on first boot of an instance ## modifications made here will not survive a re-bundle. --- 8< --- Types: deb URIs: http://us-east-2.ec2.archive.ubuntu.com/ubuntu/ Suites: noble noble-updates noble-backports Components: main universe restricted multiverse Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg Types: deb URIs: http://us-east-2.ec2.archive.ubuntu.com/ubuntu/ Suites: noble noble-updates noble-backports Components: main universe restricted multiverse Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg ## Ubuntu security updates. Aside from URIs and Suites, ## this should mirror your choices in the previous section. Types: deb URIs: http://security.ubuntu.com/ubuntu Suites: noble-security Components: main universe restricted multiverse Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg We get fallback handling by apt itself by adding multiple mirrors in URIs, apt tries first (the regional) and falls back to global ubuntu repos if there's an issue. We also setup a temporary apt config that forces the APT_OPTIONS for all apt calls so we don't need to do it in every call site. I ended up dropping the in-repo sources file since they are strictly worse than what we get from AWS in the build. There's no change in suites or components between old and new, just that we get ubuntu upstream as a fallback. Well technically there's a slight difference since we are basing off of cloud-init generated files and they can theoretically change under us but I'll gamble that it'll be fine or better off. Besides, one day we'll be on NixOS as the ultimate "make sure we know everything in the instance" ;). I also got rid of the `add-apt-repository --yes universe` because universe is already enabled. [^1]: AMI=ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.04-amd64-server-20260604
1 parent 6d180e3 commit ad2d779

6 files changed

Lines changed: 44 additions & 278 deletions

File tree

amazon-amd64-nix.pkr.hcl

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,6 @@ source "amazon-ebssurrogate" "source" {
170170
build {
171171
sources = ["source.amazon-ebssurrogate.source"]
172172

173-
provisioner "file" {
174-
source = "ebssurrogate/files/sources.cfg"
175-
destination = "/tmp/sources.list"
176-
}
177-
178173
provisioner "file" {
179174
source = "ebssurrogate/files/ebsnvme-id"
180175
destination = "/tmp/ebsnvme-id"

amazon-arm64-nix.pkr.hcl

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,6 @@ source "amazon-ebssurrogate" "source" {
170170
build {
171171
sources = ["source.amazon-ebssurrogate.source"]
172172

173-
provisioner "file" {
174-
source = "ebssurrogate/files/sources-arm64.cfg"
175-
destination = "/tmp/sources.list"
176-
}
177-
178173
provisioner "file" {
179174
source = "ebssurrogate/files/ebsnvme-id"
180175
destination = "/tmp/ebsnvme-id"

ebssurrogate/files/sources-arm64.cfg

Lines changed: 0 additions & 10 deletions
This file was deleted.

ebssurrogate/files/sources.cfg

Lines changed: 0 additions & 10 deletions
This file was deleted.

ebssurrogate/scripts/chroot-bootstrap-nix.sh

Lines changed: 6 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -8,166 +8,20 @@ set -o errexit
88
set -o pipefail
99
set -o xtrace
1010

11-
# Switch to a different mirror
12-
function switch_mirror {
13-
local new_mirror=$1
14-
local sources_file=/etc/apt/sources.list
15-
16-
echo "Switching to mirror: $new_mirror"
17-
if [[ $ARCH == amd64 ]]; then
18-
sed -i "s|http://[^/]*/ubuntu/|http://$new_mirror/ubuntu/|g" "$sources_file"
19-
else
20-
sed -i "s|http://[^/]*/ubuntu-ports/|http://$new_mirror/ubuntu-ports/|g" "$sources_file"
21-
fi
22-
23-
# Show what we're using
24-
echo "Current sources.list configuration:"
25-
grep -E '^deb ' "$sources_file" | head -3
26-
}
27-
28-
# Get list of mirrors to try
29-
function get_mirror_list {
30-
local sources_file=/etc/apt/sources.list
31-
local -a mirrors=()
32-
33-
# Priority order:
34-
# 1. Country-specific mirror (most reliable)
35-
# 2. Regional CDN (can be inconsistent)
36-
# 3. Global fallback
37-
38-
local current_region
39-
if [[ $ARCH == amd64 ]]; then
40-
current_region=$(grep -oP '(?<=http://)[^.]+(?=\.ec2\.archive\.ubuntu\.com)' "$sources_file" | head -1 || echo "")
41-
42-
if [[ -n $current_region ]]; then
43-
mirrors+=("$current_region.ec2.archive.ubuntu.com")
44-
fi
45-
46-
mirrors+=("archive.ubuntu.com")
47-
else
48-
current_region=$(grep -oP '(?<=http://)[^.]+(?=\.clouds\.ports\.ubuntu\.com)' "$sources_file" | head -1 || echo "")
49-
50-
# Singapore country mirror for ap-southeast-1
51-
if [[ $current_region == "ap-southeast-1" ]]; then
52-
mirrors+=("sg.ports.ubuntu.com")
53-
fi
54-
55-
if [[ -n $current_region ]]; then
56-
mirrors+=("$current_region.clouds.ports.ubuntu.com")
57-
fi
58-
mirrors+=("ports.ubuntu.com")
59-
fi
60-
61-
echo "${mirrors[@]}"
62-
}
63-
64-
# Mirror fallback function for resilient apt-get update
11+
# The following 2 functions don'treally do much since we are now using deb822 formatted sources with fallbacks in the URIs.
12+
# This means apt-get handles fallback on its own, much better and cleaner than we are doing.
13+
# Leaving the functions as is for now to make the diff smaller, soon will go away.
6514
function apt_update_with_fallback {
66-
local sources_file=/etc/apt/sources.list
67-
local -a mirror_list
68-
readarray mirror_list < <(get_mirror_list)
69-
local attempt=1
70-
local max_attempts=${#mirror_list[@]}
71-
72-
for mirror in "${mirror_list[@]}"; do
73-
echo "========================================="
74-
echo "Attempting apt-get update with mirror: $mirror"
75-
echo "Attempt $attempt of $max_attempts"
76-
echo "========================================="
77-
78-
switch_mirror "$mirror"
79-
80-
# Attempt update with timeout (5 minutes)
81-
if timeout 300 apt-get "${APT_OPTIONS[@]}" update 2>&1; then
82-
echo "========================================="
83-
echo "✓ Successfully updated apt cache using mirror: $mirror"
84-
echo "========================================="
85-
return 0
86-
else
87-
local ret=$?
88-
echo "========================================="
89-
echo "✗ Failed to update using mirror: $mirror"
90-
echo "Exit code: $ret"
91-
echo "========================================="
92-
93-
# Clean partial downloads
94-
apt-get clean
95-
rm -rf /var/lib/apt/lists/*
96-
97-
# Exponential backoff before next attempt
98-
if [[ $attempt -lt $max_attempts ]]; then
99-
local sleep_time=$((attempt * 5))
100-
echo "Waiting $sleep_time seconds before trying next mirror..."
101-
sleep $sleep_time
102-
fi
103-
fi
104-
105-
attempt=$((attempt + 1))
106-
done
107-
108-
echo "========================================="
109-
echo "ERROR: All mirror tiers failed after $max_attempts attempts"
110-
echo "========================================="
111-
return 1
15+
timeout 300 apt-get "${APT_OPTIONS[@]}" update 2>&1
11216
}
11317

114-
# Wrapper for apt-get install with mirror fallback on 404 errors
11518
function apt_install_with_fallback {
116-
local -a mirror_list
117-
readarray mirror_list < <(get_mirror_list)
118-
local attempt=1
119-
local max_attempts=${#mirror_list[@]}
120-
121-
for mirror in "${mirror_list[@]}"; do
122-
echo "========================================="
123-
echo "Attempting apt-get install with mirror: $mirror"
124-
echo "Attempt $attempt of $max_attempts"
125-
echo "========================================="
126-
127-
switch_mirror "$mirror"
128-
129-
# Re-run apt-get update to get package lists from new mirror
130-
if ! timeout 300 apt-get "${APT_OPTIONS[@]}" update 2>&1; then
131-
echo "Warning: apt-get update failed for mirror $mirror, trying next..."
132-
attempt=$((attempt + 1))
133-
continue
134-
fi
135-
136-
# Run apt-get install directly (no output capture to avoid buffering/timeout issues)
137-
if apt-get "$@"; then
138-
echo "========================================="
139-
echo "✓ Successfully installed packages using mirror: ${mirror}"
140-
echo "========================================="
141-
return 0
142-
else
143-
local ret=$?
144-
# On failure, check if it's a mirror issue worth retrying
145-
echo "========================================="
146-
echo "✗ apt-get failed with exit code: $ret"
147-
echo "========================================="
148-
fi
149-
150-
# Clean apt cache before potential retry
151-
apt-get clean
152-
153-
if ((attempt < max_attempts)); then
154-
local sleep_time=$((attempt * 5))
155-
echo "Waiting $sleep_time seconds before trying next mirror..."
156-
sleep $sleep_time
157-
fi
158-
159-
attempt=$((attempt + 1))
160-
done
161-
162-
echo "========================================="
163-
echo "ERROR: All mirror tiers failed for apt-get install after $max_attempts attempts"
164-
echo "========================================="
165-
return 1
19+
apt-get "$@"
16620
}
16721

16822
function update_install_packages {
16923
# Update APT with new sources (using fallback mechanism)
170-
cat /etc/apt/sources.list
24+
tail -n+1 /etc/apt/sources.list /etc/apt/sources.list.d/*
17125
if ! apt_update_with_fallback; then
17226
echo "FATAL: Failed to update package lists with any mirror tier"
17327
exit 1
@@ -208,12 +62,6 @@ function update_install_packages {
20862
# apt upgrade
20963
apt-get upgrade -y
21064

211-
# Install OpenSSH and other packages
212-
add-apt-repository --yes universe
213-
if ! apt_update_with_fallback; then
214-
echo "FATAL: Failed to update package lists after adding universe repository"
215-
exit 1
216-
fi
21765
if ! apt_install_with_fallback install -y --no-install-recommends \
21866
openssh-server \
21967
git \

0 commit comments

Comments
 (0)