Using goss and Ansible templates for System Testing

Here is how we have used goss and Ansible templates to run system tests after building syslog-ng servers


We are using Ansible to deploy Splunk environment(s) at one of our customers’ site. We were looking for a  way to run system tests after the deployment of the splunk environment is complete and stumbled upon goss.  goss is a self contained binary that allows you to run different tests’ type, like

  • is a service running
  • is a port listening
  • does the file/directory exists
  • running any shell command and compare against an expected output
  • a lot more…

Folder structure

├── ansible.cfg
├── files
├── goss_deploy.yml
├── goss_run_test.yml
├── group_vars
│   └── all
│       └── vars.yml
├── inventory
│   ├── dev
│   ├── hosts
│   ├── prd
│   └── sit
├── roles
│   ├── hf
│   │   └── templates
│   │       └── goss_test_00.yml
│   ├── syslog
│   │   └── templates
│   │       ├── goss_test_00.j2
│   │       ├── goss_test_01.j2
│   │       └── goss_test_02.j2
│   └── uf
│       └── templates
│           └── goss_test_00.j2
└── test.yml

Splitting and ordering tests

I had to split goss tests into multiple files since goss doesn’t naturally support the ability to order tests, but rather executes them sequentially in the alphabetical order of the test type, .i.e addr, dns, command, file, etc..

In my case here is how I’ve broken down the tests

  • goss_test_00
    • general service, port and file tests
  • goss_test_01
    • executing a command (to send test syslog packets locally)
  • goss_test_02.
    • file tests that verifies the files were created as a result of the command that were run as part goss_test_01

Then the playbook that runs the test will search for all the goss_test files that are relevant to the current role and will run them in a “numbered” order

One note is that I had to add an empty files folder in the “root” as Ansible will try to search relative to all the files folders inside it’s structure


- name: run goss test on remote
  hosts: "{{ splunk_group }}"
    - syslog
    - hf
    - uf
  gather_facts: no
    - name: save goss files list
        goss_files : "{{ lookup('fileglob', '../roles/{{splunk_group}}/templates/*.j2', wantlist=True) | sort }}"
    - name: print
          - "{{ goss_files }}"

    - name: Copy goss test from template to remote
        src: "{{ item }}"
        dest: /tmp/{{ item | basename | regex_replace('\.j2','.yml') }}
        mode: '0644'
        - "{{ goss_files }}"

    - name: Run goss
      command: /usr/local/bin/goss --gossfile /tmp/"{{ item | basename | regex_replace('\.j2','.yml') }}" validate --format tap
        - "{{ goss_files }}"
      ignore_errors: yes
      become: yes
      register: goss_result

    - name: Print Goss Results
        msg: "{{ item.stdout_lines }}" 
      with_items: "{{ goss_result.results }}"

goss, Ansible and Templates

I have also used the “power” of Ansible variables and Jinja2 (j2) templates to populate the the goss_test.yaml files.

For example I have a variables file that contains all the ports’ information

    tcp: 7001
    udp: 7101
    tcp: 8001
    udp: 8101
    tcp: 9001
    udp: 9101

As you see, there are 6 ports here (for now) and it will be tedious to each time populate the goss_test*.yaml files “manually” not to mentioned that the ports information might change, so instead I i’ve decided to “combine” goss ansible and templates using jinja loops.  This snippet in j2 file

{% for feed in port %}
{% for protocol, portnum in port[feed].iteritems() %}
  {{ protocol }}:{{ portnum }}:
    listening: true
{% endfor %}
{% endfor %}

will be transformed into this yaml

    listening: true
    listening: true
    listening: true
    listening: true
    listening: true
    listening: true


Please excuse me if the Ansible is not written in “proper” way, but it did work for me.

You can find the full solution here

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.