Bootstrap

九、ansible中的循环

一、ansible中循环的介绍

        我们通过”{{groups.ungrouped}}”获取到了未分组的返回信息,并使用关键字”with_items”接收了返回信息,然后使用debug模块输出了名为”item”变量的变量值,”with_items”关键字会把返回的列表信息自动处理,将每一条信息单独放在一个名为”item”的变量中,我们只要获取到名为”item”变量的变量值,即可循环的获取到列表中的每一条信息。

应用格式:

  • 对迭代项的引用,固定变量名为 "item";
  • 要在 task 中使用 with_items 或 loop 关键字给定要迭代的元素列表;

示例:

---
- hosts: web
  remote_user: root


  tasks:
  - name: test xunhuan
    debug:
      msg: "{{ item }}"
    with_items: ["1","2","3"]
#    - 1
#    - 2
#    - 3
[root@k8s-master-1 for]# ansible-playbook -C test1.yaml 

PLAY [web] **********************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************
ok: [192.168.134.138]

TASK [test xunhuan] *************************************************************************************************
ok: [192.168.134.138] => (item=1) => {
    "msg": "1"
}
ok: [192.168.134.138] => (item=2) => {
    "msg": "2"
}
ok: [192.168.134.138] => (item=3) => {
    "msg": "3"
}

PLAY RECAP ******************************************************************************************************
192.168.134.138            : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

示例2:稍微复杂点的

---
- hosts: web
  remote_user: root

  tasks:
  - name: test xh
    debug:
      msg: "{{ item.test1 }}"
    with_items:
    - { test1: a,test2: b }
    - { test1: c,test2: d }
# 上例中自定义列表中的每一个条目都是一个对象,我们可以通过对象的属性对应的”键”,获取到对应的”值”,
# 如上例所示,第一个条目的test1键对应的值是a,第二个条目的test1键对应的值是c,所以执行上例playbook以后,”a”和”c”会被输出:

示例3:

比如:在不会使用循环之前,我们要在同一目录下创建4个文件,代码如下:

--
- hosts: web
  remote_user: root
  tasks:
  - file:
      path: "/opt/a"
      state: touch
  - file:
      path: "/opt/b"
      state: touch
  - file:
      path: "/opt/c"
      state: touch
  - file:
      path: "/opt/d"
      state: touch
这样看着很臃肿,可以使用循环来实现创建文件
--
- hosts: web
  remote_user: root
  tasks:
  - name: touch file
    file:
      path: "{{ item }}"
      state: touch
    with_items: [ /tmp/a,/tmp/b,/tmp/c,/tmp/d ]
或者:
    - /tmp/a
    - /tmp/b
    - /tmp/c
    - /tmp/d
[root@k8s-master-1 for]# ansible-playbook -C test2.yaml 

PLAY [web] ********************************************

TASK [Gathering Facts] ********************************
ok: [192.168.134.138]

TASK [touch file] *************************************
ok: [192.168.134.138] => (item=/tmp/a)
ok: [192.168.134.138] => (item=/tmp/b)
ok: [192.168.134.138] => (item=/tmp/c)
ok: [192.168.134.138] => (item=/tmp/d)

PLAY RECAP ********************************************
192.168.134.138        : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

一、使用loop关键字 做循环

示例1:2..6版本之后 官方推荐使用loop循环

---
- hosts: web
  remote_user: root


  tasks:
  - name: test xunhuan
    debug:
      msg: "{{ item }}"
    loop: ["1","2","3"]
[root@k8s-master-1 for]# ansible-playbook -C test1.yaml 

PLAY [web] ***********************************************************************************

TASK [Gathering Facts] **********************************************************************
ok: [192.168.134.138]

TASK [test xunhuan] ****************************************************************************
ok: [192.168.134.138] => (item=1) => {
    "msg": "1"
}
ok: [192.168.134.138] => (item=2) => {
    "msg": "2"
}
ok: [192.168.134.138] => (item=3) => {
    "msg": "3"
}

PLAY RECAP ********************************************************************************************
192.168.134.138     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
      

示例2:

---
- hosts: web
  remote_user: root

  vars:
    test:
    - 1
    - 2
  tasks:
  - name: test loop
    debug:
      msg: "{{ item }}"
    loop: "{{ test }}"
[root@k8s-master-1 for]# ansible-playbook test1.yaml 

PLAY [web] *****************************************************************************************

