examples, oneshot services rework
Signed-off-by: fbt <fbt@fleshless.org>
This commit is contained in:
parent
5506a922c6
commit
e227235f46
|
@ -8,6 +8,9 @@ Services
|
|||
A service is a script in the ssm's init.d directory.
|
||||
By default it's /etc/ssm/services for system services and $XDG_CONFIG_HOME/ssm/services for user ones.
|
||||
|
||||
Note that they are BASH scripts that get sourced by `ssm`. Same pitfalls apply.
|
||||
Hopefully, you won't have to do complex logic in the services.
|
||||
|
||||
## Global settings
|
||||
|
||||
* `cgroups = 0` — Enable cgroup-related features.
|
||||
|
@ -41,4 +44,4 @@ Optional settings (incomplete list):
|
|||
* `service_oneshot = no` — The service is supposed to do something and die instead of daemonizing.
|
||||
* `service_signals_passthru` — Array, empty by default. Which signals should the svc pass directly to the service mainpid. This is dangerous, use with caution.
|
||||
|
||||
Quote your expansions btw. This is still BASH.
|
||||
Mind your expansions.
|
||||
|
|
11
examples/services/iptables
Executable file
11
examples/services/iptables
Executable file
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env ssm
|
||||
|
||||
service_oneshot = true
|
||||
service_command = /usr/bin/false
|
||||
|
||||
service::pre_start() {
|
||||
cat <<- EOF
|
||||
Please don't. Use ferm or any other wrapper.
|
||||
You will just reinvent one in here anyway.
|
||||
EOF
|
||||
}
|
8
examples/services/nginx
Executable file
8
examples/services/nginx
Executable file
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env ssm
|
||||
|
||||
service_respawn = on-failure
|
||||
service_command = /usr/bin/nginx
|
||||
service_pidfile = /run/nginx.pid
|
||||
|
||||
# Do not reload the service if the config test fails.
|
||||
pre_reload() { "$service_command" -t "$@"; }
|
9
examples/services/rc.local
Executable file
9
examples/services/rc.local
Executable file
|
@ -0,0 +1,9 @@
|
|||
#!/usr/bin/env ssm
|
||||
|
||||
service_type = oneshot
|
||||
service_command = /etc/rc.local
|
||||
|
||||
pre_start() {
|
||||
# Do nothing, successfully, if /etc/rc.local is not executable.
|
||||
[[ -x "/etc/rc.local" ]] || die 0
|
||||
}
|
10
examples/services/sshd
Executable file
10
examples/services/sshd
Executable file
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env ssm
|
||||
|
||||
service_respawn = always
|
||||
service_command = /usr/bin/sshd -D -f "/etc/ssh/sshd_config"
|
||||
|
||||
pre_start() {
|
||||
if ! [[ -e "/etc/ssh/ssh_host_key" ]]; then
|
||||
ssh-keygen -A
|
||||
fi
|
||||
}
|
7
examples/services/tinc
Executable file
7
examples/services/tinc
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env ssm
|
||||
|
||||
# This trick was neat back in 2011, I swear
|
||||
var tinc_network = "${service_name##*-}"
|
||||
|
||||
service_respawn = on-failure
|
||||
service_command = /usr/bin/tincd -D -n "$tinc_network"
|
11
examples/ssm.conf
Normal file
11
examples/ssm.conf
Normal file
|
@ -0,0 +1,11 @@
|
|||
# This is actually a bash script
|
||||
# Everything in ssm is a bash script.
|
||||
|
||||
# Enable cgroup-related functions.
|
||||
# This requires quite specific setup that is undocumented as of yet, sorry.
|
||||
#cgroups = 0
|
||||
|
||||
# You can also set service-level options here, as local defaults.
|
||||
# I really do not advise doing that, but you *can*.
|
||||
# For example:
|
||||
#service_workdir = /
|
80
ssm
80
ssm
|
@ -189,7 +189,7 @@ svc() {
|
|||
|
||||
rm -f "$svc_pidfile" "$service_pidfile" "$service_ready_flag"
|
||||
|
||||
die 0
|
||||
die "$job_exit"
|
||||
}; trap 'svc::cleanup' TERM
|
||||
|
||||
svc::reload() {
|
||||
|
@ -229,11 +229,7 @@ svc() {
|
|||
|
||||
# Wait for the process to exit and record the exit code
|
||||
# This depends on a few things
|
||||
if service_managed; then
|
||||
printf '%s' "$job_pid" > "$service_pidfile"
|
||||
|
||||
wait "$job_pid"; job_exit=$?
|
||||
else
|
||||
if service_own_pidfile; then
|
||||
# We need to wait for the service to write down its pidfile
|
||||
until service_pidfile is file; do
|
||||
(( counter >= service_pidfile_timeout*10 )) && {
|
||||
|
@ -246,10 +242,16 @@ svc() {
|
|||
|
||||
read -r job_pid < "$service_pidfile"
|
||||
|
||||
# We consider any termination of an unmanaged service to be a failure
|
||||
# We consider any termination of a service with its own pidfile
|
||||
# to be a failure
|
||||
anywait "$job_pid"; job_exit=127
|
||||
else
|
||||
printf '%s' "$job_pid" > "$service_pidfile"
|
||||
|
||||
wait "$job_pid"; job_exit=$?
|
||||
fi
|
||||
|
||||
# One service failure, two service failures...
|
||||
if service_success_exit u "$job_exit"; then
|
||||
job_success = 1
|
||||
(( fail_counter )) && fail_counter--
|
||||
|
@ -258,16 +260,17 @@ svc() {
|
|||
fail_counter++
|
||||
fi
|
||||
|
||||
# Record the exit code
|
||||
printf '%s' "$job_exit" > "$service_exit_file"
|
||||
|
||||
# Back off if the service exits too much AND too quickly.
|
||||
service_respawn_force || {
|
||||
if ! service_respawn_force; then
|
||||
if (( fail_counter >= 3 )); then
|
||||
printf -v date '%(%s)T'
|
||||
|
||||
(( (date - last_respawn) <= 5 )) && break
|
||||
fi
|
||||
}
|
||||
fi
|
||||
|
||||
# Respawn, if necessary
|
||||
service_respawn_flag || break
|
||||
|
@ -419,26 +422,26 @@ start() {
|
|||
depend "${service_depends[@]}" || return 7
|
||||
depend_ready "${service_depends_ready[@]}" || return 7
|
||||
|
||||
mktmpfiles || return 13
|
||||
|
||||
rm -f "$service_stopped_flag"
|
||||
|
||||
mktmpfiles || return 13
|
||||
|
||||
svc "${service_command[@]}" & job=$!
|
||||
|
||||
if service_oneshot; then
|
||||
spawn "${service_command[@]}"; res=$?
|
||||
wait "$job"; res=$?
|
||||
|
||||
(( res )) && {
|
||||
printf '%s' "$res" > "$service_exit_file"
|
||||
return "$res"
|
||||
return 17
|
||||
}
|
||||
printf '1' > "$service_enabled_flag"
|
||||
else
|
||||
svc "${service_command[@]}" &
|
||||
fi
|
||||
|
||||
if timer "$service_ready_timeout" run_service_action 'ready'; then
|
||||
set_ready
|
||||
else
|
||||
return 5
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
@ -457,10 +460,7 @@ reload() {
|
|||
stop() {
|
||||
if service_oneshot; then
|
||||
service_enabled || return 3
|
||||
|
||||
rm -f "$service_enabled_flag"
|
||||
|
||||
return 0
|
||||
return 7
|
||||
else
|
||||
service_running || return 3
|
||||
|
||||
|
@ -499,12 +499,12 @@ info() {
|
|||
var _type = 'daemon'
|
||||
var _info_items
|
||||
|
||||
service_oneshot && {
|
||||
if service_oneshot; then
|
||||
_status_label = 'Enabled'
|
||||
_type = 'oneshot'
|
||||
}
|
||||
|
||||
status && _status = 'yes'
|
||||
service_enabled && _status = 'yes'
|
||||
else
|
||||
service_running && _status = 'yes'
|
||||
fi
|
||||
|
||||
_info_items = \
|
||||
"Name" "$service_name" \
|
||||
|
@ -584,7 +584,6 @@ var service_pid \
|
|||
service_logfile_out \
|
||||
service_logfile_err \
|
||||
service_ready_flag \
|
||||
service_enabled_flag \
|
||||
service_stopped_flag \
|
||||
service_exit_file \
|
||||
service_exit_last \
|
||||
|
@ -638,7 +637,7 @@ var cgroups = 0 # Enable cgroup-related functions
|
|||
var usrdir = '/usr/share/ssm'
|
||||
|
||||
# These are not
|
||||
var service_managed = 1
|
||||
var service_own_pidfile = 0
|
||||
var service_oneshot = 0
|
||||
var service_running = 0
|
||||
var service_enabled = 0
|
||||
|
@ -769,7 +768,6 @@ readonly service_name
|
|||
|
||||
# These depend on the service_name and make little sense to reconfigure.
|
||||
service_ready_flag := "$rundir/$service_name.ready"
|
||||
service_enabled_flag := "$rundir/$service_name.enabled"
|
||||
service_stopped_flag := "$rundir/$service_name.stopped"
|
||||
service_exit_file := "$rundir/$service_name.exit"
|
||||
service_cgroup_name := "$service_name"
|
||||
|
@ -801,8 +799,12 @@ if ! service_respawn == 'no'; then
|
|||
esac
|
||||
fi
|
||||
|
||||
# Unset the managed flag on services with their own pidfile
|
||||
service_pidfile && service_managed = 0
|
||||
if service_respawn_flag && service_oneshot; then
|
||||
die 89 'Cowardly refusing to respawn a oneshot service'
|
||||
fi
|
||||
|
||||
# Catch services with their own pidfile, set the appropriate flag.
|
||||
service_pidfile && service_own_pidfile = 1
|
||||
|
||||
# Semi-hardcoded stuff
|
||||
svc_pidfile = "$rundir/$service_name.svc_pid"
|
||||
|
@ -851,12 +853,6 @@ if svc_pidfile is file; then
|
|||
fi
|
||||
fi
|
||||
|
||||
# Maybe the service is enabled?
|
||||
if service_enabled_flag is file; then
|
||||
# Yay, it is!
|
||||
service_enabled = 1
|
||||
fi
|
||||
|
||||
# Let's see if the service was deliberately stopped
|
||||
if service_stopped_flag is file; then
|
||||
# Ooh, it was.
|
||||
|
@ -867,7 +863,9 @@ fi
|
|||
if service_exit_file is file; then
|
||||
read -r service_exit_last < "$service_exit_file"
|
||||
|
||||
if ! service_success_exit u "$service_exit_last"; then
|
||||
if service_success_exit u "$service_exit_last"; then
|
||||
service_oneshot && service_enabled = 1
|
||||
else
|
||||
# :(
|
||||
service_failed = 1
|
||||
fi
|
||||
|
@ -904,7 +902,8 @@ case "$2" in
|
|||
result "$res" \
|
||||
0 "Stopped $service_name" \
|
||||
3 "$service_name is not running" \
|
||||
5 "Operation timed out"
|
||||
5 "Operation timed out" \
|
||||
7 "Can't “stop” a oneshot service. Use reset-exit if you want to “start” the service again"
|
||||
;;
|
||||
|
||||
start)
|
||||
|
@ -915,7 +914,8 @@ case "$2" in
|
|||
7 "Failed to start dependencies for $service_name: ${failed_deps[@]}" \
|
||||
9 "service_command does not exist: ${service_command[0]}" \
|
||||
13 "Failed to create temporary files for $service_name" \
|
||||
15 "Refusing to start $service_name: the service cgroup is not empty and \$service_cgroup_exclusive is set"
|
||||
15 "Refusing to start $service_name: the service cgroup is not empty and \$service_cgroup_exclusive is set" \
|
||||
17 "$service_name failed"
|
||||
;;
|
||||
|
||||
reload)
|
||||
|
|
49
ssm.conf
49
ssm.conf
|
@ -1,49 +0,0 @@
|
|||
# This is actually a bash script
|
||||
|
||||
# Enable cgroup-related functions
|
||||
#cgroups = 0
|
||||
|
||||
# Where to search for services, works as a PATH-like array.
|
||||
#service_path = "$XDG_CONFIG_HOME/ssm/services" /etc/ssm/services "$rundir/services" /usr/share/ssm/services
|
||||
|
||||
# Service defaults
|
||||
|
||||
## Respawn the service if it exits
|
||||
#service_respawn = 0
|
||||
|
||||
## Working directory
|
||||
#service_workdir = '/'
|
||||
|
||||
## How long do we wait for the service to stop
|
||||
#service_stop_timeout = 30
|
||||
|
||||
## How long do we wait for the service to get ready
|
||||
#service_ready_timeout = 15
|
||||
|
||||
## Signals to pass through to the service under the respawner
|
||||
#service_signals = 1 10 12
|
||||
|
||||
## The signal to send to reload the service
|
||||
#service_reload_signal = 1
|
||||
|
||||
## The signal to send to stop the service
|
||||
#service_stop_signal = 15
|
||||
|
||||
## These only work with cgroups = 1:
|
||||
|
||||
## Check if the recorded PID of the service is in the correct cgroup.
|
||||
#service_cgroup_strict = 1
|
||||
|
||||
## Refuse to start the service if its cgroup is not empty
|
||||
#service_cgroup_exclusive = 0
|
||||
|
||||
## Wait on all the members of the cgroup to exit when stopping the service.
|
||||
#service_cgroup_wait = 0
|
||||
|
||||
## Send a kill signal to the members of cgroup when
|
||||
## stopping the service, and the signal to send:
|
||||
#service_cgroup_kill = 0
|
||||
#service_cgroup_kill_signal = 15
|
||||
|
||||
# Clean up the cgroup when the service exits for any reason
|
||||
#service_cgroup_cleanup = 0
|
Loading…
Reference in New Issue
Block a user