From 1ce56d3d9e024ecd5e494239323954cf3b624e03 Mon Sep 17 00:00:00 2001 From: Matt Anson Date: Mon, 5 Dec 2022 12:30:58 +0000 Subject: [PATCH] Get users and groups from distinct API requests An API request to retrieve a list of all users and groups is subject to pagination, which can break assumptions if your object exists but is not returned in the first page results. Query each user and group from the API directly, and then parse the result to distinguish between objects that are present or absent. --- roles/pulp_group/tasks/main.yml | 68 +++++++----- roles/pulp_user/tasks/main.yml | 101 ++++++++++-------- .../tasks/user_groups/add_or_remove_users.yml | 19 +--- .../user_groups/remove_user_from_groups.yml | 46 +------- 4 files changed, 102 insertions(+), 132 deletions(-) diff --git a/roles/pulp_group/tasks/main.yml b/roles/pulp_group/tasks/main.yml index 6ff6ab5..7b26b21 100644 --- a/roles/pulp_group/tasks/main.yml +++ b/roles/pulp_group/tasks/main.yml @@ -1,24 +1,45 @@ --- -- name: Get group list +- name: Get information for each group uri: - url: "{{ pulp_group_url }}" + url: "{{ pulp_group_url }}?name={{ item.name }}" user: "{{ pulp_username }}" password: "{{ pulp_password }}" method: GET status_code: 200 force_basic_auth: true - register: groups_list_result + loop: "{{ pulp_groups }}" + register: groups_get_result + +- name: Reset groups facts + set_fact: + remove_groups: [] + create_groups: [] + +- name: Set groups to remove fact + set_fact: + remove_groups: "{{ remove_groups + [group.json.results[0]] }}" + loop: "{{ groups_get_result.results }}" + loop_control: + loop_var: "group" + label: "{{ group.item.name }}" + when: + - group.json.count == 1 + - group.item.state is defined + - group.item.state == "absent" -- name: Set fact remove_groups +- name: Set groups to create fact set_fact: - remove_groups: "{{ (remove_groups | default([])) + [item.name] }}" - when: item.state is defined and item.state == 'absent' - with_items: "{{ pulp_groups }}" + create_groups: "{{ create_groups + [group.item] }}" + loop: "{{ groups_get_result.results }}" + loop_control: + loop_var: "group" + label: "{{ group.item.name }}" + when: + - group.json.count == 0 + - group.item.state is not defined or group.item.state != "absent" - name: Create groups - vars: - groupnames: "{{ groups_list_result.json.results | map(attribute='name') | list }}" uri: url: "{{ pulp_group_url }}" user: "{{ pulp_username }}" @@ -29,32 +50,21 @@ body: name: "{{ item.name }}" body_format: form-urlencoded - loop: "{{ pulp_groups }}" - register: result - when: - - item.name not in groupnames - - item.state is not defined or item.state != 'absent' - changed_when: result.status == 201 - -- name: Initialise hrefs - set_fact: - hrefs: [] - -- name: Set fact hrefs - set_fact: - hrefs: "{{ (hrefs | default([])) + [item.pulp_href] }}" - when: item.name in (remove_groups | default([])) - with_items: "{{ groups_list_result.json.results }}" + loop: "{{ create_groups }}" + loop_control: + label: "{{ item.name }}" + changed_when: true - name: Remove groups uri: - url: "{{ pulp_url }}{{ item }}" + url: "{{ pulp_url }}{{ item.pulp_href }}" user: "{{ pulp_username }}" password: "{{ pulp_password }}" force_basic_auth: true method: DELETE status_code: 204 body_format: form-urlencoded - loop: "{{ hrefs }}" - register: result - changed_when: result.status == 204 + loop: "{{ remove_groups }}" + loop_control: + label: "{{ item.name }}" + changed_when: true diff --git a/roles/pulp_user/tasks/main.yml b/roles/pulp_user/tasks/main.yml index a27b292..e4f8b5c 100644 --- a/roles/pulp_user/tasks/main.yml +++ b/roles/pulp_user/tasks/main.yml @@ -1,24 +1,56 @@ --- - -- name: Get user list +- name: Get information for each user uri: - url: "{{ pulp_user_url }}" + url: "{{ pulp_user_url }}?username={{ item.username }}" user: "{{ pulp_username }}" password: "{{ pulp_password }}" method: GET status_code: 200 force_basic_auth: true - register: users_list_result + loop: "{{ pulp_users }}" + register: users_get_result + +- name: Reset users facts + set_fact: + remove_users: [] + create_users: [] + update_users: [] + +- name: Set users to delete fact + set_fact: + remove_users: "{{ remove_users + [user.json.results[0]] }}" + loop: "{{ users_get_result.results }}" + loop_control: + loop_var: "user" + label: "{{ user.item.username }}" + when: + - user.json.count == 1 + - user.item.state is defined + - user.item.state == "absent" -- name: Set fact remove_users +- name: Set users to create fact set_fact: - remove_users: "{{ (remove_users | default([])) + [item.username] }}" - when: item.state is defined and item.state == 'absent' - with_items: "{{ pulp_users }}" + create_users: "{{ create_users + [user.item] }}" + loop: "{{ users_get_result.results }}" + loop_control: + loop_var: "user" + label: "{{ user.item.username }}" + when: + - user.json.count == 0 + - user.item.state is not defined or user.item.state != "absent" + +- name: Set users to update fact + set_fact: + update_users: "{{ update_users + [user.json.results[0] | combine(user.item) | combine({'existing_groups': user.json.results[0]['groups']}) ] }}" + loop: "{{ users_get_result.results }}" + loop_control: + loop_var: "user" + label: "{{ user.item.username }}" + when: + - user.json.count == 1 + - user.item.state is not defined or user.item.state != "absent" - name: Create users - vars: - usernames: "{{ users_list_result.json.results | map(attribute='username') | list }}" uri: url: "{{ pulp_user_url }}" user: "{{ pulp_username }}" @@ -35,21 +67,14 @@ is_staff: "{{ item.is_staff | default(None) }}" is_active: "{{ item.is_active | default(None) }}" body_format: form-urlencoded - loop: "{{ pulp_users }}" + loop: "{{ create_users }}" loop_control: label: "{{ item.username }}" - register: result - when: - - item.username not in usernames - - item.state is not defined or item.state != 'absent' - changed_when: result.status == 201 + changed_when: true - name: Update existing users - vars: - usernames: "{{ users_list_result.json.results | map(attribute='username') | list }}" - url_query: "[?username=='{{ item.username }}'].pulp_href" uri: - url: "{{ pulp_url }}{{ users_list_result.json.results | json_query(url_query) | first }}" + url: "{{ pulp_url }}{{ item.pulp_href }}" user: "{{ pulp_username }}" password: "{{ pulp_password }}" force_basic_auth: true @@ -63,46 +88,30 @@ is_staff: "{{ item.is_staff | default(None) }}" is_active: "{{ item.is_active | default(None) }}" body_format: form-urlencoded - loop: "{{ pulp_users }}" + loop: "{{ update_users }}" loop_control: label: "{{ item.username }}" register: result - when: - - item.username in usernames - - item.state is not defined or item.state != 'absent' - changed_when: - # The pulp API currently does not report when a change is made, so we must - # manually check - - result.json not in users_list_result.json.results - - result.status == 200 + changed_when: true - name: Add or remove user from group(s) include_tasks: user_groups/add_or_remove_users.yml - # Noop if pulp_users is defined but empty - loop: "{{ pulp_users }}" - when: item.state is not defined or item.state != 'absent' + # All users that aren't state: absent are in play here + loop: "{{ create_users + update_users }}" loop_control: loop_var: user - -- name: Initialise hrefs - set_fact: - hrefs: [] - -- name: Set fact hrefs - set_fact: - hrefs: "{{ (hrefs | default([])) + [item.pulp_href] }}" - when: item.username in (remove_users | default([])) - with_items: "{{ users_list_result.json.results }}" + label: "{{ user.username }}" - name: Delete users uri: - url: "{{ pulp_url }}{{ item }}" + url: "{{ pulp_url }}{{ item.pulp_href }}" user: "{{ pulp_username }}" password: "{{ pulp_password }}" force_basic_auth: true method: DELETE status_code: 204 body_format: form-urlencoded - loop: "{{ hrefs }}" - register: result - changed_when: result.status == 204 + loop: "{{ remove_users }}" + loop_control: + label: "{{ item.username }}" + changed_when: true diff --git a/roles/pulp_user/tasks/user_groups/add_or_remove_users.yml b/roles/pulp_user/tasks/user_groups/add_or_remove_users.yml index cedc7e1..812a4a6 100644 --- a/roles/pulp_user/tasks/user_groups/add_or_remove_users.yml +++ b/roles/pulp_user/tasks/user_groups/add_or_remove_users.yml @@ -1,27 +1,14 @@ --- -- name: Get all groups that user belongs to - uri: - url: "{{ pulp_user_url }}?username={{ user.username }}" - user: "{{ pulp_username }}" - password: "{{ pulp_password }}" - method: GET - status_code: 200 - force_basic_auth: true - register: user_group_result - -- name: Set current_group_membership fact - set_fact: - current_group_membership: "{{ user_group_result | json_query('json.results[*].groups') | flatten | map(attribute='name') | list }}" - - name: Remove user from groups not defined in pulp_users include_tasks: remove_user_from_groups.yml - loop: "{{ current_group_membership | difference(user.groups | default([], true)) }}" + loop: "{{ user.existing_groups | map(attribute='name') | difference(user.groups | default([], true)) }}" loop_control: loop_var: remove_group + when: user.existing_groups is defined - name: Add user to groups defined in pulp_users include_tasks: add_user_to_groups.yml - loop: "{{ user.groups | default([], true) | difference(current_group_membership) }}" + loop: "{{ user.groups | default([], true) | difference(user.existing_groups | default([]) | map(attribute='name') ) }}" loop_control: loop_var: add_group diff --git a/roles/pulp_user/tasks/user_groups/remove_user_from_groups.yml b/roles/pulp_user/tasks/user_groups/remove_user_from_groups.yml index 0e1ac08..e5bb8d0 100644 --- a/roles/pulp_user/tasks/user_groups/remove_user_from_groups.yml +++ b/roles/pulp_user/tasks/user_groups/remove_user_from_groups.yml @@ -1,51 +1,11 @@ --- # These user/group combinations definitely DO exist on pulp server -- name: Get group href from Pulp API - uri: - url: "{{ pulp_add_group_user_url }}?name={{ remove_group }}" - user: "{{ pulp_username }}" - password: "{{ pulp_password }}" - method: GET - status_code: 200 - force_basic_auth: true - register: group_href_result - -# We should only return a single group here because we've just queried -# from pulp API -- name: Fail when group cannot be unambiguosly returned from Pulp API - fail: - msg: > - "Pulp API query: GET '{{ group_href_result.url }}' did not return - exactly one group. Groupname '{{ remove_group }}' was found - '{{ group_href_result.json.count }}' times. - Groupnames should be unique and exist before associating users - with them" - when: group_href_result.json.count != 1 - -- name: Get user id from Pulp API - uri: - url: "{{ pulp_user_url }}?username={{ user.username }}" - user: "{{ pulp_username }}" - password: "{{ pulp_password }}" - method: GET - status_code: 200 - force_basic_auth: true - register: user_list_result - -- name: Fail when user id cannot be unambiguosly returned from Pulp API - fail: - msg: > - "Pulp API query: GET '{{ user_list_result.url }}' did not return - exactly one user id. User '{{ user.username }}' was found - '{{ user_list_result.json.count }}' times." - when: user_list_result.json.count != 1 - # Will fail before we get here if the group/user doesn't exist - name: Remove user from group # DELETE {{ pulp_url }}/pulp/api/v3/groups/880/users/11/ uri: - url: "{{ pulp_url }}{{ group_href_result.json.results[0].pulp_href }}users/{{ user_list_result.json.results[0].id }}/" + url: "{{ pulp_url }}{{ user_group.pulp_href }}users/{{ user.id }}/" user: "{{ pulp_username }}" password: "{{ pulp_password }}" method: DELETE @@ -54,3 +14,7 @@ force_basic_auth: true # If we get here, we're always changing something changed_when: true + loop: "{{ user.existing_groups | selectattr('name', 'equalto', remove_group) }}" + loop_control: + loop_var: user_group + label: "{{ user.username }} {{ user_group.name }}"