如何在systemd服务启动失败时使Ansible失败?

7

我有一个systemd服务,我想通过Ansible启动它。

我的systemd服务单元文件如下:

[Unit]
Description=Collector service
After=network.target mariadb.service
Requires=mariadb.service

[Service]
Type=simple
ExecStart=/opt/collector/app.py
WorkingDirectory=/opt/collector
Restart=on-abort
User=root

[Install]
WantedBy=multi-user.target

我正在使用Type=simple,因为这看起来像是正确的解决方案(也是此问题中首选的解决方案)。

我也尝试使用Type=oneshot(正如最初提出这个问题的用户所建议的将其作为这个问题的重复),但问题在于/opt/collector/app.py脚本是一个长时间运行的进程:

while True:
    t = threading.Thread(...)
    t.start()
    t.join()
    time.sleep(15)

使用Type=oneshot参数时,Ansible会永久阻塞

我的Ansible起始代码如下:

- name: start Collector service
  systemd:
    name: collector
    state: started
    enabled: yes

在目标系统上,systemctl 将显示以下内容:
[root@srv01 /]# systemctl
  UNIT                           LOAD   ACTIVE     SUB       DESCRIPTION
  dev-sda1.device                loaded activating tentative /dev/sda1
  -.mount                        loaded active     mounted   /
  dev-mqueue.mount               loaded active     mounted   POSIX Message Queue File System
  etc-hostname.mount             loaded active     mounted   /etc/hostname
  etc-hosts.mount                loaded active     mounted   /etc/hosts
  etc-resolv.conf.mount          loaded active     mounted   /etc/resolv.conf
  run-user-0.mount               loaded active     mounted   /run/user/0
  session-73.scope               loaded active     running   Session 73 of user root
  crond.service                  loaded active     running   Command Scheduler
  dbus.service                   loaded active     running   D-Bus System Message Bus
  haproxy.service                loaded active     running   HAProxy Load Balancer
<E2><97><8F> collector.service          loaded failed     failed   Collector service
....

由于Python进程异常(使用未定义的变量),服务失败了。

但是我的Ansible剧本运行并没有失败:

TASK [inventory : start Collector service] *********************************
changed: [srv01]

我尝试了使用systemdservice Ansible模块,但行为都是一样的。
如何让Ansible:
  • 在systemd单元启动失败时失败?
  • 不阻塞并使systemd以active running状态运行while True过程?

这个问题不是提到的那个问题的重复。请查看最后的编辑。由于systemd需要启动长时间运行的进程,因此oneshot不是解决方案。 - Gabriel Petrovay
没有人建议oneshot是你的解决方案,还有其他选项需要你去探索和选择。我关闭了这个问题,因为你问了一个为什么它没有返回错误的原因,而另一个答案以一种很好的方式解释了这个问题。这也不是Ansible的问题,因为systemctl start的行为完全相同 - 所以你可以从你的问题中删除所有与Ansible相关的内容。你只剩下一个开放且过于广泛的问题“如何用Python编写一个守护进程”。 - techraf
但问题在于systemd本身的行为是正确的。困难在于如何从Ansible中运行它(即永久阻塞或不显示故障)。如果您有解决此问题的Ansible解决方案,可以发布答案。这样,如果您认为自己知道一切,可能会阻止其他人提供/接收答案。干杯! - Gabriel Petrovay
1
另外,从纯净的角度来看,我不知道你为什么要指出与simple vs oneshot systemd选项明确比较的另一个问题。对于“探索其他选项[...]”,我认为你应该指向:https://www.freedesktop.org/software/systemd/man/systemd.service.html (顺便说一下,我已经阅读过它,但仍然没有找到从Ansible运行它的解决方案)。 - Gabriel Petrovay
@GabrielPetrovay 我指向你那个答案是因为它包含了Type=simple的描述和为什么它不会在该设置下对你有用。 ・ 所以你声称 systemd 的行为与 Ansible 不同,也与其设计方式不同(请阅读其他答案),对吗?然后你认为这是“正确”的?与文档相反的行为? ・ 将“认为自己知道一切”的态度归因于想要帮助的人不仅是粗鲁的,而且还会适得其反。 - techraf
我在想是否使用-vvvv(或更多的v)运行可以帮助显示正在发生的事情。这个ansible任务正在做两件事:启动然后启用。也许第一个任务失败了,但第二个任务成功了,这是ansible返回的rc。您可以尝试将这两个任务分成单独的任务。 - brianc
2个回答

3
我在遇到类似无声失败的服务问题时偶然发现了这个。我还找到了一个描述此问题的错误报告,经过一些研究,我找到了一个解决方法:bug report
- name: start Collector service
  systemd:
    name: collector
    state: started
    enabled: yes

- name: make sure Collector service is really running
  command: systemctl is-active collector

请注意,对于Type=simple服务来说,只有在它启动后立即失败时才会失败。"最初的回答"

0

您可以使用failed_when,例如:

- name:  validating processes started correctly
  shell: pgrep toto| wc -l
  register: after_count
  failed_when: after_count.stdout_lines[0] == "1"

failed_when 会在返回的进程数不等于 == 1 时使任务失败。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接