From 70bc40403a9360b37870760d99346d855ac1d1c2 Mon Sep 17 00:00:00 2001 From: Qi Zhang Date: Tue, 10 Sep 2024 13:48:31 +0800 Subject: [PATCH] feat: custom cluster install script Signed-off-by: Qi Zhang --- script/install-cluster.sh | 842 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 842 insertions(+) create mode 100644 script/install-cluster.sh diff --git a/script/install-cluster.sh b/script/install-cluster.sh new file mode 100644 index 000000000..1f9e84101 --- /dev/null +++ b/script/install-cluster.sh @@ -0,0 +1,842 @@ +#!/bin/sh + +set -e + +if [ "${DEBUG}" = 1 ]; then + set -x +fi + +# Usage: +# curl ... | ENV_VAR=... sh - +# or +# ENV_VAR=... ./install.sh +# + +# Environment variables: +# +# - INSTALL_RKE2_CHANNEL +# Channel to use for fetching rke2 download URL. +# Defaults to 'stable'. +# +# - INSTALL_RKE2_METHOD +# The installation method to use. +# Default is on RPM-based systems is "rpm", all else "tar". +# +# - INSTALL_RKE2_TYPE +# Type of rke2 service. Can be either "server" or "agent". +# Default is "server". +# +# - INSTALL_RKE2_EXEC +# This is an alias for INSTALL_RKE2_TYPE, included for compatibility with K3s. +# If both are set, INSTALL_RKE2_TYPE is preferred. +# +# - INSTALL_RKE2_VERSION +# Version of rke2 to download from github. +# +# - INSTALL_RKE2_RPM_RELEASE_VERSION +# Version of the rke2 RPM release to install. +# Format would be like "1.el7" or "2.el8" +# +# - INSTALL_RKE2_TAR_PREFIX +# Installation prefix when using the tar installation method. +# Default is /usr/local, unless /usr/local is read-only or has a dedicated mount point, +# in which case /opt/rke2 is used instead. +# +# - INSTALL_RKE2_COMMIT +# Commit of RKE2 to download from temporary cloud storage. +# For developer & QA use only +# +# - INSTALL_RKE2_AGENT_IMAGES_DIR +# Installation path for airgap images when installing from CI commit +# Default is /var/lib/rancher/rke2/agent/images +# +# - INSTALL_RKE2_ARTIFACT_PATH +# If set, the install script will use the local path for sourcing the rke2.linux-$SUFFIX and sha256sum-$ARCH.txt files +# rather than the downloading the files from the internet. +# Default is not set. +# +# - INSTALL_RKE2_SKIP_RELOAD +# If set, the install script will skip reloading systemctl daemon after the tar has been extracted and systemd units +# have been moved. +# Default is not set. +# +# - INSTALL_RKE2_SKIP_FAPOLICY +# If set, the install script will skip adding fapolicy rules +# Default is not set. + + +# info logs the given argument at info log level. +info() { + echo "[INFO] " "$@" +} + +# warn logs the given argument at warn log level. +warn() { + echo "[WARN] " "$@" >&2 +} + +# fatal logs the given argument at fatal log level. +fatal() { + echo "[ERROR] " "$@" >&2 + if [ -n "${SUFFIX}" ]; then + echo "[ALT] Please visit 'https://github.com/rancher/rke2/releases' directly and download the latest rke2.${SUFFIX}.tar.gz" >&2 + fi + exit 1 +} + +# check_target_mountpoint return success if the target directory is on a dedicated mount point +check_target_mountpoint() { + mountpoint -q "${INSTALL_RKE2_TAR_PREFIX}" +} + +# check_target_ro returns success if the target directory is read-only +check_target_ro() { + touch "${INSTALL_RKE2_TAR_PREFIX}"/.rke2-ro-test && rm -rf "${INSTALL_RKE2_TAR_PREFIX}"/.rke2-ro-test + test $? -ne 0 +} + +parse_args() { + NODE_ROLES="" + while [ $# -gt 0 ]; do + case "$1" in + "--controlplane") + info "Role requested: controlplane" + RKE2_DISABLE_ROLE_CONTROLPLANE=false + if [ -z "$NODE_ROLES" ]; then + NODE_ROLES="controlplane" + else + NODE_ROLES="${NODE_ROLES},controlplane" + fi + shift 1 + ;; + "--etcd") + info "Role requested: etcd" + RKE2_DISABLE_ROLE_ETCD=false + if [ -z "$NODE_ROLES" ]; then + NODE_ROLES="etcd" + else + NODE_ROLES="${NODE_ROLES},etcd" + fi + shift 1 + ;; + "--worker") + info "Role requested: worker" + if [ "${RKE2_DISABLE_ROLE_CONTROLPLANE}" != "false" ] && [ "${RKE2_DISABLE_ROLE_ETCD}" != "false" ]; then + INSTALL_RKE2_TYPE=agent + fi + if [ -z "$NODE_ROLES" ]; then + NODE_ROLES="worker" + else + NODE_ROLES="${NODE_ROLES},worker" + fi + shift 1 + ;; + "--external-ip") + RKE2_NODE_EXTERNAL_IP="$2" + shift 2 + ;; + "--internal-ip") + RKE2_NODE_INTERNAL_IP="$2" + shift 2 + ;; + "--token") + RKE2_TOKEN="$2" + shift 2 + ;; + *) + fatal "Unknown argument passed in ($1)" + ;; + esac + done +} + +# setup_env defines needed environment variables. +setup_env() { + RKE2_NODE_IPS=$(ip -4 addr show scope global | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -n 1) + INSTALL_RKE2_MIRROR=cn + INSTALL_RKE2_METHOD=tar + INSTALL_RKE2_VERSION=v1.29.7+rke2r1 + STORAGE_URL="https://rke2-ci-builds.s3.amazonaws.com" + INSTALL_RKE2_GITHUB_URL="https://github.com/rancher/rke2" + if [ "${INSTALL_RKE2_MIRROR}" = cn ]; then + INSTALL_RKE2_GITHUB_URL="https://rancher-mirror.rancher.cn/rke2" + fi + DEFAULT_TAR_PREFIX="/usr/local" + # --- bail if we are not root --- + if [ ! $(id -u) -eq 0 ]; then + fatal "You need to be root to perform this install" + fi + + # --- make sure install channel has a value + if [ -z "${INSTALL_RKE2_CHANNEL}" ]; then + INSTALL_RKE2_CHANNEL="stable" + fi + + # --- make sure install type has a value + if [ -z "${INSTALL_RKE2_TYPE}" ]; then + INSTALL_RKE2_TYPE="${INSTALL_RKE2_EXEC:-server}" + fi + + # --- use rpm install method if available by default + if [ -z "${INSTALL_RKE2_ARTIFACT_PATH}" ] && [ -z "${INSTALL_RKE2_COMMIT}" ] && [ -z "${INSTALL_RKE2_METHOD}" ] && command -v yum >/dev/null 2>&1; then + INSTALL_RKE2_METHOD="rpm" + fi + + # --- install tarball to /usr/local by default, except if /usr/local is on a separate partition or is read-only + # --- in which case we go into /opt/rke2. + if [ -z "${INSTALL_RKE2_TAR_PREFIX}" ]; then + INSTALL_RKE2_TAR_PREFIX=${DEFAULT_TAR_PREFIX} + if check_target_mountpoint || check_target_ro; then + INSTALL_RKE2_TAR_PREFIX="/opt/rke2" + warn "${DEFAULT_TAR_PREFIX} is read-only or a mount point; installing to ${INSTALL_RKE2_TAR_PREFIX}" + fi + fi + + if [ -z "${INSTALL_RKE2_AGENT_IMAGES_DIR}" ]; then + INSTALL_RKE2_AGENT_IMAGES_DIR="/var/lib/rancher/rke2/agent/images" + fi +} + +# register node to the cluster +register_node() { + while true; do + # Re-acquire registration information + REGISTER_NODE_INFO=$(curl -sfSL --connect-timeout 5 "$1/console/install_cluster?node_name=${RKE2_NODE_EXTERNAL_IP:-${RKE2_NODE_INTERNAL_IP:-${RKE2_NODE_IPS}}}&node_ip=${RKE2_NODE_INTERNAL_IP:-${RKE2_NODE_IPS}}&node_role=$NODE_ROLES") + + # Get server_ip and is_server information + SERVER_IP=$(echo "$REGISTER_NODE_INFO" | jq -r '.data.bean.server_ip') + IS_SERVER=$(echo "$REGISTER_NODE_INFO" | jq -r '.data.bean.is_server') + + # If it is server, return directly + if [ "$IS_SERVER" = "true" ]; then + return + fi + + # If server_ip is not empty, set RKE2_SERVER_URL and exit the loop + if [ -n "$SERVER_IP" ]; then + RKE2_SERVER_URL=https://$SERVER_IP:9345 + break + fi + + # server_ip is empty. Wait 5 seconds and try again + sleep 5 + done +} + +# node-label: +# - "kubernetes.io/role=worker" +setup_config() { + if [ ! -d "/etc/rancher/rke2" ]; then + mkdir -p /etc/rancher/rke2 + fi + if [ ! -f "/etc/rancher/rke2/config.yaml" ]; then + cat >/etc/rancher/rke2/config.yaml </dev/null 2>&1; then + fatal "Cannot perform ${INSTALL_RKE2_METHOD:-tar} install on host with existing RKE2 RPMs - please run rke2-uninstall.sh first" + fi + ;; + esac +} + +# setup_arch set arch and suffix, +# fatal if architecture not supported. +setup_arch() { + case ${ARCH:=$(uname -m)} in + x86_64|amd64) + ARCH=amd64 + SUFFIX=$(uname -s | tr '[:upper:]' '[:lower:]')-${ARCH} + ;; + aarch64|arm64) + ARCH=arm64 + SUFFIX=$(uname -s | tr '[:upper:]' '[:lower:]')-${ARCH} + ;; + s390x) + ARCH=s390x + SUFFIX=$(uname -s | tr '[:upper:]' '[:lower:]')-${ARCH} + ;; + *) + fatal "unsupported architecture ${ARCH}" + ;; + esac +} + +# verify_downloader verifies existence of +# network downloader executable. +verify_downloader() { + cmd="$(command -v "${1}")" + if [ -z "${cmd}" ]; then + return 1 + fi + if [ ! -x "${cmd}" ]; then + return 1 + fi + + # Set verified executable as our downloader program and return success + DOWNLOADER=${cmd} + return 0 +} + +# verify_fapolicyd verifies existence of +# fapolicyd and fagenrules executables and make sure that fapolicyd service is running. +verify_fapolicyd() { + cmd="$(command -v "fapolicyd")" + if [ -z "${cmd}" ]; then + return 1 + fi + cmd="$(command -v "fagenrules")" + if [ -z "${cmd}" ]; then + return 1 + fi + systemctl is-active --quiet fapolicyd || return 1 + + return 0 +} + +# setup_tmp creates a temporary directory +# and cleans up when done. +setup_tmp() { + TMP_DIR=$(mktemp -d -t rke2-install.XXXXXXXXXX) + TMP_CHECKSUMS=${TMP_DIR}/rke2.checksums + TMP_TARBALL=${TMP_DIR}/rke2.tarball + TMP_AIRGAP_CHECKSUMS=${TMP_DIR}/rke2-images.checksums + TMP_AIRGAP_TARBALL=${TMP_DIR}/rke2-images.tarball + cleanup() { + code=$? + set +e + trap - EXIT + rm -rf "${TMP_DIR}" + exit $code + } + trap cleanup INT EXIT +} + +# --- use desired rke2 version if defined or find version from channel --- +get_release_version() { + if [ "${INSTALL_RKE2_MIRROR}" = cn ]; then + INSTALL_RKE2_VERSION=$( echo ${INSTALL_RKE2_VERSION} | sed 's/+/-/g' ) + fi + if [ -n "${INSTALL_RKE2_COMMIT}" ]; then + version="commit ${INSTALL_RKE2_COMMIT}" + elif [ -n "${INSTALL_RKE2_VERSION}" ]; then + version=${INSTALL_RKE2_VERSION} + else + info "finding release for channel ${INSTALL_RKE2_CHANNEL}" + INSTALL_RKE2_CHANNEL_URL=${INSTALL_RKE2_CHANNEL_URL:-'https://update.rke2.io/v1-release/channels'} + if [ "${INSTALL_RKE2_MIRROR}" = cn ]; then + INSTALL_RKE2_CHANNEL_URL="https://rancher-mirror.rancher.cn/rke2/channels" + fi + version_url="${INSTALL_RKE2_CHANNEL_URL}/${INSTALL_RKE2_CHANNEL}" + case ${DOWNLOADER} in + *curl) + version=$(${DOWNLOADER} -w "%{url_effective}" -L -s -S "${version_url}" -o /dev/null | sed -e 's|.*/||') + if [ "${INSTALL_RKE2_MIRROR}" = cn ]; then + version=$(${DOWNLOADER} -s -S "${version_url}") + fi + ;; + *wget) + version=$(${DOWNLOADER} -SqO /dev/null "${version_url}" 2>&1 | grep -i Location | sed -e 's|.*/||') + if [ "${INSTALL_RKE2_MIRROR}" = cn ]; then + version=$(${DOWNLOADER} -qO - "${version_url}") + fi + ;; + *) + fatal "Unsupported downloader executable '${DOWNLOADER}'" + ;; + esac + INSTALL_RKE2_VERSION="${version}" + if [ "${INSTALL_RKE2_MIRROR}" = cn ]; then + INSTALL_RKE2_VERSION=$( echo ${INSTALL_RKE2_VERSION} | sed 's/+/-/g') + fi + fi +} + +# check_download performs a HEAD request to see if a file exists at a given url +check_download() { + case ${DOWNLOADER} in + *curl) + curl -o "/dev/null" -fsLI -X HEAD "$1" + ;; + *wget) + wget -q --spider "$1" + ;; + *) + fatal "downloader executable not supported: '${DOWNLOADER}'" + ;; + esac +} + +# download downloads a file from a url using either curl or wget +download() { + if [ $# -ne 2 ]; then + fatal "download needs exactly 2 arguments" + fi + + case ${DOWNLOADER} in + *curl) + curl -o "$1" -fsSL "$2" + ;; + *wget) + wget -qO "$1" "$2" + ;; + *) + fatal "downloader executable not supported: '${DOWNLOADER}'" + ;; + esac + + # Abort if download command failed + if [ $? -ne 0 ]; then + fatal "download failed" + fi +} + +# download_checksums downloads hash from github url. +download_checksums() { + if [ -n "${INSTALL_RKE2_COMMIT}" ]; then + CHECKSUMS_URL=${STORAGE_URL}/rke2.${SUFFIX}-${INSTALL_RKE2_COMMIT}.tar.gz.sha256sum + else + CHECKSUMS_URL=${INSTALL_RKE2_GITHUB_URL}/releases/download/${INSTALL_RKE2_VERSION}/sha256sum-${ARCH}.txt + fi + info "downloading checksums at ${CHECKSUMS_URL}" + download "${TMP_CHECKSUMS}" "${CHECKSUMS_URL}" + CHECKSUM_EXPECTED=$(grep "rke2.${SUFFIX}.tar.gz" "${TMP_CHECKSUMS}" | awk '{print $1}') +} + +# download_tarball downloads binary from github url. +download_tarball() { + if [ -n "${INSTALL_RKE2_COMMIT}" ]; then + TARBALL_URL=${STORAGE_URL}/rke2.${SUFFIX}-${INSTALL_RKE2_COMMIT}.tar.gz + else + TARBALL_URL=${INSTALL_RKE2_GITHUB_URL}/releases/download/${INSTALL_RKE2_VERSION}/rke2.${SUFFIX}.tar.gz + fi + info "downloading tarball at ${TARBALL_URL}" + download "${TMP_TARBALL}" "${TARBALL_URL}" +} + +# download_dev_rpm downloads dev rpm from remote repository +download_dev_rpm() { + if [ -z "${INSTALL_RKE2_COMMIT}" ]; then + fatal 'Development rpm requires a commit hash' + fi + + DEST="${1}" + RPM_FILE=$(basename "${DEST}") + RPM_URL="${STORAGE_URL}/${RPM_FILE}" + + info "downloading rpm at ${RPM_URL}" + download "${DEST}" "${RPM_URL}" +} + +# stage_local_checksums stages the local checksum hash for validation. +stage_local_checksums() { + info "staging local checksums from ${INSTALL_RKE2_ARTIFACT_PATH}/sha256sum-${ARCH}.txt" + cp -f "${INSTALL_RKE2_ARTIFACT_PATH}/sha256sum-${ARCH}.txt" "${TMP_CHECKSUMS}" + CHECKSUM_EXPECTED=$(grep "rke2.${SUFFIX}.tar.gz" "${TMP_CHECKSUMS}" | awk '{print $1}') + if [ -f "${INSTALL_RKE2_ARTIFACT_PATH}/rke2-images.${SUFFIX}.tar.zst" ]; then + AIRGAP_CHECKSUM_EXPECTED=$(grep "rke2-images.${SUFFIX}.tar.zst" "${TMP_CHECKSUMS}" | awk '{print $1}') + elif [ -f "${INSTALL_RKE2_ARTIFACT_PATH}/rke2-images.${SUFFIX}.tar.gz" ]; then + AIRGAP_CHECKSUM_EXPECTED=$(grep "rke2-images.${SUFFIX}.tar.gz" "${TMP_CHECKSUMS}" | awk '{print $1}') + fi +} + +# stage_local_tarball stages the local tarball. +stage_local_tarball() { + info "staging tarball from ${INSTALL_RKE2_ARTIFACT_PATH}/rke2.${SUFFIX}.tar.gz" + cp -f "${INSTALL_RKE2_ARTIFACT_PATH}/rke2.${SUFFIX}.tar.gz" "${TMP_TARBALL}" +} + +# stage_local_airgap_tarball stages the local checksum hash for validation. +stage_local_airgap_tarball() { + if [ -f "${INSTALL_RKE2_ARTIFACT_PATH}/rke2-images.${SUFFIX}.tar.zst" ]; then + info "staging zst airgap image tarball from ${INSTALL_RKE2_ARTIFACT_PATH}/rke2-images.${SUFFIX}.tar.zst" + cp -f "${INSTALL_RKE2_ARTIFACT_PATH}/rke2-images.${SUFFIX}.tar.zst" "${TMP_AIRGAP_TARBALL}" + AIRGAP_TARBALL_FORMAT=zst + elif [ -f "${INSTALL_RKE2_ARTIFACT_PATH}/rke2-images.${SUFFIX}.tar.gz" ]; then + info "staging gzip airgap image tarball from ${INSTALL_RKE2_ARTIFACT_PATH}/rke2-images.${SUFFIX}.tar.gz" + cp -f "${INSTALL_RKE2_ARTIFACT_PATH}/rke2-images.${SUFFIX}.tar.gz" "${TMP_AIRGAP_TARBALL}" + AIRGAP_TARBALL_FORMAT=gz + fi +} + +# verify_tarball verifies the downloaded installer checksum. +verify_tarball() { + info "verifying tarball" + CHECKSUM_ACTUAL=$(sha256sum "${TMP_TARBALL}" | awk '{print $1}') + if [ "${CHECKSUM_EXPECTED}" != "${CHECKSUM_ACTUAL}" ]; then + fatal "download sha256 does not match ${CHECKSUM_EXPECTED}, got ${CHECKSUM_ACTUAL}" + fi +} + +# unpack_tarball extracts the tarball, correcting paths and moving systemd units as necessary +unpack_tarball() { + info "unpacking tarball file to ${INSTALL_RKE2_TAR_PREFIX}" + mkdir -p ${INSTALL_RKE2_TAR_PREFIX} + tar xzf "${TMP_TARBALL}" -C "${INSTALL_RKE2_TAR_PREFIX}" + if [ "${INSTALL_RKE2_TAR_PREFIX}" != "${DEFAULT_TAR_PREFIX}" ]; then + info "updating tarball contents to reflect install path" + sed -i "s|${DEFAULT_TAR_PREFIX}|${INSTALL_RKE2_TAR_PREFIX}|" ${INSTALL_RKE2_TAR_PREFIX}/lib/systemd/system/rke2-*.service ${INSTALL_RKE2_TAR_PREFIX}/bin/rke2-uninstall.sh + info "moving systemd units to /etc/systemd/system" + mv -f ${INSTALL_RKE2_TAR_PREFIX}/lib/systemd/system/rke2-*.service /etc/systemd/system/ + info "install complete; you may want to run: export PATH=\$PATH:${INSTALL_RKE2_TAR_PREFIX}/bin" + fi +} + +# download_airgap_checksums downloads the checksum file for the airgap image tarball +# and prepares the checksum value for later validation. +download_airgap_checksums() { + if [ -z "${INSTALL_RKE2_COMMIT}" ]; then + return + fi + AIRGAP_CHECKSUMS_URL=${STORAGE_URL}/rke2-images.${SUFFIX}-${INSTALL_RKE2_COMMIT}.tar.zst.sha256sum + # try for zst first; if that fails use gz for older release branches + if ! check_download "${AIRGAP_CHECKSUMS_URL}"; then + AIRGAP_CHECKSUMS_URL=${STORAGE_URL}/rke2-images.${SUFFIX}-${INSTALL_RKE2_COMMIT}.tar.gz.sha256sum + fi + info "downloading airgap checksums at ${AIRGAP_CHECKSUMS_URL}" + download "${TMP_AIRGAP_CHECKSUMS}" "${AIRGAP_CHECKSUMS_URL}" + AIRGAP_CHECKSUM_EXPECTED=$(grep "rke2-images.${SUFFIX}.tar" "${TMP_AIRGAP_CHECKSUMS}" | awk '{print $1}') +} + +# download_airgap_tarball downloads the airgap image tarball. +download_airgap_tarball() { + if [ -z "${INSTALL_RKE2_COMMIT}" ]; then + return + fi + AIRGAP_TARBALL_URL=${STORAGE_URL}/rke2-images.${SUFFIX}-${INSTALL_RKE2_COMMIT}.tar.zst + # try for zst first; if that fails use gz for older release branches + if ! check_download "${AIRGAP_TARBALL_URL}"; then + AIRGAP_TARBALL_URL=${STORAGE_URL}/rke2-images.${SUFFIX}-${INSTALL_RKE2_COMMIT}.tar.gz + fi + info "downloading airgap tarball at ${AIRGAP_TARBALL_URL}" + download "${TMP_AIRGAP_TARBALL}" "${AIRGAP_TARBALL_URL}" +} + +# verify_airgap_tarball compares the airgap image tarball checksum to the value +# calculated by CI when the file was uploaded. +verify_airgap_tarball() { + if [ -z "${AIRGAP_CHECKSUM_EXPECTED}" ]; then + return + fi + info "verifying airgap tarball" + AIRGAP_CHECKSUM_ACTUAL=$(sha256sum "${TMP_AIRGAP_TARBALL}" | awk '{print $1}') + if [ "${AIRGAP_CHECKSUM_EXPECTED}" != "${AIRGAP_CHECKSUM_ACTUAL}" ]; then + fatal "download sha256 does not match ${AIRGAP_CHECKSUM_EXPECTED}, got ${AIRGAP_CHECKSUM_ACTUAL}" + fi +} + +# install_airgap_tarball moves the airgap image tarball into place. +install_airgap_tarball() { + if [ -z "${AIRGAP_CHECKSUM_EXPECTED}" ]; then + return + fi + mkdir -p "${INSTALL_RKE2_AGENT_IMAGES_DIR}" + # releases that provide zst artifacts can read from the compressed archive; older releases + # that produce only gzip artifacts need to have the tarball decompressed ahead of time + if grep -sqF '.tar.zst' "${TMP_AIRGAP_CHECKSUMS}" || [ "${AIRGAP_TARBALL_FORMAT}" = "zst" ]; then + info "installing airgap tarball to ${INSTALL_RKE2_AGENT_IMAGES_DIR}" + mv -f "${TMP_AIRGAP_TARBALL}" "${INSTALL_RKE2_AGENT_IMAGES_DIR}/rke2-images.${SUFFIX}.tar.zst" + else + info "decompressing airgap tarball to ${INSTALL_RKE2_AGENT_IMAGES_DIR}" + gzip -dc "${TMP_AIRGAP_TARBALL}" > "${INSTALL_RKE2_AGENT_IMAGES_DIR}/rke2-images.${SUFFIX}.tar" + fi + # Search for and install additional rke2 images + for IMAGE in "${INSTALL_RKE2_ARTIFACT_PATH}"/rke2-images-*."${SUFFIX}"*; do + if [ -f "${IMAGE}" ]; then + info "Installing airgap image from ${IMAGE}" + cp "${IMAGE}" "${INSTALL_RKE2_AGENT_IMAGES_DIR}" + fi + done +} + +# install_dev_rpm orchestrates the installation of RKE2 unsigned development rpms +install_dev_rpm() { + rpm_installer="${1:-yum}" + distro="${2:-centos7}" + + [ -z "${TMP_DIR}" ] && setup_tmp + + case "${rpm_installer}" in + *zypper*) + ${rpm_installer} install --allow-unsigned-rpm -y \ + "${STORAGE_URL}/rke2-common-${INSTALL_RKE2_COMMIT}.${distro}.rpm" \ + "${STORAGE_URL}/rke2-${INSTALL_RKE2_TYPE}-${INSTALL_RKE2_COMMIT}.${distro}.rpm" + ;; + *) + download_dev_rpm "${TMP_DIR}/rke2-common-${INSTALL_RKE2_COMMIT}.${distro}.rpm" + download_dev_rpm "${TMP_DIR}/rke2-${INSTALL_RKE2_TYPE}-${INSTALL_RKE2_COMMIT}.${distro}.rpm" + ${rpm_installer} install -y "${TMP_DIR}"/*.rpm + ;; + esac + + if [ -f "${INSTALL_RKE2_ARTIFACT_PATH}/rke2-images.${SUFFIX}.tar.zst" ]; then + return + fi + + download_airgap_checksums + download_airgap_tarball + verify_airgap_tarball + install_airgap_tarball +} + +# do_install_rpm builds a yum repo config from the channel and version to be installed, +# and calls yum to install the required packages. +do_install_rpm() { + . /etc/os-release + if [ -r /etc/redhat-release ] || [ -r /etc/centos-release ] || [ -r /etc/oracle-release ] || [ -r /etc/system-release ] || [ "${ID_LIKE%%[ ]*}" = "suse" ]; then + repodir=/etc/yum.repos.d + if [ -d /etc/zypp/repos.d ]; then + repodir=/etc/zypp/repos.d + fi + if [ "${ID_LIKE%%[ ]*}" = "suse" ]; then + # create the /var/lib/rpm-state in SLE systems to fix the prein selinux macro + if [ "${TRANSACTIONAL_UPDATE=false}" != "true" ] && [ -x /usr/sbin/transactional-update ]; then + transactional_update_run="transactional-update --no-selfupdate -d run" + fi + ${transactional_update_run} mkdir -p /var/lib/rpm-state + # configure infix and rpm_installer + rpm_site_infix=microos + if [ "${VARIANT_ID:-}" = sle-micro ] || [ "${ID:-}" = sle-micro ]; then + rpm_site_infix=slemicro + package_installer=zypper + fi + rpm_installer="zypper --gpg-auto-import-keys" + if [ "${TRANSACTIONAL_UPDATE=false}" != "true" ] && [ -x /usr/sbin/transactional-update ]; then + rpm_installer="transactional-update --no-selfupdate -d run ${rpm_installer}" + fi + else + maj_ver=$(echo "$VERSION_ID" | sed -E -e "s/^([0-9]+)\.?[0-9]*$/\1/") + case ${maj_ver} in + 7|8|9) + : + ;; + 2023) # detect amazon linux 2023 distro + maj_ver="8" + ;; + *) # set default distro to centos 7, for edge cases such as fedora + maj_ver="7" + ;; + esac + rpm_site_infix=centos/${maj_ver} + rpm_installer="yum" + fi + + fi + case "${INSTALL_RKE2_CHANNEL}" in + v*.*) + # We are operating with a version-based channel, so we should parse our version out + rke2_majmin=$(echo "${INSTALL_RKE2_CHANNEL}" | sed -E -e "s/^v([0-9]+\.[0-9]+).*/\1/") + rke2_rpm_channel=$(echo "${INSTALL_RKE2_CHANNEL}" | sed -E -e "s/^v[0-9]+\.[0-9]+-(.*)/\1/") + # If our regex fails to capture a "sane" channel out of the specified channel, fall back to `stable` + if [ "${rke2_rpm_channel}" = ${INSTALL_RKE2_CHANNEL} ]; then + info "using stable RPM repositories" + rke2_rpm_channel="stable" + fi + ;; + *) + get_release_version + rke2_majmin=$(echo "${INSTALL_RKE2_VERSION}" | sed -E -e "s/^v([0-9]+\.[0-9]+).*/\1/") + rke2_rpm_channel=${1} + ;; + esac + info "using ${rke2_majmin} series from channel ${rke2_rpm_channel}" + rpm_site="rpm.rancher.io" + if [ "${rke2_rpm_channel}" = "testing" ]; then + rpm_site="rpm-${rke2_rpm_channel}.rancher.io" + fi + + rm -f ${repodir}/rancher-rke2*.repo + cat <<-EOF >"${repodir}/rancher-rke2.repo" +[rancher-rke2-common-${rke2_rpm_channel}] +name=Rancher RKE2 Common (${1}) +baseurl=https://${rpm_site}/rke2/${rke2_rpm_channel}/common/${rpm_site_infix}/noarch +enabled=1 +gpgcheck=1 +repo_gpgcheck=0 +gpgkey=https://${rpm_site}/public.key +EOF + + if [ -z "${INSTALL_RKE2_COMMIT}" ]; then + cat <<-EOF >>"${repodir}/rancher-rke2.repo" +[rancher-rke2-${rke2_majmin}-${rke2_rpm_channel}] +name=Rancher RKE2 ${rke2_majmin} (${1}) +baseurl=https://${rpm_site}/rke2/${rke2_rpm_channel}/${rke2_majmin}/${rpm_site_infix}/x86_64 +enabled=1 +gpgcheck=1 +repo_gpgcheck=0 +gpgkey=https://${rpm_site}/public.key +EOF + fi + + if rpm -q --quiet rke2-selinux; then + # remove rke2-selinux module in el9 before upgrade to allow container-selinux to upgrade safely + if check_available_upgrades container-selinux && check_available_upgrades rke2-selinux && check_breaking_version container-selinux 2 189; then + MODULE_PRIORITY=$(semodule --list=full | grep rke2 | cut -f1 -d" ") + if [ -n "${MODULE_PRIORITY}" ]; then + semodule -X $MODULE_PRIORITY -r rke2 || true + fi + fi + fi + + if [ -z "${INSTALL_RKE2_VERSION}" ] && [ -z "${INSTALL_RKE2_COMMIT}" ]; then + ${rpm_installer} install -y "rke2-${INSTALL_RKE2_TYPE}" + elif [ -n "${INSTALL_RKE2_COMMIT}" ]; then + rel_distro="$(echo "${rpm_site_infix}" | tr -d /)" + install_dev_rpm "${rpm_installer}" "${rel_distro}" + else + rke2_rpm_version=$(echo "${INSTALL_RKE2_VERSION}" | sed -E -e "s/[\+-]/~/g" | sed -E -e "s/v(.*)/\1/") + if [ -n "${INSTALL_RKE2_RPM_RELEASE_VERSION}" ]; then + ${rpm_installer} install -y "rke2-${INSTALL_RKE2_TYPE}-${rke2_rpm_version}-${INSTALL_RKE2_RPM_RELEASE_VERSION}" + else + ${rpm_installer} install -y "rke2-${INSTALL_RKE2_TYPE}-${rke2_rpm_version}" + fi + fi +} + +check_breaking_version() { + maj=$2 + min=$3 + + current_maj=$(rpm -qi $1 | awk -F': ' '/Version/ {print $2}' | sed -E -e "s/^([0-9]+)\.([0-9]+).*/\1/") + current_min=$(rpm -qi $1 | awk -F': ' '/Version/ {print $2}' | sed -E -e "s/^([0-9]+)\.([0-9]+).*/\2/") + + if [ "${current_maj}" == "${maj}" ] && [ $current_min -le $min ]; then + return 0 + fi + + return 1 +} + +check_available_upgrades() { + . /etc/os-release + set +e + if [ "${ID_LIKE%%[ ]*}" = "suse" ]; then + available_upgrades=$(zypper -q -t -s 11 se -s -u --type package $1 | tail -n 1 | grep -v "No matching" | awk '{print $3}') + else + available_upgrades=$(yum -q --refresh list $1 --upgrades | tail -n 1 | awk '{print $2}') + fi + set -e + if [ -n "${available_upgrades}" ]; then + return 0 + fi + return 1 +} + +do_install_tar() { + setup_tmp + + if [ -n "${INSTALL_RKE2_ARTIFACT_PATH}" ]; then + stage_local_checksums + stage_local_airgap_tarball + stage_local_tarball + else + get_release_version + info "using ${INSTALL_RKE2_VERSION:-commit $INSTALL_RKE2_COMMIT} as release" + download_airgap_checksums + download_airgap_tarball + download_checksums + download_tarball + fi + + verify_airgap_tarball + install_airgap_tarball + verify_tarball + unpack_tarball + + if [ -z "${INSTALL_RKE2_SKIP_RELOAD}" ]; then + systemctl daemon-reload + fi +} + +setup_fapolicy_rules() { + if [ -r /etc/redhat-release ] || [ -r /etc/centos-release ] || [ -r /etc/oracle-release ] || [ -r /etc/rocky-release ] || [ -r /etc/system-release ]; then + verify_fapolicyd || return 0 + # setting rke2 fapolicyd rules + cat <<-EOF >"/etc/fapolicyd/rules.d/80-rke2.rules" +allow perm=any all : dir=/var/lib/rancher/ +allow perm=any all : dir=/opt/cni/ +allow perm=any all : dir=/run/k3s/ +allow perm=any all : dir=/var/lib/kubelet/ +EOF + if [ -z "${INSTALL_RKE2_SKIP_RELOAD}" ]; then + fagenrules --load || fatal "failed to load rke2 fapolicyd rules" + systemctl restart fapolicyd + fi + fi +} + +start_rke2_systemd() { + + if [ "${INSTALL_RKE2_TYPE}" = "agent" ]; then + systemctl enable rke2-agent.service + info "Starting RKE2 agent, Please wait about 10 minutes. You can open new terminal to check the status with 'systemctl status rke2-agent' and logs with 'journalctl -u rke2-agent'" + systemctl start rke2-agent.service + fi + + if [ "${INSTALL_RKE2_TYPE}" = "server" ]; then + systemctl enable rke2-server.service + info "Starting RKE2 server, Please wait about 10 minutes. You can open new terminal to check the status with 'systemctl status rke2-server' and logs with 'journalctl -u rke2-server'" + systemctl start rke2-server.service + if [ "$IS_SERVER" = "true" ]; then + curl -sfSL --connect-timeout 5 "$1/console/cluster --form kubeconfig=/etc/rancher/rke2/rke2.yaml" + fi + + fi +} + +do_install() { + parse_args "$@" + setup_env + check_method_conflict + setup_arch + if [ -z "${INSTALL_RKE2_ARTIFACT_PATH}" ]; then + verify_downloader curl || verify_downloader wget || fatal "can not find curl or wget for downloading files" + fi + verify_downloader jq || fatal "can not find jq tool for parsing json" + register_node "$1" + setup_config + + case ${INSTALL_RKE2_METHOD} in + yum | rpm | dnf) + do_install_rpm "${INSTALL_RKE2_CHANNEL}" + ;; + *) + do_install_tar "${INSTALL_RKE2_CHANNEL}" + ;; + esac + if [ -z "${INSTALL_RKE2_SKIP_FAPOLICY}" ]; then + setup_fapolicy_rules + fi + start_rke2_systemd "$1" +} + +do_install "$@" +exit 0 \ No newline at end of file