From 4f886c5eaba83e92adb62212d9a35bb7cc627595 Mon Sep 17 00:00:00 2001 From: ju-ponectus Date: Mon, 13 Feb 2017 11:35:55 +0100 Subject: [PATCH 1/7] First step: acheve all the tasks dealing with EC2 instance setup --- aws-app.sh | 165 +++++++++++++++++++++++++++++++++++++++ inc/aws.sh | 136 ++++++++++++++++++++++++++++++++ inc/funcs.sh | 77 ++++++++++++++++++ resources/nginx/helloapp | 14 ++++ 4 files changed, 392 insertions(+) create mode 100755 aws-app.sh create mode 100755 inc/aws.sh create mode 100755 inc/funcs.sh create mode 100644 resources/nginx/helloapp diff --git a/aws-app.sh b/aws-app.sh new file mode 100755 index 0000000..187d70a --- /dev/null +++ b/aws-app.sh @@ -0,0 +1,165 @@ +#!/bin/bash + +# Basic Python app git parameters +BASIC_APP_URL=https://github.com/wvchallenges/opseng-challenge-app +BASIC_APP_DEFAULT_BRANCH=master +BASIC_APP_DEFAULT_TAG=HEAD + +# SSH Key Pair name +KEY_PAIR_NAME=HelloAppKey + +# Security group +SECGRP_NAME=HelloAppSecGrp +SECGRP_DESC="Security group for Hello App access" +SECGRP_RULES_PORT=( 22 80 ) + +# Base Nginx configuration to use for app publication +NGINX_TEMPLATE=resources/nginx/helloapp + +# AWS EC2 Instance parameters +AWS_EC2_INSTANCE_TYPE=t2.micro +AWS_EC2_INSTANCE_TAG_NAME=usage +AWS_EC2_INSTANCE_TAG_VALUE=opseng-challenge-lamure + +# Ubuntu Xenial Amazon image +AWS_EC2_UBUNTU_AMI_ID=ami-539ac933 +AWS_EC2_UBUNTU_LOGIN=ubuntu + +# SSH EC2 Instance +SSH_CMD="ssh -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/${KEY_PAIR_NAME}.pem -l ${AWS_EC2_UBUNTU_LOGIN}" + +# Get this script install dir +SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" + +source "$SCRIPT_DIR/inc/funcs.sh" +source "$SCRIPT_DIR/inc/aws.sh" + +echoStep "Starting HelloApp deployment" + +# 1- Manage SSH key pair +echoStep "Manage SSH key pair" +checkKeypair ${KEY_PAIR_NAME} +if [ $? -ne 0 ]; then + echoWarning "${KEY_PAIR_NAME} key pair does not exist. We are going to create it." + createAndInstallKeypair ${KEY_PAIR_NAME} + if [ $? -ne 0 ]; then + echoError "Could not create and install new key pair. Exiting." + exit 1 + fi +else + echoSuccess "${KEY_PAIR_NAME} key pair already exists." + if [ ! -f ~/.ssh/${KEY_PAIR_NAME}.pem ]; then + echoWarning "Private key file does not exist locally. We are going to recreate key pair." + deleteKeypair ${KEY_PAIR_NAME} + if [ $? -ne 0 ]; then + echoError "Could not delete existing key pair. Exiting." + exit 1 + fi + createAndInstallKeypair ${KEY_PAIR_NAME} + if [ $? -ne 0 ]; then + echoError "Could not create and install new key pair. Exiting." + exit 1 + fi + fi +fi + +# 2- Manage security group +echoStep "Manage security group" +CREATE_RULES=0 +checkSecGrp ${SECGRP_NAME} +if [ $? -ne 0 ]; then + echoWarning "${SECGRP_NAME} security group does not exist. We are going to create it." + createSecGrp ${SECGRP_NAME} "${SECGRP_DESC}" + if [ $? -ne 0 ]; then + echoError "Could not create security group. Exiting." + exit 1 + fi + CREATE_RULES=1 +else + echoSuccess "${SECGRP_NAME} security group already exists. Will check rules to be sure they exist." + CREATE_RULES=1 +fi + +if [ $CREATE_RULES -eq 1 ]; then + for i in "${SECGRP_RULES_PORT[@]}" + do + createSecGrpRule ${SECGRP_NAME} ${i} + if [ $? -ne 0 ]; then + echoError "Could not create inbound rule for port ${i}. Exiting." + exit 1 + fi + done +fi + +# 3- Create EC2 instance +echoStep "Create EC2 instance" +checkInstance ${AWS_EC2_INSTANCE_TAG_NAME} ${AWS_EC2_INSTANCE_TAG_VALUE} +if [ $? -eq 0 ]; then + echoInfo "EC2 instance already exists. We are going to try to ssh it." + INSTANCE_ID=$(getInstanceId ${AWS_EC2_INSTANCE_TAG_NAME} ${AWS_EC2_INSTANCE_TAG_VALUE}) + if [ $? -ne 0 ]; then + echoError "Could not get EC2 instance ID" + exit 1 + fi + INSTANCE_PUBLIC_DNS_NAME=$(getInstancePublicDnsName ${INSTANCE_ID}) + if [ $? -ne 0 ]; then + echoError "Could not get EC2 instance public DNS name" + exit 1 + fi + echoInfo "Existing EC2 instance public DNS name: ${INSTANCE_PUBLIC_DNS_NAME}" + ${SSH_CMD} ${INSTANCE_PUBLIC_DNS_NAME} exit + if [ $? -ne 0 ]; then + echoError "Could not ssh EC2 instance. We are going to delete and recreate it." + deleteInstance ${INSTANCE_ID} + if [ $? -ne 0 ]; then + echoError "Could not terminate existing instance. Exiting." + exit 1 + fi + echoSuccess "EC2 instance successfully deleted." + INSTANCE_ID=$(createAndRunInstance ${AWS_EC2_UBUNTU_AMI_ID} ${AWS_EC2_INSTANCE_TYPE} ${KEY_PAIR_NAME} ${SECGRP_NAME}) + if [ $? -ne 0 ]; then + echoError "Could not create and run new EC2 instance. Exiting." + exit 1 + fi + echoSuccess "EC2 instance successfully created and launched." + echoInfo "Create tag for new instance" + tagInstance ${INSTANCE_ID} ${AWS_EC2_INSTANCE_TAG_NAME} ${AWS_EC2_INSTANCE_TAG_VALUE} + if [ $? -ne 0 ]; then + echoError "Could not create tag EC2 instance. Exiting." + exit 1 + fi + echoSuccess "EC2 instance successfully tagged." + else + echoSuccess "SSH connection to EC2 instance successfully acheived." + fi +else + echoInfo "EC2 instance not found, we are going to create it." + INSTANCE_ID=$(createAndRunInstance ${AWS_EC2_UBUNTU_AMI_ID} ${AWS_EC2_INSTANCE_TYPE} ${KEY_PAIR_NAME} ${SECGRP_NAME}) + if [ $? -ne 0 ]; then + echoError "Could not create and run new EC2 instance. Exiting." + exit 1 + fi + echoSuccess "EC2 instance successfully created and launched." + echoInfo "Create tag for new instance" + tagInstance ${INSTANCE_ID} ${AWS_EC2_INSTANCE_TAG_NAME} ${AWS_EC2_INSTANCE_TAG_VALUE} + if [ $? -ne 0 ]; then + echoError "Could not create tag EC2 instance. Exiting." + exit 1 + fi + echoSuccess "EC2 instance successfully tagged." +fi + +INSTANCE_PUBLIC_DNS_NAME=$(getInstancePublicDnsName ${INSTANCE_ID}) +echoInfo "EC2 instance public DNS name: ${INSTANCE_PUBLIC_DNS_NAME}" + +echoStep "Wait some time so as to let EC2 instance start..." +sleep 5 + +# 4- Configure instance and install app +echoStep "Configure instance and install app" +echoInfo "Update available packages list" +${SSH_CMD} ${INSTANCE_PUBLIC_DNS_NAME} sudo apt-get update -q +if [ $? -ne 0 ]; then + echoError "Unable to update packages list. Exiting." + exit 1 +fi diff --git a/inc/aws.sh b/inc/aws.sh new file mode 100755 index 0000000..1bd9686 --- /dev/null +++ b/inc/aws.sh @@ -0,0 +1,136 @@ +#!/bin/bash + +AWS_CLI_OUTPUT=json +AWS_CLI_REGION=us-west-1 +AWS_CLI_EC2_CMD="aws --output ${AWS_CLI_OUTPUT} --region ${AWS_CLI_REGION} ec2" + +# Key pair management +checkKeypair() { + local _KEYPAIR_NAME=$1 + + ${AWS_CLI_EC2_CMD} describe-key-pairs --key-names ${_KEYPAIR_NAME} > /dev/null 2>&1 +} +export -f checkKeypair + +deleteKeypair() { + local _KEYPAIR_NAME=$1 + + ${AWS_CLI_EC2_CMD} delete-key-pair --key-name ${_KEYPAIR_NAME} > /dev/null 2>&1 +} +export -f deleteKeypair + +createAndInstallKeypair() { + local _KEYPAIR_NAME=$1 + + ${AWS_CLI_EC2_CMD} create-key-pair --key-name ${_KEYPAIR_NAME} > /tmp/keypair.out 2>&1 + if [ $? -ne 0 ]; then + rm -f /tmp/keypair.out + return 1 + else + echo /tmp/keypair.out | python -c "import sys, json; print json.load(sys.stdin)['KeyMaterial']" > ~/.ssh/${_KEYPAIR_NAME}.pem + mkdir -p ~/.ssh + chmod 700 ~/.ssh + chmod 400 ~/.ssh/${_KEYPAIR_NAME}.pem + rm -f /tmp/keypair.out + return 0 + fi +} +export -f createAndInstallKeypair + +# Security group management +checkSecGrp() { + local _SECGRP_NAME=$1 + + ${AWS_CLI_EC2_CMD} describe-security-groups --group-names ${_SECGRP_NAME} > /dev/null 2>&1 +} +export -f checkSecGrp + +createSecGrp() { + local _SECGRP_NAME=$1 + local _SECGRP_DESC=$2 + + ${AWS_CLI_EC2_CMD} create-security-group --group-name ${_SECGRP_NAME} --description "${_SECGRP_DESC}" > /dev/null 2>&1 +} +export -f createSecGrp + +createSecGrpRule() { + local _SECGRP_NAME=$1 + local _SECGRP_RULE_PORT=$2 + + ${AWS_CLI_EC2_CMD} authorize-security-group-ingress --group-name ${_SECGRP_NAME} --protocol tcp --port ${_SECGRP_RULE_PORT} --cidr 0.0.0.0/0 > /dev/null 2> /tmp/secgroup_rule.err + + if [ $? -ne 0 ]; then + if [ $(grep -c "InvalidPermission.Duplicate" /tmp/secgroup_rule.err) -gt 0 ]; then + return 0 + fi + return 1 + fi + return 0 +} +export -f createSecGrpRule + +# Instances management +checkInstance() { + local _TAG_NAME=$1 + local _TAG_VALUE=$2 + + local _INSTANCES_COUNT=$(${AWS_CLI_EC2_CMD} describe-instances --filters "Name=tag:${_TAG_NAME},Values=${_TAG_VALUE}" "Name=instance-state-code,Values=16" | python -c "import sys, json; print len(json.load(sys.stdin)['Reservations'])") + + if [ $_INSTANCES_COUNT -gt 0 ]; then + return 0 + fi + + return 1 +} +export -f checkInstance + +getInstanceId() { + local _TAG_NAME=$1 + local _TAG_VALUE=$2 + + local _INSTANCE_ID=$(${AWS_CLI_EC2_CMD} describe-instances --filters "Name=tag:${_TAG_NAME},Values=${_TAG_VALUE}" "Name=instance-state-code,Values=16" | python -c "import sys, json; print json.load(sys.stdin)['Reservations'][0]['Instances'][0]['InstanceId']") + echo ${_INSTANCE_ID} +} +export -f getInstanceId + +deleteInstance() { + local _INSTANCE_ID=$1 + + ${AWS_CLI_EC2_CMD} terminate-instances --instance-ids ${_INSTANCE_ID} > /dev/null 2>&1 +} +export -f deleteInstance + +createAndRunInstance() { + local _AMI_IMAGE_ID=$1 + local _INSTANCE_TYPE=$2 + local _KEYPAIR_NAME=$3 + local _SECGRP_NAME=$4 + + ${AWS_CLI_EC2_CMD} run-instances --image-id ${_AMI_IMAGE_ID} --count 1 --instance-type ${_INSTANCE_TYPE} --key-name ${_KEYPAIR_NAME} --security-groups ${_SECGRP_NAME} > /tmp/instance.out 2>&1 + + if [ $? -ne 0 ]; then + return 1 + else + local _INSTANCE_ID=$(cat /tmp/instance.out | python -c "import sys, json; print json.load(sys.stdin)['Instances'][0]['InstanceId']") + echo ${_INSTANCE_ID} + return 0 + fi +} +export -f createAndRunInstance + +getInstancePublicDnsName() { + local _INSTANCE_ID=$1 + + local _PUBLIC_DNS_NAME=$(${AWS_CLI_EC2_CMD} describe-instances --instance-ids ${_INSTANCE_ID} | python -c "import sys, json; print json.load(sys.stdin)['Reservations'][0]['Instances'][0]['PublicDnsName']") + echo ${_PUBLIC_DNS_NAME} +} +export -f getInstancePublicDnsName + +tagInstance() { + local _INSTANCE_ID=$1 + local _TAG_NAME=$2 + local _TAG_VALUE=$3 + + ${AWS_CLI_EC2_CMD} create-tags --resources ${_INSTANCE_ID} --tags Key=${_TAG_NAME},Value=${_TAG_VALUE} > /dev/null 2>&1 +} +export -f tagInstance diff --git a/inc/funcs.sh b/inc/funcs.sh new file mode 100755 index 0000000..eb625f0 --- /dev/null +++ b/inc/funcs.sh @@ -0,0 +1,77 @@ +#!/bin/bash + +# Prints message using color in terminal +# Function from http://aarvik.dk/echo-colors/ +# Usage: echo "Hej" | cecho ORANGE +cecho(){ + BLACK="\033[0;30m" + BLUE="\033[0;34m" + GREEN="\033[0;32m" + CYAN="\033[0;36m" + RED="\033[0;31m" + PURPLE="\033[0;35m" + ORANGE="\033[0;33m" + LGRAY="\033[0;37m" + DGRAY="\033[1;30m" + LBLUE="\033[1;34m" + LGREEN="\033[1;32m" + LCYAN="\033[1;36m" + LRED="\033[1;31m" + LPURPLE="\033[1;35m" + YELLOW="\033[1;33m" + WHITE="\033[1;37m" + NORMAL="\033[m" + + color=\$${1:-NORMAL} + + echo -ne "$(eval echo ${color})" + cat + + echo -ne "${NORMAL}" +} + +# Prints an error message to terminal +echoError() { + local _MSG=$1 + + echo $_MSG | cecho RED +} +export -f echoError + +# Prints a warning message to terminal +echoWarning() { + local _MSG=$1 + + echo $_MSG | cecho ORANGE +} +export -f echoWarning + +# Prints a success message to terminal +echoSuccess() { + local _MSG=$1 + + echo $_MSG | cecho GREEN +} +export -f echoSuccess + +# Prints an info message to terminal +echoInfo() { + local _MSG=$1 + + echo $_MSG +} +export -f echoInfo + +# Prints a debug message to terminal +echoDebug() { + local _MSG=$1 + + echo $_MSG | cecho CYAN +} +export -f echoDebug + +echoStep() { + local _MSG=$1 + + echo "-> $_MSG" +} diff --git a/resources/nginx/helloapp b/resources/nginx/helloapp new file mode 100644 index 0000000..383c8f3 --- /dev/null +++ b/resources/nginx/helloapp @@ -0,0 +1,14 @@ +server { + listen 80; + server_name ##SERVERNAME##; + + access_log /var/log/nginx-helloapp-access.log; + error_log /var/log/nginx-helloapp-error.log; + root ##WEBROOT##; + + location / { + proxy_pass http://127.0.0.1:##GUNICORN_PORT##; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } +} From 9d95e72ef375df31bf95b996c1227b4888dc7a14 Mon Sep 17 00:00:00 2001 From: ju-ponectus Date: Mon, 13 Feb 2017 13:57:11 +0100 Subject: [PATCH 2/7] App installation and services configuration inside EC2 instance. --- aws-app.sh | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 4 deletions(-) diff --git a/aws-app.sh b/aws-app.sh index 187d70a..d40af3a 100755 --- a/aws-app.sh +++ b/aws-app.sh @@ -2,8 +2,7 @@ # Basic Python app git parameters BASIC_APP_URL=https://github.com/wvchallenges/opseng-challenge-app -BASIC_APP_DEFAULT_BRANCH=master -BASIC_APP_DEFAULT_TAG=HEAD +BASIC_APP_DEFAULT_BRANCH_OR_TAG=master # SSH Key Pair name KEY_PAIR_NAME=HelloAppKey @@ -13,8 +12,13 @@ SECGRP_NAME=HelloAppSecGrp SECGRP_DESC="Security group for Hello App access" SECGRP_RULES_PORT=( 22 80 ) +# Variables related to EC2 Instance installation and configuration +REQUIRED_PKGS="git-core nginx python python-pip" +HELLOAPP_INSTALLDIR=/var/www/helloapp +GUNICORN_PORT=8000 # Base Nginx configuration to use for app publication NGINX_TEMPLATE=resources/nginx/helloapp +NGINX_CONFDIR=/etc/nginx # AWS EC2 Instance parameters AWS_EC2_INSTANCE_TYPE=t2.micro @@ -25,8 +29,9 @@ AWS_EC2_INSTANCE_TAG_VALUE=opseng-challenge-lamure AWS_EC2_UBUNTU_AMI_ID=ami-539ac933 AWS_EC2_UBUNTU_LOGIN=ubuntu -# SSH EC2 Instance +# SSH related commands for EC2 Instance SSH_CMD="ssh -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/${KEY_PAIR_NAME}.pem -l ${AWS_EC2_UBUNTU_LOGIN}" +SCP_CMD="scp -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/${KEY_PAIR_NAME}.pem" # Get this script install dir SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" @@ -158,8 +163,70 @@ sleep 5 # 4- Configure instance and install app echoStep "Configure instance and install app" echoInfo "Update available packages list" -${SSH_CMD} ${INSTANCE_PUBLIC_DNS_NAME} sudo apt-get update -q +${SSH_CMD} ${INSTANCE_PUBLIC_DNS_NAME} "sudo apt-get update -q > /dev/null 2>&1" if [ $? -ne 0 ]; then echoError "Unable to update packages list. Exiting." exit 1 fi +echoSuccess "Packages list successfully updated." +echoInfo "Install required packages on instance (${REQUIRED_PKGS})" +${SSH_CMD} ${INSTANCE_PUBLIC_DNS_NAME} "sudo apt-get install -yq ${REQUIRED_PKGS} > /dev/null 2>&1" +if [ $? -ne 0 ]; then + echoError "Something went wrong during packages installation. Exiting." + exit 1 +fi +echoSuccess "Required packages successfully installed." +echoInfo "Get HelloApp code (branch or tag = ${BASIC_APP_DEFAULT_BRANCH_OR_TAG})" +${SSH_CMD} ${INSTANCE_PUBLIC_DNS_NAME} "sudo rm -rf ${HELLOAPP_INSTALLDIR} 2> /dev/null; \ + sudo mkdir -p ${HELLOAPP_INSTALLDIR} \ + && sudo chown ${AWS_EC2_UBUNTU_LOGIN} ${HELLOAPP_INSTALLDIR} \ + && cd ${HELLOAPP_INSTALLDIR} \ + && git clone --branch ${BASIC_APP_DEFAULT_BRANCH_OR_TAG} --depth 1 ${BASIC_APP_URL} . > /dev/null 2>&1" +if [ $? -ne 0 ]; then + echoError "Something went wrong during Hello App source code installation. Exiting." + exit 1 +fi +echoSuccess "Hello App source code successfully downloaded." +echoInfo "Install HelloApp Python requirements" +${SSH_CMD} ${INSTANCE_PUBLIC_DNS_NAME} "cd ${HELLOAPP_INSTALLDIR} \ + && sudo pip install -r requirements.txt > /dev/null 2>&1" +if [ $? -ne 0 ]; then + echoError "Something went wrong during Hello App Python requirements installation. Exiting." + exit 1 +fi +echoSuccess "Hello App source Python requirements successfully installed." +echoInfo "Launch Gunicorn" +${SSH_CMD} ${INSTANCE_PUBLIC_DNS_NAME} "cd ${HELLOAPP_INSTALLDIR} \ + && sudo gunicorn -D app:app > /dev/null 2>&1" +if [ $? -ne 0 ]; then + echoError "An error occured while trying to launch Gunicorn. Exiting." + exit 1 +fi +echoSuccess "Gunicorn successfully started." +echoInfo "Generate Nginx configuration from template" +sed "s/##SERVERNAME##/${INSTANCE_PUBLIC_DNS_NAME}/g;\ + s@##WEBROOT##@${HELLOAPP_INSTALLDIR}@g;\ + s/##GUNICORN_PORT##/${GUNICORN_PORT}/g" "${SCRIPT_DIR}/${NGINX_TEMPLATE}" > /tmp/helloapp.nginx 2> /dev/null +if [ $? -ne 0 ]; then + echoError "Something went wrong during Nginx configuration generation. Exiting." + exit 1 +fi +echoSuccess "NGinx configuration successfully generated." +echoInfo "Send Nginx configuration to EC2 instance" +${SCP_CMD} /tmp/helloapp.nginx ${AWS_EC2_UBUNTU_LOGIN}@${INSTANCE_PUBLIC_DNS_NAME}:/tmp/helloapp +if [ $? -ne 0 ]; then + echoError "Something went wrong during Nginx configuration SCP transfer. Exiting." + exit 1 +fi +echoSuccess "NGinx configuration successfully sent to EC2 instance." +echoInfo "Configure Nginx on EC2 instance" +${SSH_CMD} ${INSTANCE_PUBLIC_DNS_NAME} "sudo cp /tmp/helloapp ${NGINX_CONFDIR}/sites-available \ + && sudo rm -f ${NGINX_CONFDIR}/sites-enabled/* \ + && sudo ln -s ${NGINX_CONFDIR}/sites-available/helloapp ${NGINX_CONFDIR}/sites-enabled/helloapp \ + && sudo service nginx restart > /dev/null 2>&1" +if [ $? -ne 0 ]; then + echoError "Something went wrong during Nginx configuration. Exiting." + exit 1 +fi +echoSuccess "NGinx successfully configured." +echoStep "HelloApp deployment successfully finished, it is available at http://${INSTANCE_PUBLIC_DNS_NAME}" From 85bfe7d7a8e693fa0549c784c00d197cd7e679c7 Mon Sep 17 00:00:00 2001 From: ju-ponectus Date: Mon, 13 Feb 2017 15:55:05 +0100 Subject: [PATCH 3/7] Script arguments and set AWS resources names --- aws-app.sh | 43 ++++++++++++++++++++++++++++-------- inc/aws.sh | 4 ++-- inc/{funcs.sh => outputs.sh} | 13 +++++++++++ 3 files changed, 49 insertions(+), 11 deletions(-) rename inc/{funcs.sh => outputs.sh} (73%) diff --git a/aws-app.sh b/aws-app.sh index d40af3a..f4e4166 100755 --- a/aws-app.sh +++ b/aws-app.sh @@ -5,10 +5,10 @@ BASIC_APP_URL=https://github.com/wvchallenges/opseng-challenge-app BASIC_APP_DEFAULT_BRANCH_OR_TAG=master # SSH Key Pair name -KEY_PAIR_NAME=HelloAppKey +KEY_PAIR_NAME=julien.HelloAppKey # Security group -SECGRP_NAME=HelloAppSecGrp +SECGRP_NAME=julien.HelloAppSecGrp SECGRP_DESC="Security group for Hello App access" SECGRP_RULES_PORT=( 22 80 ) @@ -22,11 +22,11 @@ NGINX_CONFDIR=/etc/nginx # AWS EC2 Instance parameters AWS_EC2_INSTANCE_TYPE=t2.micro -AWS_EC2_INSTANCE_TAG_NAME=usage -AWS_EC2_INSTANCE_TAG_VALUE=opseng-challenge-lamure +AWS_EC2_INSTANCE_TAG_NAME=Name +AWS_EC2_INSTANCE_TAG_VALUE=julien.HelloAppInstance # Ubuntu Xenial Amazon image -AWS_EC2_UBUNTU_AMI_ID=ami-539ac933 +AWS_EC2_UBUNTU_AMI_ID=ami-7c803d1c AWS_EC2_UBUNTU_LOGIN=ubuntu # SSH related commands for EC2 Instance @@ -36,8 +36,33 @@ SCP_CMD="scp -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~ # Get this script install dir SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" -source "$SCRIPT_DIR/inc/funcs.sh" -source "$SCRIPT_DIR/inc/aws.sh" +source "${SCRIPT_DIR}/inc/outputs.sh" +source "${SCRIPT_DIR}/inc/aws.sh" + +BASIC_APP_BRANCH_OR_TAG= +while [ $# -ge 1 ] +do + key="$1" + + case $key in + -b|--branch-or-tag) + BASIC_APP_BRANCH_OR_TAG="$2" + shift # past argument + ;; + -h|--help) + printHelp + exit 0 + ;; + *) + # unknown option + ;; + esac + shift # past argument or value +done + +if [ -z "${BASIC_APP_BRANCH_OR_TAG}" ]; then + BASIC_APP_BRANCH_OR_TAG=$BASIC_APP_DEFAULT_BRANCH_OR_TAG +fi echoStep "Starting HelloApp deployment" @@ -176,12 +201,12 @@ if [ $? -ne 0 ]; then exit 1 fi echoSuccess "Required packages successfully installed." -echoInfo "Get HelloApp code (branch or tag = ${BASIC_APP_DEFAULT_BRANCH_OR_TAG})" +echoInfo "Get HelloApp code (branch or tag = ${BASIC_APP_BRANCH_OR_TAG})" ${SSH_CMD} ${INSTANCE_PUBLIC_DNS_NAME} "sudo rm -rf ${HELLOAPP_INSTALLDIR} 2> /dev/null; \ sudo mkdir -p ${HELLOAPP_INSTALLDIR} \ && sudo chown ${AWS_EC2_UBUNTU_LOGIN} ${HELLOAPP_INSTALLDIR} \ && cd ${HELLOAPP_INSTALLDIR} \ - && git clone --branch ${BASIC_APP_DEFAULT_BRANCH_OR_TAG} --depth 1 ${BASIC_APP_URL} . > /dev/null 2>&1" + && git clone --branch ${BASIC_APP_BRANCH_OR_TAG} --depth 1 ${BASIC_APP_URL} . > /dev/null 2>&1" if [ $? -ne 0 ]; then echoError "Something went wrong during Hello App source code installation. Exiting." exit 1 diff --git a/inc/aws.sh b/inc/aws.sh index 1bd9686..8bf50c1 100755 --- a/inc/aws.sh +++ b/inc/aws.sh @@ -1,7 +1,7 @@ #!/bin/bash AWS_CLI_OUTPUT=json -AWS_CLI_REGION=us-west-1 +AWS_CLI_REGION=us-west-2 AWS_CLI_EC2_CMD="aws --output ${AWS_CLI_OUTPUT} --region ${AWS_CLI_REGION} ec2" # Key pair management @@ -27,7 +27,7 @@ createAndInstallKeypair() { rm -f /tmp/keypair.out return 1 else - echo /tmp/keypair.out | python -c "import sys, json; print json.load(sys.stdin)['KeyMaterial']" > ~/.ssh/${_KEYPAIR_NAME}.pem + cat /tmp/keypair.out | python -c "import sys, json; print json.load(sys.stdin)['KeyMaterial']" > ~/.ssh/${_KEYPAIR_NAME}.pem mkdir -p ~/.ssh chmod 700 ~/.ssh chmod 400 ~/.ssh/${_KEYPAIR_NAME}.pem diff --git a/inc/funcs.sh b/inc/outputs.sh similarity index 73% rename from inc/funcs.sh rename to inc/outputs.sh index eb625f0..7f48d59 100755 --- a/inc/funcs.sh +++ b/inc/outputs.sh @@ -75,3 +75,16 @@ echoStep() { echo "-> $_MSG" } + +printHelp() { + cat << EOF +usage: $0 [-b|--branch-or-tag ][-h|--help] + +-b|--branch-or-tag Sets the branch or tag name of the GitHub repository to deploy to AWS +-h|--help Prints this help message + +Sets up required AWS resources and deploys Python app available here: https://github.com/wvchallenges/opseng-challenge-app +Thanks for this challenge! Julien +EOF +} +export -f printHelp From 30b51f10d7aaf3cd8513d484bbe0d58c1bda5dc1 Mon Sep 17 00:00:00 2001 From: ju-ponectus Date: Mon, 13 Feb 2017 17:09:53 +0100 Subject: [PATCH 4/7] Code reorganization --- aws-app.sh | 199 +++------------------------------------ inc/aws-app-steps.sh | 219 +++++++++++++++++++++++++++++++++++++++++++ inc/aws.sh | 3 + 3 files changed, 236 insertions(+), 185 deletions(-) create mode 100644 inc/aws-app-steps.sh diff --git a/aws-app.sh b/aws-app.sh index f4e4166..642cc95 100755 --- a/aws-app.sh +++ b/aws-app.sh @@ -1,8 +1,8 @@ #!/bin/bash # Basic Python app git parameters -BASIC_APP_URL=https://github.com/wvchallenges/opseng-challenge-app -BASIC_APP_DEFAULT_BRANCH_OR_TAG=master +HELLO_APP_GIT_URL=https://github.com/wvchallenges/opseng-challenge-app +HELLO_APP_DEFAULT_BRANCH_OR_TAG=master # SSH Key Pair name KEY_PAIR_NAME=julien.HelloAppKey @@ -38,15 +38,16 @@ SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" source "${SCRIPT_DIR}/inc/outputs.sh" source "${SCRIPT_DIR}/inc/aws.sh" +source "${SCRIPT_DIR}/inc/aws-app-steps.sh" -BASIC_APP_BRANCH_OR_TAG= +HELLO_APP_BRANCH_OR_TAG= while [ $# -ge 1 ] do key="$1" case $key in -b|--branch-or-tag) - BASIC_APP_BRANCH_OR_TAG="$2" + HELLO_APP_BRANCH_OR_TAG="$2" shift # past argument ;; -h|--help) @@ -60,198 +61,26 @@ do shift # past argument or value done -if [ -z "${BASIC_APP_BRANCH_OR_TAG}" ]; then - BASIC_APP_BRANCH_OR_TAG=$BASIC_APP_DEFAULT_BRANCH_OR_TAG +if [ -z "${HELLO_APP_BRANCH_OR_TAG}" ]; then + HELLO_APP_BRANCH_OR_TAG=$HELLO_APP_DEFAULT_BRANCH_OR_TAG fi echoStep "Starting HelloApp deployment" # 1- Manage SSH key pair -echoStep "Manage SSH key pair" -checkKeypair ${KEY_PAIR_NAME} -if [ $? -ne 0 ]; then - echoWarning "${KEY_PAIR_NAME} key pair does not exist. We are going to create it." - createAndInstallKeypair ${KEY_PAIR_NAME} - if [ $? -ne 0 ]; then - echoError "Could not create and install new key pair. Exiting." - exit 1 - fi -else - echoSuccess "${KEY_PAIR_NAME} key pair already exists." - if [ ! -f ~/.ssh/${KEY_PAIR_NAME}.pem ]; then - echoWarning "Private key file does not exist locally. We are going to recreate key pair." - deleteKeypair ${KEY_PAIR_NAME} - if [ $? -ne 0 ]; then - echoError "Could not delete existing key pair. Exiting." - exit 1 - fi - createAndInstallKeypair ${KEY_PAIR_NAME} - if [ $? -ne 0 ]; then - echoError "Could not create and install new key pair. Exiting." - exit 1 - fi - fi -fi +manageKeypair ${KEY_PAIR_NAME} # 2- Manage security group -echoStep "Manage security group" -CREATE_RULES=0 -checkSecGrp ${SECGRP_NAME} -if [ $? -ne 0 ]; then - echoWarning "${SECGRP_NAME} security group does not exist. We are going to create it." - createSecGrp ${SECGRP_NAME} "${SECGRP_DESC}" - if [ $? -ne 0 ]; then - echoError "Could not create security group. Exiting." - exit 1 - fi - CREATE_RULES=1 -else - echoSuccess "${SECGRP_NAME} security group already exists. Will check rules to be sure they exist." - CREATE_RULES=1 -fi - -if [ $CREATE_RULES -eq 1 ]; then - for i in "${SECGRP_RULES_PORT[@]}" - do - createSecGrpRule ${SECGRP_NAME} ${i} - if [ $? -ne 0 ]; then - echoError "Could not create inbound rule for port ${i}. Exiting." - exit 1 - fi - done -fi +manageSecGrp ${SECGRP_NAME} "${SECGRP_DESC}" # 3- Create EC2 instance -echoStep "Create EC2 instance" -checkInstance ${AWS_EC2_INSTANCE_TAG_NAME} ${AWS_EC2_INSTANCE_TAG_VALUE} -if [ $? -eq 0 ]; then - echoInfo "EC2 instance already exists. We are going to try to ssh it." - INSTANCE_ID=$(getInstanceId ${AWS_EC2_INSTANCE_TAG_NAME} ${AWS_EC2_INSTANCE_TAG_VALUE}) - if [ $? -ne 0 ]; then - echoError "Could not get EC2 instance ID" - exit 1 - fi - INSTANCE_PUBLIC_DNS_NAME=$(getInstancePublicDnsName ${INSTANCE_ID}) - if [ $? -ne 0 ]; then - echoError "Could not get EC2 instance public DNS name" - exit 1 - fi - echoInfo "Existing EC2 instance public DNS name: ${INSTANCE_PUBLIC_DNS_NAME}" - ${SSH_CMD} ${INSTANCE_PUBLIC_DNS_NAME} exit - if [ $? -ne 0 ]; then - echoError "Could not ssh EC2 instance. We are going to delete and recreate it." - deleteInstance ${INSTANCE_ID} - if [ $? -ne 0 ]; then - echoError "Could not terminate existing instance. Exiting." - exit 1 - fi - echoSuccess "EC2 instance successfully deleted." - INSTANCE_ID=$(createAndRunInstance ${AWS_EC2_UBUNTU_AMI_ID} ${AWS_EC2_INSTANCE_TYPE} ${KEY_PAIR_NAME} ${SECGRP_NAME}) - if [ $? -ne 0 ]; then - echoError "Could not create and run new EC2 instance. Exiting." - exit 1 - fi - echoSuccess "EC2 instance successfully created and launched." - echoInfo "Create tag for new instance" - tagInstance ${INSTANCE_ID} ${AWS_EC2_INSTANCE_TAG_NAME} ${AWS_EC2_INSTANCE_TAG_VALUE} - if [ $? -ne 0 ]; then - echoError "Could not create tag EC2 instance. Exiting." - exit 1 - fi - echoSuccess "EC2 instance successfully tagged." - else - echoSuccess "SSH connection to EC2 instance successfully acheived." - fi -else - echoInfo "EC2 instance not found, we are going to create it." - INSTANCE_ID=$(createAndRunInstance ${AWS_EC2_UBUNTU_AMI_ID} ${AWS_EC2_INSTANCE_TYPE} ${KEY_PAIR_NAME} ${SECGRP_NAME}) - if [ $? -ne 0 ]; then - echoError "Could not create and run new EC2 instance. Exiting." - exit 1 - fi - echoSuccess "EC2 instance successfully created and launched." - echoInfo "Create tag for new instance" - tagInstance ${INSTANCE_ID} ${AWS_EC2_INSTANCE_TAG_NAME} ${AWS_EC2_INSTANCE_TAG_VALUE} - if [ $? -ne 0 ]; then - echoError "Could not create tag EC2 instance. Exiting." - exit 1 - fi - echoSuccess "EC2 instance successfully tagged." -fi +manageInstance ${AWS_EC2_UBUNTU_AMI_ID} ${AWS_EC2_INSTANCE_TYPE} ${KEY_PAIR_NAME} ${SECGRP_NAME} ${AWS_EC2_INSTANCE_TAG_NAME} ${AWS_EC2_INSTANCE_TAG_VALUE} "${SSH_CMD}" +INSTANCE_ID=$(getInstanceId ${AWS_EC2_INSTANCE_TAG_NAME} ${AWS_EC2_INSTANCE_TAG_VALUE}) INSTANCE_PUBLIC_DNS_NAME=$(getInstancePublicDnsName ${INSTANCE_ID}) echoInfo "EC2 instance public DNS name: ${INSTANCE_PUBLIC_DNS_NAME}" -echoStep "Wait some time so as to let EC2 instance start..." -sleep 5 - # 4- Configure instance and install app -echoStep "Configure instance and install app" -echoInfo "Update available packages list" -${SSH_CMD} ${INSTANCE_PUBLIC_DNS_NAME} "sudo apt-get update -q > /dev/null 2>&1" -if [ $? -ne 0 ]; then - echoError "Unable to update packages list. Exiting." - exit 1 -fi -echoSuccess "Packages list successfully updated." -echoInfo "Install required packages on instance (${REQUIRED_PKGS})" -${SSH_CMD} ${INSTANCE_PUBLIC_DNS_NAME} "sudo apt-get install -yq ${REQUIRED_PKGS} > /dev/null 2>&1" -if [ $? -ne 0 ]; then - echoError "Something went wrong during packages installation. Exiting." - exit 1 -fi -echoSuccess "Required packages successfully installed." -echoInfo "Get HelloApp code (branch or tag = ${BASIC_APP_BRANCH_OR_TAG})" -${SSH_CMD} ${INSTANCE_PUBLIC_DNS_NAME} "sudo rm -rf ${HELLOAPP_INSTALLDIR} 2> /dev/null; \ - sudo mkdir -p ${HELLOAPP_INSTALLDIR} \ - && sudo chown ${AWS_EC2_UBUNTU_LOGIN} ${HELLOAPP_INSTALLDIR} \ - && cd ${HELLOAPP_INSTALLDIR} \ - && git clone --branch ${BASIC_APP_BRANCH_OR_TAG} --depth 1 ${BASIC_APP_URL} . > /dev/null 2>&1" -if [ $? -ne 0 ]; then - echoError "Something went wrong during Hello App source code installation. Exiting." - exit 1 -fi -echoSuccess "Hello App source code successfully downloaded." -echoInfo "Install HelloApp Python requirements" -${SSH_CMD} ${INSTANCE_PUBLIC_DNS_NAME} "cd ${HELLOAPP_INSTALLDIR} \ - && sudo pip install -r requirements.txt > /dev/null 2>&1" -if [ $? -ne 0 ]; then - echoError "Something went wrong during Hello App Python requirements installation. Exiting." - exit 1 -fi -echoSuccess "Hello App source Python requirements successfully installed." -echoInfo "Launch Gunicorn" -${SSH_CMD} ${INSTANCE_PUBLIC_DNS_NAME} "cd ${HELLOAPP_INSTALLDIR} \ - && sudo gunicorn -D app:app > /dev/null 2>&1" -if [ $? -ne 0 ]; then - echoError "An error occured while trying to launch Gunicorn. Exiting." - exit 1 -fi -echoSuccess "Gunicorn successfully started." -echoInfo "Generate Nginx configuration from template" -sed "s/##SERVERNAME##/${INSTANCE_PUBLIC_DNS_NAME}/g;\ - s@##WEBROOT##@${HELLOAPP_INSTALLDIR}@g;\ - s/##GUNICORN_PORT##/${GUNICORN_PORT}/g" "${SCRIPT_DIR}/${NGINX_TEMPLATE}" > /tmp/helloapp.nginx 2> /dev/null -if [ $? -ne 0 ]; then - echoError "Something went wrong during Nginx configuration generation. Exiting." - exit 1 -fi -echoSuccess "NGinx configuration successfully generated." -echoInfo "Send Nginx configuration to EC2 instance" -${SCP_CMD} /tmp/helloapp.nginx ${AWS_EC2_UBUNTU_LOGIN}@${INSTANCE_PUBLIC_DNS_NAME}:/tmp/helloapp -if [ $? -ne 0 ]; then - echoError "Something went wrong during Nginx configuration SCP transfer. Exiting." - exit 1 -fi -echoSuccess "NGinx configuration successfully sent to EC2 instance." -echoInfo "Configure Nginx on EC2 instance" -${SSH_CMD} ${INSTANCE_PUBLIC_DNS_NAME} "sudo cp /tmp/helloapp ${NGINX_CONFDIR}/sites-available \ - && sudo rm -f ${NGINX_CONFDIR}/sites-enabled/* \ - && sudo ln -s ${NGINX_CONFDIR}/sites-available/helloapp ${NGINX_CONFDIR}/sites-enabled/helloapp \ - && sudo service nginx restart > /dev/null 2>&1" -if [ $? -ne 0 ]; then - echoError "Something went wrong during Nginx configuration. Exiting." - exit 1 -fi -echoSuccess "NGinx successfully configured." -echoStep "HelloApp deployment successfully finished, it is available at http://${INSTANCE_PUBLIC_DNS_NAME}" +setupAndDeployApp ${INSTANCE_PUBLIC_DNS_NAME} $HELLO_APP_BRANCH_OR_TAG $HELLO_APP_GIT_URL \ + $HELLOAPP_INSTALLDIR $AWS_EC2_UBUNTU_LOGIN "$REQUIRED_PKGS" "${SCRIPT_DIR}/${NGINX_TEMPLATE}" \ + $GUNICORN_PORT $NGINX_CONFDIR "$SSH_CMD" "$SCP_CMD" diff --git a/inc/aws-app-steps.sh b/inc/aws-app-steps.sh new file mode 100644 index 0000000..8246f05 --- /dev/null +++ b/inc/aws-app-steps.sh @@ -0,0 +1,219 @@ +#!/bin/bash + + +manageKeypair() { + local _KEY_PAIR_NAME=$1 + + echoStep "Manage SSH key pair" + checkKeypair ${_KEY_PAIR_NAME} + if [ $? -ne 0 ]; then + echoWarning "${_KEY_PAIR_NAME} key pair does not exist. We are going to create it." + createAndInstallKeypair ${_KEY_PAIR_NAME} + if [ $? -ne 0 ]; then + echoError "Could not create and install new key pair. Exiting." + exit 1 + fi + else + echoSuccess "${_KEY_PAIR_NAME} key pair already exists." + if [ ! -f ~/.ssh/${_KEY_PAIR_NAME}.pem ]; then + echoWarning "Private key file does not exist locally. We are going to recreate key pair." + deleteKeypair ${_KEY_PAIR_NAME} + if [ $? -ne 0 ]; then + echoError "Could not delete existing key pair. Exiting." + exit 1 + fi + createAndInstallKeypair ${_KEY_PAIR_NAME} + if [ $? -ne 0 ]; then + echoError "Could not create and install new key pair. Exiting." + exit 1 + fi + fi + fi +} +export -f manageKeypair + +manageSecGrp() { + local _SECGRP_NAME=$1 + local _SECGRP_DESC="$2" + + echoStep "Manage security group" + local _CREATE_RULES=0 + checkSecGrp ${_SECGRP_NAME} + if [ $? -ne 0 ]; then + echoWarning "${_SECGRP_NAME} security group does not exist. We are going to create it." + createSecGrp ${_SECGRP_NAME} "${_SECGRP_DESC}" + if [ $? -ne 0 ]; then + echoError "Could not create security group. Exiting." + exit 1 + fi + _CREATE_RULES=1 + else + echoSuccess "${_SECGRP_NAME} security group already exists. Will check rules to be sure they exist." + _CREATE_RULES=1 + fi + + if [ $_CREATE_RULES -eq 1 ]; then + for i in "${SECGRP_RULES_PORT[@]}" + do + createSecGrpRule ${_SECGRP_NAME} ${i} + if [ $? -ne 0 ]; then + echoError "Could not create inbound rule for port ${i}. Exiting." + exit 1 + fi + done + fi +} +export -f manageSecGrp + +manageInstance() { + local _EC2_AMI_ID=$1 + local _EC2_INSTANCE_TYPE=$2 + local _KEY_PAIR_NAME=$3 + local _SECGRP_NAME=$4 + local _TAG_NAME=$5 + local _TAG_VALUE=$6 + local _SSH_CMD="$7" + + echoStep "Create EC2 instance" + checkInstance ${_TAG_NAME} ${_TAG_VALUE} + if [ $? -eq 0 ]; then + echoInfo "EC2 instance already exists. We are going to try to ssh it." + local _INSTANCE_ID=$(getInstanceId ${_TAG_NAME} ${_TAG_VALUE}) + if [ $? -ne 0 ]; then + echoError "Could not get EC2 instance ID" + exit 1 + fi + local _INSTANCE_PUBLIC_DNS_NAME=$(getInstancePublicDnsName ${_INSTANCE_ID}) + if [ $? -ne 0 ]; then + echoError "Could not get EC2 instance public DNS name" + exit 1 + fi + echoInfo "Existing EC2 instance public DNS name: ${_INSTANCE_PUBLIC_DNS_NAME}" + ${_SSH_CMD} ${_INSTANCE_PUBLIC_DNS_NAME} exit + if [ $? -ne 0 ]; then + echoError "Could not ssh EC2 instance. We are going to delete and recreate it." + deleteInstance ${_INSTANCE_ID} + if [ $? -ne 0 ]; then + echoError "Could not terminate existing instance. Exiting." + exit 1 + fi + echoSuccess "EC2 instance successfully deleted." + echoInfo "Create new EC2 instance." + createAndTagInstance ${_EC2_AMI_ID} ${_EC2_INSTANCE_TYPE} ${_KEY_PAIR_NAME} ${_SECGRP_NAME} ${_TAG_NAME} ${_TAG_VALUE} + else + echoSuccess "SSH connection to EC2 instance successfully acheived." + fi + else + echoInfo "EC2 instance not found, we are going to create it." + createAndTagInstance ${_EC2_AMI_ID} ${_EC2_INSTANCE_TYPE} ${_KEY_PAIR_NAME} ${_SECGRP_NAME} ${_TAG_NAME} ${_TAG_VALUE} + fi +} + +createAndTagInstance() { + local _EC2_AMI_ID=$1 + local _EC2_INSTANCE_TYPE=$2 + local _KEY_PAIR_NAME=$3 + local _SECGRP_NAME=$4 + local _TAG_NAME=$5 + local _TAG_VALUE=$6 + + local _INSTANCE_ID=$(createAndRunInstance ${_EC2_AMI_ID} ${_EC2_INSTANCE_TYPE} ${_KEY_PAIR_NAME} ${_SECGRP_NAME}) + if [ $? -ne 0 ]; then + echoError "Could not create and run new EC2 instance. Exiting." + exit 1 + fi + echoSuccess "EC2 instance successfully created and launched." + echoStep "Wait some time so as to let EC2 instance start..." + sleep 5 + echoInfo "Create tag for new instance" + tagInstance ${_INSTANCE_ID} ${_TAG_NAME} ${_TAG_VALUE} + if [ $? -ne 0 ]; then + echoError "Could not create tag EC2 instance. Exiting." + exit 1 + fi + echoSuccess "EC2 instance successfully tagged." +} + +setupAndDeployApp() { + local _INSTANCE_PUBLIC_DNS_NAME=$1 + local _APP_BRANCH_OR_TAG=$2 + local _APP_URL=$3 + local _APP_INSTALLDIR=$4 + local _INSTANCE_LOGIN=$5 + local _REQUIRED_PKGS="$6" + local _NGING_TPL="$7" + local _GUNICORN_PORT=$8 + local _NGINX_CONFDIR=$9 + local _SSH_CMD="${10}" + local _SCP_CMD="${11}" + + echoStep "Configure instance and install app" + echoInfo "Update available packages list" + ${_SSH_CMD} ${_INSTANCE_PUBLIC_DNS_NAME} "sudo apt-get update -q > /dev/null 2>&1" + if [ $? -ne 0 ]; then + echoError "Unable to update packages list. Exiting." + exit 1 + fi + echoSuccess "Packages list successfully updated." + echoInfo "Install required packages on instance (${_REQUIRED_PKGS})" + ${_SSH_CMD} ${_INSTANCE_PUBLIC_DNS_NAME} "sudo apt-get install -yq ${_REQUIRED_PKGS} > /dev/null 2>&1" + if [ $? -ne 0 ]; then + echoError "Something went wrong during packages installation. Exiting." + exit 1 + fi + echoSuccess "Required packages successfully installed." + echoInfo "Get HelloApp code (branch or tag = ${_APP_BRANCH_OR_TAG})" + ${_SSH_CMD} ${_INSTANCE_PUBLIC_DNS_NAME} "sudo rm -rf ${_APP_INSTALLDIR} 2> /dev/null; \ + sudo mkdir -p ${_APP_INSTALLDIR} \ + && sudo chown ${_INSTANCE_LOGIN} ${_APP_INSTALLDIR} \ + && cd ${_APP_INSTALLDIR} \ + && git clone --branch ${_APP_BRANCH_OR_TAG} --depth 1 ${_APP_URL} . > /dev/null 2>&1" + if [ $? -ne 0 ]; then + echoError "Something went wrong during Hello App source code installation. Exiting." + exit 1 + fi + echoSuccess "Hello App source code successfully downloaded." + echoInfo "Install HelloApp Python requirements" + ${_SSH_CMD} ${_INSTANCE_PUBLIC_DNS_NAME} "cd ${_APP_INSTALLDIR} \ + && sudo pip install -r requirements.txt > /dev/null 2>&1" + if [ $? -ne 0 ]; then + echoError "Something went wrong during Hello App Python requirements installation. Exiting." + exit 1 + fi + echoSuccess "Hello App source Python requirements successfully installed." + echoInfo "Launch Gunicorn" + ${_SSH_CMD} ${_INSTANCE_PUBLIC_DNS_NAME} "cd ${_APP_INSTALLDIR} \ + && sudo gunicorn -D app:app > /dev/null 2>&1" + if [ $? -ne 0 ]; then + echoError "An error occured while trying to launch Gunicorn. Exiting." + exit 1 + fi + echoSuccess "Gunicorn successfully started." + echoInfo "Generate Nginx configuration from template" + sed "s/##SERVERNAME##/${_INSTANCE_PUBLIC_DNS_NAME}/g;\ + s@##WEBROOT##@${_APP_INSTALLDIR}@g;\ + s/##GUNICORN_PORT##/${_GUNICORN_PORT}/g" "${_NGING_TPL}" > /tmp/helloapp.nginx 2> /dev/null + if [ $? -ne 0 ]; then + echoError "Something went wrong during Nginx configuration generation. Exiting." + exit 1 + fi + echoSuccess "NGinx configuration successfully generated." + echoInfo "Send Nginx configuration to EC2 instance" + ${_SCP_CMD} /tmp/helloapp.nginx ${_INSTANCE_LOGIN}@${_INSTANCE_PUBLIC_DNS_NAME}:/tmp/helloapp + if [ $? -ne 0 ]; then + echoError "Something went wrong during Nginx configuration SCP transfer. Exiting." + exit 1 + fi + echoSuccess "NGinx configuration successfully sent to EC2 instance." + echoInfo "Configure Nginx on EC2 instance" + ${_SSH_CMD} ${_INSTANCE_PUBLIC_DNS_NAME} "sudo cp /tmp/helloapp ${_NGINX_CONFDIR}/sites-available \ + && sudo rm -f ${_NGINX_CONFDIR}/sites-enabled/* \ + && sudo ln -s ${_NGINX_CONFDIR}/sites-available/helloapp ${_NGINX_CONFDIR}/sites-enabled/helloapp \ + && sudo service nginx restart > /dev/null 2>&1" + if [ $? -ne 0 ]; then + echoError "Something went wrong during Nginx configuration. Exiting." + exit 1 + fi + echoSuccess "NGinx successfully configured." + echoStep "HelloApp deployment successfully finished, it is available at http://${_INSTANCE_PUBLIC_DNS_NAME}" +} diff --git a/inc/aws.sh b/inc/aws.sh index 8bf50c1..f638c64 100755 --- a/inc/aws.sh +++ b/inc/aws.sh @@ -27,6 +27,9 @@ createAndInstallKeypair() { rm -f /tmp/keypair.out return 1 else + if [ -f ~/.ssh/${_KEYPAIR_NAME}.pem ]; then + rm -f ~/.ssh/${_KEYPAIR_NAME}.pem + fi cat /tmp/keypair.out | python -c "import sys, json; print json.load(sys.stdin)['KeyMaterial']" > ~/.ssh/${_KEYPAIR_NAME}.pem mkdir -p ~/.ssh chmod 700 ~/.ssh From 15abcbf0fa8fab1575f225c9ca4e542c825b20bd Mon Sep 17 00:00:00 2001 From: ju-ponectus Date: Mon, 13 Feb 2017 17:32:32 +0100 Subject: [PATCH 5/7] Readme file --- README.md | 65 +++++++++++++++++-------------------------------------- 1 file changed, 20 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index ac59dab..77038e1 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,33 @@ # Wave Operations Engineering Development Challenge -Applicants for the [Operations Engineering team](https://wave.bamboohr.co.uk/jobs/) at Wave must complete the following challenge, and submit a solution prior to the interviewing process. +This is my (Julien) submission for Wave ops challenge. -The purpose of this exercise is to create something that we can discuss during the on-site interview, and that's representative of the kind of things we do here on a daily basis. +## What I have done -There isn't a hard deadline for this exercise; take as long as you need to complete it. However, in terms of total time spent actively working on the challenge, we ask that you not spend more than a few hours, as we value your time and expect to leave things open to discussion in the on-site interview. +This project only consists in some shell scripts, I just wanted to keep it simple and be as efficient as possible. +I'm somewhat proud of acheiving this challenge because I had never used AWS until now. And I have also learned a lot of thing about Python web apps since it was also the first time I have to deploy this kind of things. -Send your completed submission to your contact at Wave. Feel free to email [ops.careers@waveapps.com](ops.careers@waveapps.com) if you have any questions. +## How it works -## Submission Instructions +Simply run aws-app.sh to deploy the app. There are also some parameters : -1. Fork this project on GitHub - you'll need to create an account if you don't already have one -1. Complete the project as described below within your fork -1. Push all of your changes to your fork on GitHub and submit a pull request -1. Email your contact at Wave to let them know you have submitted a solution, and make sure to include your GitHub username in your email (so we can match applicants with pull requests) +```bash +usage: $0 [-b|--branch-or-tag ][-h|--help] -## Alternate Submission Instructions (if you don't want to publicize completing the challenge) - -1. Clone the repository -1. Complete your project as described below within your local repository -1. Email a patch file to your contact at Wave - -## Project Description - -There's a basic Python app available [here](https://github.com/wvchallenges/opseng-challenge-app). Your task is to host this app on AWS, using the current `HEAD` of the `master` branch as of when we test your submission. - -The OS used for hosting, and the tools & techniques used to accomplish this are up to you. Once you're done, please submit a paragraph or two in your `README` about what you're particularly proud of in your implementation, and why. Be deliberate in your choices and design, as we'll use them as a starting point for our discussions. - -### Deliverables - -You should provide at least an executable bash script called `aws-app.sh`. You're welcome to include other files and install/use other tools in your repo as needed, but `aws-app.sh` is what we'll run to test your submission (see the evaluation section). - -#### Notes - -* **Do not check AWS keys or any other secret credentials into git** -* Prefix all of your AWS resources (when possible) with your first name (example: joanne.domain.com) +-b|--branch-or-tag Sets the branch or tag name of the GitHub repository to deploy to AWS +-h|--help Prints this help message +``` -## Evaluation +## Some more info -We'll do the following, using on a stock OSX machine with Python 2.7.10 or higher (but <3.0), the `awscli` Python package installed, and appropriate AWS environment variables set: -``` -$ git clone / # Or we'll apply your patch file to a checked-out branch -$ cd -$ ./aws-app.sh -``` -We expect that this will output a URL, and we'll then visit that URL to confirm it has the output generated by the current `HEAD` of the `master` branch of the repo linked to above. +I chose to use an Ubuntu EC2 instance because I use Debian-based distros every day, so I really feel comfortable using then. +It is the same for the Nginx server I used, I know it is a quite solid and easy to install solution when you need a reverse proxy to publish a web app. -When we're evaluating your submission, some of the questions we'll be asking are: +## Improvements -* If we follow the steps above, do we end up with a working app at the URL specified? -* Does the working app reflect what's at the `HEAD` of the `master` branch right now, or at a point in the past? -* If we wanted to push out an updated version of the app's code, how much work would that be? -* Which application(s) and OS were chosen to host the app, and why? -* Which hosting strategy was selected, and did you have a good reason to pick that one? -* Are the decisions and strengths/weaknesses of this strategy discussed? -* How much of the hosting infrastructure is created when calling `aws-app.sh`, and how much does the script assume already exists or is created by hand in the console? +Some things could be improved in what I have done: +- Use something like [RunIt](https://wiki.debian.org/runit) to manage Gunicorn deamon and to be sure it runs after the EC2 instance is restarted for instance +- Extract parameters from main shell script in order to store them in a Yaml file for instance, which is more user-friendly +- Store the opseng-challenge-app files in a S3 bucket and mount this storage from EC2 instance in order to be able to quickly scale up the system by adding some other EC2 instances sharing the same bucket. +- Use Route53 to define an easy to remember DNS name for the app From 5fdfac1c97db3302471dd258385e2e51aa9508c2 Mon Sep 17 00:00:00 2001 From: ju-ponectus Date: Mon, 13 Feb 2017 17:33:23 +0100 Subject: [PATCH 6/7] Readme typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 77038e1..7100090 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ I'm somewhat proud of acheiving this challenge because I had never used AWS unti Simply run aws-app.sh to deploy the app. There are also some parameters : ```bash -usage: $0 [-b|--branch-or-tag ][-h|--help] +usage: ./aws-app.sh [-b|--branch-or-tag ][-h|--help] -b|--branch-or-tag Sets the branch or tag name of the GitHub repository to deploy to AWS -h|--help Prints this help message From 9e7aedeeb20c043a3b54a21fcb7d17af64bed3e5 Mon Sep 17 00:00:00 2001 From: ju-ponectus Date: Mon, 13 Feb 2017 20:40:40 +0100 Subject: [PATCH 7/7] Correct some bugs and final cleanup --- README.md | 2 ++ aws-app.sh | 7 +++-- inc/aws-app-steps.sh | 57 ++++++++++++++++++---------------- inc/aws.sh | 26 ++++------------ inc/{outputs.sh => toolbox.sh} | 17 ++++++---- resources/nginx/helloapp | 4 +-- 6 files changed, 57 insertions(+), 56 deletions(-) rename inc/{outputs.sh => toolbox.sh} (88%) diff --git a/README.md b/README.md index 7100090..e31b983 100644 --- a/README.md +++ b/README.md @@ -31,3 +31,5 @@ Some things could be improved in what I have done: - Extract parameters from main shell script in order to store them in a Yaml file for instance, which is more user-friendly - Store the opseng-challenge-app files in a S3 bucket and mount this storage from EC2 instance in order to be able to quickly scale up the system by adding some other EC2 instances sharing the same bucket. - Use Route53 to define an easy to remember DNS name for the app +- Use virtualenv to run Python web app in a box and to be able to publish other Python apps using different versions of the same libraries +- Use Docker to containerize the app and to be able to deploy it everywhere (different OSes, different cloud providers...) diff --git a/aws-app.sh b/aws-app.sh index 642cc95..a873e19 100755 --- a/aws-app.sh +++ b/aws-app.sh @@ -36,7 +36,7 @@ SCP_CMD="scp -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~ # Get this script install dir SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" -source "${SCRIPT_DIR}/inc/outputs.sh" +source "${SCRIPT_DIR}/inc/toolbox.sh" source "${SCRIPT_DIR}/inc/aws.sh" source "${SCRIPT_DIR}/inc/aws-app-steps.sh" @@ -76,7 +76,7 @@ manageSecGrp ${SECGRP_NAME} "${SECGRP_DESC}" # 3- Create EC2 instance manageInstance ${AWS_EC2_UBUNTU_AMI_ID} ${AWS_EC2_INSTANCE_TYPE} ${KEY_PAIR_NAME} ${SECGRP_NAME} ${AWS_EC2_INSTANCE_TAG_NAME} ${AWS_EC2_INSTANCE_TAG_VALUE} "${SSH_CMD}" -INSTANCE_ID=$(getInstanceId ${AWS_EC2_INSTANCE_TAG_NAME} ${AWS_EC2_INSTANCE_TAG_VALUE}) +INSTANCE_ID=$(cat ./instance.id) INSTANCE_PUBLIC_DNS_NAME=$(getInstancePublicDnsName ${INSTANCE_ID}) echoInfo "EC2 instance public DNS name: ${INSTANCE_PUBLIC_DNS_NAME}" @@ -84,3 +84,6 @@ echoInfo "EC2 instance public DNS name: ${INSTANCE_PUBLIC_DNS_NAME}" setupAndDeployApp ${INSTANCE_PUBLIC_DNS_NAME} $HELLO_APP_BRANCH_OR_TAG $HELLO_APP_GIT_URL \ $HELLOAPP_INSTALLDIR $AWS_EC2_UBUNTU_LOGIN "$REQUIRED_PKGS" "${SCRIPT_DIR}/${NGINX_TEMPLATE}" \ $GUNICORN_PORT $NGINX_CONFDIR "$SSH_CMD" "$SCP_CMD" + +# 5- Exit +cleanupAndExit 0 diff --git a/inc/aws-app-steps.sh b/inc/aws-app-steps.sh index 8246f05..7666ac5 100644 --- a/inc/aws-app-steps.sh +++ b/inc/aws-app-steps.sh @@ -1,6 +1,5 @@ #!/bin/bash - manageKeypair() { local _KEY_PAIR_NAME=$1 @@ -11,7 +10,7 @@ manageKeypair() { createAndInstallKeypair ${_KEY_PAIR_NAME} if [ $? -ne 0 ]; then echoError "Could not create and install new key pair. Exiting." - exit 1 + cleanupAndExit 1 fi else echoSuccess "${_KEY_PAIR_NAME} key pair already exists." @@ -20,17 +19,16 @@ manageKeypair() { deleteKeypair ${_KEY_PAIR_NAME} if [ $? -ne 0 ]; then echoError "Could not delete existing key pair. Exiting." - exit 1 + cleanupAndExit 1 fi createAndInstallKeypair ${_KEY_PAIR_NAME} if [ $? -ne 0 ]; then echoError "Could not create and install new key pair. Exiting." - exit 1 + cleanupAndExit 1 fi fi fi } -export -f manageKeypair manageSecGrp() { local _SECGRP_NAME=$1 @@ -44,7 +42,7 @@ manageSecGrp() { createSecGrp ${_SECGRP_NAME} "${_SECGRP_DESC}" if [ $? -ne 0 ]; then echoError "Could not create security group. Exiting." - exit 1 + cleanupAndExit 1 fi _CREATE_RULES=1 else @@ -58,12 +56,11 @@ manageSecGrp() { createSecGrpRule ${_SECGRP_NAME} ${i} if [ $? -ne 0 ]; then echoError "Could not create inbound rule for port ${i}. Exiting." - exit 1 + cleanupAndExit 1 fi done fi } -export -f manageSecGrp manageInstance() { local _EC2_AMI_ID=$1 @@ -74,6 +71,10 @@ manageInstance() { local _TAG_VALUE=$6 local _SSH_CMD="$7" + if [ -f ./instance.id ]; then + rm -f ./instance.id + fi + echoStep "Create EC2 instance" checkInstance ${_TAG_NAME} ${_TAG_VALUE} if [ $? -eq 0 ]; then @@ -81,30 +82,31 @@ manageInstance() { local _INSTANCE_ID=$(getInstanceId ${_TAG_NAME} ${_TAG_VALUE}) if [ $? -ne 0 ]; then echoError "Could not get EC2 instance ID" - exit 1 + cleanupAndExit 1 fi local _INSTANCE_PUBLIC_DNS_NAME=$(getInstancePublicDnsName ${_INSTANCE_ID}) if [ $? -ne 0 ]; then echoError "Could not get EC2 instance public DNS name" - exit 1 + cleanupAndExit 1 fi echoInfo "Existing EC2 instance public DNS name: ${_INSTANCE_PUBLIC_DNS_NAME}" ${_SSH_CMD} ${_INSTANCE_PUBLIC_DNS_NAME} exit if [ $? -ne 0 ]; then - echoError "Could not ssh EC2 instance. We are going to delete and recreate it." + echoWarning "Could not ssh EC2 instance. We are going to delete and recreate it." deleteInstance ${_INSTANCE_ID} if [ $? -ne 0 ]; then echoError "Could not terminate existing instance. Exiting." - exit 1 + cleanupAndExit 1 fi echoSuccess "EC2 instance successfully deleted." echoInfo "Create new EC2 instance." createAndTagInstance ${_EC2_AMI_ID} ${_EC2_INSTANCE_TYPE} ${_KEY_PAIR_NAME} ${_SECGRP_NAME} ${_TAG_NAME} ${_TAG_VALUE} else + echo $_INSTANCE_ID > ./instance.id echoSuccess "SSH connection to EC2 instance successfully acheived." fi else - echoInfo "EC2 instance not found, we are going to create it." + echoWarning "EC2 instance not found, we are going to create it." createAndTagInstance ${_EC2_AMI_ID} ${_EC2_INSTANCE_TYPE} ${_KEY_PAIR_NAME} ${_SECGRP_NAME} ${_TAG_NAME} ${_TAG_VALUE} fi } @@ -120,16 +122,17 @@ createAndTagInstance() { local _INSTANCE_ID=$(createAndRunInstance ${_EC2_AMI_ID} ${_EC2_INSTANCE_TYPE} ${_KEY_PAIR_NAME} ${_SECGRP_NAME}) if [ $? -ne 0 ]; then echoError "Could not create and run new EC2 instance. Exiting." - exit 1 + cleanupAndExit 1 fi echoSuccess "EC2 instance successfully created and launched." + echo $_INSTANCE_ID > ./instance.id echoStep "Wait some time so as to let EC2 instance start..." sleep 5 echoInfo "Create tag for new instance" tagInstance ${_INSTANCE_ID} ${_TAG_NAME} ${_TAG_VALUE} if [ $? -ne 0 ]; then echoError "Could not create tag EC2 instance. Exiting." - exit 1 + cleanupAndExit 1 fi echoSuccess "EC2 instance successfully tagged." } @@ -152,14 +155,14 @@ setupAndDeployApp() { ${_SSH_CMD} ${_INSTANCE_PUBLIC_DNS_NAME} "sudo apt-get update -q > /dev/null 2>&1" if [ $? -ne 0 ]; then echoError "Unable to update packages list. Exiting." - exit 1 + cleanupAndExit 1 fi echoSuccess "Packages list successfully updated." echoInfo "Install required packages on instance (${_REQUIRED_PKGS})" ${_SSH_CMD} ${_INSTANCE_PUBLIC_DNS_NAME} "sudo apt-get install -yq ${_REQUIRED_PKGS} > /dev/null 2>&1" if [ $? -ne 0 ]; then echoError "Something went wrong during packages installation. Exiting." - exit 1 + cleanupAndExit 1 fi echoSuccess "Required packages successfully installed." echoInfo "Get HelloApp code (branch or tag = ${_APP_BRANCH_OR_TAG})" @@ -170,23 +173,24 @@ setupAndDeployApp() { && git clone --branch ${_APP_BRANCH_OR_TAG} --depth 1 ${_APP_URL} . > /dev/null 2>&1" if [ $? -ne 0 ]; then echoError "Something went wrong during Hello App source code installation. Exiting." - exit 1 + cleanupAndExit 1 fi echoSuccess "Hello App source code successfully downloaded." echoInfo "Install HelloApp Python requirements" ${_SSH_CMD} ${_INSTANCE_PUBLIC_DNS_NAME} "cd ${_APP_INSTALLDIR} \ - && sudo pip install -r requirements.txt > /dev/null 2>&1" + && sudo pip install -r requirements.txt > /dev/null 2>&1" if [ $? -ne 0 ]; then echoError "Something went wrong during Hello App Python requirements installation. Exiting." - exit 1 + cleanupAndExit 1 fi echoSuccess "Hello App source Python requirements successfully installed." echoInfo "Launch Gunicorn" - ${_SSH_CMD} ${_INSTANCE_PUBLIC_DNS_NAME} "cd ${_APP_INSTALLDIR} \ - && sudo gunicorn -D app:app > /dev/null 2>&1" + ${_SSH_CMD} ${_INSTANCE_PUBLIC_DNS_NAME} "sudo killall -q gunicorn ; \ + cd ${_APP_INSTALLDIR} \ + && sudo gunicorn -b 127.0.0.1:${_GUNICORN_PORT} -D app:app > /dev/null 2>&1" if [ $? -ne 0 ]; then echoError "An error occured while trying to launch Gunicorn. Exiting." - exit 1 + cleanupAndExit 1 fi echoSuccess "Gunicorn successfully started." echoInfo "Generate Nginx configuration from template" @@ -195,15 +199,16 @@ setupAndDeployApp() { s/##GUNICORN_PORT##/${_GUNICORN_PORT}/g" "${_NGING_TPL}" > /tmp/helloapp.nginx 2> /dev/null if [ $? -ne 0 ]; then echoError "Something went wrong during Nginx configuration generation. Exiting." - exit 1 + cleanupAndExit 1 fi echoSuccess "NGinx configuration successfully generated." echoInfo "Send Nginx configuration to EC2 instance" ${_SCP_CMD} /tmp/helloapp.nginx ${_INSTANCE_LOGIN}@${_INSTANCE_PUBLIC_DNS_NAME}:/tmp/helloapp if [ $? -ne 0 ]; then echoError "Something went wrong during Nginx configuration SCP transfer. Exiting." - exit 1 + cleanupAndExit 1 fi + rm -f /tmp/helloapp.nginx echoSuccess "NGinx configuration successfully sent to EC2 instance." echoInfo "Configure Nginx on EC2 instance" ${_SSH_CMD} ${_INSTANCE_PUBLIC_DNS_NAME} "sudo cp /tmp/helloapp ${_NGINX_CONFDIR}/sites-available \ @@ -212,7 +217,7 @@ setupAndDeployApp() { && sudo service nginx restart > /dev/null 2>&1" if [ $? -ne 0 ]; then echoError "Something went wrong during Nginx configuration. Exiting." - exit 1 + cleanupAndExit 1 fi echoSuccess "NGinx successfully configured." echoStep "HelloApp deployment successfully finished, it is available at http://${_INSTANCE_PUBLIC_DNS_NAME}" diff --git a/inc/aws.sh b/inc/aws.sh index f638c64..f59e7d4 100755 --- a/inc/aws.sh +++ b/inc/aws.sh @@ -10,35 +10,30 @@ checkKeypair() { ${AWS_CLI_EC2_CMD} describe-key-pairs --key-names ${_KEYPAIR_NAME} > /dev/null 2>&1 } -export -f checkKeypair deleteKeypair() { local _KEYPAIR_NAME=$1 ${AWS_CLI_EC2_CMD} delete-key-pair --key-name ${_KEYPAIR_NAME} > /dev/null 2>&1 } -export -f deleteKeypair createAndInstallKeypair() { local _KEYPAIR_NAME=$1 - ${AWS_CLI_EC2_CMD} create-key-pair --key-name ${_KEYPAIR_NAME} > /tmp/keypair.out 2>&1 + ${AWS_CLI_EC2_CMD} create-key-pair --key-name ${_KEYPAIR_NAME} > /tmp/julien.keypair.out 2>&1 if [ $? -ne 0 ]; then - rm -f /tmp/keypair.out return 1 else if [ -f ~/.ssh/${_KEYPAIR_NAME}.pem ]; then rm -f ~/.ssh/${_KEYPAIR_NAME}.pem fi - cat /tmp/keypair.out | python -c "import sys, json; print json.load(sys.stdin)['KeyMaterial']" > ~/.ssh/${_KEYPAIR_NAME}.pem + cat /tmp/julien.keypair.out | python -c "import sys, json; print json.load(sys.stdin)['KeyMaterial']" > ~/.ssh/${_KEYPAIR_NAME}.pem mkdir -p ~/.ssh chmod 700 ~/.ssh chmod 400 ~/.ssh/${_KEYPAIR_NAME}.pem - rm -f /tmp/keypair.out return 0 fi } -export -f createAndInstallKeypair # Security group management checkSecGrp() { @@ -46,7 +41,6 @@ checkSecGrp() { ${AWS_CLI_EC2_CMD} describe-security-groups --group-names ${_SECGRP_NAME} > /dev/null 2>&1 } -export -f checkSecGrp createSecGrp() { local _SECGRP_NAME=$1 @@ -54,23 +48,21 @@ createSecGrp() { ${AWS_CLI_EC2_CMD} create-security-group --group-name ${_SECGRP_NAME} --description "${_SECGRP_DESC}" > /dev/null 2>&1 } -export -f createSecGrp createSecGrpRule() { local _SECGRP_NAME=$1 local _SECGRP_RULE_PORT=$2 - ${AWS_CLI_EC2_CMD} authorize-security-group-ingress --group-name ${_SECGRP_NAME} --protocol tcp --port ${_SECGRP_RULE_PORT} --cidr 0.0.0.0/0 > /dev/null 2> /tmp/secgroup_rule.err + ${AWS_CLI_EC2_CMD} authorize-security-group-ingress --group-name ${_SECGRP_NAME} --protocol tcp --port ${_SECGRP_RULE_PORT} --cidr 0.0.0.0/0 > /dev/null 2> /tmp/julien.secgroup_rule.out if [ $? -ne 0 ]; then - if [ $(grep -c "InvalidPermission.Duplicate" /tmp/secgroup_rule.err) -gt 0 ]; then + if [ $(grep -c "InvalidPermission.Duplicate" /tmp/julien.secgroup_rule.out) -gt 0 ]; then return 0 fi return 1 fi return 0 } -export -f createSecGrpRule # Instances management checkInstance() { @@ -85,7 +77,6 @@ checkInstance() { return 1 } -export -f checkInstance getInstanceId() { local _TAG_NAME=$1 @@ -94,14 +85,12 @@ getInstanceId() { local _INSTANCE_ID=$(${AWS_CLI_EC2_CMD} describe-instances --filters "Name=tag:${_TAG_NAME},Values=${_TAG_VALUE}" "Name=instance-state-code,Values=16" | python -c "import sys, json; print json.load(sys.stdin)['Reservations'][0]['Instances'][0]['InstanceId']") echo ${_INSTANCE_ID} } -export -f getInstanceId deleteInstance() { local _INSTANCE_ID=$1 ${AWS_CLI_EC2_CMD} terminate-instances --instance-ids ${_INSTANCE_ID} > /dev/null 2>&1 } -export -f deleteInstance createAndRunInstance() { local _AMI_IMAGE_ID=$1 @@ -109,17 +98,16 @@ createAndRunInstance() { local _KEYPAIR_NAME=$3 local _SECGRP_NAME=$4 - ${AWS_CLI_EC2_CMD} run-instances --image-id ${_AMI_IMAGE_ID} --count 1 --instance-type ${_INSTANCE_TYPE} --key-name ${_KEYPAIR_NAME} --security-groups ${_SECGRP_NAME} > /tmp/instance.out 2>&1 + ${AWS_CLI_EC2_CMD} run-instances --image-id ${_AMI_IMAGE_ID} --count 1 --instance-type ${_INSTANCE_TYPE} --key-name ${_KEYPAIR_NAME} --security-groups ${_SECGRP_NAME} > /tmp/julien.instance.out 2>&1 if [ $? -ne 0 ]; then return 1 else - local _INSTANCE_ID=$(cat /tmp/instance.out | python -c "import sys, json; print json.load(sys.stdin)['Instances'][0]['InstanceId']") + local _INSTANCE_ID=$(cat /tmp/julien.instance.out | python -c "import sys, json; print json.load(sys.stdin)['Instances'][0]['InstanceId']") echo ${_INSTANCE_ID} return 0 fi } -export -f createAndRunInstance getInstancePublicDnsName() { local _INSTANCE_ID=$1 @@ -127,7 +115,6 @@ getInstancePublicDnsName() { local _PUBLIC_DNS_NAME=$(${AWS_CLI_EC2_CMD} describe-instances --instance-ids ${_INSTANCE_ID} | python -c "import sys, json; print json.load(sys.stdin)['Reservations'][0]['Instances'][0]['PublicDnsName']") echo ${_PUBLIC_DNS_NAME} } -export -f getInstancePublicDnsName tagInstance() { local _INSTANCE_ID=$1 @@ -136,4 +123,3 @@ tagInstance() { ${AWS_CLI_EC2_CMD} create-tags --resources ${_INSTANCE_ID} --tags Key=${_TAG_NAME},Value=${_TAG_VALUE} > /dev/null 2>&1 } -export -f tagInstance diff --git a/inc/outputs.sh b/inc/toolbox.sh similarity index 88% rename from inc/outputs.sh rename to inc/toolbox.sh index 7f48d59..8a4162e 100755 --- a/inc/outputs.sh +++ b/inc/toolbox.sh @@ -36,7 +36,6 @@ echoError() { echo $_MSG | cecho RED } -export -f echoError # Prints a warning message to terminal echoWarning() { @@ -44,7 +43,6 @@ echoWarning() { echo $_MSG | cecho ORANGE } -export -f echoWarning # Prints a success message to terminal echoSuccess() { @@ -52,7 +50,6 @@ echoSuccess() { echo $_MSG | cecho GREEN } -export -f echoSuccess # Prints an info message to terminal echoInfo() { @@ -60,7 +57,6 @@ echoInfo() { echo $_MSG } -export -f echoInfo # Prints a debug message to terminal echoDebug() { @@ -68,7 +64,6 @@ echoDebug() { echo $_MSG | cecho CYAN } -export -f echoDebug echoStep() { local _MSG=$1 @@ -87,4 +82,14 @@ Sets up required AWS resources and deploys Python app available here: https://gi Thanks for this challenge! Julien EOF } -export -f printHelp + +cleanupAndExit() { + local _EXIT_CODE=$1 + + if [ -f ./instance.id ]; then + rm -f ./instance.id + fi + find /tmp -maxdepth 1 -type f -name "julien.*.out" -exec rm -f {} \; + + exit $_EXIT_CODE +} diff --git a/resources/nginx/helloapp b/resources/nginx/helloapp index 383c8f3..b5fe0a8 100644 --- a/resources/nginx/helloapp +++ b/resources/nginx/helloapp @@ -2,8 +2,8 @@ server { listen 80; server_name ##SERVERNAME##; - access_log /var/log/nginx-helloapp-access.log; - error_log /var/log/nginx-helloapp-error.log; + access_log /var/log/nginx/helloapp-access.log; + error_log /var/log/nginx/helloapp-error.log; root ##WEBROOT##; location / {