From 42a4e017c8d41d640aa2adb9f9c087baa0c8b3e1 Mon Sep 17 00:00:00 2001 From: Christian Richter Date: Mon, 11 Apr 2022 16:09:09 +0200 Subject: [PATCH] Add reference implementation for health & readiness endpoint in IDP Signed-off-by: Christian Richter --- idp/pkg/server/debug/server.go | 37 +++++++++++++++++++----------- ocis-pkg/shared/healthchecklist.go | 29 +++++++++++++++++++++++ 2 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 ocis-pkg/shared/healthchecklist.go diff --git a/idp/pkg/server/debug/server.go b/idp/pkg/server/debug/server.go index 9da10444f..fab17857f 100644 --- a/idp/pkg/server/debug/server.go +++ b/idp/pkg/server/debug/server.go @@ -3,9 +3,12 @@ package debug import ( "io" "net/http" + "net/url" "github.com/owncloud/ocis/idp/pkg/config" + "github.com/owncloud/ocis/ocis-pkg/log" "github.com/owncloud/ocis/ocis-pkg/service/debug" + "github.com/owncloud/ocis/ocis-pkg/shared" "github.com/owncloud/ocis/ocis-pkg/version" ) @@ -21,23 +24,30 @@ func Server(opts ...Option) (*http.Server, error) { debug.Token(options.Config.Debug.Token), debug.Pprof(options.Config.Debug.Pprof), debug.Zpages(options.Config.Debug.Zpages), - debug.Health(health(options.Config)), + debug.Health(health(options.Config, options.Logger)), debug.Ready(ready(options.Config)), ), nil } // health implements the health check. -func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) { +func health(cfg *config.Config, l log.Logger) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "text/plain") - w.WriteHeader(http.StatusOK) - - // TODO: check if services are up and running - - _, err := io.WriteString(w, http.StatusText(http.StatusOK)) - // io.WriteString should not fail but if it does we want to know. + targetHost, err := url.Parse(cfg.Ldap.URI) if err != nil { - panic(err) + l.Fatal().Err(err).Str("uri", cfg.Ldap.URI).Msg("invalid LDAP URI") + } + err = shared.RunChecklist(shared.TCPConnect(targetHost.Host)) + retVal := http.StatusOK + if err != nil { + l.Error().Err(err).Msg("Healtcheck failed") + retVal = http.StatusInternalServerError + } + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(retVal) + + _, err = io.WriteString(w, http.StatusText(retVal)) + if err != nil { + l.Fatal().Err(err).Msg("Could not write health check body") } } } @@ -47,9 +57,10 @@ func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain") w.WriteHeader(http.StatusOK) - - // TODO: check if services are up and running - + // if we can call this function, a http(200) is a valid response as + // there is nothing we can check at this point for IDP + // if there is a mishap when initializing, there is a minimal (talking ms or ns window) + // timeframe where this code is callable _, err := io.WriteString(w, http.StatusText(http.StatusOK)) // io.WriteString should not fail but if it does we want to know. if err != nil { diff --git a/ocis-pkg/shared/healthchecklist.go b/ocis-pkg/shared/healthchecklist.go new file mode 100644 index 000000000..ce240d7ed --- /dev/null +++ b/ocis-pkg/shared/healthchecklist.go @@ -0,0 +1,29 @@ +package shared + +import "net" + +// Check is a single health-check +type Check func() error + +// RunChecklist runs all the given checks +func RunChecklist(checks ...Check) error { + for _, c := range checks { + err := c() + if err != nil { + return err + } + } + return nil +} + +// TCPConnect connects to a given tcp endpoint +func TCPConnect(host string) Check { + return func() error { + conn, err := net.Dial("tcp", host) + if err != nil { + return err + } + defer conn.Close() + return nil + } +}