Skip to content

Instantly share code, notes, and snippets.

@alloydwhitlock
Created December 12, 2018 00:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alloydwhitlock/e617bec734d9fd3e00be37d307d0ffb0 to your computer and use it in GitHub Desktop.
Save alloydwhitlock/e617bec734d9fd3e00be37d307d0ffb0 to your computer and use it in GitHub Desktop.
Consul Health Check
package main
import (
"encoding/json"
"fmt"
"github.com/urfave/cli"
"io/ioutil"
"log"
"net/http"
"os"
"strings"
)
type ServiceHealth struct {
ServiceName string `json:"ServiceName"`
Node string `json:"Node"`
Status string `json:"Status"`
}
var (
consulHealthEndpoint = "/v1/health/checks/"
httpProto = "http://"
instanceCounter int
failedCounter int
isBad = false
)
func main() {
app := cli.NewApp()
app.Name = "Consul Service Health Checker"
app.Description = "Get health status from Consul for named service(s)"
app.Version = "0.0.1"
app.Flags = []cli.Flag{
cli.StringFlag{
Name: "consul, c",
Usage: "Host + port of Consul service (e.g., 'localhost:8500')",
},
cli.BoolFlag{
Name: "secure, s",
Usage: "Use HTTPS instead of HTTP",
},
cli.StringSliceFlag{
Name: "name, n",
Usage: "Name or names of services to check, (e.g., 'apache2')",
},
}
app.Action = func(c *cli.Context) error {
// Set HTTP or HTTPS
if c.Bool("secure") {
httpProto = "https://"
}
if c.String("consul") == "" {
os.Exit(2)
}
// Check Consul host is valid
_, err := http.Get(httpProto + c.String("consul"))
if err != nil {
fmt.Printf("COMMUNICATION ERROR:%v\n", httpProto+c.String("consul"))
os.Exit(2)
}
// Retrieve each service status
for _, serviceName := range c.StringSlice("name") {
// Retrieve Consul health status
res, err := http.Get(httpProto + c.String("consul") + consulHealthEndpoint + serviceName)
if err != nil {
panic(err.Error())
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
panic(err.Error())
}
var data []ServiceHealth
err = json.Unmarshal(body, &data)
if err != nil {
panic(err.Error())
}
// Validate if each instance passing health checks
instanceCounter = 0
failedCounter = 0
for _, instance := range data {
status := string(strings.ToLower(instance.Status))
if status != "passing" {
isBad = true
failedCounter++
}
instanceCounter++
}
healthyInstances := instanceCounter - failedCounter
// Bad service name will return a valid JSON object, but this works for a validation check
if healthyInstances == 0 {
isBad = true
fmt.Printf("NAME:%v:ERROR:BADVALUE\n", strings.ToUpper(serviceName))
}
// Display the total number of healthy, working instances in output
if isBad {
fmt.Printf("NAME:%s:PASS:COUNT:%v:FAIL:%v\n", strings.ToUpper(serviceName), healthyInstances, failedCounter)
} else {
fmt.Printf("NAME:%s:PASS:COUNT:%v:FAIL:0\n", strings.ToUpper(serviceName), instanceCounter)
}
}
if isBad {
fmt.Print("FAILED SERVICE HEALTH CHECK ENCOUNTERED\n")
os.Exit(2)
} else {
}
return nil
}
err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment