Skip to content

Commit 60c31f0

Browse files
authored
Merge pull request #5480 from damdo/improve-ami-publishing-docs
📖 Add find-ami-publishing-inputs script + docs instructions
2 parents c57821f + ab1e241 commit 60c31f0

File tree

2 files changed

+228
-0
lines changed

2 files changed

+228
-0
lines changed

docs/book/src/development/amis.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ For a new Kubernetes version that you want to build an AMI for you will need to
2222

2323
You can determine these values directly or by looking at the publish debian apt repositories for the k8s release.
2424

25+
A quick way to get these values is by using the find-ami-publishing-inputs script.
26+
The script lives under `/scripts` in the root directory of CAPA, and can be invoked like so (supposing you want to publish k8s v1.32 AMIs):
27+
```
28+
./scripts/find-ami-publishing-inputs.sh v1.32
29+
```
30+
2531
## Build
2632

2733
### Using GitHub Actions Workflow

scripts/find-ami-publishing-inputs.sh

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
#!/bin/bash
2+
#
3+
# Script to find various Kubernetes-related package versions for CAPA AMI publishing
4+
# based on a target Kubernetes release series (e.g., v1.31 or 1.31) or a
5+
# specific patch version (e.g., v1.31.5 or 1.31.5).
6+
#
7+
# Usage: ./script.sh [vX.Y | X.Y | vX.Y.Z | X.Y.Z]
8+
# Example: ./script.sh v1.31
9+
# ./script.sh 1.31
10+
# ./script.sh v1.31.5
11+
# ./script.sh 1.31.5
12+
# ./script.sh
13+
#
14+
15+
# Exit immediately if a command exits with a non-zero status.
16+
# Treat unset variables as an error.
17+
# The return value of a pipeline is the status of the last command to exit with a non-zero status,
18+
# or zero if no command exited with a non-zero status.
19+
set -euo pipefail
20+
21+
# --- Dependency Checks ---
22+
# Check for container runtime
23+
if command -v podman &> /dev/null; then
24+
CONTAINER_CMD="podman"
25+
elif command -v docker &> /dev/null; then
26+
CONTAINER_CMD="docker"
27+
else
28+
echo "ERROR: Neither 'podman' nor 'docker' command found. Please install one." >&2
29+
exit 1
30+
fi
31+
echo "INFO: Using container runtime: $CONTAINER_CMD"
32+
33+
# Check for other required host tools
34+
REQUIRED_TOOLS=( "curl" "grep" "sed" "awk" "cut" "sort" "tail" )
35+
MISSING_TOOLS=()
36+
for tool in "${REQUIRED_TOOLS[@]}"; do
37+
if ! command -v "$tool" &> /dev/null; then
38+
MISSING_TOOLS+=("$tool")
39+
fi
40+
done
41+
42+
if [ ${#MISSING_TOOLS[@]} -ne 0 ]; then
43+
echo "ERROR: Missing required command-line tools: ${MISSING_TOOLS[*]}" >&2
44+
echo "Please install them and try again." >&2
45+
exit 1
46+
fi
47+
echo "INFO: All required host tools found."
48+
49+
50+
# --- Configuration & Input Handling ---
51+
DEFAULT_K8S_RELEASE_SERIES_NO_V="1.31"
52+
K8S_RELEASE_ARG="${1:-}" # Get potential argument
53+
K8S_TARGET_VERSION_NO_V="" # Specific X.Y.Z requested, if any
54+
K8S_TARGET_VERSION_V="" # Specific vX.Y.Z requested, if any
55+
56+
if [[ -n "$K8S_RELEASE_ARG" ]]; then
57+
# Argument provided, validate and normalize
58+
if [[ "$K8S_RELEASE_ARG" =~ ^v([0-9]+\.[0-9]+)\.([0-9]+)$ ]]; then # Matches vX.Y.Z
59+
K8S_RELEASE_SERIES="v${BASH_REMATCH[1]}" # vX.Y
60+
K8S_RELEASE_SERIES_NO_V="${BASH_REMATCH[1]}" # X.Y
61+
K8S_TARGET_VERSION_NO_V="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}" # X.Y.Z
62+
K8S_TARGET_VERSION_V="$K8S_RELEASE_ARG" # vX.Y.Z
63+
echo "INFO: Specific version requested: ${K8S_TARGET_VERSION_V}"
64+
elif [[ "$K8S_RELEASE_ARG" =~ ^([0-9]+\.[0-9]+)\.([0-9]+)$ ]]; then # Matches X.Y.Z
65+
K8S_RELEASE_SERIES="v${BASH_REMATCH[1]}" # vX.Y
66+
K8S_RELEASE_SERIES_NO_V="${BASH_REMATCH[1]}" # X.Y
67+
K8S_TARGET_VERSION_NO_V="$K8S_RELEASE_ARG" # X.Y.Z
68+
K8S_TARGET_VERSION_V="v$K8S_RELEASE_ARG" # vX.Y.Z
69+
echo "INFO: Specific version requested: ${K8S_TARGET_VERSION_V}"
70+
elif [[ "$K8S_RELEASE_ARG" =~ ^v([0-9]+\.[0-9]+)$ ]]; then # Matches vX.Y
71+
K8S_RELEASE_SERIES="$K8S_RELEASE_ARG"
72+
K8S_RELEASE_SERIES_NO_V="${BASH_REMATCH[1]}"
73+
echo "INFO: Release series requested: ${K8S_RELEASE_SERIES}"
74+
elif [[ "$K8S_RELEASE_ARG" =~ ^([0-9]+\.[0-9]+)$ ]]; then # Matches X.Y
75+
K8S_RELEASE_SERIES="v$K8S_RELEASE_ARG"
76+
K8S_RELEASE_SERIES_NO_V="$K8S_RELEASE_ARG"
77+
echo "INFO: Release series requested: ${K8S_RELEASE_SERIES}"
78+
else
79+
echo "ERROR: Invalid format for Kubernetes version/series argument: '$K8S_RELEASE_ARG'." >&2
80+
echo " Expected format 'vX.Y', 'X.Y', 'vX.Y.Z', or 'X.Y.Z'." >&2
81+
exit 1
82+
fi
83+
else
84+
# No argument, use default series
85+
K8S_RELEASE_SERIES_NO_V="$DEFAULT_K8S_RELEASE_SERIES_NO_V"
86+
K8S_RELEASE_SERIES="v$K8S_RELEASE_SERIES_NO_V"
87+
echo "INFO: No version specified, using default series: ${K8S_RELEASE_SERIES}"
88+
fi
89+
90+
echo "--- Finding versions for Kubernetes release series: ${K8S_RELEASE_SERIES} ---"
91+
echo "INFO: Using Kubernetes major.minor: ${K8S_RELEASE_SERIES_NO_V}"
92+
93+
# --- Get Deb Package Versions ---
94+
echo "INFO: Running container (${CONTAINER_CMD}) to fetch deb package versions from pkgs.k8s.io..."
95+
96+
# Construct the command for kubectl lookup based on whether a specific version was requested
97+
if [[ -n "$K8S_TARGET_VERSION_NO_V" ]]; then
98+
# Look for the exact X.Y.Z version (allow any deb revision like -1.1)
99+
# Need to escape special characters for grep and ensure we match start of version
100+
KUBECTL_LOOKUP_PATTERN="${K8S_TARGET_VERSION_NO_V}-[0-9]"
101+
KUBECTL_NOT_FOUND_MSG="kubectl version ${K8S_TARGET_VERSION_NO_V} not found"
102+
# We still sort and take tail -n 1 in case multiple deb revisions exist for the same k8s version
103+
KUBECTL_MADISON_CMD="apt-cache madison kubectl | grep \"${KUBECTL_LOOKUP_PATTERN}\" | sort -V | tail -n 1 || echo \"${KUBECTL_NOT_FOUND_MSG}\""
104+
else
105+
# Look for the latest within the X.Y series
106+
KUBECTL_LOOKUP_PATTERN="${K8S_RELEASE_SERIES_NO_V}"
107+
KUBECTL_NOT_FOUND_MSG="kubectl version not found for series ${K8S_RELEASE_SERIES_NO_V}"
108+
KUBECTL_MADISON_CMD="apt-cache madison kubectl | grep \"${KUBECTL_LOOKUP_PATTERN}\" | sort -V | tail -n 1 || echo \"${KUBECTL_NOT_FOUND_MSG}\""
109+
fi
110+
111+
PACKAGE_INFO=$(${CONTAINER_CMD} run --platform=linux/amd64 --rm -i ubuntu:22.04 /bin/bash <<EOF
112+
set -e # Exit on error inside the container script
113+
export DEBIAN_FRONTEND=noninteractive
114+
apt-get update > /dev/null
115+
apt-get install -y gpg curl sudo > /dev/null
116+
117+
# Add Kubernetes APT repository using the vX.Y format
118+
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/${K8S_RELEASE_SERIES}/deb/ /" | tee /etc/apt/sources.list.d/kubernetes.list > /dev/null
119+
mkdir -p -m 755 /etc/apt/keyrings
120+
curl -fsSL "https://pkgs.k8s.io/core:/stable:/${K8S_RELEASE_SERIES}/deb/Release.key" | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg > /dev/null
121+
apt-get update > /dev/null
122+
123+
# Output marker and package info for kubectl using the constructed command
124+
echo "---KUBECTL_START---"
125+
eval "$KUBECTL_MADISON_CMD" # Use eval to run the command string built on the host
126+
echo "---KUBECTL_END---"
127+
128+
# Output marker and package info for CNI (always latest for the series)
129+
echo "---CNI_START---"
130+
apt-cache madison kubernetes-cni | sort -V | tail -n 1 || echo "kubernetes-cni version not found"
131+
echo "---CNI_END---"
132+
EOF
133+
)
134+
135+
# Check if container command was successful
136+
if [ $? -ne 0 ]; then
137+
echo "ERROR: Failed to run ${CONTAINER_CMD} container." >&2
138+
exit 1
139+
fi
140+
141+
echo "INFO: Processing package information..."
142+
143+
# Extract kubectl version found by the container
144+
K8S_DEB_VERSION_LINE=$(echo "${PACKAGE_INFO}" | awk '/---KUBECTL_START---/{flag=1; next} /---KUBECTL_END---/{flag=0} flag')
145+
if [[ -z "$K8S_DEB_VERSION_LINE" || "$K8S_DEB_VERSION_LINE" == *"not found"* ]]; then
146+
# Use the specific "not found" message from the container if available
147+
NOT_FOUND_MSG=$(echo "$K8S_DEB_VERSION_LINE" | grep "not found" || echo "Could not find requested kubectl deb package version.")
148+
echo "ERROR: ${NOT_FOUND_MSG}" >&2
149+
exit 1
150+
fi
151+
# Extract the version part (e.g., 1.31.5-1.1) which is the 3rd field
152+
K8S_DEB_VERSION=$(echo "$K8S_DEB_VERSION_LINE" | awk '{print $3}')
153+
154+
# Extract latest CNI version (always latest for the series)
155+
CNI_DEB_VERSION_LINE=$(echo "${PACKAGE_INFO}" | awk '/---CNI_START---/{flag=1; next} /---CNI_END---/{flag=0} flag')
156+
if [[ -z "$CNI_DEB_VERSION_LINE" || "$CNI_DEB_VERSION_LINE" == *"not found"* ]]; then
157+
echo "ERROR: Could not find kubernetes-cni deb package version for series ${K8S_RELEASE_SERIES}." >&2
158+
exit 1
159+
fi
160+
# Extract the version part (e.g., 1.5.1-1.1) which is the 3rd field
161+
CNI_DEB_VERSION=$(echo "$CNI_DEB_VERSION_LINE" | awk '{print $3}')
162+
163+
# --- Derive K8s Versions ---
164+
# K8s Semver (vX.Y.Z)
165+
if [[ -n "$K8S_TARGET_VERSION_V" ]]; then
166+
# If specific version was requested, use that as the Semver base
167+
K8S_SEMVER="$K8S_TARGET_VERSION_V"
168+
# Sanity check: ensure the found deb package matches the requested semver
169+
FOUND_SEMVER_BASE="v$(echo "$K8S_DEB_VERSION" | cut -d'-' -f1)"
170+
if [[ "$FOUND_SEMVER_BASE" != "$K8S_SEMVER" ]]; then
171+
echo "WARN: Found kubectl deb version (${K8S_DEB_VERSION}) does not match requested K8s Semver (${K8S_SEMVER}). Using found version's base." >&2
172+
K8S_SEMVER="$FOUND_SEMVER_BASE" # Trust the found version more
173+
fi
174+
else
175+
# If only series was requested, derive Semver from the found deb package
176+
K8S_SEMVER="v$(echo "$K8S_DEB_VERSION" | cut -d'-' -f1)"
177+
fi
178+
179+
# K8s Release Series (vX.Y) - Always derived from the input/default series
180+
K8S_RELEASE_SERIES_OUTPUT="${K8S_RELEASE_SERIES}"
181+
182+
# K8s RPM Package Version (X.Y.Z) - Derived from the final K8S_SEMVER
183+
K8S_RPM_VERSION="${K8S_SEMVER#v}"
184+
185+
# --- Derive CNI Version ---
186+
# CNI Semver (vX.Y.Z) - Derived from the latest CNI deb package found for the series
187+
CNI_SEMVER="v$(echo "$CNI_DEB_VERSION" | cut -d'-' -f1)"
188+
189+
# --- Determine CRICTL Version ---
190+
# Always based on the K8S_RELEASE_SERIES (vX.Y)
191+
echo "INFO: Fetching crictl release tags from GitHub API for series ${K8S_RELEASE_SERIES}..."
192+
CRICTL_RAW_TAG=$(curl -s https://api.github.com/repos/kubernetes-sigs/cri-tools/releases \
193+
| grep '"tag_name":' \
194+
| grep "\"${K8S_RELEASE_SERIES}." \
195+
| sed -E 's/.*"tag_name": *"([^"]+)".*/\1/' \
196+
| sort -V \
197+
| tail -n 1 \
198+
|| echo "" ) # Avoid script exit if curl or grep fails in the pipe
199+
200+
if [ -z "$CRICTL_RAW_TAG" ]; then
201+
echo "WARN: Could not automatically determine latest crictl tag for ${K8S_RELEASE_SERIES} from GitHub API." >&2
202+
echo "WARN: Please verify the crictl version manually at https://github.com/kubernetes-sigs/cri-tools/releases" >&2
203+
CRICTL_VERSION="<Check Manually for ${K8S_RELEASE_SERIES}>"
204+
else
205+
CRICTL_VERSION="${CRICTL_RAW_TAG#v}"
206+
fi
207+
208+
209+
# --- Output Results ---
210+
echo
211+
echo "--- Derived Versions for K8s ${K8S_RELEASE_SERIES} (Target: ${K8S_TARGET_VERSION_V:-Latest}) ---"
212+
# Output order from previous request is maintained
213+
printf "%-25s : %s\n" "K8s Semver" "${K8S_SEMVER}"
214+
printf "%-25s : %s\n" "K8s Release Series" "${K8S_RELEASE_SERIES_OUTPUT}"
215+
printf "%-25s : %s\n" "K8s RPM Package Version" "${K8S_RPM_VERSION}"
216+
printf "%-25s : %s\n" "K8s Deb Package Version" "${K8S_DEB_VERSION}"
217+
printf "%-25s : %s\n" "CNI Semver" "${CNI_SEMVER}"
218+
printf "%-25s : %s\n" "CNI Deb Package Version" "${CNI_DEB_VERSION}"
219+
printf "%-25s : %s\n" "CRICTL Version" "${CRICTL_VERSION}"
220+
echo "---------------------------------------"
221+
222+
exit 0

0 commit comments

Comments
 (0)