如何通过Ansible检查远程服务器的“正常运行时间”,并通过邮件以CSV和HTML格式发送报告?

How to check `uptime` of Remote Server thru Ansible and send report as CSV and HTML via mail?

提问人:sab 提问时间:10/23/2023 最后编辑:U880Dsab 更新时间:10/24/2023 访问量:133

问:

我创建了一个 Ansbile 脚本来检查远程服务器(库存组中的近 60+ 台服务器),并将其发送到带有 CSV 和 HTML 文件的电子邮件。它正在工作,但它为每个服务器发送单独的邮件。uptimelinux

我需要它来收集输出并以 csv 和 HTML 格式发送一封包含所有服务器正常运行时间和主机名的邮件。

这是我的剧本。

main.yaml

---
- name: Generate Uptime HTML Report and Send Email
  hosts: linux
  gather_facts: true

  vars:

    email_subject: Uptime Report
    email_host: xyz
    email_from: xyz
    email_to: xyz
    email_body_template: templates/report.html.j2
    csv_path: /tmp
    csv_filename: report.csv
    headers: Hostname,Uptime_In_Days

  tasks:

    - name: Get Uptime
      command: uptime
      register: uptime_result

    - name: Extract Uptime in Days
      set_fact:
        uptime_days: "{{ uptime_result.stdout | regex_replace('^.*up ([0-9]+) day.*', '\\1') | int }}"
      when: uptime_result.rc == 0

    - name: Create CSV Data
      set_fact:
        csv_data:
          - Hostname: "{{ inventory_hostname }}"
            Uptime_In_Days: "{{ uptime_days }}"
      when: uptime_result.rc == 0

    - name: Transfer CSV Data File
      copy:
        content: "{{ csv_data | to_nice_json }}"
        dest: "{{ csv_path }}/{{ csv_filename }}"
        mode: '0644'

    - name: Send Email
      mail:
        host: "{{ email_host }}"
        from: "{{ email_from }}"
        to: "{{ email_to }}"
        subject: "[Ansible] {{ email_subject }}"
        body: "{{ lookup('template', email_body_template) }}"
        attach: "{{ csv_path }}/{{ csv_filename }}"
        subtype: html

html.j2

<sub><table style="border: 1px solid black; border-collapse: collapse;">
<tr>
    {% for header in headers.split(",") %}
    <th style="border: 1px solid black; padding: 8px 16px;">{{ header }}</th>
    {% endfor %}
</tr>
{% for host in csv_data %}
<tr>
    {% for header in headers.split(",") %}
    <td style="border: 1px solid black; padding: 8px 16px;">{{ host[header] }}</td>
    {% endfor %}
</tr>
{% endfor %}
</table></sub>
Linux Ansible 正常运行时间

评论


答:

0赞 U880D 10/23/2023 #1

如何在 Linux 远程节点上收集正常运行时间

由于您已经为了获得可用的 Ansible 事实,因此它还包含 .请参阅最小可重现示例gather_factsansible_uptime_seconds

---
- hosts: localhost
  become: false
  gather_facts: true

  tasks:

  - debug:
      msg: "Days up: {{ (ansible_facts.uptime_seconds / 86400) | int }}"

没有必要 和 .commandset_fact

它正在工作,但它......对于每个服务器。

因此,可以直接在控制节点上为当前播放中的所有主机编写 CSV 报告。

---
- hosts: linux
  become: false
  gather_facts: true

  vars:

    csv_path: '.'
    csv_filename: 'report.csv'

  tasks:

  - name: Write uptime into CSV
    delegate_to: localhost # aka Control Node
    lineinfile:
      dest: "{{ csv_path }}/{{ csv_filename }}"
      line: "{{ inventory_hostname }},{{ (ansible_facts.uptime_seconds / 86400) | int }}"
      create: true
      state: present
    loop: "{{ ansible_play_hosts }}"

For How to proceed further? you may have a look into

Similar Q&A

1赞 Vladimir Botka 10/24/2023 #2

Take the attribute uptime_seconds from ansible_facts and set the variable uptime in days

    - set_fact:
        uptime: "{{ (ansible_facts.uptime_seconds/86400)|round(2) }}"

