ansible-playbook的循环(Loops)

1.标准的Loops:也是最常用的一种循环
例:当需要安装10个软件包时,不用写10次任务,只需要写一次然后进行循环即可

#注:已经安装的软件系统即不在安装
[root@nfs-server playbook]# cat yum_list.yml 
---
- hosts: webservers
  remote_user: root
  gather_facts: False
  tasks: 
  - name: "需要安装的软件清单"
    yum: name={{ item }} state=present
    with_items:
      - lrzsz
      - vim
      - sysstat
[root@nfs-server playbook]# ansible-playbook yum_list.yml

PLAY [webservers] **************************************************************************************************************************************

TASK [需要安装的软件清单] ***************************************************************************************************************************************
changed: [192.168.2.101] => (item=[u'lrzsz', u'vim', u'sysstat'])
changed: [192.168.2.111] => (item=[u'lrzsz', u'vim', u'sysstat'])

PLAY RECAP *********************************************************************************************************************************************
192.168.2.101              : ok=1    changed=1    unreachable=0    failed=0   
192.168.2.111              : ok=1    changed=1    unreachable=0    failed=0

2.字典格式的循环:with_items

#写法一:
[root@nfs-server playbook]# cat dict_list.yml
---
- hosts: webservers
  remote_user: root
  gather_facts: False
  tasks:
  - name: "字典格式的循环"
    debug: msg="name ---->{{ item.name }},age---->{{ item.age }}"
    with_items:
      - {name: "Liu Zhengwei",age: 28}
      - {name: "Jia Dongli",age: 25}
#写法二:
[root@nfs-server playbook]# cat dict_list.yml
---
- hosts: webservers
  remote_user: root
  gather_facts: False
  tasks:
  - name: "字典格式的循环"
    debug: msg="name ---->{{ item.name }},age---->{{ item.age }}"
    with_items:
      - name: "Liu Zhengwei"
        age: 28
      - name: "Jia Dongli"
        age: 25
#注:以上两种写法效果是一样的
[root@nfs-server playbook]# ansible-playbook dict_list.yml

PLAY [webservers] **************************************************************************************************************************************

TASK [字典格式的循环] *****************************************************************************************************************************************
ok: [192.168.2.101] => (item={u'age': 28, u'name': u'Liu Zhengwei'}) => {
    "item": {
        "age": 28, 
        "name": "Liu Zhengwei"
    }, 
    "msg": "name ---->Liu Zhengwei,age---->28"
}
ok: [192.168.2.101] => (item={u'age': 25, u'name': u'Jia Dongli'}) => {
    "item": {
        "age": 25, 
        "name": "Jia Dongli"
    }, 
    "msg": "name ---->Jia Dongli,age---->25"
}
ok: [192.168.2.111] => (item={u'age': 28, u'name': u'Liu Zhengwei'}) => {
    "item": {
        "age": 28, 
        "name": "Liu Zhengwei"
    }, 
    "msg": "name ---->Liu Zhengwei,age---->28"
}
ok: [192.168.2.111] => (item={u'age': 25, u'name': u'Jia Dongli'}) => {
    "item": {
        "age": 25, 
        "name": "Jia Dongli"
    }, 
    "msg": "name ---->Jia Dongli,age---->25"
}

PLAY RECAP *********************************************************************************************************************************************
192.168.2.101              : ok=1    changed=0    unreachable=0    failed=0   
192.168.2.111              : ok=1    changed=0    unreachable=0    failed=0

3.嵌套Loops(列表格式的循环,用于1对多或者多对多关系时)--> with_nested

[root@nfs-server playbook]# cat netsted_list.yml 
---
- hosts: webservers
  remote_user: root
  gather_facts: False
  tasks:
  - name: "实现1对多关系的循环"
    debug: msg="name--->{{ item[0] }},value--->{{  item[1] }}"
    with_nested:
      - ['A']
      - ['a','b','c' ]
[root@nfs-server playbook]# ansible-playbook netsted_list.yml -l 192.168.2.101

PLAY [webservers] **************************************************************************************************************************************

