Skip to content

Commit 78b219f

Browse files
authored
Merge pull request #3548 from ntnn/cherry-pick-3537
[release-0.28] Fix `Cluster` kind and multiple `/clusters/` in URLs
2 parents 62d5c42 + 0904139 commit 78b219f

File tree

7 files changed

+338
-72
lines changed

7 files changed

+338
-72
lines changed

pkg/server/config.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ import (
6666
"github.com/kcp-dev/kcp/pkg/server/openapiv3"
6767
kcpserveroptions "github.com/kcp-dev/kcp/pkg/server/options"
6868
"github.com/kcp-dev/kcp/pkg/server/options/batteries"
69-
"github.com/kcp-dev/kcp/pkg/server/requestinfo"
7069
apisv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"
7170
kcpclientset "github.com/kcp-dev/kcp/sdk/client/clientset/versioned/cluster"
7271
kcpinformers "github.com/kcp-dev/kcp/sdk/client/informers/externalversions"
@@ -403,9 +402,6 @@ func NewConfig(ctx context.Context, opts kcpserveroptions.CompletedOptions) (*Co
403402
virtualWorkspaceServerProxyTransport = transport
404403
}
405404

406-
// Make sure to set our RequestInfoResolver that is capable of populating a RequestInfo even for /services/... URLs.
407-
c.GenericConfig.RequestInfoResolver = requestinfo.NewKCPRequestInfoResolver()
408-
409405
// preHandlerChainMux is called before the actual handler chain. Note that BuildHandlerChainFunc below
410406
// is called multiple times, but only one of the handler chain will actually be used. Hence, we wrap it
411407
// to give handlers below one mux.Handle func to call.
@@ -479,7 +475,7 @@ func NewConfig(ctx context.Context, opts kcpserveroptions.CompletedOptions) (*Co
479475
// that path itself, instead of the rest of the handler chain above handling it.
480476
mux := http.NewServeMux()
481477
mux.Handle("/", apiHandler)
482-
*c.preHandlerChainMux = append(*c.preHandlerChainMux, mux)
478+
*c.preHandlerChainMux = []*http.ServeMux{mux}
483479
apiHandler = mux
484480

485481
apiHandler = filters.WithAuditInit(apiHandler) // Must run before any audit annotation is made

pkg/server/filters/filters.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121
"fmt"
2222
"net/http"
2323
"net/url"
24-
"regexp"
2524
"strings"
2625

2726
"github.com/munnerz/goautoneg"
@@ -45,21 +44,11 @@ type (
4544
const (
4645
workspaceAnnotation = "tenancy.kcp.io/workspace"
4746

48-
// inactiveAnnotation is the annotation denoting a logical cluster should be
49-
// deemed unreachable.
50-
inactiveAnnotation = "internal.kcp.io/inactive"
51-
5247
// clusterKey is the context key for the request namespace.
5348
acceptHeaderContextKey acceptHeaderContextKeyType = iota
5449
)
5550

5651
var (
57-
// reClusterName is a regular expression for cluster names. It is based on
58-
// modified RFC 1123. It allows for 63 characters for single name and includes
59-
// KCP specific ':' separator for workspace nesting. We are not re-using k8s
60-
// validation regex because its purpose is for single name validation.
61-
reClusterName = regexp.MustCompile(`^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?:)*[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$`)
62-
6352
errorScheme = runtime.NewScheme()
6453
errorCodecs = serializer.NewCodecFactory(errorScheme)
6554
)
@@ -87,6 +76,20 @@ func WithAuditEventClusterAnnotation(handler http.Handler) http.HandlerFunc {
8776
// It also trims "/clusters/" prefix from the URL.
8877
func WithClusterScope(apiHandler http.Handler) http.HandlerFunc {
8978
return func(w http.ResponseWriter, req *http.Request) {
79+
cl, err := request.ValidClusterFrom(req.Context())
80+
if err == nil {
81+
// This is a failsafe - this should not happen.
82+
// If a cluste is already set in the request context it
83+
// should not be present in the URL path.
84+
responsewriters.ErrorNegotiated(
85+
apierrors.NewBadRequest(
86+
fmt.Sprintf("found cluster %q in the request context, when trying to read cluster from URL", cl.Name.String()),
87+
),
88+
errorCodecs, schema.GroupVersion{},
89+
w, req)
90+
return
91+
}
92+
9093
path, newURL, found, err := ClusterPathFromAndStrip(req)
9194
if err != nil {
9295
responsewriters.ErrorNegotiated(

pkg/server/filters/filters_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"fmt"
2121
"os"
2222
"path/filepath"
23+
"regexp"
2324
"runtime"
2425
"strings"
2526
"testing"
@@ -30,6 +31,14 @@ import (
3031
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
3132
)
3233

34+
var (
35+
// reClusterName is a regular expression for cluster names. It is based on
36+
// modified RFC 1123. It allows for 63 characters for single name and includes
37+
// KCP specific ':' separator for workspace nesting. We are not re-using k8s
38+
// validation regex because its purpose is for single name validation.
39+
reClusterName = regexp.MustCompile(`^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?:)*[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$`)
40+
)
41+
3342
func Test_isPartialMetadataHeader(t *testing.T) {
3443
tests := map[string]struct {
3544
accept string

pkg/server/filters/inactivelogicalcluster.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ import (
3030
corev1alpha1informers "github.com/kcp-dev/kcp/sdk/client/informers/externalversions/core/v1alpha1"
3131
)
3232

33+
const (
34+
// InactiveAnnotation is the annotation denoting a logical cluster should be
35+
// deemed unreachable.
36+
InactiveAnnotation = "internal.kcp.io/inactive"
37+
)
38+
3339
// WithBlockInactiveLogicalClusters ensures that any requests to logical
3440
// clusters marked inactive are rejected.
3541
func WithBlockInactiveLogicalClusters(handler http.Handler, kcpClusterClient corev1alpha1informers.LogicalClusterClusterInformer) http.HandlerFunc {
@@ -39,15 +45,9 @@ func WithBlockInactiveLogicalClusters(handler http.Handler, kcpClusterClient cor
3945
}
4046

4147
return func(w http.ResponseWriter, req *http.Request) {
42-
_, newURL, _, err := ClusterPathFromAndStrip(req)
43-
if err != nil {
44-
responsewriters.InternalError(w, req, err)
45-
return
46-
}
47-
4848
isException := false
4949
for _, prefix := range allowedPathPrefixes {
50-
if strings.HasPrefix(newURL.String(), prefix) {
50+
if strings.HasPrefix(req.URL.String(), prefix) {
5151
isException = true
5252
}
5353
}
@@ -56,7 +56,7 @@ func WithBlockInactiveLogicalClusters(handler http.Handler, kcpClusterClient cor
5656
if cluster != nil && !cluster.Name.Empty() && !isException {
5757
logicalCluster, err := kcpClusterClient.Cluster(cluster.Name).Lister().Get(corev1alpha1.LogicalClusterName)
5858
if err == nil {
59-
if ann, ok := logicalCluster.ObjectMeta.Annotations[inactiveAnnotation]; ok && ann == "true" {
59+
if ann, ok := logicalCluster.ObjectMeta.Annotations[InactiveAnnotation]; ok && ann == "true" {
6060
responsewriters.ErrorNegotiated(
6161
apierrors.NewForbidden(corev1alpha1.Resource("logicalclusters"), cluster.Name.String(), errors.New("logical cluster is marked inactive")),
6262
errorCodecs, schema.GroupVersion{}, w, req,

pkg/server/requestinfo/kcp_request_info_resolver.go

Lines changed: 0 additions & 48 deletions
This file was deleted.

0 commit comments

Comments
 (0)