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 }}"