ansible.posix icon indicating copy to clipboard operation
ansible.posix copied to clipboard

`synchronize` fails to accept `ansible_port` as string

Open silverwind opened this issue 3 years ago • 12 comments

SUMMARY

When ansible is launched with -e ansible_port=1234, the ansible_port variable will be of type str, which is not accepted by the module and no -o Port=1234 is passed down to rsync. If the same variable is defined as int type, it works as expected.

ISSUE TYPE
  • Bug Report
COMPONENT NAME

ansible.posix.synchronize

ANSIBLE VERSION
ansible [core 2.13.4]
  config file = None
  configured module search path = ['/Users/name/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python3.10/site-packages/ansible
  ansible collection location = /Users/name/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/local/bin/ansible
  python version = 3.10.8 (main, Nov 15 2022, 05:25:54) [Clang 14.0.0 (clang-1400.0.29.202)]
  jinja version = 3.1.2
  libyaml = True
COLLECTION VERSION
Collection    Version
------------- -------
ansible.posix 1.4.0
CONFIGURATION
<empty>
OS / ENVIRONMENT

macOS 13

STEPS TO REPRODUCE
- hosts: all
  tasks:
    - ansible.posix.synchronize:
        src: "./"
        dest: "/opt/app/"

Run via ansible-playbook -i 127.0.0.1, -vvv -e ansible_port=1234 playbook.yml, observe no -o Port=1234 being passed.

EXPECTED RESULTS

success

ACTUAL RESULTS

fails as it tries to ssh to localhost port 22:

fatal: [127.0.0.1]: FAILED! => {"changed": false, "cmd": "/usr/local/bin/rsync --delay-updates -F --compress --archive --rsync-path='sudo -u root rsync' --out-format='<<CHANGED>>%i %n%L' /Users/user/app/ /opt/app/", "msg": "rsync: [Receiver] mkdir \"/opt/app\" failed: Permission denied (13)\nrsync error: error in file IO (code 11) at main.c(793) [Receiver=3.2.7]\n", "rc": 11}

silverwind avatar Nov 22 '22 15:11 silverwind

Hello, @silverwind. I've tried to run playbook as you pointed out and got this error on 'gather facts' task:

fatal: [127.0.0.1]: UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: ssh: connect to host 127.0.0.1 port 1234: Connection refused",
    "unreachable": true
}

I reproduced your error with connection: local. Task failed because you don't have permissions to create files. There is no problems with ports otherwise you would get error on 'gather facts' task as I mentioned earlier. If you add options --ask-become-pass --become it will work:

ansible-playbook --ask-become-pass --become -i 127.0.0.1, -vvv -e ansible_port=1234 playbook.yml

vladislav-sharapov avatar Dec 16 '22 19:12 vladislav-sharapov

You need a SSH daemon listening on localhost:1234. In my case it's a Vagrant VM which has my SSH key installed. --ask-become-pass should therefore be unnecessary as it authorizes with SSH key, there are no passwords involved.

silverwind avatar Dec 16 '22 19:12 silverwind

You should be able to reproduce if you disable gather_facts, so it goes directly to the synchronize step, and in that case you don't need anything listening on localhost:1234 to observe the missing rsync option -o Port=1234 in the debug.

silverwind avatar Dec 16 '22 19:12 silverwind

Here is a repo to reproduce. There is str.sh and int.sh, the only difference between them is that str.sh passes the port on the command line, while int.sh passes it via vars.

As int -o Port=1234 is present:

./int.sh
...
    "msg": "ansible_port is type int"
...
fatal: [127.0.0.1]: FAILED! => {"changed": false, "cmd": "/usr/local/bin/rsync --delay-updates -F --compress --archive --rsh='/usr/local/bin/ssh -S none -o Port=1234 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' --out-format='<<CHANGED>>%i %n%L' /Users/silverwind/git/ansible-synchronize-port/ 127.0.0.1:/opt/app/", "msg": "ssh: connect to host 127.0.0.1 port 1234: Connection refused\r\nrsync: connection unexpectedly closed (0 bytes received so far) [sender]\nrsync error: unexplained error (code 255) at io.c(231) [sender=3.2.7]\n", "rc": 255}

As str is it absent (and it goes to localhost:22):

./str.sh
...
    "msg": "ansible_port is type str"
...
fatal: [127.0.0.1]: FAILED! => {"changed": false, "cmd": "/usr/local/bin/rsync --delay-updates -F --compress --archive --out-format='<<CHANGED>>%i %n%L' /Users/silverwind/git/ansible-synchronize-port/ /opt/app/", "msg": "rsync: [Receiver] mkdir \"/opt/app\" failed: Permission denied (13)\nrsync error: error in file IO (code 11) at main.c(793) [Receiver=3.2.7]\n", "rc": 11}

silverwind avatar Dec 16 '22 19:12 silverwind

I think https://github.com/ansible-collections/ansible.posix/issues/376 is the same root cause where ansible_port is passed as string.

silverwind avatar Dec 16 '22 20:12 silverwind

I suppose difference in how ansible-playbook choose connection type. With gather_facts: false connection is local otherwise it's ssh.

vladislav-sharapov avatar Dec 16 '22 20:12 vladislav-sharapov

There should not be any SSH connection intiated by ansible-core in this playbook. The first connection is from the synchronize module and I see it actually fails to pass the whole --rsh argument to rsync when ansible_port is str.

silverwind avatar Dec 16 '22 20:12 silverwind

I've tried to run playbook without ansible_port at all and in this case connection is local.

vladislav-sharapov avatar Dec 16 '22 20:12 vladislav-sharapov

I believe there is difference between passing ansible_port in playbook or in cli. Try to pass ansible_port like this ansible-playbook -i 127.0.0.1, -vvv -e '{"ansible_port":1234}' playbook.yml and you will see:

ok: [127.0.0.1] => {
    "msg": "ansible_port is type int"
}

but connection is still local.

vladislav-sharapov avatar Dec 16 '22 20:12 vladislav-sharapov

It should not matter whether connection is local or not. The reproduction demonstrates the the module goes haywire and fails to pass options to rsync as soon as type is str.

And yeah, there are various workarounds, https://github.com/ansible-collections/ansible.posix/issues/376#issuecomment-1222046195 is another one.

silverwind avatar Dec 16 '22 20:12 silverwind

It's matter because module decides whether rsh is needed or not like this https://github.com/ansible-collections/ansible.posix/blob/main/plugins/modules/synchronize.py#L383. Module doesn't go haywire as soon as type is str. I've showed it in previous comment.

vladislav-sharapov avatar Dec 16 '22 21:12 vladislav-sharapov

You are right, if I change 127.0.0.1 to 1.2.3.4, the bug does not show and the --rsh option is present even if port is str.

Interesting that it only triggers when local and port is str.

silverwind avatar Dec 16 '22 21:12 silverwind