From 3c8fbe39b971108c81d41b683caf8c9b45437963 Mon Sep 17 00:00:00 2001 From: zryfish Date: Wed, 29 Jul 2020 21:51:55 +0800 Subject: [PATCH] fix websocket lost query string bug (#2705) Signed-off-by: Jeff --- pkg/apiserver/dispatch/dispatch.go | 9 +++++++++ pkg/apiserver/filters/requestinfo.go | 23 ++++++++++++++++------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/pkg/apiserver/dispatch/dispatch.go b/pkg/apiserver/dispatch/dispatch.go index 8a365eb9f..e764ccdaa 100644 --- a/pkg/apiserver/dispatch/dispatch.go +++ b/pkg/apiserver/dispatch/dispatch.go @@ -20,6 +20,7 @@ import ( "fmt" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/util/httpstream" "k8s.io/apimachinery/pkg/util/net" "k8s.io/apimachinery/pkg/util/proxy" "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters" @@ -159,6 +160,14 @@ func (c *clusterDispatch) Dispatch(w http.ResponseWriter, req *http.Request, han if len(u.Query()["dryRun"]) != 0 { req.URL.RawQuery = strings.Replace(req.URL.RawQuery, "dryRun", "dryrun", 1) } + + // kube-apiserver lost query string when proxy websocket requests, there are several issues opened + // tracking this, like https://github.com/kubernetes/kubernetes/issues/89360. Also there is a promising + // PR aim to fix this, but it's unlikely it will get merged soon. So here we are again. Put raw query + // string in Header and extract it on member cluster. + if httpstream.IsUpgradeRequest(req) && len(req.URL.RawQuery) != 0 { + req.Header.Set("X-KubeSphere-Rawquery", req.URL.RawQuery) + } } else { // everything else goes to ks-apiserver, since our ks-apiserver has the ability to proxy kube-apiserver requests diff --git a/pkg/apiserver/filters/requestinfo.go b/pkg/apiserver/filters/requestinfo.go index a1848b05e..1e2ac9c0e 100644 --- a/pkg/apiserver/filters/requestinfo.go +++ b/pkg/apiserver/filters/requestinfo.go @@ -26,13 +26,6 @@ import ( func WithRequestInfo(handler http.Handler, resolver request.RequestInfoResolver) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - ctx := req.Context() - info, err := resolver.NewRequestInfo(req) - if err != nil { - responsewriters.InternalError(w, req, fmt.Errorf("failed to crate RequestInfo: %v", err)) - return - } - // KubeSphere supports kube-apiserver proxy requests in multicluster mode. But kube-apiserver // stripped all authorization headers. Use custom header to carry token to avoid losing authentication token. // We may need a better way. See issue below. @@ -54,6 +47,22 @@ func WithRequestInfo(handler http.Handler, resolver request.RequestInfoResolver) req.URL.RawQuery = strings.Replace(req.URL.RawQuery, "dryrun", "dryRun", 1) } + // kube-apiserver lost query string when proxy websocket requests, there are several issues opened + // tracking this, like https://github.com/kubernetes/kubernetes/issues/89360. Also there is a promising + // PR aim to fix this, but it's unlikely it will get merged soon. So here we are again. Put raw query + // string in Header and extract it on member cluster. + if rawQuery := req.Header.Get("X-KubeSphere-Rawquery"); len(rawQuery) != 0 && len(req.URL.RawQuery) == 0 { + req.URL.RawQuery = rawQuery + req.Header.Del("X-KubeSphere-Rawquery") + } + + ctx := req.Context() + info, err := resolver.NewRequestInfo(req) + if err != nil { + responsewriters.InternalError(w, req, fmt.Errorf("failed to crate RequestInfo: %v", err)) + return + } + req = req.WithContext(request.WithRequestInfo(ctx, info)) handler.ServeHTTP(w, req) })