スクリプト条件がTrueの場合にのみsystemdサービスを実行する

スクリプト条件がTrueの場合にのみsystemdサービスを実行する

以下のように液晶画面に書き込むシステムサービスがあります。

[Unit]
Description=LCD Screen


[Service]
Type=simple
User=admin
WorkingDirectory=/lcd
ExecStart=sudo /run_lcd.py
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=lcd-service
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

LCDがコンピュータに接続されている場合にのみサービスを実行したいと思います。パネルはシリアルポートを介して接続されているため、これを知る唯一の方法は特定のメッセージをLCD画面に送信することです。このメッセージは、接続されると値を返します。これをスクリプトで実行する場合、スクリプトの出力を取得し、その出力に基づいてサービスを実行する方法はありますか?

私は見たことがないsystemdの条件と主張しかし、私が望むことができるオプションは表示されません。どんな助けでも大変感謝します。

答え1

Edgarの答えはExecStartPre=悪くありませんが、実行がブロックされるとExecStart=サービスにフラグが立てられますfailed

また、それを試すことができますExecCondition=。この動作はExecStartPre=とのCondition*=混合と同じです。

終了コード 行動
0 デバイスは引き続き起動します。
1-254 開始は放棄され、ユニットは続くinactive (dead)
255 捨て始め、ユニットはfailed

簡単な例は次のとおりです。

$ cat condition.service 
[Service]
ExecCondition=/bin/false
ExecStart=/bin/sleep 20

$ systemctl --user start  condition.service
$ systemctl --user status condition.service
● condition.service
     Loaded: loaded 
     Active: inactive (dead)

Starting condition.service...
condition.service: Control process exited, code=exited, status=1/FAILURE
condition.service: Skipped due to 'exec-condition'.

あなたはrestart=always質問を提出します。起動が無効になったらExecCondition=もう一度やり直してください...永遠に...(RestartSec=起動制限に達するのを防ぎます)これはあなたが望むものではないかもしれません。

restart=on-failureあなたのサービスが返されたら、EXIT_SUCCESSおそらくそのタスクは完了したので、そのタスクを再要求する必要はありません。ただし、return EXIT_FAILURE;エラーが発生した場合はいつでも再起動できます。 ExecCondition=これを可能にしなさい。

を使用すると、ExecStartPre=スクリプトがサービスを無効にしようとすると、サービスは失敗して終了します。これはrestart=on-failureあなたが利用できず、唯一のオプションかもしれないrestart=on-successことを意味します。restart=no


その他のヒント:

  • User=admin
    • sudoスクリプトで使用しています。これはNOPASSWD:sudoeradminに依存するだけでなくroot。このスクリプトを実行するためにroot権限が必要な場合は、サービスをrootとして直接実行してこの行を削除してください。
  • ExecStart=sudo /run_lcd.py
    • run_lcd.py一般的にはインストールしないでください/。自分で作成した(または手動でインストールした)スクリプトであれば、それに入れてください/usr/local/bin。このような組織は、新しいサーバーを再作成するときに「すべてのローカルコンテンツ」を見つけるのに本当に役立ちます。ハードウェア。
  • Type=simple
    • 明示的に表現しても悪いことはないと思いますが、これがデフォルトですType=。ファイルが複雑になるので、これを追加しません。
  • Standard{Output,Error}=syslog
    • このsyslogオプションはsystemdから削除されました。それでも以前のバージョンと互換性がありますが、以下から削除されました。文書。デフォルトのログを使用するには、この行を削除します(必要に応じて渡されます)。ドキュメント(Debian Busterの確認)では、次のように述べています。

    システムログロギングに加えて、標準出力はsyslog(3)システムのsyslogサービスに接続されます。ロギングデーモンは通常、受信したすべてをsyslogに渡すように構成されています。この場合、このオプションはロギングと変わりません。

  • RestartSec=10
    • これは、人々が再起動制限に達するのを避けるために使用するトリックです。multi-user.target起動後にグラフィックアプリケーションを起動する人に特に便利です。より良い解決策は、リソースが準備された後にのみデバイスを起動することです。一般的に使用するのがWantedBy=graphical.target正しい解決策です。 After=graphical.targetまた、すべてが準備されるまでサービスが開始されないようにします。あなたのサービスはグラフィックに関連しているように見えるので、これらのコンテンツが役に立つと思います。それにもかかわらず、最終的にうまく機能するサービスを持っていれば、RestartSet=それは必要ありません。

それを組み合わせるには、次のようにします。

[Unit]
Description=LCD Screen
After=graphical.target

[Service]
WorkingDirectory=/lcd
ExecCondition=/usr/bin/python3 /usr/local/bin/checkScreen.py
ExecStart=/usr/local/bin/run_lcd.py
SyslogIdentifier=lcd-service
Restart=on-failure

[Install]
WantedBy=graphical.target

答え2

@Pankiが言ったようRestart=alwaysにに変更する必要があります。Restart=on-successExecStartPre

したがって、別のスクリプト(Pythonと仮定)を使用して画面が接続されていることを確認することをお勧めします。たとえば、単純なPythonスクリプトは次のようになります。

/checkScreen.py

#you will have to add before this lines the code
#used for getting the status of screen

if screenIsConnected:
    exit(0)
else:
    exit(1)

あなたのシステムサービスは次のとおりです。

[Unit]
Description=LCD Screen

[Service]
Type=simple
User=admin
WorkingDirectory=/lcd
ExecStartPre=/usr/bin/python3 /checkScreen.py
ExecStart=sudo /run_lcd.py
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=lcd-service
Restart=on-success
RestartSec=10

[Install]
WantedBy=multi-user.target

関連情報