Skip to content

Commit e734ff2

Browse files
authored
Merge pull request #3537 from ntnn/kcp2811
Fix `Cluster` kind and multiple `/clusters/` in URLs
2 parents a3f627f + a5bd98d commit e734ff2

File tree

7 files changed

+338
-73
lines changed

7 files changed

+338
-73
lines changed

pkg/server/config.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ import (
6969
"github.com/kcp-dev/kcp/pkg/server/openapiv3"
7070
kcpserveroptions "github.com/kcp-dev/kcp/pkg/server/options"
7171
"github.com/kcp-dev/kcp/pkg/server/options/batteries"
72-
"github.com/kcp-dev/kcp/pkg/server/requestinfo"
7372
apisv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"
7473
kcpclientset "github.com/kcp-dev/kcp/sdk/client/clientset/versioned/cluster"
7574
kcpinformers "github.com/kcp-dev/kcp/sdk/client/informers/externalversions"
@@ -406,9 +405,6 @@ func NewConfig(ctx context.Context, opts kcpserveroptions.CompletedOptions) (*Co
406405
virtualWorkspaceServerProxyTransport = transport
407406
}
408407

409-
// Make sure to set our RequestInfoResolver that is capable of populating a RequestInfo even for /services/... URLs.
410-
c.GenericConfig.RequestInfoResolver = requestinfo.NewKCPRequestInfoResolver()
411-
412408
// Prepare an authentication index to be used later by a middleware. We start it early
413409
// because it can potentially fail and the BuildHandlerChainFunc() has no way to return
414410
// an error.
@@ -424,7 +420,6 @@ func NewConfig(ctx context.Context, opts kcpserveroptions.CompletedOptions) (*Co
424420

425421
authIndex = authIndexState
426422
}
427-
428423
// preHandlerChainMux is called before the actual handler chain. Note that BuildHandlerChainFunc below
429424
// is called multiple times, but only one of the handler chain will actually be used. Hence, we wrap it
430425
// to give handlers below one mux.Handle func to call.
@@ -516,7 +511,7 @@ func NewConfig(ctx context.Context, opts kcpserveroptions.CompletedOptions) (*Co
516511
// that path itself, instead of the rest of the handler chain above handling it.
517512
mux := http.NewServeMux()
518513
mux.Handle("/", apiHandler)
519-
*c.preHandlerChainMux = append(*c.preHandlerChainMux, mux)
514+
*c.preHandlerChainMux = []*http.ServeMux{mux}
520515
apiHandler = mux
521516

522517
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)