I am trying to get the "count" value from the dictionary
"{ \"_id\" : ObjectId(\"5d3a1643c43c898d01a3c740\"), \"count\" : 2 }"
present at the last element of the ansible stdout_lines.
TASK [version_update : debug] ******************************************************************************************************************************************
ok: [192.168.27.125] => {
"count_info.stdout": "MongoDB shell version v4.0.6\nconnecting to: mongodb://127.0.0.1:27017/configure-db?gssapiServiceName=mongodb\nImplicit session: session { \"id\" : UUID(\"4bfad3ba-981f-47de-86f9-a1fadbe28e12\") }\nMongoDB server version: 4.0.6\n{ \"_id\" : ObjectId(\"5d3a1643c43c898d01a3c740\"), \"count\" : 2 }"
}
TASK [version_update : debug] ******************************************************************************************************************************************
ok: [192.168.27.125] => {
"count_info.stdout_lines": [
"MongoDB shell version v4.0.6",
"connecting to: mongodb://127.0.0.1:27017/configure-db?gssapiServiceName=mongodb",
"Implicit session: session { \"id\" : UUID(\"4bfad3ba-981f-47de-86f9-a1fadbe28e12\") }",
"MongoDB server version: 4.0.6",
"{ \"_id\" : ObjectId(\"5d3a1643c43c898d01a3c740\"), \"count\" : 2 }"
]
}
I tried the following two ways but not successful.
- debug:
msg: "{{ (count_info.stdout_lines[-1] | from_json).count }}"
- name: count value
debug:
msg: "{{ count_info.stdout_lines[-1] | json_query('count') }}"
Error log:
TASK [version_update : debug] ******************************************************************************************************************************************
fatal: [192.168.27.125]: FAILED! => {"msg": "the field 'args' has an invalid value ({u'msg': u'{{ (count_info.stdout_lines[-1] | from_json).count }}'}), and could not be converted to an dict.The error was: No JSON object could be decoded\n\nThe error appears to have been in '/home/admin/playbook-3/roles/version_update/tasks/version_update.yml': line 73, 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- debug:\n ^ here\n"}
to retry, use: --limit #/home/admin/playbook-3/version_update.retry
TASK [version_update : count value] ************************************************************************************************************************************
ok: [192.168.27.125] => {
"msg": ""
}
Your last line in the output is not a pure json string (probably bson from your MongoDB output). The error you get is actually coming from the filter itself not getting a correct input and failing.
You will have to translate that to pure json before you can use the from_json filter. The offending data is the ObjectId(\"5d3a1643c43c898d01a3c740\") that cannot be deserialized by the filter. This should be changed in the task/command you use to register your variable. You can have a look at this interesting question on the subject with many answers that will probably give you some clues.
Once this is done, accessing your data becomes easy as you had already figured out. Here is an example with a modified sample data (the way I think you should finally get it) just to confirm your where on the right track.
- name: Get count in json serialized string
hosts: localhost
gather_facts: false
vars:
"count_info":
"stdout_lines": [
"MongoDB shell version v4.0.6",
"connecting to: mongodb://127.0.0.1:27017/configure-db?gssapiServiceName=mongodb",
"Implicit session: session { \"id\" : UUID(\"4bfad3ba-981f-47de-86f9-a1fadbe28e12\") }",
"MongoDB server version: 4.0.6",
"{ \"_id\" : \"someDeserializedId\", \"count\" : 2 }"
]
tasks:
- name: Get count
debug:
msg: "{{ (count_info.stdout_lines[-1] | from_json).count }}"
And the result
PLAY [Get count in json serialized string] ********************************************************************************************************************************************************************************
TASK [Get count] **********************************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "2"
}
although the element has the structure of a dictionary, its in fact a string, which i couldnt filter it with to_json or to_nice_json to convert it to a dictionary.
using the below sequence of tasks will get the value you want to pick up, unfortunately i didnt find a way to do it in one task. the logic is as follows:
get the last element from the list, and split the string into key-value substrings, separated by the ,.
parse this list and find the element that contains the keyword count (you can enhance it here if you think the count may appear in other lines too). then with regex, get the numerical value out of it.
PB:
---
- hosts: localhost
gather_facts: false
vars:
final_count_value: -1
count_info:
stdout_lines:
- MongoDB shell version v4.0.6
- 'connecting to: mongodb://127.0.0.1:27017/configure-db?gssapiServiceName=mongodb'
- 'Implicit session: session { "id" : UUID("4bfad3ba-981f-47de-86f9-a1fadbe28e12")
}'
- 'MongoDB server version: 4.0.6'
- '{ "_id" : ObjectId("5d3a1643c43c898d01a3c740"), "count" : 2 }'
tasks:
- name: prepare list var
set_fact:
temp_list: "{{ (count_info.stdout_lines | last).split(', ') | list }}"
- name: find count
set_fact:
final_count_value: "{{ item | regex_replace('\"count\" : ', '') | regex_replace(' }', '') }}"
when: item is search('count')
with_items:
- "{{ temp_list }}"
- name: print result
debug:
var: final_count_value
output:
PLAY [localhost] *******************************************************************************************************************************************************************************************************
TASK [prepare list var] ************************************************************************************************************************************************************************************************
ok: [localhost]
TASK [find count] ******************************************************************************************************************************************************************************************************
skipping: [localhost] => (item={ "_id" : ObjectId("5d3a1643c43c898d01a3c740"))
ok: [localhost] => (item="count" : 2 })
TASK [print result] ****************************************************************************************************************************************************************************************************
ok: [localhost] => {
"final_count_value": "2"
}
UPDATE
to subtract 1 from the result, you should use:
- name: find count and subtract 1
set_fact:
final_count_value: "{{ item | regex_replace('\"count\" : ', '') | regex_replace(' }', '') | int - 1 }}"
when: item is search('count')
with_items:
- "{{ temp_list }}"
hope it helps!.
Related
The idea is to add an item into the array if the item does not exist. The select attribute function returns an empty list even though there are items. Therefore the length of an empty is always 0, which in turn will create a new list every time in my case. So the union function in add a new comment section is returning a list with the only new comment erasing all the old ones.
I understand that the issue is with t_array_exists["ansible_facts"]|selectattr("common_motd_qsc_comments_array", "defined")|list|length == 0 conditional statement but I am not sure what I am doing wrong. I have tried many variations of this command. Few of them are commented. Any advice/suggestion is appreciated :)
main.yml:
- name: Get comment array from facts
set_fact:
common_motd_qsc_comments_array: "{{ ansible_local['snps']['motd']['comment_array'] }}"
register: t_array_exists
when:
- ansible_local['snps']['motd'] is defined
- ansible_local['snps']['motd']['comment_array'] is defined
- debug:
var: t_array_exists
- debug:
var: t_array_exists["ansible_facts"]|selectattr("common_motd_qsc_comments_array", "defined")|list
# var: ansible_facts|selectattr("common_motd_qsc_comments_array", "defined")|list
# var: t_array_exists|selectattr("common_motd_qsc_comments_array", "defined")|list
- name: Create an empty array if there is no array
set_fact:
common_motd_qsc_comments_array: []
when:
- t_array_exists["ansible_facts"]|selectattr("common_motd_qsc_comments_array", "defined")|list|length == 0
- debug:
var: t_array_exists["ansible_facts"]|selectattr("common_motd_qsc_comments_array", "defined")|list|length
- name: Deleting a comment if it exists
set_fact:
common_motd_qsc_comments_array: "{{ common_motd_qsc_comments_array | difference([t_new_entry]) }}"
loop: "{{ common_motd_qsc_delete_comment }}"
when: t_new_entry in common_motd_qsc_comments_array
vars:
t_new_entry: "{{ item | trim }}"
- name: Add a new comment if it doesn't exist
set_fact:
common_motd_qsc_comments_array: "{{ common_motd_qsc_comments_array | union([t_new_entry]) }}"
loop: "{{ common_motd_qsc_add_comment }}"
when: t_new_entry not in common_motd_qsc_comments_array
vars:
t_new_entry: "{{ item | trim }}"
- name: Saving comments to snps.fact file
ini_file:
dest: "/etc/ansible/facts.d/snps.fact"
section: 'motd' # header
option: 'comment_array' # key
value: "{{ common_motd_qsc_comments_array }}" # value
Ansible output:
TASK [common/motd_scratch/v1 : Get comment array from facts] ***************************************************************************************
ok: [ansible-poc-cos6]
TASK [common/motd_scratch/v1 : debug] **************************************************************************************************************
ok: [ansible-poc-cos6] => {
"t_array_exists": {
"ansible_facts": {
"common_motd_qsc_comments_array": [
"new comment 1"
]
},
"changed": false,
"failed": false
}
}
TASK [common/motd_scratch/v1 : debug] **************************************************************************************************************
ok: [ansible-poc-cos6] => {
"ansible_facts|selectattr(\"common_motd_qsc_comments_array\", \"defined\")|list": []
}
TASK [common/motd_scratch/v1 : Create an empty array if there is no array] *************************************************************************
ok: [ansible-poc-cos6]
TASK [common/motd_scratch/v1 : debug] **************************************************************************************************************
ok: [ansible-poc-cos6] => {
"t_array_exists[\"ansible_facts\"]|selectattr(\"common_motd_qsc_comments_array\", \"defined\")|list|length": "0"
}
TASK [common/motd_scratch/v1 : Add a new comment if it doesn't exist] ******************************************************************************
ok: [ansible-poc-cos6] => (item=new comment 22)
TASK [common/motd_scratch/v1 : Saving comments to snps.fact file] **********************************************************************************
changed: [ansible-poc-cos6]
TASK [common/motd_scratch/v1 : debug] **************************************************************************************************************
ok: [ansible-poc-cos6] => {
"common_motd_qsc_add_comment": [
"new comment 22"
]
}
snps.fact output:
Before:
[motd]
comment_array = ['new comment 1']
After passing new_comment as "new comment 2":
[motd]
comment_array = ['new comment 2']
Expected:
[motd]
comment_array = ['new comment 1', 'new comment 2']
You can do all of the above in one single easy step. Here is an MCVE playbook to illustrate.
Prior to running the playbook, I added the following file on my machine:
/etc/ansible/facts.d/snps.fact
{
"motd_example1": [
"One message",
"A message",
"Message to delete"
],
"motd_example2": [
"Some messages",
"Mandatory message",
"Other message"
]
}
The playbook
---
- name: Add/Remove list elements demo
hosts: localhost
gather_facts: true
vars:
# The (list of) custom message(s) I want to add if not present
my_custom_mandatory_messages:
- Mandatory message
# The (list of) custom message(s) I want to remove if present
my_custom_messages_to_delete:
- Message to delete
# The list of custom vars I'm going to loop over for demo
# In your case, you can simply use your single motd var
# directly in the below task without looping. I added this
# for convenience as the expression is exactly the same
# in all cases. Only the input data changes
my_motd_example_vars:
- motd_example1
- motd_example2
- motd_example3 # This one does not even exist in ansible_local.snps
tasks:
- name: Show result using local facts for each demo test var
debug:
msg: "{{ ansible_local.snps[item] | default([])
| union(my_custom_mandatory_messages)
| difference(my_custom_messages_to_delete) }}"
loop: "{{ my_motd_example_vars }}"
- name: Proove it works with a totaly undefined var
debug:
msg: "{{ totally.undefined.var | default([])
| union(my_custom_mandatory_messages)
| difference(my_custom_messages_to_delete) }}"
The result
TASK [Gathering Facts] **********************************************************************************************************************************************************************************************************************
ok: [localhost]
TASK [Show result using local facts for each demo test var] *********************************************************************************************************************************************************************************
ok: [localhost] => (item=motd_example1) => {
"msg": [
"One message",
"A message",
"Mandatory message"
]
}
ok: [localhost] => (item=motd_example2) => {
"msg": [
"Some messages",
"Mandatory message",
"Other message"
]
}
ok: [localhost] => (item=motd_example3) => {
"msg": [
"Mandatory message"
]
}
TASK [Simple proof that it works with a totaly undefined var] *******************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
"Mandatory message"
]
}
PLAY RECAP **********************************************************************************************************************************************************************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Not sure I understood exactly what the problem is, but if you are trying to merge two dictionaries (with one overwriting the other if the key already exists), then you might want to take a look at:
https://docs.ansible.com/ansible/latest/user_guide/playbooks_advanced_syntax.html#yaml-anchors-and-aliases-sharing-variable-values
The very first example shows exactly that, with just YAML. If that doesn't do the trick, then you might want to try the combine filter:
https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#combining-hashes-dictionaries
HTH
Alex
I was able to fix it with the help of my colleague. I just had to check if comment_array is not defined instead of trying to find its length. A simple alternate idea which works :)
- name: Create an empty array if there is no array
set_fact:
common_motd_qsc_comments_array: []
when:
- ansible_local['snps']['motd']['comment_array'] is not defined
Thank you all for your help :)
I have a var file like below and the two items don't work the same: the first one is treated as a JSON object and I can access its properties, such as script.name, but it's not the case for the second item which seems to be a plain string.
How can I define the second element of the list in such a way that I can access its properties?
---
file2: script2.j2
scripts_list:
- { name: script1, file: script1.j2 }
- "{ name: script2, file: {{ file2 }} }"
More details - I use the list in a loop like this:
# main.yml
- include_tasks: script.yml
loop: "{{ scripts_list }}"
loop_control:
loop_var: script
# script.yml
- debug:
msg: "loop variable = {{ script }}"
- debug:
msg: "loop variable name = {{ script.name }}"
The first item in the list works fine, but the second returns an error when accessing its name property.
The output seems to show that the first item is treated as a JSON structure whereas the second is just a plain string:
TASK [test : debug] ******************************************************************************************************************************************************************************************************************************
ok: [test] => {
"msg": "loop variable = {u'name': u'script1', u'file': u'script1.j2'}"
}
TASK [test : debug] ******************************************************************************************************************************************************************************************************************************
ok: [test] => {
"msg": "loop variable name = script1"
}
TASK [test : debug] ******************************************************************************************************************************************************************************************************************************
ok: [test] => {
"msg": "loop variable = { name: script2, file: script2.j2 }"
}
TASK [test : debug] ******************************************************************************************************************************************************************************************************************************
fatal: [test]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'unicode object' has no attribute 'name'\n"}
How can I define the second element of the list in such a way that I can access its properties?
Well IMO the best way to address this since you are defining your scripts info inside a yaml file is to use a yaml definition for all of them and to quote elements with jinja2 templating appropriately.
scripts_list:
- name: script1
file: script1.j2
- name: script2
file: "{{ file2 }}"
If for some reason you want to keep the jsonish definition, the following should work as expected:
scripts_list:
- { name: script1, file: script1.j2 }
- { name: script2, file: "{{ file2 }}" }
I've got a list of string element in a ansible var. I'm looking how to append to each element of the list with a defined string.
Do you know how I can do? I didn't find a way to do so.
Input:
[ "a", "b", "c" ]
Output:
[ "a-Z", "b-Z", "c-Z" ]
I really didn't like using the add-on filters or the loop. However, I stumbled across this blog post https://www.itix.fr/blog/ansible-add-prefix-suffix-to-list/ that used a different method that worked in Ansible 2.9.x.
- set_fact:
output: "{{ list_to_suffix | product(['-Z']) | map('join') | list }}"
You can use join for this. Please see the code below:
playbook -->
---
- hosts: localhost
vars:
input: [ "a", "b", "c" ]
tasks:
- name: debug
set_fact:
output: "{{ output | default([]) + ['-'.join((item,'Z'))] }}"
loop: "{{ input | list}}"
- debug:
var: output
output -->
PLAY [localhost] ********************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************
ok: [localhost]
TASK [debug] ************************************************************************************************************
ok: [localhost] => (item=a)
ok: [localhost] => (item=b)
ok: [localhost] => (item=c)
TASK [debug] ************************************************************************************************************
ok: [localhost] => {
"output": [
"a-Z",
"b-Z",
"c-Z"
]
}
PLAY RECAP **************************************************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0
With simple filters
shell> cat filter_plugins/string_filters.py
def string_prefix(prefix, s):
return prefix + s
def string_postfix(postfix, s):
return s + postfix
class FilterModule(object):
''' Ansible filters. Python string operations.'''
def filters(self):
return {
'string_prefix' : string_prefix,
'string_postfix' : string_postfix
}
the tasks below
- set_fact:
output: "{{ input|map('string_prefix', '-Z')|list }}"
- debug:
var: output
give
"output": [
"a-Z",
"b-Z",
"c-Z"
]
The same output gives the loop below
- set_fact:
output: "{{ output|default([]) + [item + '-Z'] }}"
loop: "{{ input }}"
- debug:
var: output
Below is how both prefix and suffix can be done in one line
- debug:
var: result
vars:
prefix: foo1
suffix: foo2
a_list: [ "bar", "bat", "baz" ]
result: "{{ [prefix] | product(a_list) | map('join') | list | product([suffix]) | map('join') | list }}"
Yet another solution, for pre-fixing and post-fixing, without custom filters (which make a very elegant code, by the way):
- set_fact:
input: ['a', 'b', 'c']
suffix: '-Z'
prefix: 'A-'
- debug:
var: suffixed
vars:
suffixed: "{{ input | zip_longest([], fillvalue=suffix) | map('join') | list }}"
- debug:
var: prefixed
vars:
prefixed: "{{ [] | zip_longest(input, fillvalue=prefix) | map('join') | list }}"
"suffixed": [
"a-Z",
"b-Z",
"c-Z"
]
"prefixed": [
"A-a",
"A-b",
"A-c"
]
A lot of the other answers felt a bit cumbersome when I wanted to both append and prepend data, so I ended up using regex_replace with map instead, which simplifies things quite considerably in my opinion:
- name: Create some data to play with
set_fact:
domains:
- example-one
- example-two
- example-three
tld: com
- name: Demonstrate the method
debug:
msg: >-
{{
domains
| map('regex_replace', '^(.*)$', 'www.\1.' + tld)
}}
Outputs:
TASK [example : Create some data to play with] ****************************
ok: [server]
TASK [example : Demonstrate the method] ***********************************
ok: [server] => {
"msg": [
"www.example-one.com",
"www.example-two.com",
"www.example-three.com"
]
}
In writing this answer, I actually found this documented in the Ansible docs, so it appears this is a recommended method too.
I'm seeking for your ideas to elegantly handle a from_json filter failure when it happens.
I have a generic task in an ansible role that I use to call different groovy script in sonatype nexus repository manager (the full role is available on github)
- name: Calling Groovy script {{ script_name }}
uri:
url: "{{ nexus_api_scheme }}://{{ nexus_api_hostname }}:{{ nexus_api_port }}\
{{ nexus_api_context_path }}{{ nexus_rest_api_endpoint }}/{{ script_name }}/run"
user: 'admin'
password: "{{ current_nexus_admin_password }}"
headers:
Content-Type: "text/plain"
method: POST
force_basic_auth: yes
validate_certs: "{{ nexus_api_validate_certs }}"
body: "{{ args | to_json }}"
register: script_run
The scripts I call all return a json map
{
"name": "name of the script",
"result": "whatever was used as a groovy return statement"
}
Note: there is no way to add anything else to this map from groovy, I can only push data back to ansible in the result
I want to use result to further detail if my script call leads to an error, a change or an ok status in ansible. Some groovy scripts are fully "ansible aware" and will return in result an escaped json string I can use to check for error/changes.
Here is a semi-fictive example:
{
"name": "create_repos_from_list",
"result": "{\"changed\": false, \"error\": false, \"action_details\": [{\"name\": \"my_registry\", \"format\": \"docker\", \"type\": \"hosted\", \"status\": \"no change\"}]}"
}
But (for time being...) some other scripts are not "ansible aware" (or I cannot change them myself) and will return in result a simple string (without any usable information in most cases).
Now my real problem: If I get a json result I want to use it to check for failure or change. If its not a json result, I'll just rely on the http 200 for a success (until the script can be fixed).
I was almost there with the following options to my task:
failed_when: >-
script_run.status != 200
or
(script_run.json.result | from_json | default({})).error | default(false) | bool
changed_when: >-
(script_run.json.result | from_json | default({})).changed | default(false) | bool
Unfortunately, when result is a simple string, from_json will fire an error (Expecting value: line 1 column 1 (char 0)) before the default can be applied and my playbook ends there.
My current workaround is to add another condition to check if result starts with a { before trying to read json but I'm not really happy with this (as the json string might still be corrupted and still lead to an error)
If any of you have experience/idea on how to gracefully handle this json decode error with a default value or to nicelly check if a string can be decoded as json in ansible, I'll take all suggestions.
I found out that writing complex stuff in failed_when/changed_when can get easily out of hand. Have you tried creating a filter and then do something like failed_when: script_run | my_role_failed ?
https://gist.github.com/tuxfight3r/37048ba536575277f5f4d26813d69489
filters live inside your ansible role, under filter_plugins/, so distribution shouldnt be an issue. You can go as far as creating empty ansible roles that only define filters and then include them in other roles (through meta/main.yml) to be used there.
I'm not sure it meets the "elegant" threshold, but I used a custom test plugin, and a jinja2 {{ <something> if <test> else <somethingelse> }} expression to solve this problem:
# test_plugins/is_json.py
import json
def is_json(input_string):
''' Tests if input_string is valid JSON
Returns a bool
'''
try:
json.loads(input_string)
return True
except:
return False
class TestModule(object):
def tests(self):
return {
'json': is_json,
}
# test_json_test.yaml
---
- name: 'Test json test'
hosts: localhost
tasks:
- name: 'Give us an empty dict on invalid json'
with_items:
- ' {"somekey": "somevalue"} ' # valid JSON
# ^-extra space here to ensure Ansible treats this as a string
- '{"somekey": "somevalue"}' # valid JSON
- ' { }' # valid
- ' [ ]' # valid
- '[]' # valid
- "I'm not valid JSON" # invalid JSON
debug:
msg: '{{ item if item is json else "{}" }}'
# ^^^^-our test
Output:
PLAY [Test json test] *************
TASK [Gathering Facts] ************
ok: [localhost]
TASK [Give us an empty dict on invalid json] ************
ok: [localhost] => (item= {"somekey": "somevalue"} ) => {
"msg": " {\"somekey\": \"somevalue\"} "
}
ok: [localhost] => (item={'somekey': 'somevalue'}) => {
"msg": {
"somekey": "somevalue"
}
}
ok: [localhost] => (item= { }) => {
"msg": " { }"
}
ok: [localhost] => (item= [ ]) => {
"msg": " [ ]"
}
ok: [localhost] => (item=[]) => {
"msg": []
}
ok: [localhost] => (item=I'm not valid JSON) => {
"msg": {}
}
PLAY RECAP ****************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
I need to merge two JSON objects based on first object keys
object1 = {
"params" : {
"type": ["type1", "type2"],
"requeststate": []
}
}
object2 = {
"params" : {
"type": ["type2", "type3", "type4"],
"requeststate": ["Original", "Revised" ],
"responsestate": ["Approved" ]
}
}
I need to merge two object based on first object key and my output should look like below
mergedobject = {
"params" : {
"type": ["type1", "type2", "type3", "type4"],
"requeststate": ["Original", "Revised"]
}
}
i searched for my case and didnt find much details
Please let me know is it possible to do with ansible
I can able to merge array with
set_fact:
mergedrequeststate: "{{ object1.params.requeststate + object2.params.requeststate }}"
but my case involved with morethan 15 params object and I cant declare all the param object . Also it may grow in future and I need handle that if possible.
Please comment if you need more details.
Thanks for your support
Use the combine filter.
- set_fact:
mergedobject: "{{ object1.params | combine (object2.params) }}"
the requirement is well described, i would only add that you want to merge the keys and get the unique values from the 2 objects (if that's not the case, pay attention to the union filter in the PB below). Also, your example variables assume that the we want to merge the keys under objectX.params.
without further due, here is a PB that will get you going. there is 1 debug step to display all the keys your object1.params has, then a loop to merge the values of the 2 objects, then a final print.
PB:
---
- hosts: localhost
gather_facts: false
vars:
object1:
params:
type:
- type1
- type2
requeststate: []
object2:
params:
type:
- type2
- type3
- type4
requeststate:
- Original
- Revised
responsestate:
- Approved
tasks:
- name: print all the keys in the object1.params variable
debug:
msg: "{{ object1['params'].keys() | list }}"
- name: for each key, merge from the 2 variables
set_fact:
mergedobj: "{{ mergedobj|default({}) | combine({item: object1['params'][item] | union(object2['params'][item]) }) }}"
with_items:
- "{{ object1['params'].keys() | list }}"
- name: print final result
debug:
var: mergedobj
execution result:
[http_offline#greenhat-29 tests]$ ansible-playbook test.yml
PLAY [localhost] *******************************************************************************************************************************************************************************************************
TASK [print all the keys in the object1.params variable] ***************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
"type",
"requeststate"
]
}
TASK [for each key, merge from the 2 variables] ************************************************************************************************************************************************************************
ok: [localhost] => (item=type)
ok: [localhost] => (item=requeststate)
TASK [print final result] **********************************************************************************************************************************************************************************************
ok: [localhost] => {
"mergedobj": {
"requeststate": [
"Original",
"Revised"
],
"type": [
"type1",
"type2",
"type3",
"type4"
]
}
}
PLAY RECAP *************************************************************************************************************************************************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0
[http_offline#greenhat-29 tests]$
hope it helps
you should check out the documentation, you can simply do:
- set_fact:
mergedobject: "{{ object1 | combine(object2, recursive=True) }}"