Reputation: 301
So, we are wanting to propagate a list of logged-in users to our hosts. We have a batch script that does this for us and parses it to JSON format.
- name: Process win_shell output
set_fact:
qusers: "{{ qusers_ps.stdout | from_json }}"
- debug:
var: qusers
verbosity: 2
This debug outputs the following:
{
"qusers": {
"Server1": []
},
"_ansible_verbose_always": true,
"_ansible_no_log": false,
"changed": false
}
{
"qusers": {
"Server2": [
{
"USERNAME": "user102",
"SESSIONNAME": "rdp-tcp#0",
"ID": "6",
"STATE": "Active",
"IDLE TIME": "32",
"LOGON TIME": "5/29/2020 9:13 AM"
}
]
},
"_ansible_verbose_always": true,
"_ansible_no_log": false,
"changed": false
}
{
"qusers": {
"Server3": [
{
"USERNAME": "user183",
"SESSIONNAME": "",
"ID": "49",
"STATE": "Disc",
"IDLE TIME": "14:34",
"LOGON TIME": "5/28/2020 7:58 AM"
},
{
"USERNAME": "user103",
"SESSIONNAME": "",
"ID": "51",
"STATE": "Disc",
"IDLE TIME": "18:26",
"LOGON TIME": "5/28/2020 8:18 AM"
},
{
"USERNAME": "user148",
"SESSIONNAME": "",
"ID": "52",
"STATE": "Disc",
"IDLE TIME": "17:10",
"LOGON TIME": "5/28/2020 9:08 AM"
}
]
},
"_ansible_verbose_always": true,
"_ansible_no_log": false,
"changed": false
}
So you can see that debug returns JSON with the server name as the root element, and then an array of objects with key/pair values. We need to be able to query values within these array objects, such as 'USERNAME' and 'IDLE TIME' for each server. I've been able to do this statically (shown below) to grab the user of the first array object, but I can't figure out how to do this dynamically.
- name: Test selecting JSON output and register as array
debug:
msg: "{{ item.value }}"
loop: "{{ q('dict', qusers) }}"
register: user_op
- name: Set array variable
set_fact:
user_array: "{{ user_op.results }}"
- name: Print item value # Prints array object as is
debug:
msg: "{{ item.item.value }} "
with_items: "{{ user_array }}"
- name: Test pulling JSON from array with conditional # This one works, but only grabs the first user
debug:
msg: "{{ item.item.value[0]['USERNAME'] }} is logged into {{item.item.key }}"
with_items: "{{ user_array }}"
when: item.item.value != []
The last play is the only time I've ever been able to reach a specific key/pair element. How do I modify this to dynamically perform this operation for every user session object in the array instead of only the first, and without hard coding numbers??
Upvotes: 1
Views: 2742
Reputation: 44615
I cannot easily reproduce your play loop over your three hosts, so I made a demo with your example data and a prompt allowing to choose which host to display. Of course this will be taken in charge directly for you when you repoduce this in your current playbook.
The idea is to:
dict2items
(same result as the dict
lookup you used).Below my MCVE and a play for the third element. You can play yourself for the other ones. As you can see this can actually fit in a single task once you have loaded the info from your json output.
---
- hosts: localhost
gather_facts: false
vars_prompt:
- name: host
prompt: "display host ? (1-3)"
private: no
default: 1
vars:
"qusers1": {
"Server1": []
}
"qusers2": {
"Server2": [
{
"USERNAME": "user102",
"SESSIONNAME": "rdp-tcp#0",
"ID": "6",
"STATE": "Active",
"IDLE TIME": "32",
"LOGON TIME": "5/29/2020 9:13 AM"
}
]
}
"qusers3": {
"Server3": [
{
"USERNAME": "user183",
"SESSIONNAME": "",
"ID": "49",
"STATE": "Disc",
"IDLE TIME": "14:34",
"LOGON TIME": "5/28/2020 7:58 AM"
},
{
"USERNAME": "user103",
"SESSIONNAME": "",
"ID": "51",
"STATE": "Disc",
"IDLE TIME": "18:26",
"LOGON TIME": "5/28/2020 8:18 AM"
},
{
"USERNAME": "user148",
"SESSIONNAME": "",
"ID": "52",
"STATE": "Disc",
"IDLE TIME": "17:10",
"LOGON TIME": "5/28/2020 9:08 AM"
}
]
}
tasks:
- name: Load the relevent host data for demo to be in same condition as in original play
set_fact:
qusers: "{{ lookup('vars', 'qusers' + host) }}"
- name: Show info about users
vars:
host_users_info: "{{ (qusers | dict2items).0 }}"
servername: "{{ host_users_info.key }}"
loguedin_users: "{{ host_users_info.value }}"
debug:
msg: "{{ item.USERNAME }} is logged into {{ servername }} and is idle for {{ item['IDLE TIME'] }}"
loop: "{{ loguedin_users }}"
Which gives for element 3
$ ansible-playbook test.yml
display host ? (1-3) [1]: 3
PLAY [localhost] ************************************************************************************************************************************
TASK [Load the relevent host data for demo to be in same condition as in original play] *************************************************************
ok: [localhost]
TASK [Show info about users] ************************************************************************************************************************
ok: [localhost] => (item={'USERNAME': 'user183', 'SESSIONNAME': '', 'ID': '49', 'STATE': 'Disc', 'IDLE TIME': '14:34', 'LOGON TIME': '5/28/2020 7:58 AM'}) => {
"msg": "user183 is logged into Server3 and is idle for 14:34"
}
ok: [localhost] => (item={'USERNAME': 'user103', 'SESSIONNAME': '', 'ID': '51', 'STATE': 'Disc', 'IDLE TIME': '18:26', 'LOGON TIME': '5/28/2020 8:18 AM'}) => {
"msg": "user103 is logged into Server3 and is idle for 18:26"
}
ok: [localhost] => (item={'USERNAME': 'user148', 'SESSIONNAME': '', 'ID': '52', 'STATE': 'Disc', 'IDLE TIME': '17:10', 'LOGON TIME': '5/28/2020 9:08 AM'}) => {
"msg": "user148 is logged into Server3 and is idle for 17:10"
}
PLAY RECAP ******************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Upvotes: 1