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  }