Return a dict with information about users of a Postgres server.

    Set return_password to True to get password hash in the result.

    CLI Example:

    .. code-block:: bash

        salt '*' postgres.user_list

def user_list(user=None, host=None, port=None, maintenance_db=None,
              password=None, runas=None, return_password=False):
    '''
    Return a dict with information about users of a Postgres server.

    Set return_password to True to get password hash in the result.

    CLI Example:

    .. code-block:: bash

        salt '*' postgres.user_list
    '''

    ret = {}

    ver = _parsed_version(user=user,
                          host=host,
                          port=port,
                          maintenance_db=maintenance_db,
                          password=password,
                          runas=runas)
    if ver:
        if ver >= _LooseVersion('9.1'):
            replication_column = 'pg_roles.rolreplication'
        else:
            replication_column = 'NULL'
        if ver >= _LooseVersion('9.5'):
            rolcatupdate_column = 'NULL'
        else:
            rolcatupdate_column = 'pg_roles.rolcatupdate'
    else:
        log.error('Could not retrieve Postgres version. Is Postgresql server running?')
        return False

    # will return empty string if return_password = False
    _x = lambda s: s if return_password else ''

    query = (''.join([
        'SELECT '
        'pg_roles.rolname as "name",'
        'pg_roles.rolsuper as "superuser", '
        'pg_roles.rolinherit as "inherits privileges", '
        'pg_roles.rolcreaterole as "can create roles", '
        'pg_roles.rolcreatedb as "can create databases", '
        '{0} as "can update system catalogs", '
        'pg_roles.rolcanlogin as "can login", '
        '{1} as "replication", '
        'pg_roles.rolconnlimit as "connections", '
        '(SELECT array_agg(pg_roles2.rolname)'
        '    FROM pg_catalog.pg_auth_members'
        '    JOIN pg_catalog.pg_roles pg_roles2 ON (pg_auth_members.roleid = pg_roles2.oid)'
        '    WHERE pg_auth_members.member = pg_roles.oid) as "groups",'
        'pg_roles.rolvaliduntil::timestamp(0) as "expiry time", '
        'pg_roles.rolconfig  as "defaults variables" '
        , _x(', COALESCE(pg_shadow.passwd, pg_authid.rolpassword) as "password" '),
        'FROM pg_roles '
        , _x('LEFT JOIN pg_authid ON pg_roles.oid = pg_authid.oid ')
        , _x('LEFT JOIN pg_shadow ON pg_roles.oid = pg_shadow.usesysid')
    ]).format(rolcatupdate_column, replication_column))

    rows = psql_query(query,
                      runas=runas,
                      host=host,
                      user=user,
                      port=port,
                      maintenance_db=maintenance_db,
                      password=password)

    def get_bool(rowdict, key):
        '''
        Returns the boolean value of the key, instead of 't' and 'f' strings.
        '''
        if rowdict[key] == 't':
            return True
        elif rowdict[key] == 'f':
            return False
        else:
            return None

    for row in rows:
        retrow = {}
        for key in ('superuser', 'inherits privileges', 'can create roles',
                    'can create databases', 'can update system catalogs',
                    'can login', 'replication', 'connections'):
            retrow[key] = get_bool(row, key)
        for date_key in ('expiry time',):
            try:
                retrow[date_key] = datetime.datetime.strptime(
                    row[date_key], '%Y-%m-%d %H:%M:%S')
            except ValueError:
                retrow[date_key] = None
        retrow['defaults variables'] = row['defaults variables']
        if return_password:
            retrow['password'] = row['password']
        # use csv reader to handle quoted roles correctly
        retrow['groups'] = list(csv.reader([row['groups'].strip('{}')]))[0]
        ret[row['name']] = retrow

    return ret