Compare commits

..

2 Commits

Author SHA1 Message Date
Ian Fijolek
5141df3878 Do build and test in one image 2019-11-21 15:38:29 -08:00
Ian Fijolek
c770da4d12 Try to cache go modules 2019-11-21 15:36:30 -08:00
13 changed files with 82 additions and 239 deletions
+2 -17
View File
@@ -1,23 +1,8 @@
ARG REPO=library ARG REPO=library
FROM ${REPO}/alpine:3.10 FROM ${REPO}/busybox:latest
RUN mkdir /app WORKDIR /root/
WORKDIR /app/
# Copy minitor in
ARG ARCH=amd64 ARG ARCH=amd64
COPY ./minitor-go ./minitor COPY ./minitor-go ./minitor
# Add common checking tools
RUN apk --no-cache add bash=~5.0 curl=~7.66 jq=~1.6
# Add minitor user for running as non-root
RUN addgroup -S minitor && adduser -S minitor -G minitor
# Copy scripts
COPY ./scripts /app/scripts
RUN chmod -R 755 /app/scripts
# Drop to non-root user
USER minitor
ENTRYPOINT [ "./minitor" ] ENTRYPOINT [ "./minitor" ]
+3 -21
View File
@@ -1,7 +1,7 @@
ARG REPO=library ARG REPO=library
FROM golang:1.12-alpine AS builder FROM golang:1.12-alpine AS builder
RUN apk add --no-cache git=~2 RUN apk add --no-cache git
RUN mkdir /app RUN mkdir /app
WORKDIR /app WORKDIR /app
@@ -16,26 +16,8 @@ ARG VERSION=dev
ENV CGO_ENABLED=0 GOOS=linux GOARCH=${ARCH} ENV CGO_ENABLED=0 GOOS=linux GOARCH=${ARCH}
RUN go build -ldflags "-X main.version=${VERSION}" -a -installsuffix nocgo -o minitor . RUN go build -ldflags "-X main.version=${VERSION}" -a -installsuffix nocgo -o minitor .
FROM ${REPO}/alpine:3.10 FROM ${REPO}/busybox:latest
RUN mkdir /app WORKDIR /root/
WORKDIR /app/
# Copy minitor in
COPY --from=builder /app/minitor . COPY --from=builder /app/minitor .
# Add common checking tools
RUN apk --no-cache add bash=~5.0 curl=~7.66 jq=~1.6
# Add minitor user for running as non-root
RUN addgroup -S minitor && adduser -S minitor -G minitor
# Copy scripts
COPY ./scripts /app/scripts
RUN chmod -R 755 /app/scripts
# Drop to non-root user
USER minitor
ENTRYPOINT [ "./minitor" ] ENTRYPOINT [ "./minitor" ]
# vim: set filetype=dockerfile:
+12 -9
View File
@@ -3,11 +3,10 @@ package main
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"log"
"os/exec" "os/exec"
"text/template" "text/template"
"time" "time"
log "github.com/sirupsen/logrus"
) )
// Alert is a config driven mechanism for sending a notice // Alert is a config driven mechanism for sending a notice
@@ -39,7 +38,9 @@ func (alert Alert) IsValid() bool {
// BuildTemplates compiles command templates for the Alert // BuildTemplates compiles command templates for the Alert
func (alert *Alert) BuildTemplates() error { func (alert *Alert) BuildTemplates() error {
log.Debugf("Building template for alert %s", alert.Name) if LogDebug {
log.Printf("DEBUG: Building template for alert %s", alert.Name)
}
if alert.commandTemplate == nil && alert.Command != nil { if alert.commandTemplate == nil && alert.Command != nil {
alert.commandTemplate = []*template.Template{} alert.commandTemplate = []*template.Template{}
for i, cmdPart := range alert.Command { for i, cmdPart := range alert.Command {
@@ -59,8 +60,8 @@ func (alert *Alert) BuildTemplates() error {
} }
// Send will send an alert notice by executing the command template // Send will send an alert notice by executing the command template
func (alert Alert) Send(notice AlertNotice) (outputStr string, err error) { func (alert Alert) Send(notice AlertNotice) (output_str string, err error) {
log.Infof("Sending alert %s for %s", alert.Name, notice.MonitorName) log.Printf("INFO: Sending alert %s for %s", alert.Name, notice.MonitorName)
var cmd *exec.Cmd var cmd *exec.Cmd
if alert.commandTemplate != nil { if alert.commandTemplate != nil {
command := []string{} command := []string{}
@@ -94,8 +95,10 @@ func (alert Alert) Send(notice AlertNotice) (outputStr string, err error) {
var output []byte var output []byte
output, err = cmd.CombinedOutput() output, err = cmd.CombinedOutput()
outputStr = string(output) output_str = string(output)
log.Debugf("Alert output for: %s\n---\n%s\n---", alert.Name, outputStr) if LogDebug {
log.Printf("DEBUG: Alert output for: %s\n---\n%s\n---", alert.Name, output_str)
return outputStr, err }
return output_str, err
} }
+12 -13
View File
@@ -1,9 +1,8 @@
package main package main
import ( import (
"log"
"testing" "testing"
log "github.com/sirupsen/logrus"
) )
func TestAlertIsValid(t *testing.T) { func TestAlertIsValid(t *testing.T) {
@@ -23,13 +22,13 @@ func TestAlertIsValid(t *testing.T) {
} }
for _, c := range cases { for _, c := range cases {
log.Debugf("Testing case %s", c.name) log.Printf("Testing case %s", c.name)
actual := c.alert.IsValid() actual := c.alert.IsValid()
if actual != c.expected { if actual != c.expected {
t.Errorf("IsValid(%v), expected=%t actual=%t", c.name, c.expected, actual) t.Errorf("IsValid(%v), expected=%t actual=%t", c.name, c.expected, actual)
log.Debugf("Case failed: %s", c.name) log.Printf("Case failed: %s", c.name)
} }
log.Debugf("-----") log.Println("-----")
} }
} }
@@ -72,19 +71,19 @@ func TestAlertSend(t *testing.T) {
} }
for _, c := range cases { for _, c := range cases {
log.Debugf("Testing case %s", c.name) log.Printf("Testing case %s", c.name)
c.alert.BuildTemplates() c.alert.BuildTemplates()
output, err := c.alert.Send(c.notice) output, err := c.alert.Send(c.notice)
hasErr := (err != nil) hasErr := (err != nil)
if output != c.expectedOutput { if output != c.expectedOutput {
t.Errorf("Send(%v output), expected=%v actual=%v", c.name, c.expectedOutput, output) t.Errorf("Send(%v output), expected=%v actual=%v", c.name, c.expectedOutput, output)
log.Debugf("Case failed: %s", c.name) log.Printf("Case failed: %s", c.name)
} }
if hasErr != c.expectErr { if hasErr != c.expectErr {
t.Errorf("Send(%v err), expected=%v actual=%v", c.name, "Err", err) t.Errorf("Send(%v err), expected=%v actual=%v", c.name, "Err", err)
log.Debugf("Case failed: %s", c.name) log.Printf("Case failed: %s", c.name)
} }
log.Debugf("-----") log.Println("-----")
} }
} }
@@ -95,7 +94,7 @@ func TestAlertSendNoTemplates(t *testing.T) {
if err == nil { if err == nil {
t.Errorf("Send(no template), expected=%v actual=%v", "Err", output) t.Errorf("Send(no template), expected=%v actual=%v", "Err", output)
} }
log.Debugf("-----") log.Println("-----")
} }
func TestAlertBuildTemplate(t *testing.T) { func TestAlertBuildTemplate(t *testing.T) {
@@ -110,13 +109,13 @@ func TestAlertBuildTemplate(t *testing.T) {
} }
for _, c := range cases { for _, c := range cases {
log.Debugf("Testing case %s", c.name) log.Printf("Testing case %s", c.name)
err := c.alert.BuildTemplates() err := c.alert.BuildTemplates()
hasErr := (err != nil) hasErr := (err != nil)
if hasErr != c.expectErr { if hasErr != c.expectErr {
t.Errorf("IsValid(%v), expected=%t actual=%t", c.name, c.expectErr, err) t.Errorf("IsValid(%v), expected=%t actual=%t", c.name, c.expectErr, err)
log.Debugf("Case failed: %s", c.name) log.Printf("Case failed: %s", c.name)
} }
log.Debugf("-----") log.Println("-----")
} }
} }
+10 -8
View File
@@ -3,9 +3,9 @@ package main
import ( import (
"errors" "errors"
"io/ioutil" "io/ioutil"
"log"
"os" "os"
log "github.com/sirupsen/logrus"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )
@@ -22,20 +22,20 @@ func (config Config) IsValid() (isValid bool) {
// Validate monitors // Validate monitors
if config.Monitors == nil || len(config.Monitors) == 0 { if config.Monitors == nil || len(config.Monitors) == 0 {
log.Errorf("Invalid monitor configuration: Must provide at least one monitor") log.Printf("ERROR: Invalid monitor configuration: Must provide at least one monitor")
isValid = false isValid = false
} }
for _, monitor := range config.Monitors { for _, monitor := range config.Monitors {
if !monitor.IsValid() { if !monitor.IsValid() {
log.Errorf("Invalid monitor configuration: %s", monitor.Name) log.Printf("ERROR: Invalid monitor configuration: %s", monitor.Name)
isValid = false isValid = false
} }
// Check that all Monitor alerts actually exist // Check that all Monitor alerts actually exist
for _, isUp := range []bool{true, false} { for _, isUp := range []bool{true, false} {
for _, alertName := range monitor.GetAlertNames(isUp) { for _, alertName := range monitor.GetAlertNames(isUp) {
if _, ok := config.Alerts[alertName]; !ok { if _, ok := config.Alerts[alertName]; !ok {
log.Errorf( log.Printf(
"Invalid monitor configuration: %s. Unknown alert %s", "ERROR: Invalid monitor configuration: %s. Unknown alert %s",
monitor.Name, alertName, monitor.Name, alertName,
) )
isValid = false isValid = false
@@ -46,12 +46,12 @@ func (config Config) IsValid() (isValid bool) {
// Validate alerts // Validate alerts
if config.Alerts == nil || len(config.Alerts) == 0 { if config.Alerts == nil || len(config.Alerts) == 0 {
log.Errorf("Invalid alert configuration: Must provide at least one alert") log.Printf("ERROR: Invalid alert configuration: Must provide at least one alert")
isValid = false isValid = false
} }
for _, alert := range config.Alerts { for _, alert := range config.Alerts {
if !alert.IsValid() { if !alert.IsValid() {
log.Errorf("Invalid alert configuration: %s", alert.Name) log.Printf("ERROR: Invalid alert configuration: %s", alert.Name)
isValid = false isValid = false
} }
} }
@@ -85,7 +85,9 @@ func LoadConfig(filePath string) (config Config, err error) {
return return
} }
log.Debugf("Config values:\n%v\n", config) if LogDebug {
log.Printf("DEBUG: Config values:\n%v\n", config)
}
if !config.IsValid() { if !config.IsValid() {
err = errors.New("Invalid configuration") err = errors.New("Invalid configuration")
-1
View File
@@ -4,6 +4,5 @@ go 1.12
require ( require (
github.com/prometheus/client_golang v1.2.1 github.com/prometheus/client_golang v1.2.1
github.com/sirupsen/logrus v1.4.2
gopkg.in/yaml.v2 v2.2.4 gopkg.in/yaml.v2 v2.2.4
) )
-2
View File
@@ -53,7 +53,6 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT
github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -69,7 +68,6 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+8 -9
View File
@@ -3,12 +3,14 @@ package main
import ( import (
"flag" "flag"
"fmt" "fmt"
"log"
"time" "time"
log "github.com/sirupsen/logrus"
) )
var ( var (
// LogDebug will control whether debug messsages should be logged
LogDebug = false
// ExportMetrics will track whether or not we want to export metrics to prometheus // ExportMetrics will track whether or not we want to export metrics to prometheus
ExportMetrics = false ExportMetrics = false
// MetricsPort is the port to expose metrics on // MetricsPort is the port to expose metrics on
@@ -33,7 +35,9 @@ func checkMonitors(config *Config) error {
// Should probably consider refactoring everything below here // Should probably consider refactoring everything below here
if alertNotice != nil { if alertNotice != nil {
log.Debugf("Recieved an alert notice from %s", alertNotice.MonitorName) if LogDebug {
log.Printf("DEBUG: Recieved an alert notice from %s", alertNotice.MonitorName)
}
alertNames := monitor.GetAlertNames(alertNotice.IsUp) alertNames := monitor.GetAlertNames(alertNotice.IsUp)
if alertNames == nil { if alertNames == nil {
// This should only happen for a recovery alert. AlertDown is validated not empty // This should only happen for a recovery alert. AlertDown is validated not empty
@@ -77,16 +81,11 @@ func checkMonitors(config *Config) error {
func main() { func main() {
// Get debug flag // Get debug flag
var debug = flag.Bool("debug", false, "Enables debug logs (default: false)") flag.BoolVar(&LogDebug, "debug", false, "Enables debug logs (default: false)")
flag.BoolVar(&ExportMetrics, "metrics", false, "Enables prometheus metrics exporting (default: false)") flag.BoolVar(&ExportMetrics, "metrics", false, "Enables prometheus metrics exporting (default: false)")
var showVersion = flag.Bool("version", false, "Display the version of minitor and exit") var showVersion = flag.Bool("version", false, "Display the version of minitor and exit")
flag.Parse() flag.Parse()
// Set debug if flag is set
if *debug {
log.SetLevel(log.DebugLevel)
}
// Print version if flag is provided // Print version if flag is provided
if *showVersion { if *showVersion {
log.Println("Minitor version:", version) log.Println("Minitor version:", version)
+19 -14
View File
@@ -1,11 +1,10 @@
package main package main
import ( import (
"log"
"math" "math"
"os/exec" "os/exec"
"time" "time"
log "github.com/sirupsen/logrus"
) )
// Monitor represents a particular periodic check of a command // Monitor represents a particular periodic check of a command
@@ -71,18 +70,20 @@ func (monitor *Monitor) Check() (bool, *AlertNotice) {
alertNotice = monitor.failure() alertNotice = monitor.failure()
} }
log.Debugf("Command output: %s", monitor.lastOutput) if LogDebug {
log.Printf("DEBUG: Command output: %s", monitor.lastOutput)
}
if err != nil { if err != nil {
log.Debugf("Command result: %v", err) if LogDebug {
log.Printf("DEBUG: Command result: %v", err)
}
} }
log.WithFields(log.Fields{ log.Printf(
"monitor": monitor.Name, "INFO: %s success=%t, alert=%t",
"success": isSuccess,
"alert": alertNotice != nil,
}).Infof(
"%s checked",
monitor.Name, monitor.Name,
isSuccess,
alertNotice != nil,
) )
return isSuccess, alertNotice return isSuccess, alertNotice
@@ -108,13 +109,15 @@ func (monitor *Monitor) failure() (notice *AlertNotice) {
monitor.failureCount++ monitor.failureCount++
// If we haven't hit the minimum failures, we can exit // If we haven't hit the minimum failures, we can exit
if monitor.failureCount < monitor.getAlertAfter() { if monitor.failureCount < monitor.getAlertAfter() {
log.Debugf( if LogDebug {
"%s failed but did not hit minimum failures. "+ log.Printf(
"DEBUG: %s failed but did not hit minimum failures. "+
"Count: %v alert after: %v", "Count: %v alert after: %v",
monitor.Name, monitor.Name,
monitor.failureCount, monitor.failureCount,
monitor.getAlertAfter(), monitor.getAlertAfter(),
) )
}
return return
} }
@@ -152,17 +155,19 @@ func (monitor Monitor) getAlertAfter() int16 {
// Zero is one! // Zero is one!
if monitor.AlertAfter == 0 { if monitor.AlertAfter == 0 {
return 1 return 1
} } else {
return monitor.AlertAfter return monitor.AlertAfter
} }
}
// GetAlertNames gives a list of alert names for a given monitor status // GetAlertNames gives a list of alert names for a given monitor status
func (monitor Monitor) GetAlertNames(up bool) []string { func (monitor Monitor) GetAlertNames(up bool) []string {
if up { if up {
return monitor.AlertUp return monitor.AlertUp
} } else {
return monitor.AlertDown return monitor.AlertDown
} }
}
func (monitor Monitor) createAlertNotice(isUp bool) *AlertNotice { func (monitor Monitor) createAlertNotice(isUp bool) *AlertNotice {
// TODO: Maybe add something about recovery status here // TODO: Maybe add something about recovery status here
+9 -21
View File
@@ -1,41 +1,29 @@
--- check_interval: 30
check_interval: 5
monitors: monitors:
- name: Fake Website - name: My Website
command: [ 'curl', '-s', '-o', '/dev/null', 'https://minitor.mon' ] command: [ 'curl', '-s', '-o', '/dev/null', 'https://minitor.mon' ]
alert_down: [log_down, mailgun_down, sms_down] alert_down: [ log, mailgun_down, sms_down ]
alert_up: [log_up, email_up] alert_up: [ log, email_up ]
check_interval: 10 # Must be at minimum the global `check_interval` check_interval: 30 # Must be at minimum the global `check_interval`
alert_after: 3 alert_after: 3
alert_every: -1 # Defaults to -1 for exponential backoff. 0 to disable repeating alert_every: -1 # Defaults to -1 for exponential backoff. 0 to disable repeating
- name: Real Website
command: ['curl', '-s', '-o', '/dev/null', 'https://google.com']
alert_down: [log_down, mailgun_down, sms_down]
alert_up: [log_up, email_up]
check_interval: 5
alert_after: 3
alert_every: -1
alerts: alerts:
log_down:
command: ["echo", "Minitor failure for {{.MonitorName}}"]
log_up:
command: ["echo", "Minitor recovery for {{.MonitorName}}"]
email_up: email_up:
command: [ sendmail, "me@minitor.mon", "Recovered: {monitor_name}", "We're back!" ] command: [ sendmail, "me@minitor.mon", "Recovered: {monitor_name}", "We're back!" ]
mailgun_down: mailgun_down:
command_shell: > command: >
curl -s -X POST curl -s -X POST
-F subject="Alert! {{.MonitorName}} failed" -F subject="Alert! {monitor_name} failed"
-F from="Minitor <minitor@minitor.mon>" -F from="Minitor <minitor@minitor.mon>"
-F to=me@minitor.mon -F to=me@minitor.mon
-F text="Our monitor failed" -F text="Our monitor failed"
https://api.mailgun.net/v3/minitor.mon/messages https://api.mailgun.net/v3/minitor.mon/messages
-u "api:${MAILGUN_API_KEY}" -u "api:${MAILGUN_API_KEY}"
sms_down: sms_down:
command_shell: > command: >
curl -s -X POST -F "Body=Failure! {{.MonitorName}} has failed" curl -s -X POST -F "Body=Failure! {monitor_name} has failed"
-F "From=${AVAILABLE_NUMBER}" -F "To=${MY_PHONE}" -F "From=${AVAILABLE_NUMBER}" -F "To=${MY_PHONE}"
"https://api.twilio.com/2010-04-01/Accounts/${ACCOUNT_SID}/Messages" "https://api.twilio.com/2010-04-01/Accounts/${ACCOUNT_SID}/Messages"
-u "${ACCOUNT_SID}:${AUTH_TOKEN}" -u "${ACCOUNT_SID}:${AUTH_TOKEN}"
-5
View File
@@ -1,5 +0,0 @@
# Minitor Scripts
A collection of some handy scripts to use with Minitor
These are not included with the Python package, but they are included in the Docker image in `/app/scripts`.
-51
View File
@@ -1,51 +0,0 @@
#! /bin/bash
set -e
#################
# docker_check.sh
#
# Checks the most recent state exit code of a Docker container
#################
# Docker host will default to a socket
# To override, export DOCKER_HOST to a new hostname
DOCKER_HOST="${DOCKER_HOST:=socket}"
container_name="$1"
# Curls Docker either using a socket or URL
function curl_docker {
local path="$1"
if [ "$DOCKER_HOST" == "socket" ]; then
curl --unix-socket /var/run/docker.sock "http://localhost/$path" 2>/dev/null
else
curl "http://${DOCKER_HOST}/$path" 2>/dev/null
fi
}
# Returns caintainer ID for a given container name
function get_container_id {
local container_name="$1"
curl_docker 'containers/json?all=1' \
| jq -r ".[] | {Id, Name: .Names[]} | select(.Name == \"/${container_name}\") | .Id"
}
# Returns container JSON
function inspect_container {
local container_id=$1
curl_docker "containers/$container_id/json"
}
if [ -z "$container_name" ]; then
echo "Usage: $0 container_name"
echo "Will exit with the last status code of continer with provided name"
exit 1
fi
container_id=$(get_container_id $container_name)
if [ -z "$container_id" ]; then
echo "ERROR: Could not find container with name: $container_name"
exit 1
fi
exit_code=$(inspect_container "$container_id" | jq -r .State.ExitCode)
exit "$exit_code"
-61
View File
@@ -1,61 +0,0 @@
#! /bin/bash
set -e
#################
# docker_healthcheck.sh
#
# Returns the results of a Docker Healthcheck for a container
#################
# Docker host will default to a socket
# To override, export DOCKER_HOST to a new hostname
DOCKER_HOST="${DOCKER_HOST:=socket}"
container_name="$1"
# Curls Docker either using a socket or URL
function curl_docker {
local path="$1"
if [ "$DOCKER_HOST" == "socket" ]; then
curl --unix-socket /var/run/docker.sock "http://localhost/$path" 2>/dev/null
else
curl "http://${DOCKER_HOST}/$path" 2>/dev/null
fi
}
# Returns caintainer ID for a given container name
function get_container_id {
local container_name="$1"
curl_docker 'containers/json?all=1' \
| jq -r ".[] | {Id, Name: .Names[]} | select(.Name == \"/${container_name}\") | .Id"
}
# Returns container JSON
function inspect_container {
local container_id="$1"
curl_docker "containers/$container_id/json"
}
if [ -z "$container_name" ]; then
echo "Usage: $0 container_name"
echo "Will return results of healthcheck for continer with provided name"
exit 1
fi
container_id=$(get_container_id "$container_name")
if [ -z "$container_id" ]; then
echo "ERROR: Could not find container with name: $container_name"
exit 1
fi
health=$(inspect_container "$container_id" | jq -r '.State.Health.Status')
case "$health" in
null)
echo "No healthcheck results"
;;
starting|healthy)
echo "Status: '$health'"
;;
*)
echo "Status: '$health'"
exit 1
esac