TASK [实现1对多关系的循环] **************************************************************************************************************************************
ok: [192.168.2.101] => (item=[u'A', u'a']) => {
    "item": [
        "A", 
        "a"
    ], 
    "msg": "name--->A,value--->a"
}
ok: [192.168.2.101] => (item=[u'A', u'b']) => {
    "item": [
        "A", 
        "b"
    ], 
    "msg": "name--->A,value--->b"
}
ok: [192.168.2.101] => (item=[u'A', u'c']) => {
    "item": [
        "A", 
        "c"
    ], 
    "msg": "name--->A,value--->c"
}

PLAY RECAP *********************************************************************************************************************************************
192.168.2.101              : ok=1    changed=0    unreachable=0    failed=0

4.散列loops:with_dict(支持更丰富的数据结构)

注:with_dict的写法在新版本中进行了改变,必须要写成字典的形式,跟我下面写的格式一样

[root@nfs-server playbook]# cat with_dict.yml 
---
- hosts: webservers
  gather_facts: False
  remote_user: root
  vars:
    user:
      shencan:
        name: shencan
        shell: bash
      ruifengyun:
        name: ruifengyun
        shell: zsh
  tasks:
  - name: debug loops
    debug: "msg=name--->{{ item.key }} value--->{{ item.value.name }} shell--->{{ item.value.shell }}"
    with_dict: "{{ user }}"

[root@nfs-server playbook]# ansible-playbook with_dict.yml -l 192.168.2.101

PLAY [webservers] **************************************************************************************************************************************

TASK [debug loops] *************************************************************************************************************************************
ok: [192.168.2.101] => (item={'key': u'ruifengyun', 'value': {u'shell': u'zsh', u'name': u'ruifengyun'}}) => {
    "item": {
        "key": "ruifengyun", 
        "value": {
            "name": "ruifengyun", 
            "shell": "zsh"
        }
    }, 
    "msg": "name--->ruifengyun"
}
ok: [192.168.2.101] => (item={'key': u'shencan', 'value': {u'shell': u'bash', u'name': u'shencan'}}) => {
    "item": {
        "key": "shencan", 
        "value": {
            "name": "shencan", 
            "shell": "bash"
        }
    }, 
    "msg": "name--->shencan"
}

PLAY RECAP *********************************************************************************************************************************************
192.168.2.101              : ok=1    changed=0    unreachable=0    failed=0

5.文件匹配loops:with_fileglob

在工作中,我们经常遇到需要针对一个目录下指定格式的文件进行处理,这个时候直接引用with_fileglob循环去匹配我们需要处理的文件即可

