#!/bin/bash ### BEGIN INIT INFO # Provides: @DAEMON@ # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Required-Start: # Required-Stop: # Short-Description: Yandex daemon ### END INIT INFO USER=metrika GROUP=metrika SHELL=/bin/bash PROGRAM=@DAEMON@ SYSCONFDIR=/etc/$PROGRAM LOGDIR=/var/log/$PROGRAM LOCALSTATEDIR=/var/lock BINDIR=/usr/bin CRONFILE=/etc/cron.d/@CRONFILE@ CNFFILE=$SYSCONFDIR/config.xml LOCKFILE=$LOCALSTATEDIR/$PROGRAM RETVAL=0 DEFAULT_NUMBER_OF_PROCESSES=1 NUMBER_OF_PROCESSES=$DEFAULT_NUMBER_OF_PROCESSES LOG_FILE="" # On x86_64, check for required instruction set. if uname -mpi | grep -q 'x86_64'; then if ! grep -q 'sse4_2' /proc/cpuinfo; then # On KVM, cpuinfo could falsely not report SSE 4.2 support, so skip the check. if ! grep -q 'Common KVM processor' /proc/cpuinfo; then # Some other VMs also report wrong flags in cpuinfo. # Tricky way to test for instruction set: # create temporary binary and run it; # if it get caught illegal instruction signal, # then required instruction set is not supported really. # # Generated this way: # gcc -xc -Os -static -nostdlib - <<< 'void _start() { __asm__("pcmpgtq %%xmm0, %%xmm1; mov $0x3c, %%rax; xor %%rdi, %%rdi; syscall":::"memory"); }' && strip -R .note.gnu.build-id -R .comment -R .eh_frame -s ./a.out && gzip -c -9 ./a.out | base64 -w0; echo if ! (echo -n 'H4sICAwAW1cCA2Eub3V0AKt39XFjYmRkgAEmBjsGEI+H0QHMd4CKGyCUAMUsGJiBJDNQNUiYlQEZOKDQclB9cnD9CmCSBYqJBRxQOvBpSQobGfqIAWn8FuYnPI4fsAGyPQz/87MeZtArziguKSpJTGLQK0mtKGGgGHADMSgoYH6AhTMPNHyE0NQzYuEzYzEXFr6CBPQDANAsXKTwAQAA' | base64 -d | gzip -d > /tmp/clickhouse_test_sse42 && chmod a+x /tmp/clickhouse_test_sse42 && /tmp/clickhouse_test_sse42); then echo 'SSE 4.2 instruction set is not supported' exit 3 fi fi fi fi # С помощью xmlstarlet пытаемся взять некоторые параметры из конфига if command -v xmlstarlet >/dev/null 2>&1; then NUMBER_OF_PROCESSES=$(xmlstarlet sel -t -v "/yandex/number_of_processes" $CNFFILE || echo $DEFAULT_NUMBER_OF_PROCESSES) LOG_FILE=$(xmlstarlet sel -t -v "/yandex/logger/log" $CNFFILE || echo $LOG_FILE) fi PIDDIR=/var/run/$PROGRAM PIDFILE_PREFIX=$PIDDIR/$PROGRAM PIDFILE_RE="$PIDFILE_PREFIX[0-9]*.pid" SUPPORTED_COMMANDS="{start|stop|status|restart|forcestop|forcerestart|reload|condstart|condstop|condrestart|condreload}" is_supported_command() { echo $SUPPORTED_COMMANDS | grep -E "(\{|\|)$1(\||})" &> /dev/null } generate_program_name() { if [ $NUMBER_OF_PROCESSES -eq 1 ]; then echo $PROGRAM else echo $PROGRAM$1 fi } generate_pid_name() { if [ $NUMBER_OF_PROCESSES -gt 1 ]; then echo $PIDFILE_PREFIX$1.pid else echo $PIDFILE_PREFIX.pid fi } specific_log_file_for_each_process() { # Не будем менять имя лог файла, при одном процессе # Не выставляем, если имя лог файла пустое if [ $NUMBER_OF_PROCESSES -gt 1 ] && [ "$LOG_FILE" != "" ]; then log_file=$(echo $LOG_FILE | sed "s/\.log/$1.log/") echo "--log-file=\"$log_file\"" fi echo "" } find_pid_files() { [[ -e $PIDDIR ]] && find $PIDDIR -regex "$PIDFILE_RE" } is_running() { pidfile=$1 [ -r "$pidfile" ] && pgrep -s $(cat "$pidfile") 1> /dev/null 2> /dev/null } running_processes() { pidfiles=$(find_pid_files) running=0 for pidfile in $pidfiles; do if is_running $pidfile; then running=$(($running + 1)) fi done echo $running } any_runs() { if [[ $(running_processes) -gt 0 ]]; then return 0; else return 1; fi } all_runs() { [[ $(running_processes) -eq $NUMBER_OF_PROCESSES ]] } wait4done() { while any_runs; do sleep 1 done } start() { [ -x $BINDIR/$PROGRAM ] || exit 0 local EXIT_STATUS EXIT_STATUS=0 echo -n "Start $PROGRAM service: " ulimit -n 262144 if all_runs; then echo -n "already running " EXIT_STATUS=1 else mkdir -p $LOGDIR mkdir -p $PIDDIR chown -R $USER:$GROUP $LOGDIR chown -R $USER:$GROUP $PIDDIR chown -R $USER:$GROUP $SYSCONFDIR for i in $(seq 1 $NUMBER_OF_PROCESSES); do if ! is_running $(generate_pid_name $i); then rm -f $(generate_pid_name $i) # чтобы лок не удерживался в течении времени жизни дочернего процесса, освободим лок su -l $USER -s $SHELL -c "flock -u 9; exec -a $(generate_program_name $i) \"$BINDIR/$PROGRAM\" --daemon --pid-file=\"$(generate_pid_name $i)\" --config-file=\"$CNFFILE\" $(specific_log_file_for_each_process $i)" EXIT_STATUS=$? if [[ $EXIT_STATUS -ne 0 ]]; then break fi fi done fi if [[ $EXIT_STATUS -eq 0 ]]; then echo "DONE" else echo "FAILED" fi return $EXIT_STATUS } stop() { local EXIT_STATUS EXIT_STATUS=0 echo -n "Stop $PROGRAM service: " for pid_file in $(find_pid_files); do kill -TERM `cat "$pid_file"` done wait4done echo "DONE" return $EXIT_STATUS } restart() { stop start } forcestop() { local EXIT_STATUS EXIT_STATUS=0 echo -n "Stop $PROGRAM service: " for pid_file in $(find_pid_files); do kill -9 `cat "$pid_file"` done wait4done echo "DONE" return $EXIT_STATUS } forcerestart() { forcestop start } enable_cron() { sed -i 's/^#*//' "$CRONFILE" } disable_cron() { sed -i 's/^#*/#/' "$CRONFILE" } is_cron_disabled() { [[ `grep -E "^#.*" $CRONFILE` == `cat $CRONFILE` ]]; } main() { # See how we were called. EXIT_STATUS=0 case "$1" in start) start && enable_cron ;; stop) disable_cron && stop ;; restart) restart && enable_cron ;; forcestop) disable_cron && forcestop ;; forcerestart) forcerestart && enable_cron ;; reload) restart ;; condstart) all_runs || start ;; condstop) any_runs && stop ;; condrestart) any_runs && restart ;; condreload) any_runs && restart ;; esac exit $EXIT_STATUS } status() { if [[ $(running_processes) -eq $NUMBER_OF_PROCESSES ]]; then echo "$PROGRAM service is running" else if is_cron_disabled; then echo "$PROGRAM service is stopped"; else echo "$PROGRAM: $(($NUMBER_OF_PROCESSES - $(running_processes))) of $NUMBER_OF_PROCESSES processes unexpectedly terminated" fi fi } # выполняем команды, не нуждающиеся в блокировке if ! is_supported_command "$1"; then echo "Usage: ${0##*/} $SUPPORTED_COMMANDS" exit 2 fi if [[ "$1" == "status" ]]; then status exit 0 fi ( if flock -n 9; then main "$@" else echo "Init script is already running" && exit 1 fi ) 9> $LOCKFILE