TASK [Gathering Facts] ********************************************************************************
ok: [192.168.134.138]

TASK [test loop] *************************************************************************************
ok: [192.168.134.138] => (item=1) => {
    "msg": 1
}
ok: [192.168.134.138] => (item=2) => {
    "msg": 2
}

PLAY RECAP ************************************************************************************************
192.168.134.138        : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

示例3:使用循环批量创建用户

---
- hosts: web
  remote_user: root

  tasks:
  - name: create group
    group:
      name: "{{ item }}"
      state: present
    loop:
    - group1
    - group2
    - group3
  - name: create user
    user:
      name: "{{ item.user }}"
      group: "{{ item.group }}"
      uid: "{{ item.uid }}"
      state: present
      create_home: yes
    loop:
    - { user: user1, group: group1, uid: 2001}
    - { user: user2, group: group2, uid: 2002}
    - { user: user3, group: group3, uid: 2003}
[root@k8s-master-1 for]# ansible-playbook -C test4.yaml 

TASK [create group] ***********************************************************************************
changed: [192.168.134.138] => (item=group1)
changed: [192.168.134.138] => (item=group2)
changed: [192.168.134.138] => (item=group3)

TASK [create user] ************************************************************************************
changed: [192.168.134.138] => (item={u'group': u'group1', u'user': u'user1', u'uid': 2001})
changed: [192.168.134.138] => (item={u'group': u'group2', u'user': u'user2', u'uid': 2002})
changed: [192.168.134.138] => (item={u'group': u'group3', u'user': u'user3', u'uid': 2003})

PLAY RECAP ***************************************************************************
192.168.134.138          : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

二、for循环

示例:

---
- hosts: web

  tasks:
  - shell: "ls /home"
    register: returnvalue
  - debug:
      var: returnvalue
将shell模块执行后的返回值写入了名为”returnvalue”的变量中,然后使用debug模块输出了”returnvalue”变量的值,如下图

上例并没有借助循环重复调用shell模块,如果使用循环多次调用shell模块执行不同的命令,返回信息的格式还会和原来一样吗?
---
- hosts: web
  remote_user: root

  tasks:
  - shell: "{{ item }}"

    with_items:
    - "ls /home"
    - "ls /k8s"
    register: returnvalue

  - debug:
      var: returnvalue
# 如上例所示,我们使用循环重复调用了shell模块两次,分别执行了两条命令,然后将shell模块的返回值存放到了”returnvalue”变量中,
# 最后使用debug模块输出了”returnvalue”变量的值.
[root@k8s-master-1 for]# ansible-playbook test3.yaml 



TASK [shell] *************************************************************************
changed: [192.168.134.138] => (item=ls /home)
changed: [192.168.134.138] => (item=ls /k8s)

TASK [debug] **************************************************************************
ok: [192.168.134.138] => {
    "returnvalue": {
        "changed": true, 
        "msg": "All items completed", 
        "results": [
            {
                "ansible_loop_var": "item", 
                "changed": true, 
                "cmd": "ls /home", 
                "delta": "0:00:00.004525", 
                "end": "2023-07-26 16:15:29.446294", 
                "failed": false, 
                "invocation": {
                    "module_args": {
                        "_raw_params": "ls /home", 
                        "_uses_shell": true, 
                        "argv": null, 
                        "chdir": null, 
                        "creates": null, 
                        "executable": null, 
                        "removes": null, 
                        "stdin": null, 
                        "stdin_add_newline": true, 
                        "strip_empty_ends": true, 
                        "warn": true
                    }
                }, 
                "item": "ls /home", 
                "rc": 0, 
                "start": "2023-07-26 16:15:29.441769", 
                "stderr": "", 
                "stderr_lines": [], 
                "stdout": "job\nwuzhaobo", 
                "stdout_lines": [
                    "job", 
                    "wuzhaobo"
                ]
            }, 
            {
                "ansible_loop_var": "item", 
                "changed": true, 
                "cmd": "ls /k8s", 
                "delta": "0:00:00.004677", 
                "end": "2023-07-26 16:15:29.739434", 
                "failed": false, 
                "invocation": {
                    "module_args": {
                        "_raw_params": "ls /k8s", 
                        "_uses_shell": true, 
                        "argv": null, 
                        "chdir": null, 
                        "creates": null, 
                        "executable": null, 
                        "removes": null, 
                        "stdin": null, 
                        "stdin_add_newline": true, 
                        "strip_empty_ends": true, 
                        "warn": true
                    }
                }, 
                "item": "ls /k8s", 
                "rc": 0, 
                "start": "2023-07-26 16:15:29.734757", 
                "stderr": "", 
                "stderr_lines": [], 
                "stdout": "data\netcd\nkubernetes", 
                "stdout_lines": [
                    "data", 
                    "etcd", 
                    "kubernetes"
                ]
            }
        ]
    }
}

