Romain
Romain

Reputation: 192

Is there a way to insert raw escaped json in json body in ansible

See below first call which works. This is an example of how I create a template on my system. Notice I have to use {% raw %} ... {% endraw %} so ansible doesn't try to interpret the variables in my template.

    - name: Create a template : OK
      uri:
        url: https://{{ ip }}/api/v1/templates
        method: POST
        headers:
          Authorization: "{{ token }}"
          Content-Type: application/json
        body: |
          {
            "name": "{{ template_name }}",
            "type": "v1",
            "description": "{{ template_name }}",
            "content": "template: |  {% raw %}\n    {\n   \"class\": \"ABC\",\n      \"param\": {{param1::integer}}\n  }{% endraw %}"
          }
        body_format: json
        timeout: 60
        status_code: 202
        validate_certs: false
      register: json_response

Output OK:

    ok: [notahost] => {
        "invocation": {
            "module_args": {
                "body": {
                    "content": "template: |  \n    {\n   \"class\": \"ABC\",\n      \"param\": {{param1::integer}}\n  }", 
                    "description": "test1", 
                    "name": "test1", 
                    "type": "v1"
                }, 
                "body_format": "json", 

Now, I am trying to move the content of the template outside in a file called template1.j2.

template1.j2:

    {% raw %} 
    {
      "class": "ABC",
      "param": {{param1::integer}}
    } 
    {% endraw %}

I insert the template template1.j2 into my JSON body (noticed I added the {% raw %} ... {% endraw %} inside the template).

    - name: Create a template NOK
      uri:
        url: https://{{ ip }}/api/v1/templates
        method: POST
        headers:
          Authorization: "{{ token }}"
          Content-Type: application/json
        body: |
          {
            "name": "{{ template_name }}",
            "type": "v1",
            "description": "{{ template_name }}",
            "content": "template: | {{ lookup('file','template1.j2') }}"
          }
        body_format: json
        timeout: 60
        status_code: 202
        validate_certs: false
      register: json_response

Output NOK:

    fatal: [notahost]: FAILED! => {
        "content": "{\"message\":\"request body has an error: failed to decode request body: invalid character '\\\\n' in string literal\"}\n", 
        "invocation": {
            "module_args": {
                "body": "{\n  \"name\": \"test2\",\n  \"type\": \"v1\",\n  \"description\": \"test2\",\n  \"content\": \"template: |  \n{\n    \"class\": \"ABC\",\n    \"param\": {{param1::integer}}\n} \n\"\n}\n", 
                "body_format": "json", 

For some reason, it looks like the way I am doing this doesn't work, ansible still try to interpret the variable in my template at creation.

Any idea on how to get his work with my template outside the ansible task?

PS: I have tried to load the template file using the shell ansible module and that did not help.

Thanks & Regards, Romain

Upvotes: 2

Views: 1019

Answers (1)

Vladimir Botka
Vladimir Botka

Reputation: 68189

Use lookup 'file' instead of 'template', e.g. the template (that you actually don't want to use as a template in this task)

shell> cat template1.j2
param: {{param1.integer}}

and the play

- hosts: localhost
  vars:
    param1:
      integer: 99
  tasks:
    - debug:
        msg: |
          {{ lookup('template', 'template1.j2') }}
          {{ lookup('file', 'template1.j2') }}

gives

  msg: |-
    param: 99
  
    param: {{param1.integer}}

Given the template

shell> cat template1.j2
{
  "class": "ABC",
  "param": {{param1::integer}}
}

The play below shows how to create a body with and without the template

- hosts: localhost

  vars:
    template_name: test1

    body1: |
      {
      "name": "{{ template_name }}",
      "type": "v1",
      "description": "{{ template_name }}",
      "content": "template: |  {% raw %}\n    {\n   \"class\": \"ABC\",\n      \"param\": {{param1::integer}}\n  }{% endraw %}"
      }

    body2:
      {
      "name": "{{ template_name }}",
      "type": "v1",
      "description": "{{ template_name }}",
      "content": "template: |  \n{{ lookup('file','template1.j2') }}"
      }

  tasks:
    - debug:
        var: body1|type_debug
    - debug:
        var: body1
    - debug:
        var: body2|type_debug
    - debug:
        var: body2

gives

ok: [localhost] => 
  body1|type_debug: dict

ok: [localhost] => 
  body1:
    content: |-
      template: |
          {
         "class": "ABC",
            "param": {{param1::integer}}
        }
    description: test1
    name: test1
    type: v1
ok: [localhost] => 
  body2|type_debug: dict

ok: [localhost] => 
  body2:
    content: |-
      template: |
      {
        "class": "ABC",
        "param": {{param1::integer}}
      }
    description: test1
    name: test1
    type: v1

Upvotes: 1

Related Questions