# Buggy code
def mk_token(opts, tdata):
    """
    Mint a new token using the config option hash_type and store tdata with 'token' attribute set
    to the token.
    This module uses the hash of random 512 bytes as a token.

    :param opts: Salt master config options
    :param tdata: Token data to be stored with 'token' attirbute of this dict set to the token.
    :returns: tdata with token if successful. Empty dict if failed.
    """
    hash_type = getattr(hashlib, opts.get("hash_type", "md5"))
    tok = six.text_type(hash_type(os.urandom(512)).hexdigest())
    t_path = os.path.join(opts["token_dir"], tok)
    while os.path.isfile(t_path):
        tok = six.text_type(hash_type(os.urandom(512)).hexdigest())
        t_path = os.path.join(opts["token_dir"], tok)
    tdata["token"] = tok
    serial = salt.payload.Serial(opts)
    try:
        with salt.utils.files.set_umask(0o177):
            with salt.utils.files.fopen(t_path, "w+b") as fp_:
                fp_.write(serial.dumps(tdata))
    except (IOError, OSError):
        log.warning('Authentication failure: can not write token file "%s".', t_path)
        return {}
    return tdata


# Traceback (UnpackValueError)
2016-11-27 03:12:16,885 [salt.config                                          ][DEBUG   ][21595] Reading configuration from /etc/salt/master
2016-11-27 03:12:16,933 [salt.config                                          ][DEBUG   ][21595] Using cached minion ID from /etc/salt/minion_id: rbalvcdstestm.bas.roche.com
2016-11-27 03:12:16,935 [salt.config                                          ][DEBUG   ][21595] Reading configuration from /etc/salt/master
2016-11-27 03:12:17,167 [salt.utils.lazy                                      ][DEBUG   ][21595] LazyLoaded local_cache.clean_old_jobs
2016-11-27 03:12:17,168 [salt.payload                                         ][CRITICAL][21595] Could not deserialize msgpack message.This often happens when trying to read a file not in binary modeTo see message payload, enable debug logging and retry. Exception: Unpack failed: error = 0
2016-11-27 03:12:17,168 [salt.payload                                         ][DEBUG   ][21595] Msgpack deserialization failure on message:
2016-11-27 03:12:17,168 [salt.utils.process                                   ][ERROR   ][21595] An un-handled exception from the multiprocessing process 'Maintenance-2441' was caught:
Traceback (most recent call last):
File "/usr/lib/python2.6/site-packages/salt/utils/process.py", line 616, in _run
return self._original_run()
File "/usr/lib/python2.6/site-packages/salt/master.py", line 238, in run
salt.daemons.masterapi.clean_expired_tokens(self.opts)
File "/usr/lib/python2.6/site-packages/salt/daemons/masterapi.py", line 149, in clean_expired_tokens
token_data = serializer.loads(token_file.read())
File "/usr/lib/python2.6/site-packages/salt/payload.py", line 117, in loads
return msgpack.loads(msg, use_list=True)
File "msgpack/_unpacker.pyx", line 145, in msgpack._unpacker.unpackb (msgpack/_unpacker.cpp:145)
UnpackValueError: Unpack failed: error = 0
2016-11-27 03:12:17,173 [salt.utils.process                                   ][INFO    ][7911] Process <class 'salt.master.Maintenance'> (21595) died with exit status None, restarting...
2016-11-27 03:12:18,187 [salt.utils.process                                   ][DEBUG   ][7911] Started 'salt.master.Maintenance' with pid 22028

# Fixed code
def mk_token(opts, tdata):
    """
    Mint a new token using the config option hash_type and store tdata with 'token' attribute set
    to the token.
    This module uses the hash of random 512 bytes as a token.

    :param opts: Salt master config options
    :param tdata: Token data to be stored with 'token' attirbute of this dict set to the token.
    :returns: tdata with token if successful. Empty dict if failed.
    """
    hash_type = getattr(hashlib, opts.get("hash_type", "md5"))
    tok = six.text_type(hash_type(os.urandom(512)).hexdigest())
    t_path = os.path.join(opts["token_dir"], tok)
    temp_t_path = "{}.tmp".format(t_path)
    while os.path.isfile(t_path):
        tok = six.text_type(hash_type(os.urandom(512)).hexdigest())
        t_path = os.path.join(opts["token_dir"], tok)
    tdata["token"] = tok
    serial = salt.payload.Serial(opts)
    try:
        with salt.utils.files.set_umask(0o177):
            with salt.utils.files.fopen(temp_t_path, "w+b") as fp_:
                fp_.write(serial.dumps(tdata))
        os.rename(temp_t_path, t_path)
    except (IOError, OSError):
        log.warning('Authentication failure: can not write token file "%s".', t_path)
        return {}
    return tdata