首页 > 解决方案 > 如何为循环的每次迭代触发 Ansible Play

问题描述

下面注册的变量command_result从数据库中获取记录,这些记录可能是多行的。

下面帮助我遍历command_result变量中数据库的每条记录。

   - debug:
       msg: "This is a database line: {{ item }}"
     with_items: "{{ command_result.stdout_lines }}"

我现在需要的是为每个循环迭代以及相应的{{ item }}.

- hosts: "{{ item.stdout.split('\t')[0] }}"
  tasks:
    - name: Check if reboot is required
      shell: /home/ansible/scripts/check.sh "{{ item.stdout.split('\t')[1] }}"
      register: output

    - debug: var=output.stdout_lines

    - add_host: name={{ item }}
               groups=dest_nodes
               ansible_user={{ USER }}
     with_items: "{{ dest_ip.split(',') }}"

项目值将在每个循环中发生变化,并将被馈送到上面的播放中。

综上所述:如果数据库在{{ command_result.stdout_lines }}shell 模块中返回三个记录,那么 play 应该被调用三次,每个记录的详细信息{{ item }}分别在其中。

例如:数据库可以返回任意数量的行,假设它返回三行类型<listofhosts>\t<somearguments>::

host5,host8\targ1
host6,host2\targ3
host9,host3,host4\targ4

我需要的是循环with_items: {{ command_result.stdout_lines }}将运行三个播放,每个播放为该运行及其各自的参数构建主机列表的动态主机组。

所以:

希望这能让我的要求得到理解。

我正在使用最新版本的 Ansible。

标签: loopsansible

解决方案


您应该能够通过模块创建动态主机组来运行此类任务add_host

此外,为了满足每行有多个主机的要求,我们首先在模块的帮助下重新创建一个干净的列表set_fact
然后,使用新创建的列表,我们可以使用循环with_subelements来创建正确的元组(check_arg, host)

这是一个示例,我dynamic_hosts在 play 的变量中伪造了您的数据库输出:

---
- hosts: 127.0.0.1
  gather_facts: false
  connection: local
  vars:
    dynamic_hosts:
      - "host5,host8\targ1"
      - "host6,host2\targ3"
      - "host9,host3,host4\targ4"

  tasks:
    - debug:
        msg: "{{ dynamic_hosts }}"

    - name: Make a clean list out of the hosts and arguments
      set_fact:
         hosts: "{{ hosts | default([]) + [ {'hosts': item.split('\t')[0].split(','), 'check_arg': item.split('\t')[1]} ] }}"
      with_items: "{{ dynamic_hosts }}"

    - debug:
        msg: "{{ hosts }}"

    - name: Adding hosts to a dynamic group based on the faked database output stored in hosts
      add_host:
        name: "{{ item.1 }}"
        check_arg: "{{ item.0.check_arg }}"
        ansible_host: 127.0.0.1
        ansible_connection: local
        groups: nodes_to_run_on
      with_subelements:
        - "{{ hosts }}"
        - hosts

- hosts: nodes_to_run_on
  gather_facts: false
  tasks:
    - debug:
        msg: "Run the shell with the argument `{{ check_arg }}` here"

如您所见,我正在创建一个以nodes_to_run_on该剧第一部分命名的主机组,并借助add_host. 稍后,我将使用此主机组在该组中的所有主机上运行一组新任务。
这将是这个剧本的输出:

PLAY [127.0.0.1] **********************************************************************************************************************************

TASK [debug] **************************************************************************************************************************************
ok: [127.0.0.1] => {
    "msg": [
        "host5,host8\targ1",
        "host6,host2\targ3",
        "host9,host3,host4\targ4"
    ]
}

TASK [Make a clean list out of the hosts and arguments] ******************************************************************************************
ok: [127.0.0.1] => (item=host5,host8    arg1)
ok: [127.0.0.1] => (item=host6,host2    arg3)
ok: [127.0.0.1] => (item=host9,host3,host4  arg4)

TASK [debug] **************************************************************************************************************************************
ok: [127.0.0.1] => {
    "msg": [
        {
            "check_arg": "arg1",
            "hosts": [
                "host5",
                "host8"
            ]
        },
        {
            "check_arg": "arg3",
            "hosts": [
                "host6",
                "host2"
            ]
        },
        {
            "check_arg": "arg4",
            "hosts": [
                "host9",
                "host3",
                "host4"
            ]
        }
    ]
}

TASK [Adding hosts to a dynamic group based on the faked database output stored in hosts] *********************************************************
changed: [127.0.0.1] => (item=[{'check_arg': 'arg1'}, 'host5'])
changed: [127.0.0.1] => (item=[{'check_arg': 'arg1'}, 'host8'])
changed: [127.0.0.1] => (item=[{'check_arg': 'arg3'}, 'host6'])
changed: [127.0.0.1] => (item=[{'check_arg': 'arg3'}, 'host2'])
changed: [127.0.0.1] => (item=[{'check_arg': 'arg4'}, 'host9'])
changed: [127.0.0.1] => (item=[{'check_arg': 'arg4'}, 'host3'])
changed: [127.0.0.1] => (item=[{'check_arg': 'arg4'}, 'host4'])

