From 00e7c020b210073f1a9e5ccfcf056b15a4ee965a Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Wed, 15 Aug 2018 16:22:26 -0400 Subject: [PATCH] Add backup feature to user module (#41854) * Add backup option * Only backup shadow file when the OS has one * Only backup shadow file for SunOS * Update docs on backup feature * Add changelog fragment * Add tests for shadow backup * Remove backup option, make it automatic Remove the option to enable/disable backups and make it automatic. Add note to docs describing this behavior. Change tests to account for new module behavior. Change section name in changelog fragment since minor_features is not a valid section. --- .../fragments/user-module-backup-shadow.yaml | 2 ++ lib/ansible/modules/system/user.py | 8 +++++++ test/integration/targets/user/tasks/main.yml | 23 +++++++++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 changelogs/fragments/user-module-backup-shadow.yaml diff --git a/changelogs/fragments/user-module-backup-shadow.yaml b/changelogs/fragments/user-module-backup-shadow.yaml new file mode 100644 index 00000000000..c8e556493d5 --- /dev/null +++ b/changelogs/fragments/user-module-backup-shadow.yaml @@ -0,0 +1,2 @@ +minor_changes: + - user - backup shadow file on platforms where the module modifies it directly (https://github.com/ansible/ansible/issues/40696) diff --git a/lib/ansible/modules/system/user.py b/lib/ansible/modules/system/user.py index c0677a2ae19..0d5680c4b26 100644 --- a/lib/ansible/modules/system/user.py +++ b/lib/ansible/modules/system/user.py @@ -22,6 +22,8 @@ notes: they generally come pre-installed with the system and Ansible will require they are present at runtime. If they are not, a descriptive error message will be shown. - For Windows targets, use the M(win_user) module instead. + - On SunOS platforms, the shadow file is backed up automatically since this module edits it directly. + On other platforms, the shadow file is backed up by the underlying tools used by this module. description: - Manage user accounts and user attributes. - For Windows targets, use the M(win_user) module instead. @@ -474,6 +476,10 @@ class User(object): cmd = [str(x) for x in cmd] return self.module.run_command(cmd, use_unsafe_shell=use_unsafe_shell, data=data) + def backup_shadow(self): + if not self.module.check_mode and self.SHADOWFILE: + return self.module.backup_local(self.SHADOWFILE) + def remove_user_userdel(self): if self.local: command_name = 'luserdel' @@ -1598,6 +1604,7 @@ class SunOS(User): if not self.module.check_mode: # we have to set the password by editing the /etc/shadow file if self.password is not None: + self.backup_shadow() minweeks, maxweeks, warnweeks = self.get_password_defaults() try: lines = [] @@ -1702,6 +1709,7 @@ class SunOS(User): # we have to set the password by editing the /etc/shadow file if self.update_password == 'always' and self.password is not None and info[1] != self.password: + self.backup_shadow() (rc, out, err) = (0, '', '') if not self.module.check_mode: minweeks, maxweeks, warnweeks = self.get_password_defaults() diff --git a/test/integration/targets/user/tasks/main.yml b/test/integration/targets/user/tasks/main.yml index 690c00b107d..edb9ddfe72b 100644 --- a/test/integration/targets/user/tasks/main.yml +++ b/test/integration/targets/user/tasks/main.yml @@ -386,3 +386,26 @@ that: - bsd_account_expiration.stdout == '0' when: ansible_os_family == 'FreeBSD' + + +## shadow backup +- block: + - name: Create a user to test shadow file backup + user: + name: ansibulluser + state: present + register: result + + - name: Find shadow backup files + find: + path: /etc + patterns: 'shadow\..*~$' + use_regex: yes + register: shadow_backups + + - name: Assert that a backup file was created + assert: + that: + - result.bakup + - shadow_backups.files | map(attribute='path') | list | length > 0 + when: ansible_os_family == 'Solaris'