Declare the dictionary

  host_uptime: "{{ dict(ansible_play_hosts|
                        zip(ansible_play_hosts|
                            map('extract', hostvars, 'uptime'))) }}"

gives, for example

  host_uptime:
    test_11: '0.52'
    test_13: '0.52'

Create the templates. Fit the formats to your needs

shell> cat templates/report.html.j2
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Report hosts uptime</title>
  </head>
  <body>
    <table>
      <tr>
{% for header in headers.split(',') %}
        <th>{{ header }}</th>
{% endfor %}
      </tr>
{% for host in ansible_play_hosts %}
      <tr>
        <td>{{ host }}</td><td>{{ host_uptime[host] }}</td>
      </tr>
{% endfor %}
    </table>
  </body>
</html>
shell> cat templates/report.csv.j2
{{ headers }}
{% for host,uptime in host_uptime.items() %}
{{ host }},{{ uptime }}
{% endfor %}

测试 HTML 模板

    - debug:
        msg: "{{ lookup('template', 'report.html.j2') }}"

  msg: |-
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <title>Report hosts uptime</title>
      </head>
      <body>
        <table>
          <tr>
            <th>Host</th>
            <th>Uptime_In_Days</th>
          </tr>
          <tr>
            <td>test_11</td><td>0.52</td>
          </tr>
          <tr>
            <td>test_13</td><td>0.52</td>
          </tr>
        </table>
      </body>
    </html>

测试 CSV 模板

    - debug:
        msg: "{{ lookup('template', 'report.csv.j2') }}"

  msg: |-
    Host,Uptime_In_Days
    test_11,0.52
    test_13,0.52

在 localhost 上写入文件

    - template:
        src: report.csv.j2
        dest: /tmp/report.csv
        mode: 0644
      delegate_to: localhost
      run_once: true

shell> cat /tmp/report.csv 
Host,Uptime_In_Days
test_11,0.52
test_13,0.52

发送邮件

   - mail:
        host: localhost
        from: "{{ ansible_user }}"
        to: root
        subject: '[Ansible] Report uptime'
        body: "{{ lookup('template', 'report.html.j2') }}"
        subtype: html
        attach: /tmp/report.csv
      delegate_to: localhost
      run_once: true

给出(电子邮件客户端将 HTML 呈现为文本)

Return-Path: <[email protected]>
X-Original-To: root
Delivered-To: [email protected]
Received: from [127.0.0.1] (localhost [127.0.0.1])
 by example.org (Postfix) with ESMTPS id 2FCC41802F6
 for <root>; Tue, 24 Oct 2023 05:24:20 +0200 (CEST)
Content-Type: multipart/mixed; -charset="utf-8"; boundary="===============6826681646037083043=="
MIME-Version: 1.0
From: [email protected]
Date: Tue, 24 Oct 2023 05:24:20 +0200
Subject: [Ansible] Report uptime
X-Mailer: Ansible mail module
To: [email protected]
Cc: 
Message-Id: <[email protected]>

Report hosts uptime
Host Uptime_In_Days
test_110.52
test_130.52



[report.csv  application/octet-stream (65 bytes)]

用于测试的完整 playbook 示例

- name: Mail uptime table
  hosts: all
  gather_facts: true

  vars:

    headers: Host,Uptime_In_Days
    host_uptime: "{{ dict(ansible_play_hosts|
                          zip(ansible_play_hosts|
                              map('extract', hostvars, 'uptime'))) }}"
    
  tasks:

    - set_fact:
        uptime: "{{ (ansible_facts.uptime_seconds/86400)|round(2) }}"

    - block:
        
        - debug:
            var: host_uptime
        - debug:
            msg: "{{ lookup('template', 'report.html.j2') }}"
        - debug:
            msg: "{{ lookup('template', 'report.csv.j2') }}"

      when: debug|d(false)|bool
      run_once: true

    - block:

        - template:
            src: report.csv.j2
            dest: /tmp/report.csv
            mode: 0644

        - mail:
            host: localhost
            from: "{{ ansible_user }}"
            to: root
            subject: '[Ansible] Report uptime'
            body: "{{ lookup('template', 'report.html.j2') }}"
            subtype: html
            attach: /tmp/report.csv
          when: mail_enable|d(false)|bool

      delegate_to: localhost
      run_once: true