Writing ansible module in shell/bash script

Hi,
I am not sure whether there is any document on writing BASH/SH module in ansible, but I did found a few example. But I would like to know what is return value for JSON as indicated in this post here https://groups.google.com/forum/?fromgroups=&pli=1#!searchin/ansible-project/shell$20script$20module/ansible-project/pb6_YyZWJs0/l-KZKNjs_t4J. Also, is there some function header like the initscript “functions” that I can reuse for the BASH/SH module?

I understand writing the module in Python and using Python > 2.6 is the best way forward, but I have a lot of older Linux/Unix servers and have restriction on installing any new packages on them. In addition, the environment also have a few network devices that only support SSH and basic shell. I had been using the “raw” module, but I would like to write/reuse some of my current shell script (in BASH), and convert them into ansible module. Is that possible?

Thank you.
Regards,
SHTan

Hi SHTan,

Here's a version of my site_facts module, written in plain bash:
https://gist.github.com/4324790

To help with more fancy JSON operations in bash, the most impressive
thing I've found is this:
https://github.com/kristopolous/TickTick
However, it does some kind of on-the-fly rewriting of the script as it
is run, so you need to use it from a script file. It won't work in an
interactive shell, and it might not work for Ansible.

Cheers,
Chris

I am not sure whether there is any document on writing BASH/SH module in
ansible, but I did found a few example. But I would like to know what is
return value for JSON

You should be able to get by, either by printing JSON to stdout, or
doing something like this:

----8<-------8<-------8<-------8<-------8<-------8<-------8<---
#!/bin/sh

# do something clever

echo "ok=true changed=true name='John Doe'"
----8<-------8<-------8<-------8<-------8<-------8<-------8<---

ansible server -m jp1
server | success >> {
    "changed": true,
    "name": "John Doe",
    "ok": true
}

Also, is there some function header like the initscript "functions" that I
can reuse for the BASH/SH module?

I don't think that exists.

        -JP

I can confirm that is a viable option. Send me a line if you want to talk more about it.

-andreas

Hi JP,
Yes, I know about these few variables from your sample shell script module :slight_smile:
But I am actually looking for a complete list of JSON returned variable, and the meaning of them.

Thank you.

Hi Andreas,
Thanks. I had used the sample shell script module from JP to do some testing and experiment, and I would like to findout whether there is something documented on the JSON variables which I can use to “echo” or “print” from the shell script module.

I got a number of shell scripts, which I usually use to update the remote hosts via ssh, and I am trying to make them ansible-module so that it can be reuse and I can also contribute back to the project.

Thank you.

Ser Heang Tan wrote:

Hi JP,
Yes, I know about these few variables from your sample shell script module
:slight_smile:
But I am actually looking for a complete list of JSON returned variable,
and the meaning of them.

You can return whatever data you want. There are really very few that have
any special meaning, everything else is up to the module to define and the
user to use. The special ones are:

- failed=True, indicating that the action failed
- skipped=True, indicating a pre-condition for running the task was already
  met
- changed=True/False, indicating the task changed/didn't change something,
  used to trigger notifiers and coloring of the output.
- ansible_facts=<dict>, containing custom facts that will be usable as
  variables in following tasks
- stdout=<str>, containing text output. Will be split into lines that can be
  used if register'd
- msg, used for e.g. failure messages

Daniel

Thanks Daniel. With that info, it help me to better understand the possible output/return that my script should do as ansible-module.

Thank you.

An additional tip -- If you want to read the arguments to a module,
they are in key=value format, and can be read by parsing the file
given as the first argument ($1) to the module script

Also also -- there is no reason to return changed if nothing has
changed, or failed if nothing has failed, ansible assumes the value of
these variables is no unless otherwise specified.

the JSON here document is a pretty good idea for bash.

