在ansible的playbook中如果发现需要有很多task重复的引用某一个相同的模块时这个时候需要使用loops去编写playbook减少使用某个模块。

标准循环

标准循环关键字:”with_items:”
编写standerloop.yaml的playbook文件分别对远程主机打印one,two这两个值:

---
  - gather_facts: Flase
    hosts: all
    tasks:
    -
      debug: "msg= \"name -----> {{ item }}\""
      name: "debug loops"
      with_items:
       - one
       - two

执行的结果如下:

ansible 无盘_字符串

with_items的值是python list数据结构,可以理解为每个task会循环读取list里面的值,然后key的名称是item,当然list里面也支持python字典形式:

---
  - gather_facts: Flase
    hosts: all
    tasks:
    -
      debug: "msg=\"name -----> {{ item.key }}    vaule -----> {{ item.vaule }}\""
      name: "debug loops"
      with_items:
       - { key: "one", vaule: "VAULE1"}
       - { key: "two", vaule: "VAULE2"}

执行结果如下:

ansible 无盘_字符串_02

嵌套循环

嵌套循环主要实现一对多,多对多的合并

---
-
  hosts: all
  gather_facts: False
  tasks:
  - name: debug loops
    debug: "msg=\"name -----> {{ item[0] }} vaule -----> {{ item[1] }}\""
    with_nested:
    - ['Ansible']
    - ['test1','test2','test3']

得到的结果如下:

ansible 无盘_ansible 无盘_03

散列loops(对哈希表进行循环)

标准的loop最外层必须是Python的list数据类型,而散列loops直接支持YAML格式的数据变量。散列的loops直接支持YAML格式的数据变量。使用with_dict来循环哈希表中的元素,with_dict是接收一个Python字典(经过yaml.load后)的格式变量:

---
-
  hosts: all
  gather_facts: False
  vars:
   user:
    Bob_hou:
     name: Bob_Hou
     shell: bash
    Jmilk:
     name: Jmilk
     shell: zsh
  tasks:
  -
    name: debug loops
    debug: "msg=\"name -----> {{item.key }} value -----> {{item.value.name }} shell -----> {{ item.value.shell }}\""
    with_dict: "{{ user }}"

输出的结果为:

ansible 无盘_playbook_04

文件匹配loop

在编写playbook的时候需要针对文件进行操作中最常使用到的循环,例如我们需要对一个目录下指定格式的文件进行处理,这个时候我们直接使用with_fileglob循环去匹配我们需要处理的文件。例如我要寻找playbook中所有的yaml格式的剧本文件,于是编写一个如下的文件匹配循环:

---
-
  hosts: all
  gather_facts: False
  tasks:
  -
    name: debug loops
    debug: "msg=\"files -----> {{ item }}\""
    with_fileglob:
    -
      /root/playbook/*.yaml

with_fileglob这个时候会匹配root/playbook目录下所有以yaml结尾的文件,当作{{ item }} 变量,运行的结果如下:

ansible 无盘_nginx_05

实际上文件循环是使用python glob模块去做文件模糊匹配:

>>> import glob
>>> print glob.glob('/root/playbook/*.yaml')
['/root/playbook/nginx-116.yaml', '/root/playbook/fileloop.yaml', '/root/playbook/var.yaml', '/root/playbook/standerloop.yaml', '/root/playbook/nestedloop.yaml', '/root/playbook/variable.yaml', '/root/playbook/nginx.yaml', '/root/playbook/hashloop.yaml']

随机选择loop

利用with_random_choice在传入的list中随机选择一个,与使用python random实现原理一样。它有时可以用作一个简化版的负载均衡器,比如作为条件判断。提供的字符串中的其中一个会被随机选中。

---
-
  hosts: all
  gather_facts: False
  tasks:
  -
    name: debug loops
    debug: "msg=\"name -----> {{ item }}\""
    with_random_choice:
    - "web"
    - "devstack"
    - "nginx"

执行的结果如下:

ansible 无盘_ansible 无盘_06

条件判断Loops

如我们执行一个task之后,我们想要检测这个task结果是否达到了预想状态,如果没有没有达到预想状态,我们就需要退出整个playbook执行,这个时候可以使用循环检测判断了。

---
-
  hosts: all
  gather_facts: False
  tasks:
  -
    name: debug loops
    shell: cat /root/ansible
    register: host
    until: host.stdout.startswith("cat")
    retries: 5
    delay: 5

每5秒执行一次cat /root/ansible结果,然后将结果交给register的host参数,然后判断host.stdout.startswith的内容是否是cat字符串开头,如果条件成立,此task运行完成,如果条件不成立5s后重试,5次还不成立,此task运行失败。这里我选用的目录就是一个假目录,所以最后执行结果会是失败的。

ansible 无盘_字符串_07

文件优先匹配

如果你想引用一个文件,而该文件是从一组文件中根据给定条件匹配出来的,你可以使用这种模式:

---
-
  hosts: all
  gather_facts: True
  tasks:
  -
    name: debug loops
    debug: "msg=\"files -----> {{item }}\""
    with_first_found:
    -
      "{{ ansible_distribution }}.yaml"
    -
      "nginx.yaml"

with_first_found会从list里面定义的文件从上往下一个一个的匹配,如果匹配到了item就是该文件。输出结果如下:

ansible 无盘_playbook_08

register loops循环

register适用于task直接互相传递数据的,一般我们会把register用在单一的task中进行变量临时存储,其实register还可以同时接受多个task的结果当做变量临时存储:

---
-
  hosts: all
  gather_facts: True
  tasks:
  -
    name: debug loops
    shell: "{{ item }}"
    with_items:
    -
      hostname
    -
      uname
    register: ret
  - name: display loops
    debug: "msg=\"{% for i in ret.results %} {{ i.stdout }} {% endfor %}\""

输出结果如下:

ansible 无盘_ansible 无盘_09