github.com/dustinrc/deis@v1.10.1-0.20150917223407-0894a5fb979e/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.\""