Run long shell command on remote servers using ansible

ansibleansible-playbook

I have a task in which I want to run below command on a shell on remote servers but whenever I run my playbook, it always gives me exception:

  - name: copy files
    shell: "machines=(machineA machineB machineC); for machine in $(shuf -e ${machines[@]}); do ssh -o StrictHostKeyChecking=no david@$machine 'ls -1 /process/snap/{{ folder }}/*' | parallel -j{{ threads }} 'scp -o StrictHostKeyChecking=no david@${machine}:{} /data/files/'; [ $? -eq 0 ] && break; done"

Below is the error: I can't figure out what wrong I am doing here?

"stderr": "/bin/sh: 1: Syntax error: \"(\" unexpected", "stderr_lines": ["/bin/sh: 1: Syntax error: \"(\" unexpected"], "stdout": "", "stdout_lines": []}

I am able to run this command directly on shell on any remote servers but I am having issues while running through ansible.

This is my script that I have converted in one line and using in shell module:

machines=(machineA machineB machineC)
for machine in $(shuf -e ${machines[@]}); do 
    ssh -o StrictHostKeyChecking=no david@$machine 'ls -1 /process/snap/{{ folder }}/*' | parallel -j{{ threads }} 'scp -o StrictHostKeyChecking=no david@${machine}:{} /data/files/'
   [ $? -eq 0 ] && break
done

Update:

I tried like this now and it is giving me different exception.

  - name: copy files
    shell: |
      set -x
      machines=(machineA machineB machineC)
      for machine in $(shuf -e ${machines[@]}); do
          ssh -o StrictHostKeyChecking=no david@$machine 'ls -1 /process/snap/{{ folder }}/*' | parallel -j{{ parallelism }} 'scp -o StrictHostKeyChecking=no david@${machine}:{} /data/files/'
          [ $? -eq 0 ] && break
      done
    args:
      executable: /bin/bash

Full error: (I have shortened it down)

fatal: [some_machine]: FAILED! => {"changed": true, "cmd": "machines=(machineA machineB machineC)\n for machine in $(shuf -e ${machines[@]}); do\n ssh -o StrictHostKeyChecking=no david@$machine 'ls -1 /process/snap/20180422/*' | parallel -j10 'scp -o StrictHostKeyChecking=no david@${machine}:{} /data/files/'\n [ $? -eq 0 ] && break\n done", "delta": "0:00:37.546329", "end": "2018-04-29 23:27:44.003538", "msg": "non-zero return code", "rc": 1, "start": "2018-04-29 23:27:06.457209", "stderr": "ssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known\r\nssh: Could not resolve hostname : Name or service not known", "ssh: Could not resolve hostname : Name or service not known", "ssh: Could not resolve hostname : Name or service not known"], "stdout": "", "stdout_lines": []}

Also I tried this basic thing as well and this passes without any errors so I assume this works then?

  - name: copy files
    shell: |
      set -x
      machines=(machineA machineB machineC)
      for machine in $(shuf -e ${machines[@]}); do
          echo $machine
          [ $? -eq 0 ] && break
      done
    args:
      executable: /bin/bash

I believe it is some problem maybe with my scp statement? I am not sure just guessing?

Best Answer

Well I can't tell what your problem is exactly, but the error indicates that you have a syntax error in your command. Which is almost certainly related to something being escaped or not translated properly as it is executed.

A couple things I have to suggest. First use the yaml syntax to include a block of text which includes line endings.

- name: Run Script
  shell: |
    machines=(machineA machineB machineC)
    for machine in $(shuf -e ${machines[@]}); do
        ssh -o StrictHostKeyChecking=no david@$machine 'ls -1 /process/snap/{{ folder }}/*' |
        parallel -j{{ threads }} 'scp -o StrictHostKeyChecking=no david@${machine}:{} /data/files/'
      [ $? -eq 0 ] && break
    done

I think, that your fragment may have some bashisms. You may need to specify that your script be executed via bash instead of /bin/sh.

- name: Run command that requires bash
  shell: echo 'not a very good example.
  args:
    executable: /bin/bash

You might also want to add a set -x as the first line of your fragment. The more verbose output from the shell should help you see what exactly the error is.

Of course I would also suggest you try to use Ansible modules to do this instead. I suspect maybe the synchronize module combined with the async features.