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

Intro

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_goss/
├── README.md
├── 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 }}"
  roles:
    - syslog
    - hf
    - uf
  gather_facts: no
  tasks:
    - name: save goss files list
      set_fact:
        goss_files : "{{ lookup('fileglob', '../roles/{{splunk_group}}/templates/*.j2', wantlist=True) | sort }}"
    - name: print
      debug:
        msg: 
          - "{{ goss_files }}"

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

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

    - name: Print Goss Results
      debug:
        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

port:
  dns:
    tcp: 7001
    udp: 7101
  dual:
    tcp: 8001
    udp: 8101
  relay:
    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

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

will be transformed into this yaml

port:
  udp:7101:
    listening: true
  tcp:7001:
    listening: true
  udp:8101:
    listening: true
  tcp:8001:
    listening: true
  udp:9101:
    listening: true
  tcp:9001:
    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 https://github.com/ilyaresh/ansible_goss

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.