Linux

systemd 呼叫 bash 腳本在守護程序之前創建符號連結

  • December 10, 2018

在 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 擁有的附加文件,組具有原始舊文件名的根:“started_atSomeDate”。

那是從哪裡來的?

如果舊符號連結“test_outLink”不存在(因為它同時被某人刪除),腳本的終端呼叫按預期工作,但啟動 systemd 服務會將新創建的“test_outLink”添加為 root 擁有的正常文件使用組 root 並且服務無法啟動。

這裡出現了嚴重錯誤,雖然 systemd 服務單元使用者和組是 test1,但 root 在這裡混在一起。誰能解釋一下?我究竟做錯了什麼?

我的建議是你應該使用一個 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 執行步驟的順序肯定存在問題(以及哪個程序執行它們,這導致不同的權限/所有權),所以我對你報告的結果並不感到驚訝。我想,無論如何,我的建議是使用單個包裝器執行程序腳本來簡化它,因此希望這可以解決您的問題。

引用自:https://unix.stackexchange.com/questions/487009