Tiny (< 9MB) CLI utility to perform health checks everywhere (container, local, etc)
# via docker
$ docker run --rm gregthebunny/go-healthcheck probe '{{ .Assert.HTTPStatusCode .HTTP.Handler "GET" "https://github.com" nil 200 }}'
# ... or from source
$ make build
# check if github.com is up
$ build/bin/healthcheck probe '{{ .Assert.HTTPStatusCode .HTTP.Handler "GET" "https://github.com" nil 200 }}'
INFO [16:47:40] starting probe probe=p0 status=STARTED
INFO [16:47:40] finished probe probe=p0 status=PASS
INFO [16:47:40] 1 of 1 probes passed 👍
EXIT 0
NAME:
healthcheck - HealthCheck Utility
USAGE:
healthcheck [global options] command [command options] [arguments...]
COMMANDS:
probe Performs a HTTP connection check
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--help, -h show help (default: false)
--log-level value Set the log output verbosity (default: "info") [$HC_DEBUG]
--no-fail If set failed checks won't cause the program to exit with an error code (default: false) [$HC_NO_FAIL]
--no-fail-affirmative If set the program won't exit with an error code as long as at least one probe passed (default: false) [$HC_NO_FAIL_AFFIRMATIVE]
--output If set rendered output will be printed to stdout (default: false) [$HC_OUTPUT]
--timeout value Maximum time in seconds after an unfinished probe will fail (default: 30) [$HC_TIMEOUT]
# docker build -t hc-echo-example .
# docker run --name hc-echo-example --rm -p 5678:5678 hc-echo-example -text='my name is earl!'
# open http://localhost:5678
FROM hashicorp/http-echo
COPY --from=gregthebunny/go-healthcheck /bin/healthcheck /bin/healthcheck
ENV PROBE='{{ .Assert.HTTPBodyContains .HTTP.Handler "GET" "http://127.0.0.1:5678" nil "my name is earl!" }}'
HEALTHCHECK --start-period=10s --retries=3 --timeout=10s --interval=10s \
CMD ["/bin/healthcheck", "probe", "$PROBE"]
Now build and run:
$ docker build -t hc-echo-example .
$ docker run --name hc-echo-example --rm -p 5678:5678 hc-echo-example -text='my name is earl!'
docker inspect --format "{{json .State.Health }}" hc-echo-example | jq
{
"Status": "healthy",
"FailingStreak": 0,
"Log": [
{
"Start": "2022-06-30T16:45:01.876566358Z",
"End": "2022-06-30T16:45:01.963092081Z",
"ExitCode": 0,
"Output": "time=\"16:45:01\" level=info msg=\"starting probe\" probe=p0 status=STARTED\ntime=\"16:45:01\" level=info msg=\"finished probe\" probe=p0 status=PASS\ntime=\"16:45:01\" level=info msg=\"1 of 1 probes passed 👍\"\n"
},
{
"Start": "2022-06-30T16:45:11.970180983Z",
"End": "2022-06-30T16:45:12.036572081Z",
"ExitCode": 0,
"Output": "time=\"16:45:12\" level=info msg=\"starting probe\" probe=p0 status=STARTED\ntime=\"16:45:12\" level=info msg=\"finished probe\" probe=p0 status=PASS\ntime=\"16:45:12\" level=info msg=\"1 of 1 probes passed 👍\"\n"
}
]
}
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f73899dc2b6c hc-echo-example "/http-echo '-text=m…" 2 minutes ago Up 2 minutes (healthy) 0.0.0.0:5678->5678/tcp hc-echo-example
# play with env vars
$ MY_NAME=Earl ./healthcheck probe '{{ .Assert.Equal "My name is Earl!" ("My name is $MY_NAME!"|expandenv) }}'
INFO [16:19:52] starting probe probe=p0 status=STARTED
INFO [16:19:52] finished probe probe=p0 status=PASS
INFO [16:19:52] 1 of 1 probes passed 👍
EXIT 0
# run multiple probes
$ MY_NAME=Earl ./healthcheck probe '{{ .Assert.Equal "Me llamo Earl!" ("My name is $MY_NAME!"|expandenv) }}' \
'{{ .Assert.Equal "My name is Earl!" ("My name is $MY_NAME!"|expandenv) }}'
INFO [16:41:53] starting probe probe=p0 status=STARTED
WARNING[16:41:53]
Error: Not equal:
expected: "Me llamo Earl!"
actual : "My name is Earl!"
Diff:
--- Expected
+++ Actual
@@ -1 +1 @@
-Me llamo Earl!
+My name is Earl! probe=p0
WARNING[16:41:53] finished probe probe=p0 status=FAIL
INFO [16:41:53] starting probe probe=p1 status=STARTED
INFO [16:41:53] finished probe probe=p1 status=PASS
ERROR [16:41:53] 1 of 2 probes failed 😭
FAIL
EXIT 1
Probes are basically go-templates (see "https://pkg.go.dev/text/template" to learn how utilize them) where you can perform assertions on static or dynamic values
The renderer comes with the Sprig extension to add some more convenience. See "http://masterminds.github.io/sprig/" for documentation and the sources on Github (https://github.com/Masterminds/sprig)
Here are some examples on how sprig can help you:
export HTTP_PORT=8080 healthcheck probe '{{ .Assert.Equal "http://localhost:8080" ("http://localhost:$HTTP_PORT"|expandenv) }}'
export HTTP_URL=http://localhost:8080 healthcheck probe '{{ .Assert.Equal "http://localhost:8080" ("HTTP_URL"|env) }}'
Most assertions available in the probes are provided by Testify (see https://github.com/stretchr/testify). Have a look at the API Doc to see detailed information about it: https://pkg.go.dev/github.com/stretchr/[email protected]/assert#Assertions
Here are some examples on how you can use assertions in probes:
{{ .Assert.True false }}
{{ .Assert.Equal 200 (.HTTP.Request "GET" "http://localhost:8080").StatusCode }}
{{ .Assert.Regexp "^start"|regexp "its not starting" }}
{{ .Assert.NotRegexp (call .Regexp "^start") "its not starting" }}
{{ .Assert.HTTPStatusCode .HTTP.Handler "GET" "http://google.com" nil }}
{{ .Assert.HTTPError .HTTP.Handler "GET" "http://localhost:8080" nil }}
{{ .Assert.HTTPSuccess .HTTP.Handler "GET" "http://localhost:8080" nil }}
{{ .Assert.HTTPBodyContains .HTTP.Handler "GET" "http://localhost:8080" nil "hello world" }}
{{ .Assert.HTTPBodyNotContains .HTTP.Handler "GET" "http://localhost:8080" nil "hello world" }}
This tool is base on multiple awesome open source libraries shout-outs to:
- https://github.com/stretchr/testify
- https://github.com/Masterminds/sprig
- https://github.com/urfave/cli
MIT License
Copyright (c) 2022 Maximilian Reichel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.