# Buggy code
def filter_list(s3, bucket, s3filelist, strategy):
    keeplist = list(s3filelist)

    for e in keeplist:
        e["_strategy"] = strategy

    # init/fetch info from S3 if we're going to use it for comparisons
    if not strategy == "force":
        keeplist = head_s3(s3, bucket, s3filelist)

    # now actually run the strategies
    if strategy == "checksum":
        for entry in keeplist:
            if entry.get("s3_head"):
                # since we have a remote s3 object, compare the values.
                if entry["s3_head"]["ETag"] == entry["local_etag"]:
                    # files match, so remove the entry
                    entry["skip_flag"] = True
                else:
                    # file etags don't match, keep the entry.
                    pass
            else:  # we don't have an etag, so we'll keep it.
                pass
    elif strategy == "date_size":
        for entry in keeplist:
            if entry.get("s3_head"):
                # fstat = entry['stat']
                local_modified_epoch = entry["modified_epoch"]
                local_size = entry["bytes"]

                # py2's datetime doesn't have a timestamp() field, so we have to revert to something more awkward.
                # remote_modified_epoch = entry['s3_head']['LastModified'].timestamp()
                remote_modified_datetime = entry["s3_head"]["LastModified"]
                delta = remote_modified_datetime - datetime.datetime(
                    1970, 1, 1, tzinfo=tz.tzutc()
                )
                remote_modified_epoch = delta.seconds + (delta.days * 86400)

                remote_size = entry["s3_head"]["ContentLength"]

                entry["whytime"] = "{} / {}".format(
                    local_modified_epoch, remote_modified_epoch
                )
                entry["whysize"] = "{} / {}".format(local_size, remote_size)

                if (
                    local_modified_epoch <= remote_modified_epoch
                    or local_size == remote_size
                ):
                    entry["skip_flag"] = True
            else:
                entry["why"] = "no s3_head"
    # else: probably 'force'. Basically we don't skip with any with other strategies.
    else:
        pass

    # prune 'please skip' entries, if any.
    return [x for x in keeplist if not x.get("skip_flag")]


# Traceback (exceptions.ValueError)
Using /apps/mule-platform/mule/ansible.cfg as config file
Loading callback plugin default of type stdout, v2.0 from /apps/ansible/lib/ansible/plugins/callback/__init__.pyc

PLAYBOOK: s3.yml **************************************************************************************************
1 plays in s3.yml

PLAY [localhost] **************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************
Using module file /apps/ansible/lib/ansible/modules/system/setup.py
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: mulrddep
<localhost> EXEC /bin/sh -c 'echo ~ &amp;&amp; sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 &amp;&amp; mkdir -p "` echo /home/mulrddep/.ansible/tmp/ansible-tmp-1502754249.89-250223534758667 `" &amp;&amp; echo ansible-tmp-1502754249.89-250223534758667="` echo /home/mulrddep/.ansible/tmp/ansible-tmp-1502754249.89-250223534758667 `" ) &amp;&amp; sleep 0'
<localhost> PUT /tmp/tmpL1iEtj TO /home/mulrddep/.ansible/tmp/ansible-tmp-1502754249.89-250223534758667/setup.py
<localhost> EXEC /bin/sh -c 'chmod u+x /home/mulrddep/.ansible/tmp/ansible-tmp-1502754249.89-250223534758667/ /home/mulrddep/.ansible/tmp/ansible-tmp-1502754249.89-250223534758667/setup.py &amp;&amp; sleep 0'
<localhost> EXEC /bin/sh -c '/usr/bin/python /home/mulrddep/.ansible/tmp/ansible-tmp-1502754249.89-250223534758667/setup.py; rm -rf "/home/mulrddep/.ansible/tmp/ansible-tmp-1502754249.89-250223534758667/" > /dev/null 2>&amp;1 &amp;&amp; sleep 0'
ok: [localhost]
META: ran handlers