PLAY RECAP *******************************************************************************
192.168.134.138       : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
# 可以发现,当使用了循环以后,每次shell模块执行后的返回值都会放入一个名为”results”的序列中,其实,”results”也是一个返回值,
# 当模块中使用了循环时,模块每次执行的返回值都会追加存放到”results”这个返回值中,所以,我们可以通过”results”关键字获取到每次模块执行后的返回值,
# 示例如下:
---
- hosts: web
  remote_user: root

  tasks:
  - shell: "{{ item }}"

    with_items:
    - "ls /home"
    - "ls /k8s"
    register: returnvalue

  - debug:
      msg: "{{ item.stdout }}"

    with_items: "{{ returnvalue.results }}"
# 上例中,我们先使用循环重复的调用了shell模块,然后将shell模块每次执行后的返回值注册到了变量”returnvalue”中,之后,在使用debug模块时,通过返回值”results”获取到了之前每次执行shell模块的返回值(shell每次执行后的返回值已经被放入到item变量中),最后又通过返回值”stdout”获取到了每次shell模块执行后的标准输出.如下图:
 

 或者使用for打印信息

---
- hosts: web
  remote_user: root

  tasks:
  - shell: "{{ item }}"
   # register: returnvalue
    with_items:
    - "ls /home"
    - "ls /k8s"
    register: returnvalue

  - debug:
      msg:
        "{% for i in returnvalue.results %}
           {{ i.stdout }}
         {% endfor %}"
[root@k8s-master-1 for]# ansible-playbook  test3.yaml 

PLAY [web] *********************************

TASK [Gathering Facts] *********************
ok: [192.168.134.138]

TASK [shell] ******************************
changed: [192.168.134.138] => (item=ls /home)
changed: [192.168.134.138] => (item=ls /k8s)

TASK [debug] ******************************
ok: [192.168.134.138] => {
    "msg": " job\nwuzhaobo  data\netcd\nkubernetes "
}

PLAY RECAP *******************************
192.168.134.138      : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

#上例使用了一个for循环遍历了” returnvalue.results”列表,上例中for循环的语法为jinja2语言中的for循环语法,jinja2是一种模板语言,jinja2是一个基于python的模板引擎,所以,在ansible中,我们可以使用jinja2编写模板文件,然后再根据模板文件来生成配置文件,jinja2中也有一些控制语句结构,比如for循环,上例中使用的就是jinja2语法中的for循环,如果你执行了上例的playbook,你会发现,debug模块只执行了一次,msg中对应的信息是所有shell模块执行后的stdout返回值,因为debug模块只是输出了经过jinja2的for循环处理过的信息而已,debug模块并没有因为for循环而被重复的调用。

三、loop循环寄过滤器

1、loop代替with_list

loop 代替with_list:当处理列表是,列表不会别拉平

示例:

---
- hosts: web
  remote_user: root

  vars:
    test:
    - 1
    - [ 1,a,b ]
    - 2
  tasks:
  - name: test loop
    debug:
      msg: "{{ item }}"
    loop: "{{ test }}"
[root@k8s-master-1 for]# ansible-playbook -C test1.yaml
ok: [192.168.134.138] => (item=1) => {
    "msg": 1
}
ok: [192.168.134.138] => (item=[1, u'a', u'b']) => {
    "msg": [
        1, 
        "a", 
        "b"
    ]
}
ok: [192.168.134.138] => (item=2) => {
    "msg": 2
}
2、loop+flatten 过滤器 代替 with_flattened

flatten过滤器可以替代 with_flattened,当处理多层嵌套时,列表中的层级都会被拉平

---
- hosts: web
  remote_user: root

  vars:
    test:
    - 1
    - [ 1,a,b ]
    - 2
  tasks:
  - name: test loop
    debug:
      msg: "{{ item }}"
    loop: "{{ test | flatten }}"
