快捷玩Ansible循环任务-灵析社区

秋月无边

1. 招式简介—利用循环迭代任务

在Ansible编写剧本的时候,我们往往遇到许多重复性的操作,比如安装各种软件包,在某个目录操作各种文件等等。通过利用循环,我们无需编写多个使用同一模块的任务。例如,他们不必编写五个任务来确保存在五个用户,而是只需编写一个任务来对含有五个用户的列表迭代,从而确保它们都存在。

Ansible支持使用loop关键字对一组项目迭代任务。可以配置循环以利用列表中的各个项目、列表中各个文件的内容、生成的数字序列或更为复杂的结构来重复任务。

2. 基础演练—编写简单循环

循环可对一组项目进行迭代任务。使用loop关键字添加到任务中,将应对其迭代任务的项目列表取为值。循环变量item保存每个迭代过程中使用的值。可以理解为loop和item就是一配对

举个例子:

不用循环的写法:

---
- hosts: localhost
  tasks:
    - name: mkdir /home/student/abc
      shell: mkdir /home/student/abc
    - name: mkdir /home/student/cde
      shell: mkdir /home/student/cde

使用简单的循环:

# cat test.yml
---
- hosts: localhost
  tasks:
    - name: mkdir /home/student/ file
      shell: "mkdir /home/student/{{ item }}"
      loop:
        - abc
        - cde

明显使用一次shell模块,而不用使用二次就可以达到最终的需求。(突然感觉气血通畅,爽!)

还有另一种写法:

(这种偏门点的招式,还是看看就好)

---
- hosts: localhost
  vars:
    dir_name:
      - abc
      - cde
  tasks:
    - name: mkdir /home/student/ file
      shell: "mkdir /home/student/{{ item }}"
      loop: "{{ dir_name }}"

3. 招式外放—循环散列或字典列表

loop列表可不以简单的值作为调用,而是使用散列或字典,这较为复杂一点的写法。

在以下示例中,列表中的每个项实际上是散列或字典。示例中的每个散列或字典具有两个键,即name和groups,当前item循环变量中每个键的值可以分别通过item.name和item.groups变量来检索

---
- hosts: localhost
  tasks:
    - name: user loop test
      user:
        name: "{{ item.name }}"
        state: present
        group: "{{ item.group }}"
      loop:
        - name: chap
          group: chap
        - name: rebel
          group: rebel

(还记得上文所说的loop和item配对吗?item.name其实就是loop.name,人家是比翼双飞,水影鸳鸾 >.<)

较早样式的循环关键字

在Ansible2.5之前,大多数playbook使用不同的循环语法。提供了多个循环关键字,前缀为with_,后面跟Ansible查找插件的名称。这种循环语法在现有playbook中很常见,但在将来的某个时候可能会被弃用。

(看来招式还是需要定期更新才行,不过在人家还没有过时前,还是得先见招拆招。)

较早样式的Ansible循环

with_****items循环playbook演示:

---
- hosts: localhost
  vars:
    data:
      - abc
      - cde
      - efg
  tasks:
    - name: with_item test
      debug:
        msg: "{{ item }}"
      with_items: "{{ data }}"

4. 一剑定江山—将Register变量与Loop一起使用

register关键字也可以用来捕获循环任务的输出。以下代码片段显示了循环任务中register变量的结构:

register和loop配合使用

[student@servera example]$ cat loop-register.yml
---
- hosts: localhost
  tasks:
    - name: register and loop
      shell: "echo test {{ item }}"
      loop:
        - abc
        - cde
      register: results
      
    - name: print result
      debug:
        var: results
[student@servera example]$ ansible-playbook loop-register.yml 

PLAY [loop-register] *******************************************************************

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

TASK [register and loop] ***************************************************************
changed: [localhost] => (item=abc)
changed: [localhost] => (item=def)

