我如何判断脚本是由 systemd 调用还是由用户调用?
我为一个老式守护进程创建了一个服务。我们刚刚切换到 systemd,我的一些管理员喜欢直接调用 rc 脚本。在机器重启的情况下,这种方法效果不佳。Systemd 不会遵守,PIDFile=
因为新启动的守护进程不属于该服务的 cgroup。
我添加了服务文件和 rc_script。我无法区分用户 ID,因为要使用脚本,用户必须是foobaruser
。
停止服务现在有问题,因为 systemd 会从已删除的 pid 文件中识别出这一点。
那么我如何知道该脚本是否是由 systemd 调用的?
foobar.服务
[Unit]
Description=Foobar Service
After=syslog.target network.target
[Service]
Type=forking
User=foobaruser
LimitNOFILE=60000
LimitNPROC=8000
TasksMax=8000
PIDFile=/local/foobar/foo.pid
ExecStart=/opt/foobar/rc_script start
ExecStop=/opt/foobar/rc_script stop
TimeoutSec=100
TimeoutStopSec=300
KillMode=none
RemainAfterExit=no
Environment=LANG=de_DE.UTF-8
[Install]
WantedBy=multi-user.target
/opt/foobar/rc_script 骨架
#!/bin/bash
case $1 in
start)
VAR_IS_SYSTEMD=$( ... script to check if bash is run from systemd ... )
if [ "$VAR_IS_SYSTEMD" = false ] ; then
sudo systemctl start foobar.service
exit
fi
# start service within systemd
;;
stop)
# stop service
;;
esac
答案1
我同意其他发帖者的观点,您应该尝试重写服务以根本不调用该脚本(如果您的管理员想继续使用它,这是可以的,但 systemd 服务是否需要所有 36 个选项?) - 但检测该脚本是否是从 systemd 调用的也不难。
systemd v232 添加了单元调用 ID 的概念,该 ID 会通过
$INVOCATION_ID
环境变量传递给单元。您可以检查是否已设置。systemd v231+
$JOURNAL_STREAM
为 stdout 或 stderr 连接到日志的服务设置变量,您的服务似乎就是这种情况,因此如果您使用的是 systemd v231,您也可以检查该变量。(在 v232+ 上,$INVOCATION_ID
绝对是更好的选择。)在旧版 systemd 中,我认为不存在始终存在的环境变量,但您当然可以通过向服务中添加如下内容来自己定义一个环境变量:
Environment=LAUNCHED_BY_SYSTEMD=1
答案2
一个简单的解决方案是使用不同的脚本来启动 systemd。/opt/foobar/rc_script 应该只调用systemctl start foobar.service
和systemctl stop foobar.service
。
Suse 使用$SYSTEMD_NO_WRAP
,但我不知道这是 systemd 标准还是 Suse 特有的。
if test -z "$SYSTEMD_NO_WRAP"; then
...
/usr/bin/systemctl [start|stop] xxx.service
答案3
对于“Amazon Linux 2”和“Red Hat Enterprise Linux 7”,我找到了一个解决方案。
在这些 Linux 系统上,系统进程PID=1
是。systemd启动脚本的comm=systemd
父 ID是。PPID
1
在其他 Linux 系统中可能并非如此。
#!/bin/bash
VAR_IS_SYSTEMD_SYSTEM=$( [[ $(ps -o comm -p 1 --no-headers | tr -d ' ') == "systemd" ]] && echo true )
echo VAR_IS_SYSTEMD_SYSTEM = ${VAR_IS_SYSTEMD_SYSTEM}
VAR_IS_DAEMON_SCRIPT=$( [[ "${PPID}" == "1" ]] && echo true )
echo VAR_IS_DAEMON_SCRIPT = ${VAR_IS_DAEMON_SCRIPT}
if [[ "${VAR_IS_SYSTEMD_SYSTEM}" = true ]] && [[ "${VAR_IS_DAEMON_SCRIPT}" = true ]]; then
echo "You are a systemd Daemon Script"
else
echo "You are a normal Script"
fi
使用的元素/命令:
ps -o comm -p 1 --无标头
获取进程1的命令名称
tr-d' '
从 ps 命令中删除格式化空格
“${PPID}”
bash 进程的父 PID