139

I am pulling JSON via the URI module and want to write the received content out to a file. I am able to get the content and output it to the debugger so I know the content has been received, but I do not know the best practice for writing files.

Keith Adler
  • 20,880
  • 28
  • 119
  • 189

4 Answers4

255

An important comment from tmoschou:

As of Ansible 2.10, The documentation for ansible.builtin.copy says:
If you need variable interpolation in copied files, use the
ansible.builtin.template module. Using a variable in the content
field will result in unpredictable output.

For more details see this and an explanation


Original answer:

You could use the copy module, with the content parameter:

- copy: content="{{ your_json_feed }}" dest=/path/to/destination/file

The docs here: copy module

Ramon de la Fuente
  • 8,044
  • 3
  • 32
  • 31
  • 8
    content="{{ your_json_feed }}" deals with whitespace and newlines. The quotes are important. – m.kocikowski Jan 23 '15 at 19:21
  • @RamondelaFuente If I would like to add multiple vars content to the file, I need to use "copy" module multiple times or is there any other way? – Kishore Reddy Jun 29 '16 at 05:37
  • 1
    @KishoreReddy I imagine you can use the jinja2 syntax to append variables. Something like "{{ variable ~ another_variable }}". Not pretty, but if things get any more complicated you could use the `template:` module and fill it with the variables registered at runtime. – Ramon de la Fuente Jun 30 '16 at 12:16
  • This works better when you want to generate a sha256 sum file in the form `shahash /path/to/file` (note 2 spaces between) and then validate from the command line (via `sha256sum -c shafile` ) what you generated via Ansible. – Daniel Andrei Mincă Mar 23 '17 at 14:49
  • 6
    As of Ansible 2.10, The documentation for `ansible.builtin.copy` says: _If you need variable interpolation in copied files, use the `ansible.builtin.template` module. Using a variable in the `content` field will result in unpredictable output._ For more details see https://github.com/ansible/ansible/issues/50580 and an explanation at https://github.com/ansible/ansible/issues/34595#issuecomment-356091161 – tmoschou Jan 06 '21 at 01:37
  • I found this answer because I was looking for a way to upload a file from an encrypted vault. Turns out, `ansible.builtin.copy` can [directly decrypt and upload](https://docs.ansible.com/ansible/latest/user_guide/vault.html#when-are-encrypted-files-made-visible) a file! – iliis Dec 27 '21 at 19:41
  • For human-readable output, I recommend also using `to_nice_json` filter, for example, ```content="{{ your_json_feed | to_nice_json }}"``` – zegoat7 Jan 19 '22 at 11:09
22

Based on Ramon's answer I run into an error. The problem where spaces in the JSON I tried to write I got it fixed by changing the task in the playbook to look like:

- copy:
    content: "{{ your_json_feed }}"
    dest: "/path/to/destination/file"

As of now I am not sure why this was needed. My best guess is that it had something to do with how variables are replaced in Ansible and the resulting file is parsed.

Tobias Kremer
  • 1,531
  • 2
  • 15
  • 21
  • Honestly, I found this to be the most helpful correct answer as it's good syntax for playbooks; although I generally add "- name: ..." to my playbook tasks. – Josh Apr 07 '23 at 18:17
22

Unless you are writing very small files, you should probably use templates.

Example:

- name: copy upstart script
  template: 
    src: myCompany-service.conf.j2 
    dest: "/etc/init/myCompany-service.conf"
4wk_
  • 2,458
  • 3
  • 34
  • 46
Janus Troelsen
  • 20,267
  • 14
  • 135
  • 196
  • 2
    While Ramon's answer addresses exactly what was asked, this answer is the best approach in general. For example, if you have a playbook that creates VMs in the cloud and you would like to generate an inventory of hosts for another playbook, a template is the way to go. – Luis Artola Jul 10 '16 at 08:00
  • Can you explain why this is better? – Vorticity Feb 26 '20 at 19:39
  • @Vorticity better than what? – Janus Troelsen Feb 26 '20 at 19:45
  • @JanusTroelsen Sorry, can you explain why this is better than the accepted answer when writing large files? – Vorticity Feb 26 '20 at 19:48
  • 1
    @Vorticity because it becomes unwieldy when you have a file embedded in another file. you need escaping and syntax highlighting won't work. the templating mechanism enables inserting things in the middle if you need that. – Janus Troelsen Feb 26 '20 at 23:07
  • This does not really answers how to write a _variable_ to a file. Templates do not cut it because for each variable you will need a different template (with that exact variable), which, if all you need is to write a variable to a file feels ridiculous. – Andrew Savinykh Jul 14 '22 at 07:18
2

We can directly specify the destination file with the dest option now. In the below example, the output json is stored into the /tmp/repo_version_file

- name: Get repository file repo_version model to set ambari_managed_repositories=false
  uri:
    url: 'http://<server IP>:8080/api/v1/stacks/HDP/versions/3.1/repository_versions/1?fields=operating_systems/*'
    method: GET
    force_basic_auth: yes
    user: xxxxx
    password: xxxxx
    headers:
      "X-Requested-By": "ambari"
      "Content-type": "Application/json"
    status_code: 200
    dest: /tmp/repo_version_file
Xavier Lowmiller
  • 1,381
  • 1
  • 15
  • 24
venkata
  • 447
  • 3
  • 15