Too true. I went through the whole thing line by line (forcing myself awake every couple of lines).
Alas, the only interesting thing is what’s not there. At the end, we see the guts of the synchronize.py module get copied to your delegate_to: host, and a chmod u+x on the containing directory and the file itself:
Using module file /usr/share/ansible/collections/ansible_collections/ansible/posix/plugins/modules/synchronize.py
<192.168.151.237> PUT /runner/.ansible/tmp/ansible-local-2295bqx_n8/tmpokmyow7d TO /root/.ansible/tmp/ansible-tmp-1718701712.9134433-213-60173677516755/AnsiballZ_synchronize.py
<192.168.151.237> SSH: EXEC sftp -b - -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o 'User="root"' -o ConnectTimeout=10 -o 'ControlPath="/runner/cp/63d63d053c"' '[192.168.151.237]'
<192.168.151.237> (0, b'sftp> put /runner/.ansible/tmp/ansible-local-2295bqx_n8/tmpokmyow7d /root/.ansible/tmp/ansible-tmp-1718701712.9134433-213-60173677516755/AnsiballZ_synchronize.py\\n', b'')
<192.168.151.237> ESTABLISH SSH CONNECTION FOR USER: root
<192.168.151.237> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o 'User="root"' -o ConnectTimeout=10 -o 'ControlPath="/runner/cp/63d63d053c"' 192.168.151.237 '/bin/sh -c '"'"'chmod u+x /root/.ansible/tmp/ansible-tmp-1718701712.9134433-213-60173677516755/ /root/.ansible/tmp/ansible-tmp-1718701712.9134433-213-60173677516755/AnsiballZ_synchronize.py && sleep 0'"'"''
<192.168.151.237> (0, b'', b'')
After that, we see it get run under /bin/sh with the -c parameter:
<192.168.151.237> ESTABLISH SSH CONNECTION FOR USER: root
<192.168.151.237> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o 'User="root"' -o ConnectTimeout=10 -o 'ControlPath="/runner/cp/63d63d053c"' -tt 192.168.151.237 '/bin/sh -c '"'"'/usr/bin/python3 /root/.ansible/tmp/ansible-tmp-1718701712.9134433-213-60173677516755/AnsiballZ_synchronize.py && sleep 0'"'"''
Notably absent is any hint of the parameters you used on ansible.builtin.synchronize, or of any activity from that point forward.
Also crucially absent is any hint of the synchronize task running as remcpyusr rather than root. At this point of desperation, I would try adding “become_user: remcpyusr” on that final task at the same indentation level as delegate_to: and loop:. It’s grasping at straws really, but at this point we’re just trying to get it to behave differently. We don’t even care particularly whether that difference is effective; we’re just hoping for something noticeable.
If anybody else has another suggestion, we’d love to hear it!
The log you shared answers one of my other questions. Every new play causes a new round of facts gathering for each host. Most of the time (ignoring the infinite amount of time at the last task) is spent re-gathering host facts. That’s why you’d want to use when: "'blah_blah' in group_names" on tasks instead of starting new plays. Play setup is eating up your clock.
[Edit: you could add gather_facts: false on those later plays.]
Finally, drop those “Set permissions […]” tasks, and move the owner:, group:, and mode: settings up to the “Distribute […]” tasks. (The “Set permissions […]” tasks aren’t actually doing anything; the owner and group are already defaulting to remcpyusr, but it’s better to be explicit about them in the “Distribute […]” tasks.)