我正在尝试弄清楚是否有可能播放一个循环遍历一组配置/定义了特定主机变量的主机。
比如这是我的库存文件
controlplanes:
hosts:
host1.example.com:
workers:
hosts:
host2.example.com:
longhorn:
storage: true
host3.example.com:
longhorn:
storage: true
基本上我的目标是从一台主机运行
kubectl label
命令以将注释应用于特定的 kubernetes 节点,但我只想让命令针对特定的主机列表运行,例如有longhorn.storage=true
的主机,所以在上面的例子中,我应该只循环遍历2个主机。
这可能吗?我知道我可以遍历所有主机,但我似乎无法访问任何给定主机的变量,我想
hostvars[hostname].longhorn.storage
可能会给我访问权限,但结果似乎表明它没有定义,所以我认为我的方法是不正确的。
- name: Loop Test
hosts: controlplanes
tasks:
- debug:
msg: "{{ item }}"
loop:
- "{{ groups['all'] }}"
add_host:
与现有的清单主机,然后将“新”主机分配给组,以及添加您希望的任何其他主机变量
给定清单
[controlplane]
alpha ansible_host=127.0.0.5
[workers]
beta ansible_host=127.0.0.6
charlie ansible_host=127.0.0.7
[workers:vars]
longhorn=true
然后剧本:
- hosts: all
tasks:
- delegate_to: localhost
run_once: true
add_host:
name: '{{ item }}'
groups:
- longer
have_longhorn: true
loop: '{{ long_hosts | from_yaml }}'
vars:
# this nonsense is because jinja2 does not have list comprehensions
long_hosts: |
{% for hn in groups["all"] if 'longhorn' in hostvars[hn] %}
- {{ hn }}
{% endfor -%}
- hosts: longer
tasks:
- debug:
msg: |
{{ inventory_hostname }} ({{ ansible_host }}) have_long={{ have_longhorn }}
long={{ longhorn }}
我以为
可能会给我访问权限,但结果似乎表明它没有定义。hostvars[hostname].longhorn.storage
它仅针对清单中存在 var 的主机定义。例如,对于您的
controlplanes
,它是未定义的。因此,调用该 var 的正确方法是使用 default
过滤器(别名 d
)以确保您始终获得一个值,例如:
when: hostvars[hostname].longhorn.storage | d(false) | bool
bool
过滤器 来保护结果,以防 var 被解析为清单中的字符串。
constructed
动态库存 的完美候选。
示例文件结构:
$ tree
.
├── dummy_playbook.yml
└── inventories
└── demo
├── 01-hosts.yml
└── 02-longhorn_group-constructed.yml
为了这个例子的需要,我稍微修改了你的初始库存。这是
inventories/demo/01-hosts.yml
的内容
---
controlplanes:
hosts:
host1.example.com:
workers:
hosts:
host2.example.com:
longhorn:
storage: true
# Example to show it does not break if var isn't defined
host3.example.com:
host4.example.com:
longhorn:
storage: true
host5.example.com:
longhorn:
storage: false
魔法发生在
inventories/demo/02-longhorn_group-constructed.yml
。我们根据之前的静态库存文件中的变量值创建一个动态组:
---
plugin: ansible.builtin.constructed
strict: False
groups:
longhorn_storage: longhorn.storage | d(false) | bool
然后我们可以使用
dummy_playbook.yml
快速测试它:
---
- name: Run a task from controlplane for each host having longhorn storage
hosts: controlplanes
gather_facts: false
tasks:
- name: Dummy demo tasks
ansible.builtin.debug:
msg:
- I'm running from {{ inventory_hostname }}
- I would do something for target {{ item }}
loop: "{{ groups.longhorn_storage }}"
测试剧本结果:
$ ansible-playbook -i inventories/demo/ dummy_playbook.yml
PLAY [Run a task from controlplane for each host having longhorn storage] *****************************************************************************************************************************************************
TASK [Dummy demo tasks] *******************************************************************************************************************************************************************************************************
ok: [host1.example.com] => (item=host2.example.com) => {
"msg": [
"I'm running from host1.example.com",
"I would do something for target host2.example.com"
]
}
ok: [host1.example.com] => (item=host4.example.com) => {
"msg": [
"I'm running from host1.example.com",
"I would do something for target host4.example.com"
]
}
PLAY RECAP ********************************************************************************************************************************************************************************************************************
host1.example.com : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
另一种检查库存是否按预期解析的方法是简单地使用命令列出其内容
ansible-inventory -i inventories/demo/ --list
给出:
{
"_meta": {
"hostvars": {
"host2.example.com": {
"longhorn": {
"storage": true
}
},
"host4.example.com": {
"longhorn": {
"storage": true
}
},
"host5.example.com": {
"longhorn": {
"storage": false
}
}
}
},
"all": {
"children": [
"ungrouped",
"controlplanes",
"workers",
"longhorn_storage"
]
},
"controlplanes": {
"hosts": [
"host1.example.com"
]
},
"longhorn_storage": {
"hosts": [
"host2.example.com",
"host4.example.com"
]
},
"workers": {
"hosts": [
"host2.example.com",
"host3.example.com",
"host4.example.com",
"host5.example.com"
]
}
}
在第一场比赛中创建列表longhorn_group
- hosts: all
tasks:
- set_fact:
longhorn_storage: "{{ longhorn.storage|d(false) }}"
- set_fact:
longhorn_group: "{{ hostvars|dict2items|
selectattr('value.longhorn_storage')|
map(attribute='key') }}"
run_once: true
并在第二场比赛中使用它
- hosts: controlplanes
tasks:
- debug:
var: longhorn_group
- debug:
msg: "{{ item }}"
loop: "{{ longhorn_group }}"
给(删节)
TASK [debug] *********************************************************************************
ok: [host1.example.com] =>
longhorn_group:
- host2.example.com
- host3.example.com
TASK [debug] *********************************************************************************
ok: [host1.example.com] => (item=host2.example.com) =>
msg: host2.example.com
ok: [host1.example.com] => (item=host3.example.com) =>
msg: host3.example.com
完整的测试剧本示例
- hosts: all
tasks:
- set_fact:
longhorn_storage: "{{ longhorn.storage|d(false) }}"
- set_fact:
longhorn_group: "{{ hostvars|dict2items|
selectattr('value.longhorn_storage')|
map(attribute='key') }}"
run_once: true
- hosts: controlplanes
tasks:
- debug:
var: longhorn_group
- debug:
msg: "{{ item }}"
loop: "{{ longhorn_group }}"