sigs.k8s.io/cluster-api@v1.7.1/internal/controllers/topology/cluster/patches/variables/variables.go (about) 1 /* 2 Copyright 2021 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 variables calculates variables for patching. 18 package variables 19 20 import ( 21 "encoding/json" 22 23 "github.com/pkg/errors" 24 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" 25 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 26 "k8s.io/utils/ptr" 27 28 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 29 expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1" 30 runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" 31 "sigs.k8s.io/cluster-api/internal/contract" 32 ) 33 34 const ( 35 // emptyDefinitionFrom may be supplied in variable values. 36 emptyDefinitionFrom = "" 37 ) 38 39 // Global returns variables that apply to all the templates, including user provided variables 40 // and builtin variables for the Cluster object. 41 func Global(clusterTopology *clusterv1.Topology, cluster *clusterv1.Cluster, definitionFrom string, patchVariableDefinitions map[string]bool) ([]runtimehooksv1.Variable, error) { 42 variables := []runtimehooksv1.Variable{} 43 44 // Add user defined variables from Cluster.spec.topology.variables. 45 for _, variable := range clusterTopology.Variables { 46 // Don't add user-defined "builtin" variable. 47 if variable.Name == runtimehooksv1.BuiltinsName { 48 continue 49 } 50 // Add the variable if it is defined for the current patch or it is defined for all the patches. 51 if variable.DefinitionFrom == emptyDefinitionFrom || variable.DefinitionFrom == definitionFrom { 52 // Add the variable if it has a definition from this patch in the ClusterClass. 53 if _, ok := patchVariableDefinitions[variable.Name]; ok { 54 variables = append(variables, runtimehooksv1.Variable{Name: variable.Name, Value: variable.Value}) 55 } 56 } 57 } 58 59 // Construct builtin variable. 60 builtin := runtimehooksv1.Builtins{ 61 Cluster: &runtimehooksv1.ClusterBuiltins{ 62 Name: cluster.Name, 63 Namespace: cluster.Namespace, 64 Topology: &runtimehooksv1.ClusterTopologyBuiltins{ 65 Version: cluster.Spec.Topology.Version, 66 Class: cluster.Spec.Topology.Class, 67 }, 68 }, 69 } 70 if cluster.Spec.ClusterNetwork != nil { 71 clusterNetworkIPFamily, _ := cluster.GetIPFamily() 72 builtin.Cluster.Network = &runtimehooksv1.ClusterNetworkBuiltins{ 73 IPFamily: ipFamilyToString(clusterNetworkIPFamily), 74 } 75 if cluster.Spec.ClusterNetwork.ServiceDomain != "" { 76 builtin.Cluster.Network.ServiceDomain = &cluster.Spec.ClusterNetwork.ServiceDomain 77 } 78 if cluster.Spec.ClusterNetwork.Services != nil && cluster.Spec.ClusterNetwork.Services.CIDRBlocks != nil { 79 builtin.Cluster.Network.Services = cluster.Spec.ClusterNetwork.Services.CIDRBlocks 80 } 81 if cluster.Spec.ClusterNetwork.Pods != nil && cluster.Spec.ClusterNetwork.Pods.CIDRBlocks != nil { 82 builtin.Cluster.Network.Pods = cluster.Spec.ClusterNetwork.Pods.CIDRBlocks 83 } 84 } 85 86 // Add builtin variables derived from the cluster object. 87 variable, err := toVariable(runtimehooksv1.BuiltinsName, builtin) 88 if err != nil { 89 return nil, err 90 } 91 variables = append(variables, *variable) 92 93 return variables, nil 94 } 95 96 // ControlPlane returns variables that apply to templates belonging to the ControlPlane. 97 func ControlPlane(cpTopology *clusterv1.ControlPlaneTopology, cp, cpInfrastructureMachineTemplate *unstructured.Unstructured) ([]runtimehooksv1.Variable, error) { 98 variables := []runtimehooksv1.Variable{} 99 100 // Construct builtin variable. 101 builtin := runtimehooksv1.Builtins{ 102 ControlPlane: &runtimehooksv1.ControlPlaneBuiltins{ 103 Name: cp.GetName(), 104 }, 105 } 106 107 // If it is required to manage the number of replicas for the ControlPlane, set the corresponding variable. 108 // NOTE: If the Cluster.spec.topology.controlPlane.replicas field is nil, the topology reconciler won't set 109 // the replicas field on the ControlPlane. This happens either when the ControlPlane provider does 110 // not implement support for this field or the default value of the ControlPlane is used. 111 if cpTopology.Replicas != nil { 112 replicas, err := contract.ControlPlane().Replicas().Get(cp) 113 if err != nil { 114 return nil, errors.Wrap(err, "failed to get spec.replicas from the ControlPlane") 115 } 116 builtin.ControlPlane.Replicas = replicas 117 } 118 119 version, err := contract.ControlPlane().Version().Get(cp) 120 if err != nil { 121 return nil, errors.Wrap(err, "failed to get spec.version from the ControlPlane") 122 } 123 builtin.ControlPlane.Version = *version 124 125 if cpInfrastructureMachineTemplate != nil { 126 builtin.ControlPlane.MachineTemplate = &runtimehooksv1.ControlPlaneMachineTemplateBuiltins{ 127 InfrastructureRef: runtimehooksv1.ControlPlaneMachineTemplateInfrastructureRefBuiltins{ 128 Name: cpInfrastructureMachineTemplate.GetName(), 129 }, 130 } 131 } 132 133 variable, err := toVariable(runtimehooksv1.BuiltinsName, builtin) 134 if err != nil { 135 return nil, err 136 } 137 variables = append(variables, *variable) 138 139 return variables, nil 140 } 141 142 // MachineDeployment returns variables that apply to templates belonging to a MachineDeployment. 143 func MachineDeployment(mdTopology *clusterv1.MachineDeploymentTopology, md *clusterv1.MachineDeployment, mdBootstrapTemplate, mdInfrastructureMachineTemplate *unstructured.Unstructured, definitionFrom string, patchVariableDefinitions map[string]bool) ([]runtimehooksv1.Variable, error) { 144 variables := []runtimehooksv1.Variable{} 145 146 // Add variables overrides for the MachineDeployment. 147 if mdTopology.Variables != nil { 148 for _, variable := range mdTopology.Variables.Overrides { 149 // Add the variable if it is defined for the current patch or it is defined for all the patches. 150 if variable.DefinitionFrom == emptyDefinitionFrom || variable.DefinitionFrom == definitionFrom { 151 // Add the variable if it has a definition from this patch in the ClusterClass. 152 if _, ok := patchVariableDefinitions[variable.Name]; ok { 153 variables = append(variables, runtimehooksv1.Variable{Name: variable.Name, Value: variable.Value}) 154 } 155 } 156 } 157 } 158 159 // Construct builtin variable. 160 builtin := runtimehooksv1.Builtins{ 161 MachineDeployment: &runtimehooksv1.MachineDeploymentBuiltins{ 162 Version: *md.Spec.Template.Spec.Version, 163 Class: mdTopology.Class, 164 Name: md.Name, 165 TopologyName: mdTopology.Name, 166 }, 167 } 168 if md.Spec.Replicas != nil { 169 builtin.MachineDeployment.Replicas = ptr.To[int64](int64(*md.Spec.Replicas)) 170 } 171 172 if mdBootstrapTemplate != nil { 173 builtin.MachineDeployment.Bootstrap = &runtimehooksv1.MachineBootstrapBuiltins{ 174 ConfigRef: &runtimehooksv1.MachineBootstrapConfigRefBuiltins{ 175 Name: mdBootstrapTemplate.GetName(), 176 }, 177 } 178 } 179 180 if mdInfrastructureMachineTemplate != nil { 181 builtin.MachineDeployment.InfrastructureRef = &runtimehooksv1.MachineInfrastructureRefBuiltins{ 182 Name: mdInfrastructureMachineTemplate.GetName(), 183 } 184 } 185 186 variable, err := toVariable(runtimehooksv1.BuiltinsName, builtin) 187 if err != nil { 188 return nil, err 189 } 190 variables = append(variables, *variable) 191 192 return variables, nil 193 } 194 195 // MachinePool returns variables that apply to templates belonging to a MachinePool. 196 func MachinePool(mpTopology *clusterv1.MachinePoolTopology, mp *expv1.MachinePool, mpBootstrapObject, mpInfrastructureMachinePool *unstructured.Unstructured, definitionFrom string, patchVariableDefinitions map[string]bool) ([]runtimehooksv1.Variable, error) { 197 variables := []runtimehooksv1.Variable{} 198 199 // Add variables overrides for the MachinePool. 200 if mpTopology.Variables != nil { 201 for _, variable := range mpTopology.Variables.Overrides { 202 // Add the variable if it is defined for the current patch or it is defined for all the patches. 203 if variable.DefinitionFrom == emptyDefinitionFrom || variable.DefinitionFrom == definitionFrom { 204 // Add the variable if it has a definition from this patch in the ClusterClass. 205 if _, ok := patchVariableDefinitions[variable.Name]; ok { 206 variables = append(variables, runtimehooksv1.Variable{Name: variable.Name, Value: variable.Value}) 207 } 208 } 209 } 210 } 211 212 // Construct builtin variable. 213 builtin := runtimehooksv1.Builtins{ 214 MachinePool: &runtimehooksv1.MachinePoolBuiltins{ 215 Version: *mp.Spec.Template.Spec.Version, 216 Class: mpTopology.Class, 217 Name: mp.Name, 218 TopologyName: mpTopology.Name, 219 }, 220 } 221 if mp.Spec.Replicas != nil { 222 builtin.MachinePool.Replicas = ptr.To[int64](int64(*mp.Spec.Replicas)) 223 } 224 225 if mpBootstrapObject != nil { 226 builtin.MachinePool.Bootstrap = &runtimehooksv1.MachineBootstrapBuiltins{ 227 ConfigRef: &runtimehooksv1.MachineBootstrapConfigRefBuiltins{ 228 Name: mpBootstrapObject.GetName(), 229 }, 230 } 231 } 232 233 if mpInfrastructureMachinePool != nil { 234 builtin.MachinePool.InfrastructureRef = &runtimehooksv1.MachineInfrastructureRefBuiltins{ 235 Name: mpInfrastructureMachinePool.GetName(), 236 } 237 } 238 239 variable, err := toVariable(runtimehooksv1.BuiltinsName, builtin) 240 if err != nil { 241 return nil, err 242 } 243 variables = append(variables, *variable) 244 245 return variables, nil 246 } 247 248 // toVariable converts name and value to a variable. 249 func toVariable(name string, value interface{}) (*runtimehooksv1.Variable, error) { 250 marshalledValue, err := json.Marshal(value) 251 if err != nil { 252 return nil, errors.Wrapf(err, "failed to set variable %q: error marshalling", name) 253 } 254 255 return &runtimehooksv1.Variable{ 256 Name: name, 257 Value: apiextensionsv1.JSON{Raw: marshalledValue}, 258 }, nil 259 } 260 261 func ipFamilyToString(ipFamily clusterv1.ClusterIPFamily) string { 262 switch ipFamily { 263 case clusterv1.DualStackIPFamily: 264 return "DualStack" 265 case clusterv1.IPv4IPFamily: 266 return "IPv4" 267 case clusterv1.IPv6IPFamily: 268 return "IPv6" 269 default: 270 return "Invalid" 271 } 272 }