[root@k8s-master-1 for]# ansible-playbook -C test1.yaml
ok: [192.168.134.138] => (item=1) => {
    "msg": 1
}
ok: [192.168.134.138] => (item=1) => {
    "msg": 1
}
ok: [192.168.134.138] => (item=a) => {
    "msg": "a"
}
ok: [192.168.134.138] => (item=b) => {
    "msg": "b"
}
ok: [192.168.134.138] => (item=2) => {
    "msg": 2
}
3、loop+flatten 过滤器(加参数) 代替 with_items

        loop+flatten 过滤器(加参数 levels=2 ) 代替 with_items:档处理多层嵌套列表时,只有列表的第2层会被拉平

---
- hosts: web
  remote_user: root

  vars:
    test:

    - [ 1,[a,b,[c,d]],[q,w]]
  tasks:
  - name: test loop
    debug:
      msg: "{{ item }}"
    loop: "{{ test | flatten(levels=2) }}"
[root@k8s-master-1 for]# ansible-playbook -C test1.yaml
ok: [192.168.134.138] => (item=1) => {
    "msg": 1
}
ok: [192.168.134.138] => (item=a) => {
    "msg": "a"
}
ok: [192.168.134.138] => (item=b) => {
    "msg": "b"
}
ok: [192.168.134.138] => (item=[u'c', u'd']) => {
    "msg": [
        "c", 
        "d"
    ]
}
ok: [192.168.134.138] => (item=q) => {
    "msg": "q"
}
ok: [192.168.134.138] => (item=w) => {
    "msg": "w"
}
可以看到 只有列表的第二层被拉平,如果levels=1,则只有列表第一层回被拉平
4、zip_longest过滤器+list过滤器代替 with_together。将两个列表中的元素”对齐合并”

zip_longest过滤器配合list过滤器 示例:

---
- hosts: web
  remote_user: root
  vars:
    testlist1: [a,b,c]
    testlist2: [1,2,3]
    testlist3: [A,B,C,D]
  tasks:
  - name: test with_together
    debug:
      msg: "{{ item.0 }} - {{ item.1 }} - {{ item.2 }}"
    with_together:
    - "{{ testlist1 }}"
    - "{{ testlist2 }}"
    - "{{ testlist3 }}"

  - name: test zip_longest+list
    debug:
      msg: "{{ item.0 }} - {{ item.1 }} - {{ item.2 }}"
    loop: "{{  testlist1 | zip_longest(testlist2,testlist3) | list  }}"
[root@k8s-master-1 for]# ansible-playbook -C test1.yaml 
ok: [192.168.134.138] => (item=[u'a', 1, u'A']) => {
    "msg": "a - 1 - A"
}
ok: [192.168.134.138] => (item=[u'b', 2, u'B']) => {
    "msg": "b - 2 - B"
}
ok: [192.168.134.138] => (item=[u'c', 3, u'C']) => {
    "msg": "c - 3 - C"
}
ok: [192.168.134.138] => (item=[None, None, u'D']) => {
    "msg": " -  - D"
}

TASK [test zip_longest+list] *************************************************************
ok: [192.168.134.138] => (item=[u'a', 1, u'A']) => {
    "msg": "a - 1 - A"
}
ok: [192.168.134.138] => (item=[u'b', 2, u'B']) => {
    "msg": "b - 2 - B"
}
ok: [192.168.134.138] => (item=[u'c', 3, u'C']) => {
    "msg": "c - 3 - C"
}
ok: [192.168.134.138] => (item=[None, None, u'D']) => {
    "msg": " -  - D"
}
可以看到两个关键字  输出的结果是一样的,with_together、loop: zip_longest(var1,var2) | list
当多个列表使用with_together进行合并时,如果多个列表的长度不同,则使用最长的列表长度进行对其,由于段列表中的长度不够,会使用空置来对齐。
zip_longest和with_together 一样,对列表进行组合,但是还需要使用  list过滤 将组合后的数据列表化,
zip_longest 默认也是使用空值进行对齐,如果不想为空,可以设置默认值“fillvalue='W'”:此时,为空的就会用W 来代替
loop: "{{  testlist1 | zip_longest(testlist2,testlist3,fillvalue='W') | list  }}"
zip_longest 是使用最长的列表进行对齐
zip:是使用最短的列表进行对齐
5、product过滤器配合list过滤器代替with_nested/with_cartesian
6、range过滤器配合list过滤器with_sequence
7、random函数 替代 with_random_choice
8、dictsort过滤器也可以替代with_dict
9、subelements过滤器with_subelements

