#!/usr/bin/env bash

set -e -o pipefail

# Bootstrap host with Chef and apply Orchard workflow, roughly outlined as follows:
## 1. Bootstrap host from workstation
## 2. Update node definition file on Chef server
## 3. Add encryption secrets for encrypted data bags
  ## a. if -e is specified, also copy over AWS SSM encryption secret
## 4. Run chef on the node after node definition has been updated
## 5. Delete or leave encryption secret, depending on future needs. 

# Global variables
CHEF_REPO_DIRECTORY=$(dirname -- "$0")
CHEF_SECRET_DIRECTORY="${CHEF_REPO_DIRECTORY}/.chef/"
ECS_ANYWHERE=false
KNIFE_BINARY=$(/usr/bin/which knife)
DELETE_SECRET=false
SECRET_FILES=('encrypted_data_bag_secret')
SPLUNK_SHEET_ADD=true
SSH_USER='root'
SSH_OPTS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
CHEF_BOOTSTRAP_VERSION=''

function bootstrap_host { 
  # Bootstrap the host accordingly. 

  if [ -n "${SSH_KEY}" ]; then
    printf '%s\n'
    printf '%s\n' "SSH key specified"
    SCP_COMMAND="scp -i ${SSH_KEY} ${SSH_OPTS}"
    SSH_COMMAND="ssh -i ${SSH_KEY} ${SSH_OPTS}"
    KNIFE_SSH_COMMAND="-i ${SSH_KEY}"
  else
    SCP_COMMAND="scp ${SSH_OPTS}"
    SSH_COMMAND="ssh ${SSH_OPTS}"
    KNIFE_SSH_COMMAND=''
  fi

  if [ -n "${HOST_USER}" ]; then
    SSH_USER=${HOST_USER}
  fi

  if [ -n "${CHEF_CLIENT_VERSION}" ]; then
    printf '%s\n'
    printf '%s\n' "Chef client version ${CHEF_CLIENT_VERSION} specified"
    CHEF_BOOTSTRAP_VERSION=" --bootstrap-version ${CHEF_CLIENT_VERSION}"
  fi

  [ "${VERBOSE}" = true ] && printf '%s\n' "Running initial knife commands"
    
  KNIFE_COMMAND_STRING="${KNIFE_BINARY} bootstrap -y ${BOOTSTRAP_IP} ${CHEF_BOOTSTRAP_VERSION} -x ${SSH_USER} ${KNIFE_SSH_COMMAND} -N ${BOOTSTRAP_HOSTNAME} --sudo"

  if $(${KNIFE_BINARY} node show ${BOOTSTRAP_HOSTNAME} 2>&1 | grep -iq "Node Name" > /dev/null); then 
    printf '%s\n'
    printf '%s\n' "${BOOTSTRAP_HOSTNAME} is already an active Chef-managed host. Here is its current configuration:"
    ${KNIFE_BINARY} node show ${BOOTSTRAP_HOSTNAME} && exit 0
  else
    [ "${VERBOSE}" = true ] && printf '%s\n' "Host not found. I will now bootstrap it..."
  fi

  ${KNIFE_COMMAND_STRING}

  # Add node definition file. This assumes you have configured one with the appropriate role and details
  NODE_DEFINITION_FILE=$(find "${CHEF_REPO_DIRECTORY}" -type f -name "*${BOOTSTRAP_HOSTNAME}*")
  if [ -f "${NODE_DEFINITION_FILE}" ]; then
    printf "%s\n Uploading node definition file from ${NODE_DEFINITION_FILE}"
    ${KNIFE_BINARY} node from file "${NODE_DEFINITION_FILE}"
  else
    printf '%s\n'
    printf '%s\n' "Node file not found in ${CHEF_REPO_DIRECTORY}. Please create a corresponding node file matching the hostname."
    exit 1
  fi

  if [ "${ECS_ANYWHERE}" = true ]; then
    SECRET_FILES+=('ssm_activation_encryption_secret')
  fi

  # Now temporarily copy over secret files
  printf '%s\n'
  printf '%s\n' "Copying secret file to node. You may be prompted for the node's ${SSH_USER} password one or more times..."
  printf '%s\n'
  for SECRET_FILE in "${SECRET_FILES[@]}"; do
    cat ${CHEF_SECRET_DIRECTORY}/${SECRET_FILE} | ${SSH_COMMAND} ${SSH_USER}@${BOOTSTRAP_IP} "sudo tee /etc/chef/${SECRET_FILE} >/dev/null" && printf '%s\n' "${SECRET_FILE} copied to node Chef directory"
  done

# Add temp user-data script 
cat << EOF > temp.sh
sudo chef-client
EOF

  if [ "${DELETE_SECRET}" = true ]; then
    printf '%s\n'
    printf '%s\n' "Removing encryption secret..."
    for SECRET_FILE in "${SECRET_FILES[@]}"; do
      echo "rm -rf /etc/chef/${SECRET_FILE}" >> temp.sh
    done
  else
    printf '%s\n' "Leaving encryption secrets for future client runs. You must now manually manage them."
  fi
  chmod +x temp.sh

  printf '%s\n' "Running chef-client to converge based on its updated node definition. You may be prompted for the node's ${SSH_USER} password one or more times..."
  printf '%s\n'
  ${SCP_COMMAND} temp.sh ${SSH_USER}@${BOOTSTRAP_IP}:/tmp && printf '%s\n' "Script file copied to node tmp directory"
  printf '%s\n'
  echo "/tmp/temp.sh" | ${SSH_COMMAND} ${SSH_USER}@${BOOTSTRAP_IP}

  rm -rf temp.sh

  if [ "${SPLUNK_SHEET_ADD}" = true ]; then
    printf '%s\n'
    printf '%s\n' "Adding to splunk host spreadsheet for GSIRT..."
    ${KNIFE_BINARY} exec ${CHEF_REPO_DIRECTORY}/splunk_host_list/generate_splunk_spreadsheet.rb ${BOOTSTRAP_HOSTNAME}
  else
    printf '%s\n' "Not adding to splunk host spreadsheet, since -s was passed in to the script."
  fi
}

while getopts 'c:eh:i:k:su:v' flag; do
  case "${flag}" in
  c) CHEF_CLIENT_VERSION="${OPTARG}" ;;
  e) ECS_ANYWHERE=true ;;
  h) BOOTSTRAP_HOSTNAME="${OPTARG}" ;;
  i) BOOTSTRAP_IP="${OPTARG}" ;;
  k) SSH_KEY="${OPTARG}" ;;
  s) SPLUNK_SHEET_ADD=false ;;
  u) HOST_USER="${OPTARG}" ;;
  v) VERBOSE=true && printf '%s\n' "Verbose output enabled" ;;
  *) printf "Unexpected option ${flag}\n"
     exit 1 ;;
  esac
done

[ -n "${BOOTSTRAP_HOSTNAME}" ] && [ -n "${BOOTSTRAP_IP}" ] && bootstrap_host
