How to unit test infrastructure using goss infrastructure validator
Goss is a cool tool for verifying the current state of certain aspects of a machine, like determine whether files exist or not, if specific services run and so on.
It is simple to use and configure, and offers a general overview of the system quickly, which might speed up issue resolution times.
The only thing needed for goss to run is the Goss binary somewhere in your $PATH and at least a goss.yaml
file (called a gossfile) containing the desired running state configuration.
An sample configuration can be found at the goss repo quickstart section.
However, the standard approach is not necessarily the optimal, especially if we are dealing with machines with a multitude of services, ports and/or files to be checked.
My approach of goss-validating is to decouple gossfiles by service. So, for example, apache checks go into goss_apache.yml
, haproxy’s at goss_haproxy.yml
etc.
This structure increases maintainability, so that we can run plenty of infra checks without having to manage a huge configuration monolith.
How to follow my approach
It’s easy, Ansible. Using Ansible (and especially group/host variables) is probably the best way we can take advantage of goss’ capabilities.
I prefer to include a separate tasks/goss_validation.yml
task for generating the service-specific checks on a globally accessible directory (like /etc/goss.d
).
A service gossfile contains checks only for a specific service:
user:
{{ nginx.user }}:
exists: true
group:
{{ nginx.group }}:
exists: true
service:
nginx:
enabled: true
running: true
file:
{% for conf in nginx.config.files %}
{{ conf.dest }}:
exists: true
owner: {{ conf.owner }}
group: {{ conf.group }}
{% endfor %}
port:
{% for port in nginx.ports %}
tcp:{{ port }}:
listening: true
{% endfor %}%
A user can then run tasks by service, or just run goss validate
on their home directory, where we have already deployed a gossfile containing the directory of the entirety of checks.
In the goss role, a simple task for the user’s home gossfile:
- name: Deploy validation file on each user's home
copy:
src: 'files/goss.yaml'
dest: "{{ item.home }}/goss.yaml"
loop: "{{ users }}"
The file contains only the directive to load all tests:
gossfile:
/etc/goss.d/*: {}
To be continued…