11

I've got a task (actually a role, but using a task here to make the example easier) that I don't own which does some operations on a variable. It assumes the variable is an integer. I need to somehow pass it a variable and have it come through as an int, and I'm not having any luck.

Here is a super simplified version of the task that I don't own:

frob.yml

- name: Validate that frob_count is <= 100
  fail: msg="{{frob_count}} is greater than 100"
  when: frob_count > 100

- name: Do real work
  debug: msg="We frobbed {{frob_count}} times!"

My playbook is:

- name: Frob some things
  hosts: localhost
  vars:
    things:
      - parameter: 1
      - parameter: 2
      - parameter: 45
  tasks:
    - with_items: "{{things}}"
      include: frob.yml
      vars:
        frob_count: "{{item.parameter}}"

No matter what, I get errors like "1 is greater than 100" from frob.yml. Looks like it's getting the var as a string instead of an integer.

I've tried stuff like frob_count: "{{item.parameter | int}}" with no luck. If I could change frob.yml it'd be easy, but like I said, that's out of my control. Any thoughts?

This is on Ansible 2.6.4

techraf
  • 64,883
  • 27
  • 193
  • 198
Joe
  • 3,827
  • 1
  • 25
  • 37

3 Answers3

20

Solution

  1. Upgrade to Ansible 2.7 (currently available as the stable-2.7 branch, scheduled for GA on Oct. 4th, 2018).

  2. Add jinja2_native=True to the [defaults] section of the ansible.cfg (or set an environment variable ANSIBLE_JINJA2_NATIVE=True.

  3. Leave your code as in the question (i.e., frob_count: "{{item.parameter}}").

The result:

TASK [Do real work] **********************************************************************************************************************
ok: [localhost] => {
    "msg": "We frobbed 1 times!"
}

TASK [Validate that frob_count is <= 100] ************************************************************************************************
skipping: [localhost]

TASK [Do real work] **********************************************************************************************************************
ok: [localhost] => {
    "msg": "We frobbed 2 times!"
}

TASK [Validate that frob_count is <= 100] ************************************************************************************************
skipping: [localhost]

TASK [Do real work] **********************************************************************************************************************
ok: [localhost] => {
    "msg": "We frobbed 45 times!"
}

Explanation

Currently any value returned by Jinja2 template is a string, so even if you used the int filter inside (as in {{item.parameter | int}}) the output is always rendered to a string by Ansible.

Ansible 2.7 will use (with the above parameter) a feature of Jinja 2.10 called Native Python Types and retain the data type.

techraf
  • 64,883
  • 27
  • 193
  • 198
  • Sounds like I'll have to hope my organization adopts 2.7 quickly, or make a PR to the troublesome script and cross my fingers. Ah well. Thanks! – Joe Sep 25 '18 at 13:11
  • Perfect, this is a proper workaround for Ansible issue https://github.com/ansible/ansible/issues/17992 – lexadler Jul 15 '20 at 09:21
0

When you send the variable with that include task, it turns into unicode even forcing int on your playbook. So you need to use the int filter on frob.yml like this:

frob.yml

- name: Validate that frob_count is <= 100
  fail: msg="{{frob_count}} is greater than 100"
  when: frob_count|int > 100
Kelson Silva
  • 512
  • 2
  • 9
  • Yeah, but in my scenario I can't edit the task. Furthermore, passing an int literal (like `frob_count: 5`) works just fine – Joe Sep 24 '18 at 21:33
  • Hm, based on https://github.com/ansible/ansible/issues/9362 and https://github.com/pallets/jinja/pull/708 it sounds like this is a Jinja issue... – Joe Sep 24 '18 at 21:34
  • 1
    @KelsonSilva "*When you send the variable with that `include` task, it turns into unicode*" -- wrong. You can replace `include` with `debug: msg={{ frob_count | type_debug }}` and you'll see the type is Unicode. `include`/"*sending*" (whatever it means) is not the reason. And OP clearly said they have no control over `frob.yml`. – techraf Sep 24 '18 at 22:07
  • @techraf I see... Thank you for that explanation, my understanding was wrong about that... I appreciate! – Kelson Silva Sep 25 '18 at 13:14
-2

I found a solution that seems to work and it doesn't require the ANSIBLE_JINJA2_NATIVE=True env variable

If instead of

initialDelaySeconds: "{{ _initialDelaySeconds }}"

you do

initialDelaySeconds: |
    {{ _initialDelaySeconds }}

you can omit the " in the jinja template and the value is not converted to string!

miguel_rdp
  • 17
  • 3