2020-11-27 15:46:37 -08:00
// package readiness implements a minimal health-checking mechanism for use as k8s readiness probes. It will always
// return a "ready" state after the conditions have been met for the first time - it's not meant for monitoring.
//
// Uses a global singleton registry (similar to the Prometheus client's default behavior).
package readiness
import (
"bytes"
"fmt"
"net/http"
"sync"
)
var (
mu = sync . Mutex { }
registry = map [ string ] bool { }
)
2020-11-29 04:30:18 -08:00
type Component string
2020-11-27 15:46:37 -08:00
// RegisterComponent registers the given component name such that it is required to be ready for the global check to succeed.
2020-11-29 04:30:18 -08:00
func RegisterComponent ( component Component ) {
2020-11-27 15:46:37 -08:00
mu . Lock ( )
2020-11-29 04:30:18 -08:00
if _ , ok := registry [ string ( component ) ] ; ok {
2020-11-27 15:46:37 -08:00
panic ( "component already registered" )
}
2020-11-29 04:30:18 -08:00
registry [ string ( component ) ] = false
2020-11-27 15:46:37 -08:00
mu . Unlock ( )
}
// SetReady sets the given global component state.
2020-11-29 04:30:18 -08:00
func SetReady ( component Component ) {
2020-11-27 15:46:37 -08:00
mu . Lock ( )
2020-11-29 04:30:18 -08:00
if ! registry [ string ( component ) ] {
registry [ string ( component ) ] = true
2020-11-27 15:46:37 -08:00
}
mu . Unlock ( )
}
// Handler returns a net/http handler for the readiness check. It returns 200 OK if all components are ready,
// or 412 Precondition Failed otherwise. For operator convenience, a list of components and their states
// is returned as plain text (not meant for machine consumption!).
func Handler ( w http . ResponseWriter , r * http . Request ) {
ready := true
resp := new ( bytes . Buffer )
_ , err := resp . Write ( [ ] byte ( "[not suitable for monitoring - do not parse]\n\n" ) )
if err != nil {
panic ( err )
}
2021-08-08 01:58:23 -07:00
_ , err = resp . Write ( [ ] byte ( "[these values update AT STARTUP ONLY - see https://github.com/certusone/wormhole/blob/dev.v2/docs/operations.md#readyz]\n\n" ) )
if err != nil {
panic ( err )
}
2020-11-27 15:46:37 -08:00
2021-07-21 11:59:47 -07:00
mu . Lock ( )
2020-11-27 15:46:37 -08:00
for k , v := range registry {
2021-08-30 11:40:38 -07:00
_ , err = fmt . Fprintf ( resp , "%s\t%v\n" , k , v )
2020-11-27 15:46:37 -08:00
if err != nil {
panic ( err )
}
if ! v {
ready = false
}
}
2021-07-21 11:59:47 -07:00
mu . Unlock ( )
2020-11-27 15:46:37 -08:00
if ! ready {
w . WriteHeader ( http . StatusPreconditionFailed )
} else {
w . WriteHeader ( http . StatusOK )
}
_ , _ = resp . WriteTo ( w )
}