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.
This commit is contained in:
Sam Doran 2018-08-15 16:22:26 -04:00 committed by ansibot
parent 0971a342d8
commit 00e7c020b2
3 changed files with 33 additions and 0 deletions

View file

@ -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)

View file

@ -22,6 +22,8 @@ notes:
they generally come pre-installed with the system and Ansible will require they 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. 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. - 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: description:
- Manage user accounts and user attributes. - Manage user accounts and user attributes.
- For Windows targets, use the M(win_user) module instead. - For Windows targets, use the M(win_user) module instead.
@ -474,6 +476,10 @@ class User(object):
cmd = [str(x) for x in cmd] cmd = [str(x) for x in cmd]
return self.module.run_command(cmd, use_unsafe_shell=use_unsafe_shell, data=data) 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): def remove_user_userdel(self):
if self.local: if self.local:
command_name = 'luserdel' command_name = 'luserdel'
@ -1598,6 +1604,7 @@ class SunOS(User):
if not self.module.check_mode: if not self.module.check_mode:
# we have to set the password by editing the /etc/shadow file # we have to set the password by editing the /etc/shadow file
if self.password is not None: if self.password is not None:
self.backup_shadow()
minweeks, maxweeks, warnweeks = self.get_password_defaults() minweeks, maxweeks, warnweeks = self.get_password_defaults()
try: try:
lines = [] lines = []
@ -1702,6 +1709,7 @@ class SunOS(User):
# we have to set the password by editing the /etc/shadow file # 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: if self.update_password == 'always' and self.password is not None and info[1] != self.password:
self.backup_shadow()
(rc, out, err) = (0, '', '') (rc, out, err) = (0, '', '')
if not self.module.check_mode: if not self.module.check_mode:
minweeks, maxweeks, warnweeks = self.get_password_defaults() minweeks, maxweeks, warnweeks = self.get_password_defaults()

View file

@ -386,3 +386,26 @@
that: that:
- bsd_account_expiration.stdout == '0' - bsd_account_expiration.stdout == '0'
when: ansible_os_family == 'FreeBSD' 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'