From 3208a290ab7555fd35f3452fce34b81cc2011a2e Mon Sep 17 00:00:00 2001 From: Frank Brehm Date: Wed, 30 Mar 2016 22:47:34 +0200 Subject: [PATCH] Adding some own modules and states and using them --- _modules/str_manip.py | 14 +++++ _modules/user_info.py | 120 +++++++++++++++++++++++++++++++++++++++++ _states/user_info.py | 123 ++++++++++++++++++++++++++++++++++++++++++ basic/root.sls | 5 ++ top.sls | 3 ++ 5 files changed, 265 insertions(+) create mode 100644 _modules/str_manip.py create mode 100644 _modules/user_info.py create mode 100644 _states/user_info.py create mode 100644 basic/root.sls diff --git a/_modules/str_manip.py b/_modules/str_manip.py new file mode 100644 index 0000000..68dc0fc --- /dev/null +++ b/_modules/str_manip.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +''' +Performing some string manipulations. +''' + +import re + +def camelCase(st): + output = ''.join(x for x in st.title() if x.isalnum()) + return output[0].lower() + output[1:] + +def CamelCase(st): + return ''.join(x for x in st.title() if x.isalnum()) + diff --git a/_modules/user_info.py b/_modules/user_info.py new file mode 100644 index 0000000..b582245 --- /dev/null +++ b/_modules/user_info.py @@ -0,0 +1,120 @@ +# -*- coding: utf-8 -*- +''' +Manage user gecos with the usermod command +''' + +# Import python libs +#import re + +try: + import pwd +except ImportError: + pass +import logging +#import copy + +# Import salt libs +import salt.utils +#from salt._compat import string_types + +log = logging.getLogger(__name__) + + +# ----------------------------------------------------------------------------- +def _get_gecos(name): + ''' + Retrieve GECOS field info + ''' + gecos_field = pwd.getpwnam(name).pw_gecos + if not gecos_field: + return '' + return gecos_field.strip() + + +# ----------------------------------------------------------------------------- +def chgecos(name, gecos): + ''' + Change the gecos information of the user + + CLI Example: + + .. code-block:: bash + + salt '*' user_info.chgecos root "root ServerXYZ" + ''' + + used_gecos = '' + if gecos is not None: + used_gecos = str(gecos).strip() + + pre_gecos = _get_gecos(name) + if used_gecos == pre_gecos: + log.debug("User {0!r} has already gecos {1!r}.".format(name, used_gecos)) + return True + + log.info("Setting gecos of user {0!r} to {1!r} ...".format(name, used_gecos)) + + cmd = 'usermod -c "{0}" {1}'.format(used_gecos, name) + __salt__['cmd.run'](cmd) + + post_gecos = _get_gecos(name) + if pre_gecos != post_gecos: + return post_gecos == used_gecos + return False + + +# ----------------------------------------------------------------------------- +def info(name): + ''' + Return user information + + CLI Example: + + .. code-block:: bash + + salt '*' user.info root + ''' + + log.debug("Trying to get informations about user {0!r} ...".format(name)) + + try: + data = pwd.getpwnam(name) + except KeyError: + return {} + else: + return _format_info(data) + + +# ----------------------------------------------------------------------------- +def list_groups(name): + ''' + Return a list of groups the named user belongs to + + CLI Example: + + .. code-block:: bash + + salt '*' user.list_groups foo + ''' + return salt.utils.get_group_list(name) + + +# ----------------------------------------------------------------------------- +def _format_info(data): + ''' + Return user information in a pretty way + ''' + + return {'gid': data.pw_gid, + 'groups': list_groups(data.pw_name), + 'home': data.pw_dir, + 'name': data.pw_name, + 'passwd': data.pw_passwd, + 'shell': data.pw_shell, + 'uid': data.pw_uid, + 'gecos': data.pw_gecos} + + +# ----------------------------------------------------------------------------- + +# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/_states/user_info.py b/_states/user_info.py new file mode 100644 index 0000000..4967446 --- /dev/null +++ b/_states/user_info.py @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- +''' +Management of user name (gecos) +=============================== + +The user_info state is designated for managing the full username +in the passwd file (gecos). + + fred: + user_info.present: + - gecos: Fred Jones + +''' + +# Import python libs +import logging + +# Import salt libs +import salt.utils + +log = logging.getLogger(__name__) + + +# ----------------------------------------------------------------------------- +def _group_changes(cur, wanted, remove=True): + ''' + Determine if the groups need to be changed + ''' + old = set(cur) + new = set(wanted) + if (remove and old != new) or (not remove and not new.issubset(old)): + return True + return False + + +# ----------------------------------------------------------------------------- +def _changes(name, gecos=None): + ''' + Return a dict of the changes required for a user if the user is present, + otherwise return False. + ''' + + lusr = __salt__['user_info.info'](name) + if not lusr: + return False + + change = {} + if gecos is not None: + gecos = gecos.strip() + if lusr['gecos'] != gecos: + change['gecos'] = gecos + + return change + + +# ----------------------------------------------------------------------------- +def present(name, gecos=None): + ''' + Ensure, that the user information of the named user are correct. + + name + The name of the user to manage + + gecos + The gecos (the complete username) to assign. + ''' + + if gecos is not None: + gecos = str(gecos).strip() + + ret = {'name': name, + 'changes': {}, + 'result': True, + 'comment': 'User {0!r} is present and up to date'.format(name)} + + changes = _changes(name, gecos=gecos) + if not changes: + if changes is False: + msg = "User {0!r} to change the the user info does not exists.".format(name) + log.warning(msg) + else: + msg = "User {0!r} is up to date.".format(name) + ret['comment'] = msg + return ret + + log.debug("Got following changes for user {0!r}: {1!r}".format(name, changes)) + + # The user is present + if __opts__['test']: + ret['result'] = None + ret['comment'] = ('The following user attributes are set to be changed:\n') + for key, val in changes.items(): + ret['comment'] += '{0}: {1}\n'.format(key, val) + return ret + + pre = __salt__['user_info.info'](name) + + for key, val in changes.items(): + if key == 'gecos': + __salt__['user_info.chgecos'](name, val) + else: + __salt__['user.ch{0}'.format(key)](name, val) + + post = __salt__['user_info.info'](name) + spost = {} + # See if anything changed + for key in post: + if post[key] != pre[key]: + ret['changes'][key] = post[key] + if ret['changes']: + ret['comment'] = 'Updated user {0}'.format(name) + changes = _changes(name, gecos=gecos) + if changes: + ret['comment'] = 'These values could not be changed: {0}'.format( + changes + ) + ret['result'] = False + return ret + + +# ----------------------------------------------------------------------------- + +# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/basic/root.sls b/basic/root.sls new file mode 100644 index 0000000..d4df3f6 --- /dev/null +++ b/basic/root.sls @@ -0,0 +1,5 @@ +#------------------------------------- +root: + user_info.present: + - gecos: root {{ salt['str_manip.CamelCase'](salt['grains.get']('host')) }} + diff --git a/top.sls b/top.sls index 5add587..8e287de 100644 --- a/top.sls +++ b/top.sls @@ -12,6 +12,7 @@ base: - basic.rsyslog - basic.shells - basic.skel + - basic.root - postfix.common - fail2ban - bind @@ -27,4 +28,6 @@ base: - basic.chrony - basic.rsyslog - basic.shells + - basic.skel + - basic.root -- 2.39.5