TASK [print result] ********************************************************************
ok: [localhost] => {
    "results": {
        "changed": true, 
        "msg": "All items completed", 
        "results": [
            {
                "ansible_loop_var": "item", 
                "changed": true, 
                "cmd": "echo test abc", 
                "delta": "0:00:00.007471", 
                "end": "2021-12-09 23:47:00.084344", 
                "failed": false, 
                "invocation": {
                    "module_args": {
                        "_raw_params": "echo test abc", 
                        "_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": "abc", 
                "rc": 0, 
                "start": "2021-12-09 23:47:00.076873", 
                "stderr": "", 
                "stderr_lines": [], 
                "stdout": "test abc", 
                "stdout_lines": [
                    "test abc"
                ]
            }, 
            {
                "ansible_loop_var": "item", 
                "changed": true, 
                "cmd": "echo test def", 
                "delta": "0:00:00.007672", 
                "end": "2021-12-09 23:47:00.259170", 
                "failed": false, 
                "invocation": {
                    "module_args": {
                        "_raw_params": "echo test def", 
                        "_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": "def", 
                "rc": 0, 
                "start": "2021-12-09 23:47:00.251498", 
                "stderr": "", 
                "stderr_lines": [], 
                "stdout": "test def", 
                "stdout_lines": [
                    "test def"
                ]
            }
        ]
    }
}

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

更进一步的运用:

[student@servera example]$ cat loop-register.yml
---
- name: loop-register
  hosts: localhost
  tasks:
    - name: register and loop
      shell: "echo test {{ item }}"
      loop:
        - abc
        - cde
      register: results

    - name: print results
      debug:
        msg: "Send out the message: {{ item.stdout }}"
      loop: "{{ results['results'] }}"
# 此为运用散列或字典列表的形式,将results这注册变量所输出项中取results项中的值。
#      loop: "{{ results.results }}"
# 还记得这个一样的写法吗~~不记得可参考https://blog.csdn.net/qq_41765918/article/details/121796046 章节中,新旧语法对比。
[student@servera example]$ ansible-playbook loop-register.yml 

PLAY [loop-register] *******************************************************************

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

TASK [register and loop] ***************************************************************
changed: [localhost] => (item=abc)
changed: [localhost] => (item=def)

TASK [print results] *******************************************************************
ok: [localhost] => (item={u'stderr_lines': [], u'ansible_loop_var': u'item', u'end': u'2021-12-09 23:41:27.978177', u'stderr': u'', u'stdout': u'test abc', u'changed': True, u'failed': False, u'delta': u'0:00:00.007256', u'cmd': u'echo test abc', u'item': u'abc', u'rc': 0, u'invocation': {u'module_args': {u'warn': True, u'executable': None, u'_uses_shell': True, u'strip_empty_ends': True, u'_raw_params': u'echo test abc', u'removes': None, u'argv': None, u'creates': None, u'chdir': None, u'stdin_add_newline': True, u'stdin': None}}, u'stdout_lines': [u'test abc'], u'start': u'2021-12-09 23:41:27.970921'}) => {
    "msg": "Send out the message: test abc"
}
ok: [localhost] => (item={u'stderr_lines': [], u'ansible_loop_var': u'item', u'end': u'2021-12-09 23:41:28.148281', u'stderr': u'', u'stdout': u'test def', u'changed': True, u'failed': False, u'delta': u'0:00:00.007047', u'cmd': u'echo test def', u'item': u'def', u'rc': 0, u'invocation': {u'module_args': {u'warn': True, u'executable': None, u'_uses_shell': True, u'strip_empty_ends': True, u'_raw_params': u'echo test def', u'removes': None, u'argv': None, u'creates': None, u'chdir': None, u'stdin_add_newline': True, u'stdin': None}}, u'stdout_lines': [u'test def'], u'start': u'2021-12-09 23:41:28.141234'}) => {
    "msg": "Send out the message: test def"
}

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

总结

  • 理解Ansible循环任务的使用场景。
  • 运用loop与item编写循环任务。
  • 理解循环任务与注册变量的搭配。

阅读量:1796

点赞量:0

收藏量:0