ansible-collections / ansible.posix

Ansible Collection for Posix
Other
155 stars 149 forks source link

`synchronize` fails to accept `ansible_port` as string #396

Open silverwind opened 1 year ago

silverwind commented 1 year ago
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
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}
vladislav-sharapov commented 1 year ago

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
silverwind commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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

vladislav-sharapov commented 1 year ago

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

silverwind commented 1 year ago

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.

vladislav-sharapov commented 1 year ago

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

vladislav-sharapov commented 1 year ago

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.

silverwind commented 1 year ago

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.

vladislav-sharapov commented 1 year ago

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.

silverwind commented 1 year ago

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.