Python modules have a slight leg up in they can use the common core
(and are faster, due to some clever tricks), but things like Ruby and
Perl can at least use available JSON libraries to help them along.
The arguments are still key=value though, and not JSON, as they are
passed from the playbook or CLI across relatively raw.

* Michael DeHaan <michael.dehaan at gmail.com> [2012/12/18 20:37]:

An additional tip -- If you want to read the arguments to a
module, they are in key=value format, and can be read by parsing
the file given as the first argument ($1) to the module script

Actually, you don't even need to parse the args; the key=value
format they use is valid sh variable syntax. All you need to do is
source $1, and the variables become available in your env.

Sweet! Killer feature I didn't even plan for :slight_smile:

  • Michael DeHaan <michael.dehaan at gmail.com> [2012/12/18 20:37]:

An additional tip – If you want to read the arguments to a
module, they are in key=value format, and can be read by parsing
the file given as the first argument ($1) to the module script

Actually, you don’t even need to parse the args; the key=value
format they use is valid sh variable syntax. All you need to do is
source $1, and the variables become available in your env.

Sweet! Killer feature I didn’t even plan for :slight_smile:

Sorry if I jump into this old discussion, but I’m a new user and I am as well starting to develop some ansible modules, so I would like to contribute.

I’ve noticed that the module acts a bit differently if you call it from ansible or from ansible-playbook: in the first case the module script is called with all the arguments on the command line, while in the latter it’s called with just one argument which is a file containing the module arguments.

In my module script I’ve therefore added the following at the beginning:

[ -f $1 ] && source $1 || eval $*

in order to make it work with both ansible and ansible-playbook.

Moreover, I usually use the following syntax to print json structures:

cat <<EOF
{
“failed”: false,
“changed”: true,
“foo”: “bar”
}
EOF

which is, IMHO, quite handy.

I still have a few question though:

  • does ansible gives a special meaning to the exit status of the script? If I exit with 0 or 1 is it the same for ansible as long as the output is json-ized and meaningful?
  • is the standard error ignored by ansible?
  • does ansible set any environment variable the module can access, like variables or group names?
  • is there a way to show the module documentation using ansible-doc.

.a.

P.S. I know the preferred way to develop modules is using Python, but sometimes a shell script is a lot easier and faster to write, and since ansible is so wonderful to allow you to do it… :slight_smile:

"I've noticed that the module acts a bit differently if you call it
from `ansible` or from `ansible-playbook`: in the first case the
module script is called with all the arguments on the command line,
while in the latter it's called with just one argument which is a file
containing the module arguments."

This actually isn't the case, it is true when you write non-python
modules you get the arguments file.

To answer other questions, modules do not see any variables -- this is
a basically a security feature, only arguments you pass to modules get
sent to modules, there is a principle of 'least data exchange'. (Same
reason we don't have a fileserver).

exit codes are not important, but a script should always return 0 and
returned failed=1 (or True) in the JSON on failure.

Ansible also supports "baby JSON" which is just a list of key=value
pairs, so you don't technically have to output JSON.

non-Python modules won't work with ansible-doc currently.

Hi Folks,

My module, written in bash shell, does exactly what it is supposed to do (set up an snmpd v3 password), and ends with:

echo “changed=true”

but it results in:

xxxxxx.example.com | FAILED >> {
“failed”: true,
“msg”: “changed=true\r\n”,
“parsed”: false
}

This module, rescued from an old (pre 1.0) installation of ansible, used to succeed, so I wonder, what changed, or what I might have done wrong.

This is Ansible 1.8.2-1.el6 from the epel repo, running on centos 6.5.

Any help welcome.

Thanks,

Ed Greenberg
Lake George, NY

I think the simple module output parser got deprecated and dropped in the meantime. Try echoing ‘{changed: true}’

Ed Greenberg greenberg.ed@gmail.com napisał:

I fixed this with: echo -n ‘{“changed”: “true”}’

Note that the quotes around “changed” and “true” were essential.

Thanks all