[root@nfs-server playbook]# cat with_fileglob.yml
---
- hosts: webservers
  remote_user: root
  gather_facts: False
  tasks:
  - name: debug loops
    debug: "msg=files-->{{ item }}"
    with_fileglob:
      - /var/log/nginx/*.gz
[root@nfs-server playbook]# ansible-playbook with_fileglob.yml

PLAY [webservers] **************************************************************************************************************************************

TASK [debug loops] *************************************************************************************************************************************
ok: [192.168.2.101] => (item=/var/log/nginx/host.access.log-20170816.gz) => {
    "item": "/var/log/nginx/host.access.log-20170816.gz", 
    "msg": "files-->/var/log/nginx/host.access.log-20170816.gz"
}
ok: [192.168.2.101] => (item=/var/log/nginx/error.log-20170815.gz) => {
    "item": "/var/log/nginx/error.log-20170815.gz", 
    "msg": "files-->/var/log/nginx/error.log-20170815.gz"
}
ok: [192.168.2.101] => (item=/var/log/nginx/error.log-20170823.gz) => {
    "item": "/var/log/nginx/error.log-20170823.gz", 
    "msg": "files-->/var/log/nginx/error.log-20170823.gz"
}

ok: [192.168.2.111] => (item=/var/log/nginx/access.log-20170817.gz) => {
    "item": "/var/log/nginx/access.log-20170817.gz", 
    "msg": "files-->/var/log/nginx/access.log-20170817.gz"
}
ok: [192.168.2.111] => (item=/var/log/nginx/error.log-20170825.gz) => {
    "item": "/var/log/nginx/error.log-20170825.gz", 
    "msg": "files-->/var/log/nginx/error.log-20170825.gz"
}

PLAY RECAP *********************************************************************************************************************************************
192.168.2.101              : ok=1    changed=0    unreachable=0    failed=0   
192.168.2.111              : ok=1    changed=0    unreachable=0    failed=0

6.随机选择loops:with_random_choice(会从给定的值中随便选取一个显示)

[root@nfs-server playbook]# cat with_random_choice.yml
---
- hosts: webservers
  remote_user: root
  gather_facts: False
  tasks:
  - name: debug loops
    debug: 'msg="name --> {{ item }}"'
    with_random_choice:
      - "Beijing"
      - "Shanghai"
      - "TianJin"
[root@nfs-server playbook]# ansible-playbook with_random_choice.yml

PLAY [webservers] **************************************************************************************************************************************

TASK [debug loops] *************************************************************************************************************************************
ok: [192.168.2.101] => (item=Beijing) => {
    "item": "Beijing", 
    "msg": "name --> Beijing"
}
ok: [192.168.2.111] => (item=Shanghai) => {
    "item": "Shanghai", 
    "msg": "name --> Shanghai"
}

PLAY RECAP *********************************************************************************************************************************************
192.168.2.101              : ok=1    changed=0    unreachable=0    failed=0   
192.168.2.111              : ok=1    changed=0    unreachable=0    failed=0

7.条件判断loops

在某些情况下,我们需要检测某个task是否达到了预想的状态,如果没有达到,就需要退出整个剧本。

until:检测条件

retries:检测次数

delay:每次检测的间隔时长

[root@nfs-server playbook]# cat if_else.yml
---
- hosts: webservers
  remote_user: root
  gather_facts: False
  tasks:
  - name: "对task的执行结果进行判断"
    shell: cat /etc/fstab
    register: info
    until: info.stdout.startswith("sysfs")
    retries: 5
    delay: 5
[root@nfs-server playbook]# ansible-playbook if_else.yml 

PLAY [webservers] **************************************************************************************************************************************

TASK [对task的执行结果进行判断] **********************************************************************************************************************************
FAILED - RETRYING: 对task的执行结果进行判断 (5 retries left).
FAILED - RETRYING: 对task的执行结果进行判断 (5 retries left).
FAILED - RETRYING: 对task的执行结果进行判断 (4 retries left).
FAILED - RETRYING: 对task的执行结果进行判断 (4 retries left).
FAILED - RETRYING: 对task的执行结果进行判断 (3 retries left).
FAILED - RETRYING: 对task的执行结果进行判断 (3 retries left).
FAILED - RETRYING: 对task的执行结果进行判断 (2 retries left).
FAILED - RETRYING: 对task的执行结果进行判断 (2 retries left).
FAILED - RETRYING: 对task的执行结果进行判断 (1 retries left).
FAILED - RETRYING: 对task的执行结果进行判断 (1 retries left).
fatal: [192.168.2.111]: FAILED! => {"attempts": 5, "changed": true, "cmd": "cat /etc/fstab", "delta": "0:00:00.003310", "end": "2017-09-04 01:09:18.651001", "failed": true, "rc": 0, "start": "2017-09-04 01:09:18.647691", "stderr": "", "stderr_lines": [], "stdout": "\n#\n# /etc/fstab\n# Created by anaconda on Sun Jun 26 03:08:48 2016\n#\n# Accessible filesystems, by reference, are maintained under '/dev/disk'\n# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info\n#\n/dev/mapper/vg_test2-lv_root /                       ext4    defaults        1 1\nUUID=8699d6c2-883b-41a0-8282-5be27641ee02 /boot                   ext4    defaults        1 2\n/dev/mapper/vg_test2-lv_swap swap                    swap    defaults        0 0\ntmpfs                   /dev/shm                tmpfs   defaults        0 0\ndevpts                  /dev/pts                devpts  gid=5,mode=620  0 0\nsysfs                   /sys                    sysfs   defaults        0 0\nproc                    /proc                   proc    defaults        0 0\n/dev/cdrom              /media/cdrom            iso9660 defaults        0 0", "stdout_lines": ["", "#", "# /etc/fstab", "# Created by anaconda on Sun Jun 26 03:08:48 2016", "#", "# Accessible filesystems, by reference, are maintained under '/dev/disk'", "# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info", "#", "/dev/mapper/vg_test2-lv_root /                       ext4    defaults        1 1", "UUID=8699d6c2-883b-41a0-8282-5be27641ee02 /boot                   ext4    defaults        1 2", "/dev/mapper/vg_test2-lv_swap swap                    swap    defaults        0 0", "tmpfs                   /dev/shm                tmpfs   defaults        0 0", "devpts                  /dev/pts                devpts  gid=5,mode=620  0 0", "sysfs                   /sys                    sysfs   defaults        0 0", "proc                    /proc                   proc    defaults        0 0", "/dev/cdrom              /media/cdrom            iso9660 defaults        0 0"]}
fatal: [192.168.2.101]: FAILED! => {"attempts": 5, "changed": true, "cmd": "cat /etc/fstab", "delta": "0:00:00.002489", "end": "2017-09-04 01:11:02.560507", "failed": true, "rc": 0, "start": "2017-09-04 01:11:02.558018", "stderr": "", "stderr_lines": [], "stdout": "\n#\n# /etc/fstab\n# Created by anaconda on Sun Jun 26 03:11:47 2016\n#\n# Accessible filesystems, by reference, are maintained under '/dev/disk'\n# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info\n#\n/dev/mapper/vg_test3-lv_root /                       ext4    defaults        1 1\nUUID=e48217af-0ad9-45be-aa68-b0b1bbc88c97 /boot                   ext4    defaults        1 2\n/dev/mapper/vg_test3-lv_swap swap                    swap    defaults        0 0\ntmpfs                   /dev/shm                tmpfs   defaults        0 0\ndevpts                  /dev/pts                devpts  gid=5,mode=620  0 0\nsysfs                   /sys                    sysfs   defaults        0 0\nproc                    /proc                   proc    defaults        0 0\n/dev/cdrom              /media/cdrom            iso9660 defaults        0 0", "stdout_lines": ["", "#", "# /etc/fstab", "# Created by anaconda on Sun Jun 26 03:11:47 2016", "#", "# Accessible filesystems, by reference, are maintained under '/dev/disk'", "# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info", "#", "/dev/mapper/vg_test3-lv_root /                       ext4    defaults        1 1", "UUID=e48217af-0ad9-45be-aa68-b0b1bbc88c97 /boot                   ext4    defaults        1 2", "/dev/mapper/vg_test3-lv_swap swap                    swap    defaults        0 0", "tmpfs                   /dev/shm                tmpfs   defaults        0 0", "devpts                  /dev/pts                devpts  gid=5,mode=620  0 0", "sysfs                   /sys                    sysfs   defaults        0 0", "proc                    /proc                   proc    defaults        0 0", "/dev/cdrom              /media/cdrom            iso9660 defaults        0 0"]}
	to retry, use: --limit @/ansible/playbook/if_else.retry

PLAY RECAP *********************************************************************************************************************************************
192.168.2.101              : ok=0    changed=0    unreachable=0    failed=1   
192.168.2.111              : ok=0    changed=0    unreachable=0    failed=1

8.register同时接收多个变量进行传递

#注:接收到的多个值可以用jinja的for循环方式显示每个值
[root@nfs-server playbook]# cat register_vars.yml
---
- hosts: webservers
  remote_user: root
  gather_facts: False
  tasks:
  - name: "register接受多个值测试"
    shell: "{{ item }}"
    with_items:
      - hostname
      - uname
    register: ret
  - name: "显示接收到的值"
    debug: 'msg="{% for i in ret.results %} {{ i.stdout }} {% endfor%}"'
[root@nfs-server playbook]# ansible-playbook register_vars.yml

PLAY [webservers] **************************************************************************************************************************************

TASK [register接受多个值测试] *********************************************************************************************************************************
changed: [192.168.2.101] => (item=hostname)
changed: [192.168.2.111] => (item=hostname)
changed: [192.168.2.101] => (item=uname)
changed: [192.168.2.111] => (item=uname)

TASK [显示接收到的值] *****************************************************************************************************************************************
ok: [192.168.2.101] => {
    "msg": " lamp1  Linux "
}
ok: [192.168.2.111] => {
    "msg": " lamp2  Linux "
}

PLAY RECAP *********************************************************************************************************************************************
192.168.2.101              : ok=2    changed=1    unreachable=0    failed=0   
192.168.2.111              : ok=2    changed=1    unreachable=0    failed=0