Return value from Bash to Ansible

3,811 views
Skip to first unread message

zorg...@gmail.com

unread,
Apr 22, 2015, 10:49:05 AM4/22/15
to ansible...@googlegroups.com
Hello,

I'm using Ansible 1.7.2 and I've written a Bash module to use at a very early stage of Linux installation (Python not fully available yet). It works correctly except that the return value is seen as stdout and is not interpreted as a special value (changed, failed, skipped, ok).

my_playbook.yml:
[...]
   
- name: my action
      shell: /path/to/my_action.sh {{ my_arg }}
     
when: my_arg is defined
[...]



my_action.sh:
[...]
echo
'ok: true'
exit 0
[...]



Execution:
[root@my_host] # ansible-playbook -v -l $(hostname -s) -c local /path/to/my_playbook.yml
[...]
TASK
: [my action] *************************************************************
changed
: [my_host] => {"changed": true, "cmd": "/path/to/my_action.sh my_arg", "delta": "0:00:00.255756", "end": "2015-04-22 15:54:57.077314", "rc": 0, "start": "2015-04-22 15:54:56.821558", "stderr": "", "stdout": "ok: true"}
[...]



In the execution, you can read "ok: true" in stdout. I would like to get it instead of "changed": true. I tried many different syntaxes to tell Ansible I had no change in the script, without any success:

echo '{"ok": "true"}'
echo
'{ok=True}'
echo
'ok: True'
echo
'ok=True'
echo
'ok=true'
...


What did I do wrong? Thanks in advance for your explanations.

Brian Coca

unread,
Apr 22, 2015, 10:52:43 AM4/22/15
to ansible...@googlegroups.com
shell/command/raw actions by default are always changed, you want to
use the changed_when clause. The return of ok/changed=true/false only
works for modules written in shell, not for scripts called from shell
module (FYI, there is also script module).


--
Brian Coca

zorg...@gmail.com

unread,
Apr 22, 2015, 11:36:38 AM4/22/15
to ansible...@googlegroups.com
Guy, you saved my day!

You are right, my script is not a module, it is just called by the shell module. Then using the changed_when clause did the job. Here is the code.

my_playbook.yml:
[...]
   
- name: my action
      shell
: /path/to/my_action.sh {{ my_arg }}

     
register: script
      changed_when
: script.rc == "changed"

     
when: my_arg is defined
[...]



my_action.sh:
[...]
echo
"rc=changed"
exit 0
[...]



Execution:
[root@my_host] # ansible-playbook -v -l $(hostname -s) -c local /path/to/my_playbook.yml
[...]
TASK
: [my action] *************************************************************

ok
: [my_host] => {"changed": false, "cmd": "/path/to/my_action.sh 2015-04-05", "delta": "0:00:00.213521", "end": "2015-04-22 17:17:54.159018", "rc": 0, "start": "2015-04-22 17:17:53.945497", "stderr": "", "stdout": "", "stdout_lines": []}

Thank you very much, Brian!

Dag Wieers

unread,
Apr 22, 2015, 11:52:26 AM4/22/15
to ansible...@googlegroups.com
On Wed, 22 Apr 2015, zorg...@gmail.com wrote:

> Guy, you saved my day!
>
> You are right, my script is not a module, it is just called by the *shell*
> module. Then using the *changed_when* clause did the job. Here is the code.
>
> *my_playbook.yml*:
> [...]
> - name: my action
> shell: /path/to/my_action.sh {{ my_arg }}
> register: script
> changed_when: script.rc == "changed"
> when: my_arg is defined
> [...]
>
>
>
> *my_action.sh*:
> [...]
> echo "rc=changed"
> exit 0
> [...]
>
>
>
> *Execution*:
> [root@my_host] # ansible-playbook -v -l $(hostname -s) -c local
> /path/to/my_playbook.yml
> [...]
> TASK: [my action]
> *************************************************************
> ok: [my_host] => {"changed": false, "cmd": "/path/to/my_action.sh
> 2015-04-05", "delta": "0:00:00.213521", "end": "2015-04-22 17:17:54.159018",
> "rc": 0, "start": "2015-04-22 17:17:53.945497", "stderr": "", "stdout": "",
> "stdout_lines": []}
>
> Thank you very much, Brian!

I don't think this is right, script.rc reflects the return code, which is
an integer in the range 0 and 255. In your case this is 0 because you did
a "exit 0". So it can never be "changed".

Why not make your script into an Bash ansible module and have it return
"changed": true ? Here is a simple example of how to achieve this:

The bash module:
----
[dag@moria ansible]$ cat library/my_action
#!/bin/bash

changed=true
cpu_count=2
cpu_type="intel"

cat <<EOF
{
"changed": $changed,
"ansible_facts": {
"cpu_count": $cpu_count,
"cpu_type": "$cpu_type"
}
}
EOF
exit 0
----


The playbook:
----
- hosts: all
gather_facts: no
tasks:
- action: my_action
register: script

- action: debug msg='CPU count is {{ cpu_count }}'
----


The output:
----
[dag@moria ansible]$ ansible-playbook -v -l localhost testmodule.yml

PLAY [all]
********************************************************************

TASK: [my_action]
********************************************************************
changed: [localhost] => {"ansible_facts": {"cpu_count": 2, "cpu_type": "intel"}, "changed": true}

TASK: [debug msg='CPU count is {{ cpu_count }}']
********************************************************************
ok: [localhost] => {
"msg": "CPU count is 2"
}

PLAY RECAP
********************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0
----

Hope this helps...

--
Dag
Reply all
Reply to author
Forward
0 new messages