Problem description
I noticed this when using Graylog Collector Sidecar which uses this library to generate init scripts (see here).
The init script created for SysV systems (CentOS/RedHat 6) doesn't create a consistent PID file, which can lead to multiple processes running, especially if you try restarting the process after it's already been started on boot (very common).
The template here creates a PID file using the name of the running script. The problem is that SysV scripts are symlinked from their runlevel to the main script, and the filenames are different. So the script name called on boot is different from the script called from the service command.
For example when you boot a system into a runlevel, it will look for that level's startup scripts, in this case /etc/rc.d/rc3.d/S99collector-sidecar which is actually a symlink to the main startup script:
# runlevel
N 3
# ls -lh /etc/rc.d/rc3.d/S99collector-sidecar
lrwxrwxrwx. 1 root root 27 Nov 2 15:56 /etc/rc.d/rc3.d/S99collector-sidecar -> ../init.d/collector-sidecar
This means the PID file from the init on boot is named /var/run/S99collector-sidecar.pid. Now if you try to restart the service using the service command it's going to call /etc/rc.d/init.d/collector-sidecar (NOT S99collector-sidecar), and create a PID file at /var/run/collector-sidecar.pid which is different. The result is the is_running() function doesn't find the original PID and now there's two processes running:
# service collector-sidecar restart
Not running
Starting collector-sidecar
# ps -ef | grep -i graylog
root 2819 1 0 15:58 ? 00:00:00 /usr/bin/graylog-collector-sidecar
root 2896 2819 0 15:58 ? 00:00:00 /usr/bin/filebeat -c /etc/graylog/collector-sidecar/generated/filebeat.yml
root 3070 1 0 16:00 pts/0 00:00:00 /usr/bin/graylog-collector-sidecar
root 3104 3070 0 16:00 pts/0 00:00:00 /usr/bin/filebeat -c /etc/graylog/collector-sidecar/generated/filebeat.yml
Proposed solutions
I would suggest setting the name variable to the symlink destination by using the readlink command, so this:
would become:
name=$(basename $(readlink -f $0))
Now both scripts result in the same filename, whether they were executed via symlink or not:
# basename $(readlink -f /etc/rc.d/init.d/collector-sidecar)
collector-sidecar
# basename $(readlink -f /etc/rc.d/rc3.d/S99collector-sidecar)
collector-sidecar
Optionally (or in addition to this), you could make the name variable itself be configurable in the template so that it can be set statically. Not sure if the template language supports optional parameters.
Problem description
I noticed this when using Graylog Collector Sidecar which uses this library to generate init scripts (see here).
The init script created for SysV systems (CentOS/RedHat 6) doesn't create a consistent PID file, which can lead to multiple processes running, especially if you try restarting the process after it's already been started on boot (very common).
The template here creates a PID file using the name of the running script. The problem is that SysV scripts are symlinked from their runlevel to the main script, and the filenames are different. So the script name called on boot is different from the script called from the
servicecommand.For example when you boot a system into a runlevel, it will look for that level's startup scripts, in this case
/etc/rc.d/rc3.d/S99collector-sidecarwhich is actually a symlink to the main startup script:This means the PID file from the init on boot is named
/var/run/S99collector-sidecar.pid. Now if you try to restart the service using theservicecommand it's going to call/etc/rc.d/init.d/collector-sidecar(NOTS99collector-sidecar), and create a PID file at/var/run/collector-sidecar.pidwhich is different. The result is theis_running()function doesn't find the original PID and now there's two processes running:Proposed solutions
I would suggest setting the
namevariable to the symlink destination by using thereadlinkcommand, so this:would become:
Now both scripts result in the same filename, whether they were executed via symlink or not:
Optionally (or in addition to this), you could make the
namevariable itself be configurable in the template so that it can be set statically. Not sure if the template language supports optional parameters.