TASK [Upload to s3 bucket] ****************************************************************************************
task path: /apps/mule-platform/mule/s3.yml:36
Using module file /apps/ansible/lib/ansible/modules/cloud/amazon/s3_sync.py
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: mulrddep
<localhost> EXEC /bin/sh -c 'echo ~ &amp;&amp; sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 &amp;&amp; mkdir -p "` echo /home/mulrddep/.ansible/tmp/ansible-tmp-1502754251.47-153974990253487 `" &amp;&amp; echo ansible-tmp-1502754251.47-153974990253487="` echo /home/mulrddep/.ansible/tmp/ansible-tmp-1502754251.47-153974990253487 `" ) &amp;&amp; sleep 0'
<localhost> PUT /tmp/tmpL1iEtj TO /home/mulrddep/.ansible/tmp/ansible-tmp-1502754251.47-153974990253487/s3_sync.py
<localhost> EXEC /bin/sh -c 'chmod u+x /home/mulrddep/.ansible/tmp/ansible-tmp-1502754251.47-153974990253487/ /home/mulrddep/.ansible/tmp/ansible-tmp-1502754251.47-153974990253487/s3_sync.py &amp;&amp; sleep 0'
<localhost> EXEC /bin/sh -c '/usr/bin/python /home/mulrddep/.ansible/tmp/ansible-tmp-1502754251.47-153974990253487/s3_sync.py; rm -rf "/home/mulrddep/.ansible/tmp/ansible-tmp-1502754251.47-153974990253487/" > /dev/null 2>&amp;1 &amp;&amp; sleep 0'
fatal: [localhost]: FAILED! => {
"changed": false,
"failed": true,
"invocation": {
"module_args": {
"aws_access_key": "ASIAILNFILJ74DT75P3A",
"aws_secret_key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"bucket": "suncorp-mule-connector-updatesites",
"ec2_url": null,
"exclude": ".*",
"file_change_strategy": "force",
"file_root": "/tmp/connector-life400/",
"include": "*",
"key_prefix": "connector-life400",
"mime_map": null,
"mode": "push",
"permission": null,
"profile": null,
"region": "ap-southeast-2",
"retries": null,
"security_token": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"validate_certs": true
}
},
"msg": "zero length field name in format zero length field name in format - <type 'exceptions.ValueError'>",
"traceback": [
"Traceback (most recent call last):",
"  File \"/tmp/ansible_ZjFzBU/ansible_module_s3_sync.py\", line 478, in main",
"    result['filelist_local_etag'] = calculate_local_etag(result['filelist_s3'])",
"  File \"/tmp/ansible_ZjFzBU/ansible_module_s3_sync.py\", line 330, in calculate_local_etag",
"    retentry['local_etag'] = calculate_multipart_etag(fileentry['fullpath'])",
"  File \"/tmp/ansible_ZjFzBU/ansible_module_s3_sync.py\", line 265, in calculate_multipart_etag",
"    new_etag = '\"{}\"'.format(md5s[0].hexdigest())",
"ValueError: zero length field name in format"
]
}
to retry, use: --limit @/apps/mule-platform/mule/s3.retry

PLAY RECAP ********************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=1

# Fixed code
def filter_list(s3, bucket, s3filelist, strategy):
    keeplist = list(s3filelist)

    for e in keeplist:
        e["_strategy"] = strategy

    # init/fetch info from S3 if we're going to use it for comparisons
    if not strategy == "force":
        keeplist = head_s3(s3, bucket, s3filelist)

    # now actually run the strategies
    if strategy == "checksum":
        for entry in keeplist:
            if entry.get("s3_head"):
                # since we have a remote s3 object, compare the values.
                if entry["s3_head"]["ETag"] == entry["local_etag"]:
                    # files match, so remove the entry
                    entry["skip_flag"] = True
                else:
                    # file etags don't match, keep the entry.
                    pass
            else:  # we don't have an etag, so we'll keep it.
                pass
    elif strategy == "date_size":
        for entry in keeplist:
            if entry.get("s3_head"):
                # fstat = entry['stat']
                local_modified_epoch = entry["modified_epoch"]
                local_size = entry["bytes"]

                # py2's datetime doesn't have a timestamp() field, so we have to revert to something more awkward.
                # remote_modified_epoch = entry['s3_head']['LastModified'].timestamp()
                remote_modified_datetime = entry["s3_head"]["LastModified"]
                delta = remote_modified_datetime - datetime.datetime(
                    1970, 1, 1, tzinfo=tz.tzutc()
                )
                remote_modified_epoch = delta.seconds + (delta.days * 86400)

                remote_size = entry["s3_head"]["ContentLength"]

                entry["whytime"] = "{0} / {1}".format(
                    local_modified_epoch, remote_modified_epoch
                )
                entry["whysize"] = "{0} / {1}".format(local_size, remote_size)

                if (
                    local_modified_epoch <= remote_modified_epoch
                    or local_size == remote_size
                ):
                    entry["skip_flag"] = True
            else:
                entry["why"] = "no s3_head"
    # else: probably 'force'. Basically we don't skip with any with other strategies.
    else:
        pass

    # prune 'please skip' entries, if any.
    return [x for x in keeplist if not x.get("skip_flag")]