def user(
    state, host, name,
    # Desired user settings
    present=True,
    user_hostname='localhost', password=None, privileges=None,
    # Details for speaking to MySQL via `mysql` CLI via `mysql` CLI
    mysql_user=None, mysql_password=None,
    mysql_host=None, mysql_port=None,
):
    '''
    Add/remove/update MySQL users.

    + name: the name of the user
    + present: whether the user should exist or not
    + user_hostname: the hostname of the user
    + password: the password of the user (if created)
    + privileges: the global privileges for this user
    + mysql_*: global module arguments, see above

    Hostname:
        this + ``name`` makes the username - so changing this will create a new
        user, rather than update users with the same ``name``.

    Password:
        will only be applied if the user does not exist - ie pyinfra cannot
        detect if the current password doesn't match the one provided, so won't
        attempt to change it.
    '''

    current_users = host.fact.mysql_users(
        mysql_user, mysql_password, mysql_host, mysql_port,
    )

    user_host = '{0}@{1}'.format(name, user_hostname)
    is_present = user_host in current_users

    # User not wanted?
    if not present:
        if is_present:
            yield make_execute_mysql_command(
                'DROP USER "{0}"@"{1}"'.format(name, user_hostname),
                user=mysql_user,
                password=mysql_password,
                host=mysql_host,
                port=mysql_port,
            )
        return

    # If we want the user and they don't exist
    if present and not is_present:
        sql_bits = ['CREATE USER "{0}"@"{1}"'.format(name, user_hostname)]
        if password:
            sql_bits.append('IDENTIFIED BY "{0}"'.format(password))

        yield make_execute_mysql_command(
            ' '.join(sql_bits),
            user=mysql_user,
            password=mysql_password,
            host=mysql_host,
            port=mysql_port,
        )

    # If we're here either the user exists or we just created them; either way
    # now we can check any privileges are set.
    if privileges:
        yield _privileges(
            state, host, name, privileges,
            user_hostname=user_hostname,
            mysql_user=mysql_user, mysql_password=mysql_password,
            mysql_host=mysql_host, mysql_port=mysql_port,
        )
Add/remove/update MySQL users.

    + name: the name of the user
    + present: whether the user should exist or not
    + user_hostname: the hostname of the user
    + password: the password of the user (if created)
    + privileges: the global privileges for this user
    + mysql_*: global module arguments, see above

    Hostname:
        this + ``name`` makes the username - so changing this will create a new
        user, rather than update users with the same ``name``.

    Password:
        will only be applied if the user does not exist - ie pyinfra cannot
        detect if the current password doesn't match the one provided, so won't
        attempt to change it.