简介
我们在编写playbook的时候,不可避免的要执行一些重复性操作,比如指安装软件包,批量创建用户,操作某个目录下的所有文件等。正如我们所说,ansible一门简单的自动化语言,所以流程控制、循环语句这些编程语言的基本元素它同样都具备。
旧循环语句(版本在2.5之前仅有的)
在Ansible 2.5以前,playbook通过不同的循环语句以实现不同的循环,这些语句使用with_
作为前缀。这些语法目前仍然兼容,但在未来的某个时间点,会逐步废弃。
循环语句关键字 描述
with_items 简单的列表循环
with_nested 嵌套循环
with_dict 循环字典
with_fileglob 循环指定目录中的所有文件
with_lines 循环一个文件中的所有行
with_sequence 生成一个自增的整数序列,可以指定起始值和结束值以及步长。参数以key=value的形式指定,format指定输出的格式。数字可以是十进制、十六进制、八进制
with_subelement 遍历子元素
with_together 遍历数据并行集合
with_items
自定义with_list循环列表
小练习:在受管主机中创建4个文件
在没有学会循环之前,我们会这样写
---
- hosts: test70
remote_user: root
gather_facts: no
tasks:
- file:
path: "/opt/a"
state: touch
- file:
path: "/opt/b"
state: touch
- file:
path: "/opt/c"
state: touch
- file:
path: "/opt/d"
state: touch
在使用循环之后,我们这样写
借助注册函数,多次执行循环中的不同命令
for循环实现遍历
---
- hosts: test70
gather_facts: no
tasks:
- shell: "{{item}}"
with_items:
- "ls /opt"
- "ls /home"
register: returnvalue
- debug:
msg:
"{% for i in returnvalue.results %}
{{ i.stdout }}
{% endfor %}"
嵌套列表的定义
(将使用with_items的两种语法结合)
with_list关键字
with_flattened关键字
上述三种关键字的区别
with_together关键字
with_cartesian关键字
1.我们可以这样
mkdir -p {a,b,c}/{test1,test2}
2.
with_indexed_items关键字
单层列表时
---
- hosts: test70
remote_user: root
gather_facts: no
tasks:
- debug:
msg: "index is : {{ item.0 }} , value is {{ item.1 }}"
with_indexed_items:
- test1
- test2
- test3
执行结果如下:
TASK [debug] **********************************
ok: [test70] => (item=(0, u'test1')) => {
"changed": false,
"item": [
0,
"test1"
],
"msg": [
0,
"test1"
]
}
ok: [test70] => (item=(1, u'test2')) => {
"changed": false,
"item": [
1,
"test2"
],
"msg": [
1,
"test2"
]
}
ok: [test70] => (item=(2, u'test3')) => {
"changed": false,
"item": [
2,
"test3"
],
"msg": [
2,
"test3"
]
}
两层列表嵌套时
---
- hosts: testA
remote_user: root
gather_facts: no
tasks:
- debug:
msg: "index is : {{ item.0 }} , value is {{ item.1 }}"
with_indexed_items:
- [ test1, test2 ]
- [ test3, test4, test5 ]
- [ test6, test7 ]
执行结果:
TASK [debug] *****************************
ok: [test70] => (item=(0, u'test1')) => {
"changed": false,
"item": [
0,
"test1"
],
"msg": "index is : 0 , value is test1"
}
ok: [test70] => (item=(1, u'test2')) => {
"changed": false,
"item": [
1,
"test2"
],
"msg": "index is : 1 , value is test2"
}
ok: [test70] => (item=(2, u'test3')) => {
"changed": false,
"item": [
2,
"test3"
],
"msg": "index is : 2 , value is test3"
}
ok: [test70] => (item=(3, u'test4')) => {
"changed": false,
"item": [
3,
"test4"
],
"msg": "index is : 3 , value is test4"
}
ok: [test70] => (item=(4, u'test5')) => {
"changed": false,
"item": [
4,
"test5"
],
"msg": "index is : 4 , value is test5"
}
ok: [test70] => (item=(5, u'test6')) => {
"changed": false,
"item": [
5,
"test6"
],
"msg": "index is : 5 , value is test6"
}
ok: [test70] => (item=(6, u'test7')) => {
"changed": false,
"item": [
6,
"test7"
],
"msg": "index is : 6 , value is test7"
}
多层列表嵌套时
TASK [debug] ********************************
ok: [test70] => (item=(0, u'test1')) => {
"changed": false,
"item": [
0,
"test1"
],
"msg": [
0,
"test1"
]
}
ok: [test70] => (item=(1, u'test2')) => {
"changed": false,
"item": [
1,
"test2"
],
"msg": [
1,
"test2"
]
}
ok: [test70] => (item=(2, u'test3')) => {
"changed": false,
"item": [
2,
"test3"
],
"msg": [
2,
"test3"
]
}
ok: [test70] => (item=(3, [u'test4', u'test5'])) => {
"changed": false,
"item": [
3,
[
"test4",
"test5"
]
],
"msg": [
3,
[
"test4",
"test5"
]
]
}
ok: [test70] => (item=(4, u'test6')) => {
"changed": false,
"item": [
4,
"test6"
],
"msg": [
4,
"test6"
]
}
with_sequence关键字
更简单的count
2.3.
---
- hosts: test70
remote_user: root
gather_facts: no
tasks:
- debug:
msg: "{{item}}"
with_sequence: start=2 end=6 stride=2 format="number is %0.2f"
TASK [debug] ***************************
ok: [test70] => (item=number is 2.00) => {
"changed": false,
"item": "number is 2.00",
"msg": "number is 2.00"
}
ok: [test70] => (item=number is 4.00) => {
"changed": false,
"item": "number is 4.00",
"msg": "number is 4.00"
}
ok: [test70] => (item=number is 6.00) => {
"changed": false,
"item": "number is 6.00",
"msg": "number is 6.00"
}
with_random_choice关键字
with_dict关键字
字典的嵌套
2.
with_subelements关键字
with_file关键字
with_fileglob关键字
2.
lookup插件
lookup(查找; 查表)
lookup插件之file插件
- debug:
msg: "{{ lookup('file','/testdir/testfile',wantlist=true) }}"
- debug:
msg: "{{ query('file','/testdir/testfile') }}"
- debug:
msg: "{{ lookup('file','/testdir/testfil',errors='ignore') }}"
lookup插件的其他用法
---
- hosts: testA
remote_user: root
gather_facts: no
tasks:
#file插件可以获取ansible主机中指定文件的内容
- debug:
msg: "{{ lookup('file','/testdir/testfile') }}"
#env插件可以获取ansible主机中指定变量的值
- debug:
msg: "{{ lookup('env','PATH') }}"
#first_found插件可以获取列表中第一个找到的文件
#按照列表顺序在ansible主机中查找
- debug:
msg: "{{ lookup('first_found',looklist) }}"
vars:
looklist:
- /testdir
- /tmp/staging
#当使用with_first_found时,可以在列表的最后添加- skip: true
#表示如果列表中的所有文件都没有找到,则跳过当前任务,不会报错
#当不确定有文件能够被匹配到时,推荐这种方式
- debug:
msg: "{{item}}"
with_first_found:
- /testdir1
- /tmp/staging
- skip: true
#ini插件可以在ansible主机中的ini文件中查找对应key的值
#如下示例表示从test.ini文件中的testA段落中查找testa1对应的值
#测试文件/testdir/test.ini的内容如下(不包含注释符#号)
#[testA]
#testa1=Andy
#testa2=Armand
#
#[testB]
#testb1=Ben
- debug:
msg: "{{ lookup('ini','testa1 section=testA file=/testdir/test.ini') }}"
#当未找到对应key时,默认返回空字符串,如果想要指定返回值,可以使用default选项,如下
#msg: "{{ lookup('ini','test666 section=testA file=/testdir/test.ini default=notfound') }}"
#可以使用正则表达式匹配对应的键名,需要设置re=true,表示开启正则支持,如下
#msg: "{{ lookup('ini','testa[12] section=testA file=/testdir/test.ini re=true') }}"
#ini插件除了可以从ini类型的文件中查找对应key,也可以从properties类型的文件中查找key
#默认在操作的文件类型为ini,可以使用type指定properties类型,如下例所示
#如下示例中,application.properties文件内容如下(不包含注释符#号)
#http.port=8080
#redis.no=0
#imageCode = 1,2,3
- debug:
msg: "{{ lookup('ini','http.port type=properties file=/testdir/application.properties') }}"
#dig插件可以获取指定域名的IP地址
#此插件依赖dnspython库,可使用pip安装pip install dnspython
#如果域名使用了CDN,可能返回多个地址
- debug:
msg: "{{ lookup('dig','www.baidu.com',wantlist=true) }}"
#password插件可以生成随机的密码并保存在指定文件中
- debug:
msg: "{{ lookup('password','/tmp/testpasswdfile') }}"