github.com/mboersma/deis@v1.13.4/database/bin/boot (about) 1 #!/usr/bin/env bash 2 # 3 # This script is designed to be run inside the container 4 # 5 6 # fail hard and fast even on pipelines 7 set -eo pipefail 8 9 # set debug based on envvar 10 [[ $DEBUG ]] && set -x 11 12 # configure etcd 13 export ETCD_PORT="${ETCD_PORT:-4001}" 14 export ETCD="$HOST:$ETCD_PORT" 15 export ETCD_PATH="${ETCD_PATH:-/deis/database}" 16 export ETCD_TTL="${ETCD_TTL:-20}" 17 18 export BUCKET_NAME=${BUCKET_NAME:-db_wal} 19 20 # wait for etcd to be available 21 until etcdctl --no-sync -C "$ETCD" ls >/dev/null 2>&1; do 22 echo "database: waiting for etcd at $ETCD..." 23 sleep $((ETCD_TTL/2)) # sleep for half the TTL 24 done 25 26 # wait until etcd has discarded potentially stale values 27 sleep $((ETCD_TTL+1)) 28 29 function etcd_set_default { 30 set +e 31 ERROR="$(etcdctl --no-sync -C "$ETCD" mk "$ETCD_PATH/$1" "$2" 2>&1 >/dev/null)" 32 33 if [[ $? -ne 0 ]] && echo "$ERROR" | grep -iqve "key already exists"; then 34 echo "etcd_set_default: an etcd error occurred ($ERROR)" 35 echo "aborting..." 36 exit 1 37 fi 38 set -e 39 } 40 41 etcd_set_default engine postgresql_psycopg2 42 etcd_set_default adminUser "${PG_ADMIN_USER:-postgres}" 43 etcd_set_default adminPass "${PG_ADMIN_PASS:-changeme123}" 44 etcd_set_default user "${PG_USER_NAME:-deis}" 45 etcd_set_default password "${PG_USER_PASS:-changeme123}" 46 etcd_set_default name "${PG_USER_DB:-deis}" 47 etcd_set_default bucketName "${BUCKET_NAME}" 48 49 # stub out the confd reload script before it gets templated 50 echo '#!/bin/sh' > /usr/local/bin/reload 51 chmod 0755 /usr/local/bin/reload 52 53 # wait for confd to run once and install initial templates 54 until confd -onetime -node "$ETCD" -confdir /app --log-level error; do 55 echo "database: waiting for confd to write initial templates..." 56 sleep $((ETCD_TTL/2)) # sleep for half the TTL 57 done 58 59 PG_DATA_DIR=/var/lib/postgresql/9.3/main 60 61 # initialize database if one doesn't already exist 62 # for example, in the case of a data container 63 if [[ ! -d $PG_DATA_DIR ]]; then 64 chown -R postgres:postgres /var/lib/postgresql 65 sudo -u postgres /usr/bin/initdb -D $PG_DATA_DIR 66 fi 67 68 # ensure WAL log bucket exists 69 envdir /etc/wal-e.d/env /app/bin/create_bucket "${BUCKET_NAME}" 70 INIT_ID=$(etcdctl -C "$ETCD" get "$ETCD_PATH/initId" 2> /dev/null || echo none) 71 echo "database: expecting initialization id: $INIT_ID" 72 73 initial_backup=0 74 if [[ "$(cat $PG_DATA_DIR/initialized 2> /dev/null)" != "$INIT_ID" ]]; then 75 echo "database: no existing database found or it is outdated." 76 # check if there are any backups -- if so, let's restore 77 # we could probably do better than just testing number of lines -- one line is just a heading, meaning no backups 78 BACKUP_LIST=$(envdir /etc/wal-e.d/env wal-e --terse backup-list) # if this fails, this script will exit 79 if [[ $(echo "$BACKUP_LIST" | wc -l) -gt "1" ]]; then 80 echo "database: restoring from backup..." 81 rm -rf $PG_DATA_DIR 82 sudo -u postgres envdir /etc/wal-e.d/env wal-e backup-fetch $PG_DATA_DIR LATEST 83 chown -R postgres:postgres $PG_DATA_DIR 84 chmod 0700 $PG_DATA_DIR 85 echo "restore_command = 'envdir /etc/wal-e.d/env wal-e wal-fetch \"%f\" \"%p\"'" | sudo -u postgres tee $PG_DATA_DIR/recovery.conf >/dev/null 86 else 87 echo "database: no backups found. Initializing a new database..." 88 initial_backup=1 89 fi 90 # either way, we mark the database as initialized 91 INIT_ID=$(cat /proc/sys/kernel/random/uuid) 92 echo "$INIT_ID" > $PG_DATA_DIR/initialized 93 etcdctl --no-sync -C "$ETCD" set "$ETCD_PATH/initId" "$INIT_ID" >/dev/null 94 else 95 echo "database: existing data directory found. Starting postgres..." 96 fi 97 98 # Explicitly correct permissions on this file. This compensates for the fact 99 # it may have been initially written by root above, but more importantly, if 100 # it's already owned by root, this will correct the permissions during upgrade. 101 chown postgres:postgres /var/lib/postgresql/9.3/main/initialized 102 103 # run the service in the background 104 sudo -i -u postgres /usr/bin/postgres \ 105 -c config-file="${PG_CONFIG:-/etc/postgresql/main/postgresql.conf}" \ 106 -c listen-addresses="${PG_LISTEN:-*}" & 107 108 SERVICE_PID=$! 109 110 # smart shutdown on SIGINT and SIGTERM 111 function on_exit() { 112 kill -TERM $SERVICE_PID 113 wait $SERVICE_PID 2>/dev/null 114 exit 0 115 } 116 trap on_exit INT TERM 117 118 # spawn confd in the background to update services based on etcd changes 119 confd -node "$ETCD" -confdir /app --log-level error --interval 5 & 120 121 # wait for the service to become available 122 until sudo -u postgres psql -l -t >/dev/null 2>&1; do sleep 1; done 123 124 # perform a one-time reload to populate database entries 125 /usr/local/bin/reload 126 127 if [[ "${initial_backup}" == "1" ]] ; then 128 echo "database: performing an initial backup..." 129 # perform an initial backup 130 sudo -u postgres envdir /etc/wal-e.d/env wal-e backup-push $PG_DATA_DIR 131 fi 132 133 sudo -Eu postgres /app/bin/backup & 134 135 echo "database: postgres is running..." 136 137 # publish the service to etcd using the injected HOST and EXTERNAL_PORT 138 if [[ ! -z $EXTERNAL_PORT ]]; then 139 # configure service discovery 140 PORT=${PORT:-5432} 141 PROTO=${PROTO:-tcp} 142 143 set +e 144 145 # wait for the service to become available on PORT 146 until sudo -u postgres psql -l -t >/dev/null 2>&1; do sleep 1; done 147 148 # while the port is listening, publish to etcd 149 while [[ ! -z $(netstat -lnt | awk "\$6 == \"LISTEN\" && \$4 ~ \".$PORT\" && \$1 ~ \"$PROTO.?\"") ]] ; do 150 etcdctl --no-sync -C "$ETCD" set "$ETCD_PATH/host" "$HOST" --ttl "$ETCD_TTL" >/dev/null 151 etcdctl --no-sync -C "$ETCD" set "$ETCD_PATH/port" "$EXTERNAL_PORT" --ttl "$ETCD_TTL" >/dev/null 152 sleep $((ETCD_TTL/2)) # sleep for half the TTL 153 done 154 155 # if the loop quits, something went wrong 156 exit 1 157 158 fi 159 160 wait