Add group module to manage groups and group membership

This relies on groupadd, groupmod, groupdel, and gpasswd utilities on
the system.  You can optionally modify the gid for the group.  You can
also add/remove a user to/from a group with the option member.  Member
state is defined with the option memberstate.
This commit is contained in:
Stephen Fromm 2012-03-27 11:10:59 -07:00 committed by Michael DeHaan
parent 8592b3b40d
commit db677954ac

225
library/group Executable file
View file

@ -0,0 +1,225 @@
#!/usr/bin/env python
# (c) 2012, Stephen Fromm <sfromm@gmail.com>
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
try:
import json
except ImportError:
import simplejson as json
import os
import grp
import shlex
import subprocess
import sys
GROUPADD = "/usr/sbin/groupadd"
GROUPDEL = "/usr/sbin/groupdel"
GROUPMOD = "/usr/sbin/groupmod"
GPASSWD = "/usr/bin/gpasswd"
def debug(msg):
# ansible ignores stderr, so it's safe to use for debug
print >>sys.stderr, msg
#pass
def exit_json(rc=0, **kwargs):
if 'name' in kwargs:
debug("add group info to exit_json")
add_group_info(kwargs)
print json.dumps(kwargs)
sys.exit(rc)
def fail_json(**kwargs):
kwargs['failed'] = True
exit_json(rc=1, **kwargs)
def add_group_info(kwargs):
name = kwargs['name']
if group_exists(name):
kwargs['state'] = 'present'
info = group_info(name)
kwargs['gid'] = info[2]
kwargs['members'] = info[3]
else:
kwargs['state'] = 'absent'
return kwargs
def group_del(group):
cmd = [GROUPDEL, group]
debug("Arguments to groupdel: %s" % (" ".join(cmd)))
rc = subprocess.call(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if rc == 0:
return True
else:
return False
def group_add(group, **kwargs):
cmd = [GROUPADD]
for key in kwargs:
if key == 'gid' and kwargs[key] is not None:
cmd.append('-g')
cmd.append(kwargs[key])
cmd.append(group)
debug("Arguments to groupadd: %s" % (" ".join(cmd)))
rc = subprocess.call(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if rc == 0:
return True
else:
return False
def group_mod(group, **kwargs):
cmd = [GROUPMOD]
info = group_info(group)
for key in kwargs:
if key == 'gid':
if kwargs[key] is not None and info[2] != int(kwargs[key]):
cmd.append('-g')
cmd.append(kwargs[key])
if len(cmd) == 1:
return False
cmd.append(group)
debug("Arguments to groupmod: %s" % (" ".join(cmd)))
rc = subprocess.call(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if rc == 0:
return True
else:
return False
def group_has_member(group, member):
if not group_exists(group):
return False
info = group_info(group)
if member in info[3]:
return True
else:
return False
def group_add_member(group, member):
cmd = [GPASSWD, '-a', member, group]
debug("Arguments to gpasswd: %s" % (" ".join(cmd)))
rc = subprocess.call(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if rc == 0:
return True
else:
return False
def group_del_member(group, member):
cmd = [GPASSWD, '-d', member, group]
debug("Arguments to gpasswd: %s" % (" ".join(cmd)))
rc = subprocess.call(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if rc == 0:
return True
else:
return False
def group_exists(group):
try:
if grp.getgrnam(group):
return True
except KeyError:
return False
def group_info(group):
if not group_exists(group):
return False
try:
info = list(grp.getgrnam(group))
except KeyError:
return False
return info
# ===========================================
if not os.path.exists(GROUPADD):
if os.path.exists("/sbin/groupadd"):
GROUPADD = "/sbin/groupadd"
else:
fail_json(msg="Cannot find groupadd")
if not os.path.exists(GROUPDEL):
if os.path.exists("/sbin/groupdel"):
GROUPDEL = "/sbin/groupdel"
else:
fail_json(msg="Cannot find groupdel")
if not os.path.exists(GROUPMOD):
if os.path.exists("/sbin/groupmod"):
GROUPDEL = "/sbin/groupmod"
else:
fail_json(msg="Cannot find groupmod")
if not os.path.exists(GPASSWD):
if os.path.exists("/bin/gpasswd"):
GROUPDEL = "/bin/gpasswd"
else:
fail_json(msg="Cannot find gpasswd")
if len(sys.argv) == 2 and os.path.exists(sys.argv[1]):
argfile = sys.argv[1]
args = open(argfile, 'r').read()
else:
args = ' '.join(sys.argv[1:])
items = shlex.split(args)
if not len(items):
fail_json(msg='the module requires arguments -a')
sys.exit(1)
params = {}
for x in items:
(k, v) = x.split("=")
params[k] = v
state = params.get('state','present')
name = params.get('name', None)
gid = params.get('gid', None)
# ===========================================
# the following controls group membership
member = params.get('member', None)
memberstate = params.get('memberstate', 'present')
if state not in [ 'present', 'absent' ]:
fail_json(msg='invalid state')
if memberstate not in [ 'present', 'absent' ]:
fail_json(msg='invalid memberstate')
if name is None:
fail_json(msg='name is required')
changed = False
rc = 0
if state == 'absent':
if group_exists(name):
changed = group_del(name)
exit_json(name=name, changed=changed)
elif state == 'present':
if not group_exists(name):
changed = group_add(name, gid=gid)
else:
changed = group_mod(name, gid=gid)
if member is not None:
if memberstate == 'present':
if not group_has_member(name, member):
changed = group_add_member(name, member)
elif memberstate == 'absent':
if group_has_member(name, member):
changed = group_del_member(name, member)
else:
fail_json(name=name, msg='Unexpected position reached')
exit_json(name=name, changed=changed)
fail_json(name=name, msg='Unexpected position reached')