一、条件判断
https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#the-when-statement
when
子句。 子句里的变量不需要 {{ }}。
1、基本格式
tasks:
- name: "shut down Debian flavored systems"
command: /sbin/shutdown -t now
when: ansible_facts['os_family'] == "Debian"
# note that all variables can be used directly in conditionals without double curly braces
只有在目标主机系统是Debian的时候才会执行。不符合条件会跳过。
TASK [shut down Debian flavored systems] **************************************************************************************************************************************
skipping: [172.100.102.92]
skipping: [172.100.102.93]
2、复杂条件
使用and,or与not逻辑符号。
and
, or
tasks:
- name: "shut down CentOS 6 and Debian 7 systems"
command: /sbin/shutdown -t now
when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or
(ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7")
还可以写成列表,各个列表项之间是and关系。
- name: "shut down CentOS 6 systems"
command: /sbin/shutdown -t now
when:
- ansible_facts['distribution'] == "CentOS"
- ansible_facts['distribution_major_version'] == "6"
就是
ansible_facts['distribution'] == "CentOS"
and ansible_facts['distribution_major_version'] == "6"
not
when: not (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6")
3、判断变量是否定义
is undefined
判断变量是否没有定义。这里的ansible_facts是facts变量,肯定是定义了的。
tasks:
- name: "shut down CentOS 6 systems"
command: echo 'hello world'
when: ansible_facts is undefined
is defined
判断变量是否定义了。
when: ansible_facts is defined
还有 is not
, 上面的 is undefined
也可以写成 is not defined
。
4、循环加判断
循环与判断一起, 则每次循环都会判断一次。
如:
- hosts: 172.100.102.90
tasks:
- name: test
debug: msg={{item}}
loop: [0, 2, 4, 6, 8, 10]
when: item > 5
TASK [test] *******************************************************************************************************************************************************************
skipping: [172.100.102.90] => (item=0)
skipping: [172.100.102.90] => (item=2)
skipping: [172.100.102.90] => (item=4)
ok: [172.100.102.90] => (item=6) => {
"msg": 6
}
ok: [172.100.102.90] => (item=8) => {
"msg": 8
}
ok: [172.100.102.90] => (item=10) => {
"msg": 10
}
二、循环
ansible 2.5添加了loop
子句,用来代替with_X
。
with_X
还可以使用, 但推荐使用 loop
。
with_list
可以完全替换成loop
。
with_items
的扁平化方面需要加过滤器
循环中产生的元素使用变量item
表示。
区别
下面直接传入列表数据跟调用一个包含列表的变量是一样的。
1、with_list
--> loop
with_list
:
tasks:
- name: test
debug: msg={{item}}
with_list:
- one
- two
- [4,5]
- {'a': 1, 'b': 2}
输出结果是这样:
TASK [test] *******************************************************************************************************************************************************************
ok: [172.100.102.90] => (item=one) => {
"msg": "one"
}
ok: [172.100.102.90] => (item=two) => {
"msg": "two"
}
ok: [172.100.102.90] => (item=[4, 5]) => {
"msg": [
4,
5
]
}
ok: [172.100.102.90] => (item={u'a': 1, u'b': 2}) => {
"msg": {
"a": 1,
"b": 2
}
}
可以完全替换成loop
, 输出结构一样。
tasks:
- name: test
debug: msg={{item}}
loop:
- one
- two
- [4,5]
- {'a': 1, 'b': 2}
4、with_items
--> loop
with_items
:
tasks:
- name: test
debug: msg={{item}}
with_items:
- one
- two
- [4,5]
- {'a': 1, 'b': 2}
输出结果:
TASK [test] *******************************************************************************************************************************************************************
ok: [172.100.102.90] => (item=one) => {
"msg": "one"
}
ok: [172.100.102.90] => (item=two) => {
"msg": "two"
}
ok: [172.100.102.90] => (item=4) => {
"msg": 4
}
ok: [172.100.102.90] => (item=5) => {
"msg": 5
}
ok: [172.100.102.90] => (item={u'a': 1, u'b': 2}) => {
"msg": {
"a": 1,
"b": 2
}
}
可以看到[4,5]给扁平化了,分别循环了4个5。
loop
本身没有这个功能,想要达到相同的效果只能在调用变量的时候给变量加个过滤器。
这样做的原因其实只是因为 原来的变量数据不能或是不好改。
因为需要用变量,所以需要修改一下:
- hosts: 172.100.102.90
vars:
vara: ['one', 'two', [4, 5], {'a': 1, 'b': 2}]
tasks:
- name: test
debug: msg={{item}}
with_items: "{{ vara }}"
执行结果跟上面一样。
修改成loop
:
- hosts: 172.100.102.90
vars:
vara: ['one', 'two', [4, 5], {'a': 1, 'b': 2}]
tasks:
- name: test
debug: msg={{item}}
loop: "{{ vara | flatten(1)}}"
结果一样。
上面只是说明两者的区别,以及如果要复用的话该怎么办。
最好的方式还是修改成符合loop
使用的数据。
例子
贴几个官方loop
的例子
1、遍历列表
- name: add several users
user:
name: "{{ item }}"
state: present
groups: "wheel"
loop:
- testuser1
- testuser2
循环添加用户testuser1, testuser2。 不使用循环的话相当于:
- name: add user testuser1
user:
name: "testuser1"
state: present
groups: "wheel"
- name: add user testuser2
user:
name: "testuser2"
state: present
groups: "wheel"
2、遍历哈希列表
添加用户,并且指定用户组。
- name: add several users
user:
name: "{{ item.name }}"
state: present
groups: "{{ item.groups }}"
loop:
- { name: 'testuser1', groups: 'wheel' }
- { name: 'testuser2', groups: 'root' }
3、遍历字典
要注意,上面两个例子,提供的数据都是列表。
所以循环就可以直接使用。
如果提供的数据狮子点,需要使用过滤器转换成列表。
比如:
- hosts: 172.100.102.90
vars:
vara: {'name': 'testuser1', 'gender': 'M', 'age': 29, 'ps': ''}
tasks:
- name: test
debug: msg={{item}}
loop: "{{ vara }}"
是会报错的:
TASK [test] *******************************************************************************************************************************************************************
fatal: [172.100.102.90]: FAILED! => {"msg": "Invalid data passed to 'loop', it requires a list, got this instead: {u'gender': u'M', u'age': 29, u'name': u'testuser1', u'ps': u''}. Hint: If you passed a list/dict of just one element, try adding wantlist=True to your lookup invocation or use q/query instead of lookup."}
无效的loop数据。需要提供list类型数据。
添加字典过滤器dict2items
。
- hosts: 172.100.102.90
vars:
vara: {'name': 'testuser1', 'gender': 'M', 'age': 29, 'ps': ''}
tasks:
- name: test
debug: msg={{item}}
loop: "{{ vara | dict2items }}"
TASK [test] *******************************************************************************************************************************************************************
ok: [172.100.102.90] => (item={'key': u'gender', 'value': u'M'}) => {
"msg": {
"key": "gender",
"value": "M"
}
}
ok: [172.100.102.90] => (item={'key': u'age', 'value': 29}) => {
"msg": {
"key": "age",
"value": 29
}
}
ok: [172.100.102.90] => (item={'key': u'name', 'value': u'testuser1'}) => {
"msg": {
"key": "name",
"value": "testuser1"
}
}
ok: [172.100.102.90] => (item={'key': u'ps', 'value': u''}) => {
"msg": {
"key": "ps",
"value": ""
}
}
可以看到,把每一组key,value都取出来了。
4、条件判断
根据上面的例子,添加用户name。
在循环的过程中,只有当key等于name的时候添加。
- hosts: 172.100.102.90
vars:
vara: {'name': 'testuser1', 'gender': 'M', 'age': 29, 'ps': ''}
tasks:
- name: test
user:
name: "{{ item.value }}"
state: present
loop: "{{ vara | dict2items }}"
when: item.key == "name"
执行结果:
TASK [test] *******************************************************************************************************************************************************************
skipping: [172.100.102.90] => (item={'key': u'gender', 'value': u'M'})
skipping: [172.100.102.90] => (item={'key': u'age', 'value': 29})
changed: [172.100.102.90] => (item={'key': u'name', 'value': u'testuser1'})
skipping: [172.100.102.90] => (item={'key': u'ps', 'value': u''})
只有key==name的执行了, 其他都跳过了。 我们只需要name来创建用户。
注册变量
循环中的注册变量与非循环产生的注册变量数据结构有点不同,循环中的注册变量包含每次循环产生的数据。
- shell: "echo {{ item }}"
loop:
- "one"
- "two"
register: echo
还有好多辅助的方法,如: 每次循环暂停一段时间, 限制输出, 循环进度 等等。
感觉暂时都用不到,有兴趣的话:
https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html
官方提供的with_X替换成loop的方法
with_list
with_list
直接由loop
代替。
- name: with_list
debug:
msg: "{{ item }}"
with_list:
- one
- two
- name: with_list -> loop
debug:
msg: "{{ item }}"
loop:
- one
- two
with_items
with_items
替换为loop
和flatten
过滤器。
- name: with_items
debug:
msg: "{{ item }}"
with_items: "{{ items }}"
- name: with_items -> loop
debug:
msg: "{{ item }}"
loop: "{{ items|flatten(levels=1) }}"
with_indexed_items
with_indexed_items
替换成 loop
和flatten
滤波器还有loop_control.index_var
。
- name: with_indexed_items
debug:
msg: "{{ item.0 }} - {{ item.1 }}"
with_indexed_items: "{{ items }}"
- name: with_indexed_items -> loop
debug:
msg: "{{ index }} - {{ item }}"
loop: "{{ items|flatten(levels=1) }}"
loop_control:
index_var: index
with_flattened
with_flattened
替换为loop
和flatten
过滤器。
- name: with_flattened
debug:
msg: "{{ item }}"
with_flattened: "{{ items }}"
- name: with_flattened -> loop
debug:
msg: "{{ item }}"
loop: "{{ items|flatten }}"
with_together
with_together
替换为loop
和zip
过滤器。
- name: with_together
debug:
msg: "{{ item.0 }} - {{ item.1 }}"
with_together:
- "{{ list_one }}"
- "{{ list_two }}"
- name: with_together -> loop
debug:
msg: "{{ item.0 }} - {{ item.1 }}"
loop: "{{ list_one|zip(list_two)|list }}"
with_dict
with_dict
替换成loop
和(dictsort
或dict2items
)过滤器。
- name: with_dict
debug:
msg: "{{ item.key }} - {{ item.value }}"
with_dict: "{{ dictionary }}"
- name: with_dict -> loop (option 1)
debug:
msg: "{{ item.key }} - {{ item.value }}"
loop: "{{ dictionary|dict2items }}"
- name: with_dict -> loop (option 2)
debug:
msg: "{{ item.0 }} - {{ item.1 }}"
loop: "{{ dictionary|dictsort }}"
with_sequence
with_sequence
替换为loop
和range
函数,并可能替换为format
过滤器。
- name: with_sequence
debug:
msg: "{{ item }}"
with_sequence: start=0 end=4 stride=2 format=testuser%02x
- name: with_sequence -> loop
debug:
msg: "{{ 'testuser%02x' | format(item) }}"
# range is exclusive of the end point
loop: "{{ range(0, 4 + 1, 2)|list }}"
with_subelements
with_subelements
替换为loop
和subelements
过滤器。
- name: with_subelements
debug:
msg: "{{ item.0.name }} - {{ item.1 }}"
with_subelements:
- "{{ users }}"
- mysql.hosts
- name: with_subelements -> loop
debug:
msg: "{{ item.0.name }} - {{ item.1 }}"
loop: "{{ users|subelements('mysql.hosts') }}"
with_nested / with_cartesian
with_nested
和with_cartesian
替换为loop
和product
过滤器。
- name: with_nested
debug:
msg: "{{ item.0 }} - {{ item.1 }}"
with_nested:
- "{{ list_one }}"
- "{{ list_two }}"
- name: with_nested -> loop
debug:
msg: "{{ item.0 }} - {{ item.1 }}"
loop: "{{ list_one|product(list_two)|list }}"
with_random_choice
with_random_choice
只需使用random
过滤器即可替换,而无需使用loop
。
- name: with_random_choice
debug:
msg: "{{ item }}"
with_random_choice: "{{ my_list }}"
- name: with_random_choice -> loop (No loop is needed here)
debug:
msg: "{{ my_list|random }}"
tags: random