Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issue in ansible playbook command?

I am trying to execute a command on docker on other machine from my machine. When I execute this command:

- name: Add header
      command: docker exec cli bash -l -c "echo '{"payload":{"header":{"channel_header":{"channel_id":"gll", "type":2}},"data":{"config_update":'$(cat jaguar_update.json)'}}}' | jq . > jaguar_update_in_envelope.json"

through ansible playbook, I am getting the error shown below.

fatal:[  
   command-task
]:FAILED! =>{  
   "changed":true,
   "cmd":[  ],
   "delta":"0:00:00.131115",
   "end":"2019-07-11 17:32:44.651504",
   "msg":"non-zero return code",
   "rc":4,
   "start":"2019-07-11 17:32:44.520389",
   "stderr":"mesg: ttyname   
failed: Inappropriate ioctl for device\nparse error: Invalid numeric   
literal at line 1, column 9",
   "stderr_lines":[  
      "mesg: ttyname failed: 
Inappropriate ioctl for device",
      "parse error: Invalid numeric literal 
at line 1, column 9"
   ],
   "stdout":"",
   "stdout_lines":[  

   ]
}

But if I manually execute command in the docker container, it works fine and I don't get any issue.

EDIT: As suggested i tried with shell module

shell: docker exec cli -it bash -l -c "echo '{"payload":{"header":{"channel_header":{"channel_id":"gll", "type":2}},"data":{"config_update":'$(cat jaguar_update.json)'}}}' | jq . > jaguar_update_in_envelope.json"

But i get below error as

fatal: [command-task]: FAILED! => {"changed": true, "cmd": "docker exec cli -it bash -l -c echo '{\"payload\":{\"header\":{\"channel_header\":{\"channel_id\":\"gll\", \"type\":2}},\"data\":{\"config_update\":'$(cat jaguar_update.json)'}}}' | jq . > jaguar_update_in_envelope.json", "delta": "0:00:00.110341", "end": "2019-07-12 10:21:45.204049", "msg": "non-zero return code", "rc": 4, "start": "2019-07-12 10:21:45.093708", "stderr": "cat: jaguar_update.json: No such file or directory\nparse error: Invalid numeric literal at line 1, column 4", "stderr_lines": ["cat: jaguar_update.json: No such file or directory", "parse error: Invalid numeric literal at line 1, column 4"], "stdout": "", "stdout_lines": []}

All the files 'jaguar_update.json' present in the working directory. I have confirmed the working directory.

Above commands works if i put it in a shell script file then execute the shell script from ansible.

like image 264
TechChain Avatar asked Jul 11 '19 12:07

TechChain


People also ask

How do you troubleshoot Ansible?

Troubleshooting Ansible can be tricky but using a methodical approach combined with the built-in problem-solving tools you can make it far easier on yourself. Confirm the Ansible environment and task flow, then look for proper data types, and finally consider pausing and stepping through each task.

How do you control command failure in Ansible?

Ignoring failed commands By default Ansible stops executing tasks on a host when a task fails on that host. You can use ignore_errors to continue on in spite of the failure. The ignore_errors directive only works when the task is able to run and returns a value of 'failed'.

What is Ansible playbook command?

Ansible Playbooks are lists of tasks that automatically execute against hosts. Groups of hosts form your Ansible inventory. Each module within an Ansible Playbook performs a specific task. Each module contains metadata that determines when and where a task is executed, as well as which user executes it.

How does the Ansible playbook work?

The playbook sets three of the seven values from the command line above: the group (hosts: all), the connection method (connection: ansible.netcommon.network_cli) and the module (in each task). With those values set in the playbook, you can omit them on the command line. The playbook also adds a second task to show the config output.

How do I run ansible in Python?

If you are running Ansible in a virtual environment, you will also need to add the variable ansible_python_interpreter=/path/to/venv/bin/python Create and run your first network Ansible Playbook ¶ If you want to run this command every day, you can save it in a playbook and run it with ansible-playbook instead of ansible .

How do I use Ansible to configure network configuration?

