I'm trying to add a element to a list of dictionary.
_gitlab_runner_config:
server:
url: "https://gitlab.mydomain.com"
api_token: "XXXXXXXXXXXXXXXXXX"
registration_token: "YYYYYYYYYYYYYYYY"
global:
listen_address: ":9200"
concurent: 5
check_interval: 15
session_server:
listen_address: "0.0.0.0:8093"
advertise_address: "{{ ansible_fqdn }}:8093"
session_timeout: 600
runners:
- description: "Test runner 1"
token: ""
tags:
- test1
locked: False
active: False
run_untagged: False
access_level: "not_protected"
maximum_timeout: "3600"
executor: "docker"
executor_config:
tls_verify: false
image: "test-image"
pull_policy: "always"
volumes:
cpus:
In another task, i register the token value. Si, i want to set the value of gitlab_runner_config.runners.LIST_INDEX.token
I have try:
- name: "Save runner token"
set_fact:
_gitlab_runner_config: "{{ _gitlab_runner_config|combine({'runners': {runner_index: {'token': _gitlab_server_registered.runner.token}}} ) }}"
but it override the list.
_gitlab_runner_config.runners is a list. This implicates there might be more items on the list. If all items in the list shall be updated with the same token, e.g. mytoken, the play below does the job
vars:
mytoken: token000
tasks:
- set_fact:
config_updated: "{{ {'runners': _gitlab_runner_config.runners|
map('combine', {'token': mytoken})|
list} }}"
- set_fact:
_gitlab_runner_config: "{{ _gitlab_runner_config|
combine(config_updated) }}"
If there might be different tokens for each item of the list the list shall be updated in a loop. For example, given the list of tokens mytokens, the play below
vars:
mytokens:
- {'token': 'token000'}
- {'token': 'token001'}
- {'token': 'token002'}
tasks:
- set_fact:
runners: "{{ runners|default([]) +
[item|combine(mytokens[ansible_loop.index0])] }}"
loop: "{{ _gitlab_runner_config.runners }}"
loop_control:
extended: yes
- set_fact:
config_updated: "{{ {'runners': runners} }}"
- set_fact:
_gitlab_runner_config: "{{ _gitlab_runner_config|
combine(config_updated) }}"
- debug:
var: _gitlab_runner_config
gives
"_gitlab_runner_config": {
"global": {
"check_interval": 15,
"concurent": 5,
"listen_address": ":9200"
},
"runners": [
{
"access_level": "not_protected",
"active": false,
"description": "Test runner 1",
"executor": "docker",
"executor_config": {
"cpus": "",
"image": "test-image",
"pull_policy": "always",
"tls_verify": false,
"volumes": ""
},
"locked": false,
"maximum_timeout": "3600",
"run_untagged": false,
"tags": [
"test1"
],
"token": "token000"
}
],
"server": {
"api_token": "XXXXXXXXXXXXXXXXXX",
"registration_token": "YYYYYYYYYYYYYYYY",
"url": "https://gitlab.mydomain.com"
},
"session_server": {
"advertise_address": "srv.example.com:8093",
"listen_address": "0.0.0.0:8093",
"session_timeout": 600
}
}
Thanks for your help and answer #vladimir-botka.
But my problem is more complex but, my fault, i didn't give all the detail in my last post.
I have a dict gitlab_runner_config which contain list of runners _gitlab_runner_config.runners. I already loop in this list to register each runner, and i get a token in response (each runner will have a different token). I want to insert this token into teh field token. The whole dict gitlab_runner_config will be used for templating a config file.
The dict:
_gitlab_runner_config:
server:
url: "https://gitlab.mydomain.com"
api_token: "XXXXXXXXXXXXXXXXXX"
registration_token: "YYYYYYYYYYYYYYYY"
global:
listen_address: ":9200"
concurent: 5
check_interval: 15
session_server:
listen_address: "0.0.0.0:8093"
advertise_address: "{{ ansible_fqdn }}:8093"
session_timeout: 600
runners:
- description: "Test runner 1"
token: ""
tags:
- test1
locked: False
active: False
run_untagged: False
access_level: "not_protected"
maximum_timeout: "3600"
executor: "docker"
executor_config:
tls_verify: false
image: "test-image"
pull_policy: "always"
volumes:
cpus:
- description: "Test runner 2"
token: ""
tags:
- test2
locked: False
active: False
run_untagged: False
access_level: "not_protected"
maximum_timeout: "3600"
executor: "docker"
executor_config:
tls_verify: false
image: "test-image"
pull_policy: "always"
volumes:
cpus:
The tasks which register each runenr with a loop:
- name: "Registered runners"
include_tasks: register.yml
loop: "{{ _gitlab_runner_config.runners }}"
loop_control:
index_var: runner_index
register.yml:
- name: "Register runner on gitlab server"
gitlab_runner:
api_url: "{{ _gitlab_runner_config.server.url }}"
api_token: "{{ _gitlab_runner_config.server.api_token }}"
registration_token: "{{ _gitlab_runner_config.server.registration_token }}"
description: "[{{ ansible_fqdn }}] {{ item.description }}"
state: "present"
active: " {{ item.active }}"
tag_list: "{{ item.tags }}"
run_untagged: "{{ item.run_untagged }}"
maximum_timeout: "{{ item.maximum_timeout }}"
access_level: "{{ item.access_level }}"
locked: "{{ item.locked }}"
validate_certs: "no"
register: _gitlab_server_registered
- name: Debug
debug:
msg: "Token to merge for runner id: {{ runner_index }} : {{ gitlab_server_registered.runner.token }}"
Related
I'm unable to filter the following output with json_query, even though it works on a jmespath validator website.
Let me explain in detail with the code.
type_debug returns AnsibleUnicode for members value, so when I tried to use json_query to filter output it returned null. I need to get value from key ip, but I don't know how to do it in a good way.
---
- hosts: localhost
gather_facts: false
vars:
- RPN:
stdout: >-
"members": [
{
"id": 0,
"ip": "x.x.x.x",
"owner": "buzut",
"private_ip": "10.91.154.39",
"speed": 100,
"status": "active"
}
]
tasks:
- debug:
msg: "{{ RPN.stdout | type_debug }}"
From your question I understand that you like to gather all member with a json_query. To do so I've corrected the JSON slightly.
---
- hosts: localhost
become: false
gather_facts: false
vars:
RPN:
stdout: >-
{
"members": [{
"id": 0,
"ip": "x.x.x.x",
"owner": "buzut",
"private_ip": "10.91.154.39",
"speed": 100,
"status": "active"
}]
}
tasks:
- name: Show type(s)
debug:
msg:
- "{{ RPN.stdout | type_debug }}"
- "{{ RPN.stdout | from_json | type_debug }}"
- "{{ RPN.stdout | to_json | type_debug }}"
- name: Show members
debug:
msg: "{{ RPN.stdout | from_json | json_query('members') }}"
resulting into an output of
TASK [Show type(s)] *********
ok: [localhost] =>
msg:
- AnsibleUnicode
- dict
- str
TASK [Show members] *********
ok: [localhost] =>
msg:
- id: 0
ip: x.x.x.x
owner: buzut
private_ip: 10.91.154.39
speed: 100
status: active
I need to get value from key ip
- name: Show value of key 'ip'
debug:
msg: "{{ RPN.stdout | from_json | json_query('members[*].ip') }}"
resulting into an output of
TASK [Show value of key 'ip'] *********
ok: [localhost] =>
msg:
- x.x.x.x
Further Documentation
Selecting JSON data: JSON queries
Been at this about a week and I think it's time to post this. I'm pretty decent at ansible but clearly terrible at dictionaries.
How do I add a sub-key to a dictionary using update_list?
Alright so I have two dictionaries, one is the output of a command to pull AD Creds, the dictionary looks like this called userresult:
{
"objects": [
{
"Name" : "Administrator"
"objectSid": {
"Name" : "DOMAIN\\Administrator"
"Sid": "S-1-5-21"
}
},
{
"Name" : "Guest"
"objectSid": {
"Name" : "DOMAIN\\Guest"
"Sid": "S-1-5-22"
}
]
}
Now, I've got a dictionary that has the names and info I want to lookup (inputdictionary.yml):
dictionary:
users:
Nonexistentuser:
old_sid: 1-1-1-1
domain: nonexistentdomain
Administrator:
old_sid: 2-2-2-2
domain: DOMAIN
What I've tried:
---
- name: Update dictionary
hosts: myhosts
gather_facts: no
tasks:
- name: Get SID for user - you can ignore this part it just gets userresult
community.windows.win_domain_object_info:
filter: ObjectClass -eq 'user' -and objectCategory -eq 'Person'
properties:
- objectSid
register: userresult
- name: ready yaml dictionary
delegate_to: localhost
slurp:
path: '/home/inputdictionary.yml'
register: SourceInfo
- name: extract dictionary
set_fact:
myinfo: "{{SourceInfo['content'}] | b64decode | from_yaml ))"
- name: build a list of updates for dictionary
set_fact:
update_list: "{{ update list + update }}"
loop: "{{ myinfo.dictionary.users | dict2items }}"
loop_control:
index_var: idx
vars:
update_list: []
update:
- path: myinfo.dictonary.users[{{idx}}].new_sid
value: "TEST"
- debug:
var: update_list
Expected output:
dictionary:
users:
Nonexistentuser:
old_sid: 1-1-1-1
domain: nonexistentdomain
new_sid: TEST
Administrator:
old_sid: 2-2-2-2
domain: DOMAIN
new_sid: TEST
Current output:
TASK [build a list of updates for dictinoary]
FAILED! -> {
"msg": "template error while templating string: expected token 'end of print statement', got 'list. String: {{update list + update}}"
}
Test needs to be replaced with the new SID eventually, but I just want this step to work first..
Been trying to follow this but no avail: https://docs.ansible.com/ansible/latest/collections/ansible/utils/update_fact_module.html
Any help would be appreciated while I continue to try to fix this..
TEST needs to be replaced with the new SID eventually, but I just want this step to work first
- name: "make this working"
hosts: localhost
vars:
dictionary:
users:
Nonexistentuser:
old_sid: 1-1-1-1
domain: nonexistentdomain
Administrator:
old_sid: 2-2-2-2
domain: DOMAIN
tasks:
- name: build a list of updates for dictionary
set_fact:
update_list: "{{ update_list | d({}) | combine({ item.key: _v}) }}"
loop: "{{ dictionary.users | dict2items }}"
vars:
_k: "{{ item.key }}"
_v: "{{ item.value | combine({'new_sid': newsid}) }}"
newsid: "TEST"
- debug:
msg: '{{ update_list }}'
result:
ok: [localhost] => {
"msg": {
"Administrator": {
"domain": "DOMAIN",
"new_sid": "TEST",
"old_sid": "2-2-2-2"
},
"Nonexistentuser": {
"domain": "nonexistentdomain",
"new_sid": "TEST",
"old_sid": "1-1-1-1"
}
}
}
I have below playbook in which I search for all vars starting with static_routes__ and then merge them.
---
- hosts: localhost
gather_facts: no
vars:
static_routes__host:
management:
- address: '0.0.0.0/0'
next_hop: '192.168.0.1'
static_routes__lab:
management:
- address: '1.1.1.1/32'
next_hop: '192.168.0.1'
static_routes__test:
test:
- address: '8.8.8.8/32'
next_hop: '192.168.2.1'
tasks:
- set_fact:
static_routes: "{{ static_routes | default({}) | combine(lookup('vars', item, default={}), recursive=True, list_merge='append') }}"
loop: "{{ query('varnames', 'static_routes__') }}"
- name: Output static_routes
debug:
var: static_routes
The above will result in:
TASK [Output static_routes] ***************************************************************************************************************************************************************
ok: [localhost] => {
"static_routes": {
"management": [
{
"address": "0.0.0.0/0",
"next_hop": "192.168.0.1"
},
{
"address": "1.1.1.1/32",
"next_hop": "192.168.0.1"
}
],
"test": [
{
"address": "8.8.8.8/32",
"next_hop": "192.168.2.1"
}
]
}
}
However the merge_list_ is only available in Ansible version > 2.9, which is currently not available to me due to company policies. I'm looking for a way to replicate above output in Ansible version =< 2.9.
With the below task I'm able to sort of reproduce it but it only allows one list item.
- set_fact:
static_routes: "{{ static_routes | default({}) | combine({vrf: route | default([]) }) }}"
loop: "{{ query('varnames', 'static_routes__') }}"
vars:
vrf: "{{ lookup('dict', lookup('vars', item)).key }}"
route: "{{ lookup('dict', lookup('vars', item)).value }}"
subnet: "{{ lookup('dict', lookup('vars', item)).value.0.address }}"
next_hop: "{{ lookup('dict', lookup('vars', item)).value.0.next_hop }}"
- name: Output static_routes
debug:
var: static_routes
Found the solution:
- set_fact:
static_routes_list: "{{ static_routes_list | default({}) | combine({item: lookup('vars', item)}) }}"
loop: "{{ query('varnames', 'static_routes__') }}"
- set_fact:
static_routes: "{{ static_routes|
default({})|
combine({item.0: item.1|json_query('[].value')|flatten | unique})
}}"
loop: "{{ static_routes_list|
dict2items|
json_query('[*].value')|
map('dict2items')|list|flatten|
groupby('key')
}}"
This one seems simpler
- set_fact:
_list: "{{ _list|default([]) + [lookup('vars', item)] }}"
loop: "{{ query('varnames', 'static_routes__') }}"
- set_fact:
static_routes: "{{ static_routes|default({})|
combine({item.0: item.1|json_query('[].value')|flatten}) }}"
loop: "{{ _list|map('dict2items')|map('first')|groupby('key') }}"
gives
static_routes:
management:
- address: 0.0.0.0/0
next_hop: 192.168.0.1
- address: 1.1.1.1/32
next_hop: 192.168.0.1
test:
- address: 8.8.8.8/32
next_hop: 192.168.2.1
I am relatively new to working with Ansible Core / Tower and I am at a complete loss what is causing the following issues. I have spent the past two days reading everything I could find on the topic and I am still stuck, looking for help.
Here is what I currently have setup (among other Ansible playbooks, roles, and tasks to create brand new VPC).
Below are the tasks that I am using to create a set of new subnets, one per availability zone, and get the results back from what is created. These tasks all works perfectly as verified through the AWS Console.
### Create the Internet-facing DMZ subnets ###
- name: Create Subnet(s) in VPC - DMZ
ec2_vpc_subnet:
state: present
vpc_id: "{{ new_vpc_info['vpcs'][0]['id'] }}"
region: "{{ vpc_region }}"
az: "{{ item.az }}"
cidr: "{{ item.subnet }}"
resource_tags:
Name: "{{ item.name }}"
Role: "{{ role_tag }}"
Team: "{{ team_tag }}"
Product Area: "{{ product_area_tag }}"
Portfolio: "{{ portfolio_tag }}"
with_items: "{{ dmz_subnet_az }}"
- name: Get Sunbet Info - DMZ
ec2_vpc_subnet_facts:
region: "{{ vpc_region }}"
filters:
"tag:Name": "{{ item.name }}"
with_items: "{{ dmz_subnet_az }}"
register: new_dmz_subnets
- debug:
var=new_dmz_subnets
The output of the "debug" command is provided below, truncated to remove the rest of the subnets and redacted so I do not get yelled at, which matches up to what is in the AWS Console.
{
"changed": false,
"_ansible_verbose_always": true,
"new_dmz_subnets": {
"msg": "All items completed",
"changed": false,
"results": [
{
"_ansible_parsed": true,
"subnets": [
{
"tags": {
"Product Area": "Engineering Tools",
"Portfolio": "Shared Platform and Operations",
"Role": "splunk-proof-of-concept",
"Name": "DMZ_Subnet_A",
"Team": "Engineering Tools"
},
"subnet_id": "subnet-XXXX",
"assign_ipv6_address_on_creation": false,
"default_for_az": false,
"state": "available",
"ipv6_cidr_block_association_set": [],
"availability_zone": "us-east-1a",
"vpc_id": "vpc-XXXX",
"cidr_block": "x.x.x.x/24",
"available_ip_address_count": 251,
"id": "subnet-XXXX",
"map_public_ip_on_launch": false
}
],
"changed": false,
"_ansible_item_label": {
"subnet": "x.x.x.x/24",
"az": "us-east-1a",
"name": "DMZ_Subnet_A"
},
"item": {
"subnet": "x.x.x.x/24",
"az": "us-east-1a",
"name": "DMZ_Subnet_A"
},
"_ansible_item_result": true,
"failed": false,
"invocation": {
"module_args": {
"profile": null,
"aws_secret_key": null,
"aws_access_key": null,
"security_token": null,
"region": "us-east-1",
"filters": {
"tag:Name": "DMZ_Subnet_A"
},
"ec2_url": null,
"subnet_ids": [],
"validate_certs": true
}
},
"_ansible_ignore_errors": null,
"_ansible_no_log": false
},
{
"_ansible_parsed": true,
"subnets": [
{
"tags": {
"Product Area": "Engineering Tools",
"Portfolio": "Shared Platform and Operations",
"Role": "splunk-proof-of-concept",
"Name": "DMZ_Subnet_B",
"Team": "Engineering Tools"
},
"subnet_id": "subnet-XXXX",
"assign_ipv6_address_on_creation": false,
"default_for_az": false,
"state": "available",
"ipv6_cidr_block_association_set": [],
"availability_zone": "us-east-1b",
"vpc_id": "vpc-XXXX",
"cidr_block": "x.x.x.x/24",
"available_ip_address_count": 251,
"id": "subnet-XXXX",
"map_public_ip_on_launch": false
}
],
"changed": false,
"_ansible_item_label": {
"subnet": "x.x.x.x/24",
"az": "us-east-1b",
"name": "DMZ_Subnet_B"
},
"item": {
"subnet": "x.x.x.x/24",
"az": "us-east-1b",
"name": "DMZ_Subnet_B"
},
"_ansible_item_result": true,
"failed": false,
"invocation": {
"module_args": {
"profile": null,
"aws_secret_key": null,
"aws_access_key": null,
"security_token": null,
"region": "us-east-1",
"filters": {
"tag:Name": "DMZ_Subnet_B"
},
"ec2_url": null,
"subnet_ids": [],
"validate_certs": true
}
},
"_ansible_ignore_errors": null,
"_ansible_no_log": false
},
......
}
]
},
"_ansible_no_log": false
}
Now onto the tasks that I am having issues getting working, below is my most recent attempt, which may be completely in left field due to me trying everything I found to get it working. I am attempting to get a list of the "subnet_id" from the registered "new_dmz_subnets" variable, then concatenating it with a "name" that is set in a vars file, and finally using that information to create a NAT Gateway within each of the subnets.
### Create the NAT Gateway in VPC ###
- name: Set DMZ Subnet facts
set_fact:
subnet_id_items:
subnet_id: '{{ item.subnets | map(attribute="subnet_id") | list }}'
with_items: "{{ new_dmz_subnets }}"
register: subnet_id_list
- name: Set Name and DMZ Subnet loop facts
set_fact:
name_subnet_items:
name: "{{ nat_gateway.name }}"
subnet_id: "{{ item.subnet_id }}"
loop: "{{ subnet_id_list }}"
register: name_subnet_list
- debug:
var=name_subnet_list
- name: Create NAT Gateway, allocate new EIP, in VPC
ec2_vpc_nat_gateway:
state: present
subnet_id: "{{ item.subnet_id }}"
region: "{{ vpc_region }}"
wait: yes
if_exist_do_not_create: true
tags:
Name: "{{ item.name }}"
Role: "{{ role_tag }}"
Team: "{{ team_tag }}"
Product Area: "{{ product_area_tag }}"
Portfolio: "{{ portfolio_tag }}"
with_items: "{{ name_subnet_list }}"
register: new_nat_gateway
- debug:
var=new_nat_gateway
When I ran this setup, I got the following fatal error message, which is pretty much the same across every variation I have attempted.
12:55:15
fatal: [localhost]: FAILED! => {
"msg": "The task includes an option with an undefined variable. The error was: 'ansible.utils.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'subnets'\n\nThe error appears to have been in '/var/lib/awx/projects/_6__erik_andresen_git/ansible/splunk_poc_playbook/roles/create_networking_role/tasks/create_gateways_task.yml': line 21, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n### Starting working on this Task ###\n- name: Set DMZ Subnet facts\n ^ here\n"
}
Please let me know if I can provide any additional details and thanks in advance for the help!!!
-- Erik
I came across a setup that actually works! It may not be the best way to do it and I am still open to suggestions, but it at least works.
Here is code of the "ec2_vpc_subnet" module and collecting the Subnet IDs for later use in the playbook.
### Create the Internet-facing DMZ subnets ###
- name: Create Subnet(s) in VPC - DMZ
ec2_vpc_subnet:
state: present
vpc_id: "{{ vpc_id }}"
region: "{{ vpc_region }}"
az: "{{ item.az }}"
cidr: "{{ item.subnet }}"
resource_tags:
Name: "{{ item.name }}"
Role: "{{ role_tag }}"
Team: "{{ team_tag }}"
Product Area: "{{ product_area_tag }}"
Portfolio: "{{ portfolio_tag }}"
Created By: "{{ created_by }}"
with_items: "{{ dmz_subnet_az }}"
register: new_dmz_subnets
- name: Set facts for Subnet - DMZ
set_fact:
subnet_dmz_id: "{{ subnet_dmz_id | default({}) | combine({ item.subnet.tags.Name: item.subnet.id }) }}"
loop: "{{ new_dmz_subnets.results }}"
- debug:
var=subnet_dmz_id
And here is the use of the Subnet IDs in the "ec2_vpc_nat_gateway" module to create a NAT Gateway within each Availability Zone.
### Create the NAT Gateway in VPC ###
- name: Create NAT Gateway, allocate new EIP, in VPC
ec2_vpc_nat_gateway:
state: present
# NAT Gateways being deployed in DMZ subnets
subnet_id: "{{ subnet_dmz_id[item.subnet_name] }}"
region: "{{ vpc_region }}"
wait: yes
if_exist_do_not_create: true
# Tags not supported in the "ec2_vpc_nat_gateway" module
# https://github.com/ansible/ansible/issues/44339
#tags:
# Name: "{{ item.name }}"
# Role: "{{ role_tag }}"
# Team: "{{ team_tag }}"
# Product Area: "{{ product_area_tag }}"
# Portfolio: "{{ portfolio_tag }}"
# Created By: "{{ created_by }}"
with_items: "{{ nat_gateway }}"
register: new_nat_gateway
- debug:
var=new_nat_gateway
I have a previous task that creates weekly backups, labeling them with the server name followed by a date/time tag. The goal of this job is to go in behind it and clean up the old AMI backups, leaving only the last 3. The ec2_ami_find task works fine, but it could also return empty results for some servers and I'd like the deregister task to handle that.
The error I'm getting is pretty generic:
fatal: [127.0.0.1]: FAILED! => {
"failed": true,
"msg": "The conditional check 'item.ec2_ami_find.exists' failed. The error was: error while evaluating conditional
(item.ec2_ami_find.exists): 'dict object' has no attribute
'ec2_ami_find'\n\nThe error appears to have been in
'/root/ansible/ec2-backups-purge/roles/first_acct/tasks/main.yml': line 25,
column 3, but may\nbe elsewhere in the file depending on the exact
syntax problem.\n\nThe offending line appears to be:\n\n\n- name:
Deregister old backups\n ^ here\n"
The playbook task reads as follows:
---
- name: Find old backups
tags: always
ec2_ami_find:
owner: self
aws_access_key: "{{ access_key }}"
aws_secret_key: "{{ secret_key }}"
region: "{{ aws_region }}"
ami_tags:
Name: "{{ item }}-weekly-*"
sort: name
sort_order: descending
sort_start: 3
with_items:
- server-01
- server-02
- server-win-01
- downloads
register: stale_amis
- name: Deregister old backups
tags: always
ec2_ami:
aws_access_key: "{{ access_key }}"
aws_secret_key: "{{ secret_key }}"
region: "{{ aws_region }}"
image_id: "{{ item.ami_id }}"
delete_snapshot: True
state: absent
with_items:
- "{{ stale_amis.results }}"
Snippet of one of the results returns:
"results": [
{
"ami_id": "ami-zzzzzzz",
"architecture": "x86_64",
"block_device_mapping": {
"/dev/xvda": {
"delete_on_termination": true,
"encrypted": false,
"size": 200,
"snapshot_id": "snap-xxxxxxxxxxxxx",
"volume_type": "gp2"
}
},
"creationDate": "2017-08-01T15:26:11.000Z",
"description": "Weekly backup via Ansible",
"hypervisor": "xen",
"is_public": false,
"location": "111111111111/server-01.example.com-20170801152611Z",
"name": "server-01.example.com-20170801152611Z",
"owner_id": "111111111111",
"platform": null,
"root_device_name": "/dev/xvda",
"root_device_type": "ebs",
"state": "available",
"tags": {
"Name": "server-01-weekly-20170801152611Z",
"Type": "weekly"
},
"virtualization_type": "hvm"
},
I doubt your attempt:
with_items:
- "{{ stale_amis.results }}"
because ec2_ami_find put results into own results field. So the first AMI for first server will be stale_amis.results[0].results[0].ami_id
I advice to reduce original stale_amis to required list and loop over it. For example you can use json_query filter:
- ec2_ami:
aws_access_key: "{{ access_key }}"
aws_secret_key: "{{ secret_key }}"
region: "{{ aws_region }}"
image_id: "{{ item }}"
delete_snapshot: True
state: absent
with_items: "{{ stale_amis | json_query('results[].results[].ami_id') }}"