#!/bin/bash set -euo pipefail shopt -s extglob check_arch() { ARCH=$(uname -m) if [[ "$ARCH" != @("x86_64"|"aarch64") ]]; then echo "Your architecture '$ARCH' is not supported by $SCYLLA_PRODUCT, for supported OS and arch please refer to https://docs.scylladb.com/getting-started/os-support" exit 1 fi } check_os() { OS=$(uname -s) case "$OS" in Linux) ;; *) echo -e "Your operating system $OS is not supported by this installer.\n\nPlease consider using Docker to run Scylla on this machine:\n\nhttps://hub.docker.com/r/scylladb/scylla" && exit 1 ;; esac } echo_msg() { if [ $DRY_RUN -eq 0 ]; then echo $* fi } run_cmd() { CMD=("$@") if [ $DRY_RUN -eq 0 ]; then eval "${CMD[@]}" else echo "${CMD[@]}" fi } check_product() { case "$SCYLLA_PRODUCT" in "scylla") BRANCH_WORD="branch-" ;; "scylla-enterprise") BRANCH_WORD="enterprise-" ;; *) echo "The product '$SCYLLA_PRODUCT' is not supported by this installer." exit 1 ;; esac } is_supported_version() { if [[ -n "$SCYLLA_VERSION" ]] && [[ $SCYLLA_VERSION != *"nightly"* ]]; then if [[ "$SCYLLA_VERSION" != @(202[5-9].[1-9]*|20[3-9][0-9].*) ]]; then supported_versions_message exit 1 fi fi } supported_versions_message() { echo "The specified scylla-version '$SCYLLA_VERSION' has reached End of Life (EOL) or not available. • For OSS supported ScyllaDB versions please refer to https://docs.scylladb.com/stable/getting-started/os-support • For Enterprise supported ScyllaDB versions please refer to https://enterprise.docs.scylladb.com/stable/getting-started/os-support" } is_rc_version() { if [[ $SCYLLA_VERSION == *.rc* ]]; then # replace the 2nd '.' with '~' for RC versions, ex. x.y.rc0 -> x.y~rc0 SCYLLA_VERSION=$(echo $SCYLLA_VERSION | sed 's/\(.*\)\.)*/\1~/') elif [[ $SCYLLA_VERSION == *-rc* ]]; then # replace '-' with '~' for RC versions, ex. x.y.0-rc1 -> x.y.0~rc1 SCYLLA_VERSION=$(echo $SCYLLA_VERSION | sed 's/-/~/') fi } # Release metadata is read from the public downloads bucket: each release series # has a relocatable/scylladb-/ folder holding a 00-Build--.txt # marker per published build. S3_BUCKET_URL="https://s3.amazonaws.com/downloads.scylladb.com" RELOCATABLE_PREFIX="downloads/scylla/relocatable" # List published release series (e.g. 2026.1), latest first. # Returns curl's exit code if the bucket can't be reached. list_published_series() { local listing listing=$(curl -sf --retry 3 --max-time 10 "$S3_BUCKET_URL?prefix=$RELOCATABLE_PREFIX/scylladb-&delimiter=/" 2>/dev/null) || return echo "$listing" \ | grep -oE "$RELOCATABLE_PREFIX/scylladb-20[0-9]{2}\.[0-9]+/" \ | sed -e "s|.*/scylladb-\(.*\)/|\1|" \ | sort -V -r || true } # Print the latest GA (non-RC) patch version of a series, or nothing if none was released. # Returns curl's exit code if the bucket can't be reached. get_latest_patch_for_series() { local series=$1 local series_re=${series//./\\.} local listing listing=$(curl -sf --retry 3 --max-time 10 "$S3_BUCKET_URL?prefix=$RELOCATABLE_PREFIX/scylladb-$series/00-Build-$series.&delimiter=/" 2>/dev/null) || return echo "$listing" \ | grep -oE "00-Build-$series_re\.[0-9]+-" \ | sed -e "s/^00-Build-//; s/-$//" \ | sort -V | tail -n1 || true } # Set DEFAULT_SCYLLA_VERSION to the latest GA patch of the newest released series, # DEFAULT_SCYLLA_SERIES to that series and PUBLISHED_SERIES to all published series. # Returns curl's exit code if the bucket can't be reached. query_default_version() { DEFAULT_SCYLLA_VERSION="" DEFAULT_SCYLLA_SERIES="" PUBLISHED_SERIES=$(list_published_series) || return for series in $PUBLISHED_SERIES; do DEFAULT_SCYLLA_VERSION=$(get_latest_patch_for_series "$series") || return if [ -n "$DEFAULT_SCYLLA_VERSION" ]; then DEFAULT_SCYLLA_SERIES="$series" break fi done if [ $VERBOSE -eq 1 ]; then echo " Debug: latest released version: ${DEFAULT_SCYLLA_VERSION:-}" >&2 fi } # Check if a series is actively supported (not EOL) is_series_supported() { local series="$1" local current_version="$2" # Parse versions local series_year=$(echo "$series" | cut -d'.' -f1) local series_minor=$(echo "$series" | cut -d'.' -f2) local current_year=$(echo "$current_version" | cut -d'.' -f1) local current_minor=$(echo "$current_version" | cut -d'.' -f2) # LTS series (.1 releases) - ScyllaDB supports 2 LTS releases at a time if [ "$series_minor" = "1" ]; then # Current year LTS is always supported if [ "$series_year" = "$current_year" ]; then return 0 fi # Previous year LTS is supported if current year has an LTS if [ "$series_year" = "$((current_year - 1))" ] && [ "$current_minor" -ge 1 ]; then return 0 fi # No longer supported if it's 2+ years old return 1 fi # Non-LTS series - only current year series are supported if [ "$series_year" = "$current_year" ]; then return 0 fi # Non-LTS from previous years are EOL return 1 } list_active_releases() { echo "ScyllaDB Active Releases (Latest to Oldest):" echo "=============================================" # Check if curl is available if ! command -v curl &> /dev/null; then echo "Error: curl is not installed or not available in PATH" echo "Please install curl to use this feature" exit 1 fi local curl_exit_code=0 query_default_version || curl_exit_code=$? current_version="$DEFAULT_SCYLLA_VERSION" current_series="$DEFAULT_SCYLLA_SERIES" if [ $curl_exit_code -ne 0 ]; then echo " Network error: Failed to fetch release information from $S3_BUCKET_URL (curl exit code: $curl_exit_code)" echo " Please check your internet connection and try again" exit 1 elif [ -z "$current_version" ]; then echo " No GA release found at $S3_BUCKET_URL" echo " Please try again later or check if the bucket layout has changed" exit 1 fi # Display each active series with latest patch version for series in $PUBLISHED_SERIES; do if ! is_series_supported "$series" "$current_version"; then if [ $VERBOSE -eq 1 ]; then echo " Debug: $series is EOL" >&2 fi continue fi # The latest series was already looked up by query_default_version if [ "$series" = "$current_series" ]; then latest_patch="$current_version" elif ! latest_patch=$(get_latest_patch_for_series "$series"); then echo " Network error: Failed to fetch release information for $series from $S3_BUCKET_URL" echo " Please check your internet connection and try again" exit 1 fi # Skip series with no GA release yet (e.g. only RC builds) if [ -z "$latest_patch" ]; then if [ $VERBOSE -eq 1 ]; then echo " Debug: $series has no GA release yet" >&2 fi continue fi # Determine if this is LTS series_minor=$(echo "$series" | cut -d'.' -f2) if [ "$series_minor" = "1" ]; then lts_marker=" [LTS]" else lts_marker="" fi # Check if this is the current latest series if [ "$series" = "$current_series" ]; then support_status=" - latest" else support_status="" fi echo " $series: $latest_patch$lts_marker$support_status" done } packages_update() { if [[ "$NAME" == @(Ubuntu|Debian)* ]]; then run_cmd apt update run_cmd apt-get install $APT_FLAGS curl gnupg2 elif [[ "$NAME" == @(Amazon|Red Hat)* ]]; then run_cmd yum install $YUM_QUIET_CMD_PARAM hostname iputils fi } setup_install() { SCYLLA_GPG_KEY="d0a112e067426ab2 491c93b9de7496a7 a43e06657bac99e3 c503c686b007f39e" if [[ -n "$SCYLLA_REPO_FILE_URL" ]]; then SCYLLA_URL=${SCYLLA_REPO_FILE_URL} SCYLLA_PRODUCT_VERSION="${SCYLLA_PRODUCT}" else if [[ $SCYLLA_VERSION == *"nightly"* ]]; then SCYLLA_RELEASE=$(echo $SCYLLA_VERSION | cut -d'-' -f 2) if [ $SCYLLA_RELEASE == "master" ] || [ $SCYLLA_RELEASE == "enterprise" ]; then BRANCH_WORD="" fi if [ $1 == "debian" ]; then SCYLLA_URL="https://downloads.scylladb.com/unstable/$SCYLLA_PRODUCT/$BRANCH_WORD$SCYLLA_RELEASE/deb/unified/latest/scylladb-$SCYLLA_RELEASE/scylla.list" SCYLLA_PRODUCT_VERSION=$SCYLLA_PRODUCT elif [ $1 == "ubuntu" ]; then SCYLLA_URL="https://downloads.scylladb.com/unstable/$SCYLLA_PRODUCT/$BRANCH_WORD$SCYLLA_RELEASE/deb/unified/latest/scylladb-$SCYLLA_RELEASE/scylla.list" SCYLLA_PRODUCT_VERSION=$SCYLLA_PRODUCT else set_rpm_install_tool SCYLLA_URL="https://downloads.scylladb.com/unstable/$SCYLLA_PRODUCT/$BRANCH_WORD$SCYLLA_RELEASE/rpm/centos/latest/scylla.repo" SCYLLA_PRODUCT_VERSION=$SCYLLA_PRODUCT fi else SCYLLA_RELEASE=$(echo $SCYLLA_VERSION | sed -e "s/\([[:digit:]]\+.[[:digit:]]\+\).*/\1/g") if [ $1 == "debian" ]; then is_rc_version SCYLLA_URL="https://downloads.scylladb.com/deb/debian/scylla-$SCYLLA_RELEASE.list" SCYLLA_PRODUCT_VERSION="${SCYLLA_PRODUCT}=$SCYLLA_VERSION*" elif [ $1 == "ubuntu" ]; then is_rc_version SCYLLA_URL="https://downloads.scylladb.com/deb/ubuntu/scylla-$SCYLLA_RELEASE.list" SCYLLA_PRODUCT_VERSION="${SCYLLA_PRODUCT}=$SCYLLA_VERSION*" else set_rpm_install_tool SCYLLA_URL="https://downloads.scylladb.com/rpm/centos/scylla-$SCYLLA_RELEASE.repo" SCYLLA_PRODUCT_VERSION="$SCYLLA_PRODUCT-$SCYLLA_VERSION" fi fi fi } get_full_version() { PATCH_VERSION=$(echo $SCYLLA_VERSION | awk -v FS='.' '{print $3}') if [ -n "$PATCH_VERSION" ] && [ -z "$DEFAULT_SCYLLA_VERSION" ] || [[ $SCYLLA_VERSION == *rc* ]]; then FULL_SCYLLA_VERSION=$(apt-cache madison ${SCYLLA_PRODUCT} | grep -F -w $SCYLLA_VERSION | cut -d'|' -f 2 | sed 's/[[:space:]]//g' | head -n1) PACKAGES_LIST=',-server,-cqlsh,-kernel-conf,-conf,-python3' [[ "$SCYLLA_VERSION" == 2026.[12]* || "$SCYLLA_VERSION" == 2025.4* ]] && PACKAGES_LIST+=",-node-exporter" [[ "$SCYLLA_VERSION" == 2025.1* ]] && PACKAGES_LIST+=",-node-exporter,-tools,-tools-core" SCYLLA_PRODUCT_VERSION="${SCYLLA_PRODUCT}{$PACKAGES_LIST}=$FULL_SCYLLA_VERSION" elif [[ $SCYLLA_VERSION == *"nightly"* ]] || [[ -n "$SCYLLA_REPO_FILE_URL" ]]; then # For debug repos, install sub-packages directly excluding node-exporter # which is not included in debug repo builds if [[ "$SCYLLA_REPO_FILE_URL" == *"debug"* ]]; then SCYLLA_PRODUCT_VERSION="${SCYLLA_PRODUCT}-server ${SCYLLA_PRODUCT}-cqlsh ${SCYLLA_PRODUCT}-kernel-conf ${SCYLLA_PRODUCT}-conf ${SCYLLA_PRODUCT}-python3" fi fi } main() { DRY_RUN=0 SCYLLA_REPO_FILE_URL="" DEBUG_RUN=0 VERBOSE=0 USAGE=0 USE_TARBALL=0 DEFAULT_SCYLLA_PRODUCT="scylla" SCYLLA_PRODUCT="$DEFAULT_SCYLLA_PRODUCT" SCYLLA_VERSION="" DEFAULT_SCYLLA_VERSION="" while [ $# -gt 0 ]; do case "$1" in "-h" | "--help") USAGE=1 shift 1 ;; "--scylla-product") SCYLLA_PRODUCT="$2" shift 2 ;; "--scylla-version") SCYLLA_VERSION="$2" shift 2 ;; "--list-active-releases") list_active_releases exit 0 ;; "--dry-run") DRY_RUN=1 shift 1 ;; "--debug-run") DEBUG_RUN=1 shift 1 ;; "--scylla-repo-file-url") SCYLLA_REPO_FILE_URL="$2" shift 2 ;; "--verbose") VERBOSE=1 shift 1 ;; "--tarball") USE_TARBALL=1 shift 1 ;; *) USAGE=1 shift 1 ;; esac done if [ $USAGE -eq 1 ]; then usage exit 1 fi RETRY_OPTION="-o Acquire::Retries=3" if [ $VERBOSE -eq 1 ]; then YUM_QUIET_CMD_PARAM="--assumeyes" APT_FLAGS="--assume-yes $RETRY_OPTION" else YUM_QUIET_CMD_PARAM="--assumeyes --quiet" APT_FLAGS="-qq $RETRY_OPTION" fi check_product check_os is_supported_version # os-release may be missing in container environment by default. if [ -f "/etc/os-release" ]; then . /etc/os-release elif [ -f "/etc/arch-release" ]; then export ID=arch else echo "/etc/os-release missing." exit 1 fi packages_update if [ -z "$SCYLLA_VERSION" ] && [ -z "$SCYLLA_REPO_FILE_URL" ]; then if ! query_default_version || [ -z "$DEFAULT_SCYLLA_VERSION" ]; then echo "Unable to determine the latest ScyllaDB version from $S3_BUCKET_URL, please specify one with --scylla-version" exit 1 fi SCYLLA_VERSION="$DEFAULT_SCYLLA_VERSION" fi check_arch if [ $USE_TARBALL -eq 1 ]; then tarball_install else setup_install $ID case "$ID" in "amzn") amzn_install ;; "centos"|"rocky") centos_install ;; "debian"|"ubuntu") deb_install ;; "fedora") fedora_install ;; "almalinux") centos_install ;; "ol") ol_install ;; "rhel") rhel_install ;; *) echo "Operating system '$ID' is not supported by the package installer. Falling back to tarball installation..." tarball_install ;; esac fi echo_msg "Scylla installation done!" } usage() { cat 1>&2 <] - Scylla version to install (default: $DEFAULT_SCYLLA_VERSION) Version examples: --scylla-version nightly-master will install master latest nightly version --scylla-version nightly-5.4 will install 5.4 latest nightly version For enterprise product: --scylla-version nightly-enterprise will install enterprise latest nightly version --scylla-version nightly-202x.1 will install 202x.1 latest nightly version DEBUG OPTIONS: [--scylla-repo-file-url ] URL to test installation from a custom URL. DEBUG FLAGS: [--debug-run] - use slim/minimal dockers when needed. [--dry-run] - Prints out commands instead of executing them. [--verbose] - Runs install commands with no quiet option, and more info. EOF } require_cmd() { CMD=$1 if ! command -v "$CMD" &> /dev/null then echo "Please make sure '$CMD' is installed on this machine." exit fi } set_rpm_install_tool() { RPM_INSTALL_TOOL="yum" if [ $DEBUG_RUN -eq 1 ]; then RPM_INSTALL_TOOL="microdnf" fi require_cmd $RPM_INSTALL_TOOL } install_rpm() { ret=0 run_cmd curl -f -s -L -o /etc/yum.repos.d/scylla.repo "$SCYLLA_URL" || ret=$? if [ $ret -ne 0 ]; then supported_versions_message exit 1 fi run_cmd $RPM_INSTALL_TOOL install $YUM_QUIET_CMD_PARAM $SCYLLA_PRODUCT_VERSION } check_amzn_version() { case "$VERSION_ID" in 2*) return 1 ;; *) return 0 ;; esac } amzn_install() { if check_amzn_version = 0; then echo "Amazon Linux $VERSION_ID is not supported by this installer." exit 1 fi echo_msg "Installing Scylla version $SCYLLA_VERSION for Amazon Linux ..." set_rpm_install_tool install_rpm } check_centos_version() { case "$VERSION_ID" in 8*|9*|10*) return 1 ;; *) return 0 ;; esac } centos_install() { if check_centos_version = 0; then echo "CentOS $VERSION_ID is not supported by this installer." exit 1 fi set_rpm_install_tool echo_msg "Installing Scylla version $SCYLLA_VERSION for CentOS ..." install_rpm } fedora_install() { echo_msg "Installing Scylla version $SCYLLA_VERSION for Fedora ..." set_rpm_install_tool install_rpm } check_rhel_version() { case "$VERSION_ID" in 7.?|8*|9*|10*) return 1 ;; *) return 0 ;; esac } rhel_install() { if check_rhel_version = 0; then echo "Red Hat Enterprise Linux $VERSION_ID is not supported by this installer." exit 1 fi echo_msg "Installing Scylla version $SCYLLA_VERSION for Red Hat Enterprise Linux ..." set_rpm_install_tool install_rpm } check_ol_version() { case "$VERSION_ID" in 7.?|8*) return 1 ;; *) return 0 ;; esac } ol_install() { if check_ol_version = 0; then echo "Oracle Linux $VERSION_ID is not supported by this installer." exit 1 fi echo_msg "Installing Scylla version $SCYLLA_VERSION for Oracle Linux ..." set_rpm_install_tool install_rpm } check_debian_ubuntu_version() { if [[ "$ID" == "debian" ]]; then case "$VERSION_ID" in "9"|"10"|"11"|"12"|"13") return 0 ;; *) echo "$ID $VERSION_ID is not supported by this installer." exit 1 ;; esac elif [[ "$ID" == "ubuntu" ]]; then case "$VERSION_ID" in "20.04"|"22.04"|"24.04"|"26.04") return 0 ;; *) echo "$ID $VERSION_ID is not supported by this installer." exit 1 ;; esac fi } deb_install() { if check_debian_ubuntu_version; then export DEBIAN_FRONTEND=noninteractive APT_KEYS_DIR='/etc/apt/keyrings' ret=0 run_cmd curl -f -s -L -o /etc/apt/sources.list.d/scylla.list "$SCYLLA_URL" || ret=$? if [ $ret -ne 0 ]; then supported_versions_message exit 1 fi echo_msg "Installing Scylla version $SCYLLA_VERSION for $NAME ..." run_cmd mkdir -p $APT_KEYS_DIR run_cmd gpg --homedir /tmp --no-default-keyring --keyring /tmp/temp.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys $SCYLLA_GPG_KEY run_cmd gpg --homedir /tmp --no-default-keyring --keyring /tmp/temp.gpg --export --armor $SCYLLA_GPG_KEY | gpg --dearmor > $APT_KEYS_DIR/scylladb.gpg run_cmd apt update $APT_FLAGS get_full_version run_cmd apt-get install $APT_FLAGS $SCYLLA_PRODUCT_VERSION fi } tarball_install() { SCYLLA_RELEASE=$(echo $SCYLLA_VERSION | sed -e "s/\([[:digit:]]\+\.[[:digit:]]\+\).*/\1/g") # Determine architecture suffix if [ "$ARCH" = "aarch64" ]; then ARCH_SUFFIX="aarch64" else ARCH_SUFFIX="x86_64" fi # Discover the full build identifier from the S3 bucket listing S3_PREFIX="downloads/scylla/relocatable/scylladb-${SCYLLA_RELEASE}" BUILD_FILE=$(curl -s --retry 3 --max-time 5 "https://s3.amazonaws.com/downloads.scylladb.com?prefix=${S3_PREFIX}/00-Build-${SCYLLA_VERSION}-&delimiter=/" \ | grep -o "[^<]*" | grep -v '~rc' | head -1 | sed 's///;s/<\/Key>//') if [ -z "$BUILD_FILE" ]; then echo "Failed to find build info for version $SCYLLA_VERSION" exit 1 fi # Extract build suffix: 00-Build--.txt -> (without .txt) BUILD_SUFFIX=$(echo "$BUILD_FILE" | sed "s|.*00-Build-${SCYLLA_VERSION}-||;s|\.txt$||") TARBALL_URL="https://downloads.scylladb.com/${S3_PREFIX}/scylla-unified-${SCYLLA_VERSION}-${BUILD_SUFFIX}.${ARCH_SUFFIX}.tar.gz" echo_msg "Installing Scylla version $SCYLLA_VERSION via tarball (unified installer)..." echo_msg "Downloading from: $TARBALL_URL" INSTALL_DIR=$(mktemp -d) ret=0 curl -f -s -L "$TARBALL_URL" -o "$INSTALL_DIR/scylla-unified.tar.gz" || ret=$? if [ $ret -ne 0 ]; then echo "Failed to download Scylla tarball. Please check the version and try again." echo "URL attempted: $TARBALL_URL" rm -rf "$INSTALL_DIR" exit 1 fi tar xzf "$INSTALL_DIR/scylla-unified.tar.gz" -C "$INSTALL_DIR" # Find and run install.sh from the extracted tarball INSTALL_SCRIPT=$(find "$INSTALL_DIR" -maxdepth 2 -name "install.sh" -type f | head -1) if [ -z "$INSTALL_SCRIPT" ]; then echo "Could not find install.sh in extracted tarball." rm -rf "$INSTALL_DIR" exit 1 fi echo_msg "Running unified installer..." if [ "$(id -u)" -ne 0 ]; then run_cmd "$INSTALL_SCRIPT --nonroot" else run_cmd "$INSTALL_SCRIPT" fi rm -rf "$INSTALL_DIR" echo_msg "Run 'scylla_setup' to configure ScyllaDB before starting." } main "$@"