Ansible中基于Jinja2按指定组从ini主机清单提取主机行生成ipset
Ansible Jinja2 按目标组过滤ini inventory内容的实现方案
优先推荐:基于Ansible内置变量的实现
如果你的目标组属于当前Ansible运行时已加载的inventory,完全不需要用file lookup读取原始ini文件、也不需要手动解析文本,直接复用Ansible内置的groups、hostvars变量即可,稳定性远高于手动解析:
{% for group_name in target_groups %} {% for host in groups[group_name] %} {% if hostvars[host].ipv4_public is defined %} add {{ ipset_name }} {{ hostvars[host].ipv4_public }} {% endif %} {% if hostvars[host].ansible_host is defined %} add {{ ipset_name }} {{ hostvars[host].ansible_host }} {% endif %} {% endfor %} {% endfor %}
适配说明
- 直接遍历用户传入的
target_groups列表,逐个读取对应组下的主机、主机变量,完全跳过无关组的内容 - 不受ini文件格式(行空格、注释、块分隔规则)影响,完全由Ansible官方的ini解析逻辑保证准确性
- 如果用户传入的
target_groups是逗号分隔的字符串,可先在模板内做转换:{% set target_groups = target_groups | split(',') %}
适配现有逻辑:手动解析外部ini inventory的实现
如果你需要处理的是独立于Ansible运行时的外部ini inventory文件(也就是你当前用file lookup读取的场景),只需要在现有遍历逻辑中新增「当前所属组」的状态跟踪,即可实现按组过滤:
核心逻辑
- 遍历每一行时先做预处理(去首尾空格、跳过空行/注释行)
- 遇到形如
[组名]的章节行时,更新当前跟踪的组名 - 遇到空行时重置当前组名,退出对应组的配置块
- 仅当当前组在目标组列表中时,才执行原有ipset规则生成逻辑
修改后的模板代码
{# 初始化状态变量 #} {% set current_group = '' %} {% set target_groups = target_groups | default([]) %} {# 目标组为逗号分隔字符串时先转列表 #} {% if target_groups is string %} {% set target_groups = target_groups | split(',') %} {% endif %} {% for raw_line in inventory.split('\n') %} {% set line = raw_line.strip() %} {# 跳过空行、注释行 #} {% if not line or line.startswith('#') %} {# 空行触发当前组状态重置 #} {% if not line %} {% set current_group = '' %} {% endif %} {% continue %} {% endif %} {# 匹配组章节行,更新当前组 #} {% if line.startswith('[') and line.endswith(']') %} {% set current_group = line[1:-1].strip() %} {% continue %} {% endif %} {# 仅处理目标组下的行 #} {% if current_group in target_groups %} {% if 'ipv4_public=' in line %} add {{ ipset_name }} {{ line | regex_search( '(?<=ipv4_public=).[^ ]*' ) | trim }} {% endif %} {% if 'ansible_host=' in line %} add {{ ipset_name }} {{ line | regex_search( '(?<=ansible_host=).[^ ]*' ) | trim }} {% endif %} {% endif %} {% endfor %}
可调整的适配点
- 如果你的ini组块没有用空行分隔,而是直接以下一个
[组名]开头,可删除空行重置current_group的逻辑,遇到下一个章节行时会自动覆盖当前组 - 如果主机行包含行内注释,可对正则提取到的内容做二次截断:
{{ line | regex_search(...) | split('#')[0] | trim }},避免把注释内容带入ipset规则 - 如果你的组名包含
]字符,可把组名提取的正则改为更通用的regex_search('(?<=\[).*(?=\])')
内容的提问来源于stack exchange,提问作者2tc
相关产品推荐
相关产品推荐