二、with_items、with_list、with_flattened、with_together之间的区别和联系

一、with_items

示例1:

---
- hosts: web
  remote_user: root

  tasks:
  - name: item_list
    debug:
      msg: "{{ item }}"
    with_list:
    - [1,2,3]
    - [a,b]
[root@k8s-master-1 for]# ansible-playbook -C test2.yaml 
ok: [192.168.134.138] => (item=1) => {
    "msg": 1
}
ok: [192.168.134.138] => (item=2) => {
    "msg": 2
}
ok: [192.168.134.138] => (item=3) => {
    "msg": 3
}
ok: [192.168.134.138] => (item=a) => {
    "msg": "a"
}
ok: [192.168.134.138] => (item=b) => {
    "msg": "b"
}

二、with_list

        从示例1可以看出,debug将每个小列表的值都输出了一遍,那如果我们想,将每个小列表作为一个整体输出,该怎么办呢?使用with_list关键字替换with_items、或者 with_flattened 关键字

示例2:

---
- hosts: web
  remote_user: root

  tasks:
  - name: item_list
    debug:
      msg: "{{ item }}"
    with_list:
    - [1,2,3]
    - [a,b,c]
[root@k8s-master-1 for]# ansible-playbook -C test2.yaml 


ok: [192.168.134.138] => (item=[1, 2, 3]) => {
    "msg": [
        1, 
        2, 
        3
    ]
}
ok: [192.168.134.138] => (item=[u'a', u'b', u'c']) => {
    "msg": [
        "a", 
        "b", 
        "c"
    ]
}

PLAY RECAP ***************************************************************************
192.168.134.138       : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
// 如上述信息所示,经过with_list处理后,每个嵌套在大列表中的小列表都被当做一个整体存放在item变量中,最终被debug作为一个小整体输出了,而不会像with_items一样将小列表”展开拉平”后一并将小列表中的元素循环输出。
// 当处理单层的简单列表时,with_list与with_items没有任何区别,只有在处理上例中的”嵌套列表”时,才会体现出区别,区别就是,with_items会将嵌套在内的小列表”拉平”,拉平后循环处理所有元素,而with_list则不会”拉平”嵌套的列表,with_list只会循环的处理列表(最外层列表)中的每一项。

三、with_flattened

        当处理这种嵌套的列表时,如果想要实现”拉平”的效果,我们还能使用另外一个关键字,它就是with_flattened关键字。

示例:

---
- hosts: web
  remote_user: root

  tasks:
  - name: test with_indexed_items
    debug:
     # msg: "index is {{ item.0}}  value is {{ item.1 }}"
      msg: "{{ item }}"
    with_flattened:
    - [ a,b,c ]
    - [ 1,2,[ q,w ] ]
[root@k8s-master-1 for]# ansible-playbook -C test6.yaml 
ok: [192.168.134.138] => (item=a) => {
    "msg": "a"
}
ok: [192.168.134.138] => (item=b) => {
    "msg": "b"
}
ok: [192.168.134.138] => (item=c) => {
    "msg": "c"
}
ok: [192.168.134.138] => (item=1) => {
    "msg": 1
}
ok: [192.168.134.138] => (item=2) => {
    "msg": 2
}
ok: [192.168.134.138] => (item=q) => {
    "msg": "q"
}
ok: [192.168.134.138] => (item=w) => {
    "msg": "w"
}

四、with_together

with_together可以将两个列表中的元素”对齐合并”

---
- hosts: web
  remote_user: root

  tasks:
  - name: item_list
    debug:
      msg: "{{ item }}"
    with_together:
    - [1,2,3]
    - [a,b,c]
[root@k8s-master-1 for]# ansible-playbook -C test2.yaml 


ok: [192.168.134.138] => (item=[1, u'a']) => {
    "msg": [
        1, 
        "a"
    ]
}
ok: [192.168.134.138] => (item=[2, u'b']) => {
    "msg": [
        2, 
        "b"
    ]
}
ok: [192.168.134.138] => (item=[3, u'c']) => {
    "msg": [
        3, 
        "c"
    ]
}

