JavaSeeker
JavaSeeker

Reputation: 53

How to replace value for a key in a json file using ansible

Below is my sample.json file

 "abc": {
                "host": "xyz",
                "version": "3.0.0-4"
        },
 "def": {               
                "host": "xyz",
                "version": "3.0.0-4"
        },
 "ghi": {
                "host": "xyz",
                "version": "4.1.0-4"
        },

How to modify value of version key for some of the blocks and not modify for other blocks? For eg. in above case I want to modify version value for abc and def block but not for ghi block using ansible.

Expected o/p :

 "abc": {
                "host": "xyz",
                "version": "4.0.0-4"  // modified value
        },
 "def": {               
                "host": "xyz",
                "version": "4.0.0-4"  // modified value
        },
 "ghi": {
                "host": "xyz",
                "version": "4.1.0-4"  //not modified
        },

Upvotes: 0

Views: 3940

Answers (2)

Vladimir Botka
Vladimir Botka

Reputation: 68254

  • Read the JSON data into a dictionary. For example,
    - include_vars:
        file: sample.json
        name: sample

gives

  sample:
    abc:
      host: xyz
      version: 3.0.0-4
    def:
      host: xyz
      version: 3.0.0-4
    ghi:
      host: xyz
      version: 4.1.0-4
  • To change the version of items abc and def some structure is needed. For example, let's create a dictionary of the new versions
  new_version:
    abc: 4.0.0-4
    def: 4.0.0-4

Then the task below

    - set_fact:
        sample: "{{ sample|
                    combine({item.key: item.value|
                    combine({'version': new_version[item.key]})}) }}"
      loop: "{{ sample|dict2items }}"
      when: item.key in new_version
      vars:
        new_version:
          abc: 4.0.0-4
          def: 4.0.0-4

gives

  sample:
    abc:
      host: xyz
      version: 4.0.0-4
    def:
      host: xyz
      version: 4.0.0-4
    ghi:
      host: xyz
      version: 4.1.0-4

Note: It is not necessary to iterate set_fact. Instead, create the dictionary

  update: "{{ new_version|
              dict2items|
              json_query('[].{key: key, value: {version: value}}')|
              items2dict }}"

gives

  update:
    abc:
      version: 4.0.0-4
    def:
      version: 4.0.0-4

Then, recursively combine the dictionaries

  sample_update: "{{ sample|combine(update, recursive=true) }}"

gives the same result

  sample_update:
    abc:
      host: xyz
      version: 4.0.0-4
    def:
      host: xyz
      version: 4.0.0-4
    ghi:
      host: xyz
      version: 4.1.0-4

  • The logic of the task might be different. For example "Change the lower versions only". In this case, the data and code are simpler, e.g.
        new_version: "4.0.0-4"

The task below gives the same result

    - set_fact:
        sample: "{{ sample|combine({item.key: item.value|
                           combine({'version': new_version})}) }}"
      loop: "{{ sample|dict2items }}"
      when: item.value.version is version(new_version, 'lt')
      vars:
        new_version: "4.0.0-4"

Then, replace the file, e.g.

    - copy:
        dest: sample.json
        content: "{{ sample|to_json }}"

gives

shell> cat sample.json

{"abc": {"host": "xyz", "version": "4.0.0-4"}, "def": {"host": "xyz", "version": "4.0.0-4"}, "ghi": {"host": "xyz", "version": "4.1.0-4"}}

Upvotes: 2

vtolentino
vtolentino

Reputation: 784

Here is a small function which takes as arguments:

  • obj: Json object
  • keys: Array of keys affected
  • prop: The property to be changed
  • value: The new value of the property

let myObj = {
  "abc": { "host": "xyz", "version": "3.0.0-4" }, 
  "def": { "host": "xyz", "version": "3.0.0-4" }, 
  "ghi": { "host": "xyz", "version": "4.1.0-4" }
}


const repla = (obj, keys, prop, value) => {
  return Object.keys(obj).map((key) => {
    if(keys.indexOf(key) > -1) {
      return {[key]: {...obj[key], [prop] : value}}
    } else {
      return {[key] : obj[key]};
    }
  })
}

const newObj = repla(myObj, ["abc", "def"], "version", "newData");
console.log(newObj)

Upvotes: 0

Related Questions