前文中我们已经了解了一些用于循环的关键字,比如 with_list、with_items、with_flattened、with_together,这篇文章我们继续。

1.with_cartesian

假设,现在我有一个需求,我需要在目标主机的测试目录中创建a、b、c三个目录,这三个目录都有相同的子目录,它们都有test1和test2两个子目录,使用最原始的办法,我们可以在目标主机上执行如下一堆命令

# pwd
/testdir/testdir
# mkdir -p a/test1
# mkdir -p a/test2
# mkdir -p b/test1
# mkdir -p b/test2
# mkdir -p c/test1
# mkdir -p c/test2

当然,我们也可以使用通配符的方法,执行如下命令

# mkdir -p {a,b,c}/{test1,test2}

如果我们想要使用ansible完成上述需求,我们该怎么做呢?我们能够使用shell模块执行上述命令吗?我们来试试,在ansible主机上执行如下命令

[root@server4 ~]# ansible testB -m shell -a "mkdir -p /testdir/{a,b,c}/{test1,test2}"

我们使用上述命令成功的在目标主机上创建了符合我们要求的目录结构,其实,我们还能够使用循环完成上述工作,如果想要使用循环来完成上述工作,则需要先了解一个用于循环的关键字,这个关键字就是”with_cartesian”,这个关键字怎么使用呢?有怎样的效果的呢?来看一个小示例playbook,如下

[root@server4 ~]# vim xh10.yml 
[root@server4 ~]# cat xh10.yml 
---
- hosts: testB
  remote_user: root
  gather_facts: no
  tasks:
  - debug:
      msg: "{{item}}"
    with_cartesian:
    - [ a, b, c ]
    - [ test1, test2 ]

上例中定义了一个嵌套的列表,其中嵌套了两个小列表,第一个小列表中有a、b、c三个元素,第二个小列表中有test1、test2两个元素,然后我们使用 with_cartesian关键字处理这个嵌套的列表,然后循环调用debug模块输出了item的值,执行上例playbook后,debug模块的输出信息如下

[root@server4 ~]# ansible-playbook xh10.yml

ansible roles template示例 ansible with_items_子目录


ansible roles template示例 ansible with_items_vim_02


从输出信息可以看出,第一个小列表中的每个元素与第二个小列表中的每个元素都”两两组合在了一起”,如下图所示:

ansible roles template示例 ansible with_items_vim_03


聪明如你一定看出来了,上图中的排列组合方式就好像笛卡尔乘积中的一样,所以,”with_cartesian”关键字的作用就是将每个小列表中的元素按照”笛卡尔的方式”组合后,循环的处理每个组合,所以,你一定已经想到了,我们可以利用这个特性,完成我们之前创建目录的需求,示例playbook如下:

[root@server4 ~]# vim xh11.yml 
[root@server4 ~]# cat xh11.yml 
---
- hosts: testB
  remote_user: root
  gather_facts: no
  tasks:
  - file:
      state: directory
      path: "/testdir/{{item.0}}/{{item.1}}"
    with_cartesian:
    - [ a, b, c ]
    - [ test1, test2 ]

ansible roles template示例 ansible with_items_vim_04


上例playbook执行后,即可在目标主机中创建出符合我们要求的目录。

2.with_nested

其实,还有一个关键字可以代替”with_cartesian”,它就是”with_nested”,”with_nested”与”with_cartesian”的效果一致,可以无差别使用他们:

[root@server4 ~]# vim xh11.yml 
[root@server4 ~]# cat xh11.yml 
---
- hosts: testB
  remote_user: root
  gather_facts: no
  tasks:
  - file:
      state: directory
      path: "/testdir/{{item.0}}/{{item.1}}"
    with_nested:
    - [ a, b, c ]
    - [ test1, test2 ]

ansible roles template示例 ansible with_items_嵌套_05

3.with_indexed_items

“with_indexed_items”的用法,顾名思义,”with_indexed_items”应该与”索引”有关,没错,”with_indexed_items”的作用就是在循环处理列表时为列表中的每一项添加”数字索引”,”索引”从0开始,这样说可能不够直观,我们来看一个小示例,示例playbook如下:

```clike
[root@server4 ~]# vim xh12.yml 
[root@server4 ~]# cat xh12.yml 
---
- hosts: testB
  remote_user: root
  gather_facts: no
  tasks:
  - debug:
      msg: "{{item}}"
    with_indexed_items:
    - test1
    - test2
    - test3

上例中我们定义了一个列表,列表中有3个值,test1、test2、test3,我们使用”with_indexed_items”关键字处理这个列表,然后使用debug模块输出了item的信息,那么上例playbook执行后输出的信息如下:

ansible roles template示例 ansible with_items_子目录_06


从上述输出信息的msg中可以看到,”with_indexed_items”在处理列表中的每一项时,按照顺序为每一项添加了编号,test1对应的索引编号是0,test2的编号是1,test3的编号是2,”with_indexed_items”将添加过编号的每一项放入到了item中,所以,我们可以在处理每一项的时候同时获取到对应的编号,playbook如下

[root@server4 ~]# vim xh12.yml 
[root@server4 ~]# cat xh12.yml 
---
- hosts: testB
  remote_user: root
  gather_facts: no
  tasks:
  - debug:
      msg: "idnex is :{{item.0}},value is {{item.1}}"
    with_indexed_items:
    - test1
    - test2
    - test3
[root@server4 ~]# ansible-playbook xh12.yml

ansible roles template示例 ansible with_items_嵌套_07


上例中,我们已经能够通过”with_indexed_items”获取到列表中每个项的值以及对应的编号,但是,上述两个示例都是简单的单层列表,如果遇到像前文中出现的多层嵌套列表,”with_indexed_items”会怎样处理呢?我们来试试,示例playbook如下:

[root@server4 ~]# vim xh13.yml 
[root@server4 ~]# cat xh13.yml 
---
- hosts: testB
  remote_user: root
  gather_facts: no
  tasks:
  - debug:
      msg: "idnex is :{{item.0}},value is {{item.1}}"
    with_indexed_items:
    - [ test1, test2 ]
    - [ test3, test4, test5 ]
    - [ test6, test7 ]

ansible roles template示例 ansible with_items_嵌套_08


with_flattened 示例playbook如下:

[root@server4 ~]# vim xh13.yml 
[root@server4 ~]# cat xh13.yml 
---
- hosts: testB
  remote_user: root
  gather_facts: no
  tasks:
  - debug:
      msg: "idnex is :{{item.0}},value is {{item.1}}"
    with_flattened:
    - [ test1, test2 ]
    - [ test3, [ test4, test5 ] ]
    - [ test6, test7 ]
[root@server4 ~]# ansible-playbook xh14.yml

ansible roles template示例 ansible with_items_子目录_09


我们可以看出问题所在,没错,当多加了一层嵌套以后,”with_indexed_items”并不能像”with_flattened”一样将嵌套的列表”完全拉平”,第二层列表中的项如果仍然是一个列表,”with_indexed_items”则不会拉平这个列表,而是将其当做一个整体进行编号。