Skip to content

Commit 0cf86dd

Browse files
authored
Merge pull request #6773 from chrischdi/pr-topology-cluster-prevent-coownership
🐛 Adjust structuredmerge patch helper options to set correct allow list for Cluster objects to prevent co-ownership
2 parents 317ad64 + 03cd99a commit 0cf86dd

File tree

3 files changed

+55
-17
lines changed

3 files changed

+55
-17
lines changed

internal/controllers/topology/cluster/reconcile_state.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -439,9 +439,7 @@ func (r *Reconciler) reconcileCluster(ctx context.Context, s *scope.Scope) error
439439
ctx, log := tlog.LoggerFrom(ctx).WithObject(s.Desired.Cluster).Into(ctx)
440440

441441
// Check differences between current and desired state, and eventually patch the current object.
442-
patchHelper, err := r.patchHelperFactory(s.Current.Cluster, s.Desired.Cluster, structuredmerge.IgnorePaths{
443-
{"spec", "controlPlaneEndpoint"}, // this is a well known field that is managed by the Cluster controller, topology should not express opinions on it.
444-
})
442+
patchHelper, err := r.patchHelperFactory(s.Current.Cluster, s.Desired.Cluster)
445443
if err != nil {
446444
return errors.Wrapf(err, "failed to create patch helper for %s", tlog.KObj{Obj: s.Current.Cluster})
447445
}

internal/controllers/topology/cluster/structuredmerge/options.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,47 @@ limitations under the License.
1717
package structuredmerge
1818

1919
import (
20+
"sigs.k8s.io/controller-runtime/pkg/client"
21+
22+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
2023
"sigs.k8s.io/cluster-api/internal/contract"
2124
)
2225

26+
var (
27+
// defaultAllowedPaths are the allowed paths for all objects except Clusters.
28+
defaultAllowedPaths = []contract.Path{
29+
// apiVersion, kind, name and namespace are required field for a server side apply intent.
30+
{"apiVersion"},
31+
{"kind"},
32+
{"metadata", "name"},
33+
{"metadata", "namespace"},
34+
// the topology controller controls/has an opinion for labels, annotation, ownerReferences and spec only.
35+
{"metadata", "labels"},
36+
{"metadata", "annotations"},
37+
{"metadata", "ownerReferences"},
38+
{"spec"},
39+
}
40+
41+
// allowedPathsCluster are the allowed paths specific for Clusters.
42+
// The cluster object is not created by the topology controller and already contains fields which are
43+
// not supposed for the topology controller to have an opinion on / take (co-)ownership of.
44+
// Because of that the allowedPaths are different to other objects.
45+
// NOTE: This is mostly the same as defaultAllowedPaths but having more restrictions.
46+
allowedPathsCluster = []contract.Path{
47+
// apiVersion, kind, name and namespace are required field for a server side apply intent.
48+
{"apiVersion"},
49+
{"kind"},
50+
{"metadata", "name"},
51+
{"metadata", "namespace"},
52+
// the topology controller controls/has an opinion for the labels ClusterLabelName
53+
// and ClusterTopologyOwnedLabel as well as infrastructureRef and controlPlaneRef in spec.
54+
{"metadata", "labels", clusterv1.ClusterLabelName},
55+
{"metadata", "labels", clusterv1.ClusterTopologyOwnedLabel},
56+
{"spec", "infrastructureRef"},
57+
{"spec", "controlPlaneRef"},
58+
}
59+
)
60+
2361
// HelperOption is some configuration that modifies options for Helper.
2462
type HelperOption interface {
2563
// ApplyToHelper applies this configuration to the given helper options.
@@ -42,6 +80,20 @@ type HelperOptions struct {
4280
ignorePaths []contract.Path
4381
}
4482

83+
// newHelperOptions returns initialized HelperOptions.
84+
func newHelperOptions(target client.Object, opts ...HelperOption) *HelperOptions {
85+
helperOptions := &HelperOptions{
86+
allowedPaths: defaultAllowedPaths,
87+
}
88+
// Overwrite the allowedPaths for Cluster objects to prevent the topology controller
89+
// to take ownership of fields it is not supposed to.
90+
if _, ok := target.(*clusterv1.Cluster); ok {
91+
helperOptions.allowedPaths = allowedPathsCluster
92+
}
93+
helperOptions = helperOptions.ApplyOptions(opts)
94+
return helperOptions
95+
}
96+
4597
// ApplyOptions applies the given patch options on these options,
4698
// and then returns itself (for convenient chaining).
4799
func (o *HelperOptions) ApplyOptions(opts []HelperOption) *HelperOptions {

internal/controllers/topology/cluster/structuredmerge/serversidepathhelper.go

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,20 +42,8 @@ type serverSidePatchHelper struct {
4242

4343
// NewServerSidePatchHelper returns a new PatchHelper using server side apply.
4444
func NewServerSidePatchHelper(original, modified client.Object, c client.Client, opts ...HelperOption) (PatchHelper, error) {
45-
helperOptions := &HelperOptions{}
46-
helperOptions = helperOptions.ApplyOptions(opts)
47-
helperOptions.allowedPaths = []contract.Path{
48-
// apiVersion, kind, name and namespace are required field for a server side apply intent.
49-
{"apiVersion"},
50-
{"kind"},
51-
{"metadata", "name"},
52-
{"metadata", "namespace"},
53-
// the topology controller controls/has an opinion for labels, annotation, ownerReferences and spec only.
54-
{"metadata", "labels"},
55-
{"metadata", "annotations"},
56-
{"metadata", "ownerReferences"},
57-
{"spec"},
58-
}
45+
// Create helperOptions for filtering the original and modified objects to the desired intent.
46+
helperOptions := newHelperOptions(modified, opts...)
5947

6048
// If required, convert the original and modified objects to unstructured and filter out all the information
6149
// not relevant for the topology controller.

0 commit comments

Comments
 (0)