Bootstrap

ansible-playbook循环(loop)

一.简述:

  在使用ansible做配置管理工作中,经常会遇到很多的task都需要重复的引用某一个模块比如:一次同步N个文件,创建N个用户等,按照之前的文档来看就需要写N个task,尽管功能可以实现,但代码量会非常大/臃肿。对于这种情况,ansible是可以通过循环(loop)方式处理。

二.使用方式:

 1. 标准loops(with_items):

       应用环境比较常见,如同时copy 操作主机的aaaa和bbbb文件到被操作主机上:

---
- hosts: test

  tasks:
      - name: test
        copy: src=/tmp/{{ item }} dest=/tmp/{{ item }}
        with_items:         #也可以直接写成- ['aaaa', 'bbbb']
            - aaaa          #同样,也支持变量(with_items: "{{somelist}}")
            - bbbb

另外,with_items还支持python的字典类型:

  tasks:
      - name: test
        debug: msg="{{ item.key }}======= {{ item.var }}"
        with_items:
            - {key: 'aaaa', var: 'bbbb'}
            - {key: 'bbbb', var: 'cccc'}

2. 嵌套循环(with_nested):

     主要实现一对多或者多对多的情况,如ab组合ac组合等:

  tasks:
      - name: test
        debug: msg="{{ item[0] }}--{{ item[1] }}---{{ item[2] }}"
        with_nested:
            - ['aaaa', 'bbbb']          #同样支持变量
            - ['cccc', 'dddd', 'eeee']
            - ['ffff', 'gggg']

3. 数据并行循环(with_together):

    如上面嵌套循环,with_together可以实现aaaa cccc ffff 并行的集合循环:

  tasks:
      - name: test
        debug: msg="{{ item[0] }}--{{ item[1] }}---{{ item[2] }}"
        with_together:
            - ['aaaa', 'bbbb']
            - ['cccc', 'dddd', 'eeee']
            - ['ffff', 'gggg']

4. hash表循环(with_dict):

      ansible1.5版本以上支持,主要针对hash结构的数据进行循环,这里套用官方的例子:

---
- hosts: test
  vars:
      users:      #定义users变量
          alice:                        #用户 名字  telephone
              name: Alice Appleworth    
              telephone: 123-456-7890
          bob:
              name: Bob Bananarama
              telephone: 987-654-3210
  tasks:
      - name: test             #打印出每个用户的名字和电话
        debug: msg="User {{ item.key }} is {{ item.value.name }} ({{ item.value.telephone }})"
        with_dict: "{{ users }}"

变量也可直接定义为json格式:

- hosts: test
  vars:
      users: {"alice":{'name':'ace','telephone':'123-123'},"bob":{'name':'boe','telephone':'321-321'}}


可以通过with_subelements对子元素进行循环,参考http://docs.ansible.com/ansible/playbooks_loops.html

5. 文件列表循环(with_fileglob):

   个人理解with_fileglob就是针对文件名进行匹配,然后进行操作:

  tasks:
      - name: test
        debug: msg="file------>{{ item }}"
        with_fileglob:
            /tmp/a*.yaml        #匹配/tmp/目录下以a开头yaml结尾的文件debug处理

其实就是使用python的glob模块模糊匹配(glob.glob('/tmp/a*.yaml'))

6. 整数循环(with_sequence):

      可以针对一个数字范围安装升序进行循环,可以指定起始值、终止值,以及一个可选的递增值,数字值可以被指定为10进制,16进制(0x3f8)或者八进制(0600):

---
- hosts: all
  tasks:
    - bug: msg="file------user{{ item }}"
      with_sequence: start=4 end=16 stride=2  #从4开始到16以2递增

    - user: name=usertest{{ item }} state=present groups=evens  #创建用户usertest(1到4)
      with_sequence: count=4              #从1到4

7. 随机选择(with_random_choice):

类似于python的random模块功能,即从list中随机选择一个:

tasks:
      - name: tes
        debug: msg={{ item }}
        with_random_choice:
            - aa
            - bbb
            - ccc

8. 条件循环(until):

       可判断循环的结果是否达到设置的条件,当达到时,结束循环,当未达到时,可设置循环的次数,及一次循环和下次循环的间隔时间,当达到循环次数还未达到设置的条件时,fatal failed退出:

  tasks:
      - name: tes
        shell: tail -10 /var/log/messages
        register: error
        until: error.stdout.find('error') != -1 #检测结果是否包含‘error’信息,存在时(!=-1)退出循环
        retries: 5   循环次数
        delay: 3     间隔时间

9. 第一个匹配的文件(with_first_found):

     这个参数跟上面文件循环的区别在于,只获取第一个匹配的文件,另外:不能使用通配符的匹配(如*):

  tasks:
      - name: tes
        debug: msg={{ item }}  
        with_first_found:         #匹配当前目录下或tmp目录下的dddd.yaml
            - “dddd.yaml”
            - "/tmp/dddd.yaml"


#还有一种可以指定路径的方式:

  tasks:
      - name: tes
        debug: msg={{ item }}
        with_first_found:
            - files:
              - "ddd.yaml"
              - "dddd.yaml"
              paths:
                  - /tmp
                  - /root

10. 循环中变量赋值:

    之前已经了解过通过register可以在task直接进行赋值,register不仅可以用于单一的task中赋值临时存储,也支持接受多个task的结果作为变量临时存储,例如:

  tasks:
      - name: tes
        shell: "{{ item }}"    #循环执行hostnaem和uptime命令
        with_items:
            - hostname
            - uptime
        register: ret         然后将两者结果赋值给ret变量

      - name: test
        debug: msg="{% for i in ret.results %} --{{ i.stdout }} {% endfor %}"  #打印变量结果

执行结果如下:

其他一些方法参考:http://docs.ansible.com/ansible/playbooks_loops.html

----------------------------------------------------------------------------------------------

深耕运维行业多年,擅长linux、容器云原生、运维自动化等方面。
承接各类运维环境部署、方案设计/实施、服务代运维工作,欢迎沟通交流 !

;