i am trying to set facts from a json array, since the key contains space i am unable to parse, can someone help me here,
i want to set fact as "name": "IN-FG-04" when "vdom": "vdom-shop"
Please see my sample playbook entry
- name: Iterate JSON
set_fact:
app_item: "{{ item['scope member'] }}"
with_items: "{{ result.results }}"
register: app_result
please see the json input and this is an output of my previous task
{
"msg": {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"failed": false,
"msg": "Custom Query Success",
"results": [
{
"name": "FG-04-Policy",
"obj ver": 3,
"oid": 1196,
"package settings": {
"central-nat": "disable",
"fwpolicy-implicit-log": "disable",
"fwpolicy6-implicit-log": "disable",
"inspection-mode": "proxy"
},
"scope member": [
{
"name": "IN-FG-04",
"vdom": "vdom-shop"
}
],
"type": "pkg"
},
{
"name": "FG-04-DC",
"obj ver": 23,
"oid": 1216,
"package settings": {
"central-nat": "disable",
"fwpolicy-implicit-log": "disable",
"fwpolicy6-implicit-log": "disable",
"inspection-mode": "proxy"
},
"scope member": [
{
"name": "IN-FG-04",
"vdom": "vdom1-dc"
}
],
"type": "pkg"
}
]
}
}
The snippet below
set fact as "name": "IN-FG-04" when "vdom": "vdom-shop"
- name: "set fact as name: IN-FG-04 when vdom: vdom-shop"
set_fact:
name: "{{ result.results|json_query('[].\"scope member\"[?\"vdom\"==`\"vdom-shop\"`].name')|flatten|first }}"
- debug:
var: name
gives:
"name": "IN-FG-04"
Note: although this is quite a good exercice for practicing loops, you should definitely consider fixing the previous task giving the result or write your own filter.
First of all, you are using register on a set_fact task. It is not an error in itself but is of very limited interest. This will register if you correctly assigned a value to a variable, not the values themselves. So you will never get the expected result with this.
What you want to do is to append items to a list while you are looping over your json in the set_fact task. This is done by initializing your set_fact variable to an empty list with the default filter on first loop and appending a new list with your items.
Moreover, since you need to look at several level of your object at the same time to take decisions, you need to use a subelements loop: loop level 0 on each result and level 1 on each element of the scope member list. On each iteration, you will append an object to the list. In the example below, I used the ternary filter to decide which name to include.
---
- name: SO Test
hosts: localhost
vars:
result: {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"failed": false,
"msg": "Custom Query Success",
"results": [
{
"name": "FG-04-Policy",
"obj ver": 3,
"oid": 1196,
"package settings": {
"central-nat": "disable",
"fwpolicy-implicit-log": "disable",
"fwpolicy6-implicit-log": "disable",
"inspection-mode": "proxy"
},
"scope member": [
{
"name": "IN-FG-04",
"vdom": "vdom-shop"
}
],
"type": "pkg"
},
{
"name": "FG-04-DC",
"obj ver": 23,
"oid": 1216,
"package settings": {
"central-nat": "disable",
"fwpolicy-implicit-log": "disable",
"fwpolicy6-implicit-log": "disable",
"inspection-mode": "proxy"
},
"scope member": [
{
"name": "IN-FG-04",
"vdom": "vdom1-dc"
}
],
"type": "pkg"
}
]
}
tasks:
- name: Get all names + vdom as requested in a list
set_fact:
app_result: >-
{{
app_result
| default([])
+
[{
'name': (item.1.vdom == 'vdom-shop') | ternary(item.0.name, item.1.name),
'vdom': item.1.vdom
}]
}}
loop: "{{ lookup('subelements', result.results, 'scope member') }}"
- name: show result
debug:
var: app_result
Which results in
PLAY [SO Test] *****************************************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [Get all names + vdom as requested in a list] *****************************
ok: [localhost] => (item=[{'name': 'FG-04-Policy', 'obj ver': 3, 'oid': 1196, 'package settings': {'central-nat': 'disable', 'fwpolicy-implicit-log': 'disable', 'fwpolicy6-implicit-log': 'disable', 'inspection-mode': 'proxy'}, 'type': 'pkg'}, {'name': 'IN-FG-04', 'vdom': 'vdom-shop'}])
ok: [localhost] => (item=[{'name': 'FG-04-DC', 'obj ver': 23, 'oid': 1216, 'package settings': {'central-nat': 'disable', 'fwpolicy-implicit-log': 'disable', 'fwpolicy6-implicit-log': 'disable', 'inspection-mode': 'proxy'}, 'type': 'pkg'}, {'name': 'IN-FG-04', 'vdom': 'vdom1-dc'}])
TASK [show result] *************************************************************
ok: [localhost] => {
"app_result": [
{
"name": "FG-04-Policy",
"vdom": "vdom-shop"
},
{
"name": "IN-FG-04",
"vdom": "vdom1-dc"
}
]
}
PLAY RECAP *********************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0
Related
Below is my JSON file
[
{
"?xml": {
"attributes": {
"encoding": "UTF-8",
"version": "1.0"
}
}
},
{
"domain": [
{
"name": "mydom"
},
{
"domain-version": "12.2.1.3.0"
},
{
"server": [
{
"name": "AdminServer"
},
{
"ssl": {
"name": "AdminServer"
}
},
{
"listen-port": "12400"
},
{
"listen-address": "mydom.host1.bank.com"
}
]
},
{
"server": [
{
"name": "myserv1"
},
{
"ssl": [
{
"name": "myserv1"
},
{
"login-timeout-millis": "25000"
}
]
},
{
"listen-port": "22421"
}
]
},
{
"server": [
{
"name": "myserv2"
},
{
"ssl": {
"name": "myserv2"
}
},
{
"reverse-dns-allowed": "false"
},
{
"log": [
{
"name": "myserv2"
},
{
"file-name": "/web/bea_logs/domains/mydom/myserv2/myserv2.log"
}
]
},
{
"listen-port": "12401"
}
]
}
]
}
]
I wish to get the listen-port printed while keeping in mind that the position of listen-port element may change in the array.
I was able to get the listen port on latest ansible version 2.12.2 using the below play
- name: display Listen Port
debug:
msg: "{{ myserver.0.name }} -> {{ cpath[0]['listen-port'] }}"
loop: "{{ jsondata[1].domain }}"
vars:
myserver: "{{ item.server | selectattr('name', 'defined') | list }}"
cpath: "{{ item.server | selectattr('listen-port', 'defined') | list }}"
when: item.server is defined and (item.server | selectattr('listen-port', 'defined') | list ) != []
However, this play does not work on redhat OS where ansible version is 2.10 the latest offering.
Below is the error i recieve:
TASK [create YML for server name with Listen port] ************************************************************
Wednesday 16 March 2022 08:41:06 -0500 (0:00:00.171) 0:00:05.917 *******
skipping: [localhost] => (item={'name': 'mydom'})
skipping: [localhost] => (item={'domain-version': '12.2.1.3.0'})
failed: [localhost] (item={'server': [{'name': 'AdminServer'}, {'ssl': {'name': 'AdminServer'}}, {'listen-port': '12400'}, {'listen-address': 'mydom.host1.bank.com'}]}) => {"ansible_loop_var": "item", "changed": true, "cmd": "echo AdminServer_httpport: 12400>>/web/aes/admin/playbooks/Migrator/wlsdatadump.yml", "delta": "0:00:00.006786", "end": "2022-03-16 08:41:07.175709", "item": {"server": [{"name": "AdminServer"}, {"ssl": {"name": "AdminServer"}}, {"listen-port": "12400"}, {"listen-address": "mydom.host1.bank.com"}]}, "msg": "non-zero return code", "rc": 1, "start": "2022-03-16 08:41:07.168923", "stderr": "/bin/sh: 12400: Bad file descriptor", "stderr_lines": ["/bin/sh: 12400: Bad file descriptor"], "stdout": "", "stdout_lines": []}
skipping: [localhost] => (item={'server': [{'name': 'myserv1'}, {'ssl': [{'name': 'myserv1'}, {'login-timeout-millis': '25000'}]}, {'log': [{'name': 'myserv1'}, {'file-name': '/web/bea_logs/domains/mydom/myserv1/myserv1.log'}]}]})
skipping: [localhost] => (item={'server': [{'name': 'myserv2'}, {'ssl': {'name': 'myserv2'}}, {'reverse-dns-allowed': 'false'}, {'log': [{'name': 'myserv2'}, {'file-name': '/web/bea_logs/domains/mydom/myserv2/myserv2.log'}]}]})
Can you please suggest any other solution?
i suggest you to create a custom filter to avoid multiple choices:
you create a file myfilter.py in a folder filter_plugins (same level your playbook), i have named the plugin customfilter:
#!/usr/bin/python
class FilterModule(object):
def filters(self):
return {
'customfilter': self.customfilter
}
def customfilter(self, json):
result = []
for obj in json[1]['domain']:
for server in obj:
ob = {}
if server == 'server':
for k in obj[server]:
for x in k:
ob.update({x: k[x]})
result.append(ob)
#print(result)
return result
Playbook:
- hosts: localhost
gather_facts: no
vars:
json: "{{ lookup('file', './file.json') | from_json | customfilter }}"
tasks:
- name: display
debug:
msg: "server name: {{ server }} -> filename: {{ filename }} -> listenport: {{ listenport }}"
loop: "{{ json }}"
vars:
server: "{{ item.name }}"
filename: "{{ item.log[1]['file-name'] | d('')}}"
listenport: "{{ item['listen-port'] | d('') }}"
result:
ok: [localhost] => (item={'name': 'AdminServer', 'ssl': {'name': 'AdminServer'}, 'listen-port': '12400', 'listen-address': 'mydom.host1.bank.com'}) => {
"msg": "server name: AdminServer -> filename: -> listenport: 12400"
}
ok: [localhost] => (item={'name': 'myserv1', 'ssl': [{'name': 'myserv1'}, {'login-timeout-millis': '25000'}], 'listen-port': '22421'}) => {
"msg": "server name: myserv1 -> filename: -> listenport: 22421"
}
ok: [localhost] => (item={'name': 'myserv2', 'ssl': {'name': 'myserv2'}, 'reverse-dns-allowed': 'false', 'log': [{'name': 'myserv2'}, {'file-name': '/web/bea_logs/domains/mydom/myserv2/myserv2.log'}], 'listen-port': '12401'}) => {
"msg": "server name: myserv2 -> filename: /web/bea_logs/domains/mydom/myserv2/myserv2.log -> listenport: 12401"
}
the plugin role is to group all dictionaries of each record server in one dictionary and simplify the datas you want to use.
[
{
"name": "AdminServer",
"ssl": {
"name": "AdminServer"
},
"listen-port": "12400",
"listen-address": "mydom.host1.bank.com"
},
{
"name": "myserv1",
"ssl": [
{
"name": "myserv1"
},
{
"login-timeout-millis": "25000"
}
],
"listen-port": "22421"
},
{
"name": "myserv2",
"ssl": {
"name": "myserv2"
},
"reverse-dns-allowed": "false",
"log": [
{
"name": "myserv2"
},
{
"file-name": "/web/bea_logs/domains/mydom/myserv2/myserv2.log"
}
],
"listen-port": "12401"
}
]
I am looking to get the value in attribute average from the output.
- name: Prt volumelogicalsize
debug:
msg: "{{ (volumelogicalsize.stdout| from_json).value }}"
Below is the output
ok: [ansiblehost] => {
"msg": [
{
"displayDescription": "The percentage of the volume consumed including snapshots.",
"errorCode": "Success",
"id": "/subscriptions//resourceGroups//providers/Microsoft.NetApp/netAppAccounts/SAP-ANF-SHARED-PROD1/capacityPools//providers/Microsoft.Insights/metrics/VolumeConsumedSizePercentage",
"name": {
"localizedValue": "Percentage Volume Consumed Size",
"value": "VolumeConsumedSizePercentage"
},
"resourceGroup": "RG-CVS-USE2-SAP-ANF-Shared-Prod-1",
"timeseries": [
{
"data": [
{
"average": 71.25216012022325,
"count": null,
"maximum": null,
"minimum": null,
"timeStamp": "2021-03-17T04:00:00+00:00",
"total": null
}
],
"metadatavalues": []
}
],
"type": "Microsoft.Insights/metrics",
"unit": "Percent"
}
]
}
I am expecting the output like 71.25216012022325 or 71.25.
Based on what you are giving us in your output, you can access it doing:
- debug:
msg: "{{ (volumelogicalsize.stdout| from_json).value.0.timeseries.0.data.0.average }}"
This would give:
msg: '71.25216012022325'
And if you want only two decimal, you can use the format filter:
- debug:
msg: "{{ '%.2f' | format((volumelogicalsize.stdout| from_json).value.0.timeseries.0.data.0.average) }}"
That would give:
msg: '71.25'
I have created a template within a playbook which I want to iterate through with a list of hashes. The output of this I want to add to another var to use in a following module.
The template works and the loop looks like it works, but it never adds the last item in the list. I have recreated it in a test play.
---
- hosts: localhost
tasks:
- name: Init
set_fact:
foo: []
fqdn: "test.com"
template: []
- name: portlist
set_fact:
portlist:
- { port: 9091, index: 1 }
- { port: 9092, index: 2 }
- { port: 9093, index: 3 }
- { port: 9094, index: 4 }
- name: generate policy
set_fact:
template:
- name: "traffic to {{ item.port }}"
index: "{{ item.index }}"
match:
desc: "[{{ item.port }}]" # The field needs to be passed as a list
name: "{{ fqdn }}_{{ item.port }}"
port: "{{ item.port }}"
foo: "{{ foo + template }}"
loop: "{{ portlist }}"
- debug:
var: foo
I understand I can make this play smaller with defaults rather than initializing vars but this felt easier to read for troubleshooting.
The play results in a list of hashes which then I can input into a policy module. However it only ever gives me 3 items in the list and misses off the last item in the portlist.
TASK [debug] ***************************************************
ok: [localhost] => {
"foo": [
{
"action": {
"ref": "test.com_9091",
"this": true
},
"enable": true,
"index": "1",
"match": {
"port": {
"criteria": "IS_IN",
"port": [
9091
]
}
},
"name": "traffic to 9091"
},
{
"action": {
"ref": "test.com_9092",
"this": true
},
"enable": true,
"index": "2",
"match": {
"port": {
"criteria": "IS_IN",
"port": [
9092
]
}
},
"name": "traffic to 9092"
},
{
"action": {
"ref": "test.com_9093",
"this": true
},
"enable": true,
"index": "3",
"match": {
"port": {
"criteria": "IS_IN",
"port": [
9093
]
}
},
"name": "traffic to 9093"
}
]
}
Your problem is caused by the fact that variables defined via set_fact aren't available until after the set_fact task has finished. This means that when you set:
foo: "{{ foo + template }}"
You see the value of template from the previous loop iteration.
One way of dealing with this is to rewrite your set_fact task to set foo directly:
---
- hosts: localhost
gather_facts: false
vars:
fqdn: "test.com"
portlist:
- {port: 9091, index: 1}
- {port: 9092, index: 2}
- {port: 9093, index: 3}
- {port: 9094, index: 4}
tasks:
- name: generate policy
set_fact:
foo: >-
{{
foo + [{
'name': 'traffic to {}'.format(item.port),
'index': item.index,
'match': {
'desc': "[{}]".format(item.port),
'name': '{}_{}'.format(fqdn, item.port),
'port': item.port
}
}]
}}
vars:
foo: []
loop: "{{ portlist }}"
- debug:
var: foo
This will output:
TASK [debug] *********************************************************************************************************************************************************************************
ok: [localhost] => {
"foo": [
{
"index": 1,
"match": {
"desc": "[9091]",
"name": "test.com_9091",
"port": 9091
},
"name": "traffic to 9091"
},
{
"index": 2,
"match": {
"desc": "[9092]",
"name": "test.com_9092",
"port": 9092
},
"name": "traffic to 9092"
},
{
"index": 3,
"match": {
"desc": "[9093]",
"name": "test.com_9093",
"port": 9093
},
"name": "traffic to 9093"
},
{
"index": 4,
"match": {
"desc": "[9094]",
"name": "test.com_9094",
"port": 9094
},
"name": "traffic to 9094"
}
]
}
If you find your template-based solution more readable, you could rewrite it using two set_fact tasks like this:
---
- hosts: localhost
gather_facts: false
vars:
fqdn: "test.com"
portlist:
- {port: 9091, index: 1}
- {port: 9092, index: 2}
- {port: 9093, index: 3}
- {port: 9094, index: 4}
tasks:
- name: generate policy
set_fact:
template:
name: "traffic to {{ item.port }}"
index: "{{ item.index }}"
match:
desc: "[{{ item.port }}]" # The field needs to be passed as a list
name: "{{ fqdn }}_{{ item.port }}"
port: "{{ item.port }}"
loop: "{{ portlist }}"
register: foo
- set_fact:
foo: "{{ foo.results | map(attribute='ansible_facts.template') | list }}"
- debug:
var: foo
I am trying to build playbook that dynamically queries Windows' registry to detect installed instances of SQL Server (or anything else), its version, location, etc. and do X action for every instance. This works ok if only one SQL instance is installed but I am not sure how to achieve this in multi-instance environment as I am mixing dicts and list and I am not sure how to solve this..
As a simple example playbook below detects installed SQL instances based on reg keys and checks version of SQL for each instance. I would like to out the info on per instance basis (or even better put this into dict variable so I can use it later and add more details based on other reg keys).
Problem is that some of the returned data is a list and I am not sure how to add it to the loop (or add it to dict where key is the instance for example).
Code:
- name: 'Go to Windows registry and check if any SQL instance is installed - using win_reg_stat module'
win_reg_stat:
path: HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL
register: reg_InstalledInstances
- name: 'Go to Windows registry and for each installed instance get its version number'
win_reg_stat:
path: HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\{{item.value.raw_value}}\MSSQLServer\CurrentVersion
name: CurrentVersion
with_dict: '{{reg_InstalledInstances.properties}}'
register: reg_CurrentVersion
- debug:
msg:
- '{{reg_CurrentVersion}}'
- name: 'Show all the details'
debug:
msg:
- 'Hostname: {{inventory_hostname}}'
- 'SQL Instance: {{item.key}}'
- 'SQL Instance in Registry: {{item.value.raw_value}}'
#- 'CurrentVersion: {{reg_CurrentVersion.results.raw_value}}'
with_dict: '{{reg_InstalledInstances.properties}}'
- name:
debug:
msg:
- '{{reg_CurrentVersion}}'
Problem:
I am not sure how to refer reg_CurrentVersion into the loop - in the loop (i tried {{reg_CurrentVersion.results.item.raw_value}} as well):
...
- 'CurrentVersion: {{reg_CurrentVersion.results.raw_value}}'
with_dict: '{{reg_InstalledInstances.properties}}'
results in:
the task includes an option with an undefined variable. The error was: 'list object' has no attribute 'raw_value'
reg_CurrentVersion on its own works fine and looks like this:
ok: [gbltcdevcmdr01] => {
"msg": [
{
"changed": false,
"msg": "All items completed",
"results": [
{
"ansible_loop_var": "item",
"changed": false,
"exists": true,
"failed": false,
"item": {
"key": "SQL2014",
"value": {
"raw_value": "MSSQL12.SQL2014",
"type": "REG_SZ",
"value": "MSSQL12.SQL2014"
}
},
"raw_value": "12.0.6024.0",
"type": "REG_SZ",
"value": "12.0.6024.0"
},
{
"ansible_loop_var": "item",
"changed": false,
"exists": true,
"failed": false,
"item": {
"key": "SQL2016",
"value": {
"raw_value": "MSSQL13.SQL2016",
"type": "REG_SZ",
"value": "MSSQL13.SQL2016"
}
},
"raw_value": "13.2.5026.0",
"type": "REG_SZ",
"value": "13.2.5026.0"
},
{
"ansible_loop_var": "item",
"changed": false,
"exists": true,
"failed": false,
"item": {
"key": "MSSQLSERVER",
"value": {
"raw_value": "MSSQL11.MSSQLSERVER",
"type": "REG_SZ",
"value": "MSSQL11.MSSQLSERVER"
}
},
"raw_value": "11.0.7001.0",
"type": "REG_SZ",
"value": "11.0.7001.0"
},
{
"ansible_loop_var": "item",
"changed": false,
"exists": true,
"failed": false,
"item": {
"key": "SQL2017",
"value": {
"raw_value": "MSSQL14.SQL2017",
"type": "REG_SZ",
"value": "MSSQL14.SQL2017"
}
},
"raw_value": "14.0.1000.169",
"type": "REG_SZ",
"value": "14.0.1000.169"
}
]
}
]
}
EDIT:
at the moment if I run the initial code:
...
- name: 'Show all the details'
debug:
msg:
- 'Hostname: {{inventory_hostname}}'
- 'SQL Instance: {{item.key}}'
- 'SQL Instance in Registry: {{item.value.raw_value}}'
#- 'CurrentVersion: {{reg_CurrentVersion.results.raw_value}}'
with_dict: '{{reg_InstalledInstances.properties}}'
I got this:
ok: [testhost] => (item={'key': 'SQL2014', 'value': {'raw_value': 'MSSQL12.SQL2014', 'value': 'MSSQL12.SQL2014', 'type': 'REG_SZ'}}) => {
"msg": [
"Hostname: testhost",
"SQL Instance: SQL2014",
"SQL Instance in Registry: MSSQL12.SQL2014"
]
}
ok: [testhost] => (item={'key': 'SQL2016', 'value': {'raw_value': 'MSSQL13.SQL2016', 'value': 'MSSQL13.SQL2016', 'type': 'REG_SZ'}}) => {
"msg": [
"Hostname: testhost",
"SQL Instance: SQL2016",
"SQL Instance in Registry: MSSQL13.SQL2016"
]
}
ok: [testhost] => (item={'key': 'MSSQLSERVER', 'value': {'raw_value': 'MSSQL11.MSSQLSERVER', 'value': 'MSSQL11.MSSQLSERVER', 'type': 'REG_SZ'}}) => {
"msg": [
"Hostname: testhost",
"SQL Instance: MSSQLSERVER",
"SQL Instance in Registry: MSSQL11.MSSQLSERVER"
]
}
ok: [testhost] => (item={'key': 'SQL2017', 'value': {'raw_value': 'MSSQL14.SQL2017', 'value': 'MSSQL14.SQL2017', 'type': 'REG_SZ'}}) => {
"msg": [
"Hostname: testhost",
"SQL Instance: SQL2017",
"SQL Instance in Registry: MSSQL14.SQL2017"
]
}
I would like to simply add reg_CurrentVersion.results.raw_value as an extra line for each instance. Something like below:
ok: [testhost] => (item={'key': 'SQL2014', 'value': {'raw_value': 'MSSQL12.SQL2014', 'value': 'MSSQL12.SQL2014', 'type': 'REG_SZ'}}) => {
"msg": [
"Hostname: testhost",
"SQL Instance: SQL2014",
"SQL Instance in Registry: MSSQL12.SQL2014"
"CurrentVersion: 12.0.6024.0"
]
}
ok: [testhost] => (item={'key': 'SQL2016', 'value': {'raw_value': 'MSSQL13.SQL2016', 'value': 'MSSQL13.SQL2016', 'type': 'REG_SZ'}}) => {
"msg": [
"Hostname: testhost",
"SQL Instance: SQL2016",
"SQL Instance in Registry: MSSQL13.SQL2016"
"CurrentVersion: 13.2.5026.0"
]
}
ok: [testhost] => (item={'key': 'MSSQLSERVER', 'value': {'raw_value': 'MSSQL11.MSSQLSERVER', 'value': 'MSSQL11.MSSQLSERVER', 'type': 'REG_SZ'}}) => {
"msg": [
"Hostname: testhost",
"SQL Instance: MSSQLSERVER",
"SQL Instance in Registry: MSSQL11.MSSQLSERVER"
"CurrentVersion: 11.0.7001.0"
]
}
ok: [testhost] => (item={'key': 'SQL2017', 'value': {'raw_value': 'MSSQL14.SQL2017', 'value': 'MSSQL14.SQL2017', 'type': 'REG_SZ'}}) => {
"msg": [
"Hostname: testhost",
"SQL Instance: SQL2017",
"SQL Instance in Registry: MSSQL14.SQL2017"
"CurrentVersion: 14.0.1000.169"
]
}
PS. Is there a way to build dict and append new values to it later on?
Tomasz
Q: "Is there a way to build a dictionary and append new values to it later on?"
A: Yes. It's possible. Let's create the dictionary with the data
- set_fact:
mylist: "{{ reg_CurrentVersion.results|
json_query('[].{instance: item.key,
registry: item.value.raw_value,
version: raw_value}') }}"
- debug:
var: mylist
gives
"mylist": [
{
"instance": "SQL2014",
"registry": "MSSQL12.SQL2014",
"version": "12.0.6024.0"
},
{
"instance": "SQL2016",
"registry": "MSSQL13.SQL2016",
"version": "13.2.5026.0"
},
{
"instance": "MSSQLSERVER",
"registry": "MSSQL11.MSSQLSERVER",
"version": "11.0.7001.0"
},
{
"instance": "SQL2017",
"registry": "MSSQL14.SQL2017",
"version": "14.0.1000.169"
}
]
Append hostname to each dictionary
- set_fact:
mylist2: "{{ mylist2|default([]) +
[item|combine({'hostname': inventory_hostname})] }}"
loop: "{{ mylist }}"
- debug:
var: mylist2
gives
"mylist2": [
{
"hostname": "localhost",
"instance": "SQL2014",
"registry": "MSSQL12.SQL2014",
"version": "12.0.6024.0"
},
{
"hostname": "localhost",
"instance": "SQL2016",
"registry": "MSSQL13.SQL2016",
"version": "13.2.5026.0"
},
{
"hostname": "localhost",
"instance": "MSSQLSERVER",
"registry": "MSSQL11.MSSQLSERVER",
"version": "11.0.7001.0"
},
{
"hostname": "localhost",
"instance": "SQL2017",
"registry": "MSSQL14.SQL2017",
"version": "14.0.1000.169"
}
]
This is my output of EC2 instance. I am trying to access "instance_type".
And here is my task.
ec2:
key_name: redhat
group: MY_EC2
instance_type: t2.micro
image: ami-cfe4b2b0
region: us-east-1
zone: us-east-1a
wait: true
exact_count: 1
count_tag:
name: MyProjectInstances
instance_tags:
name: Ansible
register: ec2
- set_fact:
inst: "{{ ec2 }}"
- debug:
msg: "{{ inst }}"
I can reach Instances block through trying this.
debug:
msg: "{{ inst.instances }}" but cannot go further, getting error of undefined variable.
#
Output:
ok: [localhost] => {
"msg": {
"changed": true,
"failed": false,
"instance_ids": [
"i-0be089202b191769e"
],
"instances": [
{
"ami_launch_index": "0",
"architecture": "x86_64",
"block_device_mapping": {
"/dev/xvda": {
"delete_on_termination": true,
"status": "attached",
"volume_id": "vol-02b129004f1a5fb89"
}
},
"dns_name": "ec2-34-204-84-170.compute-1.amazonaws.com",
"ebs_optimized": false,
"groups": {
"sg-06c09a2c83d7b1a96": "MY_EC2"
},
"hypervisor": "xen",
"id": "i-0be089202b191769e",
"image_id": "ami-cfe4b2b0",
"instance_type": "t2.micro",
"kernel": null,
"key_name": "redhat",
"launch_time": "2018-07-15T14:34:43.000Z",
"placement": "us-east-1a",
"private_dns_name": "ip-172-31-35-24.ec2.internal",
"private_ip": "172.31.35.24",
"public_dns_name": "ec2-34-204-84-170.compute-1.amazonaws.com",
"public_ip": "34.204.84.170",
"ramdisk": null,
"region": "us-east-1",
"root_device_name": "/dev/xvda",
"root_device_type": "ebs",
"state": "running",
"state_code": 16,
"tags": {
"name": "Ansible"
},
"tenancy": "default",
"virtualization_type": "hvm"
}
Please try as below::
- name: Get instance Type
debug: msg={{ inst | json_query('instances[].instance_type') }}