191 lines
8.3 KiB
YAML
Executable File
191 lines
8.3 KiB
YAML
Executable File
---
|
|
- name: nested groups loop
|
|
block:
|
|
- name: Reset loop variables # without unsetting infinte loops will occur
|
|
set_fact:
|
|
group_present: false
|
|
find_groups: []
|
|
#find_users: [] # we dont want to reset this var, this will append on each loop until exit (unexpected behaviour but works)
|
|
find_group_members_tidy: []
|
|
group_members: []
|
|
samaccountname_tidy: []
|
|
samaccountname_group_members: []
|
|
member_type: []
|
|
member_attributes: []
|
|
|
|
# - name: Inspect dummy host object_attributes
|
|
# debug:
|
|
# msg: "{{ hostvars['DUMMY_HOST']['object_attributes'] }}"
|
|
|
|
- name: Filter groups into a list - CHANGED
|
|
set_fact:
|
|
find_groups: "{{ find_groups | default([]) + [dict(name=item.name, role=item.role, type=item.type)] }}"
|
|
with_items: "{{ hostvars['DUMMY_HOST']['object_attributes'] }}"
|
|
when: item.type == 'Group'
|
|
|
|
- name: Append users to list - CHANGED
|
|
set_fact:
|
|
find_users: "{{ find_users | default([]) + [dict(name=item.name, role=item.role, type=item.type)] }}"
|
|
with_items: "{{ hostvars['DUMMY_HOST']['object_attributes'] }}"
|
|
when: item.type == 'Person'
|
|
|
|
# - debug:
|
|
# msg:
|
|
# - "{{ find_groups }}"
|
|
# - "{{ find_users }}"
|
|
# when: find_groups is defined
|
|
|
|
- name: Query group members
|
|
win_shell: ([ADSISearcher] "(sAMAccountName={{ item.name }})").FindOne().Properties.member
|
|
register: find_group_members_result
|
|
with_items: "{{ find_groups }}"
|
|
when: find_groups is defined
|
|
|
|
# - debug:
|
|
# msg: "{{ find_group_members_result }}"
|
|
# when: find_group_members_result is defined
|
|
|
|
- name: Tidy group members into dict of names and role
|
|
set_fact:
|
|
find_group_members_tidy: '{{ find_group_members_tidy | default([]) + [dict(name=item.name, role=item.role)] }}'
|
|
with_items: "{{ find_group_members_result | json_query(jmesquery) }}"
|
|
vars:
|
|
jmesquery: "results[].{role: @.item.role, name: @.stdout_lines}"
|
|
when: find_groups is defined # new - did i miss this in the demo
|
|
|
|
- name: Tidy group members into dict of name and role
|
|
set_fact:
|
|
group_members: "{{ group_members | default([]) + [dict(name=item.1.split(',')[0].split('CN=')[1], role=item.0.role)] }}"
|
|
with_subelements:
|
|
- "{{ find_group_members_tidy }}"
|
|
- name
|
|
when: find_groups is defined # new - did i miss this in the demo
|
|
|
|
# - debug:
|
|
# msg: "{{ group_members }}"
|
|
# when: group_members is defined
|
|
|
|
# the UoN account field distinguishedname uses the short account name the same as samaccountname - this is helpful when looking up group members
|
|
# distinguishedname {CN=tseed,CN=Users,DC=netappsim,DC=local}
|
|
# samaccountname {tseed}
|
|
#
|
|
# out of the box AD will have the full name of the user in the distinguishedname field
|
|
# distinguishedname {CN=Toby Seed,CN=Users,DC=netappsim,DC=local}
|
|
# samaccountname {tseed}
|
|
#
|
|
# an additional check follows to lookup a samaccountname using the distinguishedname, this maintains compatibility with non UoN AD
|
|
|
|
- name: Find group members sAMAccountName
|
|
win_shell: ([ADSISearcher] "(cn={{ item.name }})").FindOne().Properties.samaccountname
|
|
register: samaccountname_result
|
|
with_items: "{{ group_members }}"
|
|
when: group_members is defined
|
|
|
|
- name: Tidy group members sAMAccountName into list
|
|
set_fact:
|
|
samaccountname_tidy: "{{ samaccountname_tidy | default([]) + [(item.stdout_lines)[0]] }}"
|
|
with_items: "{{ samaccountname_result.results }}"
|
|
when: group_members is defined
|
|
|
|
- name: Rebuild group_members dict with sAMAccountName
|
|
set_fact:
|
|
samaccountname_group_members: "{{ samaccountname_group_members | default([]) + [ dict(name=item[1], role=item[0].role) ] }}"
|
|
loop: "{{ group_members|zip(samaccountname_tidy)|list }}"
|
|
when: group_members is defined
|
|
|
|
# - debug:
|
|
# msg: "{{ samaccountname_group_members }}"
|
|
# when: group_members is defined
|
|
|
|
- name: copy samaccountname_group_members to group_members
|
|
set_fact:
|
|
group_members: "{{ samaccountname_group_members }}"
|
|
when: samaccountname_group_members is defined
|
|
|
|
# - debug:
|
|
# msg: "{{ group_members }}"
|
|
# when: group_members is defined
|
|
|
|
- name: Check AD object is user or group
|
|
win_shell: ([ADSISearcher] "(sAMAccountName={{ item.name }})").FindOne().Properties.objectcategory
|
|
register: member_type_result
|
|
with_items: "{{ group_members }}"
|
|
when: group_members is defined
|
|
|
|
# - debug:
|
|
# msg: "{{ member_type_result }}"
|
|
# when: group_members is defined
|
|
|
|
- name: Build list of AD object type
|
|
set_fact:
|
|
member_type: "{{ member_type | default([]) + [(item.stdout.split(',')[0].split('CN=')[1])] }}"
|
|
with_items: "{{ member_type_result.results }}"
|
|
when: group_members is defined
|
|
|
|
# - debug:
|
|
# msg: "{{ member_type }}"
|
|
# when: group_members is defined
|
|
|
|
- name: Build dict of object names and types
|
|
set_fact:
|
|
member_attributes: "{{ member_attributes | default([]) + [ dict(name=item[0].name, role=item[0].role, type=item[1]) ] }}" # effectively adding a new positional field from the list to the dict
|
|
loop: "{{ group_members|zip(member_type)|list }}"
|
|
when: group_members is defined
|
|
|
|
# - debug:
|
|
# msg: "{{ member_attributes }}"
|
|
# when: group_members is defined
|
|
|
|
- name: Reset/Add variable object_attributes to dummy host for next loop
|
|
add_host:
|
|
name: "DUMMY_HOST"
|
|
object_attributes: "{{ member_attributes }}"
|
|
when: member_attributes is defined
|
|
|
|
- name: Set flag to notify there are nested groups
|
|
set_fact:
|
|
group_present: true
|
|
with_items: "{{ member_attributes }}"
|
|
when: member_attributes is defined and item.type == 'Group'
|
|
#when: member_attributes is defined and item.type == 'GroupA' # used to break loop with test for no group_present
|
|
|
|
- name: Nested group present?
|
|
fail:
|
|
msg: Nested group detected, loop will run again
|
|
when: group_present
|
|
|
|
# the following tasks only run on the last run of the loop where there are no more groups detected
|
|
# append the users from the last run of the loop to find_users
|
|
# set find_users as a DUMMY_HOST variable to be retrieved from the calling script - this is how you pass variables back from different plays also works for include_tasks
|
|
|
|
- name: Append users to list
|
|
set_fact:
|
|
find_users: "{{ find_users | default([]) + [dict(name=item.name, type=item.type, role=item.role)] }}"
|
|
with_items: "{{ member_attributes }}"
|
|
when: item.type == 'Person'
|
|
|
|
# if the script was passed the members parameter containing only a group and the requester_user_ad is a member of this group
|
|
# there wont be an entry in the find_users dict as this wont have been caught and assigned the role='requestor' in the calling script
|
|
# all requester flag logic could be moved here, the calling script wouldnt need to pass the role key, we keep it for illustration as
|
|
# this script was origionally designed to assign roles for different RWX permissions on GPFS
|
|
# we add the user to the dict with role='requester'
|
|
- name: Check if requestor was nested in group and not passed in the members parameter
|
|
set_fact:
|
|
requester_found: "{{ item.name }}"
|
|
with_items: "{{ find_users }}"
|
|
when: item.name == requester_user_ad
|
|
|
|
- name: Add requestor if it was nested in group and not passed in the members parameter
|
|
set_fact:
|
|
find_users: "{{ find_users + [dict(name=requester_found, type='Person', role='requester')] }}"
|
|
when: requester_found is defined
|
|
|
|
- name: Add users to variable find_users for dummy host on final loop
|
|
add_host:
|
|
name: "DUMMY_HOST"
|
|
find_users: "{{ find_users }}"
|
|
when: find_users is defined
|
|
|
|
rescue:
|
|
|
|
- include_tasks: group_lookup.yml |