Loop through ansible_play_batch repeats output

Viewed 125

I am trying to loop through ansible_play_batch and get the server build date information from a csv server inventory file using the inventory_hostname. The problem is that it assigns the same date to all the servers and repeats the loop again to display the next server build date. Any suggestion on how to fix to show the correct information once.

Thank you

Server Inventory

serverA,,,,2019-04-24 19:57:34
serverB,,,,2019-04-26 19:47:01
serverC,,,,2020-08-20 23:30:25

Hosts

serverA
serverB
serverC

Task

- name: List Server in current play
  debug:
    msg: "Item is {{ item }} Build date {{ lookup('csvfile', item + ' file=serverInventory.csv delimiter=, col=5') }}"
  loop: "{{ ansible_play_batch }}"

Run

[serverMain]# ansible-playbook -i hosts_svrbuild  site.yml 

PLAY [Set_Up] ************************************************************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************************************************************
ok: [serverA]
ok: [serverB]
ok: [serverC]

TASK [common : List Server in current play] ******************************************************************************************************************
ok: [serverA] => (item=serverA) => {
    "msg": "Item is serverA Build date 2019-04-24 19:57:34"
}
ok: [serverB] => (item=serverA) => {
    "msg": "Item is serverA Build date 2019-04-24 19:57:34"
}
ok: [serverC] => (item=serverA) => {
    "msg": "Item is serverA Build date 2019-04-24 19:57:34"
}
ok: [serverB] => (item=serverB) => {
    "msg": "Item is serverB Build date 2019-04-26 19:47:01"
}
ok: [serverA] => (item=serverB) => {
    "msg": "Item is serverB Build date 2019-04-26 19:47:01"
}
ok: [serverC] => (item=serverB) => {
    "msg": "Item is serverB Build date 2019-04-26 19:47:01"
}
ok: [serverB] => (item=serverC) => {
    "msg": "Item is serverC Build date 2020-08-20 23:30:25"
}
ok: [serverA] => (item=serverC) => {
    "msg": "Item is serverC Build date 2020-08-20 23:30:25"
}
ok: [serverC] => (item=serverC) => {
    "msg": "Item is serverC Build date 2020-08-20 23:30:25"
}

PLAY RECAP ***************************************************************************************************************************************************
serverA             : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
serverC             : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
serverB             : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
3 Answers

There is no need to loop here in your task as you already have the natural play loop:

- name: List Server in current play
  debug:
    msg: "Current server is {{ inventory_hostname }} Build date {{ lookup('csvfile', inventory_hostname + ' file=serverInventory.csv delimiter=, col=5') }}"

For example,

- hosts: serverA,serverB,serverC
  gather_facts: false
  tasks:
    - debug:
        msg: "Item is {{ item }}
              Build date {{ lookup('csvfile',
                                   item,
                                   file='serverInventory.csv',
                                   delimiter=',',
                                   col=4) }}"
      loop: "{{ ansible_play_batch }}"
      run_once: true

gives

PLAY [serverA,serverB,serverC] ***************************************************************

TASK [debug] *********************************************************************************
ok: [serverA] => (item=serverA) => 
  msg: Item is serverA Build date 2019-04-24 19:57:34
ok: [serverA] => (item=serverB) => 
  msg: Item is serverB Build date 2019-04-26 19:47:01
ok: [serverA] => (item=serverC) => 
  msg: Item is serverC Build date 2020-08-20 23:30:25

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

Without the iteration, the task below

    - debug:
        msg: "Item is {{ inventory_hostname }}
              Build date {{ lookup('csvfile',
                                   inventory_hostname,
                                   file='serverInventory.csv',
                                   delimiter=',',
                                   col=4) }}"

gives the same messages

TASK [debug] *********************************************************************************
ok: [serverA] => 
  msg: Item is serverA Build date 2019-04-24 19:57:34
ok: [serverB] => 
  msg: Item is serverB Build date 2019-04-26 19:47:01
ok: [serverC] => 
  msg: Item is serverC Build date 2020-08-20 23:30:25

I would suggest leveraging Python split function instead of the csv plugin:

Code:

  - name: List Server in current play
    debug:
      msg: "Item is {{ item.split(',')[0] }} Build date: {{ item.split(',')[-1] }}"
    with_lines: cat servers.csv

Explanation:

Iterating over the file one line at a time. The Python split function using comma to split a line into a list of tokens. The first token(accessed with index of 0) is the server name, the last token (and I assume date is the last field in your file that contains no commas) is addressed with index of -1

Output:

TASK [List Server in current play] *********************************************
ok: [localhost] => (item=serverA,,,,2019-04-24 19:57:34) => {
    "msg": "Item is serverA Build date: 2019-04-24 19:57:34"
}
ok: [localhost] => (item=serverB,,,,2019-04-26 19:47:01) => {
    "msg": "Item is serverB Build date: 2019-04-26 19:47:01"
}
ok: [localhost] => (item=serverC,,,,2020-08-20 23:30:25) => {
    "msg": "Item is serverC Build date: 2020-08-20 23:30:25"
}
Related