One to read: Testing Ansible roles with Molecule

One to read: “Testing Ansible roles with Molecule”

This is a good brief summary of Molecule – the default testing product for Ansible (it’s now a product that the Ansible project maintains). This post also makes reference to TestInfra which is another project I need to look in to.

TestInfra really is the more interesting piece (although Molecule is interesting too), because it’s how you check exactly what is on a host. Here’s an example snippet of code (from the front page of that site’s documentation):

def test_passwd_file(host):
    passwd = host.file("/etc/passwd")
    assert passwd.contains("root")
    assert passwd.user == "root"
    assert passwd.group == "root"
    assert passwd.mode == 0o644


def test_nginx_is_installed(host):
    nginx = host.package("nginx")
    assert nginx.is_installed
    assert nginx.version.startswith("1.2")


def test_nginx_running_and_enabled(host):
    nginx = host.service("nginx")
    assert nginx.is_running
    assert nginx.is_enabled

See how easily this clearly defines what your server should look like – it’s got a file called /etc/passwd owned by root with specific permissions, and that the file contains the word root in it, likewise there is a package called nginx installed at version 1.2 and also it’s running and enabled… all good stuff, particularly from an infrastructure-as-code perspective. Now, I just need to go away and test this stuff with more diverse backgrounds than just a stock Ubuntu machine :)

One to read: Using HEREDOCs in bash to grep exit code details

One to read: “Using HEREDOCs in bash to grep exit code details”

One of my little gripes is that when you do a bit of noddy automation with bash and you capture the exit code from your app (as you should do always) but you don’t have an easy way of looking up the meaning of that exit code if things go wrong. ’cause you are going to alert/report that non-zero exit code to someone, something right?

Then you start to play with hashes et al. and write something a little more fuller, which is possible but not very nice.  And this is bash, so you should be able to just grep something really.

So, here is my work around…

Take rsync for example. Occasionally you might get a network error and your remote copy fails. Of course, being a good engineer you have captured the non-zero exit code and at least dropped this into the logs, report or an alert. But then you need to look up that code in the manuals.

eg.

$ man rsync

and scroll down through the text to get to the exit codes.

EXIT VALUES
       0      Success

       1      Syntax or usage error

       2      Protocol incompatibility

       3      Errors selecting input/output files, dirs

       4      Requested action not supported: an attempt was made to manipulate 64-bit files on a platform that cannot support them; or an option was specified that is supported by the client and not by the server.

       5      Error starting client-server protocol

       6      Daemon unable to append to log-file

       10     Error in socket I/O
Manual page rsync(1) line 2734/2862 98% (press h for help or q to quit)

This is fine and dandy. Plus there is only a few times where you may even need to do this.

But being as i am, this is not good enough for me.  The exit codes are there, why can i not look them up programmatically? (a la – grep)

Now we all know you can create hashes and lists (python speak) in bash.  But it’s cumbersome for this and hey, i have the values there and this is bash i should be able to grep them, right?

Well, it seems you can…

$ cat << EODOC | grep "dog"
cat
fish
dog
rabbit
EODOC

returns

$ cat << EODOC | grep "dog" > cat
> fish
> dog
> rabbit
> EODOC
dog

�  woo hoo. ‘simples’ as the meerkats say.

So with a little bit of bash-foo we can just pull the raw text out of any man manual and drop it into a templated function to lookup the exit codes.

Here is an example

get_rsync_error() {
        ERR_NUM=$1

		# xargs hack (bash-foo) to trim white space
		cat << EODOC | grep -P "^\s+$ERR_NUM" | xargs 

EXIT VALUES
       0      Success
       1      Syntax or usage error
       2      Protocol incompatibility
       3      Errors selecting input/output files, dirs
       4      Requested action not supported: an attempt was made to manipulate 64-bit files on a platform that cannot support them; or an option was specified that is supported by the client and not by the server.
       5      Error starting client-server protocol
       6      Daemon unable to append to log-file
       10     Error in socket I/O
       11     Error in file I/O
       12     Error in rsync protocol data stream
       13     Errors with program diagnostics
       14     Error in IPC code
       20     Received SIGUSR1 or SIGINT
       21     Some error returned by waitpid()
       22     Error allocating core memory buffers
       23     Partial transfer due to error
       24     Partial transfer due to vanished source files
       25     The --max-delete limit stopped deletions
       30     Timeout in data send/receive
       35     Timeout waiting for daemon connection
EODOC

}


        time rsync $RSYNC_OPTS --out-format="%t %i %f sent:%b" /backups/ $DEST
        ERR=$?

        echo "" 
        if [ "$ERR" -ne "0" ] ; then
                # look up the error details
                err_text=$(get_rsync_error "$ERR")
                # display the error
                echo "ERROR: [$ERR] = $err_text"
        else
                echo "***Successful"
        fi

How useful this is to anyone else, i’m not sure. But it was an itch i had to scratch. �

Did you also notice that ‘xargs’ will trim a string for you?

$ echo "   leading and trailing whitespace    " | xargs
leading and trailing whitespace

Cool huh?

Anyway, i’ll get back to my Python and Ansible now. But Granddaddy Bash still rocks in my book!

This was automatically posted from my RSS Reader, and may be edited later to add commentary.