Skip to content

Commit a4959e0

Browse files
committed
fix cluster-awareness in sync client
On-behalf-of: @SAP [email protected]
1 parent 9b070ca commit a4959e0

File tree

1 file changed

+68
-0
lines changed
  • internal/controller/syncmanager/lifecycle

1 file changed

+68
-0
lines changed

internal/controller/syncmanager/lifecycle/cluster.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@ import (
2121
"errors"
2222
"fmt"
2323
"net/http"
24+
"regexp"
2425
"strings"
2526

27+
"github.com/kcp-dev/logicalcluster/v3"
2628
"go.uber.org/zap"
2729

2830
"k8s.io/apimachinery/pkg/api/meta"
@@ -32,6 +34,7 @@ import (
3234
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
3335
"sigs.k8s.io/controller-runtime/pkg/cluster"
3436
"sigs.k8s.io/controller-runtime/pkg/kcp"
37+
"sigs.k8s.io/controller-runtime/pkg/kontext"
3538
)
3639

3740
// Cluster is a controller-runtime cluster
@@ -57,11 +60,76 @@ func newWildcardClusterMapperProvider(c *rest.Config, httpClient *http.Client) (
5760
return apiutil.NewDynamicRESTMapper(mapperCfg, httpClient)
5861
}
5962

63+
// clusterAwareRoundTripper is a cluster-aware wrapper around http.RoundTripper
64+
// taking the cluster from the context.
65+
type clusterAwareRoundTripper struct {
66+
delegate http.RoundTripper
67+
}
68+
69+
// newClusterAwareRoundTripper creates a new cluster aware round tripper.
70+
func newClusterAwareRoundTripper(delegate http.RoundTripper) *clusterAwareRoundTripper {
71+
return &clusterAwareRoundTripper{
72+
delegate: delegate,
73+
}
74+
}
75+
76+
func (c *clusterAwareRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
77+
cluster, ok := kontext.ClusterFrom(req.Context())
78+
if ok && !cluster.Empty() {
79+
return clusterRoundTripper{cluster: cluster.Path(), delegate: c.delegate}.RoundTrip(req)
80+
}
81+
return c.delegate.RoundTrip(req)
82+
}
83+
84+
// clusterRoundTripper is static cluster-aware wrapper around http.RoundTripper.
85+
type clusterRoundTripper struct {
86+
cluster logicalcluster.Path
87+
delegate http.RoundTripper
88+
}
89+
90+
func (c clusterRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
91+
if !c.cluster.Empty() {
92+
req = req.Clone(req.Context())
93+
req.URL.Path = generatePath(req.URL.Path, c.cluster)
94+
req.URL.RawPath = generatePath(req.URL.RawPath, c.cluster)
95+
}
96+
return c.delegate.RoundTrip(req)
97+
}
98+
99+
// apiRegex matches any string that has /api/ or /apis/ in it.
100+
var apiRegex = regexp.MustCompile(`(/api/|/apis/)`)
101+
102+
// generatePath formats the request path to target the specified cluster.
103+
func generatePath(originalPath string, clusterPath logicalcluster.Path) string {
104+
// If the originalPath already has cluster.Path() then the path was already modifed and no change needed
105+
if strings.Contains(originalPath, clusterPath.RequestPath()) {
106+
return originalPath
107+
}
108+
// If the originalPath has /api/ or /apis/ in it, it might be anywhere in the path, so we use a regex to find and
109+
// replaces /api/ or /apis/ with $cluster/api/ or $cluster/apis/
110+
if apiRegex.MatchString(originalPath) {
111+
return apiRegex.ReplaceAllString(originalPath, fmt.Sprintf("%s$1", clusterPath.RequestPath()))
112+
}
113+
// Otherwise, we're just prepending /clusters/$name
114+
path := clusterPath.RequestPath()
115+
// if the original path is relative, add a / separator
116+
if len(originalPath) > 0 && originalPath[0] != '/' {
117+
path += "/"
118+
}
119+
// finally append the original path
120+
path += originalPath
121+
return path
122+
}
123+
60124
func NewCluster(address string, baseRestConfig *rest.Config) (*Cluster, error) {
61125
// note that this cluster and all its components are kcp-aware
62126
config := rest.CopyConfig(baseRestConfig)
63127
config.Host = address
64128

129+
config.Wrap(func(rt http.RoundTripper) http.RoundTripper {
130+
return newClusterAwareRoundTripper(rt)
131+
})
132+
65133
clusterObj, err := cluster.New(config, func(o *cluster.Options) {
66134
o.NewCache = kcp.NewClusterAwareCache
67135
o.NewAPIReader = kcp.NewClusterAwareAPIReader

0 commit comments

Comments
 (0)