Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update HookOS downloading: #143

Merged
merged 5 commits into from
Nov 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tinkerbell/smee/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.5.0
version: 0.5.1

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
Expand Down
2 changes: 2 additions & 0 deletions tinkerbell/smee/templates/service.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{{- if .Values.deploy }}
---
apiVersion: v1
kind: Service
Expand Down Expand Up @@ -27,3 +28,4 @@ spec:
protocol: UDP
selector:
app: {{ .Values.name }}
{{- end }}
6 changes: 3 additions & 3 deletions tinkerbell/stack/Chart.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ dependencies:
version: 0.3.0
- name: smee
repository: file://../smee
version: 0.5.0
version: 0.5.1
- name: rufio
repository: file://../rufio
version: 0.4.0
- name: hegel
repository: file://../hegel
version: 0.4.0
digest: sha256:73e9f43db380aeadd559122946600d32957bb680a458365320c4dca790c31568
generated: "2024-10-30T12:38:29.599438269-06:00"
digest: sha256:cd45c3fbb6ed074365833472021dba91d7716a23b3ff23e22f17f03b2ae4cd3d
generated: "2024-11-22T21:01:58.580657087-07:00"
2 changes: 1 addition & 1 deletion tinkerbell/stack/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ dependencies:
version: "0.3.0"
repository: "file://../tink"
- name: smee
version: "0.5.0"
version: "0.5.1"
repository: "file://../smee"
- name: rufio
version: "0.4.0"
Expand Down
289 changes: 236 additions & 53 deletions tinkerbell/stack/templates/hook.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{- if .Values.stack.hook.enabled }}
{{- if and .Values.stack.enabled .Values.stack.hook.enabled }}
---
apiVersion: v1
kind: ConfigMap
Expand All @@ -8,64 +8,247 @@ metadata:
data:
entrypoint.sh: |-
#!/usr/bin/env bash
# This script is designed to download the Hook artifacts.
set -x

