# Casting a variable as an integer

**URL:** <https://forum.ansible.com/t/casting-a-variable-as-an-integer/29236>\
**Category:** Ansible Project\
**Tags:** aws\
**Created:** [December 10, 2018, 10:26pm UTC](https://forum.ansible.com/t/casting-a-variable-as-an-integer/29236 "2018-12-10T22:26:53Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Stuart\_Longland](https://avatars.discourse-cdn.com/v4/letter/s/ecc23a/32.png) [@Stuart\_Longland](https://forum.ansible.com/u/Stuart_Longland)\
**Post date:** [December 10, 2018, 10:26pm UTC](https://forum.ansible.com/t/casting-a-variable-as-an-integer/29236/1 "2018-12-10T22:26:53Z")

</div>

Hi all,

I ran into a problem yesterday trying to set up a AWS instance via an  
Ansible playbook. I'm running Ansible 2.7.1 on Gentoo (AMD64).

I have a host variable, `volume_size`, which is the size of the volume  
in GB… and in my playbook, I tried putting the following code:

> - name: Provision instances  
> &nbsp;&nbsp;ec2\_instance:  
> &nbsp;&nbsp;&nbsp;&nbsp;state: present  
> &nbsp;&nbsp;&nbsp;&nbsp;security\_group: "{{hostvars[item]['security\_group']}}"  
> &nbsp;&nbsp;&nbsp;&nbsp;key\_name: "{{aws\_key\_name}}"  
> &nbsp;&nbsp;&nbsp;&nbsp;region: "{{hostvars[item]['region']}}"  
> &nbsp;&nbsp;&nbsp;&nbsp;instance\_type: "{{hostvars[item]['instance\_type']}}"  
> &nbsp;&nbsp;&nbsp;&nbsp;image\_id: "{{hostvars[item]['image\_id']}}"  
> &nbsp;&nbsp;&nbsp;&nbsp;wait: true  
> &nbsp;&nbsp;&nbsp;&nbsp;wait\_timeout: "{{hostvars[item]['wait\_timeout']}}"  
> &nbsp;&nbsp;&nbsp;&nbsp;network:  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assign\_public\_ip: true  
> &nbsp;&nbsp;&nbsp;&nbsp;tags:  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Name: '{{item}}'  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JiraStory: "{{hostvars[item].get('jira\_story','N/A')}}"  
> &nbsp;&nbsp;&nbsp;&nbsp;volumes:  
> &nbsp;&nbsp;&nbsp;&nbsp;- device\_name: /dev/sdb  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ebs:  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;encrypted: "{{hostvars[item].get('encrypted','false') == 'true'}}"  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;volume\_size: "{{hostvars[item].get('volume\_size',100)}}"  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;volume\_type: "{{hostvars[item].get('volume\_type','gp2')}}"  
> &nbsp;&nbsp;loop: "{{ groups.aws }}"  
> &nbsp;&nbsp;when: "'aws' in groups"  
> &nbsp;&nbsp;register: ec2  
> &nbsp;&nbsp;tags:  
> &nbsp;&nbsp;- aws

That yielded this error:

> An exception occurred during task execution. To see the full traceback, use -vvv. The error was: Invalid type for parameter BlockDeviceMappings[0].Ebs.VolumeSize, value: 100, type: \<type 'str'\>, valid types: \<type 'int'\>, \<type 'long'\>  
> failed: [localhost] (item=awstest.on.widesky.cloud) =\> {"boto3\_version": "1.7.19", "botocore\_version": "1.10.19", "changed": false, "item": "awstest.on.widesky.cloud", "msg": "Failed to create new EC2 instance: Parameter validation failed:\nInvalid type for parameter BlockDeviceMappings[0].Ebs.Encrypted, value: true, type: \<type 'str'\>, valid types: \<type 'bool'\>\nInvalid type for parameter BlockDeviceMappings[0].Ebs.VolumeSize, value: 100, type: \<type 'str'\>, valid types: \<type 'int'\>, \<type 'long'\>"}  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;to retry, use: --limit @/home/stuartl/vrt/projects/widesky/ops/deploy/site.retry

I thought, maybe it's being read from the hosts file as a string and  
needs to be passed through the `int` constructor. Tried wrapping the  
variable in `int()`, that failed, but then I read the jinja2 docs which  
said to use `{{variable | int}}`. No problem…

> &nbsp;&nbsp;&nbsp;&nbsp;volumes:  
> &nbsp;&nbsp;&nbsp;&nbsp;- device\_name: /dev/sdb  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ebs:  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;encrypted: "{{hostvars[item].get('encrypted','false') == 'true'}}"  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;volume\_size: "{{hostvars[item].get('volume\_size',100) | int}}"  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;volume\_type: "{{hostvars[item].get('volume\_type','gp2')}}"

I got the same error.

I suspect that the integer is then getting cast \*back\* to a string  
before being passed onto `boto3`, which is then barfing on it.

Is there a way to tell Ansible that a particular template expression is  
to be interpreted as an integer and not as a string?

---

<div class="post-metadata">

**Author:** ![Kai\_Stian\_Olstad](https://avatars.discourse-cdn.com/v4/letter/k/e19adc/32.png) [@Kai\_Stian\_Olstad](https://forum.ansible.com/u/Kai_Stian_Olstad)\
**Post date:** [December 11, 2018, 8:07am UTC](https://forum.ansible.com/t/casting-a-variable-as-an-integer/29236/2 "2018-12-11T08:07:33Z")

</div>

You could try to do it the Ansible way and not the Python way to see if that works.

&nbsp;&nbsp;&nbsp;volume\_size: "{{hostvars[item].volume\_size | default(100) | int}}"

---

<div class="post-metadata">

**Author:** ![Stuart\_Longland](https://avatars.discourse-cdn.com/v4/letter/s/ecc23a/32.png) [@Stuart\_Longland](https://forum.ansible.com/u/Stuart_Longland)\
**Post date:** [December 11, 2018, 11:21pm UTC](https://forum.ansible.com/t/casting-a-variable-as-an-integer/29236/3 "2018-12-11T23:21:55Z")

</div>

I understood Ansible basically used the Python language within Jinja2.  
What's the difference between these two lines?

&nbsp;&nbsp;{{hostvars[item].volume\_size | default(100) | int}}  
&nbsp;&nbsp;{{hostvars[item].get('volume\_size',100) | int}}

I'd try it out, but I've now hit a second issue with `ec2_instance`, and  
that is it keeps insisting on modifying the \*existing\* instance I  
created for a customer instead of creating a \*new\* instance like I  
intended. (This is in spite of the customer instance being a  
"t3.xlarge", and my new instance having a type of "t3.nano".)

How does one tell `ec2_instance` to "leave the existing instance(s)  
alone and create a new one"?

---

<div class="post-metadata">

**Author:** ![Kai\_Stian\_Olstad](https://avatars.discourse-cdn.com/v4/letter/k/e19adc/32.png) [@Kai\_Stian\_Olstad](https://forum.ansible.com/u/Kai_Stian_Olstad)\
**Post date:** [December 12, 2018, 6:26am UTC](https://forum.ansible.com/t/casting-a-variable-as-an-integer/29236/4 "2018-12-12T06:26:38Z")

</div>

All software have bugs and the Ansible way is probably used by most and have therefore been thoroughly tested.  
So the easiest way to check that out is to test it.

---

<div class="post-metadata">

**Author:** ![Stuart\_Longland](https://avatars.discourse-cdn.com/v4/letter/s/ecc23a/32.png) [@Stuart\_Longland](https://forum.ansible.com/u/Stuart_Longland)\
**Post date:** [December 12, 2018, 6:33am UTC](https://forum.ansible.com/t/casting-a-variable-as-an-integer/29236/5 "2018-12-12T06:33:18Z")

</div>

> > I understood Ansible basically used the Python language within Jinja2.  
> > What's the difference between these two lines?
> > 
> > &nbsp;&nbsp;{{hostvars[item].volume\_size | default(100) | int}}  
> > &nbsp;&nbsp;{{hostvars[item].get('volume\_size',100) | int}}
> 
> All software have bugs and the Ansible way is probably used by most and have therefore been thoroughly tested.  
> So the easiest way to check that out is to test it.

As explained, I'm unable to test because `ec2_instance` tries to clobber  
an existing instance instead of creating a new one.

I also see that both call the `| int` filter in `jinja2`. So assuming  
`jinja2` is doing its job, the return value in \*both\* cases should be an  
`int`. `boto3` thinks though it is getting a `str`, which leads me to  
believe something in between `jinja2` and `boto3` is casting it \*back\*  
to a `str`.

> From `jinja2`'s perspective, there's no such thing as the "Ansible way",

it's \*all\* Python. I therefore have trouble understanding what's  
happening behind the scenes.

---

<div class="post-metadata">

**Author:** ![jborean](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/jborean/32/1525_2.png) [@jborean](https://forum.ansible.com/u/jborean)\
**Post date:** [December 12, 2018, 8:30am UTC](https://forum.ansible.com/t/casting-a-variable-as-an-integer/29236/6 "2018-12-12T08:30:09Z")

</div>

If you have Ansible 2.7+ and jinja2 \>= 2.10 you should be able to preserve the int types with the DEFAULT\_JINJA2\_NATIVE configuration [https://docs.ansible.com/ansible/latest/reference\_appendices/config.html#default-jinja2-native](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#default-jinja2-native). It requires you to explicitly enable through either ansible.cfg or with an environment variable which is documented in that link.

Thanks

Jordan
