#!/usr/bin/env bash # NB: local trial script has to be self-contained # See https://sipb.mit.edu/doc/safe-shell/ set -euf -o pipefail if [[ "$OSTYPE" == "linux-gnu" ]]; then export MAYBE_SUDO="sudo" else export MAYBE_SUDO="" fi if [ -t 1 ]; then export NORMAL="$(tput sgr0)" export RED="$(tput setaf 1)" export GREEN="$(tput setaf 2)" export MAGENTA="$(tput setaf 5)" export CYAN="$(tput setaf 6)" export WHITE="$(tput setaf 7)" export BOLD="$(tput bold)" else export NORMAL="" export RED="" export GREEN="" export MAGENTA="" export CYAN="" export WHITE="" export BOLD="" fi error_exit() { echo "${RED}${BOLD}ERROR${NORMAL}${BOLD}: $1${NORMAL}" shift while [ "$#" -gt "0" ]; do echo " - $1" shift done exit 1 } log_step() { echo '' echo "${GREEN}${BOLD}INFO${NORMAL}${BOLD}: $1${NORMAL}" shift while [ "$#" -gt "0" ]; do echo " - $1" shift done } log_warn() { echo '' echo "${GREEN}${BOLD}INFO${NORMAL}${BOLD}: $1${NORMAL}" shift while [ "$#" -gt "0" ]; do echo " - $1" shift done } export DISTRO=$( (lsb_release -ds || cat /etc/*release || uname -om) 2>/dev/null | head -n1) command_present() { type "$1" >/dev/null 2>&1 } retool_containers_present() { # NB: awk is to remove whitespace from `wc` RETOOL_IMAGES="$($MAYBE_SUDO docker image ls | grep 'retool.*onpremise' | wc -l | awk '{print $1}')" test "$RETOOL_IMAGES" -gt '0' } retool_trial_running() { # NB: awk is to remove whitespace from `wc` CONTAINERS="$($MAYBE_SUDO docker compose ps -q | wc -l | awk '{print $1}')" test "$CONTAINERS" -gt '0' } # NB: trim trailing slash on $TMPDIR as different OS's do it differently INSTALL_DIRECTORY="$HOME/retool" DOCKER_CONTEXT="$INSTALL_DIRECTORY/retool-onpremise" cd "$HOME" if [ ! -d "$DOCKER_CONTEXT" ]; then if [ -d "$INSTALL_DIRECTORY" ]; then log_step 'found a partial install, cleaning it up...' rm -rf "$INSTALL_DIRECTORY" fi log_step 'setting up install location...' "$INSTALL_DIRECTORY" mkdir retool && cd retool if ! command_present unzip; then log_warn '`unzip` not found!' log_warn 'Attempting to git clone instead' if command_present git; then log_step 'cloning...' git clone https://github.com/tryretool/retool-onpremise.git elif command_present yum; then log_warn 'You did not have git so installing' sudo yum install git git clone https://github.com/tryretool/retool-onpremise.git else error_exit "Please install git or unzip before continuing" fi else log_step 'downloading...' curl -L -XGET -o master.zip https://github.com/tryretool/retool-onpremise/archive/refs/heads/ssop.zip # TODO(hirday): change back to master log_step 'unpacking...' unzip master.zip mv retool-onpremise-ssop retool-onpremise # TODO(hirday): change back to master fi # NB: this is to make onprem containers to all get named the same. cd retool-onpremise if ! command_present unzip; then git checkout ssop # TODO(hirday): delete this. fi DOCKER_CONTEXT="$(pwd)" log_step 'setting environment variables' cp ./docker.env.trial docker.env read -p "Enter your license key: " licenseKey echo "LICENSE_KEY=$licenseKey" >> docker.env else cd "$DOCKER_CONTEXT" || error_exit "Couldn't \`cd\` into '$DOCKER_CONTEXT'" \ "if you are having repeat issues, you can \`rm -rf $INSTALL_DIRECTORY\`" \ "if you're still having issues, you can stop all docker containers using the \`docker\` command" fi if ! command_present docker; then # shellcheck disable=2016 log_warn '`docker` not found! Attempting to install. This may take a few minutes.' ./get-docker.sh if ! command_present docker; then if [[ "$OSTYPE" == "darwin"* ]]; then error_exit "please install \`docker\` manually" \ "Instructions can be found at ${WHITE}${BOLD}https://docs.docker.com/${NORMAL}" \ "${BOLD}Remember${NORMAL} to start the \`Docker\` app from the UI." else error_exit "please install \`docker\` manually" \ "Instructions can be found at ${WHITE}${BOLD}https://docs.docker.com/${NORMAL}" \ "${BOLD}Remember${NORMAL} to start the \`docker\` daemon/service." fi fi else # shellcheck disable=2016 log_step '`docker` found!' fi if [[ $DISTRO == *"CentOS"* ]]; then echo 'Starting docker service and making compose accessible by root user' sudo systemctl enable docker.service sudo systemctl start docker.service fi if retool_containers_present; then log_step 'noticed you have tried Retool before, cleaning up...' $MAYBE_SUDO docker compose rm -fsv fi if (! $MAYBE_SUDO docker stats --no-stream) && [ "$OSTYPE" == "linux-gnu" ] && [ "$DISTRO" != "*centos*" ]; then sudo docker service start fi if retool_trial_running; then log_step 'stopping Retool for update...' $MAYBE_SUDO docker compose down fi if [ ! -f ./docker-compose-ssl.yml ]; then mv docker-compose.yml docker-compose-ssl.yml fi if [ -f ./docker-compose-local-trial.yml ]; then mv docker-compose-local-trial.yml docker-compose.yml fi log_step 'updating Retool!' $MAYBE_SUDO docker compose pull log_step "running Retool! ${WHITE}${BOLD}This can take up to 5 minutes${NORMAL}" $MAYBE_SUDO docker compose up -d echo "" echo " -- ${GREEN}${BOLD}!! RETOOL IS BOOTING !!${NORMAL} --" # NB: the API doesn't start up the first time, this is why the below is complex WAITED=0 API_CONTAINER_ID="" api_container_up() { API_DOCKER_CONTAINER_UP=$($MAYBE_SUDO docker compose ps --filter "status=running" | grep 'retool.*api'| wc -l | awk '{print $1}') test "$API_DOCKER_CONTAINER_UP" -gt '0' } api_running() { healthcheck_response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/api/checkHealth) test $healthcheck_response -eq 200 } printf "%s%s%s%s" "Waiting for Retool to start up... " "${RED}${BOLD}" "" "$NORMAL" while [ $WAITED -lt 20 ] && api_container_up; do WAITED=$((WAITED + 1)) sleep 1 done if ! api_container_up; then $MAYBE_SUDO docker compose up -d > /dev/null 2>&1 WAITED=0 while [ $WAITED -lt 10 ] && ! api_container_up; do WAITED=$((WAITED + 1)) sleep 1 done fi # Due to a race condition with migration runner, check if api container stays up for 20 seconds. WAITED=0 while [ $WAITED -lt 20 ]; do if ! api_container_up; then $MAYBE_SUDO docker compose up -d > /dev/null 2>&1 fi WAITED=$((WAITED + 1)) sleep 1 done if ! api_container_up; then echo "ERROR: Failed starting the Retool api container" exit 1 else API_CONTAINER_ID=$( $MAYBE_SUDO docker inspect --format="{{.Id}}" $($MAYBE_SUDO docker compose ps | grep 'retool.*api' | cut -d ' ' -f 1) ) fi WAITED=0 # one request every three seconds. It takes about 40 seconds for the api to get ready so 2 minute should be enough margin while [ $WAITED -lt 40 ] && ! api_running; do WAITED=$((WAITED + 1)) # Breaking early if the container already failed due to error. if ! $($MAYBE_SUDO docker container inspect -f {{.State.Running}} $API_CONTAINER_ID ); then break fi sleep 3 done if ! api_running; then echo "There was an issue starting the Retool container" echo "You can view the logs by running: docker logs $API_CONTAINER_ID')" exit 1 fi # NB: empty stuff to fully wipe out previous line completely printf "\r%s%s%s%s%s%s%s%s" "$MAGENTA" 'Check out your ' "$BOLD" 'BROWSER' "${NORMAL}${MAGENTA}" ' for some awesomeness!!!' "$NORMAL" ' ' echo echo "" echo " ${CYAN}Navigate to${NORMAL}: ${WHITE}${BOLD}http://localhost:3000/auth/signup${NORMAL} or ${WHITE}${BOLD}[publically_accessible_ip]:3000/auth/signup${NORMAL}" echo " ${CYAN}To STOP Retool, run${NORMAL}: ${WHITE}${BOLD}${DOCKER_CONTEXT}/stop-local-trial${NORMAL}" echo " ${CYAN}To RESTART Retool, run${NORMAL}: ${WHITE}${BOLD}${DOCKER_CONTEXT}/local-trial${NORMAL}" echo "" echo "Retool was installed in ~/retool. It will run in the background until you manually stop it. If Retool stops you can restart it without losing your data. " if command_present open; then open 'http://localhost:3000/auth/signup' fi