1

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

Romain
  • 172
  • 10

1 Answers1

1

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
Vladimir Botka
  • 58,131
  • 4
  • 32
  • 63
  • Thanks Vladimir! (sorry for the spam, I did not know you have to keep the answer to the comments short and without formating). This works but my problem then is when the template is a JSON payload I am trying to insert raw in the JSON in the body of the URI POST. When I do the lookup(file...), the json inserted gets interpreted and "merge" with the JSON in the body of the URI call if that makes sense. – Romain Aug 31 '21 at 20:17
  • This works!!!! The trick was really to build the body outside the POST call in the URI module, and doing the way you are showing in your example works perfectly. Thank you so much again! – Romain Sep 01 '21 at 02:13