#!/bin/bash set -e exec > >(tee -a /var/log/eb-cfn-init.log|logger -t [eb-cfn-init] -s 2>/dev/console) 2>&1 PREINIT_CMD=' { "api_version" : "1.0", "request_id": "0", "command_name": "CMD-PreInit" } ' SELF_STARTUP_CMD=' { "api_version" : "1.0", "request_id": "0", "command_name": "CMD-SelfStartup" } ' function log { NANOSEC=`date +%N` echo -e [`date -u +"%Y-%m-%dT%H:%M:%S"`.${NANOSEC:0:3}Z] "$@" } # Emit starting log log Started EB Bootstrapping Script. # Update cfn bootstrap to get the latest version of cfn-init etc #yum update -y system-release RPMS=$1 TARBALLS=$2 EB_GEMS=$3 SIGNAL_URL=$4 STACK_ID=$5 REGION=$6 GUID=$7 HEALTHD_GROUP_ID=$8 HEALTHD_ENDPOINT=$9 PROXY_SERVER=${10} HEALTHD_PROXY_LOG_LOCATION=${11} PARAM_LIST="Received parameters:\n\ RPMS = $RPMS\n\ TARBALLS = $TARBALLS\n\ EB_GEMS = $EB_GEMS\n\ SIGNAL_URL = $SIGNAL_URL\n\ STACK_ID = $STACK_ID\n\ REGION = $REGION\n\ GUID = $GUID\n\ HEALTHD_GROUP_ID = $HEALTHD_GROUP_ID\n HEALTHD_ENDPOINT = $HEALTHD_ENDPOINT\n PROXY_SERVER = $PROXY_SERVER\n HEALTHD_PROXY_LOG_LOCATION = $HEALTHD_PROXY_LOG_LOCATION" log $PARAM_LIST # Helper functions function error_exit { cfn-signal 1 "$1" exit 1 } function tailog { log "Tailing $2" echo -e "\n******************* $1 taillog *******************" if [ -f "$2" ]; then echo -e "$(tail -n 50 $2)" else echo -e "***$1 is not available yet.***" fi echo -e "******************* End of taillog *******************\n\n" } function tail_logs { tailog eb-commandprocessor /var/log/eb-commandprocessor.log tailog eb-activity /var/log/eb-activity.log tailog eb-tools /var/log/eb-tools.log tailog eb-version-deployment /var/log/eb-version-deployment.log tailog cfn-init /var/log/cfn-init.log tailog cfn-hup /var/log/cfn-hup.log } function log_and_exit { log $1 # signal success cfn-signal 0 # Output startup logs into the console. tail_logs log Completed EB Bootstrapping Script. exit 0 } function is_baked { if [[ -f /etc/elasticbeanstalk/baking_manifest/$1 ]]; then true else false fi } function mark_installed { mkdir -p /etc/elasticbeanstalk/baking_manifest/ echo `date -u` > /etc/elasticbeanstalk/baking_manifest/$1-manifest } SLEEP_TIME=10 SLEEP_TIME_MAX=86400 # One day function sleep_delay { if (( $SLEEP_TIME < $SLEEP_TIME_MAX )); then log Sleeping $SLEEP_TIME ... sleep $SLEEP_TIME SLEEP_TIME=$(($SLEEP_TIME * 2)) else log Sleeping $SLEEP_TIME_MAX ... sleep $SLEEP_TIME_MAX fi } function retry_execute { log Started executing $@. SLEEP_TIME=10 while true; do FN_OUTPUT="" set +e "$@" RESULT=$? set -e log Command Returned: "$FN_OUTPUT" if (( $RESULT != 0 )); then log "Command return code $RESULT". tail_logs sleep_delay log Retrying... else break fi done log Completed executing $1. } function install_rpms { for RPM_LIB in $@ do log Installing RPM: $RPM_LIB. FULL_NAME=${RPM_LIB##*/} RPM_NAME=${FULL_NAME%.*} INSTALLED_RPM=$(rpm -q $RPM_NAME) RESULT=$? if (( $RESULT == 0 )); then log $RPM_NAME has already been installed. Skip installing. else FN_OUTPUT="$FN_OUTPUT\n\n$(rpm -Uv --nodeps --replacepkgs --oldpackage $RPM_LIB 2>&1)" RESULT=$? if [ $RESULT -ne 0 ]; then return $RESULT fi fi done } function install_tarballs { for TAR_BALL in $@ do log Installing tarball: $TAR_BALL. FULL_NAME=${TAR_BALL##*/} if is_baked ${FULL_NAME}-manifest; then log $FULL_NAME has already been installed. Skip installing. else FN_OUTPUT="$FN_OUTPUT\n\n$(wget --tries=3 --retry-connrefused -nv -O /tmp/$FULL_NAME $TAR_BALL 2>&1 \ && tar --no-same-owner --no-same-permissions -C / -xf /tmp/$FULL_NAME 2>&1 1>/dev/null \ && rm -f /tmp/$FULL_NAME)" RESULT=$? if [ $RESULT -ne 0 ]; then return $RESULT fi mark_installed ${FULL_NAME} fi done } function install_eb_gems { mkdir -p /tmp/ebgems source /opt/elasticbeanstalk/lib/ruby/profile.sh for GEM in $@ do log Installing EB Gem: $GEM. FULL_NAME=${GEM##*/} GEM_FULL_NAME=${FULL_NAME%.*} GEM_NAME=${GEM_FULL_NAME%-*} GEM_VERSION=${GEM_FULL_NAME##*-} INSTALLED=$(gem query -i -v $GEM_VERSION -i $GEM_NAME) RESULT=$? if (( $RESULT == 0)); then log $GEM_FULL_NAME has already been installed. Skip installing. else FN_OUTPUT="$FN_OUTPUT\n\n$(wget --tries=3 --retry-connrefused -nv -O /tmp/ebgems/$FULL_NAME $GEM 2>&1 \ && gem install -f --no-document /tmp/ebgems/$FULL_NAME 2>&1)" RESULT=$? if [ $RESULT -ne 0 ]; then return $RESULT fi fi done rm -rf /tmp/ebgems } function run_healthd { id -u healthd &>/dev/null || useradd -s /sbin/nologin healthd # Healthd config files mkdir -p /etc/healthd # root owns # Healthd logs mkdir -p /var/log/healthd chown healthd:healthd /var/log/healthd # Healthd pid directory mkdir -p /var/run/healthd chown healthd:healthd /var/run/healthd # Healthd base plugin directory mkdir -p /var/elasticbeanstalk/healthd # root owns # for reboots rm -f /etc/healthd/config.yaml echo "group_id: $HEALTHD_GROUP_ID" >> /etc/healthd/config.yaml if [ -n "$HEALTHD_ENDPOINT" ] then echo "endpoint: $HEALTHD_ENDPOINT" >> /etc/healthd/config.yaml fi echo "log_to_file: true" >> /etc/healthd/config.yaml if [ "$PROXY_SERVER" == "httpd" ] then echo "appstat_log_path: /var/log/httpd/healthd/application.log" >> /etc/healthd/config.yaml echo "appstat_unit: usec" >> /etc/healthd/config.yaml echo "appstat_timestamp_on: arrival" >> /etc/healthd/config.yaml elif [ "$PROXY_SERVER" == "nginx" ] then echo "appstat_log_path: /var/log/nginx/healthd/application.log" >> /etc/healthd/config.yaml echo "appstat_unit: sec" >> /etc/healthd/config.yaml echo "appstat_timestamp_on: completion" >> /etc/healthd/config.yaml elif [ "$PROXY_SERVER" == "other" ] then echo "appstat_log_path: $HEALTHD_PROXY_LOG_LOCATION" >> /etc/healthd/config.yaml echo "appstat_unit: sec" >> /etc/healthd/config.yaml echo "appstat_timestamp_on: completion" >> /etc/healthd/config.yaml fi cat << EOF1 > /etc/init/healthd.conf description "Elastic Beanstalk Healthd Upstart Manager" author "Elastic Beanstalk" start on runlevel [2345] stop on runlevel [!2345] respawn respawn limit 15 5 script exec /bin/bash <<"EOF2" if [ -d /etc/healthd ] then source /opt/elasticbeanstalk/lib/ruby/profile.sh exec su -s /bin/bash -c "healthd" healthd fi EOF2 end script EOF1 # force restart for custom AMIs initctl restart healthd || initctl start healthd if ( initctl status healthd | grep stop ); then initctl start healthd # wait for healthd to gracefully start first for i in `seq 1 60`; do status_output=`curl -s localhost:22221/status || true` if [ "$status_output" == '{"status":"ok"}' ]; then echo $status_output; break; fi; echo $status_output; echo "Waiting for healthd to start ..."; sleep 0.5; done fi } function stop_healthd { # remove config so it does not restart rm -rf /etc/healthd # try to stop if already running initctl stop healthd || true; # remove upstart script rm -rf /etc/init/healthd.conf } function cfn_init { log Running cfn-init ConfigSet: $1. if [[ $2 == "first_init" ]]; then local stackname=$STACK_ID else local stackname=$(/opt/elasticbeanstalk/bin/get-config meta -k stackname) log Using local cached stack name for reboot. fi FN_OUTPUT=$(EB_EVENT_FILE=/var/log/eb-startupevents.log EB_SYSTEM_STARTUP=true /opt/aws/bin/cfn-init -s "$stackname" \ -r AWSEBAutoScalingGroup --region "$REGION" --configsets $1 > /var/log/eb-cfn-init-call.log 2>&1 ) } function cfn-signal { local signalurl=$(/opt/elasticbeanstalk/bin/get-config meta -k instance_signal_url) if [[ -z $signalurl ]]; then # use default signal url if not specified in metadata signalurl=$SIGNAL_URL fi if [[ -z $2 ]]; then local reason="" else local reason=" -r $2 " fi log Sending signal $1 to CFN wait condition $signalurl /opt/aws/bin/cfn-signal -e $1 $reason "$signalurl" || log 'Wait Condition Signal expired.' } function run_eb_command { log Running EB Command: $1. FN_OUTPUT=$(CMD_DATA=$1 /opt/elasticbeanstalk/bin/command-processor -e) } function start_cfn_hup { log Starting cfn-hup. FN_OUTPUT=$(start cfn-hup LANG=$LANG) } function sync_clock { log Synchronizing network time in background. nohup ntpdate -u 0.amazon.pool.ntp.org 1.amazon.pool.ntp.org 2.amazon.pool.ntp.org 3.amazon.pool.ntp.org & } function lock_repo_version { if is_baked lock_repo_version_$GUID; then log yum repo has already been locked to $GUID. else log Locking yum repo version to GUID. mkdir -p /etc/yum/vars echo $GUID > /etc/yum/vars/guid chmod 644 /etc/yum/vars/guid for i in updates preview gpu nosrc hvm graphics; do local repo_file="/etc/yum.repos.d/amzn-$i.repo" if [ -f $repo_file ]; then sed -i -r 's/mirror.list$/mirror.list-$guid/' $repo_file fi local template_file="/etc/cloud/templates/amzn-$i.repo.tmpl" if [ -f $template_file ]; then sed -i -r 's/mirror.list$/mirror.list-\\$guid/' $template_file fi done yum clean -y all || echo Warning: cannot clean local yum cache. Continue... mark_installed lock_repo_version_$GUID log Completed yum repo version locking. fi } function update_yum_packages { if is_baked update_yum_packages_$GUID; then log yum update has already been done. else log Updating yum packages. yum --exclude=aws-cfn-bootstrap update -y || echo Warning: cannot update yum packages. Continue... mark_installed update_yum_packages_$GUID log Completed updating yum packages. fi } function create_eb_user_group { groupadd -f -r awseb log Completed creating AWS EB users and groups. } #------------- Start of Execution ----------------- sync_clock # Yum package update lock_repo_version update_yum_packages # create users and groups create_eb_user_group ## Install Packages ## retry_execute install_rpms $RPMS retry_execute install_tarballs $TARBALLS retry_execute install_eb_gems $EB_GEMS if [ -n "$HEALTHD_GROUP_ID" ] then # enhanced health log "Starting healthd" run_healthd else # basic health log "Ensuring healthd is not running" # could be already running if AMI baked from enhanced health environment stop_healthd fi # branch on if instance already initialized # set EB_FIRST_RUN only on first run, otherwise empty if [[ $(/opt/elasticbeanstalk/eb_infra/infra-provision_registrar.rb instance-init check) == "first_init" ]]; then log First init of instance. export EB_FIRST_RUN=true retry_execute cfn_init '_OnInstanceBoot' 'first_init' /opt/elasticbeanstalk/eb_infra/infra-provision_registrar.rb instance-init mark else log Reboot of instance. retry_execute cfn_init '_OnInstanceReboot' fi log Check whether controlled by launch workflow... export EB_IS_WORKFLOW_RUNNING=false LAUNCH_S3_URL=$(/opt/elasticbeanstalk/bin/get-config meta -k launchs3url) || log 'Failed to find launch s3 url.' if [[ "$LAUNCH_S3_URL" ]]; then if wget -q "$LAUNCH_S3_URL" > /dev/null; then log Worflow running. export EB_IS_WORKFLOW_RUNNING=true fi fi if [[ "$EB_IS_WORKFLOW_RUNNING" == "true" ]]; then log Workflow controlled instance. Running container provisioning... retry_execute start_cfn_hup retry_execute run_eb_command "$PREINIT_CMD" else log Scaled up instance. Running full self-initiated provisioning. # Writing startup version to prevent duplicate execution # retry_execute write_metadata retry_execute run_eb_command "$PREINIT_CMD" retry_execute run_eb_command "$SELF_STARTUP_CMD" retry_execute start_cfn_hup fi log_and_exit 'Successfully bootstrapped instance.'