kubeprobes/probes.go

109 lines
2.7 KiB
Go
Raw Permalink Normal View History

2023-07-21 23:12:18 +02:00
package kubeprobes
import (
"errors"
"fmt"
2023-07-21 23:12:18 +02:00
"net/http"
"strings"
2023-07-21 23:12:18 +02:00
)
type kubeprobes struct {
livenessProbes []ProbeFunction
readinessProbes []ProbeFunction
pathLive string
pathReady string
2023-07-21 23:12:18 +02:00
}
// New returns a new instance of a Kubernetes probes with given options.
func New(options ...Option) (Kubeprobes, error) {
2023-07-21 23:12:18 +02:00
kp := &kubeprobes{
livenessProbes: []ProbeFunction{},
readinessProbes: []ProbeFunction{},
pathLive: "/live",
pathReady: "/ready",
2023-07-21 23:12:18 +02:00
}
for _, option := range options {
option.apply(kp)
}
if err := kp.validate(); err != nil {
return nil, err
}
return kp, nil
}
func (kp *kubeprobes) validate() error {
var err error
if kp.pathLive == "" {
err = errors.Join(err, fmt.Errorf("liveness probe path must not be empty"))
}
if kp.pathReady == "" {
err = errors.Join(err, fmt.Errorf("readiness probe path must not be empty"))
}
if !strings.HasPrefix(kp.pathLive, "/") {
err = errors.Join(err, fmt.Errorf("liveness probe path must start with slash (current: %q)", kp.pathLive))
}
if !strings.HasPrefix(kp.pathReady, "/") {
err = errors.Join(err, fmt.Errorf("readiness probe path must start with slash (current: %q)", kp.pathReady))
}
if kp.pathLive == kp.pathReady {
err = errors.Join(err, fmt.Errorf("liveness and readiness probes have the same values (both %q)", kp.pathLive))
2023-07-21 23:12:18 +02:00
}
if len(kp.livenessProbes) == 0 {
err = errors.Join(err, fmt.Errorf("no liveness probes defined"))
}
if len(kp.readinessProbes) == 0 {
err = errors.Join(err, fmt.Errorf("no readiness probes defined"))
}
return err
2023-07-21 23:12:18 +02:00
}
func (kp *kubeprobes) handleLiveness(w http.ResponseWriter, _ *http.Request) {
sq := newStatusQuery(kp.livenessProbes)
if sq.isAllGreen() {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusServiceUnavailable)
2023-07-21 23:12:18 +02:00
}
}
func (kp *kubeprobes) handleReadiness(w http.ResponseWriter, _ *http.Request) {
sq := newStatusQuery(append(kp.livenessProbes, kp.readinessProbes...))
if sq.isAllGreen() {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusServiceUnavailable)
}
}
// LivenessHandler implements Kubeprobes.
func (kp *kubeprobes) LivenessHandler() http.Handler {
return http.HandlerFunc(kp.handleLiveness)
}
// ReadinessHandler implements Kubeprobes.
func (kp *kubeprobes) ReadinessHandler() http.Handler {
return http.HandlerFunc(kp.handleReadiness)
}
// ServeHTTP implements Kubeprobes.
func (kp *kubeprobes) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case kp.pathLive:
kp.handleLiveness(w, r)
case kp.pathReady:
kp.handleReadiness(w, r)
default:
w.WriteHeader(http.StatusNotFound)
2023-07-21 23:12:18 +02:00
}
}