如何循环遍历接口事实

如何循环遍历接口事实

ansible 的设置模块提供了 ansible_interfaces

"ansible_interfaces": [
    "lo", 
    "eth0",
    "eth1"
], 

根据界面,以下是一些事实:

"ansible_eth0": {
    "active": true, 
    "device": "eth0", 
    "ipv4": {
        "address": "192.168.10.2", 
        "broadcast": "192.168.10.255", 
        "netmask": "255.255.255.0", 
        "network": "192.168.10.0"
    },
    "macaddress": "52:54:00:5c:c1:36", 
    "module": "virtio_net", 
    "mtu": 1500, 
    "pciid": "virtio0", 
    "promisc": false, 
    "type": "ether"
}

如何使用 ansible_interfaces 事实来循环遍历可用的接口?

  tasks:
    - name: find interface facts
      debug: msg=ansible_{{ item }}
      with_items: "{{ ansible_interfaces }}"

这显然不起作用,因为它打印出字符串 ansible_lo、ansible_eth0 和 ansible_eth1,但我希望它打印来自这些接口的事实。一些服务器有其他接口,如网桥,所以我事先不知道要使用哪个接口。

ps 这个例子不是很有用,但最终我想用它在 elasticsearch 中存储诸如 macaddresses 之类的事实,以便于搜索哪个服务器具有哪个 macaddress。

答案1

您遇到了 Jinja/Ansible 模板的一个限制,即无法评估表达式,而这是获得类似 的值所必需的ansible_{{ item }}。您只能使用字符串。

幸运的是,有一个全局hostvars对象,您可以通过键访问所有事实,即......一个字符串。

按照下面的思路应该可以帮你实现这个目标:

tasks:
  - name: find interface facts
    debug:
      msg: "{{ hostvars[inventory_hostname]['ansible_%s' | format(item)] }}"
    with_items: "{{ ansible_interfaces }}"

答案2

你确实可以做到这一点。你只需要非常了解 j2 语法,搜索一下,然后结合一些技巧。哎呀。刚刚浪费了 2 个小时。希望我能把它保存给别人!

像这样是可行的:

    - name: Display all interfaces
  debug:
    msg: "{{ msg.split('\n') }}"
  vars:
    msg: |
        {% for iface in ansible_interfaces|sort %}
            System interface {{ iface }}
            {{ vars.ansible_facts[iface] | to_nice_json }}
        {% endfor %}

正如我所怀疑的,寻求这样做的人想要计算下一个免费界面(我所追求的)。

我这样做了:

    - name: calc next free interface
      set_fact:
        nextFreeIf: "{% set ifacePrefix = vars.ansible_default_ipv4.alias %}{% set ifaceNum = { 'cnt': 0 } %}{% macro increment(dct, key, inc=1)%}{% if dct.update({key: dct[key] + inc}) %} {% endif %}{% endmacro %}{% for iface in ansible_interfaces|sort %}{% if iface| regex_search('^' ~ vars.ansible_default_ipv4.alias) %}{{ increment(ifaceNum, 'cnt') }}{% endif %}{% endfor %}{{ifacePrefix}}:{{ifaceNum.cnt}}"

nextFreeIf 位于一行,因为,否则您会得到空白,并且修剪起来很麻烦。这很丑陋,但是,嘿,它可以工作。

真心希望能节省一些人的时间。干杯。

答案3

对我来说,代码很好添加:

    msg: "{{ hostvars[inventory_hostname]['ansible_%s' | format(item) | regex_replace('-', '_'')] }}"

到 udondan 的代码。

答案4

我在 Ansible [核心 2.11.6] 中这样做:

我所担任的角色有defaults/main.yml

netbox_url: https://something.internal/
netbox_token: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          BLABLABLABLABLABLABLABLABLA

speed_to_iftype:
  1000: "1000BASE-T (1GE)"
  10000: "SFP+ (10GE)"
  20000: "Link Aggregation Group (LAG)"

以及角色的tasks/main.yml

- name: Create interfaces
  delegate_to: localhost
  when: ansible_facts[item].speed is defined and not 'lo' == item
  netbox.netbox.netbox_device_interface:
    netbox_url: "{{ netbox_url }}"
    netbox_token: "{{ netbox_token }}"
    data:
      device: "{{ inventory_hostname }}"
      name: "{{ item }}"
      type: "{{ speed_to_iftype[ ansible_facts[item].speed ] }}"
    state: present
  loop: "{{ ansible_interfaces }}"

- name: Create IP address
  delegate_to: localhost
  when: ansible_facts[item].ipv4.address is defined and not 'lo' == item
  netbox.netbox.netbox_ip_address:
    netbox_url: "{{ netbox_url }}"
    netbox_token: "{{ netbox_token }}"
    data:
      address: "{{ ansible_facts[item].ipv4.address }}/{{ vars.ansible_facts[item].ipv4.netmask }}"
      status: Active
      dns_name: "{{ lookup('community.general.dig', ansible_facts[item].ipv4.address+'/PTR', '@ns.our.internal') | regex_replace('\\.$', '') }}"
      assigned_object:
        name: "{{ item }}"
        device: "{{ inventory_hostname }}"
    state: present
  loop: "{{ ansible_interfaces }}"

相关内容