systemd 调用 bash 脚本在守护进程之前创建符号链接

systemd 调用 bash 脚本在守护进程之前创建符号链接

在 systemd 执行守护进程之前,我需要创建或更改符号链接的目标。守护进程将其标准输出重定向到此符号链接,并随之重定向到每个启动的守护进程的特殊文件中。这就是我们的想法。我设置了名为“test_start.service”的服务单元文件:

[Unit]
Description=Test Server
After=network-online.target test_start.socket
Requires=network-online.target test_start.socket

[Service]
User=test1
Group=test1
Type=simple
ExecStartPre=/bin/bash /etc/testServer/Debug/makeOutfile.sh
ExecStart=/etc/testServer/Debug/testServer
StandardInput=socket
StandardOutput=file:/etc/testServer/Debug/test_outLink
Restart=on-failure
RestartSec=3

[Install] 
WantedBy=multi-user.target

bash 脚本“/etc/testServer/Debug/makeOutfile.sh”如下所示:

#!/usr/bin/env bash
timeStamp=$(date +%y-%m-%d_%Hh%Mm%Ss)
myfolder="/etc/testServer/Debug"
# create new logfile
touch $myfolder/started_$timeStamp
# remove old symlink if exists (owned by test1)
if [ -h $myfolder/test_outLink ]; then
    rm $myfolder/test_outLink
fi
# create new symlink
ln -s $myfolder/started_$timeStamp $myfolder/test_outLink

它在某些情况下起作用。如果符号链接存在并且它指向的文件也存在,那么一切都很好。 bash 脚本“makeOutfile.sh”通过终端运行以进行测试,并通过 systemd 服务启动运行。

但:

如果指向的文件(名称:“started_atSomeDate”)不存在(因为它同时被某人删除),则脚本的终端调用将按预期工作,但启动 systemd 服务将添加一个由 root 拥有的附加文件root 具有原始旧文件名:“started_atSomeDate”。

这是从哪里来的?

如果旧的符号链接“test_outLink”不存在(因为它同时被某人删除),则脚本的终端调用将按预期工作,但启动 systemd 服务会将新创建的“test_outLink”添加为 root 拥有的常规文件具有 root 组并且服务无法启动。

这里出了严重的问题,虽然 systemd 服务单元用户和组是 test1,但 root 却混在了这里。有人能解释一下吗?我究竟做错了什么?

答案1

我的建议是您应该使用 shell 脚本来设置日志文件使用适当的重定向执行测试服务器,从而绕过StandardOutput=不适用于您的情况的 systemd 设置。

创建一个像这样的 bash 脚本/etc/testServer/Debug/runTestServer.sh

#!/usr/bin/env bash
timeStamp=$(date +%y-%m-%d_%Hh%Mm%Ss)
myfolder="/etc/testServer/Debug"
# create new logfile
touch $myfolder/started_$timeStamp
# remove old symlink if exists (owned by test1)
if [ -h $myfolder/test_outLink ]; then
    rm $myfolder/test_outLink
fi
# create new symlink
ln -s $myfolder/started_$timeStamp $myfolder/test_outLink
# run the actual testServer
exec /etc/testServer/Debug/testServer >/etc/testServer/Debug/test_outLink

与原始脚本的唯一区别makeOutfile.sh是,该脚本执行时testServer使用适当的重定向,将其标准输出发送到您刚刚设置的日志文件。

它还用于exec确保 shell 脚本不会保留并被替换testServer(这样 systemd 就会知道服务的主进程是什么。)

在您的单元文件中,删除ExecStartPre=StandardOutput=并将其替换ExecStart=为:

ExecStart=/etc/testServer/Debug/runTestServer.sh

(或者调用脚本/bin/bash也是可能的,尽管只要脚本设置了可执行位就没有必要。)

通过像这样的脚本设置服务器,您甚至可以完全绕过符号链接并直接重定向到最终started_$timeStamp日志文件。

我没有直接查看 systemd 代码,文档也不清楚它们之间的交互StandardOutput=以及ExecStartPre=具体的交互...但是 systemd 执行步骤的顺序肯定存在问题(以及哪个进程执行它们,这会导致不同的权限/所有权),所以我对您报告的结果并不感到太惊讶。我想,无论如何,我的建议是使用单个包装执行器脚本来简化它,所以希望这能解决您的问题。

相关内容