function run_checksum_check() {
local checksum_file=$1

# releases of HookOS > 0.8.1 provided more binaries than we general want here.
# We only need the hook_aarch64 and hook_x86_64 binaries so we filter out the rest.
base_l="$(dirname ${checksum_file})"
(cd "${base_l}" && sed -i '/hook_x86_64\|hook_aarch64/!d' checksum.txt && sha512sum -c checksum.txt)
if [ $? -ne 0 ]; then
return 1

set -euo pipefail

function usage() {
echo "Usage: $0 [OPTION]..."
echo "Script for downloading HookOS artifacts"
echo
echo "Options:"
echo " -u, --url Base URL to the location of the HookOS artifacts (default: https://github.com/tinkerbell/hook/releases/download/latest)"
echo " -a, --arch Architectures to download, one of [x86_64, aarch64, both] (default: both)"
echo " -v, --version The kernel version of the HookOS artifacts to download, one of [5.10, 6.6, both] (default: 6.6)"
echo " -e, --ext The artifact extension types to download, one of [tar.gz, iso, both] (default: both)"
echo " -s, --specific-artifacts List of non-standard artifacts to download"
echo " -o, --output-dir Output directory to store the downloaded artifacts (default: .)"
echo " -h, --help Display this help and exit"
}

function validate_option() {
local option="$1"
local valid_values="$2"
local value="$3"

if [[ ! " ${valid_values[@]} " =~ " ${value} " ]]; then
>&2 echo "Invalid value: '$value' for '${option}'. Valid values are: [${valid_values[*]}]"
usage
exit 1
fi
return 0
}



function get_by_kernel_version() {
# data must be newline separated list of artifacts
local data="$1"
local version="$2"
local artifacts=""

if [[ "${version}" == "both" ]]; then
artifacts+=$(grep -v "latest-lts" <<< $data)$'\n'
artifacts+=$(grep "latest-lts" <<< "$data")
elif [[ "${version}" == "6.6" ]]; then
artifacts=$(grep "latest-lts" <<< "$data")
elif [[ "${version}" == "5.10" ]]; then
artifacts=$(grep -v "latest-lts" <<< "$data")
fi

echo "${artifacts}"
}

function get_by_extension() {
local data="$1"
local ext="$2"
local artifacts=""

if [[ "${ext}" == "both" ]]; then
artifacts=$(grep ".tar.gz" <<< "$data")$'\n'
artifacts+=$(grep ".iso" <<< "$data")
elif [[ "${ext}" == "tar.gz" ]]; then
artifacts=$(grep ".tar.gz" <<< "$data")
elif [[ "${ext}" == "iso" ]]; then
artifacts=$(grep ".iso" <<< "$data")
fi

echo "${artifacts}"
}

function get_by_arch() {
local data="$1"
local arch="$2"
local artifacts=""

if [[ "${arch}" == "both" ]]; then
artifacts+=$(grep "x86_64" <<< "$data")$'\n'
artifacts+=$(grep "aarch64" <<< "$data")
elif [[ "${arch}" == "x86_64" ]]; then
artifacts=$(grep "x86_64" <<< "$data")
elif [[ "${arch}" == "aarch64" ]]; then
artifacts=$(grep "aarch64" <<< "$data")
fi

echo "${artifacts}"
}

function download_artifacts() {
local url="$1"
local artifacts="$2"
local out_dir="$3"

while IFS= read -r line; do
wget -O "${out_dir}/${line}" "${url}/${line}"
done < <(printf '%s\n' "$artifacts")
}

function run_checksum512() {
local checksum_data="$1"
local out_dir="$2"

(cd "${out_dir}" && sha512sum -c <<< "${checksum_data}")
if [ $? -ne 0 ]; then
return 1
fi
return 0
}

function checksum_format() {
# data is a newline separated list of artifacts
local data="$1"
local raw="$2"
local checksums=""

while IFS= read -r line; do
checksums+=$(grep "${line}" <<< "${raw}")$'\n'
done < <(printf '%s\n' "$data")

echo "${checksums}"
}

# default values
url="https://github.com/tinkerbell/hook/releases/download/latest"
arch="both"
version="6.6"
ext="both"
specific_artifacts=()
output_dir="."

# valid options
valid_arches=("x86_64" "aarch64" "both")
valid_versions=("5.10" "6.6" "both")
valid_exts=("tar.gz" "iso" "both")

args=$(getopt -a -o u:a:v:e:s:o:h --long url:,arch:,version:,ext:,specific-artifacts:,output-dir:,help -- "$@")
if [[ $? -gt 0 ]]; then
usage
fi

eval set -- ${args}
while :
do
case $1 in
-u | --url)
if [[ ! -z $2 ]]; then
url=$2
fi
shift 2 ;;
-a | --arch)
if [[ ! -z $2 ]]; then
validate_option "arch" "${valid_arches[*]}" $2
arch=$2
fi
shift 2 ;;
-v | --version)
if [[ ! -z $2 ]]; then
validate_option "version" "${valid_versions[*]}" $2
version=$2
fi
shift 2 ;;
-e | --ext)
if [[ ! -z $2 ]]; then
validate_option "ext" "${valid_exts[*]}" $2
ext=$2
fi
shift 2 ;;
-s | --specific-artifacts)
if [[ ! -z $2 ]]; then
specific_artifacts=$2
fi
shift 2 ;;
-o | --output-dir)
if [[ ! -z $2 ]]; then
output_dir=$2
fi
shift 2 ;;
-h | --help)
usage
exit 1
shift ;;
# -- means the end of the arguments; drop this, and break out of the while loop
--) shift; break ;;
*) >&2 echo Unsupported option: $1
usage ;;
esac
done

echo "==> Downloading HookOS artifacts from ${url} for architecture(s): ${arch} and extension(s): ${ext} and version(s): ${version}"

# 1. Download the checksum file
# 2. Generate a list of artifacts to download based on the options provided
# 3. Run a checksum check for all artifacts to be downloaded. For artifacts that pass (meaning the artifact is already downloaded), do nothing. Make a list of artifacts that need downloaded.
# 4. If all artifacts are already downloaded, sleep and wait for signals.
# 5. Download artifacts that need downloaded.
# 6. Run a checksum check for all downloaded artifacts.
# 7. If all checksums pass, sleep and wait for signals. If any checksum fails, exit with 1.

