#!/usr/bin/env bash # # Mirantis Container Runtime installer # # Script build information: # COMMIT_SHA=cfea8c511a0f69374c432f152b0bac6c406d6cf0 # COMMIT_SHA_PVAL=cfea8c5 # SEMVER_VERSION=1.0.24 # PUBLISH_STRING=stable # ENV VARIABLES: # Essential: # - DOCKER_URL - URL to package repo # - CHANNEL - channel in the package repo # - VERSION - MCR release version # Optional: # - CONTAINERD_VERSION- Containerd package version # Development: # - DRY_RUN - installation will be with dry-run flag # - SKIP_REPO_SETUP - the current configured repos will be only used # DOCKER_URL and CHANNEL will be ignored # set -e MCR_MAIN_VERSION="" DIST_ID="" DOCKER_PACKAGE_NAME="docker-ee" DOCKER_CLI_PACKAGE_NAME="${DOCKER_PACKAGE_NAME}-cli" DOCKER_ROOTLESS_PACKAGE_NAME="${DOCKER_PACKAGE_NAME}-rootless-extras" CONTAINERD_PACKAGE_NAME="containerd.io" CRI_DOCKERD_PACKAGE_NAME="cri-dockerd-ee" RUNC_PACKAGE_NAME="runc-ee" MIN_ROOTLESS_VER="20.10.12" MIN_MCR_WITH_C8D_VER="23.0.1" SH_C='sh -c' # Parse an MCR product version string. # # If the version is well-formed, this function exits with a success status # and the parsed components of the version are placed into $BASH_REMATCH. # # ${BASH_REMATCH[1]} - the MAJOR.MINOR.PATCH # ${BASH_REMATCH[3]} - the tp or rc designator # ${BASH_REMATCH[4]} - the pre-release increment or hotfix number # # Consider the following versions that we might support: # 23.0.12 - A version by itself. Install latest release build. # 23.0.12-0 - A specific build version. We use these, for example, if the # 23.0.12-1 we need to rebuild with a new fipster. # 23.0.13-tp1 - A specific tp version # 23.0.13-tp2 # 23.0.13-rc1 - A specific rc version # 23.0.13-rc2 # function mcr_ver() { [[ $1 =~ ^([0-9]+\.[0-9]+\.[0-9]+)(-([1-9][0-9]*))?(-(tp|rc)([1-9][0-9]*))?$ ]] } get_dep_package_version_deb(){ local package="${1:?Please specify package name}" local version="${2:?Please specify package version}" local dep_package="${3:?Please specify dependance package name}" apt-cache show "${package}=${version}" \ | grep -oP "${dep_package}"' \([^ ]+ \K[^\)]+' } get_dep_package_version_yum(){ local package="${1:?Please specify package name}" local version="${2:?Please specify package version}" local dep_pkg="${3:?Please specify dependance package name}" ${SH_C} "yum deplist ${package}-${version}" \ | awk -v dep_pkg="${dep_pkg}" '$1 == "dependency:" && $2 == dep_pkg {print $4}' } get_dep_package_version_zypper(){ local package="${1:?Please specify package name}" local version="${2:?Please specify package version}" local dep_package="${3:?Please specify dependance package name}" local _full_package_version _full_package_version="$(get_full_package_version_zypper "${package}" "${version}")" # Unfortunately, zypper doesn't support `info` command for specific package version # so let's use dirty hack by downloading the rpm file and find out the dependency ${SH_C} "zypper install --force --download-only --no-confirm ${package}-${_full_package_version}" &> /dev/null local _file_package_version _file_package_version="${_full_package_version##*:}" find /var/cache/zypp/packages/ -name "${package}-${_file_package_version}"'*.rpm' -exec rpm -qR -p {} \; \ | awk '$1 == "'"${dep_package}"'" {print $3}' } get_dep_package_version(){ local package="${1:?Please specify package name}" local version="${2:?Please specify package version}" local dep_package="${3:?Please specify dependance package name}" case "${DIST_ID}" in ubuntu) get_dep_package_version_deb "${package}" "${version}" "${dep_package}" ;; centos | rhel | rocky | amzn | ol) get_dep_package_version_yum "${package}" "${version}" "${dep_package}" ;; sles | opensuse-leap) get_dep_package_version_zypper "${package}" "${version}" "${dep_package}" ;; esac } function get_package_epoch() { local package="${1:?Please specify package name}" local dist_id="${2:?Please specify dist_id}" case "${dist_id}" in ubuntu) declare -A _deb_package_epoch_map=( ["docker-ee"]="5:" ["docker-ee-cli"]="5:" ["docker-ee-rootless-extras"]="5:" ["containerd.io"]="" ) echo "${_deb_package_epoch_map[${package}]}" ;; esac } get_full_package_version_deb () { local package="${1:?Please specify package name}" local version="${2:?Please specify package version}" local _epoch _epoch="$(get_package_epoch "${package}" "${DIST_ID}")" apt-cache show "${package}=${_epoch}${version}"'*' \ | awk '$1 == "Version:" {print $2}' } get_full_package_version_yum () { local package="${1:?Please specify package name}" local version="${2:?Please specify package version}" local _repoquery=repoquery command_exists dnf && _repoquery="dnf repoquery" local _full_version _full_version="$( ${_repoquery} -q --repoid=docker-ee-"${CHANNEL}" --qf='%{evr}' "${package}-${version}"'*' )" echo "${_full_version#*:}" } get_full_package_version_zypper () { local package="${1:?Please specify package name}" local version="${2:?Please specify package version}" # Unfortunately, zypper doesn't support `info` command for specific package version # so let's use `zypper search` command which returns a sorted list of versions #S | Name | Type | Version | Arch | Repository #--+-----------+---------+-------------------------+--------+--------------- # | docker-ee | package | 3:23.0.15-3 | x86_64 | docker-ee-test # | docker-ee | package | 3:23.0.15-2.1.rc1 | x86_64 | docker-ee-test # | docker-ee | package | 3:23.0.15-0.1.tp1 | x86_64 | docker-ee-test ${SH_C} "zypper search --match-exact --details --type package ${package}" \ | gawk -v version="${version##*:}" 'index(gensub(/^[[:digit:]]+:/, "", 1, $4), version) == 1 {print $4; exit}' FS='[[:space:]]+\\|[[:space:]]+' } get_full_package_version() { local package="${1:?Please specify package name}" local version="${2:?Please specify package version}" case "${DIST_ID}" in ubuntu) get_full_package_version_deb "${package}" "${version}" ;; centos | rhel | rocky | amzn | ol) get_full_package_version_yum "${package}" "${version}" ;; sles | opensuse-leap) get_full_package_version_zypper "${package}" "${version}" ;; esac } get_docker_c8d_dep() { local version=${1:?"Please specify docker version"} local c8d_dep c8d_dep="$(get_dep_package_version "${DOCKER_PACKAGE_NAME}" "${version}" "${CONTAINERD_PACKAGE_NAME}")" get_full_package_version "${CONTAINERD_PACKAGE_NAME}" "${c8d_dep}" } get_c8d_mapped_version() { local mcr_ver=${1:-MCR_MAIN_VERSION} declare -rA _mcr_c8d_deb_map=( ["23.0.1"]="1.6.17" ["23.0.3"]="1.6.19" ["23.0.5"]="1.6.20" ["23.0.6"]="1.6.21" ["23.0.7"]="1.6.22" ["23.0.8"]="1.6.25~rc.1-1" ["23.0.9"]="1.6.28~rc.1-1" ["23.0.9-1"]="1.6.28~rc.1-2" ['23.0.10']="1.6.30~rc.2-1" ['23.0.13']="1.6.32" ['23.0.14']="1.6.33" ) declare -rA _mcr_c8d_rpm_map=( ["23.0.1"]="1.6.17" ["23.0.3"]="1.6.19" ["23.0.5"]="1.6.20" ["23.0.6"]="1.6.21" ["23.0.7"]="1.6.22" ["23.0.8"]="1.6.25-2.1.rc.1.1" ["23.0.9"]="1.6.28-2.1.rc.1.1" ["23.0.9-1"]="1.6.28-3.1.rc.1.1" ["23.0.10"]="1.6.30-2.2.rc.2.1" ['23.0.13']="1.6.32" ['23.0.14']="1.6.33" ) local _c8d_ver case "${DIST_ID}" in ubuntu) _c8d_ver="${_mcr_c8d_deb_map["${mcr_ver}"]}" ;; centos | rhel | rocky | amzn | ol | sles | opensuse-leap) _c8d_ver="${_mcr_c8d_rpm_map["${mcr_ver}"]}" ;; esac if [ -z "${_c8d_ver}" ]; then return 1 fi echo "${_c8d_ver}" } get_docker_mapped_version() { local mcr_version="${1:-MCR_MAIN_VERSION}" declare -rA mcr_docker_deb_map=( ["23.0.9"]="23.0.9~3-" ["23.0.9-1"]="23.0.9~4" ) declare -rA mcr_docker_rpm_map=( ["23.0.9"]="23.0.9-3" ["23.0.9-1"]="23.0.9-4" ) local _docker_ver case "$DIST_ID" in ubuntu) _docker_ver=${mcr_docker_deb_map[${mcr_version}]} ;; centos | rhel | rocky | amzn | ol | sles | opensuse-leap) _docker_ver=${mcr_docker_rpm_map[${mcr_version}]} ;; esac if [ -n "${_docker_ver}" ]; then echo "${_docker_ver}" fi } get_docker_package_version() { local mcr_version="${1:-MCR_MAIN_VERSION}" mcr_ver "${mcr_version}" local _main_version=${BASH_REMATCH[1]} local _prerelease_designator=${BASH_REMATCH[5]} local _build_version=${BASH_REMATCH[6]} local _prerelease="${_prerelease_designator}${_build_version}" local _ver _ver="$(get_docker_mapped_version "${mcr_version}")" if [ -n "${_ver}" ]; then echo "${_ver}" return 0 fi case "${DIST_ID}" in ubuntu) # the first number after the tilde corresponds to the prerelease # designator. for tp, it's 0, for rc, it's 2, and for release, it's 3. # build_version does not appear in prerelease versions, we ignore it. case "${_prerelease_designator}" in tp) echo "${_main_version}~0.${_build_version}.${_prerelease}" ;; rc) echo "${_main_version}~2.${_build_version}.${_prerelease}" ;; *) echo "${_main_version}~$(( 3 + _build_version ))" ;; esac ;; centos | rhel | rocky | amzn | ol) case "${_prerelease_designator}" in tp) echo "${_main_version}-0.${_build_version}.${_prerelease}." ;; rc) echo "${_main_version}-2.${_build_version}.${_prerelease}." ;; *) echo "${_main_version}-$(( 3 + _build_version ))." ;; esac ;; sles | opensuse-leap) # On zypper-based systems version terminates before any extra fluffy # bits, which means we can't end our search string (the thing we're # making here) with a dot. This means that, on zipper, we might match # both build version 29 (which ends in -30) and build version 0 (which # ends in -3). If we ever have 30 build versions, we can fix this. case "${_prerelease_designator}" in tp) echo "${_main_version}-0.${_build_version}.${_prerelease}" ;; rc) echo "${_main_version}-2.${_build_version}.${_prerelease}" ;; *) echo "${_main_version}-$(( 3 + _build_version ))" ;; esac ;; esac } get_c8d_version() { local mcr_ver=${1:?Please specify MCR package version} local docker_ver=${2:?Please specify docker package version} if [ -n "${CONTAINERD_VERSION}" ]; then echo "${CONTAINERD_VERSION}" return 0 fi get_c8d_mapped_version "${mcr_ver}" || get_docker_c8d_dep "${docker_ver}" } get_c8d_package_version() { local mcr_ver=${1:?Please specify MCR package version} local docker_ver=${2:?Please specify docker package version} get_full_package_version "${CONTAINERD_PACKAGE_NAME}" "$(get_c8d_version "${mcr_ver}" "${docker_ver}")" } command_exists() { command -v "$@" > /dev/null 2>&1 } on_ec2() { [ -f /sys/hypervisor/uuid ] && [ "$(head -c 3 /sys/hypervisor/uuid)" == ec2 ] } strip_trailing_slash() { echo "${1/%\/}" } # version_gte checks if the version specified in $VERSION is at least # the given CalVer (YY.MM) version. returns 0 (success) if $VERSION is either # unset (=latest) or newer or equal than the specified version. Returns 1 (fail) # otherwise. # # examples: # # VERSION=20.10 # version_gte 20.10 // 0 (success) # version_gte 19.03 // 0 (success) # version_gte 21.10 // 1 (fail) version_gte() { if [ -z "$VERSION" ]; then return 0 fi calver_compare "${VERSION%%-*}" "$1" } # calver_compare compares two CalVer (YY.MM.VER) version strings. returns 0 (success) # if version A is newer or equal than version B, or 1 (fail) otherwise. Patch # releases and pre-release (-alpha/-beta) are not taken into account # # examples: # # calver_compare 20.10.12 19.03 // 0 (success) # calver_compare 20.10.12 20.10.12 // 0 (success) # calver_compare 19.03.02 20.10.12 // 1 (fail) calver_compare() ( set +x yy_a="$(echo "$1" | cut -d'.' -f1)" yy_b="$(echo "$2" | cut -d'.' -f1)" if (( "$yy_a" < "$yy_b" )); then return 1 fi if (( "$yy_a" > "$yy_b" )); then return 0 fi mm_a="$(echo "$1" | cut -d'.' -f2)" mm_b="$(echo "$2" | cut -d'.' -f2)" if (( "${mm_a}" < "${mm_b}" )); then return 1 fi ver_a="$(echo "$1" | cut -d'.' -f3)" ver_b="$(echo "$2" | cut -d'.' -f3)" if (( "$ver_a" < "$ver_b" )); then return 1 fi return 0 ) ubuntu_prepare() { declare -rx DEBIAN_FRONTEND=noninteractive local _pre_reqs="apt-transport-https ca-certificates curl software-properties-common" if ! command -v gpg > /dev/null; then _pre_reqs="$_pre_reqs gnupg" fi ( set -ex ${SH_C} "apt-get update -qq" ${SH_C} "apt-get install -y -qq $_pre_reqs" &>/dev/null ) local _ubuntu_url _ubuntu_url=$(strip_trailing_slash "${DOCKER_URL}") # Check if we have a gpg (should be valid repo to use if it's there) before appending suffix if ! curl -fsSL "${_ubuntu_url}/gpg" >/dev/null; then # URL's may not be suffixed with ubuntu, let's make sure that they are if [[ ! "${_ubuntu_url}" =~ /ubuntu$ ]]; then _ubuntu_url="${_ubuntu_url}/ubuntu" fi fi local _arch _arch="$(dpkg --print-architecture)" # Grab this outside of the command to install, so it's not muddled local _release # shellcheck disable=SC1091 _release="$(. /etc/os-release && echo "${VERSION_CODENAME}")" ( set -ex curl -fsSL "${_ubuntu_url}"/gpg | ${SH_C} "apt-key add -qq -" >/dev/null ${SH_C} "add-apt-repository -y 'deb [arch=${_arch}] ${_ubuntu_url} ${_release} ${CHANNEL}'" >/dev/null ${SH_C} "apt-get update -qq" >/dev/null ) } ubuntu_install() { declare -rx DEBIAN_FRONTEND=noninteractive local docker_version="${1:?Specify docker version}" if [[ -z "${SKIP_REPO_SETUP}" ]]; then ubuntu_prepare fi local _docker_package="${DOCKER_PACKAGE_NAME}" # By default, don't include a cli_package and rootless_package to install just let the package manager grab the topmost one local _cli_package="${DOCKER_CLI_PACKAGE_NAME}" local _rootless_package="${DOCKER_ROOTLESS_PACKAGE_NAME}" local _containerd_package="${CONTAINERD_PACKAGE_NAME}" local _docker_package_version _docker_package_version="$(get_full_package_version "${_docker_package}" "${docker_version}")" local _cli_package_version _cli_package_version="$(get_full_package_version "${_cli_package}" "${docker_version}")" local _rootless_package_version if version_gte "${MIN_ROOTLESS_VER}"; then _rootless_package_version="$(get_full_package_version "${_rootless_package}" "${docker_version}")" fi echo "INFO: Searching repository for Docker package VERSION '${docker_version}'" if [ -z "${_docker_package_version}" ]; then echo echo "ERROR: '${docker_version}' not found amongst apt-cache madison results" echo exit 1 fi # If a cli package was found for the given version then include it in the installation if [ -n "${_cli_package_version}" ]; then _cli_package+="=${_cli_package_version}" fi # If a rootless package was found for the given version then include it in the installation if [ -n "$_rootless_package_version" ]; then _rootless_package+="=${_rootless_package_version}" fi _docker_package+="=${_docker_package_version}" if version_gte "$MIN_MCR_WITH_C8D_VER"; then local _c8d_version _c8d_version="$(get_c8d_package_version "${MCR_MAIN_VERSION}" "${_docker_package_version}")" if [ -n "${_c8d_version}" ]; then _containerd_package+="=${_c8d_version}" fi fi ( local _apt_flags="-y -qq --allow-downgrades ${DRY_RUN:+ --dry-run}" set -ex ${SH_C} "apt-get install ${_apt_flags} ${_docker_package} ${_cli_package} ${_rootless_package} ${_containerd_package}" ) } yum_prepare() { local dist_id="${1:?Specify Distribution Id}" local dist_version="${2:?Please specify Distribution version}" local _yum_url _yum_url=$(strip_trailing_slash "${DOCKER_URL}") ( set -ex command_exists curl || ${SH_C} 'yum install -q -y curl' ) # Check if we have a usable repo file before appending suffix if ! curl --fail --silent --location --head "${_yum_url}/docker-ee.repo" >/dev/null; then if [[ ! "${_yum_url}" =~ /centos$|/rhel$|rocky$ ]]; then _yum_url="${_yum_url}/${dist_id}" fi fi case ${dist_id}:${dist_version} in oraclelinux:7*) # Enable "Oracle Linux 7 Server Add ons (x86_64)" repo for oraclelinux7 ( set -ex ${SH_C} 'yum-config-manager --enable ol7_addons' ) ;; rhel:7*) local _extras_repo="rhel-7-server-extras-rpms" if on_ec2; then ${SH_C} "yum install -y rh-amazon-rhui-client" _extras_repo="rhel-7-server-rhui-extras-rpms" fi # We don't actually make packages for 7.1, but they can still use the 7 repository if [ "${dist_version}" = "7.1" ]; then dist_version="7" fi # Enable extras repo for rhel ( set -ex ${SH_C} "yum-config-manager --enable ${_extras_repo}" ) ;; esac ( set -ex ${SH_C} "echo '${_yum_url}' > /etc/yum/vars/dockerurl" ${SH_C} "echo '${dist_version}' > /etc/yum/vars/dockerosversion" ${SH_C} "yum install -q -y yum-utils device-mapper-persistent-data lvm2" ${SH_C} "yum-config-manager --add-repo ${_yum_url}/docker-ee.repo" ${SH_C} "yum-config-manager --disable 'docker-ee-*'" ${SH_C} "yum-config-manager --enable 'docker-ee-${CHANNEL}'" ) } yum_install() { local docker_version="${1:?Specify docker version}" local dist_id="${2:?Specify Distribution Id}" local dist_version="${3:?Please specify Distribution version}" if [[ -z "${SKIP_REPO_SETUP}" ]]; then yum_prepare "${dist_id}" "${dist_version}" fi local _docker_package="${DOCKER_PACKAGE_NAME}" # By default, don't include a cli_package and rootless_package to install just let the package manager grab the topmost one local _cli_package="${DOCKER_CLI_PACKAGE_NAME}" local _rootless_package="" local _containerd_package="${CONTAINERD_PACKAGE_NAME}" local _docker_package_version _docker_package_version="$(get_full_package_version "${_docker_package}" "${docker_version}")" local _cli_package_version _cli_package_version="$(get_full_package_version "${_cli_package}" "${docker_version}")" local _rootless_package_version if version_gte "$MIN_ROOTLESS_VER" && [ "${dist_id}:${dist_version}" != "oraclelinux:7" ]; then # like the CLI, rootless-extras packages don't start with 3:. They don't # start with anything, actually. _rootless_package="${DOCKER_ROOTLESS_PACKAGE_NAME}" _rootless_package_version="$(get_full_package_version "${_rootless_package}" "${docker_version}")" fi echo "INFO: Searching repository for Docker package VERSION '${docker_version}'" if [ -z "${_docker_package_version}" ]; then echo echo "ERROR: '${docker_version}' not found amongst yum list results" echo exit 1 fi if [ -n "$_cli_package_version" ]; then _cli_package+="-${_cli_package_version}" fi if [ -n "$_rootless_package_version" ]; then _rootless_package+="-${_rootless_package_version}" fi _docker_package+="-${_docker_package_version}" local _yum_cmd="install" # Check if we're doing an upgrade / downgrade and the command accordingly echo "INFO: Checking to determine whether this should be an upgrade or downgrade" # If the package isn't really installed then don't try upgrade / downgrade if ! yum list installed "${DOCKER_PACKAGE_NAME}" >/dev/null; then _yum_cmd="install" # Exit codes when using --assumeno will give 0 if there would be an upgrade/downgrade, 1 if there is elif ! ${SH_C} "yum upgrade --assumeno ${_docker_package}"; then _yum_cmd="upgrade" elif ! ${SH_C} "yum downgrade --assumeno ${_docker_package}"; then _yum_cmd="downgrade" fi local _c8d_version echo "INFO: will use install command $_yum_cmd" if version_gte "$MIN_MCR_WITH_C8D_VER"; then _c8d_version="$(get_c8d_package_version "${MCR_MAIN_VERSION}" "${_docker_package_version}")" if [ -n "${_c8d_version}" ]; then _containerd_package+="-${_c8d_version}" fi fi ( local _yum_flags="-q" if [ -n "${DRY_RUN}" ]; then _yum_flags+=" --assumeno" else _yum_flags+=" --assumeyes" fi set -ex ${SH_C} "yum ${_yum_cmd} ${_yum_flags} ${_docker_package} ${_cli_package} ${_rootless_package} ${_containerd_package}" ) } REPO_VERSION="" zypper_prepare() { local _arch _arch="$(uname -m)" ( set -ex ${SH_C} "zypper install --no-confirm curl gawk" ) local _zypper_url _zypper_url=$(strip_trailing_slash "${DOCKER_URL}") # No need to append sles if we already have a valid repo if ! curl -fsL "${_zypper_url}/docker-ee.repo" >/dev/null; then _zypper_url="${_zypper_url}/sles" fi ( set -ex # SLES images have installed Docker CE by default, which conflicts w/ MCR, so it needs to be deleted ${SH_C} "zypper remove -y docker docker-engine docker-libnetwork runc containerd" || true ${SH_C} "zypper removerepo docker-ee-${CHANNEL}" # this will always return 0 even if repo alias not found ${SH_C} "zypper addrepo ${_zypper_url}/${REPO_VERSION}/${_arch}/${CHANNEL} docker-ee-${CHANNEL}" ${SH_C} "rpm --import '${_zypper_url}/gpg'" ${SH_C} "zypper refresh" ) } zypper_install() { local docker_version="${1:?Specify docker version}" local dist_version="${2}" REPO_VERSION=15 if [[ -z "${SKIP_REPO_SETUP}" ]]; then zypper_prepare fi local _docker_package="${DOCKER_PACKAGE_NAME}" # By default, don't include a cli_package and _rootless_package to install just let the package manager grab the topmost one local _cli_package="${DOCKER_CLI_PACKAGE_NAME}" local _rootless_package="" local _containerd_package="${CONTAINERD_PACKAGE_NAME}" local _docker_package_version _docker_package_version="$(get_full_package_version "${_docker_package}" "${docker_version}")" local _cli_package_version _cli_package_version="$(get_full_package_version "${_cli_package}" "${docker_version}")" local _rootless_package_version if version_gte "${MIN_ROOTLESS_VER}"; then _rootless_package="${DOCKER_ROOTLESS_PACKAGE_NAME}" _rootless_package_version="$(get_full_package_version "${_rootless_package}" "${docker_version}")" fi echo "INFO: Searching repository for VERSION '${docker_version}'" if [ -z "${_docker_package_version}" ]; then echo echo "ERROR: '${docker_version}' not found amongst zypper search results" echo exit 1 fi # If a cli package was found for the given version then include it in the installation if [ -n "${_cli_package_version}" ]; then _cli_package+="-${_cli_package_version}" fi # If a rootless package was found for the given version then include it in the installation if [ -n "${_rootless_package_version}" ]; then _rootless_package+="-${_rootless_package_version}" fi _docker_package+="-${_docker_package_version}" local _c8d_version if version_gte "$MIN_MCR_WITH_C8D_VER"; then _c8d_version="$(get_c8d_package_version "${MCR_MAIN_VERSION}" "${_docker_package_version}")" if [ -n "${_c8d_version}" ]; then _containerd_package+="-${_c8d_version}" fi fi ( local _zypper_flags="--replacefiles --force --no-confirm --allow-vendor-change" if [ -n "${DRY_RUN}" ]; then _zypper_flags+=" --dry-run" fi set -ex ${SH_C} "zypper install ${_zypper_flags} ${_docker_package} ${_cli_package} ${_rootless_package} ${_containerd_package}" ) } is_fips_enabled(){ # if FIPS is enabled on the OS local fips fips=$(cat /proc/sys/crypto/fips_enabled) (( fips > 0 )) && return 0 # FIPS isn't enabled return 1 } get_channel() { declare -r DEFAULT_NONFIPS_EE_CHANNEL="stable-25.0" declare -r DEFAULT_FIPS_EE_CHANNEL="${DEFAULT_NONFIPS_EE_CHANNEL}/fips" # if CHANNEL is set, use it [[ -n "${CHANNEL}" ]] && echo "${CHANNEL}" && return 0 # if FIPS is enabled in kernel, use the FIPS channel is_fips_enabled && echo "${DEFAULT_FIPS_EE_CHANNEL}" || echo "${DEFAULT_NONFIPS_EE_CHANNEL}" } ubuntu_install_25() { local DEBIAN_FRONTEND export DEBIAN_FRONTEND=noninteractive ( set -ex $SH_C "apt-get update -qq" $SH_C "apt-get install -y -qq curl gnupg" >/dev/null ) local component component="$(get_channel)" # Download the keyring to the package-updateable location as described # in https://wiki.debian.org/DebianRepository/UseThirdParty # and configure APT to trust it only for our source's entry. local keyring="/usr/share/keyrings/mirantis-archive-keyring.pgp" local ubuntu_url ubuntu_url="${DOCKER_URL%/}" local keyring_asc if ! keyring_asc="$(curl -fsSL "$ubuntu_url/gpg")" 2>/dev/null; then # URL's may not be suffixed with ubuntu, let's make sure that they are if [[ "$ubuntu_url" != */ubuntu$ ]]; then ubuntu_url+="/ubuntu" keyring_asc="$(curl -fsSL "$ubuntu_url/gpg")" fi fi ( set -ex; $SH_C "gpg --batch --yes --output '${keyring}' --dearmor" ) <<< "$keyring_asc" # Add the apt repository for 25.0 in general # shellcheck source=/dev/null ( set -ex; $SH_C 'tee /etc/apt/sources.list.d/mirantis.sources' ) <<< "\ Types: deb URIs: $ubuntu_url Suites: $(. /etc/os-release && echo "$VERSION_CODENAME") Components: $component Architectures: $(dpkg --print-architecture) Signed-By: $keyring" ( set -ex $SH_C "apt-get update -qq" ) local docker_package="${DOCKER_PACKAGE_NAME}" local cli_package="${DOCKER_CLI_PACKAGE_NAME}" local rootless_package="${DOCKER_ROOTLESS_PACKAGE_NAME}" local containerd_package="${CONTAINERD_PACKAGE_NAME}" # TODO(dperny): make configurable, in a sane way. local cri_package="${CRI_DOCKERD_PACKAGE_NAME}" local runc_package="${RUNC_PACKAGE_NAME}" ( set -ex # Just do the full install, with all required packages. $SH_C "apt-get install -y -qq ${docker_package} ${cli_package} ${rootless_package} ${containerd_package} ${cri_package} ${runc_package}" ) } yum_install_25() { local DIST_ID="$1" # unlike ubuntu, with yum and RPMs, we install based on a specific URL. local yum_url yum_url="${DOCKER_URL%/}" local component component="$(get_channel)" command -v curl &> /dev/null || ( set -ex $SH_C "dnf install -q -y curl" ) # Check if we have a usable repo file before appending suffix if ! curl --head -fsSL "$yum_url/gpg" &>/dev/null; then if [[ ! "$yum_url" =~ /centos$|/rhel$|rocky$ ]]; then yum_url+="/$DIST_ID" fi fi # Add a repository for 25.0 in general ( set -ex; $SH_C 'tee /etc/yum.repos.d/docker-ee.repo' ) <<< "[mirantis] name=Mirantis Container Runtime baseurl=$yum_url/\$releasever/\$basearch/$component enabled=1 gpgcheck=1 gpgkey=$yum_url/gpg module_hotfixes=true" # skip all the oracle/rhel 7 stuff; we don't build 25 for those versions. local docker_package="${DOCKER_PACKAGE_NAME}" local cli_package="${DOCKER_CLI_PACKAGE_NAME}" local rootless_package="${DOCKER_ROOTLESS_PACKAGE_NAME}" local containerd_package="${CONTAINERD_PACKAGE_NAME}" local cri_package="${CRI_DOCKERD_PACKAGE_NAME}" local runc_package="${RUNC_PACKAGE_NAME}" ( set -ex $SH_C "dnf install -q -y ${docker_package} ${cli_package} ${rootless_package} ${containerd_package} ${cri_package} ${runc_package}" ) } zypper_install_25() { # Need some basic info for local dist_version dist_version=$1 local arch arch="$(uname -m)" local component component="$(get_channel)" local repo_version="${dist_version%%.*}" local zypper_flags=" --allow-vendor-change --allow-downgrade --no-confirm" # Check if we have curl. If not, we need it. command -v curl &> /dev/null || ( set -ex $SH_C "zypper install -y curl" ) local zypper_url zypper_url="${DOCKER_URL%/}" # no need to append sles if we already have a valid repo if ! curl -fsL "$zypper_url/gpg" >/dev/null; then zypper_url+="/sles" fi ( set -ex # you do, in fact, need to removerepo, or running this script a second # time on a box will fail (even if you've uninstalled in the meantime, # unless your uninstallation involved doing this command) $SH_C "zypper removerepo mirantis" # this will always return 0 even if repo alias not found $SH_C "zypper addrepo $zypper_url/$repo_version/$arch/$component mirantis" $SH_C "rpm --import '$zypper_url/gpg'" $SH_C "zypper refresh" ) local docker_package="${DOCKER_PACKAGE_NAME}" local cli_package="${DOCKER_CLI_PACKAGE_NAME}" local rootless_package="${DOCKER_ROOTLESS_PACKAGE_NAME}" local containerd_package="${CONTAINERD_PACKAGE_NAME}" local cri_package="${CRI_DOCKERD_PACKAGE_NAME}" local runc_package="${RUNC_PACKAGE_NAME}" ( set -ex # it looks like suse includes docker by default (installed, but it seems # not running), which conflicts with docker-ee (obviously). if someone is # running this script, though, they want us to resolve the conflict in our # favor, so go ahead and remove anything docker that's already there. $SH_C "zypper install $zypper_flags -y ${docker_package} ${cli_package} ${rootless_package} ${containerd_package} ${cri_package} ${runc_package}" ) } main() { local _user _user="$(id -un 2>/dev/null || true)" if [ "${_user}" != 'root' ]; then if command_exists sudo; then SH_C='sudo -E sh -c' elif command_exists su; then SH_C='su -c' else cat >&2 <<-'EOF' Error: this installer needs the ability to run commands as root. We are unable to find either "sudo" or "su" available to make this happen. EOF exit 1 fi fi # shellcheck disable=SC1091 DIST_ID="$(. /etc/os-release && echo "$ID")" local _dist_version # shellcheck disable=SC1091 _dist_version="$(. /etc/os-release && echo "$VERSION_ID")" if [ -z "${DOCKER_URL}" ]; then echo "ERROR: DOCKER_URL must be set, exiting..." exit 1 fi if ! mcr_ver "${VERSION}" && [[ "$VERSION" != 25.0* ]]; then echo "${VERSION} doesn't match with expected pattern. Version must follow this pattern a.b.c, a.b.c-d, a.b.c-(tp|rc)e, a.b.c-d-(tp|rc)e, where a,b,c,d,e are numbers." exit 1 fi MCR_MAIN_VERSION="${BASH_REMATCH[1]}${BASH_REMATCH[2]}" local _docker_pkg_ver _docker_pkg_ver="$(get_docker_package_version "${VERSION}")" case "$DIST_ID:$_dist_version" in ubuntu:20.04|ubuntu:22.04) # TODO(dperny): All of this checking to see if the version is 25.0 isn't # really future-proof, because what about 25.1? But that's tomorrow's # problem. if [[ $VERSION == 25.0* ]]; then ubuntu_install_25 else ubuntu_install "${_docker_pkg_ver}" fi exit 0 ;; centos:*|rhel:*|rocky:*) # Strip point versions, they don't really matter if [[ $VERSION == 25.0* ]]; then yum_install_25 "$DIST_ID" else yum_install "${_docker_pkg_ver}" "$DIST_ID" "${_dist_version%%.*}" fi exit 0 ;; ol:*) if [[ $VERSION == 25.0* ]]; then yum_install_25 "oraclelinux" else # Consider only major version for OL distros yum_install "${_docker_pkg_ver}" "oraclelinux" "${_dist_version%%.*}" fi exit 0 ;; sles:15*|opensuse-leap:15*) if [[ $VERSION == 25.0* ]]; then zypper_install_25 "$_dist_version" else zypper_install "${_docker_pkg_ver}" "${_dist_version%%.*}" fi exit 0 ;; *) echo echo "ERROR: Unsupported distribution / distribution version '${DIST_ID}:${_dist_version}'" echo " If you feel this is a mistake please contact Mirantis support" echo exit 1 ;; esac } main