# Buggy code
def add(
    name,
    uid=None,
    gid=None,
    groups=None,
    home=None,
    shell=None,
    unique=True,
    system=False,
    fullname="",
    roomnumber="",
    workphone="",
    homephone="",
    createhome=True,
    loginclass=None,
    root=None,
):
    """
    Add a user to the minion

    CLI Example:

    .. code-block:: bash

        salt '*' user.add name <uid> <gid> <groups> <home> <shell>
    """
    cmd = ["useradd"]
    if shell:
        cmd.extend(["-s", shell])
    if uid not in (None, ""):
        cmd.extend(["-u", str(uid)])
    if gid not in (None, ""):
        cmd.extend(["-g", str(gid)])
    elif groups is not None and name in groups:
        defs_file = "/etc/login.defs"
        if __grains__["kernel"] != "OpenBSD":
            try:
                with salt.utils.fopen(defs_file) as fp_:
                    for line in fp_:
                        if "USERGROUPS_ENAB" not in line[:15]:
                            continue

                        if "yes" in line:
                            cmd.extend(["-g", str(__salt__["file.group_to_gid"](name))])

                        # We found what we wanted, let's break out of the loop
                        break
            except OSError:
                log.debug(
                    "Error reading " + defs_file, exc_info_on_loglevel=logging.DEBUG
                )
        else:
            usermgmt_file = "/etc/usermgmt.conf"
            try:
                with salt.utils.fopen(usermgmt_file) as fp_:
                    for line in fp_:
                        if "group" not in line[:5]:
                            continue

                        cmd.extend(["-g", str(line.split()[-1])])

                        # We found what we wanted, let's break out of the loop
                        break
            except OSError:
                # /etc/usermgmt.conf not present: defaults will be used
                pass

    if createhome:
        cmd.append("-m")
    elif __grains__["kernel"] != "NetBSD" and __grains__["kernel"] != "OpenBSD":
        cmd.append("-M")

    if home is not None:
        cmd.extend(["-d", home])

    if not unique:
        cmd.append("-o")

    if (
        system
        and __grains__["kernel"] != "NetBSD"
        and __grains__["kernel"] != "OpenBSD"
    ):
        cmd.append("-r")

    if __grains__["kernel"] == "OpenBSD":
        if loginclass is not None:
            cmd.extend(["-L", loginclass])

    cmd.append(name)

    if root is not None:
        cmd.extend(("-R", root))

    ret = __salt__["cmd.run_all"](cmd, python_shell=False)

    if ret["retcode"] != 0:
        return False

    # At this point, the user was successfully created, so return true
    # regardless of the outcome of the below functions. If there is a
    # problem wth changing any of the user's info below, it will be raised
    # in a future highstate call. If anyone has a better idea on how to do
    # this, feel free to change it, but I didn't think it was a good idea
    # to return False when the user was successfully created since A) the
    # user does exist, and B) running useradd again would result in a
    # nonzero exit status and be interpreted as a False result.
    if groups:
        chgroups(name, groups)
    if fullname:
        chfullname(name, fullname)
    if roomnumber:
        chroomnumber(name, roomnumber)
    if workphone:
        chworkphone(name, workphone)
    if homephone:
        chhomephone(name, homephone)
    return True


# Traceback (KeyError)
gvlac201.dolgen.net:
----------
ID: admin
Function: group.present
Result: False
Comment: An exception occurred in this state: Traceback (most recent call last):
File "/opt/salt/lib/python2.7/site-packages/salt/state.py", line 1626, in call
**cdata['kwargs'])
File "/opt/salt/lib/python2.7/site-packages/salt/loader.py", line 1492, in wrapper
return f(*args, **kwargs)
File "/opt/salt/lib/python2.7/site-packages/salt/states/group.py", line 133, in present
members)
File "/opt/salt/lib/python2.7/site-packages/salt/states/group.py", line 49, in _changes
lgrp = __salt__['group.info'](name)
File "/opt/salt/lib/python2.7/site-packages/salt/loader.py", line 900, in __getitem__
func = super(LazyLoader, self).__getitem__(item)
File "/opt/salt/lib/python2.7/site-packages/salt/utils/lazy.py", line 93, in __getitem__
raise KeyError(key)
KeyError: 'group.info'
Started: 08:33:03.885764
Duration: 529.316 ms
Changes:
----------
ID: ahatch
Function: user.present
Result: False
Comment: An exception occurred in this state: Traceback (most recent call last):
File "/opt/salt/lib/python2.7/site-packages/salt/state.py", line 1626, in call
**cdata['kwargs'])
File "/opt/salt/lib/python2.7/site-packages/salt/loader.py", line 1492, in wrapper
return f(*args, **kwargs)
File "/opt/salt/lib/python2.7/site-packages/salt/states/user.py", line 385, in present
missing_groups = [x for x in groups if not __salt__['group.info'](x)]
File "/opt/salt/lib/python2.7/site-packages/salt/loader.py", line 900, in __getitem__
func = super(LazyLoader, self).__getitem__(item)
File "/opt/salt/lib/python2.7/site-packages/salt/utils/lazy.py", line 93, in __getitem__
raise KeyError(key)
KeyError: 'group.info'
Started: 08:33:04.415783
Duration: 6.421 ms
Changes:
----------
ID: ahatch_key
Function: ssh_auth.present
Name: ssh-rsa     AAAAB3NzaC1yc2EAAAABIwAAAQEA2rCAFL1YpFpfssaMJYg5PFr3FVoFtQ9LhNR2DTdLiA5KSful    E7fS7WTCDQgHDVdIAlEDdybqTktf0OExRfhmL5Qg6B6b9qYnIL5tChDC79xfby1Aqv/psIOciAYuy5    GaLLmSzUrjJsu+Z2482dCT7svcLhg/1oZ8ZZfVkh6H8wE1JL3eZ0mFQsTsV5SOFJHb11TKulBciXi    beKKNuk1hlT7nDN1wdHa5W6xU775CzQJhG37Yzgl1gAcSSDY0GXDynbz7TGIc/66FeAoc3N14sH    JFLvImvsIL+GmqpDKlaoMkBdTSRNeHMXGXKNraG2Xjirlbi2o8RZI00gvs/lm1WQ==     ahatch@gvllx000.dolgen.net
Result: False
Comment: An exception occurred in this state: Traceback (most recent call last):
File "/opt/salt/lib/python2.7/site-packages/salt/state.py", line 1626, in call
**cdata['kwargs'])
File "/opt/salt/lib/python2.7/site-packages/salt/loader.py", line 1492, in wrapper
return f(*args, **kwargs)
File "/opt/salt/lib/python2.7/site-packages/salt/states/ssh_auth.py", line 330, in present
config)
File "/opt/salt/lib/python2.7/site-packages/salt/modules/ssh.py", line 668, in set_auth_key
uinfo = __salt__['user.info'](user)
File "/opt/salt/lib/python2.7/site-packages/salt/loader.py", line 900, in __getitem__
func = super(LazyLoader, self).__getitem__(item)
File "/opt/salt/lib/python2.7/site-packages/salt/utils/lazy.py", line 93, in __getitem__
raise KeyError(key)
KeyError: 'user.info'
Started: 08:33:04.422682
Duration: 7.286 ms
Changes:

Summary for gvlac201.dolgen.net
------------
Succeeded: 0
Failed:    3
------------
Total states run:     3

# Fixed code
def add(
    name,
    uid=None,
    gid=None,
    groups=None,
    home=None,
    shell=None,
    unique=True,
    system=False,
    fullname="",
    roomnumber="",
    workphone="",
    homephone="",
    createhome=True,
    loginclass=None,
    root=None,
):
    """
    Add a user to the minion

    CLI Example:

    .. code-block:: bash

        salt '*' user.add name <uid> <gid> <groups> <home> <shell>
    """
    cmd = ["useradd"]
    if shell:
        cmd.extend(["-s", shell])
    if uid not in (None, ""):
        cmd.extend(["-u", str(uid)])
    if gid not in (None, ""):
        cmd.extend(["-g", str(gid)])
    elif groups is not None and name in groups:
        defs_file = "/etc/login.defs"
        if __grains__["kernel"] != "OpenBSD":
            try:
                with salt.utils.fopen(defs_file) as fp_:
                    for line in fp_:
                        if "USERGROUPS_ENAB" not in line[:15]:
                            continue

                        if "yes" in line:
                            cmd.extend(["-g", str(__salt__["file.group_to_gid"](name))])

                        # We found what we wanted, let's break out of the loop
                        break
            except OSError:
                log.debug(
                    "Error reading " + defs_file, exc_info_on_loglevel=logging.DEBUG
                )
        else:
            usermgmt_file = "/etc/usermgmt.conf"
            try:
                with salt.utils.fopen(usermgmt_file) as fp_:
                    for line in fp_:
                        if "group" not in line[:5]:
                            continue

                        cmd.extend(["-g", str(line.split()[-1])])

                        # We found what we wanted, let's break out of the loop
                        break
            except OSError:
                # /etc/usermgmt.conf not present: defaults will be used
                pass

    if createhome:
        cmd.append("-m")
    elif __grains__["kernel"] != "NetBSD" and __grains__["kernel"] != "OpenBSD":
        cmd.append("-M")

    if home is not None:
        cmd.extend(["-d", home])

    if not unique and __grains__["kernel"] != "AIX":
        cmd.append("-o")

    if (
        system
        and __grains__["kernel"] != "NetBSD"
        and __grains__["kernel"] != "OpenBSD"
    ):
        cmd.append("-r")

    if __grains__["kernel"] == "OpenBSD":
        if loginclass is not None:
            cmd.extend(["-L", loginclass])

    cmd.append(name)

    if root is not None and __grains__["kernel"] != "AIX":
        cmd.extend(("-R", root))

    ret = __salt__["cmd.run_all"](cmd, python_shell=False)

    if ret["retcode"] != 0:
        return False

    # At this point, the user was successfully created, so return true
    # regardless of the outcome of the below functions. If there is a
    # problem wth changing any of the user's info below, it will be raised
    # in a future highstate call. If anyone has a better idea on how to do
    # this, feel free to change it, but I didn't think it was a good idea
    # to return False when the user was successfully created since A) the
    # user does exist, and B) running useradd again would result in a
    # nonzero exit status and be interpreted as a False result.
    if groups:
        chgroups(name, groups)
    if fullname:
        chfullname(name, fullname)
    if roomnumber:
        chroomnumber(name, roomnumber)
    if workphone:
        chworkphone(name, workphone)
    if homephone:
        chhomephone(name, homephone)
    return True