def role(
    state, host, name,
    present=True,
    password=None, login=True, superuser=False, inherit=False,
    createdb=False, createrole=False, replication=False, connection_limit=None,
    # Details for speaking to PostgreSQL via `psql` CLI
    postgresql_user=None, postgresql_password=None,
    postgresql_host=None, postgresql_port=None,
):
    '''
    Add/remove PostgreSQL roles.

    + name: name of the role
    + present: whether the role should be present or absent
    + login: whether the role can login
    + superuser: whether role will be a superuser
    + inherit: whether the role inherits from other roles
    + createdb: whether the role is allowed to create databases
    + createrole: whether the role is allowed to create new roles
    + replication: whether this role is allowed to replicate
    + connection_limit: the connection limit for the role
    + postgresql_*: global module arguments, see above

    Updates:
        pyinfra will not attempt to change existing roles - it will either
        create or drop roles, but not alter them (if the role exists this
        operation will make no changes).
    '''

    roles = host.fact.postgresql_roles(
        postgresql_user, postgresql_password,
        postgresql_host, postgresql_port,
    )

    is_present = name in roles

    # User not wanted?
    if not present:
        if is_present:
            yield make_execute_psql_command(
                'DROP ROLE {0}'.format(name),
                user=postgresql_user,
                password=postgresql_password,
                host=postgresql_host,
                port=postgresql_port,
            )
        return

    # If we want the user and they don't exist
    if not is_present:
        sql_bits = ['CREATE ROLE {0}'.format(name)]

        for key, value in (
            ('LOGIN', login),
            ('SUPERUSER', superuser),
            ('INHERIT', inherit),
            ('CREATEDB', createdb),
            ('CREATEROLE', createrole),
            ('REPLICATION', replication),
        ):
            if value:
                sql_bits.append(key)

        if connection_limit:
            sql_bits.append('CONNECTION LIMIT {0}'.format(connection_limit))

        if password:
            sql_bits.append("PASSWORD '{0}'".format(password))

        yield make_execute_psql_command(
            ' '.join(sql_bits),
            user=postgresql_user,
            password=postgresql_password,
            host=postgresql_host,
            port=postgresql_port,
        )