스크립트 조건이 True인 경우에만 systemd 서비스 실행

스크립트 조건이 True인 경우에만 systemd 서비스 실행

아래와 같이 LCD 화면에 쓰는 시스템 서비스가 있습니다.

[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:sudoer admin에 의존할 뿐만 아니라 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

관련 정보