Skip to content

Instantly share code, notes, and snippets.

@bowei
Created April 27, 2022 16:08
Show Gist options
  • Save bowei/9ff54e863fab1ab7439b023c0ad642e8 to your computer and use it in GitHub Desktop.
Save bowei/9ff54e863fab1ab7439b023c0ad642e8 to your computer and use it in GitHub Desktop.
Simple file to HTTP healthcheck proxy
// Serves the resultFile as a response to queries. This is useful for
// assembling a custom healthcheck as a sidecar.
//
// resultFile is of format <status code> SPACE <response text>
//
// You should have a script that does the custom set of healthchecking
// on your apps and write a resulting status file.
//
// Example
//
// #!/bin/bash
// while true; do
// healthy=0
// if curl localhost:9000 1>/dev/null 2>/dev/null; then
// healthy=1
// fi
// # other checks.
// if [[ ${healthy} = "1" ]]; then
// echo "200 ok" > /result
// else
// echo "500 unhealthy" > /result
// fi
// done
package main
import (
"flag"
"fmt"
"log"
"net/http"
"os"
"strconv"
"strings"
)
var f = struct {
bindAddr string
resultFile string
}{
bindAddr: ":8080",
resultFile: "/result",
}
func handle(w http.ResponseWriter, r *http.Request) {
resultText, err := os.ReadFile(f.resultFile)
if err != nil {
log.Fatalf("os.ReadFile(%q) = _, %v", err)
}
result := strings.SplitN(string(resultText), " ", 2)
if len(result) != 2 {
w.WriteHeader(500)
err := fmt.Errorf("Invalid resultsText format (%q)", resultText)
fmt.Fprintf(w, "%v\n", err)
log.Print(err)
return
}
code, err := strconv.Atoi(result[0])
if err != nil {
w.WriteHeader(500)
err := fmt.Errorf("Invalid resultText %q: invalid status code", resultText)
fmt.Fprintf(w, "%v\n", err)
log.Print(err)
return
}
if code < 200 || code >= 600 {
w.WriteHeader(500)
err := fmt.Errorf("Invalid resultText %q: invalid status code value", resultText)
fmt.Fprintf(w, "%v\n", err)
log.Print(err)
return
}
w.WriteHeader(int(code))
w.Write([]byte(result[1]))
}
func main() {
flag.StringVar(&f.bindAddr, "bindAddr", f.bindAddr, "Address to bind healthcheck response from")
flag.StringVar(&f.resultFile, "resultFile", f.resultFile, `Location of the result file. File should be a single line of the format <status code> SPACE <response>; example: "500 server is unhealthy"`)
flag.Parse()
http.HandleFunc("/", handle)
log.Printf("Listening on %q", f.bindAddr)
log.Fatal(http.ListenAndServe(f.bindAddr, nil))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment