Mini Shell
"""
Management of user groups
=========================
The group module is used to create and manage group settings, groups can be
either present or absent. User/Group names can be passed to the ``adduser``,
``deluser``, and ``members`` parameters. ``adduser`` and ``deluser`` can be used
together but not with ``members``.
In Windows, if no domain is specified in the user or group name (i.e.
``DOMAIN\\username``) the module will assume a local user or group.
.. code-block:: yaml
cheese:
group.present:
- gid: 7648
- system: True
- addusers:
- user1
- users2
- delusers:
- foo
cheese:
group.present:
- gid: 7648
- system: True
- members:
- foo
- bar
- user1
- user2
"""
import sys
import salt.utils.platform
import salt.utils.win_functions
def _get_root_args(local):
"""
Retrieve args to use for group.info calls depending on platform and the local flag
"""
if not local or salt.utils.platform.is_windows():
return {}
return {"root": "/"}
def _changes(name, gid=None, addusers=None, delusers=None, members=None, local=False):
"""
Return a dict of the changes required for a group if the group is present,
otherwise return False.
"""
lgrp = __salt__["group.info"](name, **_get_root_args(local))
if not lgrp:
return False
# User and Domain names are not case sensitive in Windows. Let's make them
# all lower case so we can compare properly
if salt.utils.platform.is_windows():
if lgrp["members"]:
lgrp["members"] = [user.lower() for user in lgrp["members"]]
if members:
members = [
salt.utils.win_functions.get_sam_name(user).lower() for user in members
]
if addusers:
addusers = [
salt.utils.win_functions.get_sam_name(user).lower() for user in addusers
]
if delusers:
delusers = [
salt.utils.win_functions.get_sam_name(user).lower() for user in delusers
]
change = {}
ret = {}
if gid:
try:
gid = int(gid)
if lgrp["gid"] != gid:
change["gid"] = gid
except (TypeError, ValueError):
ret["result"] = False
ret["comment"] = "Invalid gid"
return ret
if members is not None and not members:
if set(lgrp["members"]).symmetric_difference(members):
change["delusers"] = set(lgrp["members"])
elif members:
# if new member list if different than the current
if set(lgrp["members"]).symmetric_difference(members):
change["members"] = members
if addusers:
users_2add = [user for user in addusers if user not in lgrp["members"]]
if users_2add:
change["addusers"] = users_2add
if delusers:
users_2del = [user for user in delusers if user in lgrp["members"]]
if users_2del:
change["delusers"] = users_2del
return change
def present(
name,
gid=None,
system=False,
addusers=None,
delusers=None,
members=None,
non_unique=False,
local=False,
):
r"""
.. versionchanged:: 3006.0
Ensure that a group is present
Args:
name (str):
The name of the group to manage
gid (str):
The group id to assign to the named group; if left empty, then the
next available group id will be assigned. Ignored on Windows
system (bool):
Whether or not the named group is a system group. This is essentially
the '-r' option of 'groupadd'. Ignored on Windows
addusers (list):
List of additional users to be added as a group members. Cannot
conflict with names in delusers. Cannot be used in conjunction with
members.
delusers (list):
Ensure these user are removed from the group membership. Cannot
conflict with names in addusers. Cannot be used in conjunction with
members.
members (list):
Replace existing group members with a list of new members. Cannot be
used in conjunction with addusers or delusers.
non_unique (bool):
Allow creating groups with duplicate (non-unique) GIDs
.. versionadded:: 3006.0
local (Only on systems with lgroupadd available):
Create the group account locally ignoring global account management
(default is False).
.. versionadded:: 3007.0
Example:
.. code-block:: yaml
# Adds DOMAIN\db_admins and Administrators to the local db_admin group
# Removes Users
db_admin:
group.present:
- addusers:
- DOMAIN\db_admins
- Administrators
- delusers:
- Users
# Ensures only DOMAIN\domain_admins and the local Administrator are
# members of the local Administrators group. All other users are
# removed
Administrators:
group.present:
- members:
- DOMAIN\domain_admins
- Administrator
"""
ret = {
"name": name,
"changes": {},
"result": True,
"comment": f"Group {name} is present and up to date",
}
if members is not None and (addusers is not None or delusers is not None):
ret["result"] = None
ret["comment"] = (
'Error: Conflicting options "members" with "addusers" and/or'
' "delusers" can not be used together. '
)
return ret
if addusers and delusers:
# -- if trying to add and delete the same user(s) at the same time.
if not set(addusers).isdisjoint(set(delusers)):
ret["result"] = None
ret["comment"] = (
"Error. Same user(s) can not be added and deleted simultaneously"
)
return ret
changes = _changes(name, gid, addusers, delusers, members, local=local)
if changes:
ret["comment"] = "The following group attributes are set to be changed:\n"
for key, val in changes.items():
ret["comment"] += f"{key}: {val}\n"
if __opts__["test"]:
ret["result"] = None
return ret
for key, val in changes.items():
if key == "gid":
__salt__["group.chgid"](name, gid, non_unique=non_unique)
continue
if key == "addusers":
for user in val:
__salt__["group.adduser"](name, user)
continue
if key == "delusers":
for user in val:
__salt__["group.deluser"](name, user)
continue
if key == "members":
__salt__["group.members"](name, ",".join(members))
continue
# Clear cached group data
sys.modules[__salt__["test.ping"].__module__].__context__.pop(
"group.getent", None
)
changes = _changes(name, gid, addusers, delusers, members, local=local)
if changes:
ret["result"] = False
ret["comment"] += "Some changes could not be applied"
ret["changes"] = {"Failed": changes}
else:
ret["changes"] = {"Final": "All changes applied successfully"}
if changes is False:
# The group is not present, make it!
if __opts__["test"]:
ret["result"] = None
ret["comment"] = f"Group {name} set to be added"
return ret
grps = __salt__["group.getent"]()
# Test if gid is free
if gid is not None and not non_unique:
gid_group = None
for lgrp in grps:
if lgrp["gid"] == gid:
gid_group = lgrp["name"]
break
if gid_group is not None:
ret["result"] = False
ret["comment"] = (
"Group {} is not present but gid {} is already taken by"
" group {}".format(name, gid, gid_group)
)
return ret
# Group is not present, make it.
if salt.utils.platform.is_windows():
add_args = {}
else:
add_args = {"local": local}
if __salt__["group.add"](
name,
gid=gid,
system=system,
non_unique=non_unique,
**add_args,
):
# if members to be added
grp_members = None
if members:
grp_members = ",".join(members)
if addusers:
grp_members = ",".join(addusers)
if grp_members:
__salt__["group.members"](name, grp_members)
# Clear cached group data
sys.modules[__salt__["test.ping"].__module__].__context__.pop(
"group.getent", None
)
ret["comment"] = f"New group {name} created"
ret["changes"] = __salt__["group.info"](name, **_get_root_args(local))
changes = _changes(name, gid, addusers, delusers, members, local=local)
if changes:
ret["result"] = False
ret["comment"] = (
"Group {} has been created but, some changes could not"
" be applied".format(name)
)
ret["changes"] = {"Failed": changes}
else:
ret["result"] = False
ret["comment"] = f"Failed to create new group {name}"
return ret
def absent(name, local=False):
"""
Ensure that the named group is absent
Args:
name (str):
The name of the group to remove
local (Only on systems with lgroupdel available):
Ensure the group account is removed locally ignoring global
account management (default is False).
.. versionadded:: 3007.0
Example:
.. code-block:: yaml
# Removes the local group `db_admin`
db_admin:
group.absent
"""
ret = {"name": name, "changes": {}, "result": True, "comment": ""}
grp_info = __salt__["group.info"](name, **_get_root_args(local))
if grp_info:
# Group already exists. Remove the group.
if __opts__["test"]:
ret["result"] = None
ret["comment"] = f"Group {name} is set for removal"
return ret
if salt.utils.platform.is_windows():
del_args = {}
else:
del_args = {"local": local}
ret["result"] = __salt__["group.delete"](name, **del_args)
if ret["result"]:
ret["changes"] = {name: ""}
ret["comment"] = f"Removed group {name}"
return ret
else:
ret["comment"] = f"Failed to remove group {name}"
return ret
else:
ret["comment"] = "Group not present"
return ret
Zerion Mini Shell 1.0