start.sh 9.33 KB
Newer Older
Michał 'rysiek' Woźniak's avatar
Michał 'rysiek' Woźniak committed
1 2
#!/bin/bash

3 4 5 6 7 8 9 10
#
# this waits for changes in files passed in params and sends php-fpm a USR1
# signal to reload the logfiles
#
# we need to watch the containing directories and filter events by files, as
# when a file is open while being deleted (as it happens with php-fpm
# logfiles), inotify fails to register a delete_self event, for some reason.
#
11 12 13 14 15
function watch_logfiles {

    # inform
    echo "+-- watching for changes in watchfile(s):"

16
    # prepare the watch files array
17 18
    unset WATCH_FILES
    WATCH_FILES=()
19 20 21 22 23 24
    
    # build the egrep filter
    # start off with the general events happening directly on watched directories
    EGREP_FILTER="^(.+ (DELETE_SELF|MOVE_SELF|UNMOUNT)"
    
    # get the watch files; filter out `/dev/null`s we don't need
25 26 27 28
    for WATCH_FILE in "$@"; do
        if [ ! $WATCH_FILE = "/dev/null" ]; then
            WATCH_FILES+=("$WATCH_FILE")
            echo "    +-- $WATCH_FILE"
29 30 31
            # add filter for the particular filee in its directory
            # TODO: escape regex special chars in filenames!
            EGREP_FILTER="${EGREP_FILTER}|$( dirname "$WATCH_FILE" )/ (MOVED_FROM|DELETE) $( basename "$WATCH_FILE" )"
32 33
        fi
    done
34
    
35 36 37 38 39 40
    # do we actually have any files to watch?
    if [ ${#WATCH_FILES[@]} = 0 ]; then 
        echo "    +-- no files to watch."
        return 0
    fi
    
41 42
    # finish the regex with a nice dollar sign
    EGREP_FILTER="$EGREP_FILTER)$"
43 44 45

    # loopy-loop!
    while true; do
46
        echo "    +-- checking watchfiles..."
47
        for WATCH_FILE in "${WATCH_FILES[@]}"; do
48
            # if the file is not there, create
49 50
            if [ ! -e "$( dirname "$WATCH_FILE" )" ]; then
                echo "        +-- waiting for missing watch file directory: $( dirname "$WATCH_FILE" )"
51
                sleep 1
52
                continue 2 # we want to break out to the outer loop, and then to continue
53 54
            fi
        done
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
        echo "    +-- watchfiles ok, setting the watches for dirs containing ${WATCH_FILES[*]}"
        
        # monitor for events on directories *containing* the files we want to watch
        # grep only the events we want
        # and then act upon them
        #
        # using pure egrep confuses read in the next piped step, so we need to work
        # around that via a minimal while look; not elegant, but works
        inotifywait -m \
            -e delete_self \
            -e move_self \
            -e unmount \
            -e delete \
            -e moved_from \
            -q $( dirname "${WATCH_FILES[@]}" ) \
            |   while true; do egrep -m 1 "$EGREP_FILTER"; done \
            |   while true; do
                    read -r AN_EVENT
                    echo "    +-- event: $AN_EVENT"
                    echo "        sending USR1 to php-fpm (pid $( cat "$PHP_PID_FILE" ))..."
                    kill -USR1 "$( cat "$PHP_PID_FILE" )"
                    # TODO handle DELETE_SELF, MOVE_SELF, UNMOUNT
                done
78 79 80
    done
}

81 82 83 84 85 86 87 88 89 90 91 92 93
function abort {
    # kill php-fpm if it is running
    [ -s $PHP_PID_FILE ] && kill -USR1 "$( cat "$PHP_PID_FILE" )"
    # inform
    echo
    echo "* * * ABORTED * * *"
    echo
    exit 0
}

# trap whatever we need to trap
trap abort SIGHUP SIGINT SIGQUIT SIGTERM SIGSTOP SIGKILL

Michał 'rysiek' Woźniak's avatar
Michał 'rysiek' Woźniak committed
94 95 96 97 98 99 100 101 102 103 104 105 106
# we need root
if [[ `whoami` != "root" ]]; then
  echo "we need root, and we are: $( whoami ); exiting!.."
  exit 1
fi

# sanity check
if [[ "$PHP_APP_NAME" == "" || "$PHP_APP_USER" == "" || "$PHP_APP_GROUP" == "" || "$PHP_APP_DIR" == "" ]]; then
  echo '$PHP_APP_NAME, $PHP_APP_USER, $PHP_APP_GROUP or $PHP_APP_DIR are not set'
  exit 2
fi

# info
107 108 109 110 111 112 113 114 115 116
echo "\$PHP_APP_NAME         :: $PHP_APP_NAME"
echo "\$PHP_APP_USER         :: $PHP_APP_USER"
echo "\$PHP_APP_GROUP        :: $PHP_APP_GROUP"
echo "\$PHP_APP_DIR          :: $PHP_APP_DIR"
echo "\$PHP_LISTEN           :: $PHP_LISTEN"
echo "\$PHP_ACCESS_LOG       :: $PHP_ACCESS_LOG"
echo "\$PHP_ERROR_LOG        :: $PHP_ERROR_LOG"
echo "\$PHP_SLOW_LOG         :: $PHP_SLOW_LOG"
echo "\$PHP_SLOW_LOG_TIMEOUT :: $PHP_SLOW_LOG_TIMEOUT"
echo "\$PHP_PID_FILE         :: $PHP_PID_FILE"
Michał 'rysiek' Woźniak's avatar
Michał 'rysiek' Woźniak committed
117 118 119

# do we have UID/GID number given explicitly?
if [[ "$PHP_APP_UID" != "" ]]; then
120
  echo "\$PHP_APP_UID          :: $PHP_APP_UID"
Michał 'rysiek' Woźniak's avatar
Michał 'rysiek' Woźniak committed
121 122
fi
if [[ "$PHP_APP_GID" != "" ]]; then
123
  echo "\$PHP_APP_GID          :: $PHP_APP_GID"
Michał 'rysiek' Woźniak's avatar
Michał 'rysiek' Woźniak committed
124 125 126
fi


Michał 'rysiek' Woźniak's avatar
Michał 'rysiek' Woźniak committed
127 128
# get group data, if any, and check if the group exists
if GROUP_DATA=`getent group "$PHP_APP_GROUP"`; then
Michał 'rysiek' Woźniak's avatar
Michał 'rysiek' Woźniak committed
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
  # it does! do we have the gid given?
  if [[ "$PHP_APP_GID" != "" ]]; then
    # we do! do these match?
    if [[ `echo "$GROUP_DATA" | cut -d ':' -f 3` != "$PHP_APP_GID" ]]; then
      # they don't. we have a problem
      echo "ERROR: group $PHP_APP_GROUP already exists, but with a different gid (`echo "$GROUP_DATA" | cut -d ':' -f 3`) than provided ($PHP_APP_GID)!"
      exit 3
    fi
  fi
  # if no gid given, the existing group satisfies us regardless of the GID

# group does not exist
else
  # do we have the gid given?
  GID_ARGS=""
  if [[ "$PHP_APP_GID" != "" ]]; then
    # we do! does a group with a given id exist?
Michał 'rysiek' Woźniak's avatar
Michał 'rysiek' Woźniak committed
146
    if getent group "$PHP_APP_GID" >/dev/null; then
Michał 'rysiek' Woźniak's avatar
Michał 'rysiek' Woźniak committed
147 148 149 150 151 152 153 154 155 156 157 158
      echo "ERROR: a group with a given id ($PHP_APP_GID) already exists, can't create group $PHP_APP_GROUP with this id"
      exit 4
    fi
    # prepare the fragment of the groupadd command
    GID_ARGS="-g $PHP_APP_GID"
  fi
  # we either have no GID given (and don't care about it), or have a GID given that does not exist in the system
  # great! let's add the group
  groupadd $GID_ARGS "$PHP_APP_GROUP"
fi


Michał 'rysiek' Woźniak's avatar
Michał 'rysiek' Woźniak committed
159 160
# get user data, if any, and check if the user exists
if USER_DATA=`id -u "$PHP_APP_USER" 2>/dev/null`; then
Michał 'rysiek' Woźniak's avatar
Michał 'rysiek' Woźniak committed
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
  # it does! do we have the uid given?
  if [[ "$PHP_APP_UID" != "" ]]; then
    # we do! do these match?
    if [[ "$USER_DATA" != "$PHP_APP_UID" ]]; then
      # they don't. we have a problem
      echo "ERROR: user $PHP_APP_USER already exists, but with a different uid ("$USER_DATA") than provided ($PHP_APP_UID)!"
      exit 5
    fi
  fi
  # if no uid given, the existing user satisfies us regardless of the uid
  # but is he in the right group?
  adduser "$PHP_APP_USER" "$PHP_APP_GROUP"

# user does not exist
else
  # do we have the uid given?
  UID_ARGS=""
  if [[ "$PHP_APP_UID" != "" ]]; then
    # we do! does a group with a given id exist?
Michał 'rysiek' Woźniak's avatar
Michał 'rysiek' Woźniak committed
180
    if getent passwd "$PHP_APP_UID" >/dev/null; then
Michał 'rysiek' Woźniak's avatar
Michał 'rysiek' Woźniak committed
181 182 183 184 185 186 187 188 189 190 191 192 193 194
      echo "ERROR: a user with a given id ($PHP_APP_UID) already exists, can't create user $PHP_APP_USER with this id"
      exit 6
    fi
    # prepare the fragment of the useradd command
    UID_ARGS="-u $PHP_APP_UID"
  fi
  # we either have no UID given (and don't care about it), or have a UID given that does not exist in the system
  # great! let's add the user
  useradd $UID_ARGS -r -g "$PHP_APP_GROUP" "$PHP_APP_USER"
fi

# do we need particular packages installed?
if [ ! -z ${INSTALL_PACKAGES+x} ]; then
  # aye, install them
195 196 197 198
  echo
  echo "* * * WARNING: INSTALL_PACKAGES envvar support is deprecated and will soon be removed!"
  echo "* * * WARNING: use INSTALL_PACKAGES build arg instead!"
  echo
Michał 'rysiek' Woźniak's avatar
Michał 'rysiek' Woźniak committed
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
  DEBIAN_FRONTEND=noninteractive apt-get -q update && apt-get -q -y --no-install-recommends install $INSTALL_PACKAGES && apt-get -q clean && apt-get -q -y autoremove
fi

# log, run and data
mkdir -p /var/log/php-fpm
mkdir -p /var/run/php-fpm
mkdir -p $PHP_APP_DIR
chown $PHP_APP_USER:$PHP_APP_GROUP /var/log/php-fpm
chown $PHP_APP_USER:$PHP_APP_GROUP /var/run/php-fpm
chown $PHP_APP_USER:$PHP_APP_GROUP $PHP_APP_DIR

# PHP-FPM pool configuration.
# expects configuration in /etc/php5/fpm/pool.d/$PHP_APP_NAME.conf file
if [ -s /etc/php5/fpm/pool.d/$PHP_APP_NAME.conf ]; then
    echo "config file /etc/php5/fpm/pool.d/$PHP_APP_NAME.conf found, ignoring any PHP_* env vars!"
else
    # if that file does not exist or is empty, it creates it with config from envvars
    echo "config file /etc/php5/fpm/pool.d/$PHP_APP_NAME.conf not found, setting up from PHP_* env vars!"
    mv /etc/php5/fpm/pool.d/pool.conf /etc/php5/fpm/pool.d/$PHP_APP_NAME.conf
218
    echo "+-- pool name..."
Michał 'rysiek' Woźniak's avatar
Michał 'rysiek' Woźniak committed
219
    sed -i "s/pool_name/$PHP_APP_NAME/g" /etc/php5/fpm/pool.d/$PHP_APP_NAME.conf
220
    echo "+-- user..."
Michał 'rysiek' Woźniak's avatar
Michał 'rysiek' Woźniak committed
221
    sed -i "s/app_user/$PHP_APP_USER/g" /etc/php5/fpm/pool.d/$PHP_APP_NAME.conf
222
    echo "+-- group..."
Michał 'rysiek' Woźniak's avatar
Michał 'rysiek' Woźniak committed
223
    sed -i "s/app_group/$PHP_APP_GROUP/g" /etc/php5/fpm/pool.d/$PHP_APP_NAME.conf
224
    echo "+-- listen..."
225
    sed -i -r -e "s@^listen = .*@listen = $PHP_LISTEN@g" /etc/php5/fpm/pool.d/$PHP_APP_NAME.conf
226
    # access and slowlog locations
227
    echo "+-- access log..."
228
    sed -i -r -e "s@^access\.log = .*@access.log = \"$PHP_ACCESS_LOG\"@g" /etc/php5/fpm/pool.d/$PHP_APP_NAME.conf
229
    echo "+-- slowlog..."
230
    sed -i -r -e "s@^slowlog = .*@slowlog = \"$PHP_SLOW_LOG\"@g" /etc/php5/fpm/pool.d/$PHP_APP_NAME.conf
231 232
    echo "+-- slowlog timeout..."
    sed -i -r -e "s@^request_slowlog_timeout = .*@request_slowlog_timeout = \"$PHP_SLOW_LOG_TIMEOUT\"@g" /etc/php5/fpm/pool.d/$PHP_APP_NAME.conf
Michał 'rysiek' Woźniak's avatar
Michał 'rysiek' Woźniak committed
233 234
fi

235 236 237 238 239 240 241 242
# Change the default error location.
echo "+-- error log..."
sed -i "s@error_log = /var/log/php5-fpm.log@error_log = \"$PHP_ERROR_LOG\"@g" /etc/php5/fpm/php-fpm.conf

# Change the default pidfile location.
echo "+-- pidfile..."
sed -i "s@pid = .*@pid = $PHP_PID_FILE@g" /etc/php5/fpm/php-fpm.conf

243 244
# let's run the darn thing,
# if there is anything to run that is
Michał 'rysiek' Woźniak's avatar
Michał 'rysiek' Woźniak committed
245 246 247 248 249 250
if [ $# -ne 0 ]; then

    # watch the files
    watch_logfiles "$PHP_ACCESS_LOG" "$PHP_ERROR_LOG" "$PHP_SLOW_LOG" &
    sleep 1

251 252 253
    echo "+-- running command:"
    echo "    $@"
    exec "$@"
Michał 'rysiek' Woźniak's avatar
Michał 'rysiek' Woźniak committed
254 255 256
else
    echo "+-- no command specified."
fi