fengye87
fengye87

Reputation: 2553

Add a new key-value to a json file using Ansible

I'm using Ansible to automate some configuration steps for my application VM, but having difficult to insert a new key-value to an existing json file on the remote host.

Say I have this json file:

{
  "foo": "bar"
}

And I want to insert a new key value pair to make the file become:

{
  "foo": "bar",
  "hello": "world"
}

Since json format is not line based, I'm excluding lineinfile module from my options. Also, I would prefer not to use any external modules. Google keeps giving me examples to show how to read json file, but nothing about change json values and write them back to file. Really appreciate your help please!

Upvotes: 35

Views: 33615

Answers (4)

juge
juge

Reputation: 41

For people who are OK with custom ansible modules: https://github.com/ParticleDecay/ansible-jsonpatch works great!

With this you can simply do:

- name: append key/values
  json_patch:
    src: /tmp/var.json
    operations:
      - op: add
        path: "/hello"
        value: "world"
    pretty: yes
    create: yes

Upvotes: 4

Herve Nicol
Herve Nicol

Reputation: 111

ilias-sp's solution is great!

In my case, it lacked the case when we may have to create a base json file. So I had to add this task in the beginning of the play:

- name: Ensure json file exists
copy:
  content: "{}"
  dest: /tmp/var.json
  force: false

Upvotes: 4

Rich Nahra
Rich Nahra

Reputation: 1

 - name: update log
    copy:
      content: "{{ log | to_nice_json}}"
      dest: "{{ log_file }}"
    vars:
      log: "{{ (lookup('file', log_file) | from_json) + ([{'job': (build_id if build_id != '' else 'dev'), 'keystore': ks, 'timestamp': ansible_date_time.iso8601}]) }}"
      log_file: log/log.json
      build_id: "{{ lookup('ENV', 'BUILD_ID') }}"
    tags: log

Upvotes: -1

ilias-sp
ilias-sp

Reputation: 6705

since the file is of json format, you could import the file to a variable, append the extra key:value pairs you want, and then write back to the filesystem.

here is a way to do it:

---
- hosts: localhost
  connection: local
  gather_facts: false
  vars:

  tasks:
  - name: load var from file
    include_vars:
      file: /tmp/var.json
      name: imported_var

  - debug:
      var: imported_var

  - name: append more key/values
    set_fact:
      imported_var: "{{ imported_var | default([]) | combine({ 'hello': 'world' }) }}"

  - debug:
      var: imported_var

  - name: write var to file
    copy: 
      content: "{{ imported_var | to_nice_json }}" 
      dest: /tmp/final.json

UPDATE:

as OP updated, the code should work towards remote host, in this case we cant use included_vars or lookups. We could use the slurp module.

NEW code for remote hosts:

---
- hosts: greenhat
  # connection: local
  gather_facts: false
  vars:

  tasks:
  - name: load var from file
    slurp:
      src: /tmp/var.json
    register: imported_var

  - debug:
      msg: "{{ imported_var.content|b64decode|from_json }}"

  - name: append more key/values
    set_fact:
      imported_var: "{{ imported_var.content|b64decode|from_json | default([]) | combine({ 'hello': 'world' }) }}"

  - debug:
      var: imported_var

  - name: write var to file
    copy: 
      content: "{{ imported_var | to_nice_json }}" 
      dest: /tmp/final.json

hope it helps

Upvotes: 48

Related Questions