You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Ansible Playbook输出作为变量用于邮件通知

问题描述

我用Ansible管理Linux服务器,写了个自动更新所有服务器并发送邮件通知的Playbook。更新功能正常,但邮件通知里没法正确包含Playbook的任务输出——我想把apt update和apt upgrade的输出放进邮件里,尝试注册变量后用.stdout获取,但没成功。

我的Playbook代码如下:

- name: Update apt repo und cache auf alle server
  apt: update_cache=yes force_apt_get=yes cache_valid_time=3600
  register: aptrepo

- name: Aktualisiert alle pakete
  apt: upgrade=dist force_apt_get=yes
  register: aptupgrade

- name: Überprüfen ob ein Neustart benötigt wird
  register: reboot_required_file
  stat: path=/var/run/reboot-required get_md5=no

- name: Neustarten wenn der Kernel der Maschine aktualisiert wurde
  reboot:
    msg: "Neustart wurde vom Ansible initiiert"
    connect_timeout: 5
    reboot_timeout: 300
    pre_reboot_delay: 0
    post_reboot_delay: 30
    test_command: uptime
  when: reboot_required_file.stat.exists
  
- name: Senden Email an Ticketsystem
  mail:
    host: smtp.office365.com
    port: 587
    username: email.de
    password: "{{emailpw}}"
    from: "email.de"
    to: "email.de"
    subject: "[INTERN] - Linux Servern wurden aktualisiert"
    body: "Folgende Linux Server wurden erfolgreich aktualisiert: {{ play_hosts | to_yaml }}\nDiese wurden ggf. neugestartet falls der Kernel aktualisiert wurde!\nOutput: {{aptrepo.stdout}}"
    secure: starttls
  delegate_to: localhost
  run_once: true

解决方案

1. 核心问题:.stdout无效的原因

Ansible的apt模块(多数内置模块都是如此)并非直接调用系统命令执行,而是通过API完成操作,因此不会把执行输出写入stdout字段,直接调用aptrepo.stdout自然拿不到内容。要获取模块执行的有效信息,需要查看注册变量的结构化字段:

  • aptupgrade.changed:判断当前主机是否有包被更新
  • aptupgrade.results:包含每个更新包的详细信息(包名、旧版本、新版本)
  • stdout_lines:部分模块会存输出,但apt模块依赖结构化数据而非命令行输出

2. 调整Playbook实现邮件输出

方案一:用模块结构化数据构建可读邮件内容

修改邮件任务的body部分,通过hostvars跨主机获取每台服务器的更新详情,同时优化格式可读性:

- name: Senden Email an Ticketsystem
  mail:
    host: smtp.office365.com
    port: 587
    username: email.de
    password: "{{emailpw}}"
    from: "email.de"
    to: "email.de"
    subject: "[INTERN] - Linux Servern wurden aktualisiert"
    body: |
      Folgende Linux Server wurden aktualisiert: {{ play_hosts | join(', ') }}
      
      {% for host in ansible_play_hosts %}
      === {{ host }} ===
      {% if hostvars[host].aptupgrade.changed %}
      Aktualisierte Pakete:
      {% for pkg in hostvars[host].aptupgrade.results %}
      - {{ pkg.name }}: {{ pkg.old_version }} -> {{ pkg.new_version }}
      {% endfor %}
      {% else %}
      Keine Pakete zur Aktualisierung vorhanden.
      {% endif %}
      
      {% if hostvars[host].reboot_required_file.stat.exists %}
      Server wurde nach der Aktualisierung neu gestartet.
      {% else %}
      Neustart nicht erforderlich.
      {% endif %}
      {% endfor %}
    secure: starttls
  delegate_to: localhost
  run_once: true

方案二:用command模块获取原始命令输出(可选)

如果一定要拿到apt update/apt upgrade的原始命令行输出,可以替换apt模块为command模块(注意:此方法会绕过Ansible幂等性检查,不如官方模块可靠):

- name: Update apt repo und cache auf alle server
  command: apt-get update -y
  register: aptrepo
  changed_when: "'Hit:' in aptrepo.stdout or 'Get:' in aptrepo.stdout"

- name: Aktualisiert alle pakete
  command: apt-get dist-upgrade -y
  register: aptupgrade
  changed_when: aptupgrade.rc != 0 or '0 upgraded, 0 newly installed' not in aptupgrade.stdout

替换后aptrepo.stdout和aptupgrade.stdout会包含命令的原始输出,可直接在邮件中调用。

3. 关键注意事项

  • 邮件任务是run_once: true且delegate_to: localhost,必须通过hostvars[host]获取远程主机的注册变量,直接调用aptrepo只会拿到localhost的空值
  • 用| join(', ')替代to_yaml可让服务器列表更易读
  • 用多行字符串标记|编写邮件body,能让格式更清晰规整

内容的提问来源于stack exchange,提问作者SirSeba

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 14:06:54