如何在 Ansible 中通过电子邮件发出警报

How to alert via email in Ansible

如果 yum 更新被标记为 'changed',我已经在 ansible 中设置了一个邮件任务来发送电子邮件。

这是我当前的工作代码:

- name: Send mail alert if updated
      community.general.mail:
        to:
        - 'recipient1'
        cc:
        - 'recipient2'
        subject: Update Alert
        body: 'Ansible Tower Updates have been applied on the following system: {{ ansible_hostname }}'
        sender: "ansible.updates@domain.com"
      delegate_to: localhost
      when: yum_update.changed

这很好用,但是,每个主机组更新的每个系统都会发送一封单独​​的电子邮件。例如,昨晚我更新了一组 20 台服务器并收到了 20 封单独的电子邮件。我知道为什么会发生这种情况,但我的问题是我将如何编写脚本以将所有系统添加到一封电子邮件中?这是否可能,或者我应该只提醒该组已更新并通知团队每个组中有哪些服务器? (我不想选择第二个选项)

编辑 1:

我已经添加了建议的代码,但现在无法接收任何电子邮件。这是错误消息:

"msg": "The conditional check '_changed|length > 0' failed. The error was: error while evaluating conditional (_changed|length > 0): {{ hostvars|dict2items| selectattr('value.yum_update.changed')| map(attribute='key')|list }}: 'ansible.vars.hostvars.HostVarsVars object' has no attribute 'yum_update'\n\nThe error appears to be in '/tmp/bwrap_1073_o8ibkgrl/awx_1073_0eojw5px/project/yum-update-ent_template_servers.yml': line 22, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n    - name: Send mail alert if updated\n      ^ here\n",

我也附上我的整个剧本以供参考:

---
- name: Update enterprise template servers
  hosts: ent_template_servers

  tasks:

    - name: Update all packages
      yum:
        name: '*'
        state: latest
      register: yum_update

    - name: Reboot if needed
      import_tasks: /usr/share/ansible/tasks/reboot-if-needed-centos.yml

    - name: Kernel Cleanup
      import_tasks: /usr/share/ansible/tasks/kernel-cleanup.yml

    - debug:
        var: yum_update.changed

    - name: Send mail alert if updated
      community.general.mail:
        to:
        - 'email@domain.com'
        subject: Update Alert
        body: |-
          Updates have been applied on the following system(s):
          {{ _changed }}
        sender: "ansible.updates@domain.com"
      delegate_to: localhost
      run_once: true
      when: _changed|length > 0
      vars:
        _changed: "{{ hostvars|dict2items|
                      selectattr('yum_update.changed')|
                      map(attribute='key')|list }}"

...

Ansible 版本为:2.9.27 Ansible Tower 版本为:3.8.3

提前致谢!

例如下面的mail任务

    - debug:
        var: yum_update.changed
    - community.general.mail:
        sender: ansible
        to: root
        subject: Update Alert
        body: |-
          Updates have been applied to the following system:
          {{ _changed }}
      delegate_to: localhost
      run_once: true
      when: _changed|length > 0
      vars:
        _changed: "{{ hostvars|dict2items|
                      selectattr('value.yum_update.changed')|
                      map(attribute='key')|list }}"
TASK [debug] ***************************************************************
ok: [host01] => 
  yum_update.changed: true
ok: [host02] => 
  yum_update.changed: false
ok: [host03] => 
  yum_update.changed: true

TASK [community.general.mail] **********************************************
ok: [host01 -> localhost]

将发送

From: ansible@domain.com
To: root@domain.com
Cc: 
Subject: Update Alert
Date: Wed, 09 Feb 2022 16:55:47 +0100
X-Mailer: Ansible mail module

Updates have been applied to the following system:
['host01', 'host03']

如果您还想收到空列表,请删除以下条件

      when: _changed|length > 0

调试

'ansible.vars.hostvars.HostVarsVars object' has no attribute 'yum_update'

问:"我可以尝试什么?"

答:部分主机缺少变量yum_update。你可以测试一下

    - debug:
        msg: "{{ hostvars|dict2items|
                 selectattr('value.yum_update.changed')|
                 map(attribute='key')|list }}"
      run_once: true

要么确保在所有主机上都定义了该变量,要么使用 json_query。此过滤器允许缺少属性,例如

    - debug:
        msg: "{{ hostvars|dict2items|
                 json_query('[?value.yum_update.changed].key') }}"
      run_once: true

问:" 'mail' 任务之前的 'debug' 任务给了我相同的输出。但是当 'mail'任务被执行。"

A:最小化代码并隔离问题。例如,在下面的代码中你可以看到

  • 变量 yum_update.changedhost03
  • 上丢失
  • 过滤器json_query忽略这个
  • 过滤器selectattr失败
    - debug:
        var: yum_update.changed

    - debug:
        msg: "{{ hostvars|dict2items|
                 json_query('[?value.yum_update.changed].key') }}"
      run_once: true

    - debug:
        msg: "{{ hostvars|dict2items|
                 selectattr('value.yum_update.changed')|
                 map(attribute='key')|list }}"
      run_once: true

给予

TASK [debug] **************************************************
ok: [host01] => 
  yum_update.changed: true
ok: [host02] => 
  yum_update.changed: false
ok: [host03] => 
  yum_update.changed: VARIABLE IS NOT DEFINED!

TASK [debug] **************************************************
ok: [host01] => 
  msg:
  - host01

TASK [debug] **************************************************
fatal: [host01]: FAILED! => 
  msg: |-
    The task includes an option with an undefined variable.
    The error was: 'ansible.vars.hostvars.HostVarsVars object'
    has no attribute 'yum_update'

如果所有变量都存在,两个过滤器给出相同的结果

TASK [debug] **************************************************
ok: [host01] => 
  yum_update.changed: true
ok: [host02] => 
  yum_update.changed: false
ok: [host03] => 
  yum_update.changed: true

TASK [debug] **************************************************
ok: [host01] => 
  msg:
  - host01
  - host03

TASK [debug] **************************************************
ok: [host01] => 
  msg:
  - host01
  - host03