sigs.k8s.io/cluster-api@v1.6.3/internal/controllers/topology/cluster/structuredmerge/options.go (about)

     1  /*
     2  Copyright 2022 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package structuredmerge
    18  
    19  import (
    20  	"sigs.k8s.io/controller-runtime/pkg/client"
    21  
    22  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    23  	"sigs.k8s.io/cluster-api/internal/contract"
    24  	"sigs.k8s.io/cluster-api/internal/util/ssa"
    25  )
    26  
    27  var (
    28  	// defaultAllowedPaths are the allowed paths for all objects except Clusters.
    29  	defaultAllowedPaths = []contract.Path{
    30  		// apiVersion, kind, name and namespace are required field for a server side apply intent.
    31  		{"apiVersion"},
    32  		{"kind"},
    33  		{"metadata", "name"},
    34  		{"metadata", "namespace"},
    35  		// uid is optional for a server side apply intent but sets the expectation of an object getting created or a specific one updated.
    36  		{"metadata", "uid"},
    37  		// the topology controller controls/has an opinion for labels, annotation, ownerReferences and spec only.
    38  		{"metadata", "labels"},
    39  		{"metadata", "annotations"},
    40  		{"metadata", "ownerReferences"},
    41  		{"spec"},
    42  	}
    43  
    44  	// allowedPathsCluster are the allowed paths specific for Clusters.
    45  	// The cluster object is not created by the topology controller and already contains fields which are
    46  	// not supposed for the topology controller to have an opinion on / take (co-)ownership of.
    47  	// Because of that the allowedPaths are different to other objects.
    48  	// NOTE: This is mostly the same as defaultAllowedPaths but having more restrictions.
    49  	allowedPathsCluster = []contract.Path{
    50  		// apiVersion, kind, name and namespace are required field for a server side apply intent.
    51  		{"apiVersion"},
    52  		{"kind"},
    53  		{"metadata", "name"},
    54  		{"metadata", "namespace"},
    55  		// uid is optional for a server side apply intent but sets the expectation of an object getting created or a specific one updated.
    56  		{"metadata", "uid"},
    57  		// the topology controller controls/has an opinion for the labels ClusterNameLabel
    58  		// and ClusterTopologyOwnedLabel as well as infrastructureRef and controlPlaneRef in spec.
    59  		{"metadata", "labels", clusterv1.ClusterNameLabel},
    60  		{"metadata", "labels", clusterv1.ClusterTopologyOwnedLabel},
    61  		{"spec", "infrastructureRef"},
    62  		{"spec", "controlPlaneRef"},
    63  	}
    64  )
    65  
    66  // HelperOption is some configuration that modifies options for Helper.
    67  type HelperOption interface {
    68  	// ApplyToHelper applies this configuration to the given helper options.
    69  	ApplyToHelper(*HelperOptions)
    70  }
    71  
    72  // HelperOptions contains options for Helper.
    73  type HelperOptions struct {
    74  	ssa.FilterObjectInput
    75  }
    76  
    77  // newHelperOptions returns initialized HelperOptions.
    78  func newHelperOptions(target client.Object, opts ...HelperOption) *HelperOptions {
    79  	helperOptions := &HelperOptions{
    80  		FilterObjectInput: ssa.FilterObjectInput{
    81  			AllowedPaths: defaultAllowedPaths,
    82  			IgnorePaths:  []contract.Path{},
    83  		},
    84  	}
    85  	// Overwrite the allowedPaths for Cluster objects to prevent the topology controller
    86  	// to take ownership of fields it is not supposed to.
    87  	if _, ok := target.(*clusterv1.Cluster); ok {
    88  		helperOptions.AllowedPaths = allowedPathsCluster
    89  	}
    90  	helperOptions = helperOptions.ApplyOptions(opts)
    91  	return helperOptions
    92  }
    93  
    94  // ApplyOptions applies the given patch options on these options,
    95  // and then returns itself (for convenient chaining).
    96  func (o *HelperOptions) ApplyOptions(opts []HelperOption) *HelperOptions {
    97  	for _, opt := range opts {
    98  		opt.ApplyToHelper(o)
    99  	}
   100  	return o
   101  }
   102  
   103  // IgnorePaths instruct the Helper to ignore given paths when computing a patch.
   104  // NOTE: ignorePaths are used to filter out fields nested inside allowedPaths, e.g.
   105  // spec.ControlPlaneEndpoint.
   106  type IgnorePaths []contract.Path
   107  
   108  // ApplyToHelper applies this configuration to the given helper options.
   109  func (i IgnorePaths) ApplyToHelper(opts *HelperOptions) {
   110  	opts.IgnorePaths = i
   111  }