Last active
October 27, 2024 17:58
-
-
Save anniethiessen/b046f013229b9448e94bf9e834c04864 to your computer and use it in GitHub Desktop.
Script file to prepare and deploy AWS ElasticBeanstalk applications.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| : ' | |
| Script file to prepare and deploy AWS ElasticBeanstalk applications. | |
| Ensure AWS EB CLI is installed and configured, | |
| define script variables, then execute script. | |
| First argument must be ElasticBeanstalk environment name, | |
| secondly optional option -c <configuration>, and | |
| all remaining options are passed to 'eb deploy' command. | |
| Accepts -v (verbose output) and -q (quiet output) arguments. | |
| Prerequisites: | |
| - awsebcli 3.20.10 -> https://pypi.org/project/awscli/ | |
| Script Variables: | |
| - CONDA_ENV: The conda environment that has required packages installed. | |
| Optional, if current environment has them installed. | |
| - APPLICATION_PATH: The path to the application root. | |
| Should be set if this script file is not in application root. | |
| Optional, defaults to null. | |
| - PERFORM_PREPARE: Whether to perform the ""prepare"" step. | |
| The ""prepare"" function prepares config files | |
| by copying them into application root from '.elasticbeanstalk/env_configs/env_name/'. | |
| This is useful if different environments have unique configurations. | |
| Should only be set to "false" if configuration files are already in their directories | |
| and in this case ""PERFORM_CLEAN"" should also be set to "false". | |
| Optional, defaults to "true". | |
| - PERFORM_DEPLOY: Whether to perform the ""deploy"" step. | |
| The ""deploy"" function deploys application to ElasticBeanstalk. | |
| Optional, defaults to "true". | |
| - PERFORM_CLEAN: Whether to perform the ""clean"" step. | |
| The ""clean"" function deletes configuration files copied in the ""prepare"" step. | |
| Should only be set to "false" if ""PERFORM_PREPARE"" is set to "false" | |
| Optional, defaults to "true". | |
| Usage Example: | |
| CONDA_ENV=xxx | |
| APPLICATION_PATH=xxx | |
| wget -cO - "<this_file_url>" > "temp.sh" | |
| chmod +x "temp.sh" | |
| source "temp.sh" "$@" | |
| rm -rf "temp.sh" | |
| ' | |
| #-------------------------------------------- | |
| #----------------- CONSTANTS ---------------- | |
| #-------------------------------------------- | |
| CONDA_ENV="${CONDA_ENV}" | |
| APPLICATION_PATH="${APPLICATION_PATH}" | |
| PERFORM_PREPARE=${PERFORM_PREPARE:-true} | |
| PERFORM_DEPLOY=${PERFORM_DEPLOY:-true} | |
| PERFORM_CLEAN=${PERFORM_CLEAN:-true} | |
| #------- DO NOT EDIT BELOW THIS LINE -------- | |
| FORMAT_SCRIPT_URL="https://gist.githubusercontent.com/anniethiessen/efb6bc0e52ccfc8b330aa41364b53e97/raw/0012edc1f009a36d196f03f09fda68e70691860b/shell_script_essentials.sh" | |
| FORMAT_SCRIPT_NAME="shell_script_essentials.sh" | |
| #-------------------------------------------- | |
| #--------------- FUNCTIONS ----------------- | |
| #-------------------------------------------- | |
| function set_opts { | |
| if [ $# -eq 0 ]; then | |
| echo "ElasticBeanstalk environment not specified." ${PROMPT_VERBOSE} | |
| exit 1 | |
| fi | |
| ENV=$1; shift; | |
| while getopts ":c:qv" flag; do | |
| case "${flag}" in | |
| c) CONFIG=${OPTARG}; shift 2;; | |
| q) OUTPUT_FLAG="-q"; shift;; | |
| v) OUTPUT_FLAG="-v"; shift;; | |
| *) | |
| esac | |
| done | |
| CONFIG="${CONFIG:-${ENV}}" | |
| OUTPUT_FLAG="${OUTPUT_FLAG:--q}" | |
| EB_OPTS=("$@") | |
| WORKING_PATH=$( pwd ) | |
| if [[ "${APPLICATION_PATH: -1}" == "/" ]]; then APPLICATION_PATH="${APPLICATION_PATH%?}"; fi | |
| if [[ "${APPLICATION_PATH:0:1}" == "/" ]]; then APPLICATION_PATH="${APPLICATION_PATH:1}"; fi | |
| if [[ -z "${APPLICATION_PATH}" ]]; then | |
| APPLICATION_PATH="${WORKING_PATH}" | |
| else APPLICATION_PATH="${WORKING_PATH}/${APPLICATION_PATH}"; fi | |
| } | |
| function activate_env { | |
| local retval | |
| output_info_message "Activating local environment '${CONDA_ENV}'." | |
| if [ -n "${CONDA_ENV}" ]; then | |
| eval "$(conda shell.bash hook)" | |
| conda activate "${CONDA_ENV}" | |
| fi | |
| retval=$? | |
| if [[ ${retval} -eq 0 ]]; then | |
| output_success_message "Local environment activated." | |
| else | |
| output_error_message "Local environment activation error." ${PROMPT_VERBOSE} | |
| exit_script | |
| fi | |
| if [[ "${OUTPUT}" == "${VERBOSE_OUTPUT}" ]]; then | |
| PYTHON_VERSION=$( python --version 2>&1 ) | |
| AWSEBCLI_VERSION=$( eb --version 2>&1 ) | |
| output_warning_message "Using ${PYTHON_VERSION} and ${AWSEBCLI_VERSION}" | |
| fi | |
| } | |
| function run_format_script { | |
| wget -cO - ${FORMAT_SCRIPT_URL} > ${FORMAT_SCRIPT_NAME} | |
| chmod +x ${FORMAT_SCRIPT_NAME} | |
| source ${FORMAT_SCRIPT_NAME} "$@" | |
| rm -rf ${FORMAT_SCRIPT_NAME} | |
| } | |
| function cancel_abort_clean_exit_trap { | |
| trap '' EXIT | |
| output_warning_message "Deployment to ElasticBeanstalk environment '${ENV}' cancelled." | |
| abort | |
| clean | |
| exit_script | |
| } | |
| function cancel_clean_trap { | |
| trap '' EXIT | |
| output_warning_message "Deployment to ElasticBeanstalk environment '${ENV}' cancelled." | |
| clean | |
| } | |
| function check_status { | |
| local ret status | |
| cd "${APPLICATION_PATH}" | |
| ret=$( eb status "${ENV}" ) | |
| if [[ "${ret}" == "ERROR: NotFoundError - Environment \"${ENV}\" not Found." ]]; then | |
| status="Not Found" | |
| else | |
| status=$( awk -F"Status: " '{print $2}' <<< "${ret}" ) | |
| status=$( echo "${status##*$'\n'}" ) | |
| status=$( sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' <<< "${status}" ) | |
| fi | |
| cd "${WORKING_PATH}" | |
| echo "${status}" | |
| } | |
| function abort { | |
| cd "${APPLICATION_PATH}" | |
| status=$( check_status ) | |
| if [[ "${status}" == "Updating" ]]; then | |
| output_warning_message "Aborting deployment to ElasticBeanstalk environment '${ENV}'." | |
| eb abort "${ENV}" &> ${OUTPUT} | |
| retval=$? | |
| if [[ ${retval} -eq 0 ]]; then | |
| output_success_message "Deployment aborted." | |
| else | |
| output_error_message "Abort deployment error." ${PROMPT_VERBOSE} | |
| fi | |
| fi | |
| cd "${WORKING_PATH}" | |
| } | |
| function prepare { | |
| if [ "${PERFORM_PREPARE}" == false ]; then | |
| output_warning_message "Preparation skipped" | |
| return | |
| fi | |
| local retval | |
| output_info_message "Copying config files '${CONFIG}'." | |
| cd "${APPLICATION_PATH}" | |
| trap cancel_clean_trap EXIT | |
| if [ -d ".elasticbeanstalk/env_configs/${CONFIG}/.ebextensions/" ]; then | |
| output_info_message "Copying '.ebextensions' config files from '${APPLICATION_PATH}/.elasticbeanstalk/env_configs/${CONFIG}/.ebextensions/'." | |
| cp -R ".elasticbeanstalk/env_configs/${CONFIG}/.ebextensions/." "${APPLICATION_PATH}/.ebextensions/" &> ${OUTPUT} | |
| retval=$? | |
| if [[ ${retval} -eq 0 ]]; then | |
| output_success_message "'.ebextensions' config files copied." | |
| else | |
| output_error_message "'.ebextensions' config file copy error." ${PROMPT_VERBOSE} | |
| exit_script | |
| fi | |
| else | |
| output_warning_message "'${APPLICATION_PATH}/.elasticbeanstalk/env_configs/${CONFIG}/.ebextensions/' directory does not exist, no files copied." | |
| fi | |
| if [ -d ".elasticbeanstalk/env_configs/${CONFIG}/.platform/" ]; then | |
| output_info_message "Copying '.platform' config files from '${APPLICATION_PATH}/.elasticbeanstalk/env_configs/${CONFIG}/.platform/'." | |
| cp -R ".elasticbeanstalk/env_configs/${CONFIG}/.platform/." "${APPLICATION_PATH}/.platform/" &> ${OUTPUT} | |
| retval=$? | |
| if [[ ${retval} -eq 0 ]]; then | |
| output_success_message "'.platform' config files copied." | |
| else | |
| output_error_message "'.platform' config file copy error." ${PROMPT_VERBOSE} | |
| exit_script | |
| fi | |
| else | |
| output_warning_message "'${APPLICATION_PATH}/.elasticbeanstalk/env_configs/${CONFIG}/.platform/' directory does not exist, no files copied." | |
| fi | |
| if [ -f ".elasticbeanstalk/env_configs/${CONFIG}/env.yaml" ]; then | |
| output_info_message "Copying 'env' config file '${APPLICATION_PATH}/.elasticbeanstalk/env_configs/${CONFIG}/env.yaml'." | |
| cp ".elasticbeanstalk/env_configs/${CONFIG}/env.yaml" "${APPLICATION_PATH}/env.yaml" &> ${OUTPUT} | |
| retval=$? | |
| if [[ ${retval} -eq 0 ]]; then | |
| output_success_message "'env.yaml' config file copied." | |
| else | |
| output_error_message "'env.yaml' config file copy error." ${PROMPT_VERBOSE} | |
| exit_script | |
| fi | |
| else | |
| output_warning_message "'${APPLICATION_PATH}/.elasticbeanstalk/env_configs/${CONFIG}/env.yaml' file does not exist, no file copied." | |
| fi | |
| if [ -f ".elasticbeanstalk/env_configs/${CONFIG}/requirements.txt" ]; then | |
| output_info_message "Copying 'requirements' config file '${APPLICATION_PATH}/.elasticbeanstalk/env_configs/${CONFIG}/requirements.txt'." | |
| cp ".elasticbeanstalk/env_configs/${CONFIG}/requirements.txt" "${APPLICATION_PATH}/requirements.txt" &> ${OUTPUT} | |
| retval=$? | |
| if [[ ${retval} -eq 0 ]]; then | |
| output_success_message "'requirements.txt' config file copied." | |
| else | |
| output_error_message "'requirements.txt' config file copy error." ${PROMPT_VERBOSE} | |
| exit_script | |
| fi | |
| else | |
| output_warning_message "'${APPLICATION_PATH}/.elasticbeanstalk/env_configs/${CONFIG}/requirements.txt' file does not exist, no file copied." | |
| fi | |
| if [ -f ".elasticbeanstalk/env_configs/${CONFIG}/.ebignore" ]; then | |
| output_info_message "Copying 'ebignore' config file '${APPLICATION_PATH}/.elasticbeanstalk/env_configs/${CONFIG}/.ebignore'." | |
| cp ".elasticbeanstalk/env_configs/${CONFIG}/.ebignore" "${APPLICATION_PATH}/.ebignore" &> ${OUTPUT} | |
| retval=$? | |
| if [[ ${retval} -eq 0 ]]; then | |
| output_success_message "'.ebignore' config file copied." | |
| else | |
| output_error_message "'.ebignore' config file copy error." ${PROMPT_VERBOSE} | |
| exit_script | |
| fi | |
| else | |
| output_warning_message "'${APPLICATION_PATH}/.elasticbeanstalk/env_configs/${CONFIG}/.ebignore' file does not exist, no file copied." | |
| fi | |
| cd "${WORKING_PATH}" | |
| } | |
| function deploy { | |
| if [ "${PERFORM_DEPLOY}" == false ]; then | |
| output_warning_message "Deploy skipped" | |
| return | |
| fi | |
| local rv retval create | |
| output_info_message "Deploying to ElasticBeanstalk environment '${ENV}'" | |
| trap cancel_clean_trap EXIT | |
| status=$( check_status ) | |
| if [[ "${status}" == "Ready" ]]; then | |
| output_info_message "ElasticBeanstalk environment '${ENV}' ready." | |
| create=false | |
| elif [[ "${status}" == "Not Found" ]]; then | |
| output_info_message "ElasticBeanstalk environment '${ENV}' will be created." | |
| create=true | |
| else | |
| output_error_message "ElasticBeanstalk environment '${ENV}' not ready, status is '${status}'." | |
| exit_script | |
| fi | |
| cd "${APPLICATION_PATH}" | |
| trap cancel_abort_clean_exit_trap SIGINT | |
| if [[ "${create}" == true ]]; then | |
| output_info_message "Running 'create' command with options:" | |
| output_info_message "${EB_OPTS[*]}" | |
| eb create "${ENV}" "${EB_OPTS[@]}" &> ${OUTPUT} | |
| else | |
| output_info_message "Running 'deploy' command with options:" | |
| output_info_message "${EB_OPTS[*]}" | |
| eb deploy "${ENV}" "${EB_OPTS[@]}" &> ${OUTPUT} | |
| fi | |
| retval=$? | |
| if [[ ${retval} -eq 0 ]]; then | |
| output_success_message "Application deployed." | |
| else | |
| output_error_message "Application deployment error." ${PROMPT_VERBOSE} | |
| exit_script | |
| fi | |
| cd "${WORKING_PATH}" | |
| } | |
| function clean { | |
| if [ "${PERFORM_CLEAN}" == false ]; then | |
| output_warning_message "Clean skipped" | |
| return | |
| fi | |
| local retval | |
| output_info_message "Deleting artifact config files." | |
| trap '' EXIT | |
| cd "${APPLICATION_PATH}" | |
| if [ -d ".elasticbeanstalk/env_configs/${CONFIG}/.ebextensions/" ]; then | |
| output_info_message "Deleting '.ebextensions' artifact config files in '${APPLICATION_PATH}/.ebextensions/'." | |
| rm -rf ".ebextensions/" &> ${OUTPUT} | |
| retval=$? | |
| if [[ ${retval} -eq 0 ]]; then | |
| output_success_message "'.ebextensions' artifact config files deleted." | |
| else | |
| output_error_message "'.ebextensions' artifact config file delete error." ${PROMPT_VERBOSE} | |
| fi | |
| else | |
| output_warning_message "'${APPLICATION_PATH}/.elasticbeanstalk/env_configs/${CONFIG}/.ebextensions/' directory does not exist, no files deleted." | |
| fi | |
| if [ -d ".elasticbeanstalk/env_configs/${CONFIG}/.platform/" ]; then | |
| output_info_message "Deleting '.platform' artifact config files in '${APPLICATION_PATH}/.platform/'." | |
| rm -rf ".platform/" &> ${OUTPUT} | |
| retval=$? | |
| if [[ ${retval} -eq 0 ]]; then | |
| output_success_message "'.platform' artifact config files deleted." | |
| else | |
| output_error_message "'.platform' artifact config file delete error." ${PROMPT_VERBOSE} | |
| fi | |
| else | |
| output_warning_message "'${APPLICATION_PATH}/.elasticbeanstalk/env_configs/${CONFIG}/.platform/' directory does not exist, no files deleted." | |
| fi | |
| if [ -f ".elasticbeanstalk/env_configs/${CONFIG}/env.yaml" ]; then | |
| output_info_message "Deleting 'env.yaml' artifact config file '${APPLICATION_PATH}/env.yaml'." | |
| rm -f "env.yaml" &> ${OUTPUT} | |
| retval=$? | |
| if [[ ${retval} -eq 0 ]]; then | |
| output_success_message "'env.yaml' artifact config file deleted." | |
| else | |
| output_error_message "'env.yaml' artifact config file delete error." ${PROMPT_VERBOSE} | |
| fi | |
| else | |
| output_warning_message "'${APPLICATION_PATH}/.elasticbeanstalk/env_configs/${CONFIG}/env.yaml' file does not exist, file not deleted." | |
| fi | |
| if [ -f ".elasticbeanstalk/env_configs/${CONFIG}/requirements.txt" ]; then | |
| output_info_message "Deleting 'requirements.txt' artifact config file '${APPLICATION_PATH}/requirements.txt'." | |
| rm -f "requirements.txt" &> ${OUTPUT} | |
| retval=$? | |
| if [[ ${retval} -eq 0 ]]; then | |
| output_success_message "'requirements.txt' artifact config file deleted." | |
| else | |
| output_error_message "'requirements.txt' artifact config file delete error." ${PROMPT_VERBOSE} | |
| fi | |
| else | |
| output_warning_message "'${APPLICATION_PATH}/.elasticbeanstalk/env_configs/${CONFIG}/requirements.txt' file does not exist, file not deleted." | |
| fi | |
| if [ -f ".elasticbeanstalk/env_configs/${CONFIG}/.ebignore" ]; then | |
| output_info_message "Deleting 'ebignore' artifact config file '${APPLICATION_PATH}/.ebignore'." | |
| rm -f ".ebignore" &> ${OUTPUT} | |
| retval=$? | |
| if [[ ${retval} -eq 0 ]]; then | |
| output_success_message "'.ebignore' artifact config file deleted." | |
| else | |
| output_error_message "'.ebignore' artifact config file delete error." ${PROMPT_VERBOSE} | |
| fi | |
| else | |
| output_warning_message "'${APPLICATION_PATH}/.elasticbeanstalk/env_configs/${CONFIG}/.ebignore' file does not exist, file not deleted." | |
| fi | |
| cd "${WORKING_PATH}" | |
| } | |
| #-------------------------------------------- | |
| #------------------ MAIN -------------------- | |
| #-------------------------------------------- | |
| set_opts "$@" | |
| run_format_script ${OUTPUT_FLAG} | |
| activate_env | |
| output_header_message "----------------------------------------" | |
| output_header_message "[1/3] PREPARE" | |
| output_header_message "preparing config artifact files ..." | |
| output_header_message "----------------------------------------" | |
| if [ "${PERFORM_PREPARE}" == true ] ; then | |
| prepare | |
| else output_warning_message "Preparation skipped"; fi | |
| output_header_message "----------------------------------------" | |
| output_header_message "[2/3] DEPLOY" | |
| output_header_message "deploying application to ElasticBeanstalk ..." | |
| output_header_message "----------------------------------------" | |
| if [ "${PERFORM_DEPLOY}" == true ] ; then | |
| deploy | |
| else output_warning_message "Deploy skipped"; fi | |
| output_header_message "----------------------------------------" | |
| output_header_message "[3/3] CLEAN" | |
| output_header_message "cleaning config artifact files ..." | |
| output_header_message "----------------------------------------" | |
| if [ "${PERFORM_CLEAN}" == true ] ; then | |
| clean | |
| else output_warning_message "Clean skipped"; fi |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Change Log:
v1: Initial
v2:
-feat: added CONDA_ENV variable: Conda environment is activated if defined (fixes v1 issue #1)
-fix: removed debug 'ls -a' command in ""deploy"" function (fixes v1 issue #2)
-fix: updated "Application Deployed" from warning message to success message (fixes v1 issue #3)
-fix: fixed incorrect directory in clean function (fixes v1 issue #4)
v3:
-update: "APPLICATION_PATH" can be null and include forward-slashes
-update: each function changes to required directory, in case only some functions are called
-fix: abort and clean trap on ctrl-c
-add: clean trap on exit
-update: check "PERFORM_*" variables inside functions in case they are called from other functions
-feat: add "activate_env" function
v4:
-feat: added create command if env does not exist
-reorganized config file prep & clean to .elasticbeanstalk/env_configs/
-add env.yaml and requirements.txt to config file prep and clean
v5:
-feat: ebignore file