简体   繁体   中英

Ansible: How to loop over registered output of dynamic hosts in the next task

I am struggling to loop over registered results.containers for all the hosts in the dynamic inventory.

Here is the code.

$cat collect.yaml 
---
- hosts: "{{ env }}"
  become: True
  tasks:
    - name: Get dockerinfo
        docker_host_info:
        containers: yes
      register: result
  
    - name: Debug dockerInfo
      debug:
        var: result.containers 

    - name: dynamic grouping
      add_host:
        name: "{{ item[0] }}"  
        groups: "{{ item[1].Image | regex_replace('.*?/(.*?):.*', '\\1') }}"
        container_name: '{{ item[1].Names[0] | regex_replace("^/", "") }}'
      with_nested: 
        -  "{{ ansible_play_batch }}"
        -  "{{ result.containers }}"

Here is result.containers output.

TASK [Debug dockerInfo]
ok: [vm1.nodekite.com] => {
"result.containers": [
{
    "Image": "ca.docker/webproxy:1.0.0",
    "Names": [
           "/customer1"
     ],
},
{
    "Image": "docker.local/egacustomer:1.0.1",
    "Names": [
           "/webproxy"
     ],
},
]}
ok: [vm2.nodekite.com ] => {
"result.containers": [
{
    "Image": "ca.docker/webproxy:1.0.0",
    "Names": [
           "/webproxyui"
     ],
},
{
    "Image": "cna-docker-local/lega-customer:1.0.1",
    "Names": [
           "/webproxy"
    ],
},
]}
ok: [vm3.nodekite.com ] => {
"result.containers": [
{
    "Image": "ca.docker/webproxy:1.0.0",
    "Names": [
           "/webproxy"
     ],
},
{
    "Image": "local.docker/saga-customer:1.0.1",
    "Names": [
           "/customerr
     ],
},
]}

Right now item[1].Image and item[1].Names[0] is only taken from first host's(vm1.nodekite.com) results.containers output. I would like to loop over for every hosts. So that, I could create dynamic group for all the hosts with their respective containers. With my code, hosts vm1,vm2,vm3 all are referring to vm1.nodekite.com's result.containers but i want the hosts to refer to their respective containers. Any help would be greatly appreciated.

I have update dynamic grouping task ouput for clarification.

changed: [vm1.nodekite.com] => {
"add_host": {
    "groups": [
        "webproxy"
    ],
    "host_name": "vm1.nodekite.com",
    "host_vars": {
    "container_name": "customer1" }
},
changed: [vm1.nodekite.com] => {
"add_host": {
    "groups": [
        "egacustomer"
    ],
    "host_name": "vm1.nodekite.com",
    "host_vars": {
    "container_name": "webproxy" }
},
changed: [vm2.nodekite.com] => {
"add_host": {
    "groups": [
        "webproxy"            >> this should be webproxy
    ],
    "host_name": "vm2.nodekite.com",
    "host_vars": {
    "container_name": "customer1" }     >> this should be webproxyui
},
changed: [vm2.nodekite.com] => {
"add_host": {
    "groups": [
        "egacustomer"           >> this should be lega-customer
    ],
    "host_name": "vm2.nodekite.com",
    "host_vars": {
    "container_name": "webproxy" }    >>  this should be webproxy
},

if you see vm2 is still referring to vm1's result.containers output.

when i try this...i get item not defined error.

   - name: adding it to groups using images
    add_host:
      name: "{{ item[0] }}"
      groups: "{{ item[1].Image | regex_replace('.*?/(.*?):.*', '\\1') }}"
      container_name: '{{ item[1].Names[0] | regex_replace("^/", "") }}'
    loop:
      -  "{{ ansible_play_batch }}"
      -  "{{ myresult.containers }}"
    vars:
      myresult: "{{ hostvars[item].result }}"
    run_once: true

Q: "Hosts shall refer to their respective containers."

A: Use hostvars. For example

    - name: dynamic grouping
      debug:
        msg:
        - "name: {{ item }}"
        - "groups: {{ my_result.containers|
                      map(attribute='Image')|
                      map('regex_replace', '.*?/(.*?):.*', '\\1')|
                      list }}"
        - "container_names: {{ my_result.containers|
                      map(attribute='Names')|
                      map('regex_replace', '\/', '')|
                      list }}"
      loop: "{{ ansible_play_batch }}"
      vars:
        my_result: "{{ hostvars[item].result }}"
      run_once: true

gives

ok: [vm1.nodekite.com] => (item=vm1.nodekite.com) => 
  msg:
  - 'name: vm1.nodekite.com'
  - 'groups: [''webproxy'', ''egacustomer'']'
  - 'container_names: ["[''customer1'']", "[''webproxy'']"]'
ok: [vm1.nodekite.com] => (item=vm2.nodekite.com) => 
  msg:
  - 'name: vm2.nodekite.com'
  - 'groups: [''webproxy'', ''lega-customer'']'
  - 'container_names: ["[''webproxyui'']", "[''webproxy'']"]'
ok: [vm1.nodekite.com] => (item=vm3.nodekite.com) => 
  msg:
  - 'name: vm3.nodekite.com'
  - 'groups: [''webproxy'', ''saga-customer'']'
  - 'container_names: ["[''webproxy'']", "[''customer'']"]'

(Feel free to fit the code to your needs.)

I was having an issue of getting the item passed into the name below to be a plain string of: item='nginx' and not item='[u'/nginx]'

To get around this, I did the following:

- name: Get docker containers
  become: docker
  community.docker.docker_container
    containers: yes
  register: docker_info

- name: Stop running containers
  become: docker
  community.docker.docker_container
    name: "{{ item }}"
    state: stopped
  loop: "{{ docker_info.containers | sum(attribute='Names', start=[]) | map('regex_replace','\\/','') | list }}"
  when: item in apps.split(,)

In this case the apps is a comma deliminated string variable I passed into the ansible playbook to limit which apps to stop.

The sum piece, flattens the Names of all the apps running into a single list.

The regex piece removes the / in the Names parameter

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM