date: 2020-03-16title: ansible添加主机及when、loop使用 #标题
tags: ansible #标签
categories: ansible # 分类

ansible总结笔记

add_host

  1. [root@nginx ansible]# cat test.yaml
  2. ---
  3. - name: add new host to test1 and test2
  4. hosts: test1
  5. gather_facts: false
  6. tasks:
  7. - name: add new host to test1 and test2
  8. add_host: # 使用add_hosts模块
  9. name: 192.168.20.3 # 指定主机名或IP
  10. groups: # groups用来指定要添加到哪个主机组
  11. - test1
  12. - test2
  13. ansible_port: 22
  14. my_var: "hello world"
  15. - name: ping test1 group in play1
  16. ping:
  17. - name: test new host in play2
  18. hosts: test1
  19. gather_facts: false
  20. tasks:
  21. - name: ping test1 group
  22. ping:
  23. - name: test new host in play3
  24. hosts: test2
  25. gather_facts: false
  26. tasks:
  27. - name: ping test2 group
  28. ping:

hosts文件中定义的主机列表如下:

  1. [root@nginx ansible]# tail -2 hosts # 没有定义test2主机组和20.3的主机
  2. [test1]
  3. 192.168.20.2

执行结果如下:
ansible添加主机及when、loop使用 - 图1

上面playbook的执行结果中,将会显示play2和play3中都出现新主机192.168.20.3,而在play1中的ping则不会出现192.168.20.3。

setup和gather_facts

setup和gather_facts模块用来收集客户端的主机信息,使用方法如下:

  1. # ansible test1 -m gather_facts
  2. 或者
  3. # ansible test1 -m setup

两者区别:

  • setup最早提供,而gather_facts模块是在ansible 2.8才提供的,gather_facts很有可能内部封装的就是setup模块。
  • gather_facts比setup模块多一个功能:并行收集多个节点信息,而且在探测到要收集多个节点信息时会自动并行。

默认执行playbook文件时,ansible都会自动执行gather_facts模块去收集节点信息,这会造成卡顿,可以取消执行收集信息的操作,如下:

  1. [root@nginx ansible]# cat a.yml
  2. ---
  3. - name: test
  4. hosts: test1
  5. gather_facts: false # 添加此配置,以取消收集客户端信息
  6. tasks:
  7. - name: test
  8. ping:

但有些时候,我们必须要收集客户端的信息,并使用它,下面将写下如何使用它。

收集到的信息格式如下:

ansible添加主机及when、loop使用 - 图2

上面是直接在终端打印出来了,那么在playbook中访问的话,方法如下:

  1. [root@nginx ansible]# cat b.yml
  2. ---
  3. - name: test
  4. hosts: test1
  5. tasks:
  6. - name: test access variables
  7. debug:
  8. var: ansible_distribution

返回结果如下:
ansible添加主机及when、loop使用 - 图3

when条件判断

  1. [root@nginx ansible]# cat a.yml
  2. ---
  3. - name: test
  4. hosts: test1
  5. gather_facts: false
  6. tasks:
  7. - debug:
  8. var: item
  9. when: # when指定item大于3并小于5才为True。
  10. - item > 3
  11. - item < 5
  12. loop: [1,2,3,4,5,6,7] # loop是循环将值赋给上面的item

返回结果如下:

ansible添加主机及when、loop使用 - 图4

可以看到在执行时跳过了1,2,3,5,6,7,只执行了4,上面的playbook文件还可以这样写:

  1. [root@nginx ansible]# cat a.yml
  2. ---
  3. - name: test
  4. hosts: test1
  5. gather_facts: false
  6. tasks:
  7. - debug:
  8. var: item
  9. when: item > 3 and item < 5 # and是与,还有or是或
  10. with_items:
  11. - 1
  12. - 2
  13. - 3
  14. - 4
  15. - 5
  16. - 6
  17. - 7

when根据条件判断是否执行该任务

  1. - name: "查看python3是否安装,忽略提示"
  2. shell: python3 #执行一条命令,将结果赋值给register定义的result
  3. register: result
  4. ignore_errors: True #忽略错误提示
  5. #拷贝Python-3.6.5
  6. - name: "copy Python3-6.5 to dest"
  7. copy: src=Python-3.6.5.tgz dest=/usr/local/src/Python-3.6.5.tgz
  8. when: result is failed #当result返回的是个错误的时候,执行此tasks
  9. #编译安装python3.6.5
  10. - name: "compile install"
  11. 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 install
  12. when: result is failed
  13. #软连接python3
  14. - name: "ln -s python3"
  15. file: src=/usr/local/python3/bin/python3 dest=/usr/bin/python3 state=link
  16. when: result is failed

when和gather_facts结合使用

针对不同的操作系统加载不同的文件

我们想象这样一个场景:ansible管理了很多服务器,有不同的操作系统,然后在不同的系统版本上需要执行的任务不一样,比如要安装httpd服务,在redhat系统中包名为httpd,在debian系统中的包名为apache2。

对于这种因环境不同而配置不同任务的场景,通常是为不同环境定义不同的任务文件或者不同的变量文件,然后使用when的环境判断加载不同的文件到playbook文件中。

如下:

  1. ---
  2. - name: test
  3. hosts: test1
  4. gather_facts: true
  5. tasks:
  6. - include_tasks: CentOS.yml
  7. when: ansible_distribution == "CentOS" # 当ansible_distribution的值为centos时,加载上面的文件
  8. - include_tasks: Debian.yml
  9. when: ansible_distribution == "Debian" # 当ansible_distribution的值为debian时,加载上面的文件
  10. # 至于ansible_distribution的值,则是gather_facts收集到的客户端信息保存到内置变量中的

