如何使用 ansible 和 jinja2 为多个主机生成 html 报告

how to generate html report for multiple hosts using ansible and jinja2

我的剧本

    - name: create HTML report
      template:
        src: report.j2
        dest: /cktreport.html
      delegate_to: localhost
      run_once: true

报告.j2

<!DOCTYPE html>
<html>
<body>
<table>
    <thead>
        <tr>
            <th>HOSTNAME</th>
            <th>PORT</th>
            <th>CKTID</th>
        </tr>
    </thead>
    <tbody>      
    {% for item in output.parsed %}
        <tr>
        {% if 'CID' in item.DESCRIP %}
            <td>{{inventory_hostname}}</td>
            <td>{{item.PORT}}</td>
            <td>{{item.DESCRIP}}</td>  
        {%elif 'ckid' in item.DESCRIP %}
            <td>{{inventory_hostname}}</td>
            <td>{{item.PORT}}</td>
            <td>{{item.DESCRIP}}</td>               
        {% endif %}    
     {% endfor %}   
        </tr>      
{% endfor %}
    </tbody>
</table>

</body>
</html>

'output.parsed' 有以下信息

TASK [debug] *******************************************************************
ok: [host-1] => {
    "msg": [
        {
            "DESCRIP": "CID: xxxx",
            "PORT": "Gi0/0/0",
            "PROTOCOL": "up",
            "STATUS": "up"
        },
        {
            "DESCRIP": "",
            "PORT": "Gi0/0/1",
            "PROTOCOL": "up",
            "STATUS": "up"
        },
        {
            "DESCRIP": "",
            "PORT": "Gi0/0/2",
            "PROTOCOL": "down",
            "STATUS": "down"
        },
        {
            "DESCRIP": "ckid: XXXX",
            "PORT": "Gi0/0/3",
            "PROTOCOL": "up",
            "STATUS": "up"
        }
    ]
}
ok: [host-2] => {
    "msg": [
        {
            "DESCRIP": "CID: xxxx",
            "PORT": "Gi0/0/1",
            "PROTOCOL": "up",
            "STATUS": "up"
        },
        {
            "DESCRIP": "",
            "PORT": "Gi0/0/6",
            "PROTOCOL": "up",
            "STATUS": "up"
        },
        {
            "DESCRIP": "",
            "PORT": "Gi0/0/7",
            "PROTOCOL": "down",
            "STATUS": "down"
        },
        {
            "DESCRIP": "ckid: XXXX",
            "PORT": "Gi0/0/8",
            "PROTOCOL": "up",
            "STATUS": "up"
        }
    ]
}

我遇到的问题是 - 当我 运行 playbook 时,只为 host-1 生成 cktreport.html, 我有多个主机,如何生成 single/one cktreport.html 以便其中包含所有主机信息。

我知道我需要修改 jinja2 模板,但不确定要使用什么逻辑。

我会理所当然地认为你的剧本针对的是魔术组 all。如果不是这种情况,只需将下面的模板替换为正确的组即可。

如果您正在做一些更复杂的事情(针对多个组,使用高级主机模式,在命令行上使用限制...)看看 special variables 比如 ansible_play_hosts 这将更适应。

在大多数情况下,在自然播放主机循环之外直接在主机列表上循环是一种不好的做法...除非有充分的理由和这个。在您的模板中,您需要遍历所有主机以包含在报告中,然后循环处理您之前收集的已解析信息。我相信以下模板应该可以满足您的要求(未经测试)。

备注:

  • 因为h实际上包含了inventory_hostname,为了简洁我直接用了。但如果您愿意,可以用 hostvars[h].inventory_hostname 替换。结果将完全相同。
  • 您的示例模板无效(关闭 endfor 没有 opennig for 挂起)。我在下面修复了它。
  • 我保留了你的 if 节,但你有几个选项可以在这里 DRY 并同时检查两个条件(使用 match test 或其他正则表达式解决方案...)以输出之后的同一块html。如果你愿意,我会让你自己探索。
<!DOCTYPE html>
<html>
<body>
<table>
    <thead>
        <tr>
            <th>HOSTNAME</th>
            <th>PORT</th>
            <th>CKTID</th>
        </tr>
    </thead>
    <tbody>
    {% for h in groups['all'] %}     
    {% for item in hostvars[h].output.parsed %}
        <tr>
        {% if 'CID' in item.DESCRIP %}
            <td>{{ h }}</td>
            <td>{{ item.PORT }}</td>
            <td>{{ item.DESCRIP }}</td>  
        {%elif 'ckid' in item.DESCRIP %}
            <td>{{ h }}</td>
            <td>{{ item.PORT }}</td>
            <td>{{ item.DESCRIP }}</td>               
        {% endif %}      
        </tr>      
    {% endfor %}
    {% endfor %}
    </tbody>
</table>

</body>
</html>