当我使用此命令和额外变量执行 ansible playbook 时
ansible-playbook controller_config/windows_domain_names.yml -e "target_win_host=testserver.testdomain.com"
其中包含一项任务
- name: Find if the variable target_win_host is a list
debug:
msg: "{{ item }} is list data type"
loop: "{{ target_win_host}}"
when: target_win_host | type_debug == 'list'
我得到的错误是
“传递到“循环”的数据无效,它需要一个列表,改为:testserver.testdomain.com。提示:如果您传递了仅包含一个元素的列表/字典,请尝试将wantlist=True添加到您的查找调用中或使用q/查询而不是查找。”
我希望应该跳过上面的块,因为它不满足变量是列表并且它是标量(字符串)的条件。
我尝试了以下不同的条件
- name: Find if the variable target_win_host is a list
debug:
msg: "{{ item }} is list data type"
loop: "{{ target_win_host}}"
when: target_win_host is not string and target_win_host is iterable and target_win_host is sequence
但与上面相同的错误。
您的方法不起作用,因为对于给定的任务,首先评估
loop:
表达式,提取第一项,然后才评估 when:
条件(每次循环迭代一次)。
换句话说,为了您的工作方法,您需要以某种方式将条件嵌入到
loop:
表达式中,并使其结果为 0 长度列表。以下任务实现了该目标。
- name: Loop over target_win_host it is a list
debug:
msg: "{{ item }} is part of a list of hosts"
loop: "{{ target_win_host if target_win_host | type_debug == 'list' else [] }}"
同时,如果您希望对所有主机执行相同的任务,无论它们是作为列表还是作为单个主机字符串给出,这可能会更好:
- name: Loop over hosts in target_win_host whether it is a list or a single host string
debug:
msg: "{{ item }} was given as one the hosts"
loop: "{{ [target_win_host] | flatten }}"
这是测试这两个选项的完整剧本:
---
- name: Conditionnal and loops
hosts: localhost
gather_facts: false
vars:
# default value as a list. Override with extra vars
target_win_host:
- host1.example.com
- host2.example.com
tasks:
- name: Loop over target_win_host it is a list
debug:
msg: "{{ item }} is part of a list of hosts"
loop: "{{ target_win_host if target_win_host | type_debug == 'list' else [] }}"
- name: Loop over hosts in target_win_host whether it is a list or a single host string
debug:
msg: "{{ item }} was given as one of the hosts"
loop: "{{ [target_win_host] | flatten }}"
这给出了:
$ ansible-playbook test.yml
PLAY [Conditionnal and loops] *************************************************************************************************************************************************************************************
TASK [Loop over target_win_host it is a list] *********************************************************************************************************************************************************************
ok: [localhost] => (item=host1.example.com) => {
"msg": "host1.example.com is part of a list of hosts"
}
ok: [localhost] => (item=host2.example.com) => {
"msg": "host2.example.com is part of a list of hosts"
}
TASK [Loop over hosts in target_win_host whether it is a list or a single host string] *****************************************************************************************************************************
ok: [localhost] => (item=host1.example.com) => {
"msg": "host1.example.com was given as one of the hosts"
}
ok: [localhost] => (item=host2.example.com) => {
"msg": "host2.example.com was given as one of the hosts"
}
PLAY RECAP ********************************************************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
$ ansible-playbook test.yml -e target_win_host=a.single.host
PLAY [Conditionnal and loops] *************************************************************************************************************************************************************************************
TASK [Loop over target_win_host it is a list] *********************************************************************************************************************************************************************
skipping: [localhost]
TASK [Loop over hosts in target_win_host whether it is a list or a single host string] *****************************************************************************************************************************
ok: [localhost] => (item=a.single.host) => {
"msg": "a.single.host was given as one of the hosts"
}
PLAY RECAP ********************************************************************************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
创建一个开关。例如,
- debug:
msg: "{{ item }}"
loop: "{{ switch }}"
vars:
target: "{{ target_hosts | d([]) }}"
type: "{{ target | type_debug }}"
switch: |
{% filter from_yaml %}
{% if type == 'str' %}
{{ target | split(',') }}
{% elif type == 'list' %}
{{ target }}
{% elif type == 'dict' %}
{{ target.keys() }}
{% else %}
[]
{% endif %}
{% endfilter %}
target: "{{ target_hosts | d([]) }}"
shell> ansible-playbook pb.yml -e target_hosts=host1
给予
msg: host1
shell> ansible-playbook pb.yml -e target_hosts=host1,host2
给予
msg: host1
msg: host2
shell> cat target_hosts_list.yml
target_hosts:
- host1
- host2
该列表也按预期工作
shell> ansible-playbook pb.yml -e @target_hosts_list.yml
给出相同的结果
msg: host1
msg: host2
shell> cat target_hosts_dict.yml
target_hosts:
host1: whatever you want 1st
host2: whatever you want 2nd
这给出了相同的结果
shell> ansible-playbook pb.yml -e @target_hosts_dict.yml
用于测试的完整剧本示例
- hosts: localhost
tasks:
- debug:
var: target_hosts | d([]) | type_debug
- debug:
msg: "{{ item }}"
loop: "{{ switch }}"
vars:
target: "{{ target_hosts | d([]) }}"
type: "{{ target | type_debug }}"
switch: |
{% filter from_yaml %}
{% if type == 'str' %}
{{ target | split(',') }}
{% elif type == 'list' %}
{{ target }}
{% elif type == 'dict' %}
{{ target.keys() }}
{% else %}
[]
{% endif %}
{% endfilter %}