diff --git a/changelogs/fragments/59772-fix_ansible_issue_58619.yaml b/changelogs/fragments/59772-fix_ansible_issue_58619.yaml new file mode 100644 index 00000000000..dbfce7a87f4 --- /dev/null +++ b/changelogs/fragments/59772-fix_ansible_issue_58619.yaml @@ -0,0 +1,5 @@ +bugfixes: + - > + group - The group module was not correctly detecting whether a local + group is existing or not with local set to yes if the same group + exists in a non local group repository e.g. LDAP. (https://github.com/ansible/ansible/issues/58619) diff --git a/lib/ansible/modules/system/group.py b/lib/ansible/modules/system/group.py index ac50bc899d3..159fee15460 100644 --- a/lib/ansible/modules/system/group.py +++ b/lib/ansible/modules/system/group.py @@ -98,6 +98,7 @@ system: ''' import grp +import os from ansible.module_utils._text import to_bytes from ansible.module_utils.basic import AnsibleModule @@ -192,11 +193,36 @@ class Group(object): return self.execute_command(cmd) def group_exists(self): - try: - if grp.getgrnam(self.name): - return True - except KeyError: - return False + # The grp module does not distinguish between local and directory accounts. + # It's output cannot be used to determine whether or not a group exists locally. + # It returns True if the group exists locally or in the directory, so instead + # look in the local GROUP file for an existing account. + if self.local: + if not os.path.exists(self.GROUPFILE): + self.module.fail_json(msg="'local: true' specified but unable to find local group file {0} to parse.".format(self.GROUPFILE)) + + exists = False + name_test = '{0}:'.format(self.name) + with open(self.GROUPFILE, 'rb') as f: + reversed_lines = f.readlines()[::-1] + for line in reversed_lines: + if line.startswith(to_bytes(name_test)): + exists = True + break + + if not exists: + self.module.warn( + "'local: true' specified and group was not found in {file}. " + "The local group may already exist if the local group database exists somewhere other than {file}.".format(file=self.GROUPFILE)) + + return exists + + else: + try: + if grp.getgrnam(self.name): + return True + except KeyError: + return False def group_info(self): if not self.group_exists(): diff --git a/test/integration/targets/group/tasks/tests.yml b/test/integration/targets/group/tasks/tests.yml index b29e2e191d9..d07ad36a3d6 100644 --- a/test/integration/targets/group/tasks/tests.yml +++ b/test/integration/targets/group/tasks/tests.yml @@ -267,3 +267,50 @@ state: absent # only applicable to Linux, limit further to CentOS where 'luseradd' is installed when: ansible_distribution == 'CentOS' + +# https://github.com/ansible/ansible/pull/59772 +- block: + - name: create group with a gid + group: + name: group1_test + gid: 1337 + local: no + state: present + register: create_group_gid + + - name: get gid of created group + command: "{{ ansible_python_interpreter | quote }} -c \"import grp; print(grp.getgrnam('group1_test').gr_gid)\"" + register: create_group_gid_actual + + - name: assert create group with a gid + assert: + that: + - create_group_gid is changed + - create_group_gid.gid | int == 1337 | int + - create_group_gid_actual.stdout | trim | int == 1337 | int + + - name: create local group with the same gid + group: + name: group1_test + gid: 1337 + local: yes + state: present + register: create_local_group_gid + + - name: assert create local group with a gid + assert: + that: + - create_local_group_gid.gid | int == 1337 | int + always: + - name: Cleanup create group with a gid + group: + name: group1_test + local: no + state: absent + - name: Cleanup create local group with the same gid + group: + name: group1_test + local: yes + state: absent + # only applicable to Linux, limit further to CentOS where 'lgroupadd' is installed + when: ansible_distribution == 'CentOS'