blob: 2394801c8609e5d9be66de47db6d6dbf9399ec28 [file]
#!/bin/bash
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# Install the prerequisites required to run the operator tests.
#
# Supported platforms: macOS (Homebrew) and Ubuntu Linux / WSL2 with Ubuntu (apt).
#
# Usage:
# ./setup.sh install what is missing
# ./setup.sh --check only report what is missing, install nothing
#
set -euo pipefail
# versions - keep aligned with the Dockerfile and .github/workflows
KUSTOMIZE_VERSION="v4.5.7" # Dockerfile
KIND_VERSION="v0.22.0" # .github/workflows/check.yml
KUBECTL_VERSION="v1.23.0" # Dockerfile
POETRY_VERSION="2.3.2" # Dockerfile ARG POETRY_VERSION
PYTHON_VERSION="3.12" # Dockerfile / pyproject.toml
TASK_VERSION="3.0.0" # minimum - Taskfile.yml uses schema version 3
CHECK_ONLY="false"
if [ "${1:-}" = "--check" ]; then CHECK_ONLY="true"; fi
MISSING=0
INSTALLED=0
say() { echo "==> $*"; }
ok() { echo " OK $*"; }
miss() { echo " MISSING $*"; }
#-----------------------------------------------------------------------------
# platform detection
#-----------------------------------------------------------------------------
detect_platform() {
case "$(uname -s)" in
Darwin) echo "mac" ;;
Linux)
if [ -f /etc/os-release ] && grep -qi '^ID=ubuntu' /etc/os-release; then
echo "ubuntu"
else
echo "unsupported-linux"
fi
;;
*) echo "unsupported" ;;
esac
}
PLATFORM="$(detect_platform)"
case "$PLATFORM" in
mac)
say "Detected macOS"
if ! command -v brew >/dev/null 2>&1; then
echo
echo "ERROR: Homebrew is required on macOS but was not found."
echo "Install it from https://brew.sh then run this script again:"
echo ' /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"'
exit 1
fi
;;
ubuntu)
say "Detected Ubuntu Linux"
;;
unsupported-linux)
echo
echo "ERROR: this Linux distribution is not supported."
echo "The tests are supported on Ubuntu. Please use Ubuntu, or a container/VM running Ubuntu."
exit 1
;;
*)
echo
echo "ERROR: unsupported operating system: $(uname -s)"
echo
echo "Running the tests requires one of:"
echo " - macOS (with Homebrew)"
echo " - Ubuntu Linux (with apt)"
echo " - Windows via WSL2 with an Ubuntu distribution"
echo
echo "On Windows, install WSL2 with Ubuntu and run this script inside it:"
echo " wsl --install -d Ubuntu"
exit 1
;;
esac
# WSL is Ubuntu underneath - just let the user know where they are
if [ "$PLATFORM" = "ubuntu" ] && grep -qi microsoft /proc/version 2>/dev/null; then
say "Running under WSL - make sure Docker Desktop has WSL integration enabled"
fi
ARCH_RAW="$(uname -m)"
case "$ARCH_RAW" in
x86_64|amd64) ARCH="amd64" ;;
arm64|aarch64) ARCH="arm64" ;;
*) echo "ERROR: unsupported architecture: $ARCH_RAW"; exit 1 ;;
esac
if [ "$PLATFORM" = "mac" ]; then OS="darwin"; else OS="linux"; fi
mkdir -p "$HOME/.local/bin"
#-----------------------------------------------------------------------------
# helpers
#-----------------------------------------------------------------------------
# need <command> <description> ; returns 0 if it must be installed
need() {
if command -v "$1" >/dev/null 2>&1; then
ok "$2 ($(command -v "$1"))"
return 1
fi
miss "$2"
MISSING=$((MISSING + 1))
[ "$CHECK_ONLY" = "true" ] && return 1
return 0
}
# like need, but stays quiet when present so the caller can report the version
need_quiet() {
command -v "$1" >/dev/null 2>&1 && return 1
miss "$2"
MISSING=$((MISSING + 1))
[ "$CHECK_ONLY" = "true" ] && return 1
return 0
}
installed() { INSTALLED=$((INSTALLED + 1)); echo " ...installed $1"; }
WARNINGS=0
warn() { WARNINGS=$((WARNINGS + 1)); echo " WARN $*"; }
# strip a leading v and keep only the leading numeric dotted version
normver() { echo "$1" | sed 's/^v//' | grep -oE '^[0-9]+(\.[0-9]+)*' || echo "0"; }
# vercmp A B -> prints "lt", "eq" or "gt" for A relative to B
vercmp() {
local a b first
a="$(normver "$1")"; b="$(normver "$2")"
[ "$a" = "$b" ] && { echo "eq"; return; }
first="$(printf '%s\n%s\n' "$a" "$b" | sort -V | head -1)"
if [ "$first" = "$a" ]; then echo "lt"; else echo "gt"; fi
}
# check_version <name> <found-version> <expected-version> [min]
# accepts a newer version but warns; refuses an older one.
# pass "min" as the 4th argument when the expected version is only a minimum,
# in which case anything newer is fine and no warning is emitted.
check_version() {
local name="$1" found="$2" want="$3" kind="${4:-pinned}"
if [ -z "$found" ]; then
warn "$name: could not determine the version (expected $want)"
return
fi
case "$(vercmp "$found" "$want")" in
eq) ok "$name $found" ;;
gt) ok "$name $found"
if [ "$kind" != "min" ]; then
warn "$name $found is newer than the expected $want - it should work, but the CI and the Dockerfile use $want"
fi ;;
lt) if [ "$kind" = "min" ]
then warn "$name $found is older than the minimum required $want - please upgrade it"
else warn "$name $found is OLDER than the required $want - please upgrade it"
fi
MISSING=$((MISSING + 1)) ;;
esac
}
apt_install() {
sudo apt-get update -qq
sudo apt-get install -y -qq "$@"
}
#-----------------------------------------------------------------------------
say "Checking prerequisites"
#-----------------------------------------------------------------------------
# --- base tools -------------------------------------------------------------
if need curl "curl"; then
if [ "$PLATFORM" = "mac" ]; then brew install curl; else apt_install curl; fi
installed curl
fi
if need git "git"; then
if [ "$PLATFORM" = "mac" ]; then brew install git; else apt_install git; fi
installed git
fi
# --- task (the build tool: every other step below is run through it) ---------
if need_quiet task "task"; then
if [ "$PLATFORM" = "mac" ]; then
brew install go-task/tap/go-task
else
curl -sL https://taskfile.dev/install.sh | sh -s -- -d -b "$HOME/.local/bin"
fi
installed task
hash -r 2>/dev/null || true
if ! command -v task >/dev/null 2>&1; then
warn "task was installed in $HOME/.local/bin but is not on your PATH yet"
fi
else
check_version "task" "$(task --version 2>/dev/null | grep -oE 'v?[0-9]+(\.[0-9]+)+' | head -1)" "$TASK_VERSION" min
fi
# --- docker (not installed automatically: it needs a desktop app / daemon) ---
if command -v docker >/dev/null 2>&1; then
ok "docker ($(command -v docker))"
else
miss "docker"
MISSING=$((MISSING + 1))
if [ "$PLATFORM" = "mac" ]; then
echo " install Docker Desktop: https://docs.docker.com/desktop/install/mac-install/"
else
echo " install with: curl -fsSL https://get.docker.com | sh"
echo " then: sudo usermod -aG docker \$USER (log out and back in)"
fi
fi
# --- python 3.12 ------------------------------------------------------------
if command -v python3 >/dev/null 2>&1 || command -v "python$PYTHON_VERSION" >/dev/null 2>&1; then
PY_BIN="$(command -v "python$PYTHON_VERSION" || command -v python3)"
check_version "python" "$("$PY_BIN" -c 'import sys; print("%d.%d"%sys.version_info[:2])')" "$PYTHON_VERSION"
else
miss "python$PYTHON_VERSION"
MISSING=$((MISSING + 1))
if [ "$CHECK_ONLY" = "false" ]; then
if [ "$PLATFORM" = "mac" ]; then
brew install "python@$PYTHON_VERSION"
else
apt_install software-properties-common
sudo add-apt-repository -y ppa:deadsnakes/ppa
apt_install "python$PYTHON_VERSION" "python$PYTHON_VERSION-venv" "python$PYTHON_VERSION-dev"
fi
installed "python$PYTHON_VERSION"
fi
fi
# --- poetry (the python package manager used by this project) ---------------
if need_quiet poetry "poetry"; then
if [ "$PLATFORM" = "mac" ]; then
brew install poetry
else
curl -sSL https://install.python-poetry.org | "python$PYTHON_VERSION" -
echo " note: ensure \$HOME/.local/bin is in your PATH"
fi
installed poetry
else
command -v poetry >/dev/null 2>&1 && \
check_version "poetry" "$(poetry --version 2>/dev/null | grep -oE '[0-9]+(\.[0-9]+)+' | head -1)" "$POETRY_VERSION"
fi
# --- kubectl ----------------------------------------------------------------
if need_quiet kubectl "kubectl"; then
if [ "$PLATFORM" = "mac" ]; then
brew install kubectl
else
curl -sL "https://dl.k8s.io/release/$KUBECTL_VERSION/bin/$OS/$ARCH/kubectl" \
-o "$HOME/.local/bin/kubectl"
chmod +x "$HOME/.local/bin/kubectl"
fi
installed kubectl
else
check_version "kubectl" "$(kubectl version --client 2>/dev/null | grep -oE 'v?[0-9]+(\.[0-9]+)+' | head -1)" "$KUBECTL_VERSION"
fi
# --- kustomize --------------------------------------------------------------
if need_quiet kustomize "kustomize"; then
if [ "$PLATFORM" = "mac" ]; then
brew install kustomize
else
URL="https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2F$KUSTOMIZE_VERSION/kustomize_${KUSTOMIZE_VERSION}_${OS}_${ARCH}.tar.gz"
curl -sL "$URL" | tar xzf - -C "$HOME/.local/bin"
chmod +x "$HOME/.local/bin/kustomize"
fi
installed kustomize
else
check_version "kustomize" "$(kustomize version 2>/dev/null | grep -oE 'v?[0-9]+(\.[0-9]+)+' | head -1)" "$KUSTOMIZE_VERSION"
fi
# --- kind -------------------------------------------------------------------
if need_quiet kind "kind"; then
if [ "$PLATFORM" = "mac" ]; then
brew install kind
else
curl -sLo "$HOME/.local/bin/kind" \
"https://kind.sigs.k8s.io/dl/$KIND_VERSION/kind-${OS}-${ARCH}"
chmod +x "$HOME/.local/bin/kind"
fi
installed kind
else
check_version "kind" "$(kind version 2>/dev/null | grep -oE 'v?[0-9]+(\.[0-9]+)+' | head -1)" "$KIND_VERSION"
fi
#-----------------------------------------------------------------------------
# summary
#-----------------------------------------------------------------------------
echo
if [ "$CHECK_ONLY" = "true" ]; then
if [ "$MISSING" -eq 0 ]; then
if [ "$WARNINGS" -gt 0 ]
then say "All prerequisites are installed ($WARNINGS version warning(s))."
else say "All prerequisites are installed."
fi
else
say "$MISSING prerequisite(s) missing - run ./setup.sh to install them."
exit 1
fi
exit 0
fi
case ":$PATH:" in
*":$HOME/.local/bin:"*) ;;
*) echo "NOTE: add \$HOME/.local/bin to your PATH:"
echo " echo 'export PATH=\$HOME/.local/bin:\$PATH' >> ~/.bashrc" ;;
esac
if [ "$WARNINGS" -gt 0 ]; then
say "Setup complete ($INSTALLED installed, $WARNINGS warning(s))."
else
say "Setup complete ($INSTALLED installed)."
fi
echo
echo "Next steps:"
echo " task setup install the python dependencies"
echo " task utest run the unit tests"