web-dev-qa-db-ja.com

Systemd:スクリプトがsystemdによって実行されたか、ユーザーによって実行されたかを通知します

スクリプトがsystemdから呼び出されたか、ユーザーから呼び出されたかを確認するにはどうすればよいですか?

古い学校のデーモン用のサービスを作成しました。 systemdに切り替えたばかりで、私の管理者の一部はrcスクリプトを直接呼び出したいと思っています。マシンを再起動した場合、これはうまく機能しません。新しく起動したデーモンはサービスのcgroupの一部ではないため、SystemdはPIDFile=を尊重しません。

サービスファイルとrc_scriptを追加しました。スクリプトを使用するには、ユーザーがfoobaruserである必要があるため、ユーザーIDで区別することはできません。

Systemdは削除されたpidファイルからこれを認識するため、サービスの停止に問題があります。

では、スクリプトがsystemdから呼び出されたかどうかを確認するにはどうすればよいですか?

foob​​ar.service

[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
3
notes-jj

スクリプトをまったく呼び出さないようにサービスを書き直そうとする他のポスターに同意します(管理者がスクリプトを使い続けたい場合は問題ありませんが、systemdサービスには36のオプションすべてが必要ですか?)–それもまたそうではありませんスクリプトがsystemdから呼び出されたかどうかを検出するのは困難です。

  • systemd v232には、ユニットの呼び出しIDの概念が追加されました。これは、$INVOCATION_ID環境変数でユニットに渡されます。設定されているかどうかを確認できます。

  • systemd v231 +は、stdoutまたはstderrがジャーナルに接続されているサービスの$JOURNAL_STREAM変数を設定します。これは、サービスに当てはまるようです。そのため、systemd v231を使用している場合は、その変数を確認することもできます。 (v232 +では、$INVOCATION_IDが間違いなく良い選択です。)

  • 古いsystemdバージョンでは、常に存在する環境変数があるとは思いませんが、次のようなものをサービスに追加することにより、もちろん自分で定義することができます。

    Environment=LAUNCHED_BY_SYSTEMD=1
    
6

簡単な解決策は、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
2
RalfFriedl

「Amazon Linux 2」と「Red Hat Enterprise Linux 7」の場合、解決策を見つけました。

これらのLinuxシステムでは、システムプロセスPID=1comm=systemd。 systemdで開始されたスクリプトの親ID PPID1

これが当てはまらない他の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 --no-headers

    プロセス1のコマンド名を取得する

  • tr -d ''

    Psコマンドから書式空白を削除する

  • 「$ {PPID}」

    Bashプロセスの親PID

1
notes-jj