Work with Serverspec alternative tool Goss
Tags: go, testing, linux
Published: 2019-11-08 10:51:47

## What is Goss?

Goss is a YAML based server testing tool written in Go.
It checks statuses of process, ports and else.

{% github https://github.com/aelsabbahy/goss %}

## Differences from Serverspec

As it is Serverspec alternative tool, there are some differences between them.

### Pros of Goss

#### Easier to write as it is YAML
Tests can be defined by a single YAML file, easier to manage and doesn't require much time to learn.

#### Able to create test suite within a second.
Goss provides a command to define a test state automatically.

#### Easy to install
Goss comes with one single binary so no need to think about dependency.

### Pros of Serverspec

#### Executable from remote
Like Ansible or Chef, able to execute from a remote node with SSH

#### More Resources
Goss supports about 20 Resources but Serverspec has twice (as of Mar 28th, 2019)

#### More flexible
Serverspec is more flexible as it allows us to code with Ruby.

## Let's try

CentOS 7.5.1804  on Vagrant.
Goss v0.3.6.

### Install

A script is prepared officially so it cannot be easier to install.
Also, `dgoss` which is a command for Docker container would be installed but I am not going to use it this time.

And please be noted that the script is not recommended for production environment.
Try manual install instead.

```
[vagrant@Vag2] ~
% curl -fsSL https://goss.rocks/install | sudo sh
Downloading https://github.com/aelsabbahy/goss/releases/download/v0.3.6/goss-linux-amd64
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   606    0   606    0     0    808      0 --:--:-- --:--:-- --:--:--   809
100 8324k  100 8324k    0     0   236k      0  0:00:35  0:00:35 --:--:--  240k
Goss v0.3.6 has been installed to /usr/local/bin/goss
goss --version
goss version v0.3.6
Downloading https://raw.githubusercontent.com/aelsabbahy/goss/master/extras/dgoss/dgoss
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  3803  100  3803    0     0   9722      0 --:--:-- --:--:-- --:--:--  9726
dgoss master has been installed to /usr/local/bin/dgoss
[vagrant@Vag2] ~
% which goss
/usr/local/bin/goss
[vagrant@Vag2] ~
%
```

### Create a test suite

As I mentioned earlier, Goss has commands to create a test suite automatically.
goss.yaml will be created by `goss autoadd` or `goss add [resource]`.

In this post, I will work on a host which HAProxy is installed.

```
[vagrant@Vag2] ~/work
% goss autoadd haproxy
Adding Group to './goss.yaml':

haproxy:
  exists: true
  gid: 188


Adding Package to './goss.yaml':

haproxy:
  installed: true
  versions:
  - 1.5.18


Adding Process to './goss.yaml':

haproxy:
  running: true


Adding Service to './goss.yaml':

haproxy:
  enabled: true
  running: true


Adding User to './goss.yaml':

haproxy:
  exists: true
  uid: 188
  gid: 188
  groups:
  - haproxy
  home: /var/lib/haproxy
  shell: /sbin/nologin


[vagrant@Vag2] ~/work
%
```

After `goss autoadd`, the created goss.yaml is here.


```
[vagrant@Vag2] ~/work
% ls -l goss.yaml
-rw-r--r-- 1 vagrant vagrant 347 Mar 23 03:55 goss.yaml
[vagrant@Vag2] ~/work
% cat goss.yaml
package:
  haproxy:
    installed: true
    versions:
    - 1.5.18
service:
  haproxy:
    enabled: true
    running: true
user:
  haproxy:
    exists: true
    uid: 188
    gid: 188
    groups:
    - haproxy
    home: /var/lib/haproxy
    shell: /sbin/nologin
group:
  haproxy:
    exists: true
    gid: 188
process:
  haproxy:
    running: true
[vagrant@Vag2] ~/work
%
```

Just a single command, below test items are created.  
* Test items vary on the target.  

- Installed packages
- is-active, is-enabled of service
- User definition
- Group definition
- Process status

You can use `add [resource]` command to specify each item one by one.

### Test execution

#### Success

Then Let's try testing.
Of course, it is easy to execute.

```
[vagrant@Vag2] ~/work
% goss validate
.............

Total Duration: 0.033s
Count: 13, Failed: 0, Skipped: 0
[vagrant@Vag2] ~/work
%
```

Each dots(...) mean each test.
The speed of the test is incredible.
It takes only 0.033 sec to test 13 items.

#### Fail

So next, we let the test fail.
Stopped the process.

```
[vagrant@Vag2] ~/work
% sudo systemctl stop haproxy
[vagrant@Vag2] ~/work
% sudo systemctl is-active haproxy
inactive
zsh: exit 3     sudo systemctl is-active haproxy
[vagrant@Vag2] ~/work
%
```

Then retry.

```
[vagrant@Vag2] ~/work
% goss validate
..F.........F

Failures/Skipped:

Process: haproxy: running:
Expected
    <bool>: false
to equal
    <bool>: true

Service: haproxy: running:
Expected
    <bool>: false
to equal
    <bool>: true

Total Duration: 0.051s
Count: 13, Failed: 2, Skipped: 0
zsh: exit 1     goss validate
[vagrant@Vag2] ~/work
%
```

As expected, process/service checks failed.

#### Changing format

Goss has several formats to output the result.
It has like JSON, and tap is the most human readable I think.

```
[vagrant@Vag2] ~/work
% goss validate --format tap
1..13
ok 1 - Group: haproxy: exists: matches expectation: [true]
ok 2 - Group: haproxy: gid: matches expectation: [188]
not ok 3 - Process: haproxy: running: doesn't match, expect: [true] found: [false]
ok 4 - User: haproxy: exists: matches expectation: [true]
ok 5 - User: haproxy: uid: matches expectation: [188]
ok 6 - User: haproxy: gid: matches expectation: [188]
ok 7 - User: haproxy: home: matches expectation: ["/var/lib/haproxy"]
ok 8 - User: haproxy: groups: matches expectation: [["haproxy"]]
ok 9 - User: haproxy: shell: matches expectation: ["/sbin/nologin"]
ok 10 - Package: haproxy: installed: matches expectation: [true]
ok 11 - Package: haproxy: version: matches expectation: [["1.5.18"]]
ok 12 - Service: haproxy: enabled: matches expectation: [true]
not ok 13 - Service: haproxy: running: doesn't match, expect: [true] found: [false]
zsh: exit 1     goss validate --format tap
[vagrant@Vag2] ~/work
%
```

#### Check with http

Goss can serve http mode and work as Healthcheck endpoint.

```
[vagrant@Vag2] ~/work
% goss serve &
2019/03/23 04:00:20 Starting to listen on: :8080

[vagrant@Vag2] ~/work
% curl localhost:8080/healthz
2019/03/23 04:00:23 [::1]:48704: requesting health probe
2019/03/23 04:00:23 [::1]:48704: Stale cache, running tests
..F.........F

Failures/Skipped:

Process: haproxy: running:
Expected
    <bool>: false
to equal
    <bool>: true

Service: haproxy: running:
Expected
    <bool>: false
to equal
    <bool>: true

Total Duration: 0.044s
Count: 13, Failed: 2, Skipped: 0
[vagrant@Vag2] ~/work
%
```

## Conclusion

As I tried, Goss is extremely great since it allows us to test within a minute.
In this post, it was only a simple test but it can be applied to production environment with more customize.

I assume Ansible can be a good match with Goss when comes to production use.
Or maybe it can extend monitoring accuracy with Goss healthcheck mode.