Skip to content

Commit

Permalink
Merge pull request #3152 from RedbackThomson/inactive_workspaces
Browse files Browse the repository at this point in the history
✨ Add inactive annotation to logicalcluster
  • Loading branch information
kcp-ci-bot committed Aug 26, 2024
2 parents 9d45e6d + 4df1bd8 commit d2ffee0
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 0 deletions.
1 change: 1 addition & 0 deletions pkg/server/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,7 @@ func NewConfig(opts kcpserveroptions.CompletedOptions) (*Config, error) {
apiHandler = filters.WithWarningRecorder(apiHandler)

apiHandler = kcpfilters.WithAuditEventClusterAnnotation(apiHandler)
apiHandler = kcpfilters.WithBlockInactiveLogicalClusters(apiHandler, c.KcpSharedInformerFactory.Core().V1alpha1().LogicalClusters())

// Add a mux before the chain, for other handlers with their own handler chain to hook in. For example, when
// the virtual workspace server is running as part of kcp, it registers /services with the mux so it can handle
Expand Down
51 changes: 51 additions & 0 deletions pkg/server/filters/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package filters

import (
"context"
"errors"
"fmt"
"net/http"
"net/url"
Expand All @@ -35,6 +36,9 @@ import (
kaudit "k8s.io/apiserver/pkg/audit"
"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
"k8s.io/apiserver/pkg/endpoints/request"

corev1alpha1 "github.com/kcp-dev/kcp/sdk/apis/core/v1alpha1"
informersv1alpha1 "github.com/kcp-dev/kcp/sdk/client/informers/externalversions/core/v1alpha1"
)

type (
Expand All @@ -44,6 +48,10 @@ type (
const (
workspaceAnnotation = "tenancy.kcp.io/workspace"

// inactiveAnnotation is the annotation denoting a logical cluster should be
// deemed unreachable.
inactiveAnnotation = "internal.kcp.io/inactive"

// clusterKey is the context key for the request namespace.
acceptHeaderContextKey acceptHeaderContextKeyType = iota
)
Expand Down Expand Up @@ -78,6 +86,49 @@ func WithAuditEventClusterAnnotation(handler http.Handler) http.HandlerFunc {
})
}

// WithBlockInactiveLogicalClusters ensures that any requests to logical
// clusters marked inactive are rejected.
func WithBlockInactiveLogicalClusters(handler http.Handler, kcpClusterClient informersv1alpha1.LogicalClusterClusterInformer) http.HandlerFunc {
allowedPathPrefixes := []string{
"/openapi",
"/apis/core.kcp.io/v1alpha1/logicalclusters",
}

return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
_, newURL, _, err := ClusterPathFromAndStrip(req)
if err != nil {
responsewriters.InternalError(w, req, err)
return
}

isException := false
for _, prefix := range allowedPathPrefixes {
if strings.HasPrefix(newURL.String(), prefix) {
isException = true
}
}

cluster := request.ClusterFrom(req.Context())
if cluster != nil && !cluster.Name.Empty() && !isException {
logicalCluster, err := kcpClusterClient.Cluster(cluster.Name).Lister().Get(corev1alpha1.LogicalClusterName)
if err == nil {
if ann, ok := logicalCluster.ObjectMeta.Annotations[inactiveAnnotation]; ok && ann == "true" {
responsewriters.ErrorNegotiated(
apierrors.NewForbidden(corev1alpha1.Resource("logicalclusters"), cluster.Name.String(), errors.New("logical cluster is marked inactive")),
errorCodecs, schema.GroupVersion{}, w, req,
)
return
}
} else if !apierrors.IsNotFound(err) {
responsewriters.InternalError(w, req, err)
return
}
}

handler.ServeHTTP(w, req)
})
}

// WithClusterScope reads a cluster name from the URL path and puts it into the context.
// It also trims "/clusters/" prefix from the URL.
func WithClusterScope(apiHandler http.Handler) http.HandlerFunc {
Expand Down

0 comments on commit d2ffee0

Please sign in to comment.