如果另一个 systemd 服务正在运行,则阻止 systemd 服务启动

如果另一个 systemd 服务正在运行,则阻止 systemd 服务启动

在 systemd(UbuntuLinux 18.04 bionic 上的 v237)中,我可以创建一个服务文件(用于A.service),并指定另一个服务Requisite=B.service。这意味着如果我尝试启动A.serviceB.service尚未运行,则 A.service 将不会启动。它是 的弱版本,当我尝试启动 时Requires它将启动。B.serviceA.service

有相反的情况吗?我可以说“如果 B.service 正在运行,那么启动此服务”/“如果B.service正在运行,那么A.service就无法启动”?

文档说如果我这样做Conflicts=B.service,启动A将停止 B,然后启动 A。但我不希望 B 停止,我只想让 A 无法启动。我想要的Conflicts是。RequisiteRequires

我可能要将其更改ExecStart为会失败的 shell 命令systemctl is-active B.service或某种黑客行为。有合适的解决方案吗?

答案1

我后来发现,这种情况的最佳选择是ExecCondition=因为它允许您进行适当的错误控制;ExecStartPre=如果退出时非零,将始终生成错误;同时ExecCondition=允许停止执行而不抛出错误,或者在需要时抛出错误。这对于ExecStartPost=处理通知非常方便(您可以设置触发器来通知服务未启动,因为另一个正在运行)。

ExecCondition= 在 ExecStartPre= 中的命令之前执行的可选命令。语法与 ExecStart= 相同,但允许多个命令行并且命令按顺序一个接一个地执行。

该行为类似于 ExecStartPre= 和条件检查的混合:当 ExecCondition= 命令以退出代码 1 到 254(含)退出时,其余命令将被跳过,并且单元不会被标记为失败。但是,如果 ExecCondition= 命令以 255 或异常退出(例如超时、被信号终止等),则该单元将被视为失败(并且将跳过其余命令)。退出代码为 0 或匹配 SuccessExitStatus= 的命令将继续执行下一个命令。

关于不要在 ExecStartPre= 中运行长时间运行的进程的建议同样适用于 ExecCondition=。在出现任何非零或异常退出(如上所述)的情况下,ExecCondition= 还将运行 ExecStopPost= 中的命令,作为停止服务的一部分。

代码逻辑都是一样的:

ExecCondition=/bin/bash -xc '/usr/bin/systemctl is-active --quiet other-unit.service && { [[ %i == "main" ]] && exit 255 || exit 1; } || exit 0'

ExecCondition=相对于 的优势ExecStartPre=在于,在这个例子中,它将检查此服务实例是否为“主”并以失败状态代码退出,因此您可以轻松注意到它;您也可以将其用作ExecStartPost=和 的触发器ExecStopPost=

一个建议是使用多个条目,而ExecCondition=不是在单个条目中运行太多命令(尽管允许);它将增强故障排除并防止由于超时而导致的失败状态。

答案2

通常,执行此操作的方法是使用ExecStartPre检查其他服务是否正在运行的命令。如果命令ExecStartPre返回错误代码,则其余启动过程将中止。

ExecStartPre=/bin/bash -c '! /usr/bin/systemctl is-active --quiet other-unit.service'

相关内容