diff --git a/install/tk.sh b/install/tk.sh index f16a2a1a5d..7962bcb84a 100755 --- a/install/tk.sh +++ b/install/tk.sh @@ -1,51 +1,183 @@ #!/usr/bin/env bash - set -e DEFAULT_BIN_DIR="/usr/local/bin" -BIN_DIR=${1:-"$DEFAULT_BIN_DIR"} - -opsys="" -if [[ "$OSTYPE" == linux* ]]; then - opsys=linux -elif [[ "$OSTYPE" == darwin* ]]; then - opsys=darwin -fi - -if [[ "$opsys" == "" ]]; then - echo "OS $OSTYPE not supported" - exit 1 -fi - -if [[ ! -x "$(command -v curl)" ]]; then - echo "curl not found" +BIN_DIR=${1:-"${DEFAULT_BIN_DIR}"} +GITHUB_REPO="fluxcd/toolkit" + +# Helper functions for logs +info() { + echo '[INFO] ' "$@" +} + +warn() { + echo '[WARN] ' "$@" >&2 +} + +fatal() { + echo '[ERROR] ' "$@" >&2 exit 1 -fi +} -tmpDir=`mktemp -d` -if [[ ! "$tmpDir" || ! -d "$tmpDir" ]]; then - echo "could not create temp dir" - exit 1 -fi +# Set os, fatal if operating system not supported +setup_verify_os() { + if [[ -z "${OS}" ]]; then + OS=$(uname) + fi + case ${OS} in + Darwin) + OS=darwin + ;; + Linux) + OS=linux + ;; + *) + fatal "Unsupported operating system ${OS}" + esac +} -function cleanup { - rm -rf "$tmpDir" +# Set arch, fatal if architecture not supported +setup_verify_arch() { + if [[ -z "${ARCH}" ]]; then + ARCH=$(uname -m) + fi + case ${ARCH} in + amd64) + ARCH=amd64 + ;; + x86_64) + ARCH=amd64 + ;; + *) + fatal "Unsupported architecture ${ARCH}" + esac } -trap cleanup EXIT +# Verify existence of downloader executable +verify_downloader() { + # Return failure if it doesn't exist or is no executable + [[ -x "$(which "$1")" ]] || return 1 -pushd $tmpDir >& /dev/null + # Set verified executable as our downloader program and return success + DOWNLOADER=$1 + return 0 +} -curl -s https://api.github.com/repos/fluxcd/toolkit/releases/latest |\ - grep browser_download |\ - grep $opsys |\ - cut -d '"' -f 4 |\ - xargs curl -sL -o tk.tar.gz +# Create tempory directory and cleanup when done +setup_tmp() { + TMP_DIR=$(mktemp -d -t tk-install.XXXXXXXXXX) + TMP_METADATA="${TMP_DIR}/tk.json" + TMP_HASH="${TMP_DIR}/tk.hash" + TMP_BIN="${TMP_DIR}/tk.tar.gz" + cleanup() { + code=$? + set +e + trap - EXIT + rm -rf "${TMP_DIR}" + exit ${code} + } + trap cleanup INT EXIT +} -tar xzf ./tk.tar.gz +# Find version from Github metadata +get_release_version() { + METADATA_URL="https://api.github.com/repos/${GITHUB_REPO}/releases/latest" -mv ./tk $BIN_DIR + info "Downloading metadata ${METADATA_URL}" + download "${TMP_METADATA}" "${METADATA_URL}" -popd >& /dev/null + VERSION_TK=$(grep '"tag_name":' "${TMP_METADATA}" | sed -E 's/.*"([^"]+)".*/\1/' | cut -c 2-) + if [[ -n "${VERSION_TK}" ]]; then + info "Using ${VERSION_TK} as release" + else + fatal "Unable to determine release version" + fi +} -echo "$(tk --version) installed" +# Download from file from URL +download() { + [[ $# -eq 2 ]] || fatal 'download needs exactly 2 arguments' + + case $DOWNLOADER in + curl) + curl -o "$1" -sfL "$2" + ;; + wget) + wget -qO "$1" "$2" + ;; + *) + fatal "Incorrect executable '${DOWNLOADER}'" + ;; + esac + + # Abort if download command failed + [[ $? -eq 0 ]] || fatal 'Download failed' +} + +# Download hash from Github URL +download_hash() { + HASH_URL="https://github.com/${GITHUB_REPO}/releases/download/v${VERSION_TK}/toolkit_${VERSION_TK}_checksums.txt" + info "Downloading hash ${HASH_URL}" + download "${TMP_HASH}" "${HASH_URL}" + HASH_EXPECTED=$(grep " tk_${VERSION_TK}_${OS}_${ARCH}.tar.gz$" "${TMP_HASH}") + HASH_EXPECTED=${HASH_EXPECTED%%[[:blank:]]*} +} + +# Download binary from Github URL +download_binary() { + BIN_URL="https://github.com/${GITHUB_REPO}/releases/download/v${VERSION_TK}/tk_${VERSION_TK}_${OS}_${ARCH}.tar.gz" + info "Downloading binary ${BIN_URL}" + download "${TMP_BIN}" "${BIN_URL}" +} + +compute_sha256sum() { + cmd=$(which sha256sum shasum | head -n 1) + case $(basename "$cmd") in + sha256sum) + sha256sum "$1" | cut -f 1 -d ' ' + ;; + shasum) + shasum -a 256 "$1" | cut -f 1 -d ' ' + ;; + *) + fatal "Can not find sha256sum or shasum to compute checksum" + ;; + esac +} + +# Verify downloaded binary hash +verify_binary() { + info "Verifying binary download" + HASH_BIN=$(compute_sha256sum "${TMP_BIN}") + HASH_BIN=${HASH_BIN%%[[:blank:]]*} + if [[ "${HASH_EXPECTED}" != "${HASH_BIN}" ]]; then + fatal "Download sha256 does not match ${HASH_EXPECTED}, got ${HASH_BIN}" + fi +} + +# Setup permissions and move binary +setup_binary() { + chmod 755 "${TMP_BIN}" + info "Installing tk to ${BIN_DIR}/tk" + tar -xzf "${TMP_BIN}" -C "${TMP_DIR}" + + local CMD_MOVE="mv -f \"${TMP_DIR}/tk\" \"${BIN_DIR}\"" + if [[ -w "${BIN_DIR}" ]]; then + eval "${CMD_MOVE}" + else + eval "sudo ${CMD_MOVE}" + fi +} + +# Run the install process +{ + setup_verify_os + setup_verify_arch + verify_downloader curl || verify_downloader wget || fatal 'Can not find curl or wget for downloading files' + setup_tmp + get_release_version + download_hash + download_binary + verify_binary + setup_binary +}