这就是with_together所谓的”对齐合并”功能
如果列表中的元素数量不同,使用with_together 关键字效果如下
ok: [192.168.134.138] => (item=[1, u'a']) => {
    "msg": [
        1, 
        "a"
    ]
}
ok: [192.168.134.138] => (item=[2, u'b']) => {
    "msg": [
        2, 
        "b"
    ]
}
ok: [192.168.134.138] => (item=[3, None]) => {
    "msg": [
        3, 
        null
    ]
}

总结:

        在处理简单的单层列表时,他们没有区别,但是当处理嵌套的多层列表时,with_items与with_flattened会将嵌套列表”拉平展开”,循环的处理每个元素,而with_list只会处理最外层的列表,将最外层的列表中的每一项循环处理。

五、with_cartesian

        上边了解了一些循环的关键字,其实还有很多,比如,现在有个需求,要在服务器创建a、b、c、三个目录,并且这3个目录都有相同的子目录,我们的实现方法有:

1、直接使用命令创建
[root@k8s-node-2 tmp]# mkdir -p a/test1
[root@k8s-node-2 tmp]# mkdir -p a/test2
[root@k8s-node-2 tmp]# mkdir -p b/test1
[root@k8s-node-2 tmp]# mkdir -p b/test2
[root@k8s-node-2 tmp]# mkdir -p c/test1
[root@k8s-node-2 tmp]# mkdir -p c/test2
2、使用通配符创建
[root@k8s-node-2 tmp]# mkdir -p {a,b,c}/{test1,test2}
3、使用ansible 的shell 模块创建
[root@k8s-master-1 for]# ansible web -m shell -a "mkdir -p /tmp/{a,b,c}/{test1,test2}"
4、使用ansible的循环来创建,关键字:with_cartesian
---
- hosts: web
  remote_user: root

  tasks:
  - name: create file
    file:
      state: directory
      path: /tmp/{{ item.0 }}/{{ item.1 }}
    with_cartesian:
    - [ a,b,c ]
    - [ test1,test2 ]
[root@k8s-master-1 for]# ansible-playbook test5.yaml
changed: [192.168.134.138] => (item=[u'a', u'test1'])
changed: [192.168.134.138] => (item=[u'a', u'test2'])
changed: [192.168.134.138] => (item=[u'b', u'test1'])
changed: [192.168.134.138] => (item=[u'b', u'test2'])
changed: [192.168.134.138] => (item=[u'c', u'test1'])
changed: [192.168.134.138] => (item=[u'c', u'test2'])
5、或者使用”with_nested” 关键字,与with_cartesian的效果一致,不做演示

六、with_indexed_items

        with_indexed_items的作用就是在循环处理列表时,为列表中的每一项添加“数字索引”,索引从0 开始。

示例:

---
- hosts: web
  remote_user: root

  tasks:
  - name: test with_indexed_items
    debug:
      msg: "{{ item }}"
    with_indexed_items:
    - a
    - b
    - c
[root@k8s-master-1 for]# ansible-playbook -C test6.yaml
ok: [192.168.134.138] => (item=[0, u'a']) => {
    "msg": [
        0, 
        "a"
    ]
}
ok: [192.168.134.138] => (item=[1, u'b']) => {
    "msg": [
        1, 
        "b"
    ]
}
ok: [192.168.134.138] => (item=[2, u'c']) => {
    "msg": [
        2, 
        "c"
    ]
}
从上述信息可以看到“with_indexed_items”将添加过编号的每一项放入到item中,所以,我们也可以获取到他的编号:
---
- hosts: web
  remote_user: root

  tasks:
  - name: test with_indexed_items
    debug:
      msg: "index is {{ item.0}}  value is {{ item.1 }}"
    with_indexed_items:
    - a
    - b
    - c
[root@k8s-master-1 for]# ansible-playbook -C test6.yaml 
ok: [192.168.134.138] => (item=[0, u'a']) => {
    "msg": "index is 0  value is a"
}
ok: [192.168.134.138] => (item=[1, u'b']) => {
    "msg": "index is 1  value is b"
}
ok: [192.168.134.138] => (item=[2, u'c']) => {
    "msg": "index is 2  value is c"
}
如果遇到比较复杂的嵌套列表,with_indesed_items的处理如下:;

  tasks:
  - name: test with_indexed_items
    debug:
      msg: "index is {{ item.0}}  value is {{ item.1 }}"
    with_indexed_items:
    - [ a,b,c ]
    - [ 1,2,3 ]
    - [ wu,kang,zhao ]
