#!/usr/bin/env bash # must be run from e2e directory set -o errexit set -o nounset set -o pipefail tfstatefile="terraform/terraform.tfstate" # Make sure we are running from the e2e/ directory [ "$(basename "$(pwd)")" == "e2e" ] || (echo "must be run from nomad/e2e directory" && exit 1) # Make sure one argument was provided (subcommand) [ ${#} -eq 1 ] || (echo "expect one argument (subcommand)" && exit 1) # Make sure terraform state file exists [ -f "${tfstatefile}" ] || (echo "file ${tfstatefile} must exist (run terraform?)" && exit 1) # Load Linux Client Node IPs from terraform state file linux_clients=$(jq -r .outputs.linux_clients.value[] <"${tfstatefile}" | xargs) # Load Windows Client Node IPs from terraform state file windows_clients=$(jq -r .outputs.windows_clients.value[] <"${tfstatefile}" | xargs) # Combine all the clients together clients="${linux_clients} ${windows_clients}" # Load Server Node IPs from terraform/terraform.tfstate servers=$(jq -r .outputs.servers.value[] <"${tfstatefile}" | xargs) # Use the 0th server as the ACL bootstrap server server0=$(echo "${servers}" | cut -d' ' -f1) # Find the .pem file to use pemfile="terraform/$(jq -r '.resources[] | select(.name=="private_key_pem") | .instances[0].attributes.filename' <"terraform/terraform.tfstate")" # See AWS service file consul_configs="/etc/consul.d" nomad_configs="/etc/nomad.d" # Not really present in the config user=ubuntu # Create a filename based on the TF state file (.serial), where we will store and/or # lookup the consul master token. The presense of this file is what determines # whether a full ACL bootstrap must occur, or if we only need to activate ACLs # whenever the "enable" sub-command is chosen. token_file="/tmp/e2e-consul-bootstrap-$(jq .serial <${tfstatefile}).token" # One argument - the subcommand to run which may be: bootstrap, enable, or disable subcommand="${1}" echo "==== SETUP configuration =====" echo "SETUP command is: ${subcommand}" echo "SETUP token file: ${token_file}" echo "SETUP servers: ${servers}" echo "SETUP linux clients: ${linux_clients}" echo "SETUP windows clients: ${windows_clients}" echo "SETUP pem file: ${pemfile}" echo "SETUP consul configs: ${consul_configs}" echo "SETUP nomad configs: ${nomad_configs}" echo "SETUP aws user: ${user}" echo "SETUP bootstrap server: ${server0}" function doSSH() { hostname="$1" command="$2" echo "-----> will ssh command '${command}' on ${hostname}" ssh \ -o StrictHostKeyChecking=no \ -o UserKnownHostsFile=/dev/null \ -i "${pemfile}" \ "${user}@${hostname}" "${command}" } function doSCP() { original="$1" username="$2" hostname="$3" destination="$4" echo "------> will scp ${original} to ${hostname}" scp \ -o StrictHostKeyChecking=no \ -o UserKnownHostsFile=/dev/null \ -i "${pemfile}" \ "${original}" "${username}@${hostname}:${destination}" } function doBootstrap() { echo "=== Bootstrap: Consul Configs ===" # Stop all Nomad agents. stopNomad # Stop all Consul agents. stopConsul # Run the activation step, which uploads the ACLs-enabled acl.hcl file # to each Consul configuration directory, then (re)starts each # Consul agent. doActivate echo "=== Bootstrap: Consul ACL Bootstrap ===" # Bootstrap Consul ACLs on server[0] echo "-> bootstrap ACL using ${server0}" consul_http_token=$(doSSH "${server0}" "/usr/local/bin/consul acl bootstrap" | grep SecretID | awk '{print $2}') consul_http_addr="http://${server0}:8500" export CONSUL_HTTP_TOKEN=${consul_http_token} export CONSUL_HTTP_ADDR=${consul_http_addr} echo " consul http: ${CONSUL_HTTP_ADDR}" echo " consul root: ${CONSUL_HTTP_TOKEN}" echo "${CONSUL_HTTP_TOKEN}" > "${token_file}" # Create Consul Server Policy & Consul Server agent tokens echo "-> configure consul server policy" consul acl policy create -name server-policy -rules @consulacls/consul-server-policy.hcl # Create & Set agent token for each Consul Server for server in ${servers}; do echo "---> will create agent token for server ${server}" server_agent_token=$(consul acl token create -description "consul server agent token" -policy-name server-policy | grep SecretID | awk '{print $2}') echo "---> setting token for server agent: ${server} -> ${server_agent_token}" (export CONSUL_HTTP_ADDR="${server}:8500"; consul acl set-agent-token agent "${server_agent_token}") echo "---> done setting agent token for server ${server}" done # Wait 10s before continuing with configuring consul clients. echo "-> sleep 10s before continuing with clients" sleep 10 # Create Consul Client Policy & Client agent tokens echo "-> configure consul client policy" consul acl policy create -name client-policy -rules @consulacls/consul-client-policy.hcl # Create & Set agent token for each Consul Client (excluding Windows) for linux_client in ${linux_clients}; do echo "---> will create consul agent token for client ${linux_client}" client_agent_token=$(consul acl token create -description "consul client agent token" -policy-name client-policy | grep SecretID | awk '{print $2}') echo "---> setting consul token for consul client ${linux_client} -> ${client_agent_token}" (export CONSUL_HTTP_ADDR="${linux_client}:8500"; consul acl set-agent-token agent "${client_agent_token}") echo "---> done setting consul agent token for client ${linux_client}" done echo "=== Bootstrap: Nomad Configs ===" # Create Nomad Server consul Policy and Nomad Server consul tokens echo "-> configure nomad server policy & consul token" consul acl policy create -name nomad-server-policy -rules @consulacls/nomad-server-policy.hcl nomad_server_consul_token=$(consul acl token create -description "nomad server consul token" -policy-name nomad-server-policy | grep SecretID | awk '{print $2}') nomad_server_consul_token_tmp=$(mktemp) cp consulacls/nomad-server-consul.hcl "${nomad_server_consul_token_tmp}" sed -i "s/CONSUL_TOKEN/${nomad_server_consul_token}/g" "${nomad_server_consul_token_tmp}" for server in ${servers}; do echo "---> upload nomad-server-consul.hcl to ${server}" doSCP "${nomad_server_consul_token_tmp}" "${user}" "${server}" "/tmp/nomad-server-consul.hcl" doSSH "${server}" "sudo mv /tmp/nomad-server-consul.hcl ${nomad_configs}/nomad-server-consul.hcl" done # Create Nomad Client consul Policy and Nomad Client consul token echo "-> configure nomad client policy & consul token" consul acl policy create -name nomad-client-policy -rules @consulacls/nomad-client-policy.hcl nomad_client_consul_token=$(consul acl token create -description "nomad client consul token" -policy-name nomad-client-policy | grep SecretID | awk '{print $2}') nomad_client_consul_token_tmp=$(mktemp) cp consulacls/nomad-client-consul.hcl "${nomad_client_consul_token_tmp}" sed -i "s/CONSUL_TOKEN/${nomad_client_consul_token}/g" "${nomad_client_consul_token_tmp}" for linux_client in ${linux_clients}; do echo "---> upload nomad-client-token.hcl to ${linux_client}" doSCP "${nomad_client_consul_token_tmp}" "${user}" "${linux_client}" "/tmp/nomad-client-consul.hcl" doSSH "${linux_client}" "sudo mv /tmp/nomad-client-consul.hcl ${nomad_configs}/nomad-client-consul.hcl" done startNomad export NOMAD_ADDR="http://${server0}:4646" echo "=== Activate: DONE ===" } function doEnable() { if [ ! -f "${token_file}" ]; then echo "ENABLE: token file does not exist, doing a full ACL bootstrap" doBootstrap else echo "ENABLE: token file already exists, will activate ACLs" doActivate fi echo "=== Enable: DONE ===" # show the status of all the agents echo "---> token file is ${token_file}" consul_http_token=$(cat "${token_file}") export CONSUL_HTTP_TOKEN="${consul_http_token}" echo "export CONSUL_HTTP_TOKEN=${CONSUL_HTTP_TOKEN}" doStatus } function doDisable() { if [ ! -f "${token_file}" ]; then echo "DISABLE: token file does not exist, did bootstrap ever happen?" exit 1 else echo "DISABLE: token file exists, will deactivate ACLs" doDeactivate fi echo "=== Disable: DONE ===" # show the status of all the agents unset CONSUL_HTTP_TOKEN doStatus } function doActivate() { echo "=== Activate ===" stopConsul # Upload acl-enable.hcl to each Consul agent's configuration directory. for agent in ${servers} ${linux_clients}; do echo " activate: upload acl-enable.hcl to ${agent}::acl.hcl" doSCP "consulacls/acl-enable.hcl" "${user}" "${agent}" "/tmp/acl.hcl" doSSH "${agent}" "sudo mv /tmp/acl.hcl ${consul_configs}/acl.hcl" done # Restart each Consul agent to pickup the new config. for agent in ${servers} ${linux_clients}; do echo " activate: restart Consul agent on ${agent} ..." doSSH "${agent}" "sudo systemctl start consul" sleep 1 done sleep 10 echo "=== Activate: DONE ===" } function stopNomad { echo "=== Stop Nomad agents ===" # Stop every Nomad agent (clients and servers) in preperation for Consul ACL # bootstrapping. for server in ${servers}; do echo " stop Nomad Server on ${server}" doSSH "${server}" "sudo systemctl stop nomad" sleep 1 done for linux_client in ${linux_clients}; do echo " stop Nomad Client on ${linux_client}" doSSH "${linux_client}" "sudo systemctl stop nomad" sleep 1 done echo "... all nomad agents stopped" } function startNomad { echo "=== Start Nomad agents ===" # Start every Nomad agent (clients and servers) after having Consul ACL # bootstrapped and configurations set for Nomad. for server in ${servers}; do echo " start Nomad Server on ${server}" doSSH "${server}" "sudo systemctl start nomad" sleep 1 done # give the servers a chance to settle sleep 10 for linux_client in ${linux_clients}; do echo " start Nomad Client on ${linux_client}" doSSH "${linux_client}" "sudo systemctl start nomad" sleep 3 done # give the clients a long time to settle sleep 30 echo "... all nomad agents started" } function stopConsul { echo "=== Stop Consul agents ===" # Stop every Nonsul agent (clients and servers) in preperation for Consul ACL # bootstrapping. for server in ${servers}; do echo " stop Consul Server on ${server}" doSSH "${server}" "sudo systemctl stop consul" sleep 1 done for linux_client in ${linux_clients}; do echo " stop Consul Client on ${linux_client}" doSSH "${linux_client}" "sudo systemctl stop consul" sleep 1 done echo "... all consul agents stopped" } function startConsulClients { echo "=== Start Consul Clients ===" # Start Consul Clients for linux_client in ${linux_clients}; do echo " start Consul Client on ${linux_client}" doSSH "${linux_client}" "sudo systemctl start consul" sleep 2 done sleep 5 # let them settle echo "... all consul clients started" } function doDeactivate { echo "=== Deactivate ===" # Upload acl-disable.hcl to each Consul Server agent's configuration directory. for server in ${servers}; do echo " deactivate: upload acl-disable.hcl to ${server}::acl.hcl" doSCP "consulacls/acl-disable.hcl" "${user}" "${server}" "/tmp/acl.hcl" doSSH "${server}" "sudo mv /tmp/acl.hcl ${consul_configs}/acl.hcl" done # Restart each Consul server agent to pickup the new config. for server in ${servers}; do echo " deactivate: restart Consul Server on ${server} ..." doSSH "${server}" "sudo systemctl restart consul" sleep 3 # let the agent settle done # Wait 10s before moving on, Consul needs a second to calm down. echo " deactivate: sleep 10s ..." sleep 10 } function doStatus { # assumes CONSUL_HTTP_TOKEN is set (or not) echo "consul members" consul members echo "" echo "nomad server members" nomad server members echo "" echo "nomad node status" nomad node status echo "" } # It's the entrypoint to our script! case "${subcommand}" in bootstrap) # The bootstrap target exists to make some local development easier. Test # cases running from the e2e framework should always use "enable" which aims # to be idempotent. doBootstrap ;; enable) doEnable ;; disable) doDisable ;; *) echo "incorrect subcommand ${subcommand}" exit 1 ;; esac