Skip to content

Commit

Permalink
Automate Docker error handling in install script (#109)
Browse files Browse the repository at this point in the history
  • Loading branch information
alalamav authored Apr 27, 2018
1 parent e233989 commit 438528f
Showing 1 changed file with 143 additions and 11 deletions.
154 changes: 143 additions & 11 deletions src/server_manager/install_scripts/install_server.sh
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,17 @@ function run_step() {
fi
}

function confirm() {
echo -n "$1"
local RESPONSE
read RESPONSE
RESPONSE=$(echo "$RESPONSE" | tr '[A-Z]' '[a-z]')
if [[ -z "$RESPONSE" ]] || [[ "$RESPONSE" = "y" ]] || [[ "$RESPONSE" = "yes" ]]; then
return 0
fi
return 1
}

function command_exists {
command -v "$@" > /dev/null 2>&1
}
Expand All @@ -80,17 +91,109 @@ function log_for_sentry() {

# Check to see if docker is installed.
function verify_docker_installed() {
if ! command_exists docker; then
log_error "Docker CE must be installed, please run \"curl -sS https://get.docker.com/ | sh\" or visit https://docs.docker.com/install/"
if command_exists docker; then
return 0
fi
log_error "NOT INSTALLED"
echo -n
if ! confirm "> Would you like to install Docker? This will run 'curl -sS https://get.docker.com/ | sh'. [Y/n] "; then
exit 0
fi
if ! run_step "Installing Docker" install_docker; then
log_error "Docker installation failed, please visit https://docs.docker.com/install for instructions."
exit 1
fi
echo -n "> Verifying Docker installation................ "
command_exists docker
}

function verify_docker_running() {
if ! docker info > /dev/null 2>&1 ; then
log_error "It seems like you may not have permission to run Docker. To solve this, you may need to add your user to the docker group. We recommend running \"sudo usermod -a -G docker $USER && newgrp docker\" and then attempting to install again."
exit 1
local readonly STDERR_OUTPUT
STDERR_OUTPUT=$(safe_docker info 2>&1 >/dev/null)
local readonly RET=$?
if [[ $RET -eq 0 ]]; then
return 0
elif [[ $STDERR_OUTPUT = *"Is the docker daemon running"* ]]; then
start_docker
fi
}

function verify_docker_permissions() {
if user_in_docker_group; then
return 0
fi
log_error "FAILED"
local readonly PROMPT="> It seems like you may not have permission to run Docker. To solve this, we will attempt to add your user to the docker group by running 'sudo usermod -a -G docker $USER'. Would you like to proceed? [Y/n] "
if ! confirm "$PROMPT"; then
exit 0
fi
if run_step "Adding $USER to docker group" add_user_to_docker_group; then
echo -n "> Docker ready................................. "
else
log_error "FAILED"
return 1
fi
}

function install_docker() {
curl -sS https://get.docker.com/ | sh > /dev/null 2>&1
}

function user_in_docker_group() {
groups $USER | grep -E '(^|\s)docker(\s|$)' > /dev/null 2>&1
}

function add_user_to_docker_group() {
sudo usermod -a -G docker $USER
}

function start_docker() {
sudo systemctl start docker.service > /dev/null 2>&1
sudo systemctl enable docker.service > /dev/null 2>&1
}

# Runs commands in the docker group.
function safe_docker() {
sg docker -c "docker $@"
}

function docker_container_exists() {
safe_docker ps | grep $1 >/dev/null 2>&1
}

function remove_shadowbox_container() {
remove_docker_container shadowbox
}

function remove_watchtower_container() {
remove_docker_container watchtower
}

function remove_docker_container() {
safe_docker "rm -f $1" >/dev/null 2>&1
}

function handle_docker_container_conflict() {
local readonly CONTAINER_NAME=$1
local readonly EXIT_ON_NEGATIVE_USER_RESPONSE=$2
local PROMPT="> The container name \"$CONTAINER_NAME\" is already in use by another container. This may happen when running this script multiple times."
if $EXIT_ON_NEGATIVE_USER_RESPONSE; then
PROMPT="$PROMPT We will attempt to remove the existing container and restart it. Would you like to proceed? [Y/n] "
else
PROMPT="$PROMPT Would you like to replace this container? If you answer no, we will proceed with the remainder of the installation. [Y/n] "
fi
if ! confirm "$PROMPT"; then
if $EXIT_ON_NEGATIVE_USER_RESPONSE; then
exit 0
fi
return 0
fi
if run_step "Removing $CONTAINER_NAME container" remove_"$CONTAINER_NAME"_container ; then
echo -n "> Restarting $CONTAINER_NAME ........................ "
start_"$CONTAINER_NAME"
return $?
fi
return 1
}

# Set trap which publishes error tag only if there is an error.
Expand Down Expand Up @@ -168,17 +271,43 @@ function start_shadowbox() {
-e "SB_METRICS_URL=${SB_METRICS_URL:-}"
-e "SB_DEFAULT_SERVER_NAME=${SB_DEFAULT_SERVER_NAME:-}"
)
docker run -d "${docker_shadowbox_flags[@]}" "${SB_IMAGE}" >/dev/null
local readonly RUN_DOCKER_ARGS="run -d ${docker_shadowbox_flags[@]} ${SB_IMAGE}"
local readonly STDERR_OUTPUT
STDERR_OUTPUT=$(safe_docker "$RUN_DOCKER_ARGS" 2>&1 >/dev/null)
local readonly RET=$?
if [[ $RET -eq 0 ]]; then
return 0
fi
log_error "FAILED"
if docker_container_exists shadowbox; then
handle_docker_container_conflict shadowbox true
else
log_error "$STDERR_OUTPUT"
return 1
fi
}

function start_watchtower() {
# Start watchtower to automatically fetch docker image updates.
# Set watchtower to refresh every 30 seconds if a custom SB_IMAGE is used (for
# testing). Otherwise refresh every hour.
readonly WATCHTOWER_REFRESH_SECONDS="${WATCHTOWER_REFRESH_SECONDS:-3600}"
local WATCHTOWER_REFRESH_SECONDS="${WATCHTOWER_REFRESH_SECONDS:-3600}"
declare -a docker_watchtower_flags=(--name watchtower --restart=always)
docker_watchtower_flags+=(-v /var/run/docker.sock:/var/run/docker.sock)
docker run -d "${docker_watchtower_flags[@]}" v2tec/watchtower --cleanup --tlsverify --interval $WATCHTOWER_REFRESH_SECONDS >/dev/null
local readonly RUN_DOCKER_ARGS="run -d ${docker_watchtower_flags[@]} v2tec/watchtower --cleanup --tlsverify --interval $WATCHTOWER_REFRESH_SECONDS"
local readonly STDERR_OUTPUT
STDERR_OUTPUT=$(safe_docker "$RUN_DOCKER_ARGS" 2>&1 >/dev/null)
local readonly RET=$?
if [[ $RET -eq 0 ]]; then
return 0
fi
log_error "FAILED"
if docker_container_exists watchtower; then
handle_docker_container_conflict watchtower false
else
log_error "$STDERR_OUTPUT"
return 1
fi
}

# Waits for Shadowbox to be up and healthy
Expand All @@ -201,9 +330,11 @@ function add_api_url_to_config() {
}

function check_firewall() {
local -r ACCESS_KEY_PORT=$(docker exec shadowbox node -e "console.log($(curl --insecure -s ${LOCAL_API_URL}/access-keys)['accessKeys'][0]['port'])")
local readonly GET_ACCESS_KEYS=$(curl --insecure -s ${LOCAL_API_URL}/access-keys)
local readonly GET_ACCESS_KEY_PORT="exec shadowbox node -e 'console.log($GET_ACCESS_KEYS[\"accessKeys\"][0][\"port\"])'"
local -r ACCESS_KEY_PORT=$(safe_docker "$GET_ACCESS_KEY_PORT")
if ! curl --max-time 5 --cacert "${SB_CERTIFICATE_FILE}" -s "${PUBLIC_API_URL}/access-keys" >/dev/null; then
echo "BLOCKED"
log_error "BLOCKED"
FIREWALL_STATUS="\
You won’t be able to access it externally, despite your server being correctly
set up, because there's a firewall (in this machine, your router or cloud
Expand All @@ -218,7 +349,7 @@ ${ACCESS_KEY_PORT}.
"
else
FIREWALL_STATUS="\
If have connection problems, it may be that your router or cloud provider
If you have connection problems, it may be that your router or cloud provider
blocks inbound connections, even though your machine seems to allow them.
- If you plan to have a single access key to access your server make sure
Expand All @@ -233,6 +364,7 @@ blocks inbound connections, even though your machine seems to allow them.

install_shadowbox() {
run_step "Verifying that Docker is installed" verify_docker_installed
run_step "Verifying Docker permissions" verify_docker_permissions
run_step "Verifying that Docker daemon is running" verify_docker_running

log_for_sentry "Creating shadowbox directory"
Expand Down

0 comments on commit 438528f

Please sign in to comment.