# Buggy code
def _publish(
    tgt,
    fun,
    arg=None,
    tgt_type="glob",
    returner="",
    timeout=5,
    form="clean",
    wait=False,
    via_master=None,
):
    """
    Publish a command from the minion out to other minions, publications need
    to be enabled on the Salt master and the minion needs to have permission
    to publish the command. The Salt master will also prevent a recursive
    publication loop, this means that a minion cannot command another minion
    to command another minion as that would create an infinite command loop.

    The arguments sent to the minion publish function are separated with
    commas. This means that for a minion executing a command with multiple
    args it will look like this::

        salt system.example.com publish.publish '*' user.add 'foo,1020,1020'

    CLI Example:

    .. code-block:: bash

        salt system.example.com publish.publish '*' cmd.run 'ls -la /tmp'
    """
    if "master_uri" not in __opts__:
        log.error(
            "Cannot run publish commands without a connection to a salt master. No command sent."
        )
        return {}
    if fun.startswith("publish."):
        log.info("Cannot publish publish calls. Returning {}")
        return {}

    arg = _parse_args(arg)

    if via_master:
        if "master_uri_list" not in __opts__:
            raise SaltInvocationError(
                message="Could not find list of masters \
                    in minion configuration but `via_master` was specified."
            )
        else:
            # Find the master in the list of master_uris generated by the minion base class
            matching_master_uris = [
                master
                for master in __opts__["master_uri_list"]
                if "//{0}:".format(via_master) in master
            ]

            if not matching_master_uris:
                raise SaltInvocationError(
                    "Could not find match for {0} in \
                list of configured masters {1} when using `via_master` option".format(
                        via_master, __opts__["master_uri_list"]
                    )
                )

            if len(matching_master_uris) > 1:
                # If we have multiple matches, consider this a non-fatal error
                # and continue with whatever we found first.
                log.warning(
                    "The `via_master` flag found \
                        more than one possible match found for {0} when evaluating \
                        list {1}".format(via_master, __opts__["master_uri_list"])
                )
            master_uri = matching_master_uris.pop()
    else:
        # If no preference is expressed by the user, just publish to the first master
        # in the list.
        master_uri = __opts__["master_uri"]

    log.info("Publishing '{0}' to {1}".format(fun, master_uri))
    auth = salt.crypt.SAuth(__opts__)
    tok = auth.gen_token("salt")
    load = {
        "cmd": "minion_pub",
        "fun": fun,
        "arg": arg,
        "tgt": tgt,
        "tgt_type": tgt_type,
        "ret": returner,
        "tok": tok,
        "tmo": timeout,
        "form": form,
        "id": __opts__["id"],
    }

    channel = salt.transport.Channel.factory(__opts__, master_uri=master_uri)
    try:
        peer_data = channel.send(load)
    except SaltReqTimeoutError:
        return "'{0}' publish timed out".format(fun)
    if not peer_data:
        return {}
    # CLI args are passed as strings, re-cast to keep time.sleep happy
    if wait:
        loop_interval = 0.3
        matched_minions = set(peer_data["minions"])
        returned_minions = set()
        loop_counter = 0
        while len(returned_minions ^ matched_minions) > 0:
            load = {
                "cmd": "pub_ret",
                "id": __opts__["id"],
                "tok": tok,
                "jid": peer_data["jid"],
            }
            ret = channel.send(load)
            returned_minions = set(ret.keys())

            end_loop = False
            if returned_minions >= matched_minions:
                end_loop = True
            elif (loop_interval * loop_counter) > timeout:
                # This may be unnecessary, but I am paranoid
                if len(returned_minions) < 1:
                    return {}
                end_loop = True

            if end_loop:
                if form == "clean":
                    cret = {}
                    for host in ret:
                        cret[host] = ret[host]["ret"]
                    return cret
                else:
                    return ret
            loop_counter = loop_counter + 1
            time.sleep(loop_interval)
    else:
        time.sleep(float(timeout))
        load = {
            "cmd": "pub_ret",
            "id": __opts__["id"],
            "tok": tok,
            "jid": peer_data["jid"],
        }
        ret = channel.send(load)
        if form == "clean":
            cret = {}
            for host in ret:
                cret[host] = ret[host]["ret"]
            return cret
        else:
            return ret


# Traceback (RestException)
2017-03-13 11:19:26.095 [INFO] 10.234.112.46 >> POST http://10.234.112.107/api/1.8/host/salt-host
{
"wwnlist":"['0011223344556677', '1122334455667788']"
}
Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/pure/rest/controller/util.py", line 97, in execute
(command, args) = get_args(command_list, version, params)
File "/usr/lib/python2.7/dist-packages/pure/rest/controller/util.py", line 392, in get_args
raise RestException("Value of argument {} needs to be one of {}.".format(key, arg.arg_type), Code.BAD_REQUEST)
RestException: Value of argument wwnlist needs to be one of ['list'].
2017-03-13 11:19:26.101 [WARNING] << 400 BAD REQUEST
{
"msg":"Value of argument wwnlist needs to be one of ['list']."
}

