Tim*_*and 5 email bash systemd ansible
我有一个systemd服务运行一个 SQL 脚本来刷新一堆物化视图。该服务每 5 分钟一班。该服务由 ansible 部署。如果 SQL 脚本失败,我想发送一封电子邮件,通知我们失败。当前代码(请参阅下面的 yml 块)将每 5 分钟左右发送一次通知电子邮件,直到我们中的一个人修复问题或停止服务。这种情况太频繁了:一封电子邮件就足够了,而且正是我所需要的。
即使脚本多次失败,我如何才能发送一封且仅一封电子邮件?
我正在考虑使用一个包装脚本,例如这个伪代码,但它看起来很丑:
# Runs every 5 min:
psql -f refresh_matviews.sql || touch refresh_matviews.failed.log
if { exists refresh_matviews.failed.log }
and { not grep "seen" refresh_matviews.failed.log } then
echo "failed!" | mail admin@foo.com
echo "seen" > refresh_matviews.failed.log
Run Code Online (Sandbox Code Playgroud)
如果使用这样的包装脚本,那么解决问题的人也需要手动清除(现已过时的)故障文件(rm refresh_matviews.failed.log),以便任何新的故障都会触发新的电子邮件。
yml 文件的相关块ansible:
- name: Add systemd service that refreshes matviews
copy:
content: |
# This service unit refreshes matviews
#
[Unit]
Description=Refreshes matviews
Wants=refresh_matviews.timer
[Service]
User=galaxy
Type=oneshot
ExecStart=/bin/bash -c '/usr/bin/psql ... -f /path/to/refresh_matviews.sql || echo 'WARNING' | /usr/bin/mail -s "not ok: refresh matviews" admin@foo.com'
[Install]
WantedBy=multi-user.target
dest: /etc/systemd/system/refresh_matviews.service
owner: root
group: root
mode: 0644
- name: Add systemd timer that refreshes matviews
copy:
content: |
# This timer unit refreshes matviews
#
[Unit]
Description=Refreshes matviews
Requires=refresh_matviews.service
[Timer]
Unit=refresh_matviews.service
OnCalendar=*-*-* *:00/5:00
[Install]
WantedBy=timers.target
dest: /etc/systemd/system/refresh_matviews.timer
owner: root
group: root
mode: 0644
Run Code Online (Sandbox Code Playgroud)
似乎ansible/systemd应该有与我需要的类似的东西,但这就是我能找到的全部:
关于给定的用例描述
\n\n\n...直到我们中的一个人解决问题或停止服务。
\n
以及所做的评论,您可以将 SQL 脚本错误状态视为有关系统的事实。所以你可以简单地引入一个自定义事实
\n\n\n通过将可执行脚本添加到
\nfacts.d.
因此,下次运行事实收集时,您的事实将仅包括脚本错误状态,您可以进一步使用基于 的条件ansible_facts。
即使目前
\n\n\n...该服务(注释:仅)由 Ansible 部署。
\n
这种方法将有助于通过 Ansible 以及发送电子邮件警报的单独脚本来维护状态。
\n关于
\n\n\n...但无法弄清楚在我的具体情况下如何准确地使用基于 ansible 事实的自定义事实和条件。
\n
我已经为如何实施和使用自定义事实?添加了一些更具体的信息。我只关注 Ansible 部分。
\n用例和快速原型
\n如何实现自定义事实?
\n首先,我需要找出辅助节点上的流复制状态。这可以作为脚本或 cronjob 在节点上频繁运行。
\npsql -c "SELECT pg_is_in_recovery(),pg_is_wal_replay_paused(), pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn(), pg_last_xact_replay_timestamp()" -x -t\nRun Code Online (Sandbox Code Playgroud)\n致谢
\n\n对于facts.d或本地事实并按顺序
\n\n\n要使用facts.d,请
\n/etc/ansible/facts.d在一个或多个远程主机上创建一个目录。...将文件添加到目录以提供您的自定义事实。所有文件名必须以.fact. 这些文件可以是 JSON、INI 或返回 JSON 的可执行文件。
由于我将使用 Ansible、Python 进行进一步处理,因此我喜欢在(预处理)之前将结果格式化为 JSON,因为这将使以后的处理更容易。
\npsql -c "SELECT json_agg(t) FROM (SELECT pg_is_in_recovery(),pg_is_wal_replay_paused(), pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn(), pg_last_xact_replay_timestamp()) t" -x -t | cut -d "|" -f 2\nRun Code Online (Sandbox Code Playgroud)\n输出可以直接完成到事实文件中
\n> /etc/ansible/fact.d/streaming.fact\nRun Code Online (Sandbox Code Playgroud)\n根据测试和结果,附加组件可能是
\n| tr -d "[:blank:]\\n"\n# or\n| tr -d "[:blank:][]\\n" # <- I\'ve used this in my example\nRun Code Online (Sandbox Code Playgroud)\n甚至是脚本或 cronjob 的返回码。就像在这个笨拙的
\n; echo "{\\"rc\\":\\"${?}\\"}" > /etc/ansible/fact.d/script.fact\nRun Code Online (Sandbox Code Playgroud)\n或者通过什么
\n./script.sh; jq --null-input --monochrome-output --arg rc "$?" \'$ARGS.named\' > /etc/ansible/facts.d/script.fact\nRun Code Online (Sandbox Code Playgroud)\n致谢
\n\n到目前为止,该实现在辅助节点上生成了两个文件。
\n~/test$ tree /etc/ansible/facts.d/\n/etc/ansible/facts.d/\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 script.fact\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 streaming.fact\n\n~/test$ cat /etc/ansible/facts.d/script.fact\n{"rc":"0"}\n\n~/test$ cat /etc/ansible/facts.d/streaming.fact\n{"pg_is_in_recovery":true,"pg_is_wal_replay_paused":false,"pg_last_wal_receive_lsn":"1/AB2345CD","pg_last_wal_replay_lsn":"1/AB2345CD","pg_last_xact_replay_timestamp":"2023-02-01T09:00:00.00000+01:00"}\nRun Code Online (Sandbox Code Playgroud)\n如何使用自定义事实?
\n一个最小的示例剧本
\n---\n- hosts: localhost\n become: false\n gather_facts: true\n\n tasks:\n\n - name: Show Facts\n debug:\n msg: "{{ ansible_facts.ansible_local }}"\nRun Code Online (Sandbox Code Playgroud)\n将导致输出
\nTASK [Show Facts] ****************************************************\nok: [localhost] =>\n msg:\n script:\n rc: \'0\'\n streaming:\n pg_is_in_recovery: true\n pg_is_wal_replay_paused: false\n pg_last_wal_receive_lsn: 1/AB2345CD\n pg_last_wal_replay_lsn: 1/AB2345CD\n pg_last_xact_replay_timestamp: \'2023-02-01T09:00:00.00000+01:00\'\nRun Code Online (Sandbox Code Playgroud)\n或者在事实文件生成失败的情况下
\nTASK [Gathering Facts] **********************************************************************************\n[WARNING]: error loading facts as JSON or ini - please check content: /etc/ansible/facts.d/script.fact\nok: [localhost]\n\nTASK [Show Facts] ***************************************************************************************\nok: [localhost] =>\n msg:\n script: \'error loading facts as JSON or ini - please check content: /etc/ansible/facts.d/script.fact\'\nRun Code Online (Sandbox Code Playgroud)\n基于(甚至自定义)ansible_facts 的条件可能看起来像
\n - name: Show Facts\n debug:\n msg: "{{ ansible_facts.ansible_local.streaming }}"\n when: not ansible_facts.ansible_local.script.rc | bool # if there was no failure, rc=0\nRun Code Online (Sandbox Code Playgroud)\n如果脚本运行失败,会生成退出代码 1 及其事实文件内容,rc: 1从而跳过该任务。
| 归档时间: |
|
| 查看次数: |
449 次 |
| 最近记录: |