date: 2020-03-16title: ansible添加主机及when、loop使用 #标题
tags: ansible #标签
categories: ansible # 分类
add_host
[root@nginx ansible]# cat test.yaml---- name: add new host to test1 and test2hosts: test1gather_facts: falsetasks:- name: add new host to test1 and test2add_host: # 使用add_hosts模块name: 192.168.20.3 # 指定主机名或IPgroups: # groups用来指定要添加到哪个主机组- test1- test2ansible_port: 22my_var: "hello world"- name: ping test1 group in play1ping:- name: test new host in play2hosts: test1gather_facts: falsetasks:- name: ping test1 groupping:- name: test new host in play3hosts: test2gather_facts: falsetasks:- name: ping test2 groupping:
hosts文件中定义的主机列表如下:
[root@nginx ansible]# tail -2 hosts # 没有定义test2主机组和20.3的主机[test1]192.168.20.2
执行结果如下:

上面playbook的执行结果中,将会显示play2和play3中都出现新主机192.168.20.3,而在play1中的ping则不会出现192.168.20.3。
setup和gather_facts
setup和gather_facts模块用来收集客户端的主机信息,使用方法如下:
# ansible test1 -m gather_facts或者# ansible test1 -m setup
两者区别:
- setup最早提供,而gather_facts模块是在ansible 2.8才提供的,gather_facts很有可能内部封装的就是setup模块。
- gather_facts比setup模块多一个功能:并行收集多个节点信息,而且在探测到要收集多个节点信息时会自动并行。
默认执行playbook文件时,ansible都会自动执行gather_facts模块去收集节点信息,这会造成卡顿,可以取消执行收集信息的操作,如下:
[root@nginx ansible]# cat a.yml---- name: testhosts: test1gather_facts: false # 添加此配置,以取消收集客户端信息tasks:- name: testping:
但有些时候,我们必须要收集客户端的信息,并使用它,下面将写下如何使用它。
收集到的信息格式如下:

上面是直接在终端打印出来了,那么在playbook中访问的话,方法如下:
[root@nginx ansible]# cat b.yml---- name: testhosts: test1tasks:- name: test access variablesdebug:var: ansible_distribution
返回结果如下:

when条件判断
[root@nginx ansible]# cat a.yml---- name: testhosts: test1gather_facts: falsetasks:- debug:var: itemwhen: # when指定item大于3并小于5才为True。- item > 3- item < 5loop: [1,2,3,4,5,6,7] # loop是循环将值赋给上面的item
返回结果如下:

