diff --git a/main.go b/main.go index 8c82df6..fb281e5 100644 --- a/main.go +++ b/main.go @@ -11,11 +11,13 @@ import ( "time" "github.com/open-policy-agent/gatekeeper-external-data-provider/pkg/handler" + "github.com/open-policy-agent/gatekeeper-external-data-provider/pkg/utils" "k8s.io/klog/v2" ) const ( + timeout = 15 * time.Second defaultPort = 8090 certName = "tls.crt" @@ -28,6 +30,8 @@ var ( port int ) +var timeoutError = string(utils.GatekeeperError("operation timed out")) + func init() { klog.InitFlags(nil) flag.StringVar(&certDir, "cert-dir", "", "path to directory containing TLS certificates") @@ -38,12 +42,12 @@ func init() { func main() { mux := http.NewServeMux() - mux.HandleFunc("POST /", handler.Handler) + mux.Handle("POST /", http.TimeoutHandler(handler.Handler(), timeout, timeoutError)) server := &http.Server{ Addr: fmt.Sprintf(":%d", port), Handler: mux, - ReadHeaderTimeout: time.Duration(15) * time.Second, + ReadHeaderTimeout: 15 * time.Second, } config := &tls.Config{ @@ -79,25 +83,3 @@ func main() { os.Exit(1) } } - -// TODO: root cause Content-Length header error -// func processTimeout(h http.HandlerFunc, duration time.Duration) http.HandlerFunc { -// return func(w http.ResponseWriter, r *http.Request) { -// ctx, cancel := context.WithTimeout(r.Context(), duration) -// defer cancel() - -// r = r.WithContext(ctx) - -// processDone := make(chan bool) -// go func() { -// h(w, r) -// processDone <- true -// }() - -// select { -// case <-ctx.Done(): -// utils.SendResponse(nil, "operation timed out", w) -// case <-processDone: -// } -// } -// } diff --git a/pkg/handler/handler.go b/pkg/handler/handler.go index 9011a98..8ae84bc 100644 --- a/pkg/handler/handler.go +++ b/pkg/handler/handler.go @@ -7,6 +7,7 @@ import ( "io" "net/http" "path/filepath" + "runtime/debug" "github.com/docker/attest/pkg/attest" "github.com/docker/attest/pkg/oci" @@ -18,7 +19,17 @@ import ( "k8s.io/klog/v2" ) -func Handler(w http.ResponseWriter, req *http.Request) { +func Handler() http.Handler { + return http.HandlerFunc(handler) +} + +func handler(w http.ResponseWriter, req *http.Request) { + defer func() { + if r := recover(); r != nil { + klog.Error(string(debug.Stack())) + klog.ErrorS(fmt.Errorf("%v", r), "panic occurred") + } + }() // read request body requestBody, err := io.ReadAll(req.Body) diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index b87218d..87fcfa2 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -13,8 +13,7 @@ const ( kind = "ProviderResponse" ) -// sendResponse sends back the response to Gatekeeper. -func SendResponse(results *[]externaldata.Item, systemErr string, w http.ResponseWriter) { +func GatekeeperResponse(results *[]externaldata.Item, systemErr string) []byte { response := externaldata.ProviderResponse{ APIVersion: apiVersion, Kind: kind, @@ -29,16 +28,25 @@ func SendResponse(results *[]externaldata.Item, systemErr string, w http.Respons response.Response.SystemError = systemErr } - klog.InfoS("sending response", "response", response) - body, err := json.Marshal(response) if err != nil { klog.ErrorS(err, "unable to marshal response") panic(err) } + return body +} + +func GatekeeperError(systemErr string) []byte { + return GatekeeperResponse(nil, systemErr) +} + +// sendResponse sends back the response to Gatekeeper. +func SendResponse(results *[]externaldata.Item, systemErr string, w http.ResponseWriter) { + body := GatekeeperResponse(results, systemErr) + klog.InfoS("sending response", "response", string(body)) w.Header().Set("Content-Type", "application/json") - _, err = w.Write(body) + _, err := w.Write(body) if err != nil { klog.ErrorS(err, "unable to write response") return