Put the concepts you learned to work with this quick tutorial. Install Ansible, execute a network configuration command manually, execute the same command with Ansible, then create a playbook so you can execute the command any time on multiple network devices.

Can I omit the-k flag in Ansible?

You can omit -k flag. If you are running Ansible in a virtual environment, you will also need to add the variable ansible_python_interpreter=/path/to/venv/bin/python If you want to run this command every day, you can save it in a playbook and run it with ansible-playbook instead of ansible.


Video Answer


2 Answers

As everyone has mentioned this does need you to use shell instead of command. Now you want to simplify this command so it can run first in bash. Which can be done easily using printf

$ printf "%s%s%s" '{"payload":{"header":{"channel_header":{"channel_id":"gll", "type":2}},"data":{"config_update":' $(<jaguar_update.json'}}}' | jq . > jaguar_update_in_envelope.json

$ cat jaguar_update_in_envelope.json
{
  "payload": {
    "header": {
      "channel_header": {
        "channel_id": "gll",
        "type": 2
      }
    },
    "data": {
      "config_update": {
        "name": "tarun"
      }
    }
  }
}

So now our commands runs without issues. Next is to move it with bash -l -c format. So instead using -c which requires us to pass the whole command as one parameter, we use the multiline commands

$ bash -l <<EOF
printf "%s%s%s" '{"payload":{"header":{"channel_header":{"channel_id":"gll", "type":2}},"data":{"config_update":' $(<jaguar_update.json) '}}}' | jq . > jaguar_update_in_envelope.json
EOF

But this fails with an error

{"payload":{"header":{"channel_header":{"channel_id":"gll", "type":2}},"data":{"config_update":{bash: line 2: name:: command not found
bash: line 3: syntax error near unexpected token `}'
bash: line 3: `} '}}}' | jq . > jaguar_update_in_envelope.json'

This is because the EOF format will treat each new line as a different command. So we need to replace all new line characters

bash -l <<EOF
printf "%s%s%s" '{"payload":{"header":{"channel_header":{"channel_id":"gll", "type":2}},"data":{"config_update":' $(sed -E 's|"|\\"|g' jaguar_update.json | tr -d '\n') '}}}' | jq . > jaguar_update_in_envelope.json
EOF

And now in ansible

- name: a play that runs entirely on the ansible host
  hosts: 127.0.0.1
  connection: local
  tasks:
     - name: Solve the problem
       shell: |
           bash -l <<EOF
                printf "%s%s%s" '{"payload":{"header":{"channel_header":{"channel_id":"gll", "type":2}},"data":{"config_update":' $(sed -E 's|"|\\"|g' jaguar_update.json | tr -d '\n') '}}}' | jq . > jaguar_update_in_envelope.json
           EOF

And the result

$ ansible-playbook test.yml
PLAY [a play that runs entirely on the ansible host] *********************************************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************************************************************************************
ok: [127.0.0.1]

TASK [Solve the problem] *************************************************************************************************************************************************************
changed: [127.0.0.1]

PLAY RECAP ***************************************************************************************************************************************************************************
127.0.0.1                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

$ cat jaguar_update_in_envelope.json
{
  "payload": {
    "header": {
      "channel_header": {
        "channel_id": "gll",
        "type": 2
      }
    },
    "data": {
      "config_update": {
        "name": "tarun"
      }
    }
  }
}
like image 185
Tarun Lalwani Avatar answered Oct 17 '22 05:10

Tarun Lalwani


To avoid any complexity, try as in this question to wrap your command in a script, and call that script (with command or shell)

- name: Add header
      raw: /path/to/script/docker-add-header.sh

And in /path/to/script/docker-add-header.sh:

docker exec cli -it bash -l -c "echo '{"payload":{"header":{"channel_header":{"channel_id":"gll", "type":2}},"data":{"config_update":'$(cat jaguar_update.json)'}}}' | jq . > jaguar_update_in_envelope.json

Try to make the script work first alone (no Ansible).
See (if it is not working, even outside any Ansible call), to escape nested double-quotes:

docker exec cli -it bash -l -c "echo '{\"payload\":{\"header\":...
like image 1
VonC Avatar answered Oct 17 '22 05:10

VonC