# Fixed code
def _publish(
    tgt,
    fun,
    arg=None,
    tgt_type="glob",
    returner="",
    timeout=5,
    form="clean",
    wait=False,
    via_master=None,
):
    """
    Publish a command from the minion out to other minions, publications need
    to be enabled on the Salt master and the minion needs to have permission
    to publish the command. The Salt master will also prevent a recursive
    publication loop, this means that a minion cannot command another minion
    to command another minion as that would create an infinite command loop.

    The arguments sent to the minion publish function are separated with
    commas. This means that for a minion executing a command with multiple
    args it will look like this::

        salt system.example.com publish.publish '*' user.add 'foo,1020,1020'

    CLI Example:

    .. code-block:: bash

        salt system.example.com publish.publish '*' cmd.run 'ls -la /tmp'
    """
    if "master_uri" not in __opts__:
        log.error(
            "Cannot run publish commands without a connection to a salt master. No command sent."
        )
        return {}
    if fun.startswith("publish."):
        log.info("Cannot publish publish calls. Returning {}")
        return {}

    arg = _parse_args(arg)

    if via_master:
        if "master_uri_list" not in __opts__:
            raise SaltInvocationError(
                message="Could not find list of masters \
                    in minion configuration but `via_master` was specified."
            )
        else:
            # Find the master in the list of master_uris generated by the minion base class
            matching_master_uris = [
                master
                for master in __opts__["master_uri_list"]
                if "//{0}:".format(via_master) in master
            ]

            if not matching_master_uris:
                raise SaltInvocationError(
                    "Could not find match for {0} in \
                list of configured masters {1} when using `via_master` option".format(
                        via_master, __opts__["master_uri_list"]
                    )
                )

            if len(matching_master_uris) > 1:
                # If we have multiple matches, consider this a non-fatal error
                # and continue with whatever we found first.
                log.warning(
                    "The `via_master` flag found \
                        more than one possible match found for {0} when evaluating \
                        list {1}".format(via_master, __opts__["master_uri_list"])
                )
            master_uri = matching_master_uris.pop()
    else:
        # If no preference is expressed by the user, just publish to the first master
        # in the list.
        master_uri = __opts__["master_uri"]

    log.info("Publishing '{0}' to {1}".format(fun, master_uri))
    auth = salt.crypt.SAuth(__opts__)
    tok = auth.gen_token("salt")
    load = {
        "cmd": "minion_pub",
        "fun": fun,
        "arg": arg,
        "tgt": tgt,
        "tgt_type": tgt_type,
        "ret": returner,
        "tok": tok,
        "tmo": timeout,
        "form": form,
        "id": __opts__["id"],
        "no_parse": __opts__.get("no_parse", []),
    }

    channel = salt.transport.Channel.factory(__opts__, master_uri=master_uri)
    try:
        peer_data = channel.send(load)
    except SaltReqTimeoutError:
        return "'{0}' publish timed out".format(fun)
    if not peer_data:
        return {}
    # CLI args are passed as strings, re-cast to keep time.sleep happy
    if wait:
        loop_interval = 0.3
        matched_minions = set(peer_data["minions"])
        returned_minions = set()
        loop_counter = 0
        while len(returned_minions ^ matched_minions) > 0:
            load = {
                "cmd": "pub_ret",
                "id": __opts__["id"],
                "tok": tok,
                "jid": peer_data["jid"],
            }
            ret = channel.send(load)
            returned_minions = set(ret.keys())

            end_loop = False
            if returned_minions >= matched_minions:
                end_loop = True
            elif (loop_interval * loop_counter) > timeout:
                # This may be unnecessary, but I am paranoid
                if len(returned_minions) < 1:
                    return {}
                end_loop = True

            if end_loop:
                if form == "clean":
                    cret = {}
                    for host in ret:
                        cret[host] = ret[host]["ret"]
                    return cret
                else:
                    return ret
            loop_counter = loop_counter + 1
            time.sleep(loop_interval)
    else:
        time.sleep(float(timeout))
        load = {
            "cmd": "pub_ret",
            "id": __opts__["id"],
            "tok": tok,
            "jid": peer_data["jid"],
        }
        ret = channel.send(load)
        if form == "clean":
            cret = {}
            for host in ret:
                cret[host] = ret[host]["ret"]
            return cret
        else:
            return ret