I’ve run into a weird behaviour regarding how Ansible handles converting strings to complex objects.
I have the following string representation of a list of dicts that I’m returning from a Cloudformation stack output:
[{“id”: “subnet-f3i4ven6lxvxr3eu”,“az”: “us-east-1a”},{“id”: “subnet-0wovp0yu5sr8pnwv”,“az”: “us-east-1b”}]
I’ve been using this in a playbook, passing it to the “loop” parameter in the following task:
- name: provision instances
ec2:
key_name: keypair1
instance_type: t2.micro
image: “{{ ami_id }}”
wait: no
exact_count: 1
count_tag:
Name: “instance{{ loop_count + 1 }}”
Type: type1
AZ: “{{ item.az }}”
group_id: “{{ cf_results.stack_outputs.SecurityGroupDetails|from_json|map(attribute=‘id’)|list }}”
termination_protection: yes
vpc_subnet_id: “{{ item.id }}”
volumes: - device_name: /dev/sda1
volume_type: gp2
volume_size: 50
delete_on_termination: true
instance_tags:
Name: “instance{{ loop_count + 1 }}”
Type: type1
Environment: prod
VPC: vpc1
Subnet: “{{ item.name }}”
AZ: “{{ item.az }}”
monitoring: yes
region: us-east-1
loop: “{{ cf_results.stack_outputs.SubnetDetails }}”
loop_control:
index_var: loop_count
register: instances
The above task works fine. However, I’ve been trying to use it to create another, single EC2 instance and I’m using filters to just select the first subnet from the list, as follows:
- name: provision vpn instance
ec2:
key_name: keypair1
instance_type: t2.micro
image: “{{ ami_id }}”
wait: no
exact_count: 1
count_tag:
Name: extra_instance
Type: type2
AZ: “{{ cf_results.stack_outputs.SubnetDetails[0].az }}”
group_id: “{{ cf_results.stack_outputs.SecurityGroupDetails|from_json|map(attribute=‘id’)|list }}”
termination_protection: yes
vpc_subnet_id: “{{ cf_results.stack_outputs.SubnetDetails[0].id }}”
assign_public_ip: yes
instance_tags:
Name: extra_instance
Type: type2
Environment: prod
VPC: vpc1
Subnet: “{{ cf_results.stack_outputs.SubnetDetails[0].id }}”
AZ: “{{ cf_results.stack_outputs.SubnetDetails[0].az }}”
monitoring: yes
region: “{{ static_config.region }}”
register: extra_instance
When the above task is executed it fails with the following error: “The task includes an option with an undefined variable. The error was: ‘str object’ has no attribute ‘az’”.
I added a ‘debug’ task to just output the first item from the list, it worked but as you can see it just outputs the first character in the string:
TASK [debug] *****************************************************************************************
ok: [localhost] => {
“cf_results.stack_outputs.SubnetDetails[0]”: “[”
}
Is there a reason why the loop parameter successfully converts the string to a list but the filter doesn’t?
Thanks,
Guy