Need to pass variable and hostname to a playbook from CSV file.

I have a CSV file that contains the IP’s and it’s variables.
I need to use the details to log in to the host and use the respective variable’s value of the specfic IP’s.

Please help me out with this.

cat AnsibleTest.csv

ip,var1,var2

10.1.1.1,rchantif1,mechlab
10.1.1.2,rchans01,contlab

My csv file looks like this and its called ip.csv:

ip,username,host

10.1.1.1,rchantif1,mechlab

10.1.1.2,rchans01,contlab

192.168.2.142,vagrant

I’m using the read_csv: module to access the data

What I did is create a playbook that prints what you are looking for the then I followed up on another task an example of logging into a host with the username and IP. I’m not 100% sure what you want to do but hopefully with the info I provided you have a start to your playbook/tasks.

---
- name: read items from csv and store as vars
  hosts: localhost
  become: false
  tasks:
    - name: read_csv
      read_csv:
        path: ip.csv
      register: ip
    - name: print csv items
      debug:
        msg: "{{ip.list.2.ip}} {{ip.list.2.username}} {{ip.list.2.host}}"
    - name:
      shell: "ssh {{ip.list.2.username}}@{{ip.list.2.ip}} 'ls -la'"

I have a CSV file that contains the IP's and it's variables.
I need to use the details to log in to the host and use the respective
variable's value of the specfic IP's.

# cat AnsibleTest.csv
ip,var1,var2
10.1.1.1,rchantif1,mechlab
10.1.1.2,rchans01,contlab

Read the the file and create new group of hosts in the first play. The use
the group in the second play. For example

cat playbook.yml

- hosts: localhost
  gather_facts: false
  tasks:
    - read_csv:
        path: AnsibleTest.csv
      register: myhosts
    - add_host:
        name: '{{ item.ip }}'
        groups: test_01
        var1: "{{ item.var1 }}"
        var2: "{{ item.var2 }}"
      loop: "{{ myhosts.list }}"

- hosts: test_01
  gather_facts: false
  tasks:
    - debug:
        msg:
          - "{{ inventory_hostname }}"
          - "{{ var1 }}"
          - "{{ var2 }}"

ansible-playbook playbook.yml

...
ok: [10.1.1.1] => {
    "msg": [
        "10.1.1.1",
        "rchantif1",
        "mechlab"
    ]
}
ok: [10.1.1.2] => {
    "msg": [
        "10.1.1.2",
        "rchans01",
        "contlab"
    ]
}

HTH,

  -vlado

thanks Vladimir, your suggestion helped a lot. Still, i am facing one challenge while using add_host. I have the csv file with the same server has different volumes. When i run the playbook, it is displaying last entry associated to the same but i would like to display all the entries. Can you suggest on the same?

cat mounts.csv

host,remote_path,mnt_path
host1,nfsvol1,mount1
host1,nfsvol2,mount2
host1,nfsvol3,mount3
host2,nfsvol1,mount1
host2,nfsvol2,mount2
host2,nfsvol3,mount3

cat mounts.yml

format your csv data file to inventory file as below. Then the variables can be used to the respective hosts directly.
Hope this helps.

Use sed and awk for formatting the inventory file from CSV file

sed ‘s/,/ /g’ mounts
awk -F’ ’ -vOFS=’ ’ ‘{ $2 = “remote_path=” $2 }2’ mounts
awk -F’ ’ -vOFS=’ ’ ‘{ $3 = “mnt_path=” $3 }3’ /tmp/mounts

cat mounts

host1 remote_path=nfsvol1 mnt_path=mount1
host1 remote_path=nfsvol2 mnt_path=mount2
host1 remote_path=nfsvol3 mnt_path=mount3
host2 remote_path=nfsvol1 mnt_path=mount1
host2 remote_path=nfsvol2 mnt_path=mount2
host2 remote_path=nfsvol3 mnt_path=mount3

Hi Pandu,

the playbook is working if the csv has single entry associated to the host, but same playbook is failing if the same host has multiple variables entries. I tried many ways by using inventory but no luck. Finally, i choose read_csv and add_host. If you have working example with inventory, can you please share with me?

cat mounts.csv [ working as expected]

host,remote_path,mnt_path
host1,nfsvol1,mount1
host2,nfsvol2,mount2
host3,nfsvol3,mount3

cat mounts.csv [ working, but it is considering last entry only]

host,remote_path,mnt_path
host1,nfsvol1,mount1
host1,nfsvol2,mount2
host1,nfsvol3,mount3
host2,nfsvol1,mount1
host2,nfsvol2,mount2
host2,nfsvol3,mount3

Regards,
Suresh

Initially, i tried your approach but engineer has to do more work to make the format as we are planning to use playbook for nfs volume migration. we have 1000’s of servers with 100’s volumes. Hence, the reason, we chosen the csv format. I have been using inventory based host connection but it is connecting even if volume is not required to mount/unmount on target host.

cat nfsvolmigration/roles/volmount/tasks/volmount.yml

... i would like to display all the entries.

# cat mounts.csv
host,remote_path,mnt_path
host1,nfsvol1,mount1
host1,nfsvol2,mount2
host1,nfsvol3,mount3
host2,nfsvol1,mount1
host2,nfsvol2,mount2
host2,nfsvol3,mount3

