github.com/technosophos/deis@v1.7.1-0.20150915173815-f9005256004b/contrib/aws/provision-aws-cluster.sh (about) 1 #!/usr/bin/env bash 2 # 3 # Usage: ./provision-aws-cluster.sh [name] 4 # The [name] is the CloudFormation stack name, and defaults to 'deis' 5 6 if [ -z "$1" ] 7 then 8 STACK_NAME=deis 9 else 10 STACK_NAME=$1 11 fi 12 13 set -e 14 15 THIS_DIR=$(cd $(dirname $0); pwd) # absolute path 16 CONTRIB_DIR=$(dirname $THIS_DIR) 17 18 source $CONTRIB_DIR/utils.sh 19 20 # check for AWS API tools in $PATH 21 if ! which aws > /dev/null; then 22 echo_red 'Please install the AWS command-line tool and ensure it is in your $PATH.' 23 exit 1 24 fi 25 26 if [ ! -z "$AWS_CLI_PROFILE" ]; then 27 EXTRA_AWS_CLI_ARGS+="--profile $AWS_CLI_PROFILE" 28 fi 29 30 if [ -z "$DEIS_NUM_INSTANCES" ]; then 31 DEIS_NUM_INSTANCES=3 32 fi 33 34 # make sure we have all VPC info 35 if [ -n "$VPC_ID" ]; then 36 if [ -z "$VPC_SUBNETS" ] || [ -z "$VPC_ZONES" ]; then 37 echo_red 'To provision Deis in a VPC, you must also specify VPC_SUBNETS and VPC_ZONES.' 38 exit 1 39 fi 40 fi 41 42 # check that the CoreOS user-data file is valid 43 $CONTRIB_DIR/util/check-user-data.sh 44 45 # Prepare bailout function to prevent us polluting the namespace 46 bailout() { 47 aws cloudformation delete-stack --stack-name $STACK_NAME 48 } 49 50 # create an AWS cloudformation stack based on CoreOS's default template 51 aws cloudformation create-stack \ 52 --template-body "$($THIS_DIR/gen-json.py --channel $COREOS_CHANNEL --version $COREOS_VERSION)" \ 53 --stack-name $STACK_NAME \ 54 --parameters "$(<$THIS_DIR/cloudformation.json)" \ 55 $EXTRA_AWS_CLI_ARGS 56 57 # loop until the instances are created 58 ATTEMPTS=60 59 SLEEPTIME=10 60 COUNTER=1 61 INSTANCE_IDS="" 62 until [ $(wc -w <<< $INSTANCE_IDS) -eq $DEIS_NUM_INSTANCES -a "$STACK_STATUS" = "CREATE_COMPLETE" ]; do 63 if [ $COUNTER -gt $ATTEMPTS ]; then 64 echo "Provisioning instances failed (timeout, $(wc -w <<< $INSTANCE_IDS) of $DEIS_NUM_INSTANCES provisioned after 10m)" 65 echo "Destroying stack $STACK_NAME" 66 bailout 67 exit 1 68 fi 69 70 STACK_STATUS=$(aws --output text cloudformation describe-stacks --stack-name $STACK_NAME --query 'Stacks[].StackStatus' $EXTRA_AWS_CLI_ARGS) 71 if [ $STACK_STATUS != "CREATE_IN_PROGRESS" -a $STACK_STATUS != "CREATE_COMPLETE" ] ; then 72 echo "error creating stack: " 73 aws --output text cloudformation describe-stack-events \ 74 --stack-name $STACK_NAME \ 75 --query 'StackEvents[?ResourceStatus==`CREATE_FAILED`].[LogicalResourceId,ResourceStatusReason]' \ 76 $EXTRA_AWS_CLI_ARGS 77 bailout 78 exit 1 79 fi 80 81 INSTANCE_IDS=$(aws ec2 describe-instances \ 82 --filters Name=tag:aws:cloudformation:stack-name,Values=$STACK_NAME Name=instance-state-name,Values=running \ 83 --query 'Reservations[].Instances[].[ InstanceId ]' \ 84 --output text \ 85 $EXTRA_AWS_CLI_ARGS) 86 87 echo "Waiting for instances to be provisioned ($STACK_STATUS, $(expr 61 - $COUNTER)0s) ..." 88 sleep $SLEEPTIME 89 90 let COUNTER=COUNTER+1 91 done 92 93 # loop until the instances pass health checks 94 COUNTER=1 95 INSTANCE_STATUSES="" 96 until [ `wc -w <<< $INSTANCE_STATUSES` -eq $DEIS_NUM_INSTANCES ]; do 97 if [ $COUNTER -gt $ATTEMPTS ]; 98 then echo "Health checks not passed after 10m, giving up" 99 echo "Destroying stack $STACK_NAME" 100 bailout 101 exit 1 102 fi 103 104 if [ $COUNTER -ne 1 ]; then sleep $SLEEPTIME; fi 105 echo "Waiting for instances to pass initial health checks ($(expr 61 - $COUNTER)0s) ..." 106 INSTANCE_STATUSES=$(aws ec2 describe-instance-status \ 107 --filters Name=instance-status.reachability,Values=passed \ 108 --instance-ids $INSTANCE_IDS \ 109 --query 'InstanceStatuses[].[ InstanceId ]' \ 110 --output text \ 111 $EXTRA_AWS_CLI_ARGS) 112 let COUNTER=COUNTER+1 113 done 114 115 # print instance info 116 echo "Instances are available:" 117 aws ec2 describe-instances \ 118 --filters Name=tag:aws:cloudformation:stack-name,Values=$STACK_NAME Name=instance-state-name,Values=running \ 119 --query 'Reservations[].Instances[].[InstanceId,PublicIpAddress,InstanceType,Placement.AvailabilityZone,State.Name]' \ 120 --output text \ 121 $EXTRA_AWS_CLI_ARGS 122 123 # get ELB public DNS name through cloudformation 124 # TODO: is "first output value" going to be reliable enough? 125 export ELB_DNS_NAME=$(aws cloudformation describe-stacks \ 126 --stack-name $STACK_NAME \ 127 --max-items 1 \ 128 --query 'Stacks[].[ Outputs[0].[ OutputValue ] ]' \ 129 --output=text \ 130 $EXTRA_AWS_CLI_ARGS) 131 132 # get ELB friendly name through aws elb 133 ELB_NAME=$(aws elb describe-load-balancers \ 134 --query 'LoadBalancerDescriptions[].[ DNSName,LoadBalancerName ]' \ 135 --output=text \ 136 $EXTRA_AWS_CLI_ARGS | grep -F $ELB_DNS_NAME | head -n1 | cut -f2) 137 echo "Using ELB $ELB_NAME at $ELB_DNS_NAME" 138 139 # Instance launched into a VPC may not have a PublicIPAddress 140 for ip_type in PublicIpAddress PrivateIpAddress; do 141 FIRST_INSTANCE=$(aws ec2 describe-instances \ 142 --filters Name=tag:aws:cloudformation:stack-name,Values=$STACK_NAME Name=instance-state-name,Values=running \ 143 --query "Reservations[].Instances[].[$ip_type]" \ 144 --output text \ 145 $EXTRA_AWS_CLI_ARGS | head -1) 146 if [[ ! $FIRST_INSTANCE == "None" ]]; then 147 break 148 fi 149 done 150 151 if [[ $FIRST_INSTANCE == "None" ]]; then 152 echo_red "The IP of any of your instances could not be found." 153 echo_red "Ensure that the cloudformation stack was created successfully." 154 exit 1 155 fi 156 157 export DEISCTL_TUNNEL=$FIRST_INSTANCE 158 159 # loop until etcd2 / fleet are up and running 160 COUNTER=1 161 until deisctl list >/dev/null; do 162 if [ $COUNTER -gt $ATTEMPTS ]; then 163 echo_red "Timed out waiting for fleet, giving up" 164 echo_red "Ensure that the private key in cloudformation.json" 165 echo_red "is added to your ssh-agent." 166 break 167 fi 168 echo "Waiting until fleet is up and running ..." 169 sleep 5 170 let COUNTER=COUNTER+1 171 done 172 173 echo_green "Enabling proxy protocol" 174 if ! deisctl config router set proxyProtocol=1; then 175 echo_red "# WARNING: Enabling proxy protocol failed." 176 echo_red "# Ensure that the private key in cloudformation.json is added to" 177 echo_red "# your ssh-agent, then enable proxy protocol before continuing:" 178 echo_red "#" 179 echo_red "# deisctl config router set proxyProtocol=1\n" 180 fi 181 182 echo_green "Your Deis cluster was deployed to AWS CloudFormation as stack "$STACK_NAME".\n" 183 echo_green "Now run this command in your shell:" 184 echo_green "export DEISCTL_TUNNEL=$FIRST_INSTANCE" 185 echo_green "and continue to follow the documentation for \"Installing the Deis Platform.\""