上面的playbook实现了针对不同的操作系统导入不同的文件,但是代码有冗余性,可以修改为下面这样:

  1. [root@nginx ansible]# cat a.yml
  2. ---
  3. - name: test
  4. hosts: test1
  5. gather_facts: true
  6. tasks:
  7. - 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:迭代一个列表

  1. [root@nginx ansible]# cat a.yml # 以下是在test1主机组上创建两个文件
  2. - name: test
  3. hosts: test1
  4. gather_facts: false
  5. tasks:
  6. - file:
  7. name: "/tmp/{{item}}" # 这里使用item调用循环的文件名
  8. state: touch
  9. with_list: # 这里定义的是文件名列表,若要使用loop指令来实现同样的功能,只需将with_list改为loop即可
  10. - "filename1"
  11. - "filename2"

with_items和with_flattened

with_list用于迭代简单的列表,但有时候列表中会嵌套列表。这时就需要使用with_items,with_items可以完全替代with_list,这里不过多解释,如用到嵌套列表,自行百度吧。

with_indexed_items

如果迭代列表时,还想要获取每个元素的索引位置,则可以使用with_indexed_items

例如:

  1. [root@nginx ansible]# cat a.yml
  2. - name: test
  3. hosts: test1
  4. gather_facts: false
  5. vars:
  6. a: [b,[c,d],e]
  7. tasks:
  8. - debug:
  9. msg: "index: {{item.0}},value: {{item.1}}"
  10. with_indexed_items: "{{a}}"

执行结果如下:

  1. ok: [192.168.20.2] => (item=[0, u'b']) => {
  2. "msg": "index: 0,value: b"
  3. }
  4. ok: [192.168.20.2] => (item=[1, u'c']) => {
  5. "msg": "index: 1,value: c"
  6. }
  7. ok: [192.168.20.2] => (item=[2, u'd']) => {
  8. "msg": "index: 2,value: d"
  9. }
  10. ok: [192.168.20.2] => (item=[3, u'e']) => {
  11. "msg": "index: 3,value: e"
  12. }

with_dict

with_dict 用于迭代一个字典结构,迭代时可以使用item.key表示每个字典元素中的key,item.value表示每个字典元素的value。

例如:

  1. - name: test
  2. hosts: test1
  3. gather_facts: false
  4. vars:
  5. users:
  6. ray_key:
  7. name: ray
  8. age: 18
  9. lvjianzhao_key:
  10. name: lvjianzhao
  11. age: 25
  12. tasks:
  13. - debug:
  14. msg: "who: {{item.key}} &&
  15. name: {{item.value.name}} &&
  16. age: {{item.value.age}}"
  17. with_dict: "{{users}}"

执行结果如下:

  1. ok: [192.168.20.2] => (item={'value': {u'age': 25, u'name': u'lvjianzhao'}, 'key': u'lvjianzhao_key'}) => {
  2. "msg": "who: lvjianzhao_key && name: lvjianzhao && age: 25"
  3. }
  4. ok: [192.168.20.2] => (item={'value': {u'age': 18, u'name': u'ray'}, 'key': u'ray_key'}) => {
  5. "msg": "who: ray_key && name: ray && age: 18"
  6. }

with_fileglob

with_fileglob用于迭代通配到的每个文件名。

例如:

  1. [root@nginx ansible]# cat a.yml
  2. - name: test
  3. hosts: test1
  4. gather_facts: false
  5. tasks:
  6. - copy:
  7. src: "{{item}}"
  8. dest: /tmp/
  9. with_fileglob: # 指定本地/etc目录下匹配到的文件
  10. - /etc/m*.conf
  11. - /etc/*.cnf

执行结果如下:

  1. TASK [copy] *************************
  2. changed: [192.168.20.2] => (item=/etc/mke2fs.conf)
  3. changed: [192.168.20.2] => (item=/etc/mtools.conf)
  4. changed: [192.168.20.2] => (item=/etc/man_db.conf)
  5. changed: [192.168.20.2] => (item=/etc/my.cnf)

with_lines

with_lines用于迭代命令输出结果的每一行。

这个功能非常使用,比如find找出一堆文件,然后进行操作,比如copy。

例如:

  1. [root@nginx ansible]# cat a.yml
  2. - name: test
  3. hosts: test1
  4. gather_facts: false
  5. tasks:
  6. - copy:
  7. src: "{{item}}"
  8. dest: /tmp/
  9. with_lines:
  10. - find /etc/ -type f -name "a*.sh"

执行结果如下:

  1. changed: [192.168.20.2] => (item=/etc/profile.d/abrt-console-notification.sh)
  2. changed: [192.168.20.2] => (item=/etc/dhcp/dhclient-exit-hooks.d/azure-cloud.sh)

循环和when

当with_xxx或loop和when指令一起使用时,when将在循环内部进行条件判断,也就是说,when决定每轮迭代时是否执行一个任务,而不是决定整个循环是否进行。

例如:

  1. [root@nginx ansible]# cat a.yml
  2. - name: test
  3. hosts: test1
  4. gather_facts: false
  5. tasks:
  6. - debug:
  7. var: item
  8. loop: [1,2,3,4,5]
  9. when: item >= 3

上面的执行结果就是会输出3,4,5三个元素。

输出结果如下:

  1. TASK [debug] *********************************************************************************
  2. skipping: [192.168.20.2] => (item=1)
  3. skipping: [192.168.20.2] => (item=2)
  4. ok: [192.168.20.2] => (item=3) => {
  5. "ansible_loop_var": "item",
  6. "item": 3
  7. }
  8. ok: [192.168.20.2] => (item=4) => {
  9. "ansible_loop_var": "item",
  10. "item": 4
  11. }
  12. ok: [192.168.20.2] => (item=5) => {
  13. "ansible_loop_var": "item",
  14. "item": 5
  15. }