From 4e49df7b88c260dbffa6559f79cf6c4f84bbefa9 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Tue, 9 Feb 2016 10:29:41 -0500 Subject: [PATCH] revamped checkmode support in user module - defaulted to commands not executing in checkmode - added force run for info gathering (for setting changed) - added debug for what would have been run in check mode - added check mode for spots that made changes using system calls instead of command - removed now redundant checkmode checks better failure now, if i missed anything, it will misreport changed value instead of old default of actually making the change in checkmode --- system/user.py | 136 +++++++++++++++++-------------------------------- 1 file changed, 47 insertions(+), 89 deletions(-) diff --git a/system/user.py b/system/user.py index b8f66f2e09f..1c97482b9e5 100755 --- a/system/user.py +++ b/system/user.py @@ -296,8 +296,12 @@ class User(object): self.ssh_file = os.path.join('.ssh', 'id_%s' % self.ssh_type) - def execute_command(self, cmd, use_unsafe_shell=False, data=None): - return self.module.run_command(cmd, use_unsafe_shell=use_unsafe_shell, data=data) + def execute_command(self, cmd, use_unsafe_shell=False, data=None, obey_checkmode=True): + if self.module.check_mode and obey_checkmode: + self.module.debug('In check mode, would have run: "%s"' % cmd) + return (0, '','') + else: + return self.module.run_command(cmd, use_unsafe_shell=use_unsafe_shell, data=data) def remove_user_userdel(self): cmd = [self.module.get_bin_path('userdel', True)] @@ -392,9 +396,8 @@ class User(object): if not os.access(usermod_path, os.X_OK): return False - cmd = [usermod_path] - cmd.append('--help') - rc, data1, data2 = self.execute_command(cmd) + cmd = [usermod_path, '--help'] + (rc, data1, data2) = self.execute_command(cmd, obey_checkmode=False) helpout = data1 + data2 # check if --append exists @@ -484,8 +487,6 @@ class User(object): # skip if no changes to be made if len(cmd) == 1: return (None, '', '') - elif self.module.check_mode: - return (0, '', '') cmd.append(self.name) return self.execute_command(cmd) @@ -592,8 +593,6 @@ class User(object): return (1, '', 'Failed to create %s: %s' % (ssh_dir, str(e))) if os.path.exists(ssh_key_file): return (None, 'Key already exists', '') - if self.module.check_mode: - return (0, '', '') cmd = [self.module.get_bin_path('ssh-keygen', True)] cmd.append('-t') cmd.append(self.ssh_type) @@ -626,7 +625,7 @@ class User(object): cmd.append('-f') cmd.append(ssh_key_file) - return self.execute_command(cmd) + return self.execute_command(cmd, obey_checkmode=False) def get_ssh_public_key(self): ssh_public_key_file = '%s.pub' % self.get_ssh_key_path() @@ -864,8 +863,6 @@ class FreeBsdUser(User): # modify the user if cmd will do anything if cmd_len != len(cmd): - if self.module.check_mode: - return (0, '', '') (rc, out, err) = self.execute_command(cmd) if rc is not None and rc != 0: self.module.fail_json(name=self.name, msg=err, rc=rc) @@ -874,8 +871,6 @@ class FreeBsdUser(User): # we have to set the password in a second command if self.update_password == 'always' and self.password is not None and info[1] != self.password: - if self.module.check_mode: - return (0, '', '') cmd = [ self.module.get_bin_path('chpass', True), '-p', @@ -1027,7 +1022,7 @@ class OpenBSDUser(User): # find current login class user_login_class = None userinfo_cmd = [self.module.get_bin_path('userinfo', True), self.name] - (rc, out, err) = self.execute_command(userinfo_cmd) + (rc, out, err) = self.execute_command(userinfo_cmd, obey_checkmode=False) for line in out.splitlines(): tokens = line.split() @@ -1048,8 +1043,6 @@ class OpenBSDUser(User): # skip if no changes to be made if len(cmd) == 1: return (None, '', '') - elif self.module.check_mode: - return (0, '', '') cmd.append(self.name) return self.execute_command(cmd) @@ -1207,8 +1200,6 @@ class NetBSDUser(User): # skip if no changes to be made if len(cmd) == 1: return (None, '', '') - elif self.module.check_mode: - return (0, '', '') cmd.append(self.name) return self.execute_command(cmd) @@ -1283,14 +1274,12 @@ class SunOS(User): cmd.append(self.name) - if self.module.check_mode: - return (0, '', '') - else: - (rc, out, err) = self.execute_command(cmd) - if rc is not None and rc != 0: - self.module.fail_json(name=self.name, msg=err, rc=rc) + (rc, out, err) = self.execute_command(cmd) + if rc is not None and rc != 0: + self.module.fail_json(name=self.name, msg=err, rc=rc) - # we have to set the password by editing the /etc/shadow file + if not self.module.check_mode: + # we have to set the password by editing the /etc/shadow file if self.password is not None: try: lines = [] @@ -1307,7 +1296,7 @@ class SunOS(User): except Exception, err: self.module.fail_json(msg="failed to update users password: %s" % str(err)) - return (rc, out, err) + return (rc, out, err) def modify_user_usermod(self): cmd = [self.module.get_bin_path('usermod', True)] @@ -1367,16 +1356,14 @@ class SunOS(User): # modify the user if cmd will do anything if cmd_len != len(cmd): - (rc, out, err) = (0, '', '') - if not self.module.check_mode: - cmd.append(self.name) - (rc, out, err) = self.execute_command(cmd) - if rc is not None and rc != 0: - self.module.fail_json(name=self.name, msg=err, rc=rc) + cmd.append(self.name) + (rc, out, err) = self.execute_command(cmd) + if rc is not None and rc != 0: + self.module.fail_json(name=self.name, msg=err, rc=rc) else: (rc, out, err) = (None, '', '') - # 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: (rc, out, err) = (0, '', '') if not self.module.check_mode: @@ -1388,7 +1375,7 @@ class SunOS(User): lines.append(line) continue fields[1] = self.password - fields[2] = str(int(time.time() / 86400)) + fields[2] = str(int(time.time() / 86400)) line = ':'.join(fields) lines.append('%s\n' % line) open(self.SHADOWFILE, 'w+').writelines(lines) @@ -1436,7 +1423,7 @@ class DarwinUser(User): def _list_user_groups(self): cmd = self._get_dscl() cmd += [ '-search', '/Groups', 'GroupMembership', self.name ] - (rc, out, err) = self.execute_command(cmd) + (rc, out, err) = self.execute_command(cmd, obey_checkmode=False) groups = [] for line in out.splitlines(): if line.startswith(' ') or line.startswith(')'): @@ -1448,7 +1435,7 @@ class DarwinUser(User): '''Return user PROPERTY as given my dscl(1) read or None if not found.''' cmd = self._get_dscl() cmd += [ '-read', '/Users/%s' % self.name, property ] - (rc, out, err) = self.execute_command(cmd) + (rc, out, err) = self.execute_command(cmd, obey_checkmode=False) if rc != 0: return None # from dscl(1) @@ -1471,7 +1458,7 @@ class DarwinUser(User): '''Return the next available uid''' cmd = self._get_dscl() cmd += ['-list', '/Users', 'UniqueID'] - (rc, out, err) = self.execute_command(cmd) + (rc, out, err) = self.execute_command(cmd, obey_checkmode=False) if rc != 0: self.module.fail_json( msg="Unable to get the next available uid", @@ -1504,8 +1491,7 @@ class DarwinUser(User): cmd += [ '-create', '/Users/%s' % self.name, 'Password', '*'] (rc, out, err) = self.execute_command(cmd) if rc != 0: - self.module.fail_json(msg='Error when changing password', - err=err, out=out, rc=rc) + self.module.fail_json(msg='Error when changing password', err=err, out=out, rc=rc) return (rc, out, err) def _make_group_numerical(self): @@ -1526,13 +1512,11 @@ class DarwinUser(User): option = '-a' else: option = '-d' - cmd = [ 'dseditgroup', '-o', 'edit', option, self.name, - '-t', 'user', group ] + cmd = [ 'dseditgroup', '-o', 'edit', option, self.name, '-t', 'user', group ] (rc, out, err) = self.execute_command(cmd) if rc != 0: self.module.fail_json(msg='Cannot %s user "%s" to group "%s".' - % (action, self.name, group), - err=err, out=out, rc=rc) + % (action, self.name, group), err=err, out=out, rc=rc) return (rc, out, err) def _modify_group(self): @@ -1551,8 +1535,6 @@ class DarwinUser(User): target = set([]) for remove in current - target: - if self.module.check_mode: - return (0, '', '', True) (_rc, _err, _out) = self.__modify_group(remove, 'delete') rc += rc out += _out @@ -1560,8 +1542,6 @@ class DarwinUser(User): changed = True for add in target - current: - if self.module.check_mode: - return (0, '', '', True) (_rc, _err, _out) = self.__modify_group(add, 'add') rc += _rc out += _out @@ -1579,7 +1559,7 @@ class DarwinUser(User): # http://support.apple.com/kb/HT5017?viewlocale=en_US cmd = [ 'defaults', 'read', plist_file, 'HiddenUsersList' ] - (rc, out, err) = self.execute_command(cmd) + (rc, out, err) = self.execute_command(cmd, obey_checkmode=False) # returned value is # ( # "_userA", @@ -1598,34 +1578,25 @@ class DarwinUser(User): if not self.name in hidden_users: cmd = [ 'defaults', 'write', plist_file, 'HiddenUsersList', '-array-add', self.name ] - if self.module.check_mode: - return 0 (rc, out, err) = self.execute_command(cmd) if rc != 0: - self.module.fail_json( - msg='Cannot user "%s" to hidden user list.' - % self.name, err=err, out=out, rc=rc) + self.module.fail_json( msg='Cannot user "%s" to hidden user list.' % self.name, err=err, out=out, rc=rc) return 0 else: if self.name in hidden_users: del(hidden_users[hidden_users.index(self.name)]) - cmd = [ 'defaults', 'write', plist_file, - 'HiddenUsersList', '-array' ] + hidden_users - if self.module.check_mode: - return 0 + cmd = [ 'defaults', 'write', plist_file, 'HiddenUsersList', '-array' ] + hidden_users (rc, out, err) = self.execute_command(cmd) if rc != 0: - self.module.fail_json( - msg='Cannot remove user "%s" from hidden user list.' - % self.name, err=err, out=out, rc=rc) + self.module.fail_json( msg='Cannot remove user "%s" from hidden user list.' % self.name, err=err, out=out, rc=rc) return 0 def user_exists(self): '''Check is SELF.NAME is a known user on the system.''' cmd = self._get_dscl() cmd += [ '-list', '/Users/%s' % self.name] - (rc, out, err) = self.execute_command(cmd) + (rc, out, err) = self.execute_command(cmd, obey_checkmode=False) return rc == 0 def remove_user(self): @@ -1637,9 +1608,7 @@ class DarwinUser(User): (rc, out, err) = self.execute_command(cmd) if rc != 0: - self.module.fail_json( - msg='Cannot delete user "%s".' - % self.name, err=err, out=out, rc=rc) + self.module.fail_json( msg='Cannot delete user "%s".' % self.name, err=err, out=out, rc=rc) if self.force: if os.path.exists(info[5]): @@ -1653,9 +1622,7 @@ class DarwinUser(User): cmd += [ '-create', '/Users/%s' % self.name] (rc, err, out) = self.execute_command(cmd) if rc != 0: - self.module.fail_json( - msg='Cannot create user "%s".' - % self.name, err=err, out=out, rc=rc) + self.module.fail_json( msg='Cannot create user "%s".' % self.name, err=err, out=out, rc=rc) self._make_group_numerical() @@ -1666,20 +1633,19 @@ class DarwinUser(User): if self.createhome: if self.home is None: self.home = '/Users/%s' % self.name - if not os.path.exists(self.home): - os.makedirs(self.home) - self.chown_homedir(int(self.uid), int(self.group), self.home) + if not self.module.check_mode: + if not os.path.exists(self.home): + os.makedirs(self.home) + self.chown_homedir(int(self.uid), int(self.group), self.home) for field in self.fields: if self.__dict__.has_key(field[0]) and self.__dict__[field[0]]: cmd = self._get_dscl() - cmd += [ '-create', '/Users/%s' % self.name, - field[1], self.__dict__[field[0]]] + cmd += [ '-create', '/Users/%s' % self.name, field[1], self.__dict__[field[0]]] (rc, _err, _out) = self.execute_command(cmd) if rc != 0: - self.module.fail_json( - msg='Cannot add property "%s" to user "%s".' + self.module.fail_json( msg='Cannot add property "%s" to user "%s".' % (field[0], self.name), err=err, out=out, rc=rc) out += _out @@ -1714,10 +1680,7 @@ class DarwinUser(User): current = self._get_user_property(field[1]) if current is None or current != self.__dict__[field[0]]: cmd = self._get_dscl() - cmd += [ '-create', '/Users/%s' % self.name, - field[1], self.__dict__[field[0]]] - if self.module.check_mode: - return (0, '', '') + cmd += [ '-create', '/Users/%s' % self.name, field[1], self.__dict__[field[0]]] (rc, _err, _out) = self.execute_command(cmd) if rc != 0: self.module.fail_json( @@ -1727,8 +1690,6 @@ class DarwinUser(User): out += _out err += _err if self.update_password == 'always' and self.password is not None: - if self.module.check_mode: - return (0, '', '') (rc, _err, _out) = self._change_user_password() out += _out err += _err @@ -1880,16 +1841,12 @@ class AIX(User): # skip if no changes to be made if len(cmd) == 1: (rc, out, err) = (None, '', '') - elif self.module.check_mode: - return (0, '', '') else: cmd.append(self.name) (rc, out, err) = self.execute_command(cmd) # set password with chpasswd if self.update_password == 'always' and self.password is not None and info[1] != self.password: - if self.module.check_mode: - return (0, '', '') cmd = [] cmd.append(self.module.get_bin_path('chpasswd', True)) cmd.append('-e') @@ -2049,8 +2006,6 @@ class HPUX(User): # skip if no changes to be made if len(cmd) == 1: return (None, '', '') - elif self.module.check_mode: - return (0, '', '') cmd.append(self.name) return self.execute_command(cmd) @@ -2128,8 +2083,11 @@ def main(): if module.check_mode: module.exit_json(changed=True) (rc, out, err) = user.create_user() - result['system'] = user.system - result['createhome'] = user.createhome + if module.check_mode: + result['system'] = user.name + else: + result['system'] = user.system + result['createhome'] = user.createhome else: # modify user (note: this function is check mode aware) (rc, out, err) = user.modify_user()