// 输出也没有问题
ok: [192.168.134.138] => (item=[0, u'a']) => {
    "msg": "index is 0  value is a"
}
ok: [192.168.134.138] => (item=[1, u'b']) => {
    "msg": "index is 1  value is b"
}
ok: [192.168.134.138] => (item=[2, u'c']) => {
    "msg": "index is 2  value is c"
}
ok: [192.168.134.138] => (item=[3, 1]) => {
    "msg": "index is 3  value is 1"
}
ok: [192.168.134.138] => (item=[4, 2]) => {
    "msg": "index is 4  value is 2"
}
ok: [192.168.134.138] => (item=[5, 3]) => {
    "msg": "index is 5  value is 3"
}
ok: [192.168.134.138] => (item=[6, u'wu']) => {
    "msg": "index is 6  value is wu"
}
ok: [192.168.134.138] => (item=[7, u'kang']) => {
    "msg": "index is 7  value is kang"
}
ok: [192.168.134.138] => (item=[8, u'zhao']) => {
    "msg": "index is 8  value is zhao"
}

在嵌套一层 看看:
    with_indexed_items:
    - [ a,b,c ]
    - [ 1,2,[ q,w ] ]
    - [ wu,kang,zhao ]
可以看到 [ q,w ] 这个列表 并不会被完全拉平显示,没有”with_flattened” 强大
ok: [192.168.134.138] => (item=[5, [u'q', u'w']]) => {
    "msg": "index is 5  value is [u'q', u'w']"

七、with_sequence

        需求:要在目标主机创建5个目录,分别是 t2 、t4、t6、t8、t10、用ansible怎么实现?

使用:with_sequence 关键字

        "with_sequence"可以帮助我们按照顺序生成数字序列,with_sequence的设置是"start=2 end=10 stride=2",其中start=2表示从2开始,end=10表示到10结束, stride=2表示步长为2,即从2到10每次增加2。

        count=5表示数字序列默认从1开始,到5结束,默认步长为1

        当我们不指定stride的值时,stride的值默认为1,但是,当end的值小于start的值时,则必须指定stride的值,而且stride的值必须是负数,

示例:

---
- hosts: web
  remote_user: root

  tasks:
  - name: test with_sequenec
    debug:
      msg: "{{ item }}"
    with_sequence:
      start=2
      end=10
      stride=2
[root@k8s-master-1 for]# ansible-playbook -C test7.yaml
ok: [192.168.134.138] => (item=2) => {
    "msg": "2"
}
ok: [192.168.134.138] => (item=4) => {
    "msg": "4"
}
ok: [192.168.134.138] => (item=6) => {
    "msg": "6"
}
ok: [192.168.134.138] => (item=8) => {
    "msg": "8"
}
ok: [192.168.134.138] => (item=10) => {
    "msg": "10"
}

八、with_random_choice

使用"with_random_choice"可以从列表的多个值中随机返回一个值

---
- hosts: web
  remote_user: root

  tasks:
  - name: test with_indexed_items
    debug:

      msg: "{{ item }}"

    with_random_choice:
    - 1
    - 2
    - 3
    - 4
[root@k8s-master-1 for]# ansible-playbook -C test6.yaml
ok: [192.168.134.138] => (item=3) => {
    "msg": 3
}
每次只返回列表中随机的一个
ok: [192.168.134.138] => (item=4) => {
    "msg": 4
}

九、with_dict

示例:

---
- hosts: web
  remote_user: root

  vars:
    users:
      wuzhaobo: male
      kangkexin: female
  tasks:
  - debug:
      msg: "{{ item }}"
    with_dict: "{{ users }}"
[root@k8s-master-1 for]# ansible-playbook -C test7.yaml
ok: [192.168.134.138] => (item={u'key': u'wuzhaobo', u'value': u'male'}) => {
    "msg": {
        "key": "wuzhaobo", 
        "value": "male"
    }
}
ok: [192.168.134.138] => (item={u'key': u'kangkexin', u'value': u'female'}) => {
    "msg": {
        "key": "kangkexin", 
        "value": "female"
    }
}
// 从输出信息可以看出,字典格式的users变量经过"with_dict"处理后,字典中的每个键值对被放到了item变量中,而且,键值对中的"键"被放入了"key"关键字中,键值对中的"值"被放入了"value"关键字中,所以,我们可以通过key关键字和value关键字分别获取到字典中键值对的"键"和"值",
示例
---
- hosts: web
  remote_user: root

  vars:
    users:
      wuzhaobo: male
      kangkexin: female
  tasks:
  - debug:
      msg: "User name is: {{item.key}},User grnder is: {{item.value}}"
    with_dict: "{{ users }}"
[root@k8s-master-1 for]# ansible-playbook -C test7.yaml
ok: [192.168.134.138] => (item={u'key': u'wuzhaobo', u'value': u'male'}) => {
    "msg": "User name is: wuzhaobo,User grnder is: male"
}
ok: [192.168.134.138] => (item={u'key': u'kangkexin', u'value': u'female'}) => {
    "msg": "User name is: kangkexin,User grnder is: female"
}
稍微复杂点的
示例:
---
- hosts: web
  remote_user: root

  vars:
    users:
      wuzhaobo:
        name: wuzhaobo
        age: 28
        telephone: 123-456-789
      kangkexin:
        name: kangkexin
        age: 26
        telephone: 987-654-321
  tasks:
  - debug:
      msg: "{{item}}"
      //msg: "User {{item.key}} is {{item.value.name}},User age is {{item.value.age}},User telephone is:{{item.value.telephone}}"
    with_dict: "{{users}}"
[root@k8s-master-1 for]# ansible-playbook -C test7.yaml
ok: [192.168.134.138] => (item={u'key': u'wuzhaobo', u'value': {u'age': 28, u'name': u'wuzhaobo', u'telephone': u'123-456-789'}}) => {
    "msg": {
        "key": "wuzhaobo", 
        "value": {
            "age": 28, 
            "name": "wuzhaobo", 
            "telephone": "123-456-789"
        }
    }
}
ok: [192.168.134.138] => (item={u'key': u'kangkexin', u'value': {u'age': 26, u'name': u'kangkexin', u'telephone': u'987-654-321'}}) => {
    "msg": {
        "key": "kangkexin", 
        "value": {
            "age": 26, 
            "name": "kangkexin", 
            "telephone": "987-654-321"
        }
    }
}
ok: [192.168.134.138] => (item={u'key': u'wuzhaobo', u'value': {u'age': 28, u'name': u'wuzhaobo', u'telephone': u'123-456-789'}}) => {
    "msg": "User wuzhaobo is wuzhaobo,User age is 28,User telephone is:123-456-789"
}
ok: [192.168.134.138] => (item={u'key': u'kangkexin', u'value': {u'age': 26, u'name': u'kangkexin', u'telephone': u'987-654-321'}}) => {
    "msg": "User kangkexin is kangkexin,User age is 26,User telephone is:987-654-321"
}

十、with_subelements

        "with_subelements"可以处理一个复合结构的字典数据,在处理这个字典的同时,需要指定一个子元素,这个子元素的值必须是一个列表,之后,"with_subelements"会将子元素的列表中的每一项作为一个整体,将其他子元素作为一个整体,然后将两个整体组合成item。

示例:

---
- hosts: web
  remote_user: root

  vars:
    users:
    - name: wuzhaobo
      age: 28
      telephone: 123-456-789
      hobby: [chi,he]      
      
    - name: kangkexin
      age: 26
      telephone: 987-654-321
      hobby:
      - chi
  tasks:
  - debug:
      #msg: "{{item}}"
      msg: "{{item.0.name}} 's hobby is {{item.1}}"
    with_subelements:
    - "{{users}}"
    - hobby
[root@k8s-master-1 for]# ansible-playbook -C test7.yaml 
ok: [192.168.134.138] => (item=[{u'age': 28, u'name': u'wuzhaobo', u'telephone': u'123-456-789'}, u'chi']) => {
    "msg": "wuzhaobo 's hobby is chi"
}
ok: [192.168.134.138] => (item=[{u'age': 28, u'name': u'wuzhaobo', u'telephone': u'123-456-789'}, u'he']) => {
    "msg": "wuzhaobo 's hobby is he"
}
ok: [192.168.134.138] => (item=[{u'age': 26, u'name': u'kangkexin', u'telephone': u'987-654-321'}, u'chi']) => {
    "msg": "kangkexin 's hobby is chi"
}
上例中,我们使用“with_subelements”关键字处理了users 变量,并指定了一个属性 hobby .
“hobby属性" 是users中每个块序列的子元素,而且,hobby属性是一个 "键值对”,其"值"是一个列表