function main() {
# 1. Download the checksum.txt file
# 2. Check the checksums for files in the checksum.txt file
# 3. If the checksums match, sleep and wait for signals
# 4. If the checksums do not match, download the files again
# 5. Check the checksums again
local base_loc="$1"
local output_dir="$2"

# 1. Download the checksum.txt file
wget -O "${output_dir}/checksum.txt" "${base_loc}/checksum.txt"
# 2. Check the checksums for files in the checksum.txt file
run_checksum_check "${output_dir}/checksum.txt"
if [[ $? -eq 0 ]]; then
# 3. If the checksums match, sleep and wait for signals
sleep infinity & PID=$!
trap "kill $PID" INT TERM
wait $PID
return 0
local checksum_file="${output_dir}/checksum.txt"

# 1.
echo "==> Downloading checksum file from ${url}"
if ! wget -O "${checksum_file}" ${url}/checksum.txt; then
echo "==> Failed to download checksum file: ${url}/checksum.txt"
return 1
fi

# 4. If the checksums do not match, download the files again
files="$base_loc/hook_aarch64.tar.gz $base_loc/hook_x86_64.tar.gz"
for f in ${files}; do
echo "${f}"
wget -P "${output_dir}" "${f}"
done

run_checksum_check "${output_dir}/checksum.txt"
if [[ $? -eq 0 ]]; then
# 3. If the checksums match, sleep and wait for signals

# 2.
echo "==> Parsing checksum file"
raw_data=$(cat "${checksum_file}")
data=$(cat "${checksum_file}" | awk '{print $2}')
by_kernel=$(get_by_kernel_version "${data}" "${version}")
by_extension=$(get_by_extension "${by_kernel}" "${ext}")
filtered=$(get_by_arch "${by_extension}" "${arch}")

# 3.
echo "==> Running initial checksum check for all artifacts"
checksums=$(checksum_format "${filtered}" "${raw_data}")
if run_checksum512 "${checksums}" "${output_dir}"; then
cd "${output_dir}"
for f in ${output_dir}/*.tar.gz; do tar --no-same-permissions --overwrite -ozxvf "${f}"; done
sleep infinity & PID=$!
trap "kill $PID" INT TERM
wait $PID
echo "==> Extracting existing artifacts"
for f in $(ls *.tar.gz | grep -vE "^dtbs"); do echo "==> Extracting ${f}"; tar --no-same-permissions --overwrite -ozxvf "${f}"; done
return 0
fi

echo "Checksums do not match. Exiting..."
return 1

# 5.
echo "==> Downloading artifacts"
download_artifacts "${url}" "${filtered}" "${output_dir}"
checksums=$(checksum_format "${filtered}" "${raw_data}")
echo "==> Running checksum check for all downloaded artifacts"
if ! run_checksum512 "${checksums}" "${output_dir}"; then
echo "==> Checksum failed for some artifacts"
return 1
fi
cd "${output_dir}"
echo "==> Extracting artifacts"
for f in $(ls *.tar.gz | grep -vE "^dtbs"); do echo "==> Extracting ${f}"; tar --no-same-permissions --overwrite -ozxvf "${f}"; done
}

main "{{ .Values.stack.hook.downloadURL }}" "/output"

if ! main; then
exit 1
fi

echo "==> All artifacts available, waiting for signals..."
sleep infinity & PID=$!
trap "kill $PID" INT TERM
wait $PID

{{- end }}
2 changes: 1 addition & 1 deletion tinkerbell/stack/templates/nginx-configmap.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{{ if .Values.stack.enabled -}}
# The NGINX ConfigMap is in a separate file because its checksum is used to trigger updates in
# the deployment.
{{ if .Values.stack.enabled -}}
apiVersion: v1
kind: ConfigMap
metadata:
Expand Down
1 change: 1 addition & 0 deletions tinkerbell/stack/templates/nginx.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ spec:
- name: download-hook
image: {{ .Values.stack.hook.image }}
command: ["/script/entrypoint.sh"]
args: ["--url", "{{ .Values.stack.hook.downloadURL }}", "--output-dir", "/output", "--arch", "{{ .Values.stack.hook.arch }}", "--version", "{{ .Values.stack.hook.kernelVersion }}", "--ext", "{{ .Values.stack.hook.extension }}"]
volumeMounts:
- mountPath: /output
name: hook-artifacts
Expand Down
2 changes: 1 addition & 1 deletion tinkerbell/stack/templates/nginx_pvc.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{- if and .Values.stack.hook.enabled (empty .Values.stack.hook.persistence.existingClaim ) }}
{{- if and .Values.stack.enabled .Values.stack.hook.enabled (empty .Values.stack.hook.persistence.existingClaim ) }}
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
Expand Down
9 changes: 6 additions & 3 deletions tinkerbell/stack/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ stack:
enabled: true
name: hook-files
port: 8080
image: bash
image: bash:5.2.37
# downloadURL only works with the > 0.8.1 Hook release because
# previous Hook versions didn't provide a checksum file.
downloadURL: https://github.com/tinkerbell/hook/releases/download/v0.9.1
downloadURL: https://github.com/tinkerbell/hook/releases/download/v0.9.2
arch: both # x86_64, aarch64, both
extension: tar.gz # iso, tar.gz, both
kernelVersion: both # 5.10, 6.6, both
persistence:
# If existingClaim is set, the local persistence volume (localPersistentVolume) objects will NOT be created.
# Use this to point to an existing production grade storage class.
Expand All @@ -39,7 +42,7 @@ stack:
name: hook-artifacts
accessModes:
- ReadWriteMany
size: 1Gi
size: 2Gi
extraLabels: {}

kubevip:
Expand Down
Loading