Permalink
942 lines (760 sloc) 23.5 KB

goss manual

Table of Contents

Usage

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.

global options

-g gossfile

The file to use when reading/writing tests. Use -g - to read from STDIN.

Valid formats:

  • YAML (default)
  • JSON

--vars

The file to read variables from when rendering gossfile templates.

Valid formats:

  • YAML (default)
  • JSON

--package

The package type to check for.

Valid options are:

  • apk
  • deb
  • pacman
  • rpm

commands

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

add, a - Add system resource to test suite

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.

Resource types

  • addr - can verify if a remote address:port is reachable, see addr
  • command - can run a command and validate the exit status and/or output
  • dns - resolves a dns name and validates the addresses
  • file - can validate a file existence, permissions, stats (size, etc) and contents
  • goss - allows you to include the contents of another gossfile
  • group - can validate the existence and values of a group on the system
  • http - can validate the HTTP response code and content of a URI, see http
  • interface - can validate the existence and values (es. the addresses) of a network interface, see interface
  • kernel-param - can validate kernel parameters (sysctl values), see kernel-param
  • mount - can validate the existence and options relative to a mount point
  • package - 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 example 80 or udp:123
  • process - can validate the status of a process
  • service - can validate if a service is running and/or enabled at boot
  • user - can validate the existence and values of a user on the system

Flags

--exclude-attr

Ignore non-required attribute(s) matching the provided glob when adding a new resource, may be specified multiple times.

Example:

$ 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

autoadd, aa - Auto add all matching resources to test suite

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 safety
  • dns
  • http
  • interface
  • kernel-param
  • mount

Example:

$ 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

render, r - Render gossfile after importing all referenced gossfiles

This command allows you to keep your tests separated and render a single, valid, gossfile, by including them with the gossfile directive.

Flags

--debug

This prints the rendered golang template prior to printing the parsed JSON/YAML gossfile.

Example:

$ 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, s - Serve a health endpoint

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

Flags

  • --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

Example:

$ goss serve &
$ curl http://localhost:8080/healthz

# JSON endpoint
$ goss serve --format json &
$ curl localhost:8080/healthz

validate, v - Validate the system

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.

Flags

  • --format, -f (output format)
    • documentation - Verbose test results
    • json - Detailed test result
    • json_oneline - Same as json, but oneliner
    • junit
    • nagios - Nagios/Sensu compatible output /w exit code 2 for failures.
    • rspecish (default) - Similar to rspec output
    • tap
    • 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 to nagios output.
    • verbose - Gives verbose output. Applies to nagios 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)

Example:

$ 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

Important note about goss file format

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.

Available tests

addr

Validates if a remote address:port are accessible.

tcp://ip-address-or-domain-name:80:
  reachable: true
  timeout: 500

command

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

dns

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

file

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

gossfile

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: {}

group

Validates the state of a group

group:
  nfsnobody:
    # required attributes
    exists: true
    # optional attributes
    gid: 65534

http

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

interface

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

kernel-param

Validates kernel param (sysctl) value.

kernel-param:
  kernel.ostype:
    # required attributes
    value: Linux

To see the full list of current values, run sysctl -a.

mount

Validates mount point attributes.

mount:
  /home:
    # required attributes
    exists: true
    # optional attributes
    opts:
    - rw
    - relatime
    source: /dev/mapper/fedora-home
    filesystem: xfs

matching

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

package

Validates the state of a package

package:
  httpd:
    # required attributes
    installed: true
    # optional attributes
    versions:
    - 2.2.15

NOTE: this check uses the --package <format> parameter passed on the command line.

port

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

process

Validates if a process is running.

process:
  chrome:
    # required attributes
    running: true

service

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.

user

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

Patterns

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.

Example

$ 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

Advanced Matchers

Goss supports advanced matchers by converting json input to gomega matchers.

Examples

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

Templates

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.

Examples

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