Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing Bash Array in Yaml

Tags:

bash

yaml

ansible

In ansible playbook, I have to read one yaml file which contains the data like:

john: stu001
bob: stu002
william: stu003

This data is dynamic, there can be number of students with their ids. I want to read this yaml in my ansible play and needs the output like :

---
- name: Students Data
  hosts: localhost
  tasks:
  - include_vars:
        file: tmp/stuData.yml
        name: stuName
  - name: "Students Details"
    uri:
      url: "{{ some_api_server }}"
      return_content: yes
      body_format: json
      method: POST
      body:
         matchers:
           - name: john
             id: stu001
             age: NA
           - name: bob
             id: stu002
             age: NA
           - name: william
             id: stu003
             age: NA
         startsAt: "{{ st_time }}"
         endsAt: "{{ en_time }}"
         createdBy: [email protected]

I have tried the following code for it:

---
- name: Students Data
  hosts: localhost
  tasks:
  - include_vars:
        file: tmp/stuData.yml
        stuName: stuName
  - name: "Students Details"
    uri:
      url: "{{ some_api_server }}"
      return_content: yes
      body_format: json
      method: POST
      body:
         matchers:
         {% for k,v in stuName.items() %}
           - name: {{ k }}
             id: {{ v }}
             age: "NA"   
         {% endfor %}
         startsAt: "{{ st_time }}"
         endsAt: "{{ en_time }}"
         createdBy: [email protected]

This is giving me syntax error in line after matchers. Can anyone please help me in writing the correct code.

like image 713
Aadhi Verma Avatar asked Apr 01 '26 04:04

Aadhi Verma


1 Answers

Create a simple script that writes the hashes, e.g.

shell> cat /tmp/xyz.sh 
#!/bin/bash
declare -A animals=(["moo"]="cow" ["woof"]="dog")
for i in "${!animals[@]}"; do
    echo "$i: ${animals[$i]}"
done

gives

shell> /tmp/xyz.sh 
woof: dog
moo: cow

Then the task

    - set_fact:
        xyz: "{{ lookup('pipe', '/tmp/xyz.sh')|from_yaml }}"

creates the dictionary

  xyz:
    moo: cow
    woof: dog

Now you can format the data to any structure, e.g.

    - set_fact:
        matchers: "{{ xyz|dict2items }}"

gives the list matchers

  matchers:
  - key: woof
    value: dog
  - key: moo
    value: cow

You can change the names of the attributes, e.g.

    - set_fact:
        matchers: "{{ xyz|dict2items(key_name='name', value_name='value') }}"

gives

  matchers:
  - name: woof
    value: dog
  - name: moo
    value: cow

Then, you can add the attribute name and put it into a list, e.g.

    - set_fact:
        _list: "{{ [{'name': 'xyz', 'matchers': matchers}] }}"

gives the structure you're looking for

  _list:
  - matchers:
    - key: woof
      value: dog
    - key: moo
      value: cow
    name: xyz

Q: "Pass this animal variable to yaml file"

A: Use copy, e.g.

    - copy:
        dest: /tmp/xyz.yml
        content: |
          - name: xyz
            matchers:
          {% for k,v in xyz.items() %}
              - name: {{ k }}
                value: {{ v }}
          {% endfor %}

gives

shell> cat /tmp/xyz.yml 
- name: xyz
  matchers:
    - name: woof
      value: dog
    - name: moo
      value: cow

, or you can use the created list, e.g.

    - copy:
        dest: /tmp/xyz.yml
        content: "{{ _list|to_yaml }}"

gives

shell> cat /tmp/xyz.yml 
- matchers:
  - {key: woof, value: dog}
  - {key: moo, value: cow}
  name: xyz

, or you can improve the format by the filter to_nice_yaml, e.g.

    - copy:
        dest: /tmp/xyz.yml
        content: "{{ _list|to_nice_yaml }}"

gives

shell> cat /tmp/xyz.yml 
-   matchers:
    -   key: woof
        value: dog
    -   key: moo
        value: cow
    name: xyz

Q: "Flow of the code is like firstly sh file will be executed that will call play."

A: There is practically no difference. Read the file instead of running the command in the pipe lookup, e.g.

shell> /tmp/xyz.sh > /tmp/xyz.txt
shell> cat /tmp/xyz.txt
woof: dog
moo: cow

Then the task

    - set_fact:
        xyz: "{{ lookup('file', '/tmp/xyz.txt')|from_yaml }}"

creates the same dictionary

  xyz:
    moo: cow
    woof: dog
like image 165
Vladimir Botka Avatar answered Apr 02 '26 17:04

Vladimir Botka