open-consul/test/load/packer/consul-ami/scripts/install-consul
2020-10-05 20:16:09 -05:00

313 lines
8.4 KiB
Bash
Executable file

#!/bin/bash
# SOURCE: GRUNTWORKS
# This script can be used to install Consul and its dependencies. This script has been tested with the following
# operating systems:
#
# 1. Ubuntu 16.04
# 1. Ubuntu 18.04
# 1. Amazon Linux 2
set -e
readonly DEFAULT_INSTALL_PATH="/opt/consul"
readonly DEFAULT_CONSUL_USER="consul"
readonly DOWNLOAD_PACKAGE_PATH="/tmp/consul.zip"
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly SYSTEM_BIN_DIR="/usr/local/bin"
readonly SCRIPT_NAME="$(basename "$0")"
function print_usage {
echo
echo "Usage: install-consul [OPTIONS]"
echo
echo "This script can be used to install Consul and its dependencies. This script has been tested with Ubuntu 16.04 and Amazon Linux 2."
echo
echo "Options:"
echo
echo -e " --version\t\tThe version of Consul to install. Optional if download-url is provided."
echo -e " --download-url\t\tUrl to exact Consul package to be installed. Optional if version is provided."
echo -e " --path\t\tThe path where Consul should be installed. Optional. Default: $DEFAULT_INSTALL_PATH."
echo -e " --user\t\tThe user who will own the Consul install directories. Optional. Default: $DEFAULT_CONSUL_USER."
echo -e " --ca-file-path\t\tPath to a PEM-encoded certificate authority used to encrypt and verify authenticity of client and server connections. Will be installed under <install-path>/tls/ca."
echo -e " --cert-file-path\t\tPath to a PEM-encoded certificate, which will be provided to clients or servers to verify the agent's authenticity. Will be installed under <install-path>/tls. Must be provided along with --key-file-path."
echo -e " --key-file-path\t\tPath to a PEM-encoded private key, used with the certificate to verify the agent's authenticity. Will be installed under <install-path>/tls. Must be provided along with --cert-file-path"
echo
echo "Example:"
echo
echo " install-consul --version 1.2.2"
}
function log {
local -r level="$1"
local -r message="$2"
local -r timestamp=$(date +"%Y-%m-%d %H:%M:%S")
>&2 echo -e "${timestamp} [${level}] [$SCRIPT_NAME] ${message}"
}
function log_info {
local -r message="$1"
log "INFO" "$message"
}
function log_warn {
local -r message="$1"
log "WARN" "$message"
}
function log_error {
local -r message="$1"
log "ERROR" "$message"
}
function assert_not_empty {
local -r arg_name="$1"
local -r arg_value="$2"
if [[ -z "$arg_value" ]]; then
log_error "The value for '$arg_name' cannot be empty"
print_usage
exit 1
fi
}
function assert_either_or {
local -r arg1_name="$1"
local -r arg1_value="$2"
local -r arg2_name="$3"
local -r arg2_value="$4"
if [[ -z "$arg1_value" && -z "$arg2_value" ]]; then
log_error "Either the value for '$arg1_name' or '$arg2_name' must be passed, both cannot be empty"
print_usage
exit 1
fi
}
# A retry function that attempts to run a command a number of times and returns the output
function retry {
local -r cmd="$1"
local -r description="$2"
for i in $(seq 1 5); do
log_info "$description"
# The boolean operations with the exit status are there to temporarily circumvent the "set -e" at the
# beginning of this script which exits the script immediatelly for error status while not losing the exit status code
output=$(eval "$cmd") && exit_status=0 || exit_status=$?
log_info "$output"
if [[ $exit_status -eq 0 ]]; then
echo "$output"
return
fi
log_warn "$description failed. Will sleep for 10 seconds and try again."
sleep 10
done;
log_error "$description failed after 5 attempts."
exit $exit_status
}
function has_yum {
[ -n "$(command -v yum)" ]
}
function has_apt_get {
[ -n "$(command -v apt-get)" ]
}
function install_dependencies {
log_info "Installing dependencies"
if $(has_apt_get); then
sudo apt-get update -y
sudo apt-get install -y awscli curl unzip jq
elif $(has_yum); then
sudo yum update -y
sudo yum install -y aws curl unzip jq
else
log_error "Could not find apt-get or yum. Cannot install dependencies on this OS."
exit 1
fi
}
function user_exists {
local -r username="$1"
id "$username" >/dev/null 2>&1
}
function create_consul_user {
local -r username="$1"
if $(user_exists "$username"); then
echo "User $username already exists. Will not create again."
else
log_info "Creating user named $username"
sudo useradd "$username"
fi
}
function create_consul_install_paths {
local -r path="$1"
local -r username="$2"
log_info "Creating install dirs for Consul at $path"
sudo mkdir -p "$path"
sudo mkdir -p "$path/bin"
sudo mkdir -p "$path/config"
sudo mkdir -p "$path/data"
sudo mkdir -p "$path/tls/ca"
log_info "Changing ownership of $path to $username"
sudo chown -R "$username:$username" "$path"
}
function fetch_binary {
local -r version="$1"
local download_url="$2"
if [[ -z "$download_url" && -n "$version" ]]; then
download_url="https://releases.hashicorp.com/consul/${version}/consul_${version}_linux_amd64.zip"
fi
retry \
"curl -o '$DOWNLOAD_PACKAGE_PATH' '$download_url' --location --silent --fail --show-error" \
"Downloading Consul to $DOWNLOAD_PACKAGE_PATH"
}
function install_binary {
local -r install_path="$1"
local -r username="$2"
local -r bin_dir="$install_path/bin"
local -r consul_dest_path="$bin_dir/consul"
local -r run_consul_dest_path="$bin_dir/run-consul"
unzip -d /tmp "$DOWNLOAD_PACKAGE_PATH"
log_info "Moving Consul binary to $consul_dest_path"
sudo mv "/tmp/consul" "$consul_dest_path"
sudo chown "$username:$username" "$consul_dest_path"
sudo chmod a+x "$consul_dest_path"
local -r symlink_path="$SYSTEM_BIN_DIR/consul"
if [[ -f "$symlink_path" ]]; then
log_info "Symlink $symlink_path already exists. Will not add again."
else
log_info "Adding symlink to $consul_dest_path in $symlink_path"
sudo ln -s "$consul_dest_path" "$symlink_path"
fi
log_info "Copying Consul run script to $run_consul_dest_path"
sudo cp "$SCRIPT_DIR/run-consul" "$run_consul_dest_path"
sudo chown "$username:$username" "$run_consul_dest_path"
sudo chmod a+x "$run_consul_dest_path"
}
function install_tls_certificates {
local -r path="$1"
local -r user="$2"
local -r ca_file_path="$3"
local -r cert_file_path="$4"
local -r key_file_path="$5"
local -r consul_tls_certs_path="$path/tls"
local -r ca_certs_path="$consul_tls_certs_path/ca"
log_info "Moving TLS certs to $consul_tls_certs_path and $ca_certs_path"
sudo mkdir -p "$ca_certs_path"
sudo mv "$ca_file_path" "$ca_certs_path/"
sudo mv "$cert_file_path" "$consul_tls_certs_path/"
sudo mv "$key_file_path" "$consul_tls_certs_path/"
sudo chown -R "$user:$user" "$consul_tls_certs_path/"
sudo find "$consul_tls_certs_path/" -type f -exec chmod u=r,g=,o= {} \;
}
function install {
local version=""
local download_url=""
local path="$DEFAULT_INSTALL_PATH"
local user="$DEFAULT_CONSUL_USER"
local ca_file_path=""
local cert_file_path=""
local key_file_path=""
while [[ $# > 0 ]]; do
local key="$1"
case "$key" in
--version)
version="$2"
shift
;;
--download-url)
download_url="$2"
shift
;;
--path)
path="$2"
shift
;;
--user)
user="$2"
shift
;;
--ca-file-path)
assert_not_empty "$key" "$2"
ca_file_path="$2"
shift
;;
--cert-file-path)
assert_not_empty "$key" "$2"
cert_file_path="$2"
shift
;;
--key-file-path)
assert_not_empty "$key" "$2"
key_file_path="$2"
shift
;;
--help)
print_usage
exit
;;
*)
log_error "Unrecognized argument: $key"
print_usage
exit 1
;;
esac
shift
done
assert_either_or "--version" "$version" "--download-url" "$download_url"
assert_not_empty "--path" "$path"
assert_not_empty "--user" "$user"
log_info "Starting Consul install"
install_dependencies
create_consul_user "$user"
create_consul_install_paths "$path" "$user"
fetch_binary "$version" "$download_url"
install_binary "$path" "$user"
if [[ -n "$ca_file_path" || -n "$cert_file_path" || -n "$key_file_path" ]]; then
install_tls_certificates "$path" "$user" "$ca_file_path" "$cert_file_path" "$key_file_path"
fi
if command -v consul; then
log_info "Consul install complete!";
else
log_info "Could not find consul command. Aborting.";
exit 1;
fi
}
install "$@"