Search
j0ke.net Open Build Service
>
Projects
>
internetx
:
projects
:
http
>
stud
> init.stud
Sign Up
|
Log In
Username
Password
Cancel
Overview
Repositories
Revisions
Requests
Users
Advanced
Attributes
Meta
File init.stud of Package stud (Revision 2)
Currently displaying revision
2
,
show latest
#!/bin/sh ### BEGIN INIT INFO # Provides: stud # Required-Start: $local_fs $remote_fs # Required-Stop: $local_fs $remote_fs # Should-Start: $syslog # Should-Stop: $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start or stop stud (SSL offloader) ### END INIT INFO ####################################################### # GLOBALS # ####################################################### # instance configuration directory CONFIG_DIR="/etc/stud" # Runtime directory data RUNTIME_DIR="/var/run/stud" ####################################################### ####################################################### stud_single_instance_config_reset() { ####################################################### # stud instance configuration # ####################################################### # stud listening address FRONTEND_ADDRESS="*,8443" # upstream service address BACKEND_ADDRESS="127.0.0.1,80" # x509 certificate file CERT_FILE="" # TLS only service? Don't set this to 1 if you're # offloading HTTPS. TLS_ONLY="0" # cipher suite (run openssl ciphers for full list) CIPHER_SUITE="HIGH" # OpenSSL engine ENGINE="" # Number of worker processes WORKERS="1" # Listen backlog BACKLOG="" # Chroot directory CHROOT_DIR="" # drop privileges and run as specified # user if set SETUID_USER="" # use shared cache with specified number of sessions # WARNING: stud must be compiled with USE_SHARED_CACHE=1 SHARED_CACHE_SESSIONS="0" # Accept cache updates on specified address # # syntax: HOST,PORT # # WARNING: stud must be compiled with USE_SHARED_CACHE=1 # SHARED_CACHE_SESSIONS must be >= 1 CACHE_UPDATE_ACCEPT="" # Send cache updates to specified list space separated peers # # syntax: HOST1,PORT HOST2,PORT # # WARNING: stud must be compiled with USE_SHARED_CACHE=1 # and CACHE_UPDATE_ACCEPT must be defined CACHE_UPDATE_SEND="" # Force network interface and ttl to receive and send multicast # cache updates # # syntax: IFACE[,TTL] # # WARNING: stud must be compiled with USE_SHARED_CACHE=1 # and CACHE_UPDATE_ACCEPT must be defined CACHE_UPDATE_IFACE="" # default tcp keepalive on client socket in seconds CLIENT_TCP_KEEPALIVE_SEC="" # log to syslog? SYSLOG="1" # Enable write-ip? WRITE_IP="0" # Enable SENDPROXY protocol; see # http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt # for additional info WRITE_PROXY="0" # Alternative OpenSSL library dir # Use this if you'd like to run stud with different # version of OpenSSL library OPENSSL_LIB_DIR="" # Semicolon separated list of process affinities; requires # taskset(8) utility. # # SYNTAX: # "<process_number>:<affinity>;<process_number2>:<affinity2>;..." # # <process_number>: stud worker process number, starting with 1 # <affinity>: process affinity, see taskset(8) for details # # EXAMPLES: # # "1:0" => bind first process to CPU0 # # "1:0;2:3-4;3:5;4:7" => bind first worker process to CPU0, # second worker process to CPU3 and CPU4, # third worker process to CPU5 and fourth # worker process to CPU7 PROCESS_AFFINITY="" # Process priority (integer between -19 to 19) # lower value means higher priority # PROCESS_PRIORITY="" # ulimit -n value before starting single stud instance # # Comment out or set to 0 to disable ulimit -n # setup. # ULIMIT_N="" # Additional stud command line options # # NOTE: set this only if you really know what your're # doing # # ADDITIONAL_STUD_OPT="" # EOF } PATH="${PATH}:." INSTANCE_NAME="" STUD=`which stud 2>/dev/null` die() { msg_log "FATAL: $@" echo "FATAL: $@" 1>&2 exit 1 } msg_log() { ident="stud" test ! -z "${INSTANCE_NAME}" && ident="${ident}/${INSTANCE_NAME}" logger -i -t "${ident}" "$@" >/dev/null 2>&1 } msg_err() { msg_log "ERROR: $@" } _real_single_instance_start() { # check stud binary if [ -z "${STUD}" ] || [ ! -f "${STUD}" ] || [ ! -x "${STUD}" ]; then die "Invalid stud binary: '${STUD}'" fi # generate stud command line options opts="-f ${FRONTEND_ADDRESS}" opts="${opts} -b ${BACKEND_ADDRESS}" if [ "${TLS_ONLY}" = "1" ]; then opts="${opts} --tls" else opts="${opts} --ssl" fi test ! -z "${CIPHER_SUITE}" && opts="${opts} -c ${CIPHER_SUITE}" test ! -z "${ENGINE}" && opts="${opts} -e ${ENGINE}" if [ ! -z "${WORKERS}" ] && [ ${WORKERS} -gt 0 ]; then opts="${opts} -n ${WORKERS}" fi if [ ! -z "${BACKLOG}" ] && [ ${BACKLOG} -gt 0 ]; then opts="${opts} -B ${BACKLOG}" fi if [ ! -z "${CLIENT_TCP_KEEPALIVE_SEC}" ] && [ ${CLIENT_TCP_KEEPALIVE_SEC} -gt 0 ]; then opts="${opts} -k ${CLIENT_TCP_KEEPALIVE_SEC}" fi # shared cache sessions... if [ ! -z "${SHARED_CACHE_SESSIONS}" ] && [ ${SHARED_CACHE_SESSIONS} -gt 0 ]; then opts="${opts} -C ${SHARED_CACHE_SESSIONS}" # shared cache stuff if [ ! -z "${CACHE_UPDATE_ACCEPT}" ]; then opts="${opts} -U ${CACHE_UPDATE_ACCEPT}" c_u=0 for h in ${CACHE_UPDATE_SEND}; do test ! -z "${h}" || continue opts="${opts} -P ${h}" c_u=$((c_u + 1)) done if [ ${c_u} -lt 1 ]; then die "Cache updates are enabled but CACHE_UPDATE_SEND option seems to be empty." fi if [ ! -z "${CACHE_UPDATE_IFACE}" ]; then opts="${opts} -M ${CACHE_UPDATE_IFACE}" fi fi fi # chroot? test ! -z "${CHROOT_DIR}" && opts="${opts} -r ${CHROOT_DIR}" test ! -z "${SETUID_USER}" && opts="${opts} -u ${SETUID_USER}" opts="${opts} -q" test "${SYSLOG}" = "1" && opts="${opts} -s" test "${WRITE_IP}" = "1" && opts="${opts} --write-ip" test "${WRITE_PROXY}" = "1" && opts="${opts} --write-proxy" if [ ! -z "${CERT_FILE}" ] && [ -f "${CERT_FILE}" ] && [ -r "${CERT_FILE}" ]; then opts="${opts} ${CERT_FILE}" else die "Invalid or unreadable certificate file '${CERT_FILE}'." fi # additional command line options?! if [ ! -z "${ADDITIONAL_STUD_OPT}" ]; then opts="${opts} ${ADDITIONAL_STUD_OPT}" fi # priority?! prefix="" if [ ! -z "${PROCESS_PRIORITY}" ]; then prefix="nice -n ${PROCESS_PRIORITY}" fi # we want to start stud in a daemon mode... opts="${opts} --daemon" # set ulimits! ulimit_set || die "Unable to set stud runtime limits." # disable linker stuff unset LD_LIBRARY_PATH # set new lib path if requested if [ ! -z "${OPENSSL_LIB_DIR}" -a -d "${OPENSSL_LIB_DIR}" ]; then LD_LIBRARY_PATH="${OPENSSL_LIB_DIR}" export LD_LIBRARY_PATH fi # start stud! msg_log "Starting instance '${INSTANCE_NAME}': ${STUD} ${opts}" out=`${prefix} ${STUD} ${opts} 2>&1` # remove lib path unset LD_LIBRARY_PATH # check invocation stud_pid=`echo "${out}" | tail -n 1 | cut -d " " -f5 | tr -d '.'` if [ -z "${stud_pid}" ]; then die "Empty stud pid. This is extremely weird." fi # wait a little bit, check if pid is still alive sleep 0.2 >/dev/null 2>&1 if ! kill -0 "${stud_pid}" >/dev/null 2>&1; then die "Stud started successfully as pid ${stud_pid} but died shortly after startup."; fi # write pid file! pid_file_write "${INSTANCE_NAME}" "${stud_pid}" || msg_warn "${Error}" # set affinity! stud_affinity_set "${stud_pid}" || die "${Error}" } stud_single_instance_start() { name="${1}" if [ -z "${name}" ]; then Error="Unable to stop undefined stud instance." return 1 fi # check if it is running if stud_single_instance_status "${name}"; then Error="Instance ${name} is already running as pid ${Error}." return 1 fi # do the real stuff... Error="" out=`_real_single_instance_start 2>&1` rv=$? if [ "${rv}" != "0" ]; then Error="${out}" rv=1 fi # this is it! :) return $rv } stud_single_instance_stop() { name="${1}" if [ -z "${name}" ]; then Error="Unable to stop undefined stud instance." return 1 fi # check if it is running stud_single_instance_status "${name}" || return 1 # time to stop instance pid="${Error}" msg_log "Stopping stud instance '${name}', pid ${pid}." ok=0 if ! kill "${pid}" >/dev/null 2>&1; then Error="Unable to stop instance: unable to kill pid ${pid}." return 1 fi # wait for termination i=0 while [ ${i} -lt 9 ]; do i=$((i + 1)) # are you dead yet? if ! kill -0 "${pid}" >/dev/null 2>&1; then ok=1 break fi sleep 0.1 >/dev/null 2>&1 done # not ok?! try to with headshot... if [ "${ok}" != "1" ]; then msg_log "Gentle stop of instance ${name} failed, trying to stop it with SIGKILL." if ! kill -9 "${pid}"; then Error="Unable to stop instance ${name}: kill(1) failed." return 1 fi fi return 0 } stud_single_instance_restart() { name="${1}" if [ -z "${name}" ]; then Error="Unable to stop undefined stud instance." return 1 fi # maybe we need to stop it first... if stud_single_instance_status "${name}"; then stud_single_instance_stop "${name}" || return 1 fi # start it back... Error="" stud_single_instance_start "${name}" } stud_single_instance_status() { Error="" if [ -z "${1}" ]; then Error="Invalid instance name." return 1 fi # get pid file... pid=`pid_file_read "${1}"` # check it... if [ -z "${pid}" ] || ! kill -0 "${pid}" >/dev/null 2>&1; then Error="Instance '${1}' is stopped." return 1 fi # set pid to Error Error="${pid}" return 0 } # reads pid file of specific instance pid_file_read() { test -z "${1}" && return 1 file="${RUNTIME_DIR}/${1}.pid" test -f "${file}" -a -r "${file}" || return 1 head -n 1 "${file}" } # writes pid file for specific instance pid_file_write() { test -z "${1}" && return 1 test -z "${2}" && return 1 # check runtime directory if [ ! -e "${RUNTIME_DIR}" ] || [ ! -d "${RUNTIME_DIR}" ] || [ ! -w "${RUNTIME_DIR}" ]; then # try to create directory mkdir -p "${RUNTIME_DIR}" || die "Unable to create missing runtime directory '${RUNTIME_DIR}'" fi file="${RUNTIME_DIR}/${1}.pid" echo "${2}" > "${file}" } # lists running instances running_instance_list() { list="" for file in ${RUNTIME_DIR}/*.pid; do test -f "${file}" || continue fileb=`basename "${file}"` name=`echo "${fileb}" | cut -d. -f1` if [ -z "${name}" ]; then msg_log "Removing bogus pid file '${file}'." rm -f "${file}" >/dev/null 2>&1 continue fi pid=`pid_file_read "${name}"` if [ -z "${pid}" ]; then msg_log "Removing bogus pid file '${file}': instance '${name}' doesn't contain pid." rm -f "${file}" >/dev/null 2>&1 continue fi # is this pid alive? if ! kill -0 "${pid}" >/dev/null 2>&1 ; then msg_log "Removing bogus pid file '${file}': instance '${name}' [pid ${pid}] is stopped." rm -f "${file}" >/dev/null 2>&1 continue fi list="${list} ${name}" done echo ${list} } stud_instances_start() { list="$@" if [ -z "${list}" ]; then list=`stud_config_instances_list` fi if [ -z "${list}" ]; then die "No stud instances configured in directory '${CONFIG_DIR}'." fi echo "Starting stud instances:" num_ok=0 num_failed=0 for instance in ${list}; do echo -n " ${instance}: " # load configuration if ! stud_single_instance_config_load "${instance}"; then echo "failed: ${Error}" return 1 # start instance elif stud_single_instance_start "${instance}"; then echo "done." msg_log "Instance ${name} successfully started." num_ok=$((num_ok + 1)) else echo "failed: ${Error}" msg_err "Error starting instance ${name}: ${Error}" num_failed=$((num_failed + 1)) fi done if [ "${num_failed}" != "0" ]; then return 1 else return 0 fi } stud_instances_stop() { list="$@" if [ -z "${list}" ]; then list=`running_instance_list` fi if [ -z "${list}" ]; then die "No stud instances are running." fi echo "Stopping stud instances:" num_ok=0 num_failed=0 for instance in ${list}; do echo -n " ${instance}: " if stud_single_instance_stop "${instance}"; then echo "done." num_ok=$((num_ok + 1)) msg_log "Instance ${instance} successfully stopped." else echo "failed: ${Error}" msg_err "Error stopping instance ${instance}: ${Error}" num_failed=$((num_failed + 1)) fi done if [ "${num_failed}" != "0" ]; then return 1 else return 0 fi } stud_instances_restart() { list="$@" if [ -z "${list}" ]; then list=`(running_instance_list ; stud_config_instances_list) | tr ' ' '\n' | sort -u | xargs echo` fi echo "Restarting stud instances: " num_ok=0 num_failed=0 for instance in ${list}; do echo -n " ${instance}: "; # load configuration if ! stud_single_instance_config_load "${instance}"; then echo "failed: ${Error}" return 1 # restart instance elif stud_single_instance_restart "${instance}"; then echo "done." num_ok=$((num_ok + 1)) msg_log "Instance ${instance} successfully restarted." else echo "failed: ${Error}" msg_err "Error restarting instance ${instance}: ${Error}" num_failed=$((num_failed + 1)) fi done if [ "${num_failed}" != "0" ]; then return 1 else return 0 fi } stud_instances_status() { list_config=`stud_config_instances_list` list_running=`running_instance_list` list_all=`echo ${list_config} ${list_running} | tr ' ' '\n' | sort -u | xargs echo` i=0; echo "Stud instance status: " if [ -z "${list_all}" ]; then die "No instances are configured and/or running." fi for instance in ${list_all}; do echo -n " ${instance}: " if stud_single_instance_status "${instance}"; then echo "running as pid $Error" i=$((i + 1)) else echo "stopped" fi done if [ ${i} -gt 0 ]; then return 0 else return 1 fi } stud_config_instances_list() { list="" for file in ${CONFIG_DIR}/*.conf; do test -f "${file}" -a -r "${file}" || continue fileb=`basename "${file}"` name=`echo "${fileb}" | cut -d. -f1` test ! -z "${name}" || continue list="${list} ${name}" done echo ${list} } stud_single_instance_config_print() { head -n 151 "$0" | tail -n 123 } stud_single_instance_config_load() { file="${CONFIG_DIR}/${1}.conf" INSTANCE_NAME="" # reset configuration stud_single_instance_config_reset Error='' if [ -f "${file}" -a -r "${file}" ]; then . "${file}" >/dev/null || Error="Unable to load instance configuration file '${file}'." else Error="Invalid or unreadable instance configuration file '${file}'." return 1 fi # set instance name... INSTANCE_NAME="${1}" return 0 } stud_instance_worker_pids() { test -z "${1}" && return 1 ps -ef | grep " ${1} " | grep -v ' 1 ' | grep -v ' grep ' | awk '{print $2}' | xargs echo } # prints worker pid for n-th worker # arguments: # $1: list of worker pids (string) # $2: worker number stud_instance_worker_pid_by_num() { i=0 local IFS=" " for e in ${1}; do i=$((i + 1)) if [ "${i}" = "${2}" ]; then echo "$e" return 0 fi done return 1 } stud_affinity_set() { # nothing to set? test -z "$PROCESS_AFFINITY" && return 0 Error="" # "1:0;2:3-4;3:5;4:7" => bind first haproxy process to CPU0, # second haproxy process to CPU3 and CPU4, # third haproxy process to CPU5 and fourth # process to CPU7 worker_pids=`stud_instance_worker_pids "${1}"` local IFS=";" item="" for item in $PROCESS_AFFINITY; do num=`echo "${item}" | cut -f1 -d:` affinity=`echo "${item}" | cut -f2 -d:` # validate process number test -z "$num" && continue test ${num} -ge 1 2>&1 || continue # validate affinity test -z "${affinity}" && continue # WORKS: OpenSUSE # DOESNT WORK: Debian/Ubuntu!!! #echo "${affinity}" | grep -qPi '[^a-f0-9\-\,x]' && continue # is this raw affinity mask? raw_affinity=0 echo "${affinity}" | grep -qE '^0x' && raw_affinity=1 # get pid for process id $num pid=`stud_instance_worker_pid_by_num "${worker_pids}" "$num"` test -z "$pid" && continue #echo "item: $item; process num: $num; pid: $pid; affinity: $affinity; raw: $raw_affinity" opt="-p" test "${raw_affinity}" = "0" && opt="${opt} -c" opt="${opt} ${affinity}" opt="${opt} ${pid}" # echo "WILL RUN: 'taskset $opt'" msg_log "Setting stud worker number ${num} (pid ${pid}) affinity using command: taskset ${opt}" eval taskset ${opt} >/dev/null 2>&1 || msg_log "Error setting process affinity." done } ulimit_n_set() { if [ -z "$ULIMIT_N" ] || [ "$ULIMIT_N" = "0" ]; then return 0 fi # try to set maximum possible limit... i="$ULIMIT_N" num=0 while [ $i -gt 0 ]; do num=$((num + 1)) if ulimit -n "$i" > /dev/null 2>&1; then percentage=$((i*100 / ${ULIMIT_N})) if [ $percentage -lt 75 ]; then Error="Filedescriptor limit set to only $i (${percentage}% of desired value of $ULIMIT_N); check your system settings." return 1 fi msg_log "Filedescriptor limit successfully set to $i (${percentage}% of desired value of $ULIMIT_N) after ${num} iteration(s)." return 0 break else i=$((i - 100)) fi done Error="Filedescriptor limit of $ULIMIT_N could not be set." msg_log "$Error" return 1 } ulimit_set() { # set fd limit ulimit_n_set || return 1 # set core file limit ulimit -c unlimited >/dev/null 2>&1 return 0 } printhelp() { cat <<EOF Usage: ${MYNAME} {start|stop|restart|status|sample_instance_config} [name, name2, ...] This is stud SSL offloader multi-instance init script. OPTIONS: -C --config-dir Instance configuration directory (Default: "${CONFIG_DIR}") This directory is searched for files matching *.conf glob pattern; each file represents single stud instance configuration file. -R --runtime-dir Runtime (pid file) directory (Default: "${RUNTIME_DIR}") --sample-config Prints out default single instance configuration -V --version Prints script version -h --help This help message EOF } # parse command line... TEMP=`getopt -o C:R:Vh --long config-dir:,runtime-dir:,sample-config,version,help -n "$MYNAME" -- "$@"` test "$?" != "0" && die "Invalid command line arguments. Run $MYNAME --help for instructions." eval set -- "$TEMP" while true; do case $1 in -C|--config-dir) CONFIG_DIR="${2}" shift 2 ;; -R|--runtime-dir) RUNTIME_DIR="${2}" shift 2 ;; --sample-config) stud_single_instance_config_print exit 0 ;; -V|--version) echo "$MYNAME $VERSION" exit 0 ;; -h|--help) printhelp exit 0 ;; --) shift break ;; *) die "Invalid command line arguments. Run $MYNAME --help for instructions." ;; esac done # weed out real action and do something case $1 in start) shift stud_instances_start "$@" ;; stop) shift stud_instances_stop "$@" ;; force-reload|restart) shift stud_instances_restart "$@" ;; status) stud_instances_status exit $? ;; sample_instance_config|instance_config) stud_single_instance_config_print exit 0 ;; *) printhelp exit 1 ;; esac # EOF