如何将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
相关产品推荐
相关产品推荐

