github.com/stefanmcshane/helm@v0.0.0-20221213002717-88a4a2c6e77d/scripts/get-helm-3 (about)

     1  #!/usr/bin/env bash
     2  
     3  # Copyright The Helm Authors.
     4  #
     5  # Licensed under the Apache License, Version 2.0 (the "License");
     6  # you may not use this file except in compliance with the License.
     7  # You may obtain a copy of the License at
     8  #
     9  #     http://www.apache.org/licenses/LICENSE-2.0
    10  #
    11  # Unless required by applicable law or agreed to in writing, software
    12  # distributed under the License is distributed on an "AS IS" BASIS,
    13  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  # See the License for the specific language governing permissions and
    15  # limitations under the License.
    16  
    17  # The install script is based off of the MIT-licensed script from glide,
    18  # the package manager for Go: https://github.com/Masterminds/glide.sh/blob/master/get
    19  
    20  : ${BINARY_NAME:="helm"}
    21  : ${USE_SUDO:="true"}
    22  : ${DEBUG:="false"}
    23  : ${VERIFY_CHECKSUM:="true"}
    24  : ${VERIFY_SIGNATURES:="false"}
    25  : ${HELM_INSTALL_DIR:="/usr/local/bin"}
    26  : ${GPG_PUBRING:="pubring.kbx"}
    27  
    28  HAS_CURL="$(type "curl" &> /dev/null && echo true || echo false)"
    29  HAS_WGET="$(type "wget" &> /dev/null && echo true || echo false)"
    30  HAS_OPENSSL="$(type "openssl" &> /dev/null && echo true || echo false)"
    31  HAS_GPG="$(type "gpg" &> /dev/null && echo true || echo false)"
    32  HAS_GIT="$(type "git" &> /dev/null && echo true || echo false)"
    33  
    34  # initArch discovers the architecture for this system.
    35  initArch() {
    36    ARCH=$(uname -m)
    37    case $ARCH in
    38      armv5*) ARCH="armv5";;
    39      armv6*) ARCH="armv6";;
    40      armv7*) ARCH="arm";;
    41      aarch64) ARCH="arm64";;
    42      x86) ARCH="386";;
    43      x86_64) ARCH="amd64";;
    44      i686) ARCH="386";;
    45      i386) ARCH="386";;
    46    esac
    47  }
    48  
    49  # initOS discovers the operating system for this system.
    50  initOS() {
    51    OS=$(echo `uname`|tr '[:upper:]' '[:lower:]')
    52  
    53    case "$OS" in
    54      # Minimalist GNU for Windows
    55      mingw*|cygwin*) OS='windows';;
    56    esac
    57  }
    58  
    59  # runs the given command as root (detects if we are root already)
    60  runAsRoot() {
    61    if [ $EUID -ne 0 -a "$USE_SUDO" = "true" ]; then
    62      sudo "${@}"
    63    else
    64      "${@}"
    65    fi
    66  }
    67  
    68  # verifySupported checks that the os/arch combination is supported for
    69  # binary builds, as well whether or not necessary tools are present.
    70  verifySupported() {
    71    local supported="darwin-amd64\ndarwin-arm64\nlinux-386\nlinux-amd64\nlinux-arm\nlinux-arm64\nlinux-ppc64le\nlinux-s390x\nwindows-amd64"
    72    if ! echo "${supported}" | grep -q "${OS}-${ARCH}"; then
    73      echo "No prebuilt binary for ${OS}-${ARCH}."
    74      echo "To build from source, go to https://github.com/helm/helm"
    75      exit 1
    76    fi
    77  
    78    if [ "${HAS_CURL}" != "true" ] && [ "${HAS_WGET}" != "true" ]; then
    79      echo "Either curl or wget is required"
    80      exit 1
    81    fi
    82  
    83    if [ "${VERIFY_CHECKSUM}" == "true" ] && [ "${HAS_OPENSSL}" != "true" ]; then
    84      echo "In order to verify checksum, openssl must first be installed."
    85      echo "Please install openssl or set VERIFY_CHECKSUM=false in your environment."
    86      exit 1
    87    fi
    88  
    89    if [ "${VERIFY_SIGNATURES}" == "true" ]; then
    90      if [ "${HAS_GPG}" != "true" ]; then
    91        echo "In order to verify signatures, gpg must first be installed."
    92        echo "Please install gpg or set VERIFY_SIGNATURES=false in your environment."
    93        exit 1
    94      fi
    95      if [ "${OS}" != "linux" ]; then
    96        echo "Signature verification is currently only supported on Linux."
    97        echo "Please set VERIFY_SIGNATURES=false or verify the signatures manually."
    98        exit 1
    99      fi
   100    fi
   101  
   102    if [ "${HAS_GIT}" != "true" ]; then
   103      echo "[WARNING] Could not find git. It is required for plugin installation."
   104    fi
   105  }
   106  
   107  # checkDesiredVersion checks if the desired version is available.
   108  checkDesiredVersion() {
   109    if [ "x$DESIRED_VERSION" == "x" ]; then
   110      # Get tag from release URL
   111      local latest_release_url="https://github.com/helm/helm/releases"
   112      if [ "${HAS_CURL}" == "true" ]; then
   113        TAG=$(curl -Ls $latest_release_url | grep 'href="/helm/helm/releases/tag/v3.[0-9]*.[0-9]*\"' | sed -E 's/.*\/helm\/helm\/releases\/tag\/(v[0-9\.]+)".*/\1/g' | head -1)
   114      elif [ "${HAS_WGET}" == "true" ]; then
   115        TAG=$(wget $latest_release_url -O - 2>&1 | grep 'href="/helm/helm/releases/tag/v3.[0-9]*.[0-9]*\"' | sed -E 's/.*\/helm\/helm\/releases\/tag\/(v[0-9\.]+)".*/\1/g' | head -1)
   116      fi
   117    else
   118      TAG=$DESIRED_VERSION
   119    fi
   120  }
   121  
   122  # checkHelmInstalledVersion checks which version of helm is installed and
   123  # if it needs to be changed.
   124  checkHelmInstalledVersion() {
   125    if [[ -f "${HELM_INSTALL_DIR}/${BINARY_NAME}" ]]; then
   126      local version=$("${HELM_INSTALL_DIR}/${BINARY_NAME}" version --template="{{ .Version }}")
   127      if [[ "$version" == "$TAG" ]]; then
   128        echo "Helm ${version} is already ${DESIRED_VERSION:-latest}"
   129        return 0
   130      else
   131        echo "Helm ${TAG} is available. Changing from version ${version}."
   132        return 1
   133      fi
   134    else
   135      return 1
   136    fi
   137  }
   138  
   139  # downloadFile downloads the latest binary package and also the checksum
   140  # for that binary.
   141  downloadFile() {
   142    HELM_DIST="helm-$TAG-$OS-$ARCH.tar.gz"
   143    DOWNLOAD_URL="https://get.helm.sh/$HELM_DIST"
   144    CHECKSUM_URL="$DOWNLOAD_URL.sha256"
   145    HELM_TMP_ROOT="$(mktemp -dt helm-installer-XXXXXX)"
   146    HELM_TMP_FILE="$HELM_TMP_ROOT/$HELM_DIST"
   147    HELM_SUM_FILE="$HELM_TMP_ROOT/$HELM_DIST.sha256"
   148    echo "Downloading $DOWNLOAD_URL"
   149    if [ "${HAS_CURL}" == "true" ]; then
   150      curl -SsL "$CHECKSUM_URL" -o "$HELM_SUM_FILE"
   151      curl -SsL "$DOWNLOAD_URL" -o "$HELM_TMP_FILE"
   152    elif [ "${HAS_WGET}" == "true" ]; then
   153      wget -q -O "$HELM_SUM_FILE" "$CHECKSUM_URL"
   154      wget -q -O "$HELM_TMP_FILE" "$DOWNLOAD_URL"
   155    fi
   156  }
   157  
   158  # verifyFile verifies the SHA256 checksum of the binary package
   159  # and the GPG signatures for both the package and checksum file
   160  # (depending on settings in environment).
   161  verifyFile() {
   162    if [ "${VERIFY_CHECKSUM}" == "true" ]; then
   163      verifyChecksum
   164    fi
   165    if [ "${VERIFY_SIGNATURES}" == "true" ]; then
   166      verifySignatures
   167    fi
   168  }
   169  
   170  # installFile installs the Helm binary.
   171  installFile() {
   172    HELM_TMP="$HELM_TMP_ROOT/$BINARY_NAME"
   173    mkdir -p "$HELM_TMP"
   174    tar xf "$HELM_TMP_FILE" -C "$HELM_TMP"
   175    HELM_TMP_BIN="$HELM_TMP/$OS-$ARCH/helm"
   176    echo "Preparing to install $BINARY_NAME into ${HELM_INSTALL_DIR}"
   177    runAsRoot cp "$HELM_TMP_BIN" "$HELM_INSTALL_DIR/$BINARY_NAME"
   178    echo "$BINARY_NAME installed into $HELM_INSTALL_DIR/$BINARY_NAME"
   179  }
   180  
   181  # verifyChecksum verifies the SHA256 checksum of the binary package.
   182  verifyChecksum() {
   183    printf "Verifying checksum... "
   184    local sum=$(openssl sha1 -sha256 ${HELM_TMP_FILE} | awk '{print $2}')
   185    local expected_sum=$(cat ${HELM_SUM_FILE})
   186    if [ "$sum" != "$expected_sum" ]; then
   187      echo "SHA sum of ${HELM_TMP_FILE} does not match. Aborting."
   188      exit 1
   189    fi
   190    echo "Done."
   191  }
   192  
   193  # verifySignatures obtains the latest KEYS file from GitHub main branch
   194  # as well as the signature .asc files from the specific GitHub release,
   195  # then verifies that the release artifacts were signed by a maintainer's key.
   196  verifySignatures() {
   197    printf "Verifying signatures... "
   198    local keys_filename="KEYS"
   199    local github_keys_url="https://raw.githubusercontent.com/helm/helm/main/${keys_filename}"
   200    if [ "${HAS_CURL}" == "true" ]; then
   201      curl -SsL "${github_keys_url}" -o "${HELM_TMP_ROOT}/${keys_filename}"
   202    elif [ "${HAS_WGET}" == "true" ]; then
   203      wget -q -O "${HELM_TMP_ROOT}/${keys_filename}" "${github_keys_url}"
   204    fi
   205    local gpg_keyring="${HELM_TMP_ROOT}/keyring.gpg"
   206    local gpg_homedir="${HELM_TMP_ROOT}/gnupg"
   207    mkdir -p -m 0700 "${gpg_homedir}"
   208    local gpg_stderr_device="/dev/null"
   209    if [ "${DEBUG}" == "true" ]; then
   210      gpg_stderr_device="/dev/stderr"
   211    fi
   212    gpg --batch --quiet --homedir="${gpg_homedir}" --import "${HELM_TMP_ROOT}/${keys_filename}" 2> "${gpg_stderr_device}"
   213    gpg --batch --no-default-keyring --keyring "${gpg_homedir}/${GPG_PUBRING}" --export > "${gpg_keyring}"
   214    local github_release_url="https://github.com/helm/helm/releases/download/${TAG}"
   215    if [ "${HAS_CURL}" == "true" ]; then
   216      curl -SsL "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" -o "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc"
   217      curl -SsL "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" -o "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc"
   218    elif [ "${HAS_WGET}" == "true" ]; then
   219      wget -q -O "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc"
   220      wget -q -O "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc"
   221    fi
   222    local error_text="If you think this might be a potential security issue,"
   223    error_text="${error_text}\nplease see here: https://github.com/helm/community/blob/master/SECURITY.md"
   224    local num_goodlines_sha=$(gpg --verify --keyring="${gpg_keyring}" --status-fd=1 "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" 2> "${gpg_stderr_device}" | grep -c -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)')
   225    if [[ ${num_goodlines_sha} -lt 2 ]]; then
   226      echo "Unable to verify the signature of helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256!"
   227      echo -e "${error_text}"
   228      exit 1
   229    fi
   230    local num_goodlines_tar=$(gpg --verify --keyring="${gpg_keyring}" --status-fd=1 "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" 2> "${gpg_stderr_device}" | grep -c -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)')
   231    if [[ ${num_goodlines_tar} -lt 2 ]]; then
   232      echo "Unable to verify the signature of helm-${TAG}-${OS}-${ARCH}.tar.gz!"
   233      echo -e "${error_text}"
   234      exit 1
   235    fi
   236    echo "Done."
   237  }
   238  
   239  # fail_trap is executed if an error occurs.
   240  fail_trap() {
   241    result=$?
   242    if [ "$result" != "0" ]; then
   243      if [[ -n "$INPUT_ARGUMENTS" ]]; then
   244        echo "Failed to install $BINARY_NAME with the arguments provided: $INPUT_ARGUMENTS"
   245        help
   246      else
   247        echo "Failed to install $BINARY_NAME"
   248      fi
   249      echo -e "\tFor support, go to https://github.com/helm/helm."
   250    fi
   251    cleanup
   252    exit $result
   253  }
   254  
   255  # testVersion tests the installed client to make sure it is working.
   256  testVersion() {
   257    set +e
   258    HELM="$(command -v $BINARY_NAME)"
   259    if [ "$?" = "1" ]; then
   260      echo "$BINARY_NAME not found. Is $HELM_INSTALL_DIR on your "'$PATH?'
   261      exit 1
   262    fi
   263    set -e
   264  }
   265  
   266  # help provides possible cli installation arguments
   267  help () {
   268    echo "Accepted cli arguments are:"
   269    echo -e "\t[--help|-h ] ->> prints this help"
   270    echo -e "\t[--version|-v <desired_version>] . When not defined it fetches the latest release from GitHub"
   271    echo -e "\te.g. --version v3.0.0 or -v canary"
   272    echo -e "\t[--no-sudo]  ->> install without sudo"
   273  }
   274  
   275  # cleanup temporary files to avoid https://github.com/helm/helm/issues/2977
   276  cleanup() {
   277    if [[ -d "${HELM_TMP_ROOT:-}" ]]; then
   278      rm -rf "$HELM_TMP_ROOT"
   279    fi
   280  }
   281  
   282  # Execution
   283  
   284  #Stop execution on any error
   285  trap "fail_trap" EXIT
   286  set -e
   287  
   288  # Set debug if desired
   289  if [ "${DEBUG}" == "true" ]; then
   290    set -x
   291  fi
   292  
   293  # Parsing input arguments (if any)
   294  export INPUT_ARGUMENTS="${@}"
   295  set -u
   296  while [[ $# -gt 0 ]]; do
   297    case $1 in
   298      '--version'|-v)
   299         shift
   300         if [[ $# -ne 0 ]]; then
   301             export DESIRED_VERSION="${1}"
   302         else
   303             echo -e "Please provide the desired version. e.g. --version v3.0.0 or -v canary"
   304             exit 0
   305         fi
   306         ;;
   307      '--no-sudo')
   308         USE_SUDO="false"
   309         ;;
   310      '--help'|-h)
   311         help
   312         exit 0
   313         ;;
   314      *) exit 1
   315         ;;
   316    esac
   317    shift
   318  done
   319  set +u
   320  
   321  initArch
   322  initOS
   323  verifySupported
   324  checkDesiredVersion
   325  if ! checkHelmInstalledVersion; then
   326    downloadFile
   327    verifyFile
   328    installFile
   329  fi
   330  testVersion
   331  cleanup