# cat mounts.yml
---
- name: mount the nfsshare in client side
  hosts: localhost
  gather_facts: false
  become: yes
  tasks:
    - name: reading volume info from csv
      read_csv:
        path: "{{ playbook_dir }}/mounts.csv"
      register: sources
      delegate_to: localhost
    - name: Grouping host and volume information
      add_host:
        name: "{{ item.host }}"
        groups: nfsgroup
        var1: "{{ item.remote_path }}"
        var2: "{{ item.mnt_path }}"
      loop: "{{ sources.list }}"

Use "groupby" filter. For example
https://jinja.palletsprojects.com/en/master/templates/#groupby

      add_host:
        name: "{{ item.0 }}"
        groups: nfsgroup
        var1: "{{ item.1|json_query('.remote_path') }}"
        var2: "{{ item.1|json_query('.mnt_path') }}"
      loop: "{{ sources.list|groupby('host') }}"

- name: list volume details
  hosts: nfsgroup
  become: yes
  gather_facts: false
  tasks:
    - debug:
        msg:
          - "{{ inventory_hostname }}"
          - "{{ var1 }}"
          - "{{ var2 }}"

You should receive lists of "remote_path" and "mnt_path" in var1 and var2
respectively.

ok: [host1] => {
    "msg": [
        "host1",
        [
            "nfsvol1",
            "nfsvol2",
            "nfsvol3"
        ],
        [
            "mount1",
            "mount2",
            "mount3"
        ]
    ]
}
ok: [host2] => {
    "msg": [
        "host2",
        [
            "nfsvol1",
            "nfsvol2",
            "nfsvol3"
        ],
        [
            "mount1",
            "mount2",
            "mount3"
        ]
    ]
}

HTH,

  -vlado

awesome, it really helped for my requirement. thank you so much Vladimir,

Regards,
Suresh

Hi Vladimir,

I have one more last question on the same request as we have different python interpreter on some hosts. Is it possible to read the python interpreter variable from CSV file while connecting the particular?
Prior to your solution, i use to use inventory to pass the variable to the host as below. Now, i want to omit inventory file as i would like to use your solution completely for host inventory. Can you please suggest same to overcome this problem other than declaring variables host_vars?

host4 ansible_python_interpreter=/usr/bin/python2.6

Regards,
Suresh

Hi Suresh,

Hi Vladimir,

I have one more last question on the same request as we have different
python interpreter on some hosts. Is it possible to read the python
interpreter variable from CSV file while connecting the particular?
Prior to your solution, i use to use inventory to pass the variable to the
host as below. Now, i want to omit inventory file as i would like to use
your solution completely for host inventory. Can you please suggest same to
overcome this problem other than declaring variables host_vars?

host4 ansible_python_interpreter=/usr/bin/python2.6

Regards,
Suresh

Yes. It's possible. Simply put the path to Python into the CSV file. For
example, put it into the first record of the particular host. Various paths
don't make sense. Right?

cat mounts.csv

host,remote_path,mnt_path,python
host1,nfsvol1,mount1,/usr/bin/python2.6
host1,nfsvol2,mount2
host1,nfsvol3,mount3
host2,nfsvol1,mount1,/usr/bin/python3.7
host2,nfsvol2,mount2
host2,nfsvol3,mount3

Then simply assign "ansible_python_interpreter in the first play

       add_host:
         name: "{{ item.0 }}"
         groups: nfsgroup
         var1: "{{ item.1|json_query('.remote_path') }}"
         var2: "{{ item.1|json_query('.mnt_path') }}"
         ansible_python_interpreter: "{{ item.1.0.python }}"
       loop: "{{ sources.list|groupby('host') }}"

(It's not necessary to delegate_to localhost when the play is running at
localhost "hosts: localhost").

HTH,
  vlado

Hi Vladimir, thanks for your help all the time.

I tried using the logic, and it worked when apply the values to debug but the same data is passing to mount module with additional quotes and brackets which is causing the errors. Any suggestions please?

Playbook and CSV details:

Would anyone please help me with this?

Regards,
Suresh

... to achieve my goal as iteration[*have multiple nfs volume in
CSV for each host*] is failing with add_host module due to *BYPASS_HOST_LOOP
= True* in module destination. ...
[...]
- name: list the volumes
  hosts: nfsgroup
  become: yes
  gather_facts: false
  tasks:
    - name: debug output
      debug:
        msg:
          - "{{ inventory_hostname }}"
          - "{{ var1 }}"
          - "{{ var2 }}"
[...]
- name: mounting the volume in the fstab file
  hosts: nfsgroup
  gather_facts: false
  become: yes
  tasks:
    - name: mounting the volume in the fstab file
      mount:
        fstype: nfs
        opts:
"rw,bg,hard,rsize=65536,wsize=65536,vers=3,actimeo=0,nointr,suid,timeo=600,tcp"
        dump: "0"
        passno: "0"
        src: "{{ var1[0] }}"
        path: "{{ var2[0] }}"
        state: mounted
      delegate_to: "{{ inventory_hostname }}"
...

delegate_to: "{{ inventory_hostname }}" is redundant.

Try "with_together"
https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#with-together

- name: mounting the volume in the fstab file
  hosts: nfsgroup
  gather_facts: false
  become: yes
  tasks:
    - name: mounting the volume in the fstab file
      mount:
        fstype: nfs
        ...
        src: "{{ item.1 }}"
        path: "{{ item.2 }}"
        state: mounted
      with_together:
        - "{{ var1 }}"
        - "{{ var2 }}"

Errata:

Awesome Vladimir, i just tried the solution that you have suggested. It’s working as per my requirement. Once again thank you so much.

Regards,
Suresh