可以看到在执行时跳过了1,2,3,5,6,7,只执行了4,上面的playbook文件还可以这样写:
[root@nginx ansible]# cat a.yml---- name: testhosts: test1gather_facts: falsetasks:- debug:var: itemwhen: item > 3 and item < 5 # and是与,还有or是或with_items:- 1- 2- 3- 4- 5- 6- 7
when根据条件判断是否执行该任务
- name: "查看python3是否安装,忽略提示"shell: python3 #执行一条命令,将结果赋值给register定义的resultregister: resultignore_errors: True #忽略错误提示#拷贝Python-3.6.5- name: "copy Python3-6.5 to dest"copy: src=Python-3.6.5.tgz dest=/usr/local/src/Python-3.6.5.tgzwhen: result is failed #当result返回的是个错误的时候,执行此tasks#编译安装python3.6.5- name: "compile install"shell: pip install --upgrade supervisor requests;cd /usr/local/src/;tar zxf Python-3.6.5.tgz; cd Python-3.6.5;./configure --prefix=/usr/local/python3 --with-ssl;make;make installwhen: result is failed#软连接python3- name: "ln -s python3"file: src=/usr/local/python3/bin/python3 dest=/usr/bin/python3 state=linkwhen: result is failed
when和gather_facts结合使用
针对不同的操作系统加载不同的文件
我们想象这样一个场景:ansible管理了很多服务器,有不同的操作系统,然后在不同的系统版本上需要执行的任务不一样,比如要安装httpd服务,在redhat系统中包名为httpd,在debian系统中的包名为apache2。
对于这种因环境不同而配置不同任务的场景,通常是为不同环境定义不同的任务文件或者不同的变量文件,然后使用when的环境判断加载不同的文件到playbook文件中。
如下:
---- name: testhosts: test1gather_facts: truetasks:- include_tasks: CentOS.ymlwhen: ansible_distribution == "CentOS" # 当ansible_distribution的值为centos时,加载上面的文件- include_tasks: Debian.ymlwhen: ansible_distribution == "Debian" # 当ansible_distribution的值为debian时,加载上面的文件# 至于ansible_distribution的值,则是gather_facts收集到的客户端信息保存到内置变量中的
上面的playbook实现了针对不同的操作系统导入不同的文件,但是代码有冗余性,可以修改为下面这样:
[root@nginx ansible]# cat a.yml---- name: testhosts: test1gather_facts: truetasks:- include_tasks: "{{ansible_distribution}}.yml"
with循环指令
当when指令和循环指令一起使用时,when的判断操作在每轮循环内执行。
loop指令用于循环,在ansible 2.5加入的,官方推荐使用loop指令,而不是with_xxx,比如:with_list、with_dict、with_item等。
相对来说with_xxx更为直观一些,with和loop都能实现一样的功能。
with_list
with_list:迭代一个列表
[root@nginx ansible]# cat a.yml # 以下是在test1主机组上创建两个文件- name: testhosts: test1gather_facts: falsetasks:- file:name: "/tmp/{{item}}" # 这里使用item调用循环的文件名state: touchwith_list: # 这里定义的是文件名列表,若要使用loop指令来实现同样的功能,只需将with_list改为loop即可- "filename1"- "filename2"
with_items和with_flattened
with_list用于迭代简单的列表,但有时候列表中会嵌套列表。这时就需要使用with_items,with_items可以完全替代with_list,这里不过多解释,如用到嵌套列表,自行百度吧。
with_indexed_items
如果迭代列表时,还想要获取每个元素的索引位置,则可以使用with_indexed_items。
例如:
[root@nginx ansible]# cat a.yml- name: testhosts: test1gather_facts: falsevars:a: [b,[c,d],e]tasks:- debug:msg: "index: {{item.0}},value: {{item.1}}"with_indexed_items: "{{a}}"
执行结果如下:
ok: [192.168.20.2] => (item=[0, u'b']) => {"msg": "index: 0,value: b"}ok: [192.168.20.2] => (item=[1, u'c']) => {"msg": "index: 1,value: c"}ok: [192.168.20.2] => (item=[2, u'd']) => {"msg": "index: 2,value: d"}ok: [192.168.20.2] => (item=[3, u'e']) => {"msg": "index: 3,value: e"}
with_dict
with_dict 用于迭代一个字典结构,迭代时可以使用item.key表示每个字典元素中的key,item.value表示每个字典元素的value。
例如:
- name: testhosts: test1gather_facts: falsevars:users:ray_key:name: rayage: 18lvjianzhao_key:name: lvjianzhaoage: 25tasks:- debug:msg: "who: {{item.key}} &&name: {{item.value.name}} &&age: {{item.value.age}}"with_dict: "{{users}}"
执行结果如下:
ok: [192.168.20.2] => (item={'value': {u'age': 25, u'name': u'lvjianzhao'}, 'key': u'lvjianzhao_key'}) => {"msg": "who: lvjianzhao_key && name: lvjianzhao && age: 25"}ok: [192.168.20.2] => (item={'value': {u'age': 18, u'name': u'ray'}, 'key': u'ray_key'}) => {"msg": "who: ray_key && name: ray && age: 18"}
with_fileglob
with_fileglob用于迭代通配到的每个文件名。
例如:
[root@nginx ansible]# cat a.yml- name: testhosts: test1gather_facts: falsetasks:- copy:src: "{{item}}"dest: /tmp/with_fileglob: # 指定本地/etc目录下匹配到的文件- /etc/m*.conf- /etc/*.cnf
执行结果如下:
TASK [copy] *************************changed: [192.168.20.2] => (item=/etc/mke2fs.conf)changed: [192.168.20.2] => (item=/etc/mtools.conf)changed: [192.168.20.2] => (item=/etc/man_db.conf)changed: [192.168.20.2] => (item=/etc/my.cnf)
with_lines
with_lines用于迭代命令输出结果的每一行。
这个功能非常使用,比如find找出一堆文件,然后进行操作,比如copy。
例如:
[root@nginx ansible]# cat a.yml- name: testhosts: test1gather_facts: falsetasks:- copy:src: "{{item}}"dest: /tmp/with_lines:- find /etc/ -type f -name "a*.sh"
执行结果如下:
changed: [192.168.20.2] => (item=/etc/profile.d/abrt-console-notification.sh)changed: [192.168.20.2] => (item=/etc/dhcp/dhclient-exit-hooks.d/azure-cloud.sh)
循环和when
当with_xxx或loop和when指令一起使用时,when将在循环内部进行条件判断,也就是说,when决定每轮迭代时是否执行一个任务,而不是决定整个循环是否进行。
例如:
[root@nginx ansible]# cat a.yml- name: testhosts: test1gather_facts: falsetasks:- debug:var: itemloop: [1,2,3,4,5]when: item >= 3
上面的执行结果就是会输出3,4,5三个元素。
输出结果如下:
TASK [debug] *********************************************************************************skipping: [192.168.20.2] => (item=1)skipping: [192.168.20.2] => (item=2)ok: [192.168.20.2] => (item=3) => {"ansible_loop_var": "item","item": 3}ok: [192.168.20.2] => (item=4) => {"ansible_loop_var": "item","item": 4}ok: [192.168.20.2] => (item=5) => {"ansible_loop_var": "item","item": 5}