PLAY [nodes_to_run_on] ****************************************************************************************************************************

TASK [debug] **************************************************************************************************************************************
ok: [host5] => {
    "msg": "Run the shell with the argument `arg1` here"
}
ok: [host8] => {
    "msg": "Run the shell with the argument `arg1` here"
}
ok: [host6] => {
    "msg": "Run the shell with the argument `arg3` here"
}
ok: [host2] => {
    "msg": "Run the shell with the argument `arg3` here"
}
ok: [host9] => {
    "msg": "Run the shell with the argument `arg4` here"
}
ok: [host3] => {
    "msg": "Run the shell with the argument `arg4` here"
}
ok: [host4] => {
    "msg": "Run the shell with the argument `arg4` here"
}

PLAY RECAP ****************************************************************************************************************************************
127.0.0.1                  : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host2                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host3                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host4                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host5                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host6                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host8                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host9                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  

请注意:这不是我们在此处创建的真正DRY主机列表,但它使解决方案保持幼稚,并且更符合KISS原则。

我们最终在这里生成的库存如下所示:

## kiss.yml ## lots of repetition
nodes_to_run_on:
  hosts:
    host5:
      check_arg: arg1
      ansible_host: 127.0.0.1
      ansible_connection: local
    host8:
      check_arg: arg1
      ansible_host: 127.0.0.1
      ansible_connection: local
    host6:
      check_arg: arg3
      ansible_host: 127.0.0.1
      ansible_connection: local
    host2:
      check_arg: arg3
      ansible_host: 127.0.0.1
      ansible_connection: local
    host9:
      check_arg: arg4
      ansible_host: 127.0.0.1
      ansible_connection: local
    host3:
      check_arg: arg4
      ansible_host: 127.0.0.1
      ansible_connection: local
    host4:
      check_arg: arg4
      ansible_host: 127.0.0.1
      ansible_connection: local

当它绝对可以干燥到

## dry.yaml ## no repetition with the help of group variables
nodes_to_run_on:
  vars:
    ansible_host: 127.0.0.1
    ansible_connection: local
  children:
    with_arg1:
      hosts:
        host5:
        host8:
      vars:
        check_arg: arg1
    with_arg3:
      hosts:
        host6:
        host2:
      vars:
        check_arg: arg3
    with_arg4:
      hosts:
        host9:
        host3:
        host4:
      vars:
        check_arg: arg4

考虑一下这出戏中的那两个:

---
- hosts: nodes_to_run_on
  gather_facts: false
  tasks:
    - debug:
        msg: "Run the shell with the argument `{{ check_arg }}` here"

kiss.yml

$ ansible-playbook example.yml --inventory=kiss.yml

PLAY [nodes_to_run_on] ****************************************************************************************************************************

TASK [debug] **************************************************************************************************************************************
ok: [host5] => {
    "msg": "Run the shell with the argument `arg1` here"
}
ok: [host8] => {
    "msg": "Run the shell with the argument `arg1` here"
}
ok: [host6] => {
    "msg": "Run the shell with the argument `arg3` here"
}
ok: [host2] => {
    "msg": "Run the shell with the argument `arg3` here"
}
ok: [host9] => {
    "msg": "Run the shell with the argument `arg4` here"
}
ok: [host3] => {
    "msg": "Run the shell with the argument `arg4` here"
}
ok: [host4] => {
    "msg": "Run the shell with the argument `arg4` here"
}

PLAY RECAP ****************************************************************************************************************************************
host2                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host3                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host4                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host5                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host6                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host8                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host9                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  

dry.yml

$ ansible-playbook example.yml --inventory=dry.yml

PLAY [nodes_to_run_on] ****************************************************************************************************************************

TASK [debug] **************************************************************************************************************************************
ok: [host5] => {
    "msg": "Run the shell with the argument `arg1` here"
}
ok: [host8] => {
    "msg": "Run the shell with the argument `arg1` here"
}
ok: [host6] => {
    "msg": "Run the shell with the argument `arg3` here"
}
ok: [host2] => {
    "msg": "Run the shell with the argument `arg3` here"
}
ok: [host9] => {
    "msg": "Run the shell with the argument `arg4` here"
}
ok: [host3] => {
    "msg": "Run the shell with the argument `arg4` here"
}
ok: [host4] => {
    "msg": "Run the shell with the argument `arg4` here"
}

PLAY RECAP ****************************************************************************************************************************************
host2                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host3                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host4                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host5                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host6                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host8                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host9                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0    

因此,您可以看到,当库存为 30行时,我们使用dry.yml24 行的库存实现了相同的效果。kiss.yml

但最终创造一个 DRY 的发明者的努力并不会真正付出代价,如果来源是,无论哪种方式,来自一个可以生成主机列表的数据库。


推荐阅读