From d2edf1d43531f938ccbdef79c927141ba193b96d Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Thu, 18 Jul 2019 10:19:11 -0400 Subject: [PATCH] User - Create parent directories if they do not exist in the specified home path (#51043) * Create a user home directory if it has parents that do not exist The useradd command line tool does not create parent directories. Check if the specified home path has parents that do not exist. If so, create them prior to running useradd, then set the proper permission on the created directory. Add tests Signed-off-by: Sam Doran * Use dict for default user group in tests Signed-off-by: Sam Doran * Fix tests Signed-off-by: Sam Doran --- .../user-home-dir-with-no-parents.yaml | 2 + lib/ansible/modules/system/user.py | 23 ++++++++++ test/integration/targets/user/tasks/main.yml | 43 +++++++++++++++++++ test/integration/targets/user/vars/main.yml | 4 ++ 4 files changed, 72 insertions(+) create mode 100644 changelogs/fragments/user-home-dir-with-no-parents.yaml diff --git a/changelogs/fragments/user-home-dir-with-no-parents.yaml b/changelogs/fragments/user-home-dir-with-no-parents.yaml new file mode 100644 index 00000000000..744b49b6d46 --- /dev/null +++ b/changelogs/fragments/user-home-dir-with-no-parents.yaml @@ -0,0 +1,2 @@ +bugfixes: + - user - create parent directories when the specified home path has parent directiries that do not exist (https://github.com/ansible/ansible/issues/41393) diff --git a/lib/ansible/modules/system/user.py b/lib/ansible/modules/system/user.py index 0e8e6f9285e..b34e8996165 100644 --- a/lib/ansible/modules/system/user.py +++ b/lib/ansible/modules/system/user.py @@ -628,6 +628,12 @@ class User(object): cmd.append(self.comment) if self.home is not None: + # If the specified path to the user home contains parent directories that + # do not exist, first create the home directory since useradd cannot + # create parent directories + parent = os.path.dirname(self.home) + if not os.path.isdir(parent): + self.create_homedir(self.home) cmd.append('-d') cmd.append(self.home) @@ -2883,7 +2889,24 @@ def main(): if not user.user_exists(): if module.check_mode: module.exit_json(changed=True) + + # Check to see if the provided home path contains parent directories + # that do not exist. + path_needs_parents = False + if user.home: + parent = os.path.basename(user.home) + if not os.path.isdir(parent): + path_needs_parents = True + (rc, out, err) = user.create_user() + + # If the home path had parent directories that needed to be created, + # make sure file permissions are correct in the created home directory. + if path_needs_parents: + info = user.user_info() + if info is not False: + user.chown_homedir(info[2], info[3], user.home) + if module.check_mode: result['system'] = user.name else: diff --git a/test/integration/targets/user/tasks/main.yml b/test/integration/targets/user/tasks/main.yml index 4f64b8fe7e2..9d32ac446fb 100644 --- a/test/integration/targets/user/tasks/main.yml +++ b/test/integration/targets/user/tasks/main.yml @@ -154,6 +154,49 @@ when: ansible_facts.system != 'Darwin' +# https://github.com/ansible/ansible/issues/41393 +# Create a new user account with a path that has parent directories that do not exist +- name: Create user with home path that has parents that do not exist + user: + name: ansibulluser2 + state: present + home: "{{ user_home_prefix[ansible_facts.system] }}/in2deep/ansibulluser2" + register: create_home_with_no_parent_1 + +- name: Create user with home path that has parents that do not exist again + user: + name: ansibulluser2 + state: present + home: "{{ user_home_prefix[ansible_facts.system] }}/in2deep/ansibulluser2" + register: create_home_with_no_parent_2 + +- name: Check the created home directory + stat: + path: "{{ user_home_prefix[ansible_facts.system] }}/in2deep/ansibulluser2" + register: home_with_no_parent_3 + +- name: Ensure user with non-existing parent paths was created successfully + assert: + that: + - create_home_with_no_parent_1 is changed + - create_home_with_no_parent_1.home == user_home_prefix[ansible_facts.system] ~ '/in2deep/ansibulluser2' + - create_home_with_no_parent_2 is not changed + - home_with_no_parent_3.stat.uid == create_home_with_no_parent_1.uid + - home_with_no_parent_3.stat.gr_name == default_user_group[ansible_facts.distribution] | default('ansibulluser2') + +- name: Cleanup test account + user: + name: ansibulluser2 + home: "{{ user_home_prefix[ansible_facts.system] }}/in2deep/ansibulluser2" + state: absent + remove: yes + +- name: Remove testing dir + file: + path: "{{ user_home_prefix[ansible_facts.system] }}/in2deep/" + state: absent + + ## user check - name: run existing user check tests diff --git a/test/integration/targets/user/vars/main.yml b/test/integration/targets/user/vars/main.yml index 603fcc59a0d..4b328f7184b 100644 --- a/test/integration/targets/user/vars/main.yml +++ b/test/integration/targets/user/vars/main.yml @@ -7,3 +7,7 @@ user_home_prefix: status_command: OpenBSD: "grep ansibulluser /etc/master.passwd | cut -d ':' -f 2" FreeBSD: 'pw user show ansibulluser' + +default_user_group: + openSUSE Leap: users + MacOSX: admin