Signed-off-by: fbt <fbt@fleshless.org>
This commit is contained in:
Jack L. Frost 2016-11-13 14:47:20 +03:00
parent 2b72e15884
commit e7c316c664
1 changed files with 140 additions and 31 deletions

171
sm
View File

@ -25,7 +25,7 @@ svc() {
kill -n "$service_stop_signal" "$service_pid" kill -n "$service_stop_signal" "$service_pid"
pid_wait "$service_pid" && { pid_wait "$service_pid" && {
rm -f $svc_pidfile rm -f $svc_pidfile $service_ready_flag
} }
}; trap 'svc::cleanup' TERM INT }; trap 'svc::cleanup' TERM INT
@ -33,27 +33,31 @@ svc() {
kill -n "$service_reload_signal" "$service_pid" kill -n "$service_reload_signal" "$service_pid"
}; trap 'svc::reload' HUP }; trap 'svc::reload' HUP
exec "$@" & "$@" &
service_pid=$! service_pid=$!
wait
}
## Respawn implementation while nullexec kill -n 0 "$service_pid"; do
respawn() {
declare jpid
respawn::cleanup() {
kill -n 15 0
wait
exit 0
}; trap 'svc::reload' TERM
while true; do
"$@" & jpid=$!
wait wait
done done
} }
#cat >/dev/null << EOF
## Respawn
respawn() {
respawn::cleanup() {
kill -n 15 $(jobs -p)
wait
exit 0
}; trap 'respawn::cleanup' TERM
while true; do
exec "$@" &
job_pid=$!
wait
done
}
#EOF
## Run a command with its output discarded ## Run a command with its output discarded
nullexec() { nullexec() {
"$@" &>/dev/null "$@" &>/dev/null
@ -64,10 +68,8 @@ pid_wait() {
declare cnt=0 declare cnt=0
while nullexec kill -0 "$1"; do while nullexec kill -0 "$1"; do
(( cnt >= service_stop_timeout )) && return 1 (( cnt >= (service_stop_timeout*10) )) && return 1
sleep 0.1
sleep 1
(( cnt++ )) (( cnt++ ))
done done
@ -87,9 +89,54 @@ is_function() {
return 1 return 1
} }
# DSL ## Simple timer
depends() { timer() {
service_depends=( "$@" ) declare cnt timeout=$1
shift
while ! "$@"; do
(( cnt >= (timeout*10) )) && return 1
sleep 0.1
(( cnt++ ))
done
return 0
}
## Is a service ready?
is_ready() [[ -f "$service_ready_flag" ]]
## Wait for this service to get ready
wait_ready() {
timer "$service_ready_timeout" is_ready
}
## Depend on other services to be started
depend() {
declare s
for s in "$@"; do
if ! "$0" "$s" qstatus; then
nullexec "$0" "$s" start || {
failed_deps+=( "$s" )
return 1
}
fi
done
}
## Depend on other services to be ready
depend_ready() {
declare s
depend "$@" || return 1
for s in "$@"; do
"$0" "$s" wait_ready || {
failed_deps+=( "$s" )
return 1
}
done
} }
# Super functions # Super functions
@ -97,6 +144,11 @@ depends() {
super_start() { super_start() {
(( service_running )) && return 3 (( service_running )) && return 3
[[ -f "${service_command[0]}" ]] || return 9
depend "${service_depends[@]}" || return 7
depend_ready "${service_depends_ready[@]}" || return 7
if (( service_managed )); then if (( service_managed )); then
if (( service_respawn )); then if (( service_respawn )); then
svc respawn "${service_command[@]}" &>"$service_logfile" & svc respawn "${service_command[@]}" &>"$service_logfile" &
@ -111,9 +163,20 @@ super_start() {
"${service_command[@]}" & "${service_command[@]}" &
fi fi
if timer "$service_ready_timeout" ready; then
printf '1' > "$service_ready_flag"
else
return 5
fi
return 0 return 0
} }
# A separate function for oneshot services
super_oneshot() {
(( service_enabled )) && return 3
}
## Reload the service ## Reload the service
## Usually just sends HUP ## Usually just sends HUP
super_reload() { super_reload() {
@ -137,11 +200,26 @@ super_stop() {
# Overloadable functions # Overloadable functions
start() { super_start; } start() { super_start; }
stop() { super_stop; } stop() { super_stop; }
reload() { super_reload; }
restart() { restart() {
"$0" "$service_name" stop "$0" "$service_name" stop
"$0" "$service_name" start "$0" "$service_name" start
} }
logs() { cat "$service_logfile"; }
## Status is a bit of a special case. It's talkative.
status() {
(( service_running )) && return 0
return 1
}
## For use in scripts
qstatus() { nullexec status; }
## By default there is no ready check
ready() { :; }
# Code # Code
main() { main() {
# Let's set some defaults # Let's set some defaults
@ -199,8 +277,10 @@ main() {
default service_pidfile "$svc_pidfile" default service_pidfile "$svc_pidfile"
default service_logfile "$logdir/$service_name.log" default service_logfile "$logdir/$service_name.log"
default service_stop_timeout 30 default service_stop_timeout 30
default service_ready_timeout 15
default service_stop_signal 15 default service_stop_signal 15
default service_reload_signal 1 default service_reload_signal 1
default service_ready_flag "$rundir/$service_name.ready"
# Let's see if there's a PID # Let's see if there's a PID
if [[ -f "$service_pidfile" ]]; then if [[ -f "$service_pidfile" ]]; then
@ -212,14 +292,14 @@ main() {
fi fi
fi fi
# Check if action is even defined # Check if action is even defined
is_function "$2" || die 17 "Function $2 is not defined for $service_name." is_function "$2" || die 17 "Function $2 is not defined for $service_name."
# Run pre_$action function # Run pre_$action function
if is_function "pre_$2"; then if is_function "pre_$2"; then
"pre_$2" || { "pre_$2" || {
printf 'pre_%s failed!\n' "$2" || die 13 printf 'pre_%s failed!\n' "$2"
die 13
} }
fi fi
@ -228,9 +308,9 @@ main() {
stop) stop)
printf 'Stopping %s... ' "$service_name" printf 'Stopping %s... ' "$service_name"
stop stop; res=$?
case "$?" in case "$res" in
0) printf 'ok.\n';; 0) printf 'ok.\n';;
3) printf 'not running.\n' "$service_name";; 3) printf 'not running.\n' "$service_name";;
5) printf 'timed out.\n';; 5) printf 'timed out.\n';;
@ -241,22 +321,51 @@ main() {
start) start)
printf 'Starting %s... ' "$service_name" printf 'Starting %s... ' "$service_name"
start start; res=$?
case "$?" in case "$res" in
0) printf 'ok.\n';; 0) printf 'ok.\n';;
3) printf 'already running.\n';; 3) printf 'already running.\n';;
5) printf 'readyness check timed out.\n';;
7) printf 'dependencies failed: %s.\n' "${failed_deps[@]}";;
9) printf 'service_command does not exist: %s.\n' "${service_command[0]}";;
*) printf 'fail.\n';; *) printf 'fail.\n';;
esac esac
;; ;;
*) "$2";; reload)
printf 'Reloading %s... ' "$service_name"
reload; res=$?
case "$res" in
0) printf 'ok.\n';;
*) printf 'fail.\n';;
esac
;;
status)
status; res=$?
case "$res" in
0) printf '%s is running/enabled.\n' "$service_name";;
1) printf '%s is not running/enabled.\n' "$service_name";;
*) printf '%s: status unknown.\n' "$service_name";;
esac
;;
logs) logs;;
*) "$2"; res=$?;;
esac esac
(( res )) && return "$res"
# Run post_$action function # Run post_$action function
if is_function "post_$2"; then if is_function "post_$2"; then
"post_$2" || { "post_$2" || {
printf 'post_%s failed!\n' "$2" || die 15 printf 'post_%s failed!\n' "$2"
die 15
} }
fi fi
} }