- Table of Contents
- Usage
- Important note about goss file format
- Available tests
- Patterns
- Advanced Matchers
- Templates
NAME:
goss - Quick and Easy server validation
USAGE:
goss [global options] command [command options] [arguments...]
VERSION:
0.0.0
COMMANDS:
validate, v Validate system
serve, s Serve a health endpoint
render, r render gossfile after imports
autoadd, aa automatically add all matching resource to the test suite
add, a add a resource to the test suite
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--gossfile, -g "./goss.yaml" Goss file to read from / write to [$GOSS_FILE]
--vars value json/yaml file containing variables for template [$GOSS_VARS]
--package Package type to use [rpm, deb, apk, pacman]
--help, -h show help
--generate-bash-completion
--version, -v print the version
Note: Most flags can be set by using environment variables, see --help
for more info.
The file to use when reading/writing tests. Use -g -
to read from STDIN
.
Valid formats:
- YAML (default)
- JSON
The file to read variables from when rendering gossfile templates.
Valid formats:
- YAML (default)
- JSON
The package type to check for.
Valid options are:
apk
deb
pacman
rpm
Commands are the actions goss can run.
- add: add a single test for a resource
- autoadd: automatically add multiple tests for a resource
- render: renders and outputs the gossfile, importing all included gossfiles
- serve: serves the gossfile validation as an HTTP endpoint on a specified address and port, so you can use your gossfile as a health repor for the host
- validate: runs the goss test suite on your server
This will add a test for a resource. Non existent resources will add a test to ensure they do not exist on the system. A sub-command resource type has to be provided when running add
.
addr
- can verify if a remoteaddress:port
is reachable, see addrcommand
- can run a command and validate the exit status and/or outputdns
- resolves a dns name and validates the addressesfile
- can validate a file existence, permissions, stats (size, etc) and contentsgoss
- allows you to include the contents of another gossfilegroup
- can validate the existence and values of a group on the systemhttp
- can validate the HTTP response code and content of a URI, see httpinterface
- can validate the existence and values (es. the addresses) of a network interface, see interfacekernel-param
- can validate kernel parameters (sysctl values), see kernel-parammount
- can validate the existence and options relative to a mount pointpackage
- can validate the status of a package using the package manager specified on the commandline with--package
port
- can validate the status of a local port, for example80
orudp:123
process
- can validate the status of a processservice
- can validate if a service is running and/or enabled at bootuser
- can validate the existence and values of a user on the system
Ignore non-required attribute(s) matching the provided glob when adding a new resource, may be specified multiple times.
$ goss a file /etc/passwd
$ goss a user nobody
$ goss a --exclude-attr home --exclude-attr shell user nobody
$ goss a --exclude-attr '*' user nobody
Automatically adds all existing resources matching the provided argument.
Will automatically add the following matching resources:
file
- only if argument contains/
group
package
port
process
- Also adding any ports it's listening to (if run as root)service
user
Will NOT automatically add:
addr
command
- for safetydns
http
interface
kernel-param
mount
$ goss autoadd sshd
Generates the following goss.yaml
port:
tcp:22:
listening: true
ip:
- 0.0.0.0
tcp6:22:
listening: true
ip:
- '::'
service:
sshd:
enabled: true
running: true
user:
sshd:
exists: true
uid: 74
gid: 74
groups:
- sshd
home: /var/empty/sshd
shell: /sbin/nologin
group:
sshd:
exists: true
gid: 74
process:
sshd:
running: true
This command allows you to keep your tests separated and render a single, valid, gossfile, by including them with the gossfile
directive.
This prints the rendered golang template prior to printing the parsed JSON/YAML gossfile.
$ cat goss_httpd_package.yaml
package:
httpd:
installed: true
versions:
- 2.2.15
$ cat goss_httpd_service.yaml
service:
httpd:
enabled: true
running: true
$ cat goss_nginx_service-NO.yaml
service:
nginx:
enabled: false
running: false
$ cat goss.yaml
gossfile:
goss_httpd_package.yaml: {}
goss_httpd_service.yaml: {}
goss_nginx_service-NO.yaml: {}
$ goss -g goss.yaml render
package:
httpd:
installed: true
versions:
- 2.2.15
service:
httpd:
enabled: true
running: true
nginx:
enabled: false
running: false
serve
exposes the goss test suite as a health endpoint on your server. The end-point will return the stest results in the format requested and an http status of 200 or 503.
serve
will look for a test suite in the same order as validate
--cache <value>
,-c <value>
- Time to cache the results (default: 5s)--endpoint <value>
,-e <value>
- Endpoint to expose (default:/healthz
)--format
,-f
- output format, same as validate--listen-addr [ip]:port
,-l [ip]:port
- Address to listen on (default::8080
)--max-concurrent
- Max number of tests to run concurrently
$ goss serve &
$ curl http://localhost:8080/healthz
# JSON endpoint
$ goss serve --format json &
$ curl localhost:8080/healthz
validate
runs the goss test suite on your server. Prints an rspec-like (by default) output of test results. Exits with status 0 on success, non-0 otherwise.
--format
,-f
(output format)documentation
- Verbose test resultsjson
- Detailed test resultjson_oneline
- Same as json, but onelinerjunit
nagios
- Nagios/Sensu compatible output /w exit code 2 for failures.rspecish
(default) - Similar to rspec outputtap
silent
- No output. Avoids exposing system information (e.g. when serving tests as a healthcheck endpoint).
--format-options
,-o
(output format option)perfdata
- Outputs Nagios "performance data". Applies tonagios
output.verbose
- Gives verbose output. Applies tonagios
output.
--max-concurrent
- Max number of tests to run concurrently--no-color
- Disable color--color
- Force enable color--retry-timeout
,-r
- Retry on failure so long as elapsed + sleep time is less than this (default: 0)--sleep
,-s
- Time to sleep between retries (default: 1s)
$ goss validate --format documentation
File: /etc/hosts: exists: matches expectation: [true]
DNS: localhost: resolvable: matches expectation: [true]
[...]
Total Duration: 0.002s
Count: 10, Failed: 2, Skipped: 0
$ curl -s https://static/or/dynamic/goss.json | goss validate
...F.F
[...]
Total Duration: 0.002s
Count: 6, Failed: 2, Skipped: 0
$ goss render | ssh remote-host 'goss -g - validate'
......
Total Duration: 0.002s
Count: 6, Failed: 0, Skipped: 0
$ goss validate --format nagios -o verbose -o perfdata
GOSS CRITICAL - Count: 76, Failed: 1, Skipped: 0, Duration: 1.009s|total=76 failed=1 skipped=0 duration=1.009s
Fail 1 - DNS: localhost: addrs: doesn't match, expect: [["127.0.0.1","::1"]] found: [["127.0.0.1"]]
$ echo $?
2
It is important to note that both YAML and JSON are formats that describe a nested data structure.
WRONG way to write a goss file
file:
/etc/httpd/conf/httpd.conf:
exists: true
service:
httpd:
enabled: true
running: true
file:
/var/www/html:
filetype: directory
exists: true
If you try to validate this file, it will only run the second file
test:
# goss validate --format documentation
File: /var/www/html: exists: matches expectation: [true]
File: /var/www/html: filetype: matches expectation: ["directory"]
Service: httpd: enabled: matches expectation: [true]
Service: httpd: running: matches expectation: [true]
Total Duration: 0.014s
Count: 8, Failed: 0, Skipped: 0
As you can see, the first file
check has not been run because the second file
entry overwrites the previous one.
You need to make sure all the entries of the same type are under the same declaration.
This is the CORRECT way to write a goss file
file:
/etc/httpd/conf/httpd.conf:
exists: true
/var/www/html:
filetype: directory
exists: true
service:
httpd:
enabled: true
running: true
Running validate with this configuration will correctly check both files:
# goss validate --format documentation
File: /var/www/html: exists: matches expectation: [true]
File: /var/www/html: filetype: matches expectation: ["directory"]
File: /etc/httpd/conf/httpd.conf: exists: matches expectation: [true]
Service: httpd: enabled: matches expectation: [true]
Service: httpd: running: matches expectation: [true]
Total Duration: 0.014s
Count: 10, Failed: 0, Skipped: 0
Please note that using the goss add
and goss autoadd
command will create a valid file, but if you're writing your files by hand you'll save a lot of time by taking this in consideration.
If you want to keep your tests in separate files, the best way to obtain a single, valid, file is to create a main goss file that includes the others with the gossfile directive and then render it.
- addr
- command
- dns
- file
- gossfile
- group
- http
- interface
- kernel-param
- matching
- mount
- package
- port
- process
- service
- user
Validates if a remote address:port
are accessible.
tcp://ip-address-or-domain-name:80:
reachable: true
timeout: 500
Validates the exit-status and output of a command
command:
go version:
# required attributes
exit-status: 0
# optional attributes
stdout:
- go version go1.6 linux/amd64
stderr: []
timeout: 10000 # in milliseconds
stdout
and stderr
can be a string or pattern
Validates that the provided address is resolvable and the addrs it resolves to.
dns:
localhost:
# required attributes
resolvable: true
# optional attributes
server: 8.8.8.8
addrs:
- 127.0.0.1
- ::1
timeout: 500 # in milliseconds
With the server attribute set, it is possible to validate the following types of DNS record:
- A
- AAAA
- CAA
- CNAME
- MX
- NS
- PTR
- SRV
- TXT
To validate specific DNS address types, prepend the hostname with the type and a colon, a few examples:
dns:
# Validate a CNAME record
CNAME:dnstest.github.io:
resolvable: true
server: 8.8.8.8
addrs:
- "github.map.fastly.net."
# Validate a PTR record
PTR:8.8.8.8:
resolvable: true
server: 8.8.8.8
addrs:
- "google-public-dns-a.google.com."
# Validate and SRV record
SRV:_https._tcp.dnstest.io:
resolvable: true
server: 8.8.8.8
addrs:
- "0 5 443 a.dnstest.io."
- "10 10 443 b.dnstest.io."
Please note that if you want localhost
to only resolve 127.0.0.1
you'll need to use Advanced Matchers
dns:
localhost:
resolvable: true
addrs:
consist-of: [127.0.0.1]
timeout: 500 # in milliseconds
Validates the state of a file, directory, or symbolic link
file:
/etc/passwd:
# required attributes
exists: true
# optional attributes
mode: "0644"
size: 2118 # in bytes
owner: root
group: root
filetype: file # file, symlink, directory
contains: [] # Check file content for these patterns
md5: 7c9bb14b3bf178e82c00c2a4398c93cd # md5 checksum of file
# A stronger checksum alternative to md5 (recommended)
sha256: 7f78ce27859049f725936f7b52c6e25d774012947d915e7b394402cfceb70c4c
/etc/alternatives/mta:
# required attributes
exists: true
# optional attributes
filetype: symlink # file, symlink, directory
linked-to: /usr/sbin/sendmail.sendmail
contains
can be a string or a pattern
Import other gossfiles from this one. This is the best way to maintain a large number of tests, and/or create profiles. See render for more examples. Glob patterns can be also be used to specify matching gossfiles.
gossfile:
goss_httpd.yaml: {}
/etc/goss.d/*.yaml: {}
Validates the state of a group
group:
nfsnobody:
# required attributes
exists: true
# optional attributes
gid: 65534
Validates HTTP response status code and content.
http:
https://www.google.com:
# required attributes
status: 200
# optional attributes
allow-insecure: false
no-follow-redirects: false # Setting this to true will NOT follow redirects
timeout: 1000
body: [] # Check http response content for these patterns
username: "" # username for basic auth
password: "" # password for basic auth
cert: /home/example/client.crt # Client certificate file which can be used for cert authentication
key: /home/example/client.key # Client private key file
headers: # Check for http headers
key:
- value
- another value
request-headers: # define headers should be send within the request
key:
- value
Validates network interface values
interface:
eth0:
# required attributes
exists: true
# optional attributes
addrs:
- 172.17.0.2/16
- fe80::42:acff:fe11:2/64
mtu: 1500
Validates kernel param (sysctl) value.
kernel-param:
kernel.ostype:
# required attributes
value: Linux
To see the full list of current values, run sysctl -a
.
Validates mount point attributes.
mount:
/home:
# required attributes
exists: true
# optional attributes
opts:
- rw
- relatime
source: /dev/mapper/fedora-home
filesystem: xfs
Validates specified content against a matcher. Best used with Templates.
With Templates:
Let's say we have a data.json
file that gets generated as part of some testing pipeline:
{
"instance_count": 14,
"failures": 3,
"status": "FAIL"
}
This could then be passed into goss: goss --vars data.json validate
And then validated against:
matching:
check_instance_count: # Make sure there is at least one instance
content: {{ .Vars.instance_count }}
matches:
gt: 0
check_failure_count_from_all_instance: # expect no failures
content: {{ .Vars.failures }}
matches: 0
check_status:
content: {{ .Vars.status }}
matches:
not: FAIL
Without Templates:
matching:
has_substr: # friendly test name
content: some string
matches:
match-regexp: some str
has_2:
content:
- 2
matches:
contain-element: 2
has_foo_bar_and_baz:
content:
foo: bar
baz: bing
matches:
and:
- have-key-with-value:
foo: bar
- have-key: baz
Validates the state of a package
package:
httpd:
# required attributes
installed: true
# optional attributes
package: pacman #set a specific package manager
versions:
- 2.2.15
Validates the state of a local port.
Note: Goss might consider your port to be listening on tcp6
rather than tcp
, try running goss add port ..
to see how goss detects it. (explanation)
port:
# {tcp,tcp6,udp,udp6}:port_num
tcp:22:
# required attributes
listening: true
# optional attributes
ip: # what IP(s) is it listening on
- 0.0.0.0
Validates if a process is running.
process:
chrome:
# required attributes
running: true
Validates the state of a service.
service:
sshd:
# required attributes
enabled: true
running: true
NOTE: this will not automatically check if the process is alive, it will check the status from systemd
/upstart
/init
.
Validates the state of a user
user:
nfsnobody:
# required attributes
exists: true
# optional attributes
uid: 65534
gid: 65534
groups:
- nfsnobody
home: /var/lib/nfs
shell: /sbin/nologin
For the attributes that use patterns (ex. file
, command
output
), each pattern is checked against the attribute string, the type of patterns are:
"string"
- checks if any line contain string."!string"
- inverse of above, checks that no line contains string"\\!string"
- escape sequence, check if any line contains"!string"
"/regex/"
- verifies that line contains regex"!/regex/"
- inverse of above, checks that no line contains regex
NOTE: Pattern attributes do not support Advanced Matchers
NOTE: Regex support is based on golang's regex engine documented here
NOTE: You will need the double backslash (\\
) escape for Regex special entities, for example \\s
for blank spaces.
$ cat /tmp/test.txt
found
!alsofound
$ cat goss.yaml
file:
/tmp/test.txt:
exists: true
contains:
- found
- /fou.d/
- "\\!alsofound"
- "!missing"
- "!/mis.ing/"
$ goss validate
..
Total Duration: 0.001s
Count: 2, Failed: 0
Goss supports advanced matchers by converting json input to gomega matchers.
Validate that user nobody
has a uid
that is less than 500
and that they are only a member of the nobody
group.
user:
nobody:
exists: true
uid:
lt: 500
groups:
consist-of: [nobody]
Matchers can be nested for more complex logic, for example you can ensure that you have 3 kernel versions installed and none of them are 4.1.0
:
package:
kernel:
installed: true
versions:
and:
- have-len: 3
- not:
contain-element: "4.1.0"
For more information see:
- gomega_test.go - For a complete set of supported json -> Gomega mapping
- gomega - Gomega matchers reference
Goss test files can leverage golang's text/template to allow for dynamic or conditional tests.
Available variables:
{{.Env}}
- Containing environment variables{{.Vars}}
- Containing the values defined in --vars file
Available functions beyond text/template built-in functions:
mkSlice "ARG1" "ARG2"
- Retuns a slice of all the arguments. See examples below for usage.getEnv "var" ["default"]
- A more forgiving env var lookup. If key is missing either "" or default (if provided) is returned.readFile "fileName"
- Reads file content into a string, trims whitespace. Useful when a file contains a token.- NOTE: Goss will error out during during the parsing phase if the file does not exist, no tests will be executed.
regexMatch "(some)?reg[eE]xp"
- Tests the piped input against the regular expression argument.
NOTE: gossfiles containing text/template {{}}
controls will no longer work with goss add/autoadd
. One way to get around this is to split your template and static goss files and use gossfile to import.
Using puppetlabs/facter or chef/ohai as external tools to provide vars.
$ goss --vars <(ohai) validate
$ goss --vars <(facter -j) validate
Using mkSlice
to define a loop locally.
file:
{{- range mkSlice "/etc/passwd" "/etc/group"}}
{{.}}:
exists: true
mode: "0644"
owner: root
group: root
filetype: file
{{end}}
Using Env variables and a vars file:
vars.yaml:
centos:
packages:
kernel:
- "4.9.11-centos"
- "4.9.11-centos2"
debian:
packages:
kernel:
- "4.9.11-debian"
- "4.9.11-debian2"
users:
- user1
- user2
goss.yaml:
package:
# Looping over a variables defined in a vars.yaml using $OS environment variable as a lookup key
{{range $name, $vers := index .Vars .Env.OS "packages"}}
{{$name}}:
installed: true
versions:
{{range $vers}}
- {{.}}
{{end}}
{{end}}
# This test is only when the OS environment variable matches the pattern
{{if .Env.OS | regexMatch "[Cc]ent(OS|os)"}}
libselinux:
installed: true
{{end}}
# Loop over users
user:
{{range .Vars.users}}
{{.}}:
exists: true
groups:
- {{.}}
home: /home/{{.}}
shell: /bin/bash
{{end}}
package:
{{if eq .Env.OS "centos"}}
# This test is only when $OS environment variable is set to "centos"
libselinux:
installed: true
{{end}}
Rendered results:
# To validate:
$ OS=centos goss --vars vars.yaml validate
# To render:
$ OS=centos goss --vars vars.yaml render
# To render with debugging enabled:
$ OS=centos goss --vars vars.yaml render --debug