diff --git a/api/bootstrap/kubeadm/v1beta1/conversion.go b/api/bootstrap/kubeadm/v1beta1/conversion.go index 5867c529afad..d74ed59a6f9f 100644 --- a/api/bootstrap/kubeadm/v1beta1/conversion.go +++ b/api/bootstrap/kubeadm/v1beta1/conversion.go @@ -240,6 +240,10 @@ func Convert_v1beta1_KubeadmConfigSpec_To_v1beta2_KubeadmConfigSpec(in *KubeadmC return autoConvert_v1beta1_KubeadmConfigSpec_To_v1beta2_KubeadmConfigSpec(in, out, s) } +func Convert_v1beta1_ClusterConfiguration_To_v1beta2_ClusterConfiguration(in *ClusterConfiguration, out *bootstrapv1.ClusterConfiguration, s apimachineryconversion.Scope) error { + return autoConvert_v1beta1_ClusterConfiguration_To_v1beta2_ClusterConfiguration(in, out, s) +} + func Convert_v1beta1_ControlPlaneComponent_To_v1beta2_ControlPlaneComponent(in *ControlPlaneComponent, out *bootstrapv1.ControlPlaneComponent, s apimachineryconversion.Scope) error { out.ExtraArgs = bootstrapv1.ConvertToArgs(in.ExtraArgs) return autoConvert_v1beta1_ControlPlaneComponent_To_v1beta2_ControlPlaneComponent(in, out, s) diff --git a/api/bootstrap/kubeadm/v1beta1/conversion_test.go b/api/bootstrap/kubeadm/v1beta1/conversion_test.go index 6c78736b4a07..59987ae9c1ce 100644 --- a/api/bootstrap/kubeadm/v1beta1/conversion_test.go +++ b/api/bootstrap/kubeadm/v1beta1/conversion_test.go @@ -60,6 +60,7 @@ func KubeadmConfigFuzzFuncs(_ runtimeserializer.CodecFactory) []interface{} { spokeDiscovery, spokeKubeadmConfigSpec, spokeKubeadmConfigStatus, + spokeClusterConfiguration, hubBootstrapTokenString, spokeBootstrapTokenString, hubKubeadmConfigSpec, @@ -71,6 +72,7 @@ func KubeadmConfigTemplateFuzzFuncs(_ runtimeserializer.CodecFactory) []interfac spokeAPIServer, spokeDiscovery, spokeKubeadmConfigSpec, + spokeClusterConfiguration, spokeBootstrapTokenString, hubBootstrapTokenString, hubKubeadmConfigSpec, @@ -131,6 +133,18 @@ func spokeKubeadmConfigSpec(in *KubeadmConfigSpec, c randfill.Continue) { in.UseExperimentalRetryJoin = false } +func spokeClusterConfiguration(in *ClusterConfiguration, c randfill.Continue) { + c.FillNoCustom(in) + + // Drop the following fields as they have been removed in v1beta2, so we don't have to preserve them. + in.Networking.ServiceSubnet = "" + in.Networking.PodSubnet = "" + in.Networking.DNSDomain = "" + in.KubernetesVersion = "" + in.ControlPlaneEndpoint = "" + in.ClusterName = "" +} + func spokeAPIServer(in *APIServer, c randfill.Continue) { c.FillNoCustom(in) diff --git a/api/bootstrap/kubeadm/v1beta1/zz_generated.conversion.go b/api/bootstrap/kubeadm/v1beta1/zz_generated.conversion.go index 0019c2599c4a..59d458d2e541 100644 --- a/api/bootstrap/kubeadm/v1beta1/zz_generated.conversion.go +++ b/api/bootstrap/kubeadm/v1beta1/zz_generated.conversion.go @@ -85,11 +85,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*ClusterConfiguration)(nil), (*v1beta2.ClusterConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta1_ClusterConfiguration_To_v1beta2_ClusterConfiguration(a.(*ClusterConfiguration), b.(*v1beta2.ClusterConfiguration), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*v1beta2.ClusterConfiguration)(nil), (*ClusterConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta2_ClusterConfiguration_To_v1beta1_ClusterConfiguration(a.(*v1beta2.ClusterConfiguration), b.(*ClusterConfiguration), scope) }); err != nil { @@ -395,16 +390,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*Networking)(nil), (*v1beta2.Networking)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta1_Networking_To_v1beta2_Networking(a.(*Networking), b.(*v1beta2.Networking), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*v1beta2.Networking)(nil), (*Networking)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta2_Networking_To_v1beta1_Networking(a.(*v1beta2.Networking), b.(*Networking), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*Partition)(nil), (*v1beta2.Partition)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_Partition_To_v1beta2_Partition(a.(*Partition), b.(*v1beta2.Partition), scope) }); err != nil { @@ -475,6 +460,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*ClusterConfiguration)(nil), (*v1beta2.ClusterConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_ClusterConfiguration_To_v1beta2_ClusterConfiguration(a.(*ClusterConfiguration), b.(*v1beta2.ClusterConfiguration), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*corev1beta1.Condition)(nil), (*v1.Condition)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_Condition_To_v1_Condition(a.(*corev1beta1.Condition), b.(*v1.Condition), scope) }); err != nil { @@ -679,11 +669,9 @@ func autoConvert_v1beta1_ClusterConfiguration_To_v1beta2_ClusterConfiguration(in if err := Convert_v1beta1_Etcd_To_v1beta2_Etcd(&in.Etcd, &out.Etcd, s); err != nil { return err } - if err := Convert_v1beta1_Networking_To_v1beta2_Networking(&in.Networking, &out.Networking, s); err != nil { - return err - } - out.KubernetesVersion = in.KubernetesVersion - out.ControlPlaneEndpoint = in.ControlPlaneEndpoint + // WARNING: in.Networking requires manual conversion: does not exist in peer-type + // WARNING: in.KubernetesVersion requires manual conversion: does not exist in peer-type + // WARNING: in.ControlPlaneEndpoint requires manual conversion: does not exist in peer-type if err := Convert_v1beta1_APIServer_To_v1beta2_APIServer(&in.APIServer, &out.APIServer, s); err != nil { return err } @@ -699,24 +687,14 @@ func autoConvert_v1beta1_ClusterConfiguration_To_v1beta2_ClusterConfiguration(in out.CertificatesDir = in.CertificatesDir out.ImageRepository = in.ImageRepository out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates)) - out.ClusterName = in.ClusterName + // WARNING: in.ClusterName requires manual conversion: does not exist in peer-type return nil } -// Convert_v1beta1_ClusterConfiguration_To_v1beta2_ClusterConfiguration is an autogenerated conversion function. -func Convert_v1beta1_ClusterConfiguration_To_v1beta2_ClusterConfiguration(in *ClusterConfiguration, out *v1beta2.ClusterConfiguration, s conversion.Scope) error { - return autoConvert_v1beta1_ClusterConfiguration_To_v1beta2_ClusterConfiguration(in, out, s) -} - func autoConvert_v1beta2_ClusterConfiguration_To_v1beta1_ClusterConfiguration(in *v1beta2.ClusterConfiguration, out *ClusterConfiguration, s conversion.Scope) error { if err := Convert_v1beta2_Etcd_To_v1beta1_Etcd(&in.Etcd, &out.Etcd, s); err != nil { return err } - if err := Convert_v1beta2_Networking_To_v1beta1_Networking(&in.Networking, &out.Networking, s); err != nil { - return err - } - out.KubernetesVersion = in.KubernetesVersion - out.ControlPlaneEndpoint = in.ControlPlaneEndpoint if err := Convert_v1beta2_APIServer_To_v1beta1_APIServer(&in.APIServer, &out.APIServer, s); err != nil { return err } @@ -732,7 +710,6 @@ func autoConvert_v1beta2_ClusterConfiguration_To_v1beta1_ClusterConfiguration(in out.CertificatesDir = in.CertificatesDir out.ImageRepository = in.ImageRepository out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates)) - out.ClusterName = in.ClusterName return nil } @@ -1737,30 +1714,6 @@ func Convert_v1beta2_NTP_To_v1beta1_NTP(in *v1beta2.NTP, out *NTP, s conversion. return autoConvert_v1beta2_NTP_To_v1beta1_NTP(in, out, s) } -func autoConvert_v1beta1_Networking_To_v1beta2_Networking(in *Networking, out *v1beta2.Networking, s conversion.Scope) error { - out.ServiceSubnet = in.ServiceSubnet - out.PodSubnet = in.PodSubnet - out.DNSDomain = in.DNSDomain - return nil -} - -// Convert_v1beta1_Networking_To_v1beta2_Networking is an autogenerated conversion function. -func Convert_v1beta1_Networking_To_v1beta2_Networking(in *Networking, out *v1beta2.Networking, s conversion.Scope) error { - return autoConvert_v1beta1_Networking_To_v1beta2_Networking(in, out, s) -} - -func autoConvert_v1beta2_Networking_To_v1beta1_Networking(in *v1beta2.Networking, out *Networking, s conversion.Scope) error { - out.ServiceSubnet = in.ServiceSubnet - out.PodSubnet = in.PodSubnet - out.DNSDomain = in.DNSDomain - return nil -} - -// Convert_v1beta2_Networking_To_v1beta1_Networking is an autogenerated conversion function. -func Convert_v1beta2_Networking_To_v1beta1_Networking(in *v1beta2.Networking, out *Networking, s conversion.Scope) error { - return autoConvert_v1beta2_Networking_To_v1beta1_Networking(in, out, s) -} - func autoConvert_v1beta1_NodeRegistrationOptions_To_v1beta2_NodeRegistrationOptions(in *NodeRegistrationOptions, out *v1beta2.NodeRegistrationOptions, s conversion.Scope) error { out.Name = in.Name out.CRISocket = in.CRISocket diff --git a/api/bootstrap/kubeadm/v1beta2/kubeadm_types.go b/api/bootstrap/kubeadm/v1beta2/kubeadm_types.go index 874d42aa9f13..48bed153e61c 100644 --- a/api/bootstrap/kubeadm/v1beta2/kubeadm_types.go +++ b/api/bootstrap/kubeadm/v1beta2/kubeadm_types.go @@ -130,35 +130,6 @@ type ClusterConfiguration struct { // +optional Etcd Etcd `json:"etcd,omitempty"` - // networking holds configuration for the networking topology of the cluster. - // NB: This value defaults to the Cluster object spec.clusterNetwork. - // +optional - Networking Networking `json:"networking,omitempty"` - - // kubernetesVersion is the target version of the control plane. - // NB: This value defaults to the Machine object spec.version - // +optional - // +kubebuilder:validation:MinLength=1 - // +kubebuilder:validation:MaxLength=256 - KubernetesVersion string `json:"kubernetesVersion,omitempty"` - - // controlPlaneEndpoint sets a stable IP address or DNS name for the control plane; it - // can be a valid IP address or a RFC-1123 DNS subdomain, both with optional TCP port. - // In case the ControlPlaneEndpoint is not specified, the AdvertiseAddress + BindPort - // are used; in case the ControlPlaneEndpoint is specified but without a TCP port, - // the BindPort is used. - // Possible usages are: - // e.g. In a cluster with more than one control plane instances, this field should be - // assigned the address of the external load balancer in front of the - // control plane instances. - // e.g. in environments with enforced node recycling, the ControlPlaneEndpoint - // could be used for assigning a stable DNS to the control plane. - // NB: This value defaults to the first value in the Cluster object status.apiEndpoints array. - // +optional - // +kubebuilder:validation:MinLength=1 - // +kubebuilder:validation:MaxLength=512 - ControlPlaneEndpoint string `json:"controlPlaneEndpoint,omitempty"` - // apiServer contains extra settings for the API server control plane component // +optional APIServer APIServer `json:"apiServer,omitempty"` @@ -201,12 +172,6 @@ type ClusterConfiguration struct { // featureGates enabled by the user. // +optional FeatureGates map[string]bool `json:"featureGates,omitempty"` - - // clusterName is the cluster name - // +optional - // +kubebuilder:validation:MinLength=1 - // +kubebuilder:validation:MaxLength=63 - ClusterName string `json:"clusterName,omitempty"` } // ControlPlaneComponent holds settings common to control plane component of the cluster. @@ -416,29 +381,6 @@ func (n *NodeRegistrationOptions) MarshalJSON() ([]byte, error) { }) } -// Networking contains elements describing cluster's networking configuration. -type Networking struct { - // serviceSubnet is the subnet used by k8s services. - // Defaults to a comma-delimited string of the Cluster object's spec.clusterNetwork.pods.cidrBlocks, or - // to "10.96.0.0/12" if that's unset. - // +optional - // +kubebuilder:validation:MinLength=1 - // +kubebuilder:validation:MaxLength=1024 - ServiceSubnet string `json:"serviceSubnet,omitempty"` - // podSubnet is the subnet used by pods. - // If unset, the API server will not allocate CIDR ranges for every node. - // Defaults to a comma-delimited string of the Cluster object's spec.clusterNetwork.services.cidrBlocks if that is set - // +optional - // +kubebuilder:validation:MinLength=1 - // +kubebuilder:validation:MaxLength=1024 - PodSubnet string `json:"podSubnet,omitempty"` - // dnsDomain is the dns domain used by k8s services. Defaults to "cluster.local". - // +optional - // +kubebuilder:validation:MinLength=1 - // +kubebuilder:validation:MaxLength=253 - DNSDomain string `json:"dnsDomain,omitempty"` -} - // BootstrapToken describes one bootstrap token, stored as a Secret in the cluster. type BootstrapToken struct { // token is used for establishing bidirectional trust between nodes and control-planes. diff --git a/api/bootstrap/kubeadm/v1beta2/zz_generated.deepcopy.go b/api/bootstrap/kubeadm/v1beta2/zz_generated.deepcopy.go index 6a2e075a0b53..eb455c3ab05f 100644 --- a/api/bootstrap/kubeadm/v1beta2/zz_generated.deepcopy.go +++ b/api/bootstrap/kubeadm/v1beta2/zz_generated.deepcopy.go @@ -157,7 +157,6 @@ func (in *ClusterConfiguration) DeepCopyInto(out *ClusterConfiguration) { *out = *in out.TypeMeta = in.TypeMeta in.Etcd.DeepCopyInto(&out.Etcd) - out.Networking = in.Networking in.APIServer.DeepCopyInto(&out.APIServer) in.ControllerManager.DeepCopyInto(&out.ControllerManager) in.Scheduler.DeepCopyInto(&out.Scheduler) @@ -1193,21 +1192,6 @@ func (in *NTP) DeepCopy() *NTP { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Networking) DeepCopyInto(out *Networking) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Networking. -func (in *Networking) DeepCopy() *Networking { - if in == nil { - return nil - } - out := new(Networking) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NodeRegistrationOptions) DeepCopyInto(out *NodeRegistrationOptions) { *out = *in diff --git a/api/controlplane/kubeadm/v1beta1/conversion_test.go b/api/controlplane/kubeadm/v1beta1/conversion_test.go index 30abe76e7da0..61367457f1ea 100644 --- a/api/controlplane/kubeadm/v1beta1/conversion_test.go +++ b/api/controlplane/kubeadm/v1beta1/conversion_test.go @@ -60,6 +60,7 @@ func KubeadmControlPlaneFuzzFuncs(_ runtimeserializer.CodecFactory) []interface{ hubKubeadmControlPlaneStatus, spokeKubeadmControlPlaneStatus, spokeKubeadmConfigSpec, + spokeClusterConfiguration, hubBootstrapTokenString, spokeBootstrapTokenString, spokeAPIServer, @@ -71,6 +72,7 @@ func KubeadmControlPlaneFuzzFuncs(_ runtimeserializer.CodecFactory) []interface{ func KubeadmControlPlaneTemplateFuzzFuncs(_ runtimeserializer.CodecFactory) []interface{} { return []interface{}{ spokeKubeadmConfigSpec, + spokeClusterConfiguration, hubBootstrapTokenString, spokeBootstrapTokenString, spokeAPIServer, @@ -167,3 +169,15 @@ func spokeKubeadmConfigSpec(in *bootstrapv1beta1.KubeadmConfigSpec, c randfill.C // Drop UseExperimentalRetryJoin as we intentionally don't preserve it. in.UseExperimentalRetryJoin = false } + +func spokeClusterConfiguration(in *bootstrapv1beta1.ClusterConfiguration, c randfill.Continue) { + c.FillNoCustom(in) + + // Drop the following fields as they have been removed in v1beta2, so we don't have to preserve them. + in.Networking.ServiceSubnet = "" + in.Networking.PodSubnet = "" + in.Networking.DNSDomain = "" + in.KubernetesVersion = "" + in.ControlPlaneEndpoint = "" + in.ClusterName = "" +} diff --git a/bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigs.yaml b/bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigs.yaml index c13911304706..b8c3ffd26bd0 100644 --- a/bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigs.yaml +++ b/bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigs.yaml @@ -4357,28 +4357,6 @@ spec: maxLength: 512 minLength: 1 type: string - clusterName: - description: clusterName is the cluster name - maxLength: 63 - minLength: 1 - type: string - controlPlaneEndpoint: - description: |- - controlPlaneEndpoint sets a stable IP address or DNS name for the control plane; it - can be a valid IP address or a RFC-1123 DNS subdomain, both with optional TCP port. - In case the ControlPlaneEndpoint is not specified, the AdvertiseAddress + BindPort - are used; in case the ControlPlaneEndpoint is specified but without a TCP port, - the BindPort is used. - Possible usages are: - e.g. In a cluster with more than one control plane instances, this field should be - assigned the address of the external load balancer in front of the - control plane instances. - e.g. in environments with enforced node recycling, the ControlPlaneEndpoint - could be used for assigning a stable DNS to the control plane. - NB: This value defaults to the first value in the Cluster object status.apiEndpoints array. - maxLength: 512 - minLength: 1 - type: string controllerManager: description: controllerManager contains extra settings for the controller manager control plane component @@ -4877,41 +4855,6 @@ spec: In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string - kubernetesVersion: - description: |- - kubernetesVersion is the target version of the control plane. - NB: This value defaults to the Machine object spec.version - maxLength: 256 - minLength: 1 - type: string - networking: - description: |- - networking holds configuration for the networking topology of the cluster. - NB: This value defaults to the Cluster object spec.clusterNetwork. - properties: - dnsDomain: - description: dnsDomain is the dns domain used by k8s services. - Defaults to "cluster.local". - maxLength: 253 - minLength: 1 - type: string - podSubnet: - description: |- - podSubnet is the subnet used by pods. - If unset, the API server will not allocate CIDR ranges for every node. - Defaults to a comma-delimited string of the Cluster object's spec.clusterNetwork.services.cidrBlocks if that is set - maxLength: 1024 - minLength: 1 - type: string - serviceSubnet: - description: |- - serviceSubnet is the subnet used by k8s services. - Defaults to a comma-delimited string of the Cluster object's spec.clusterNetwork.pods.cidrBlocks, or - to "10.96.0.0/12" if that's unset. - maxLength: 1024 - minLength: 1 - type: string - type: object scheduler: description: scheduler contains extra settings for the scheduler control plane component diff --git a/bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigtemplates.yaml b/bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigtemplates.yaml index 7895b84b2d6a..225179b4b056 100644 --- a/bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigtemplates.yaml +++ b/bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigtemplates.yaml @@ -4231,28 +4231,6 @@ spec: maxLength: 512 minLength: 1 type: string - clusterName: - description: clusterName is the cluster name - maxLength: 63 - minLength: 1 - type: string - controlPlaneEndpoint: - description: |- - controlPlaneEndpoint sets a stable IP address or DNS name for the control plane; it - can be a valid IP address or a RFC-1123 DNS subdomain, both with optional TCP port. - In case the ControlPlaneEndpoint is not specified, the AdvertiseAddress + BindPort - are used; in case the ControlPlaneEndpoint is specified but without a TCP port, - the BindPort is used. - Possible usages are: - e.g. In a cluster with more than one control plane instances, this field should be - assigned the address of the external load balancer in front of the - control plane instances. - e.g. in environments with enforced node recycling, the ControlPlaneEndpoint - could be used for assigning a stable DNS to the control plane. - NB: This value defaults to the first value in the Cluster object status.apiEndpoints array. - maxLength: 512 - minLength: 1 - type: string controllerManager: description: controllerManager contains extra settings for the controller manager control plane component @@ -4765,41 +4743,6 @@ spec: In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string - kubernetesVersion: - description: |- - kubernetesVersion is the target version of the control plane. - NB: This value defaults to the Machine object spec.version - maxLength: 256 - minLength: 1 - type: string - networking: - description: |- - networking holds configuration for the networking topology of the cluster. - NB: This value defaults to the Cluster object spec.clusterNetwork. - properties: - dnsDomain: - description: dnsDomain is the dns domain used by k8s - services. Defaults to "cluster.local". - maxLength: 253 - minLength: 1 - type: string - podSubnet: - description: |- - podSubnet is the subnet used by pods. - If unset, the API server will not allocate CIDR ranges for every node. - Defaults to a comma-delimited string of the Cluster object's spec.clusterNetwork.services.cidrBlocks if that is set - maxLength: 1024 - minLength: 1 - type: string - serviceSubnet: - description: |- - serviceSubnet is the subnet used by k8s services. - Defaults to a comma-delimited string of the Cluster object's spec.clusterNetwork.pods.cidrBlocks, or - to "10.96.0.0/12" if that's unset. - maxLength: 1024 - minLength: 1 - type: string - type: object scheduler: description: scheduler contains extra settings for the scheduler control plane component diff --git a/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller.go b/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller.go index 24b6a278250c..2296921a80e9 100644 --- a/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller.go +++ b/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller.go @@ -49,6 +49,7 @@ import ( "sigs.k8s.io/cluster-api/bootstrap/kubeadm/internal/ignition" "sigs.k8s.io/cluster-api/bootstrap/kubeadm/internal/locking" kubeadmtypes "sigs.k8s.io/cluster-api/bootstrap/kubeadm/types" + "sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/upstream" bsutil "sigs.k8s.io/cluster-api/bootstrap/util" "sigs.k8s.io/cluster-api/controllers/clustercache" "sigs.k8s.io/cluster-api/feature" @@ -546,9 +547,6 @@ func (r *KubeadmConfigReconciler) handleClusterNotInitialized(ctx context.Contex } } - // injects into config.ClusterConfiguration values from top level object - r.reconcileTopLevelObjectSettings(ctx, scope.Cluster, machine, scope.Config) - if scope.Config.Spec.InitConfiguration == nil { scope.Config.Spec.InitConfiguration = &bootstrapv1.InitConfiguration{ TypeMeta: metav1.TypeMeta{ @@ -558,7 +556,9 @@ func (r *KubeadmConfigReconciler) handleClusterNotInitialized(ctx context.Contex } } - clusterdata, err := kubeadmtypes.MarshalClusterConfigurationForVersion(scope.Config.Spec.InitConfiguration, scope.Config.Spec.ClusterConfiguration, parsedVersion) + additionalData := r.computeClusterConfigurationAdditionalData(scope.Cluster, machine, scope.Config.Spec.InitConfiguration) + + clusterdata, err := kubeadmtypes.MarshalClusterConfigurationForVersion(scope.Config.Spec.ClusterConfiguration, parsedVersion, additionalData) if err != nil { scope.Error(err, "Failed to marshal cluster configuration") return ctrl.Result{}, err @@ -1323,50 +1323,48 @@ func (r *KubeadmConfigReconciler) reconcileDiscoveryFile(ctx context.Context, cl return ctrl.Result{}, nil } -// reconcileTopLevelObjectSettings injects into config.ClusterConfiguration values from top level objects like cluster and machine. -// The implementation func respect user provided config values, but in case some of them are missing, values from top level objects are used. -func (r *KubeadmConfigReconciler) reconcileTopLevelObjectSettings(ctx context.Context, cluster *clusterv1.Cluster, machine *clusterv1.Machine, config *bootstrapv1.KubeadmConfig) { - log := ctrl.LoggerFrom(ctx) +// computeClusterConfigurationAdditionalData computes additional data that must go in kubeadm's ClusterConfiguration, but exists +// in different Cluster API objects, like e.g. the Cluster object. +func (r *KubeadmConfigReconciler) computeClusterConfigurationAdditionalData(cluster *clusterv1.Cluster, machine *clusterv1.Machine, initConfiguration *bootstrapv1.InitConfiguration) *upstream.AdditionalData { + data := &upstream.AdditionalData{} - // If there is no ControlPlaneEndpoint defined in ClusterConfiguration but - // there is a ControlPlaneEndpoint defined at Cluster level (e.g. the load balancer endpoint), + // If there is a ControlPlaneEndpoint defined at Cluster level (e.g. the load balancer endpoint), // then use Cluster's ControlPlaneEndpoint as a control plane endpoint for the Kubernetes cluster. - if config.Spec.ClusterConfiguration.ControlPlaneEndpoint == "" && cluster.Spec.ControlPlaneEndpoint.IsValid() { - config.Spec.ClusterConfiguration.ControlPlaneEndpoint = cluster.Spec.ControlPlaneEndpoint.String() - log.V(3).Info("Altering ClusterConfiguration.ControlPlaneEndpoint", "controlPlaneEndpoint", config.Spec.ClusterConfiguration.ControlPlaneEndpoint) + if cluster.Spec.ControlPlaneEndpoint.IsValid() { + data.ControlPlaneEndpoint = ptr.To(cluster.Spec.ControlPlaneEndpoint.String()) } - // If there are no ClusterName defined in ClusterConfiguration, use Cluster.Name - if config.Spec.ClusterConfiguration.ClusterName == "" { - config.Spec.ClusterConfiguration.ClusterName = cluster.Name - log.V(3).Info("Altering ClusterConfiguration.ClusterName", "clusterName", config.Spec.ClusterConfiguration.ClusterName) - } + // Use Cluster.Name + data.ClusterName = ptr.To(cluster.Name) - // If there are no Network settings defined in ClusterConfiguration, use ClusterNetwork settings, if defined + // Use ClusterNetwork settings, if defined if cluster.Spec.ClusterNetwork != nil { - if config.Spec.ClusterConfiguration.Networking.DNSDomain == "" && cluster.Spec.ClusterNetwork.ServiceDomain != "" { - config.Spec.ClusterConfiguration.Networking.DNSDomain = cluster.Spec.ClusterNetwork.ServiceDomain - log.V(3).Info("Altering ClusterConfiguration.Networking.DNSDomain", "dnsDomain", config.Spec.ClusterConfiguration.Networking.DNSDomain) + if cluster.Spec.ClusterNetwork.ServiceDomain != "" { + data.DNSDomain = ptr.To(cluster.Spec.ClusterNetwork.ServiceDomain) } - if config.Spec.ClusterConfiguration.Networking.ServiceSubnet == "" && - cluster.Spec.ClusterNetwork.Services != nil && + if cluster.Spec.ClusterNetwork.Services != nil && len(cluster.Spec.ClusterNetwork.Services.CIDRBlocks) > 0 { - config.Spec.ClusterConfiguration.Networking.ServiceSubnet = cluster.Spec.ClusterNetwork.Services.String() - log.V(3).Info("Altering ClusterConfiguration.Networking.ServiceSubnet", "serviceSubnet", config.Spec.ClusterConfiguration.Networking.ServiceSubnet) + data.ServiceSubnet = ptr.To(cluster.Spec.ClusterNetwork.Services.String()) } - if config.Spec.ClusterConfiguration.Networking.PodSubnet == "" && - cluster.Spec.ClusterNetwork.Pods != nil && + if cluster.Spec.ClusterNetwork.Pods != nil && len(cluster.Spec.ClusterNetwork.Pods.CIDRBlocks) > 0 { - config.Spec.ClusterConfiguration.Networking.PodSubnet = cluster.Spec.ClusterNetwork.Pods.String() - log.V(3).Info("Altering ClusterConfiguration.Networking.PodSubnet", "podSubnet", config.Spec.ClusterConfiguration.Networking.PodSubnet) + data.PodSubnet = ptr.To(cluster.Spec.ClusterNetwork.Pods.String()) } } - // If there are no KubernetesVersion settings defined in ClusterConfiguration, use Version from machine, if defined - if config.Spec.ClusterConfiguration.KubernetesVersion == "" && machine.Spec.Version != nil { - config.Spec.ClusterConfiguration.KubernetesVersion = *machine.Spec.Version - log.V(3).Info("Altering ClusterConfiguration.KubernetesVersion", "kubernetesVersion", config.Spec.ClusterConfiguration.KubernetesVersion) + // Use Version from machine, if defined + if machine.Spec.Version != nil { + data.KubernetesVersion = machine.Spec.Version } + + // Use ControlPlaneComponentHealthCheckSeconds from init configuration + // Note. initConfiguration.Timeouts.ControlPlaneComponentHealthCheckSeconds in v1beta3 kubeadm's API + // was part of ClusterConfiguration, so we have to bring it back as additional data. + if initConfiguration != nil && initConfiguration.Timeouts != nil && initConfiguration.Timeouts.ControlPlaneComponentHealthCheckSeconds != nil { + data.ControlPlaneComponentHealthCheckSeconds = initConfiguration.Timeouts.ControlPlaneComponentHealthCheckSeconds + } + + return data } // storeBootstrapData creates a new secret with the data passed in as input, diff --git a/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller_test.go b/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller_test.go index 5f3b047e7d0d..899973a36947 100644 --- a/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller_test.go +++ b/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller_test.go @@ -1832,57 +1832,18 @@ func TestKubeadmConfigReconciler_Reconcile_DiscoveryReconcileFailureBehaviors(t } // Set cluster configuration defaults based on dynamic values from the cluster object. -func TestKubeadmConfigReconciler_Reconcile_DynamicDefaultsForClusterConfiguration(t *testing.T) { +func TestKubeadmConfigReconciler_computeClusterConfigurationAdditionalData(t *testing.T) { k := &KubeadmConfigReconciler{} testcases := []struct { - name string - cluster *clusterv1.Cluster - machine *clusterv1.Machine - config *bootstrapv1.KubeadmConfig + name string + cluster *clusterv1.Cluster + machine *clusterv1.Machine + config *bootstrapv1.KubeadmConfig + initConfiguration *bootstrapv1.InitConfiguration }{ { - name: "Config settings have precedence", - config: &bootstrapv1.KubeadmConfig{ - Spec: bootstrapv1.KubeadmConfigSpec{ - ClusterConfiguration: &bootstrapv1.ClusterConfiguration{ - ClusterName: "mycluster", - KubernetesVersion: "myversion", - Networking: bootstrapv1.Networking{ - PodSubnet: "myPodSubnet", - ServiceSubnet: "myServiceSubnet", - DNSDomain: "myDNSDomain", - }, - ControlPlaneEndpoint: "myControlPlaneEndpoint:6443", - }, - }, - }, - cluster: &clusterv1.Cluster{ - ObjectMeta: metav1.ObjectMeta{ - Name: "OtherName", - }, - Spec: clusterv1.ClusterSpec{ - ClusterNetwork: &clusterv1.ClusterNetwork{ - Services: &clusterv1.NetworkRanges{CIDRBlocks: []string{"otherServicesCidr"}}, - Pods: &clusterv1.NetworkRanges{CIDRBlocks: []string{"otherPodsCidr"}}, - ServiceDomain: "otherServiceDomain", - }, - ControlPlaneEndpoint: clusterv1.APIEndpoint{Host: "otherVersion", Port: 0}, - }, - }, - machine: &clusterv1.Machine{ - Spec: clusterv1.MachineSpec{ - Version: ptr.To("otherVersion"), - }, - }, - }, - { - name: "Top level object settings are used in case config settings are missing", - config: &bootstrapv1.KubeadmConfig{ - Spec: bootstrapv1.KubeadmConfigSpec{ - ClusterConfiguration: &bootstrapv1.ClusterConfiguration{}, - }, - }, + name: "Propagate fields from Cluster & Machine & initConfiguration", cluster: &clusterv1.Cluster{ ObjectMeta: metav1.ObjectMeta{ Name: "mycluster", @@ -1898,7 +1859,12 @@ func TestKubeadmConfigReconciler_Reconcile_DynamicDefaultsForClusterConfiguratio }, machine: &clusterv1.Machine{ Spec: clusterv1.MachineSpec{ - Version: ptr.To("myversion"), + Version: ptr.To("v1.23.0"), + }, + }, + initConfiguration: &bootstrapv1.InitConfiguration{ + Timeouts: &bootstrapv1.Timeouts{ + ControlPlaneComponentHealthCheckSeconds: ptr.To[int32](10), }, }, }, @@ -1908,14 +1874,14 @@ func TestKubeadmConfigReconciler_Reconcile_DynamicDefaultsForClusterConfiguratio t.Run(tc.name, func(t *testing.T) { g := NewWithT(t) - k.reconcileTopLevelObjectSettings(ctx, tc.cluster, tc.machine, tc.config) - - g.Expect(tc.config.Spec.ClusterConfiguration.ControlPlaneEndpoint).To(Equal("myControlPlaneEndpoint:6443")) - g.Expect(tc.config.Spec.ClusterConfiguration.ClusterName).To(Equal("mycluster")) - g.Expect(tc.config.Spec.ClusterConfiguration.Networking.PodSubnet).To(Equal("myPodSubnet")) - g.Expect(tc.config.Spec.ClusterConfiguration.Networking.ServiceSubnet).To(Equal("myServiceSubnet")) - g.Expect(tc.config.Spec.ClusterConfiguration.Networking.DNSDomain).To(Equal("myDNSDomain")) - g.Expect(tc.config.Spec.ClusterConfiguration.KubernetesVersion).To(Equal("myversion")) + gotData := k.computeClusterConfigurationAdditionalData(tc.cluster, tc.machine, tc.initConfiguration) + g.Expect(gotData.KubernetesVersion).To(Equal(ptr.To("v1.23.0"))) + g.Expect(gotData.ControlPlaneEndpoint).To(Equal(ptr.To("myControlPlaneEndpoint:6443"))) + g.Expect(gotData.ClusterName).To(Equal(ptr.To("mycluster"))) + g.Expect(gotData.PodSubnet).To(Equal(ptr.To("myPodSubnet"))) + g.Expect(gotData.ServiceSubnet).To(Equal(ptr.To("myServiceSubnet"))) + g.Expect(gotData.DNSDomain).To(Equal(ptr.To("myDNSDomain"))) + g.Expect(gotData.ControlPlaneComponentHealthCheckSeconds).To(Equal(ptr.To[int32](10))) }) } } diff --git a/bootstrap/kubeadm/types/upstream/upstream.go b/bootstrap/kubeadm/types/upstream/upstream.go new file mode 100644 index 000000000000..226558142600 --- /dev/null +++ b/bootstrap/kubeadm/types/upstream/upstream.go @@ -0,0 +1,61 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package upstream contains types to handle additional data during Marshal or UnMarshal of kubeadm's types. +// +// In this context "Additional data" refers to data existing in the kubeadm's types, but not included in the +// corresponding Cluster API types, or migrated from one struct to another in one of the older versions +// of the kubeadm's types. +package upstream + +// AdditionalDataSetter defines capabilities of a type to set additional data. +type AdditionalDataSetter interface { + SetAdditionalData(data AdditionalData) +} + +// AdditionalDataGetter defines capabilities of a type to get additional data. +type AdditionalDataGetter interface { + GetAdditionalData(*AdditionalData) +} + +// AdditionalData is additional data that must go in kubeadm's ClusterConfiguration, but exists +// in different Cluster API objects, like e.g. the Cluster object. +type AdditionalData struct { + // Data from Cluster API's Cluster object. + KubernetesVersion *string + ClusterName *string + ControlPlaneEndpoint *string + DNSDomain *string + ServiceSubnet *string + PodSubnet *string + + // Data migrated from ClusterConfiguration to InitConfiguration in kubeadm's v1beta4 API version. + // Note: Corresponding Cluster API types are aligned with kubeadm's v1beta4 API version. + ControlPlaneComponentHealthCheckSeconds *int32 +} + +// Clone returns a clone of AdditionalData. +func (a *AdditionalData) Clone() *AdditionalData { + return &AdditionalData{ + KubernetesVersion: a.KubernetesVersion, + ClusterName: a.ClusterName, + ControlPlaneEndpoint: a.ControlPlaneEndpoint, + DNSDomain: a.DNSDomain, + ServiceSubnet: a.ServiceSubnet, + PodSubnet: a.PodSubnet, + ControlPlaneComponentHealthCheckSeconds: a.ControlPlaneComponentHealthCheckSeconds, + } +} diff --git a/bootstrap/kubeadm/types/upstreamv1beta3/conversion.go b/bootstrap/kubeadm/types/upstreamv1beta3/conversion.go index 025e4bcf1da7..a73b723793ab 100644 --- a/bootstrap/kubeadm/types/upstreamv1beta3/conversion.go +++ b/bootstrap/kubeadm/types/upstreamv1beta3/conversion.go @@ -17,11 +17,12 @@ limitations under the License. package upstreamv1beta3 import ( - "github.com/pkg/errors" apimachineryconversion "k8s.io/apimachinery/pkg/conversion" + "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/conversion" bootstrapv1 "sigs.k8s.io/cluster-api/api/bootstrap/kubeadm/v1beta2" + "sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/upstream" ) func (src *ClusterConfiguration) ConvertTo(dstRaw conversion.Hub) error { @@ -56,6 +57,10 @@ func (dst *JoinConfiguration) ConvertFrom(srcRaw conversion.Hub) error { // Custom conversion from this API, kubeadm v1beta3, to the hub version, CABPK v1beta1. +func Convert_upstreamv1beta3_ClusterConfiguration_To_v1beta2_ClusterConfiguration(in *ClusterConfiguration, out *bootstrapv1.ClusterConfiguration, s apimachineryconversion.Scope) error { + return autoConvert_upstreamv1beta3_ClusterConfiguration_To_v1beta2_ClusterConfiguration(in, out, s) +} + func Convert_upstreamv1beta3_InitConfiguration_To_v1beta2_InitConfiguration(in *InitConfiguration, out *bootstrapv1.InitConfiguration, s apimachineryconversion.Scope) error { // InitConfiguration.CertificateKey does not exist in CABPK, because Cluster API does not use automatic copy certs. return autoConvert_upstreamv1beta3_InitConfiguration_To_v1beta2_InitConfiguration(in, out, s) @@ -155,28 +160,67 @@ func Convert_v1beta2_NodeRegistrationOptions_To_upstreamv1beta3_NodeRegistration return autoConvert_v1beta2_NodeRegistrationOptions_To_upstreamv1beta3_NodeRegistrationOptions(in, out, s) } -// Custom conversions to handle fields migrated from ClusterConfiguration to Init and JoinConfiguration in the kubeadm v1beta4 API version. +// Func to allow handling fields that only exist in upstream types. + +var _ upstream.AdditionalDataSetter = &ClusterConfiguration{} -func (dst *ClusterConfiguration) ConvertFromInitConfiguration(initConfiguration *bootstrapv1.InitConfiguration) error { - if initConfiguration == nil || initConfiguration.Timeouts == nil || initConfiguration.Timeouts.ControlPlaneComponentHealthCheckSeconds == nil { - return nil +func (src *ClusterConfiguration) SetAdditionalData(data upstream.AdditionalData) { + if src == nil { + return } - dst.APIServer.TimeoutForControlPlane = bootstrapv1.ConvertFromSeconds(initConfiguration.Timeouts.ControlPlaneComponentHealthCheckSeconds) - return nil + if data.KubernetesVersion != nil { + src.KubernetesVersion = *data.KubernetesVersion + } + if data.ClusterName != nil { + src.ClusterName = *data.ClusterName + } + if data.ControlPlaneEndpoint != nil { + src.ControlPlaneEndpoint = *data.ControlPlaneEndpoint + } + if data.DNSDomain != nil { + src.Networking.DNSDomain = *data.DNSDomain + } + if data.ServiceSubnet != nil { + src.Networking.ServiceSubnet = *data.ServiceSubnet + } + if data.PodSubnet != nil { + src.Networking.PodSubnet = *data.PodSubnet + } + if data.ControlPlaneComponentHealthCheckSeconds != nil { + src.APIServer.TimeoutForControlPlane = bootstrapv1.ConvertFromSeconds(data.ControlPlaneComponentHealthCheckSeconds) + } } -func (src *ClusterConfiguration) ConvertToInitConfiguration(initConfiguration *bootstrapv1.InitConfiguration) error { - if src.APIServer.TimeoutForControlPlane == nil { - return nil +var _ upstream.AdditionalDataGetter = &ClusterConfiguration{} + +func (src *ClusterConfiguration) GetAdditionalData(data *upstream.AdditionalData) { + if src == nil { + return + } + if data == nil { + return } - if initConfiguration == nil { - return errors.New("cannot convert ClusterConfiguration to a nil InitConfiguration") + if src.KubernetesVersion != "" { + data.KubernetesVersion = ptr.To(src.KubernetesVersion) } - if initConfiguration.Timeouts == nil { - initConfiguration.Timeouts = &bootstrapv1.Timeouts{} + if src.ClusterName != "" { + data.ClusterName = ptr.To(src.ClusterName) + } + if src.ControlPlaneEndpoint != "" { + data.ControlPlaneEndpoint = ptr.To(src.ControlPlaneEndpoint) + } + if src.Networking.DNSDomain != "" { + data.DNSDomain = ptr.To(src.Networking.DNSDomain) + } + if src.Networking.ServiceSubnet != "" { + data.ServiceSubnet = ptr.To(src.Networking.ServiceSubnet) + } + if src.Networking.PodSubnet != "" { + data.PodSubnet = ptr.To(src.Networking.PodSubnet) + } + if src.APIServer.TimeoutForControlPlane != nil { + data.ControlPlaneComponentHealthCheckSeconds = bootstrapv1.ConvertToSeconds(src.APIServer.TimeoutForControlPlane) } - initConfiguration.Timeouts.ControlPlaneComponentHealthCheckSeconds = bootstrapv1.ConvertToSeconds(src.APIServer.TimeoutForControlPlane) - return nil } diff --git a/bootstrap/kubeadm/types/upstreamv1beta3/conversion_no_fuzz_test.go b/bootstrap/kubeadm/types/upstreamv1beta3/conversion_no_fuzz_test.go deleted file mode 100644 index 5c2048c15057..000000000000 --- a/bootstrap/kubeadm/types/upstreamv1beta3/conversion_no_fuzz_test.go +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright 2025 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package upstreamv1beta3 - -import ( - "testing" - - . "github.com/onsi/gomega" - "k8s.io/utils/ptr" - - bootstrapv1 "sigs.k8s.io/cluster-api/api/bootstrap/kubeadm/v1beta2" -) - -// This test case has been moved out of conversion_test.go because it should be run with the race detector. -// Note: The tests in conversion_test.go are disabled when the race detector is enabled (via "//go:build !race") because otherwise the fuzz tests would just time out. - -func TestTimeoutForControlPlaneMigration(t *testing.T) { - t.Run("from InitConfiguration to ClusterConfiguration and back", func(t *testing.T) { - g := NewWithT(t) - - initConfiguration := &bootstrapv1.InitConfiguration{ - Timeouts: &bootstrapv1.Timeouts{ - ControlPlaneComponentHealthCheckSeconds: ptr.To[int32](123), - }, - } - - clusterConfiguration := &ClusterConfiguration{} - err := clusterConfiguration.ConvertFromInitConfiguration(initConfiguration) - g.Expect(err).ToNot(HaveOccurred()) - - initConfiguration = &bootstrapv1.InitConfiguration{} - err = clusterConfiguration.ConvertToInitConfiguration(initConfiguration) - g.Expect(err).ToNot(HaveOccurred()) - g.Expect(initConfiguration.Timeouts.ControlPlaneComponentHealthCheckSeconds).To(Equal(ptr.To[int32](123))) - }) -} diff --git a/bootstrap/kubeadm/types/upstreamv1beta3/conversion_test.go b/bootstrap/kubeadm/types/upstreamv1beta3/conversion_test.go index 7488d95f63d0..5eb6601f7a83 100644 --- a/bootstrap/kubeadm/types/upstreamv1beta3/conversion_test.go +++ b/bootstrap/kubeadm/types/upstreamv1beta3/conversion_test.go @@ -48,7 +48,7 @@ func TestFuzzyConversion(t *testing.T) { Spoke: &ClusterConfiguration{}, // NOTE: Kubeadm types does not have ObjectMeta, so we are required to skip data annotation cleanup in the spoke-hub-spoke round trip test. SkipSpokeAnnotationCleanup: true, - FuzzerFuncs: []fuzzer.FuzzerFuncs{fuzzFuncs}, + FuzzerFuncs: []fuzzer.FuzzerFuncs{fuzzFuncs, clusterConfigurationFuzzFuncs}, })) t.Run("for InitConfiguration", utilconversion.FuzzTestFunc(utilconversion.FuzzTestFuncInput{ Scheme: scheme, @@ -83,10 +83,28 @@ func fuzzFuncs(_ runtimeserializer.CodecFactory) []interface{} { } } +func clusterConfigurationFuzzFuncs(_ runtimeserializer.CodecFactory) []interface{} { + return []interface{}{ + spokeClusterConfigurationFuzzer, + } +} + // Custom fuzzers for kubeadm v1beta3 types. // NOTES: // - When fields do not exist in cabpk v1beta1 types, pinning it to avoid kubeadm v1beta3 --> cabpk v1beta1 --> kubeadm v1beta3 round trip errors. +func spokeClusterConfigurationFuzzer(in *ClusterConfiguration, c randfill.Continue) { + c.FillNoCustom(in) + + // Drop the following fields as they have been removed in v1beta2, so we don't have to preserve them. + in.Networking.ServiceSubnet = "" + in.Networking.PodSubnet = "" + in.Networking.DNSDomain = "" + in.KubernetesVersion = "" + in.ControlPlaneEndpoint = "" + in.ClusterName = "" +} + func spokeInitConfigurationFuzzer(obj *InitConfiguration, c randfill.Continue) { c.FillNoCustom(obj) diff --git a/bootstrap/kubeadm/types/upstreamv1beta3/zz_generated.conversion.go b/bootstrap/kubeadm/types/upstreamv1beta3/zz_generated.conversion.go index cdb3a5225824..39b1ef5d90bf 100644 --- a/bootstrap/kubeadm/types/upstreamv1beta3/zz_generated.conversion.go +++ b/bootstrap/kubeadm/types/upstreamv1beta3/zz_generated.conversion.go @@ -83,11 +83,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*ClusterConfiguration)(nil), (*v1beta2.ClusterConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_upstreamv1beta3_ClusterConfiguration_To_v1beta2_ClusterConfiguration(a.(*ClusterConfiguration), b.(*v1beta2.ClusterConfiguration), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*v1beta2.ClusterConfiguration)(nil), (*ClusterConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta2_ClusterConfiguration_To_upstreamv1beta3_ClusterConfiguration(a.(*v1beta2.ClusterConfiguration), b.(*ClusterConfiguration), scope) }); err != nil { @@ -158,16 +153,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*Networking)(nil), (*v1beta2.Networking)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_upstreamv1beta3_Networking_To_v1beta2_Networking(a.(*Networking), b.(*v1beta2.Networking), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*v1beta2.Networking)(nil), (*Networking)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta2_Networking_To_upstreamv1beta3_Networking(a.(*v1beta2.Networking), b.(*Networking), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*Patches)(nil), (*v1beta2.Patches)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_upstreamv1beta3_Patches_To_v1beta2_Patches(a.(*Patches), b.(*v1beta2.Patches), scope) }); err != nil { @@ -183,6 +168,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*ClusterConfiguration)(nil), (*v1beta2.ClusterConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_upstreamv1beta3_ClusterConfiguration_To_v1beta2_ClusterConfiguration(a.(*ClusterConfiguration), b.(*v1beta2.ClusterConfiguration), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*ControlPlaneComponent)(nil), (*v1beta2.ControlPlaneComponent)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_upstreamv1beta3_ControlPlaneComponent_To_v1beta2_ControlPlaneComponent(a.(*ControlPlaneComponent), b.(*v1beta2.ControlPlaneComponent), scope) }); err != nil { @@ -377,11 +367,9 @@ func autoConvert_upstreamv1beta3_ClusterConfiguration_To_v1beta2_ClusterConfigur if err := Convert_upstreamv1beta3_Etcd_To_v1beta2_Etcd(&in.Etcd, &out.Etcd, s); err != nil { return err } - if err := Convert_upstreamv1beta3_Networking_To_v1beta2_Networking(&in.Networking, &out.Networking, s); err != nil { - return err - } - out.KubernetesVersion = in.KubernetesVersion - out.ControlPlaneEndpoint = in.ControlPlaneEndpoint + // WARNING: in.Networking requires manual conversion: does not exist in peer-type + // WARNING: in.KubernetesVersion requires manual conversion: does not exist in peer-type + // WARNING: in.ControlPlaneEndpoint requires manual conversion: does not exist in peer-type if err := Convert_upstreamv1beta3_APIServer_To_v1beta2_APIServer(&in.APIServer, &out.APIServer, s); err != nil { return err } @@ -397,24 +385,14 @@ func autoConvert_upstreamv1beta3_ClusterConfiguration_To_v1beta2_ClusterConfigur out.CertificatesDir = in.CertificatesDir out.ImageRepository = in.ImageRepository out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates)) - out.ClusterName = in.ClusterName + // WARNING: in.ClusterName requires manual conversion: does not exist in peer-type return nil } -// Convert_upstreamv1beta3_ClusterConfiguration_To_v1beta2_ClusterConfiguration is an autogenerated conversion function. -func Convert_upstreamv1beta3_ClusterConfiguration_To_v1beta2_ClusterConfiguration(in *ClusterConfiguration, out *v1beta2.ClusterConfiguration, s conversion.Scope) error { - return autoConvert_upstreamv1beta3_ClusterConfiguration_To_v1beta2_ClusterConfiguration(in, out, s) -} - func autoConvert_v1beta2_ClusterConfiguration_To_upstreamv1beta3_ClusterConfiguration(in *v1beta2.ClusterConfiguration, out *ClusterConfiguration, s conversion.Scope) error { if err := Convert_v1beta2_Etcd_To_upstreamv1beta3_Etcd(&in.Etcd, &out.Etcd, s); err != nil { return err } - if err := Convert_v1beta2_Networking_To_upstreamv1beta3_Networking(&in.Networking, &out.Networking, s); err != nil { - return err - } - out.KubernetesVersion = in.KubernetesVersion - out.ControlPlaneEndpoint = in.ControlPlaneEndpoint if err := Convert_v1beta2_APIServer_To_upstreamv1beta3_APIServer(&in.APIServer, &out.APIServer, s); err != nil { return err } @@ -430,7 +408,6 @@ func autoConvert_v1beta2_ClusterConfiguration_To_upstreamv1beta3_ClusterConfigur out.CertificatesDir = in.CertificatesDir out.ImageRepository = in.ImageRepository out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates)) - out.ClusterName = in.ClusterName return nil } @@ -758,30 +735,6 @@ func autoConvert_v1beta2_LocalEtcd_To_upstreamv1beta3_LocalEtcd(in *v1beta2.Loca return nil } -func autoConvert_upstreamv1beta3_Networking_To_v1beta2_Networking(in *Networking, out *v1beta2.Networking, s conversion.Scope) error { - out.ServiceSubnet = in.ServiceSubnet - out.PodSubnet = in.PodSubnet - out.DNSDomain = in.DNSDomain - return nil -} - -// Convert_upstreamv1beta3_Networking_To_v1beta2_Networking is an autogenerated conversion function. -func Convert_upstreamv1beta3_Networking_To_v1beta2_Networking(in *Networking, out *v1beta2.Networking, s conversion.Scope) error { - return autoConvert_upstreamv1beta3_Networking_To_v1beta2_Networking(in, out, s) -} - -func autoConvert_v1beta2_Networking_To_upstreamv1beta3_Networking(in *v1beta2.Networking, out *Networking, s conversion.Scope) error { - out.ServiceSubnet = in.ServiceSubnet - out.PodSubnet = in.PodSubnet - out.DNSDomain = in.DNSDomain - return nil -} - -// Convert_v1beta2_Networking_To_upstreamv1beta3_Networking is an autogenerated conversion function. -func Convert_v1beta2_Networking_To_upstreamv1beta3_Networking(in *v1beta2.Networking, out *Networking, s conversion.Scope) error { - return autoConvert_v1beta2_Networking_To_upstreamv1beta3_Networking(in, out, s) -} - func autoConvert_upstreamv1beta3_NodeRegistrationOptions_To_v1beta2_NodeRegistrationOptions(in *NodeRegistrationOptions, out *v1beta2.NodeRegistrationOptions, s conversion.Scope) error { out.Name = in.Name out.CRISocket = in.CRISocket diff --git a/bootstrap/kubeadm/types/upstreamv1beta4/conversion.go b/bootstrap/kubeadm/types/upstreamv1beta4/conversion.go index 89e3fbf29d18..92752581a5a5 100644 --- a/bootstrap/kubeadm/types/upstreamv1beta4/conversion.go +++ b/bootstrap/kubeadm/types/upstreamv1beta4/conversion.go @@ -18,9 +18,11 @@ package upstreamv1beta4 import ( apimachineryconversion "k8s.io/apimachinery/pkg/conversion" + "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/conversion" bootstrapv1 "sigs.k8s.io/cluster-api/api/bootstrap/kubeadm/v1beta2" + "sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/upstream" ) func (src *ClusterConfiguration) ConvertTo(dstRaw conversion.Hub) error { @@ -136,3 +138,68 @@ func Convert_v1beta2_Timeouts_To_upstreamv1beta4_Timeouts(in *bootstrapv1.Timeou out.Discovery = bootstrapv1.ConvertFromSeconds(in.DiscoverySeconds) return nil } + +// Func to allow handling fields that only exist in upstream types. + +var _ upstream.AdditionalDataSetter = &ClusterConfiguration{} + +func (src *ClusterConfiguration) SetAdditionalData(data upstream.AdditionalData) { + if src == nil { + return + } + + if data.KubernetesVersion != nil { + src.KubernetesVersion = *data.KubernetesVersion + } + if data.ClusterName != nil { + src.ClusterName = *data.ClusterName + } + if data.ControlPlaneEndpoint != nil { + src.ControlPlaneEndpoint = *data.ControlPlaneEndpoint + } + if data.DNSDomain != nil { + src.Networking.DNSDomain = *data.DNSDomain + } + if data.ServiceSubnet != nil { + src.Networking.ServiceSubnet = *data.ServiceSubnet + } + if data.PodSubnet != nil { + src.Networking.PodSubnet = *data.PodSubnet + } + + // NOTE: for kubeadm v1beta4 types we are not setting APIServer.TimeoutForControlPlane because it doesn't exist + // (the timeout is configured in InitConfiguration / JoinConfiguration instead). +} + +var _ upstream.AdditionalDataGetter = &ClusterConfiguration{} + +func (src *ClusterConfiguration) GetAdditionalData(data *upstream.AdditionalData) { + if src == nil { + return + } + if data == nil { + return + } + + if src.KubernetesVersion != "" { + data.KubernetesVersion = ptr.To(src.KubernetesVersion) + } + if src.ClusterName != "" { + data.ClusterName = ptr.To(src.ClusterName) + } + if src.ControlPlaneEndpoint != "" { + data.ControlPlaneEndpoint = ptr.To(src.ControlPlaneEndpoint) + } + if src.Networking.DNSDomain != "" { + data.DNSDomain = ptr.To(src.Networking.DNSDomain) + } + if src.Networking.ServiceSubnet != "" { + data.ServiceSubnet = ptr.To(src.Networking.ServiceSubnet) + } + if src.Networking.PodSubnet != "" { + data.PodSubnet = ptr.To(src.Networking.PodSubnet) + } + + // NOTE: for kubeadm v1beta4 types we are not reading ControlPlaneComponentHealthCheckSeconds into additional data + // because Cluster API types are aligned with kubeadm's v1beta4 API version. +} diff --git a/bootstrap/kubeadm/types/upstreamv1beta4/conversion_test.go b/bootstrap/kubeadm/types/upstreamv1beta4/conversion_test.go index e62bd6e949b0..dab2c0f94e8a 100644 --- a/bootstrap/kubeadm/types/upstreamv1beta4/conversion_test.go +++ b/bootstrap/kubeadm/types/upstreamv1beta4/conversion_test.go @@ -91,6 +91,14 @@ func spokeClusterConfigurationFuzzer(obj *ClusterConfiguration, c randfill.Conti obj.EncryptionAlgorithm = "" obj.CACertificateValidityPeriod = nil obj.CertificateValidityPeriod = nil + + // Drop the following fields as they have been removed in v1beta2, so we don't have to preserve them. + obj.Networking.ServiceSubnet = "" + obj.Networking.PodSubnet = "" + obj.Networking.DNSDomain = "" + obj.KubernetesVersion = "" + obj.ControlPlaneEndpoint = "" + obj.ClusterName = "" } func spokeDNSFuzzer(obj *DNS, c randfill.Continue) { diff --git a/bootstrap/kubeadm/types/upstreamv1beta4/zz_generated.conversion.go b/bootstrap/kubeadm/types/upstreamv1beta4/zz_generated.conversion.go index fb289363379d..b9585f71003b 100644 --- a/bootstrap/kubeadm/types/upstreamv1beta4/zz_generated.conversion.go +++ b/bootstrap/kubeadm/types/upstreamv1beta4/zz_generated.conversion.go @@ -198,16 +198,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*Networking)(nil), (*v1beta2.Networking)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_upstreamv1beta4_Networking_To_v1beta2_Networking(a.(*Networking), b.(*v1beta2.Networking), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*v1beta2.Networking)(nil), (*Networking)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta2_Networking_To_upstreamv1beta4_Networking(a.(*v1beta2.Networking), b.(*Networking), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*NodeRegistrationOptions)(nil), (*v1beta2.NodeRegistrationOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_upstreamv1beta4_NodeRegistrationOptions_To_v1beta2_NodeRegistrationOptions(a.(*NodeRegistrationOptions), b.(*v1beta2.NodeRegistrationOptions), scope) }); err != nil { @@ -428,11 +418,9 @@ func autoConvert_upstreamv1beta4_ClusterConfiguration_To_v1beta2_ClusterConfigur if err := Convert_upstreamv1beta4_Etcd_To_v1beta2_Etcd(&in.Etcd, &out.Etcd, s); err != nil { return err } - if err := Convert_upstreamv1beta4_Networking_To_v1beta2_Networking(&in.Networking, &out.Networking, s); err != nil { - return err - } - out.KubernetesVersion = in.KubernetesVersion - out.ControlPlaneEndpoint = in.ControlPlaneEndpoint + // WARNING: in.Networking requires manual conversion: does not exist in peer-type + // WARNING: in.KubernetesVersion requires manual conversion: does not exist in peer-type + // WARNING: in.ControlPlaneEndpoint requires manual conversion: does not exist in peer-type if err := Convert_upstreamv1beta4_APIServer_To_v1beta2_APIServer(&in.APIServer, &out.APIServer, s); err != nil { return err } @@ -449,7 +437,7 @@ func autoConvert_upstreamv1beta4_ClusterConfiguration_To_v1beta2_ClusterConfigur out.CertificatesDir = in.CertificatesDir out.ImageRepository = in.ImageRepository out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates)) - out.ClusterName = in.ClusterName + // WARNING: in.ClusterName requires manual conversion: does not exist in peer-type // WARNING: in.EncryptionAlgorithm requires manual conversion: does not exist in peer-type // WARNING: in.CertificateValidityPeriod requires manual conversion: does not exist in peer-type // WARNING: in.CACertificateValidityPeriod requires manual conversion: does not exist in peer-type @@ -460,11 +448,6 @@ func autoConvert_v1beta2_ClusterConfiguration_To_upstreamv1beta4_ClusterConfigur if err := Convert_v1beta2_Etcd_To_upstreamv1beta4_Etcd(&in.Etcd, &out.Etcd, s); err != nil { return err } - if err := Convert_v1beta2_Networking_To_upstreamv1beta4_Networking(&in.Networking, &out.Networking, s); err != nil { - return err - } - out.KubernetesVersion = in.KubernetesVersion - out.ControlPlaneEndpoint = in.ControlPlaneEndpoint if err := Convert_v1beta2_APIServer_To_upstreamv1beta4_APIServer(&in.APIServer, &out.APIServer, s); err != nil { return err } @@ -480,7 +463,6 @@ func autoConvert_v1beta2_ClusterConfiguration_To_upstreamv1beta4_ClusterConfigur out.CertificatesDir = in.CertificatesDir out.ImageRepository = in.ImageRepository out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates)) - out.ClusterName = in.ClusterName return nil } @@ -875,30 +857,6 @@ func Convert_v1beta2_LocalEtcd_To_upstreamv1beta4_LocalEtcd(in *v1beta2.LocalEtc return autoConvert_v1beta2_LocalEtcd_To_upstreamv1beta4_LocalEtcd(in, out, s) } -func autoConvert_upstreamv1beta4_Networking_To_v1beta2_Networking(in *Networking, out *v1beta2.Networking, s conversion.Scope) error { - out.ServiceSubnet = in.ServiceSubnet - out.PodSubnet = in.PodSubnet - out.DNSDomain = in.DNSDomain - return nil -} - -// Convert_upstreamv1beta4_Networking_To_v1beta2_Networking is an autogenerated conversion function. -func Convert_upstreamv1beta4_Networking_To_v1beta2_Networking(in *Networking, out *v1beta2.Networking, s conversion.Scope) error { - return autoConvert_upstreamv1beta4_Networking_To_v1beta2_Networking(in, out, s) -} - -func autoConvert_v1beta2_Networking_To_upstreamv1beta4_Networking(in *v1beta2.Networking, out *Networking, s conversion.Scope) error { - out.ServiceSubnet = in.ServiceSubnet - out.PodSubnet = in.PodSubnet - out.DNSDomain = in.DNSDomain - return nil -} - -// Convert_v1beta2_Networking_To_upstreamv1beta4_Networking is an autogenerated conversion function. -func Convert_v1beta2_Networking_To_upstreamv1beta4_Networking(in *v1beta2.Networking, out *Networking, s conversion.Scope) error { - return autoConvert_v1beta2_Networking_To_upstreamv1beta4_Networking(in, out, s) -} - func autoConvert_upstreamv1beta4_NodeRegistrationOptions_To_v1beta2_NodeRegistrationOptions(in *NodeRegistrationOptions, out *v1beta2.NodeRegistrationOptions, s conversion.Scope) error { out.Name = in.Name out.CRISocket = in.CRISocket diff --git a/bootstrap/kubeadm/types/utils.go b/bootstrap/kubeadm/types/utils.go index 956abea86da4..67f4ae6b4c0e 100644 --- a/bootstrap/kubeadm/types/utils.go +++ b/bootstrap/kubeadm/types/utils.go @@ -27,6 +27,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/scheme" bootstrapv1 "sigs.k8s.io/cluster-api/api/bootstrap/kubeadm/v1beta2" + "sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/upstream" "sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/upstreamv1beta3" "sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/upstreamv1beta4" "sigs.k8s.io/cluster-api/util/version" @@ -52,18 +53,6 @@ var ( } ) -// ConvertibleFromInitConfiguration defines capabilities of a type that during conversions gets values from initConfiguration. -// NOTE: this interface is specifically designed to handle fields migrated from ClusterConfiguration to InitConfiguration in the kubeadm v1beta4 API version. -type ConvertibleFromInitConfiguration interface { - ConvertFromInitConfiguration(initConfiguration *bootstrapv1.InitConfiguration) error -} - -// ConvertibleToInitConfiguration defines capabilities of a type that during conversions sets values to initConfiguration. -// NOTE: this interface is specifically designed to handle fields migrated from ClusterConfiguration to InitConfiguration in the kubeadm v1beta4 API version. -type ConvertibleToInitConfiguration interface { - ConvertToInitConfiguration(initConfiguration *bootstrapv1.InitConfiguration) error -} - // KubeVersionToKubeadmAPIGroupVersion maps a Kubernetes version to the correct Kubeadm API Group supported. func KubeVersionToKubeadmAPIGroupVersion(v semver.Version) (schema.GroupVersion, error) { switch { @@ -83,25 +72,25 @@ func KubeVersionToKubeadmAPIGroupVersion(v semver.Version) (schema.GroupVersion, // MarshalClusterConfigurationForVersion converts a Cluster API ClusterConfiguration type to the kubeadm API type // for the given Kubernetes Version. // NOTE: This assumes Kubernetes Version equals to kubeadm version. -func MarshalClusterConfigurationForVersion(initConfiguration *bootstrapv1.InitConfiguration, clusterConfiguration *bootstrapv1.ClusterConfiguration, version semver.Version) (string, error) { - return marshalForVersion(initConfiguration, clusterConfiguration, version, clusterConfigurationVersionTypeMap) +func MarshalClusterConfigurationForVersion(clusterConfiguration *bootstrapv1.ClusterConfiguration, version semver.Version, data *upstream.AdditionalData) (string, error) { + return marshalForVersion(clusterConfiguration, version, clusterConfigurationVersionTypeMap, data) } // MarshalInitConfigurationForVersion converts a Cluster API InitConfiguration type to the kubeadm API type // for the given Kubernetes Version. // NOTE: This assumes Kubernetes Version equals to kubeadm version. func MarshalInitConfigurationForVersion(initConfiguration *bootstrapv1.InitConfiguration, version semver.Version) (string, error) { - return marshalForVersion(nil, initConfiguration, version, initConfigurationVersionTypeMap) + return marshalForVersion(initConfiguration, version, initConfigurationVersionTypeMap, nil) } // MarshalJoinConfigurationForVersion converts a Cluster API JoinConfiguration type to the kubeadm API type // for the given Kubernetes Version. // NOTE: This assumes Kubernetes Version equals to kubeadm version. func MarshalJoinConfigurationForVersion(joinConfiguration *bootstrapv1.JoinConfiguration, version semver.Version) (string, error) { - return marshalForVersion(nil, joinConfiguration, version, joinConfigurationVersionTypeMap) + return marshalForVersion(joinConfiguration, version, joinConfigurationVersionTypeMap, nil) } -func marshalForVersion(initConfiguration *bootstrapv1.InitConfiguration, obj conversion.Hub, version semver.Version, kubeadmObjVersionTypeMap map[schema.GroupVersion]conversion.Convertible) (string, error) { +func marshalForVersion(obj conversion.Hub, version semver.Version, kubeadmObjVersionTypeMap map[schema.GroupVersion]conversion.Convertible, data *upstream.AdditionalData) (string, error) { kubeadmAPIGroupVersion, err := KubeVersionToKubeadmAPIGroupVersion(version) if err != nil { return "", err @@ -117,10 +106,8 @@ func marshalForVersion(initConfiguration *bootstrapv1.InitConfiguration, obj con return "", errors.Wrapf(err, "failed to convert to KubeadmAPI type for version %s", kubeadmAPIGroupVersion) } - if convertibleFromInitConfigurationObj, ok := targetKubeadmObj.(ConvertibleFromInitConfiguration); ok { - if err := convertibleFromInitConfigurationObj.ConvertFromInitConfiguration(initConfiguration); err != nil { - return "", errors.Wrapf(err, "failed to convert from InitConfiguration to KubeadmAPI type for version %s", kubeadmAPIGroupVersion) - } + if additionalDataSetter, ok := targetKubeadmObj.(upstream.AdditionalDataSetter); ok && data != nil { + additionalDataSetter.SetAdditionalData(*data) } codecs, err := getCodecsFor(kubeadmAPIGroupVersion, targetKubeadmObj) @@ -157,19 +144,20 @@ func toYaml(obj runtime.Object, gv runtime.GroupVersioner, codecs serializer.Cod // UnmarshalClusterConfiguration tries to translate a Kubeadm API yaml back to the Cluster API ClusterConfiguration type. // NOTE: The yaml could be any of the known formats for the kubeadm ClusterConfiguration type. -func UnmarshalClusterConfiguration(yaml string, initConfiguration *bootstrapv1.InitConfiguration) (*bootstrapv1.ClusterConfiguration, error) { +func UnmarshalClusterConfiguration(yaml string) (*bootstrapv1.ClusterConfiguration, *upstream.AdditionalData, error) { obj := &bootstrapv1.ClusterConfiguration{} - if err := unmarshalFromVersions(yaml, clusterConfigurationVersionTypeMap, initConfiguration, obj); err != nil { - return nil, err + data := &upstream.AdditionalData{} + if err := unmarshalFromVersions(yaml, clusterConfigurationVersionTypeMap, obj, data); err != nil { + return nil, nil, err } - return obj, nil + return obj, data, nil } // UnmarshalInitConfiguration tries to translate a Kubeadm API yaml back to the InitConfiguration type. // NOTE: The yaml could be any of the known formats for the kubeadm InitConfiguration type. func UnmarshalInitConfiguration(yaml string) (*bootstrapv1.InitConfiguration, error) { obj := &bootstrapv1.InitConfiguration{} - if err := unmarshalFromVersions(yaml, initConfigurationVersionTypeMap, nil, obj); err != nil { + if err := unmarshalFromVersions(yaml, initConfigurationVersionTypeMap, obj, nil); err != nil { return nil, err } return obj, nil @@ -179,13 +167,13 @@ func UnmarshalInitConfiguration(yaml string) (*bootstrapv1.InitConfiguration, er // NOTE: The yaml could be any of the known formats for the kubeadm JoinConfiguration type. func UnmarshalJoinConfiguration(yaml string) (*bootstrapv1.JoinConfiguration, error) { obj := &bootstrapv1.JoinConfiguration{} - if err := unmarshalFromVersions(yaml, joinConfigurationVersionTypeMap, nil, obj); err != nil { + if err := unmarshalFromVersions(yaml, joinConfigurationVersionTypeMap, obj, nil); err != nil { return nil, err } return obj, nil } -func unmarshalFromVersions(yaml string, kubeadmAPIVersions map[schema.GroupVersion]conversion.Convertible, initConfiguration *bootstrapv1.InitConfiguration, capiObj conversion.Hub) error { +func unmarshalFromVersions(yaml string, kubeadmAPIVersions map[schema.GroupVersion]conversion.Convertible, capiObj conversion.Hub, data *upstream.AdditionalData) error { // For each know kubeadm API version for gv, obj := range kubeadmAPIVersions { // Tries conversion from yaml to the corresponding kubeadmObj @@ -198,16 +186,14 @@ func unmarshalFromVersions(yaml string, kubeadmAPIVersions map[schema.GroupVersi _, _, err = codecs.UniversalDeserializer().Decode([]byte(yaml), &gvk, kubeadmObj) if err == nil { - if convertibleToInitConfigurationObj, ok := kubeadmObj.(ConvertibleToInitConfiguration); ok { - if err := convertibleToInitConfigurationObj.ConvertToInitConfiguration(initConfiguration); err != nil { - return errors.Wrapf(err, "failed to convert to InitConfiguration from KubeadmAPI type for version %s", gvk) - } - } - // If conversion worked, then converts the kubeadmObj (spoke) back to the Cluster API type (hub). if err := kubeadmObj.(conversion.Convertible).ConvertTo(capiObj); err != nil { return errors.Wrapf(err, "failed to convert kubeadm types to Cluster API types") } + + if additionalDataGetter, ok := kubeadmObj.(upstream.AdditionalDataGetter); ok && data != nil { + additionalDataGetter.GetAdditionalData(data) + } return nil } } diff --git a/bootstrap/kubeadm/types/utils_test.go b/bootstrap/kubeadm/types/utils_test.go index df6607a4ba30..399651c9ec56 100644 --- a/bootstrap/kubeadm/types/utils_test.go +++ b/bootstrap/kubeadm/types/utils_test.go @@ -17,6 +17,7 @@ limitations under the License. package utils import ( + "fmt" "testing" "github.com/blang/semver/v4" @@ -26,6 +27,7 @@ import ( "k8s.io/utils/ptr" bootstrapv1 "sigs.k8s.io/cluster-api/api/bootstrap/kubeadm/v1beta2" + "sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/upstream" "sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/upstreamv1beta3" "sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/upstreamv1beta4" ) @@ -120,10 +122,19 @@ func TestKubeVersionToKubeadmAPIGroupVersion(t *testing.T) { } func TestMarshalClusterConfigurationForVersion(t *testing.T) { + data := &upstream.AdditionalData{ + // KubernetesVersion is going to be set on a test bases. + ClusterName: ptr.To("mycluster"), + ControlPlaneEndpoint: ptr.To("myControlPlaneEndpoint:6443"), + DNSDomain: ptr.To("myDNSDomain"), + ServiceSubnet: ptr.To("myServiceSubnet"), + PodSubnet: ptr.To("myPodSubnet"), + ControlPlaneComponentHealthCheckSeconds: ptr.To[int32](30), + } + type args struct { - initConfiguration *bootstrapv1.InitConfiguration - capiObj *bootstrapv1.ClusterConfiguration - version semver.Version + capiObj *bootstrapv1.ClusterConfiguration + version semver.Version } tests := []struct { name string @@ -137,35 +148,20 @@ func TestMarshalClusterConfigurationForVersion(t *testing.T) { capiObj: &bootstrapv1.ClusterConfiguration{}, version: semver.MustParse("1.22.0"), }, - want: "apiServer: {}\n" + - "apiVersion: kubeadm.k8s.io/v1beta3\n" + - "controllerManager: {}\n" + - "dns: {}\n" + - "etcd: {}\n" + - "kind: ClusterConfiguration\n" + - "networking: {}\n" + - "scheduler: {}\n", - wantErr: false, - }, - { - name: "Generates a v1beta3 kubeadm configuration with data from init configuration", - args: args{ - initConfiguration: &bootstrapv1.InitConfiguration{ - Timeouts: &bootstrapv1.Timeouts{ - ControlPlaneComponentHealthCheckSeconds: ptr.To[int32](30), - }, - }, - capiObj: &bootstrapv1.ClusterConfiguration{}, - version: semver.MustParse("1.22.0"), - }, want: "apiServer:\n" + " timeoutForControlPlane: 30s\n" + "apiVersion: kubeadm.k8s.io/v1beta3\n" + + "clusterName: mycluster\n" + + "controlPlaneEndpoint: myControlPlaneEndpoint:6443\n" + "controllerManager: {}\n" + "dns: {}\n" + "etcd: {}\n" + "kind: ClusterConfiguration\n" + - "networking: {}\n" + + "kubernetesVersion: v1.22.0\n" + + "networking:\n" + + " dnsDomain: myDNSDomain\n" + + " podSubnet: myPodSubnet\n" + + " serviceSubnet: myServiceSubnet\n" + "scheduler: {}\n", wantErr: false, }, @@ -177,11 +173,17 @@ func TestMarshalClusterConfigurationForVersion(t *testing.T) { }, want: "apiServer: {}\n" + "apiVersion: kubeadm.k8s.io/v1beta4\n" + + "clusterName: mycluster\n" + + "controlPlaneEndpoint: myControlPlaneEndpoint:6443\n" + "controllerManager: {}\n" + "dns: {}\n" + "etcd: {}\n" + "kind: ClusterConfiguration\n" + - "networking: {}\n" + + "kubernetesVersion: v1.31.0\n" + + "networking:\n" + + " dnsDomain: myDNSDomain\n" + + " podSubnet: myPodSubnet\n" + + " serviceSubnet: myServiceSubnet\n" + "proxy: {}\n" + "scheduler: {}\n", wantErr: false, @@ -191,7 +193,8 @@ func TestMarshalClusterConfigurationForVersion(t *testing.T) { t.Run(tt.name, func(t *testing.T) { g := NewWithT(t) - got, err := MarshalClusterConfigurationForVersion(tt.args.initConfiguration, tt.args.capiObj, tt.args.version) + data.KubernetesVersion = ptr.To(fmt.Sprintf("v%s", tt.args.version.String())) + got, err := MarshalClusterConfigurationForVersion(tt.args.capiObj, tt.args.version, data) if tt.wantErr { g.Expect(err).To(HaveOccurred()) return @@ -347,27 +350,40 @@ func TestUnmarshalClusterConfiguration(t *testing.T) { yaml string } tests := []struct { - name string - args args - want *bootstrapv1.ClusterConfiguration - wantInitConfiguration *bootstrapv1.InitConfiguration - wantErr bool + name string + args args + want *bootstrapv1.ClusterConfiguration + wantUpstreamData *upstream.AdditionalData + wantErr bool }{ { name: "Parses a v1beta3 kubeadm configuration", args: args{ yaml: "apiServer: {}\n" + - "apiVersion: kubeadm.k8s.io/v1beta3\n" + "" + + "apiVersion: kubeadm.k8s.io/v1beta3\n" + + "clusterName: mycluster\n" + + "controlPlaneEndpoint: myControlPlaneEndpoint:6443\n" + "controllerManager: {}\n" + "dns: {}\n" + "etcd: {}\n" + "kind: ClusterConfiguration\n" + - "networking: {}\n" + + "kubernetesVersion: v1.23.1\n" + + "networking:\n" + + " dnsDomain: myDNSDomain\n" + + " podSubnet: myPodSubnet\n" + + " serviceSubnet: myServiceSubnet\n" + "scheduler: {}\n", }, - want: &bootstrapv1.ClusterConfiguration{}, - wantInitConfiguration: &bootstrapv1.InitConfiguration{}, - wantErr: false, + want: &bootstrapv1.ClusterConfiguration{}, + wantUpstreamData: &upstream.AdditionalData{ + KubernetesVersion: ptr.To("v1.23.1"), + ClusterName: ptr.To("mycluster"), + ControlPlaneEndpoint: ptr.To("myControlPlaneEndpoint:6443"), + DNSDomain: ptr.To("myDNSDomain"), + ServiceSubnet: ptr.To("myServiceSubnet"), + PodSubnet: ptr.To("myPodSubnet"), + }, + wantErr: false, }, { name: "Parses a v1beta3 kubeadm configuration with data to init configuration", @@ -376,18 +392,28 @@ func TestUnmarshalClusterConfiguration(t *testing.T) { " timeoutForControlPlane: 50s\n" + "}\n" + "apiVersion: kubeadm.k8s.io/v1beta3\n" + "" + + "clusterName: mycluster\n" + + "controlPlaneEndpoint: myControlPlaneEndpoint:6443\n" + "controllerManager: {}\n" + "dns: {}\n" + "etcd: {}\n" + "kind: ClusterConfiguration\n" + - "networking: {}\n" + + "kubernetesVersion: v1.23.1\n" + + "networking:\n" + + " dnsDomain: myDNSDomain\n" + + " podSubnet: myPodSubnet\n" + + " serviceSubnet: myServiceSubnet\n" + "scheduler: {}\n", }, want: &bootstrapv1.ClusterConfiguration{}, - wantInitConfiguration: &bootstrapv1.InitConfiguration{ - Timeouts: &bootstrapv1.Timeouts{ - ControlPlaneComponentHealthCheckSeconds: ptr.To[int32](50), - }, + wantUpstreamData: &upstream.AdditionalData{ + KubernetesVersion: ptr.To("v1.23.1"), + ClusterName: ptr.To("mycluster"), + ControlPlaneEndpoint: ptr.To("myControlPlaneEndpoint:6443"), + DNSDomain: ptr.To("myDNSDomain"), + ServiceSubnet: ptr.To("myServiceSubnet"), + PodSubnet: ptr.To("myPodSubnet"), + ControlPlaneComponentHealthCheckSeconds: ptr.To(int32(50)), }, wantErr: false, }, @@ -396,32 +422,44 @@ func TestUnmarshalClusterConfiguration(t *testing.T) { args: args{ yaml: "apiServer: {}\n" + "apiVersion: kubeadm.k8s.io/v1beta4\n" + "" + + "clusterName: mycluster\n" + + "controlPlaneEndpoint: myControlPlaneEndpoint:6443\n" + "controllerManager: {}\n" + "dns: {}\n" + "etcd: {}\n" + "kind: ClusterConfiguration\n" + - "networking: {}\n" + + "kubernetesVersion: v1.31.1\n" + + "networking:\n" + + " dnsDomain: myDNSDomain\n" + + " podSubnet: myPodSubnet\n" + + " serviceSubnet: myServiceSubnet\n" + "proxy: {}\n" + "scheduler: {}\n", }, - want: &bootstrapv1.ClusterConfiguration{}, - wantInitConfiguration: &bootstrapv1.InitConfiguration{}, - wantErr: false, + want: &bootstrapv1.ClusterConfiguration{}, + wantUpstreamData: &upstream.AdditionalData{ + KubernetesVersion: ptr.To("v1.31.1"), + ClusterName: ptr.To("mycluster"), + ControlPlaneEndpoint: ptr.To("myControlPlaneEndpoint:6443"), + DNSDomain: ptr.To("myDNSDomain"), + ServiceSubnet: ptr.To("myServiceSubnet"), + PodSubnet: ptr.To("myPodSubnet"), + }, + wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { g := NewWithT(t) - gotInitConfiguration := &bootstrapv1.InitConfiguration{} - got, err := UnmarshalClusterConfiguration(tt.args.yaml, gotInitConfiguration) + got, upstreamData, err := UnmarshalClusterConfiguration(tt.args.yaml) if tt.wantErr { g.Expect(err).To(HaveOccurred()) return } g.Expect(err).ToNot(HaveOccurred()) g.Expect(got).To(BeComparableTo(tt.want), cmp.Diff(tt.want, got)) - g.Expect(gotInitConfiguration).To(BeComparableTo(tt.wantInitConfiguration), cmp.Diff(tt.wantInitConfiguration, gotInitConfiguration)) + g.Expect(upstreamData).To(Equal(tt.wantUpstreamData)) }) } } diff --git a/controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanes.yaml b/controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanes.yaml index 45f87bb07a57..361d3bfa6a7c 100644 --- a/controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanes.yaml +++ b/controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanes.yaml @@ -5281,28 +5281,6 @@ spec: maxLength: 512 minLength: 1 type: string - clusterName: - description: clusterName is the cluster name - maxLength: 63 - minLength: 1 - type: string - controlPlaneEndpoint: - description: |- - controlPlaneEndpoint sets a stable IP address or DNS name for the control plane; it - can be a valid IP address or a RFC-1123 DNS subdomain, both with optional TCP port. - In case the ControlPlaneEndpoint is not specified, the AdvertiseAddress + BindPort - are used; in case the ControlPlaneEndpoint is specified but without a TCP port, - the BindPort is used. - Possible usages are: - e.g. In a cluster with more than one control plane instances, this field should be - assigned the address of the external load balancer in front of the - control plane instances. - e.g. in environments with enforced node recycling, the ControlPlaneEndpoint - could be used for assigning a stable DNS to the control plane. - NB: This value defaults to the first value in the Cluster object status.apiEndpoints array. - maxLength: 512 - minLength: 1 - type: string controllerManager: description: controllerManager contains extra settings for the controller manager control plane component @@ -5807,41 +5785,6 @@ spec: In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string - kubernetesVersion: - description: |- - kubernetesVersion is the target version of the control plane. - NB: This value defaults to the Machine object spec.version - maxLength: 256 - minLength: 1 - type: string - networking: - description: |- - networking holds configuration for the networking topology of the cluster. - NB: This value defaults to the Cluster object spec.clusterNetwork. - properties: - dnsDomain: - description: dnsDomain is the dns domain used by k8s services. - Defaults to "cluster.local". - maxLength: 253 - minLength: 1 - type: string - podSubnet: - description: |- - podSubnet is the subnet used by pods. - If unset, the API server will not allocate CIDR ranges for every node. - Defaults to a comma-delimited string of the Cluster object's spec.clusterNetwork.services.cidrBlocks if that is set - maxLength: 1024 - minLength: 1 - type: string - serviceSubnet: - description: |- - serviceSubnet is the subnet used by k8s services. - Defaults to a comma-delimited string of the Cluster object's spec.clusterNetwork.pods.cidrBlocks, or - to "10.96.0.0/12" if that's unset. - maxLength: 1024 - minLength: 1 - type: string - type: object scheduler: description: scheduler contains extra settings for the scheduler control plane component diff --git a/controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanetemplates.yaml b/controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanetemplates.yaml index b97cd9057957..70071538deb1 100644 --- a/controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanetemplates.yaml +++ b/controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanetemplates.yaml @@ -3649,28 +3649,6 @@ spec: maxLength: 512 minLength: 1 type: string - clusterName: - description: clusterName is the cluster name - maxLength: 63 - minLength: 1 - type: string - controlPlaneEndpoint: - description: |- - controlPlaneEndpoint sets a stable IP address or DNS name for the control plane; it - can be a valid IP address or a RFC-1123 DNS subdomain, both with optional TCP port. - In case the ControlPlaneEndpoint is not specified, the AdvertiseAddress + BindPort - are used; in case the ControlPlaneEndpoint is specified but without a TCP port, - the BindPort is used. - Possible usages are: - e.g. In a cluster with more than one control plane instances, this field should be - assigned the address of the external load balancer in front of the - control plane instances. - e.g. in environments with enforced node recycling, the ControlPlaneEndpoint - could be used for assigning a stable DNS to the control plane. - NB: This value defaults to the first value in the Cluster object status.apiEndpoints array. - maxLength: 512 - minLength: 1 - type: string controllerManager: description: controllerManager contains extra settings for the controller manager control plane component @@ -4194,41 +4172,6 @@ spec: In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string - kubernetesVersion: - description: |- - kubernetesVersion is the target version of the control plane. - NB: This value defaults to the Machine object spec.version - maxLength: 256 - minLength: 1 - type: string - networking: - description: |- - networking holds configuration for the networking topology of the cluster. - NB: This value defaults to the Cluster object spec.clusterNetwork. - properties: - dnsDomain: - description: dnsDomain is the dns domain used - by k8s services. Defaults to "cluster.local". - maxLength: 253 - minLength: 1 - type: string - podSubnet: - description: |- - podSubnet is the subnet used by pods. - If unset, the API server will not allocate CIDR ranges for every node. - Defaults to a comma-delimited string of the Cluster object's spec.clusterNetwork.services.cidrBlocks if that is set - maxLength: 1024 - minLength: 1 - type: string - serviceSubnet: - description: |- - serviceSubnet is the subnet used by k8s services. - Defaults to a comma-delimited string of the Cluster object's spec.clusterNetwork.pods.cidrBlocks, or - to "10.96.0.0/12" if that's unset. - maxLength: 1024 - minLength: 1 - type: string - type: object scheduler: description: scheduler contains extra settings for the scheduler control plane component diff --git a/controlplane/kubeadm/internal/controllers/fakes_test.go b/controlplane/kubeadm/internal/controllers/fakes_test.go index e4e2f580d3fc..c01946ec2e01 100644 --- a/controlplane/kubeadm/internal/controllers/fakes_test.go +++ b/controlplane/kubeadm/internal/controllers/fakes_test.go @@ -101,10 +101,6 @@ func (f *fakeWorkloadCluster) AllowClusterAdminPermissions(_ context.Context, _ return nil } -func (f *fakeWorkloadCluster) UpdateKubernetesVersionInKubeadmConfigMap(semver.Version) func(*bootstrapv1.ClusterConfiguration) { - return nil -} - func (f *fakeWorkloadCluster) UpdateEtcdLocalInKubeadmConfigMap(*bootstrapv1.LocalEtcd) func(*bootstrapv1.ClusterConfiguration) { return nil } diff --git a/controlplane/kubeadm/internal/controllers/helpers_test.go b/controlplane/kubeadm/internal/controllers/helpers_test.go index 903892eaef02..8002c75cbc80 100644 --- a/controlplane/kubeadm/internal/controllers/helpers_test.go +++ b/controlplane/kubeadm/internal/controllers/helpers_test.go @@ -540,7 +540,7 @@ func TestKubeadmControlPlaneReconciler_computeDesiredMachine(t *testing.T) { }, KubeadmConfigSpec: bootstrapv1.KubeadmConfigSpec{ ClusterConfiguration: &bootstrapv1.ClusterConfiguration{ - ClusterName: clusterName, + CertificatesDir: "foo", }, }, MachineNamingStrategy: &controlplanev1.MachineNamingStrategy{ @@ -553,7 +553,7 @@ func TestKubeadmControlPlaneReconciler_computeDesiredMachine(t *testing.T) { HavePrefix(kcpName + namingTemplateKey), Not(HaveSuffix("00000")), }, - wantClusterConfigurationAnnotation: "{\"marshalVersion\":\"v1beta2\",\"etcd\":{},\"networking\":{},\"apiServer\":{},\"controllerManager\":{},\"scheduler\":{},\"dns\":{},\"clusterName\":\"testCluster\"}", + wantClusterConfigurationAnnotation: "{\"marshalVersion\":\"v1beta2\",\"etcd\":{},\"apiServer\":{},\"controllerManager\":{},\"scheduler\":{},\"dns\":{},\"certificatesDir\":\"foo\"}", wantErr: false, }, { @@ -573,7 +573,7 @@ func TestKubeadmControlPlaneReconciler_computeDesiredMachine(t *testing.T) { }, KubeadmConfigSpec: bootstrapv1.KubeadmConfigSpec{ ClusterConfiguration: &bootstrapv1.ClusterConfiguration{ - ClusterName: clusterName, + CertificatesDir: "foo", }, }, MachineNamingStrategy: &controlplanev1.MachineNamingStrategy{ @@ -601,7 +601,7 @@ func TestKubeadmControlPlaneReconciler_computeDesiredMachine(t *testing.T) { }, KubeadmConfigSpec: bootstrapv1.KubeadmConfigSpec{ ClusterConfiguration: &bootstrapv1.ClusterConfiguration{ - ClusterName: clusterName, + CertificatesDir: "foo", }, }, MachineNamingStrategy: &controlplanev1.MachineNamingStrategy{ @@ -614,7 +614,7 @@ func TestKubeadmControlPlaneReconciler_computeDesiredMachine(t *testing.T) { ContainSubstring(fmt.Sprintf("%053d", 0)), Not(HaveSuffix("00000")), }, - wantClusterConfigurationAnnotation: "{\"marshalVersion\":\"v1beta2\",\"etcd\":{},\"networking\":{},\"apiServer\":{},\"controllerManager\":{},\"scheduler\":{},\"dns\":{},\"clusterName\":\"testCluster\"}", + wantClusterConfigurationAnnotation: "{\"marshalVersion\":\"v1beta2\",\"etcd\":{},\"apiServer\":{},\"controllerManager\":{},\"scheduler\":{},\"dns\":{},\"certificatesDir\":\"foo\"}", wantErr: false, }, { @@ -634,7 +634,7 @@ func TestKubeadmControlPlaneReconciler_computeDesiredMachine(t *testing.T) { }, KubeadmConfigSpec: bootstrapv1.KubeadmConfigSpec{ ClusterConfiguration: &bootstrapv1.ClusterConfiguration{ - ClusterName: clusterName, + CertificatesDir: "foo", }, }, MachineNamingStrategy: &controlplanev1.MachineNamingStrategy{ @@ -662,7 +662,7 @@ func TestKubeadmControlPlaneReconciler_computeDesiredMachine(t *testing.T) { }, KubeadmConfigSpec: bootstrapv1.KubeadmConfigSpec{ ClusterConfiguration: &bootstrapv1.ClusterConfiguration{ - ClusterName: clusterName, + CertificatesDir: "foo", }, }, }, @@ -673,7 +673,7 @@ func TestKubeadmControlPlaneReconciler_computeDesiredMachine(t *testing.T) { HavePrefix(kcpName), Not(HaveSuffix("00000")), }, - wantClusterConfigurationAnnotation: "{\"marshalVersion\":\"v1beta2\",\"etcd\":{},\"networking\":{},\"apiServer\":{},\"controllerManager\":{},\"scheduler\":{},\"dns\":{},\"clusterName\":\"testCluster\"}", + wantClusterConfigurationAnnotation: "{\"marshalVersion\":\"v1beta2\",\"etcd\":{},\"apiServer\":{},\"controllerManager\":{},\"scheduler\":{},\"dns\":{},\"certificatesDir\":\"foo\"}", }, { name: "should return the correct Machine object when creating a new Machine with additional kcp readinessGates", @@ -693,13 +693,13 @@ func TestKubeadmControlPlaneReconciler_computeDesiredMachine(t *testing.T) { }, KubeadmConfigSpec: bootstrapv1.KubeadmConfigSpec{ ClusterConfiguration: &bootstrapv1.ClusterConfiguration{ - ClusterName: clusterName, + CertificatesDir: "foo", }, }, }, }, isUpdatingExistingMachine: false, - wantClusterConfigurationAnnotation: "{\"marshalVersion\":\"v1beta2\",\"etcd\":{},\"networking\":{},\"apiServer\":{},\"controllerManager\":{},\"scheduler\":{},\"dns\":{},\"clusterName\":\"testCluster\"}", + wantClusterConfigurationAnnotation: "{\"marshalVersion\":\"v1beta2\",\"etcd\":{},\"apiServer\":{},\"controllerManager\":{},\"scheduler\":{},\"dns\":{},\"certificatesDir\":\"foo\"}", wantErr: false, }, { @@ -722,7 +722,7 @@ func TestKubeadmControlPlaneReconciler_computeDesiredMachine(t *testing.T) { }, KubeadmConfigSpec: bootstrapv1.KubeadmConfigSpec{ ClusterConfiguration: &bootstrapv1.ClusterConfiguration{ - ClusterName: clusterName, + CertificatesDir: "foo", }, }, MachineNamingStrategy: &controlplanev1.MachineNamingStrategy{ @@ -755,7 +755,7 @@ func TestKubeadmControlPlaneReconciler_computeDesiredMachine(t *testing.T) { }, KubeadmConfigSpec: bootstrapv1.KubeadmConfigSpec{ ClusterConfiguration: &bootstrapv1.ClusterConfiguration{ - ClusterName: clusterName, + CertificatesDir: "foo", }, }, MachineNamingStrategy: &controlplanev1.MachineNamingStrategy{ @@ -765,8 +765,8 @@ func TestKubeadmControlPlaneReconciler_computeDesiredMachine(t *testing.T) { }, isUpdatingExistingMachine: true, - existingClusterConfigurationAnnotation: "{\"etcd\":{},\"networking\":{},\"apiServer\":{\"extraArgs\":{\"foo\":\"bar\"}},\"controllerManager\":{},\"scheduler\":{},\"dns\":{},\"clusterName\":\"testCluster\"}", - wantClusterConfigurationAnnotation: "{\"marshalVersion\":\"v1beta2\",\"etcd\":{},\"networking\":{},\"apiServer\":{\"extraArgs\":[{\"name\":\"foo\",\"value\":\"bar\"}]},\"controllerManager\":{},\"scheduler\":{},\"dns\":{},\"clusterName\":\"testCluster\"}", + existingClusterConfigurationAnnotation: "{\"etcd\":{},\"apiServer\":{\"extraArgs\":{\"foo\":\"bar\"}},\"controllerManager\":{},\"scheduler\":{},\"dns\":{},\"certificatesDir\":\"foo\"}", + wantClusterConfigurationAnnotation: "{\"marshalVersion\":\"v1beta2\",\"etcd\":{},\"apiServer\":{\"extraArgs\":[{\"name\":\"foo\",\"value\":\"bar\"}]},\"controllerManager\":{},\"scheduler\":{},\"dns\":{},\"certificatesDir\":\"foo\"}", wantErr: false, }, { @@ -789,7 +789,7 @@ func TestKubeadmControlPlaneReconciler_computeDesiredMachine(t *testing.T) { }, KubeadmConfigSpec: bootstrapv1.KubeadmConfigSpec{ ClusterConfiguration: &bootstrapv1.ClusterConfiguration{ - ClusterName: clusterName, + CertificatesDir: "foo", }, }, MachineNamingStrategy: &controlplanev1.MachineNamingStrategy{ @@ -798,8 +798,8 @@ func TestKubeadmControlPlaneReconciler_computeDesiredMachine(t *testing.T) { }, }, isUpdatingExistingMachine: true, - existingClusterConfigurationAnnotation: "{\"marshalVersion\":\"v1beta2\",\"etcd\":{},\"networking\":{},\"apiServer\":{\"extraArgs\":[{\"name\":\"foo\",\"value\":\"bar\"}]},\"controllerManager\":{},\"scheduler\":{},\"dns\":{},\"clusterName\":\"testCluster\"}", - wantClusterConfigurationAnnotation: "{\"marshalVersion\":\"v1beta2\",\"etcd\":{},\"networking\":{},\"apiServer\":{\"extraArgs\":[{\"name\":\"foo\",\"value\":\"bar\"}]},\"controllerManager\":{},\"scheduler\":{},\"dns\":{},\"clusterName\":\"testCluster\"}", + existingClusterConfigurationAnnotation: "{\"marshalVersion\":\"v1beta2\",\"etcd\":{},\"apiServer\":{\"extraArgs\":[{\"name\":\"foo\",\"value\":\"bar\"}]},\"controllerManager\":{},\"scheduler\":{},\"dns\":{},\"certificatesDir\":\"foo\"}", + wantClusterConfigurationAnnotation: "{\"marshalVersion\":\"v1beta2\",\"etcd\":{},\"apiServer\":{\"extraArgs\":[{\"name\":\"foo\",\"value\":\"bar\"}]},\"controllerManager\":{},\"scheduler\":{},\"dns\":{},\"certificatesDir\":\"foo\"}", wantErr: false, }, } diff --git a/controlplane/kubeadm/internal/controllers/upgrade.go b/controlplane/kubeadm/internal/controllers/upgrade.go index e5e35b5660ac..72acc51229ae 100644 --- a/controlplane/kubeadm/internal/controllers/upgrade.go +++ b/controlplane/kubeadm/internal/controllers/upgrade.go @@ -60,7 +60,6 @@ func (r *KubeadmControlPlaneReconciler) upgradeControlPlane( } kubeadmCMMutators := make([]func(*bootstrapv1.ClusterConfiguration), 0) - kubeadmCMMutators = append(kubeadmCMMutators, workloadCluster.UpdateKubernetesVersionInKubeadmConfigMap(parsedVersion)) if controlPlane.KCP.Spec.KubeadmConfigSpec.ClusterConfiguration != nil { // Get the imageRepository or the correct value if nothing is set and a migration is necessary. diff --git a/controlplane/kubeadm/internal/filters_test.go b/controlplane/kubeadm/internal/filters_test.go index 43962356e36b..6f9d7728bb7c 100644 --- a/controlplane/kubeadm/internal/filters_test.go +++ b/controlplane/kubeadm/internal/filters_test.go @@ -49,7 +49,7 @@ func TestClusterConfigurationAnnotation(t *testing.T) { }, }, }, - KubernetesVersion: "v1.33.0", + CertificatesDir: "foo", }, }, }, @@ -57,7 +57,7 @@ func TestClusterConfigurationAnnotation(t *testing.T) { annotations, err := ClusterConfigurationToMachineAnnotationValue(kcp.Spec.KubeadmConfigSpec.ClusterConfiguration) g.Expect(err).NotTo(HaveOccurred()) - g.Expect(annotations).To(Equal("{\"marshalVersion\":\"v1beta2\",\"etcd\":{},\"networking\":{},\"kubernetesVersion\":\"v1.33.0\",\"apiServer\":{\"extraArgs\":[{\"name\":\"foo\",\"value\":\"bar\"}]},\"controllerManager\":{},\"scheduler\":{},\"dns\":{}}")) + g.Expect(annotations).To(Equal("{\"marshalVersion\":\"v1beta2\",\"etcd\":{},\"apiServer\":{\"extraArgs\":[{\"name\":\"foo\",\"value\":\"bar\"}]},\"controllerManager\":{},\"scheduler\":{},\"dns\":{},\"certificatesDir\":\"foo\"}")) }) t.Run("ClusterConfigurationFromMachineIsOutdated", func(t *testing.T) { g := NewWithT(t) @@ -67,15 +67,15 @@ func TestClusterConfigurationAnnotation(t *testing.T) { g.Expect(ClusterConfigurationAnnotationFromMachineIsOutdated(annotation)).To(BeTrue()) // v1beta1 annotation (without marshalVersion) - annotation = "{\"etcd\":{},\"networking\":{},\"kubernetesVersion\":\"v1.33.0\",\"apiServer\":{\"extraArgs\":{\"foo\":\"bar\"}},\"controllerManager\":{},\"scheduler\":{},\"dns\":{}}" + annotation = "{\"etcd\":{},\"apiServer\":{\"extraArgs\":{\"foo\":\"bar\"}},\"controllerManager\":{},\"scheduler\":{},\"dns\":{}}" g.Expect(ClusterConfigurationAnnotationFromMachineIsOutdated(annotation)).To(BeTrue()) // up to date annotation (marshalVersion equal to current version) - annotation = fmt.Sprintf("{\"marshalVersion\":%q,\"etcd\":{},\"networking\":{},\"kubernetesVersion\":\"v1.33.0\",\"apiServer\":{\"extraArgs\":[{\"name\":\"foo\",\"value\":\"bar\"}]},\"controllerManager\":{},\"scheduler\":{},\"dns\":{}}", bootstrapv1.GroupVersion.Version) + annotation = fmt.Sprintf("{\"marshalVersion\":%q,\"etcd\":{},\"apiServer\":{\"extraArgs\":[{\"name\":\"foo\",\"value\":\"bar\"}]},\"controllerManager\":{},\"scheduler\":{},\"dns\":{}}", bootstrapv1.GroupVersion.Version) g.Expect(ClusterConfigurationAnnotationFromMachineIsOutdated(annotation)).To(BeFalse()) // marshalVersion not equal to the current version (this should not happen because marshalVersion has been introduced with the v1beta2 API) - annotation = "{\"marshalVersion\":\"foo\",\"etcd\":{},\"networking\":{},\"kubernetesVersion\":\"v1.33.0\",\"apiServer\":{\"extraArgs\":[{\"name\":\"foo\",\"value\":\"bar\"}]},\"controllerManager\":{},\"scheduler\":{},\"dns\":{}}" + annotation = "{\"marshalVersion\":\"foo\",\"etcd\":{},\"apiServer\":{\"extraArgs\":[{\"name\":\"foo\",\"value\":\"bar\"}]},\"controllerManager\":{},\"scheduler\":{},\"dns\":{}}" g.Expect(ClusterConfigurationAnnotationFromMachineIsOutdated(annotation)).To(BeTrue()) }) t.Run("ClusterConfigurationFromMachine", func(t *testing.T) { @@ -88,7 +88,7 @@ func TestClusterConfigurationAnnotation(t *testing.T) { g.Expect(clusterConfiguration).To(BeNil()) // v1beta1 annotation (without marshalVersion) - m1.SetAnnotations(map[string]string{controlplanev1.KubeadmClusterConfigurationAnnotation: "{\"etcd\":{},\"networking\":{},\"kubernetesVersion\":\"v1.33.0\",\"apiServer\":{\"extraArgs\":{\"foo\":\"bar\"}},\"controllerManager\":{},\"scheduler\":{},\"dns\":{}}"}) + m1.SetAnnotations(map[string]string{controlplanev1.KubeadmClusterConfigurationAnnotation: "{\"etcd\":{},\"apiServer\":{\"extraArgs\":{\"foo\":\"bar\"}},\"controllerManager\":{},\"scheduler\":{},\"dns\":{},\"certificatesDir\":\"foo\"}"}) clusterConfiguration, err = ClusterConfigurationFromMachine(m1) g.Expect(err).NotTo(HaveOccurred()) g.Expect(clusterConfiguration).To(Equal(&bootstrapv1.ClusterConfiguration{ @@ -102,11 +102,11 @@ func TestClusterConfigurationAnnotation(t *testing.T) { }, }, }, - KubernetesVersion: "v1.33.0", + CertificatesDir: "foo", })) // up to date annotation (marshalVersion equal to current version) - m1.SetAnnotations(map[string]string{controlplanev1.KubeadmClusterConfigurationAnnotation: fmt.Sprintf("{\"marshalVersion\":%q,\"etcd\":{},\"networking\":{},\"kubernetesVersion\":\"v1.33.0\",\"apiServer\":{\"extraArgs\":[{\"name\":\"foo\",\"value\":\"bar\"}]},\"controllerManager\":{},\"scheduler\":{},\"dns\":{}}", bootstrapv1.GroupVersion.Version)}) + m1.SetAnnotations(map[string]string{controlplanev1.KubeadmClusterConfigurationAnnotation: fmt.Sprintf("{\"marshalVersion\":%q,\"etcd\":{},\"apiServer\":{\"extraArgs\":[{\"name\":\"foo\",\"value\":\"bar\"}]},\"controllerManager\":{},\"scheduler\":{},\"dns\":{},\"certificatesDir\":\"foo\"}", bootstrapv1.GroupVersion.Version)}) clusterConfiguration, err = ClusterConfigurationFromMachine(m1) g.Expect(err).NotTo(HaveOccurred()) g.Expect(clusterConfiguration).To(Equal(&bootstrapv1.ClusterConfiguration{ @@ -120,7 +120,7 @@ func TestClusterConfigurationAnnotation(t *testing.T) { }, }, }, - KubernetesVersion: "v1.33.0", + CertificatesDir: "foo", })) }) } @@ -156,7 +156,7 @@ func TestMatchClusterConfiguration(t *testing.T) { Spec: controlplanev1.KubeadmControlPlaneSpec{ KubeadmConfigSpec: bootstrapv1.KubeadmConfigSpec{ ClusterConfiguration: &bootstrapv1.ClusterConfiguration{ - ClusterName: "foo", + CertificatesDir: "foo", }, }, }, @@ -164,7 +164,7 @@ func TestMatchClusterConfiguration(t *testing.T) { m := &clusterv1.Machine{ ObjectMeta: metav1.ObjectMeta{ Annotations: map[string]string{ - controlplanev1.KubeadmClusterConfigurationAnnotation: "{\n \"clusterName\": \"foo\"\n}", + controlplanev1.KubeadmClusterConfigurationAnnotation: "{\n \"certificatesDir\": \"foo\"\n}", }, }, } @@ -179,7 +179,7 @@ func TestMatchClusterConfiguration(t *testing.T) { Spec: controlplanev1.KubeadmControlPlaneSpec{ KubeadmConfigSpec: bootstrapv1.KubeadmConfigSpec{ ClusterConfiguration: &bootstrapv1.ClusterConfiguration{ - ClusterName: "foo", + CertificatesDir: "foo", }, }, }, @@ -187,7 +187,7 @@ func TestMatchClusterConfiguration(t *testing.T) { m := &clusterv1.Machine{ ObjectMeta: metav1.ObjectMeta{ Annotations: map[string]string{ - controlplanev1.KubeadmClusterConfigurationAnnotation: "{\n \"clusterName\": \"bar\"\n}", + controlplanev1.KubeadmClusterConfigurationAnnotation: "{\n \"certificatesDir\": \"bar\"\n}", }, }, } @@ -195,11 +195,13 @@ func TestMatchClusterConfiguration(t *testing.T) { g.Expect(err).ToNot(HaveOccurred()) g.Expect(match).To(BeFalse()) g.Expect(diff).To(BeComparableTo(`&v1beta2.ClusterConfiguration{ - ... // 10 identical fields + ... // 4 identical fields + Scheduler: {}, + DNS: {}, +- CertificatesDir: "bar", ++ CertificatesDir: "foo", ImageRepository: "", FeatureGates: nil, -- ClusterName: "bar", -+ ClusterName: "foo", }`)) }) t.Run("Return true if cluster configuration is nil (special case)", func(t *testing.T) { @@ -295,7 +297,7 @@ func TestMatchClusterConfiguration(t *testing.T) { // This is a point in time snapshot of how a serialized ClusterConfiguration looks like; // we are hardcoding this in the test so we can detect if a change in the API impacts serialization. // NOTE: changes in the json representation do not always trigger a rollout in KCP, but they are an heads up that should be investigated. - annotationsCheckPoint := "{\"marshalVersion\":\"v1beta2\",\"etcd\":{},\"networking\":{},\"apiServer\":{\"extraArgs\":[{\"name\":\"foo\",\"value\":\"bar\"}]},\"controllerManager\":{\"extraArgs\":[{\"name\":\"foo\",\"value\":\"bar\"}]},\"scheduler\":{\"extraArgs\":[{\"name\":\"foo\",\"value\":\"bar\"}]},\"dns\":{\"imageRepository\":\"gcr.io/capi-test\",\"imageTag\":\"v1.10.1\"}}" + annotationsCheckPoint := "{\"marshalVersion\":\"v1beta2\",\"etcd\":{},\"apiServer\":{\"extraArgs\":[{\"name\":\"foo\",\"value\":\"bar\"}]},\"controllerManager\":{\"extraArgs\":[{\"name\":\"foo\",\"value\":\"bar\"}]},\"scheduler\":{\"extraArgs\":[{\"name\":\"foo\",\"value\":\"bar\"}]},\"dns\":{\"imageRepository\":\"gcr.io/capi-test\",\"imageTag\":\"v1.10.1\"}}" // compute how a serialized ClusterConfiguration looks like now annotations, err := ClusterConfigurationToMachineAnnotationValue(kcp.Spec.KubeadmConfigSpec.ClusterConfiguration) @@ -856,7 +858,7 @@ func TestMatchesKubeadmBootstrapConfig(t *testing.T) { Spec: controlplanev1.KubeadmControlPlaneSpec{ KubeadmConfigSpec: bootstrapv1.KubeadmConfigSpec{ ClusterConfiguration: &bootstrapv1.ClusterConfiguration{ - ClusterName: "foo", + CertificatesDir: "foo", }, }, }, @@ -864,7 +866,7 @@ func TestMatchesKubeadmBootstrapConfig(t *testing.T) { m := &clusterv1.Machine{ ObjectMeta: metav1.ObjectMeta{ Annotations: map[string]string{ - controlplanev1.KubeadmClusterConfigurationAnnotation: "{\n \"clusterName\": \"foo\"\n}", + controlplanev1.KubeadmClusterConfigurationAnnotation: "{\n \"certificatesDir\": \"foo\"\n}", }, }, } @@ -882,7 +884,7 @@ func TestMatchesKubeadmBootstrapConfig(t *testing.T) { Spec: controlplanev1.KubeadmControlPlaneSpec{ KubeadmConfigSpec: bootstrapv1.KubeadmConfigSpec{ ClusterConfiguration: &bootstrapv1.ClusterConfiguration{ - ClusterName: "foo", + CertificatesDir: "foo", }, }, }, @@ -890,7 +892,7 @@ func TestMatchesKubeadmBootstrapConfig(t *testing.T) { m := &clusterv1.Machine{ ObjectMeta: metav1.ObjectMeta{ Annotations: map[string]string{ - controlplanev1.KubeadmClusterConfigurationAnnotation: "{\n \"clusterName\": \"bar\"\n}", + controlplanev1.KubeadmClusterConfigurationAnnotation: "{\n \"certificatesDir\": \"bar\"\n}", }, }, } @@ -901,11 +903,13 @@ func TestMatchesKubeadmBootstrapConfig(t *testing.T) { g.Expect(err).ToNot(HaveOccurred()) g.Expect(match).To(BeFalse()) g.Expect(reason).To(BeComparableTo(`Machine KubeadmConfig ClusterConfiguration is outdated: diff: &v1beta2.ClusterConfiguration{ - ... // 10 identical fields + ... // 4 identical fields + Scheduler: {}, + DNS: {}, +- CertificatesDir: "bar", ++ CertificatesDir: "foo", ImageRepository: "", FeatureGates: nil, -- ClusterName: "bar", -+ ClusterName: "foo", }`)) }) t.Run("returns true if InitConfiguration is equal", func(t *testing.T) { @@ -1543,7 +1547,7 @@ func TestUpToDate(t *testing.T) { }, KubeadmConfigSpec: bootstrapv1.KubeadmConfigSpec{ ClusterConfiguration: &bootstrapv1.ClusterConfiguration{ - ClusterName: "foo", + CertificatesDir: "foo", }, }, RolloutBefore: &controlplanev1.RolloutBefore{ @@ -1556,7 +1560,7 @@ func TestUpToDate(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ CreationTimestamp: metav1.Time{Time: reconciliationTime.Add(-2 * 24 * time.Hour)}, // two days ago. Annotations: map[string]string{ - controlplanev1.KubeadmClusterConfigurationAnnotation: "{\n \"clusterName\": \"foo\"\n}", + controlplanev1.KubeadmClusterConfigurationAnnotation: "{\n \"certificatesDir\": \"foo\"\n}", }, }, Spec: clusterv1.MachineSpec{ @@ -1661,14 +1665,14 @@ func TestUpToDate(t *testing.T) { name: "KubeadmConfig is not up-to-date", kcp: func() *controlplanev1.KubeadmControlPlane { kcp := defaultKcp.DeepCopy() - kcp.Spec.KubeadmConfigSpec.ClusterConfiguration.ClusterName = "bar" + kcp.Spec.KubeadmConfigSpec.ClusterConfiguration.CertificatesDir = "bar" return kcp }(), machine: defaultMachine, // was created with cluster name "foo" infraConfigs: defaultInfraConfigs, machineConfigs: defaultMachineConfigs, expectUptoDate: false, - expectLogMessages: []string{"Machine KubeadmConfig ClusterConfiguration is outdated: diff: &v1beta2.ClusterConfiguration{\n ... // 10 identical fields\n ImageRepository: \"\",\n FeatureGates: nil,\n- ClusterName: \"foo\",\n+ ClusterName: \"bar\",\n }"}, + expectLogMessages: []string{"Machine KubeadmConfig ClusterConfiguration is outdated: diff: &v1beta2.ClusterConfiguration{\n ... // 4 identical fields\n Scheduler: {},\n DNS: {},\n- CertificatesDir: \"foo\",\n+ CertificatesDir: \"bar\",\n ImageRepository: \"\",\n FeatureGates: nil,\n }"}, expectConditionMessages: []string{"KubeadmConfig is not up-to-date"}, }, { diff --git a/controlplane/kubeadm/internal/webhooks/kubeadm_control_plane_test.go b/controlplane/kubeadm/internal/webhooks/kubeadm_control_plane_test.go index 7220382a7391..58d48d56cdb6 100644 --- a/controlplane/kubeadm/internal/webhooks/kubeadm_control_plane_test.go +++ b/controlplane/kubeadm/internal/webhooks/kubeadm_control_plane_test.go @@ -344,7 +344,6 @@ func TestKubeadmControlPlaneValidateUpdate(t *testing.T) { }, }, ClusterConfiguration: &bootstrapv1.ClusterConfiguration{ - ClusterName: "test", DNS: bootstrapv1.DNS{ ImageMeta: bootstrapv1.ImageMeta{ ImageRepository: "registry.k8s.io/coredns", @@ -403,7 +402,9 @@ func TestKubeadmControlPlaneValidateUpdate(t *testing.T) { validUpdateKubeadmConfigInit.Spec.KubeadmConfigSpec.InitConfiguration.NodeRegistration = bootstrapv1.NodeRegistrationOptions{} invalidUpdateKubeadmConfigCluster := before.DeepCopy() - invalidUpdateKubeadmConfigCluster.Spec.KubeadmConfigSpec.ClusterConfiguration = &bootstrapv1.ClusterConfiguration{} + invalidUpdateKubeadmConfigCluster.Spec.KubeadmConfigSpec.ClusterConfiguration = &bootstrapv1.ClusterConfiguration{ + CertificatesDir: "some-other-value", + } validUpdateKubeadmConfigJoin := before.DeepCopy() validUpdateKubeadmConfigJoin.Spec.KubeadmConfigSpec.JoinConfiguration.NodeRegistration = bootstrapv1.NodeRegistrationOptions{} @@ -498,15 +499,6 @@ func TestKubeadmControlPlaneValidateUpdate(t *testing.T) { unsetEtcdLocal := etcdLocalImageTag.DeepCopy() unsetEtcdLocal.Spec.KubeadmConfigSpec.ClusterConfiguration.Etcd.Local = nil - networking := before.DeepCopy() - networking.Spec.KubeadmConfigSpec.ClusterConfiguration.Networking.DNSDomain = "some dns domain" - - kubernetesVersion := before.DeepCopy() - kubernetesVersion.Spec.KubeadmConfigSpec.ClusterConfiguration.KubernetesVersion = "some kubernetes version" - - controlPlaneEndpoint := before.DeepCopy() - controlPlaneEndpoint.Spec.KubeadmConfigSpec.ClusterConfiguration.ControlPlaneEndpoint = "some control plane endpoint" - apiServer := before.DeepCopy() apiServer.Spec.KubeadmConfigSpec.ClusterConfiguration.APIServer = bootstrapv1.APIServer{ ControlPlaneComponent: bootstrapv1.ControlPlaneComponent{ @@ -683,11 +675,6 @@ func TestKubeadmControlPlaneValidateUpdate(t *testing.T) { withoutClusterConfiguration := before.DeepCopy() withoutClusterConfiguration.Spec.KubeadmConfigSpec.ClusterConfiguration = nil - afterEtcdLocalDirAddition := before.DeepCopy() - afterEtcdLocalDirAddition.Spec.KubeadmConfigSpec.ClusterConfiguration.Etcd.Local = &bootstrapv1.LocalEtcd{ - DataDir: "/data", - } - updateNTPServers := before.DeepCopy() updateNTPServers.Spec.KubeadmConfigSpec.NTP.Servers = []string{"new-server"} @@ -853,24 +840,6 @@ func TestKubeadmControlPlaneValidateUpdate(t *testing.T) { before: before, kcp: etcdLocalImageInvalidTag, }, - { - name: "should fail when making a change to the cluster config's networking struct", - expectErr: true, - before: before, - kcp: networking, - }, - { - name: "should fail when making a change to the cluster config's kubernetes version", - expectErr: true, - before: before, - kcp: kubernetesVersion, - }, - { - name: "should fail when making a change to the cluster config's controlPlaneEndpoint", - expectErr: true, - before: before, - kcp: controlPlaneEndpoint, - }, { name: "should allow changes to the cluster config's apiServer", expectErr: false, @@ -1031,12 +1000,6 @@ func TestKubeadmControlPlaneValidateUpdate(t *testing.T) { before: withoutClusterConfiguration, kcp: withoutClusterConfiguration, }, - { - name: "should fail if etcd local dir is changed from missing ClusterConfiguration", - expectErr: true, - before: withoutClusterConfiguration, - kcp: afterEtcdLocalDirAddition, - }, { name: "should not return an error when maxSurge value is updated to 0", expectErr: false, diff --git a/controlplane/kubeadm/internal/webhooks/scale_test.go b/controlplane/kubeadm/internal/webhooks/scale_test.go index b2067db4b1d4..275b033da9be 100644 --- a/controlplane/kubeadm/internal/webhooks/scale_test.go +++ b/controlplane/kubeadm/internal/webhooks/scale_test.go @@ -82,7 +82,6 @@ func TestKubeadmControlPlaneValidateScale(t *testing.T) { }, }, ClusterConfiguration: &bootstrapv1.ClusterConfiguration{ - ClusterName: "kcp-managed-etcd", DNS: bootstrapv1.DNS{ ImageMeta: bootstrapv1.ImageMeta{ ImageRepository: "registry.k8s.io/coredns", diff --git a/controlplane/kubeadm/internal/workload_cluster.go b/controlplane/kubeadm/internal/workload_cluster.go index b68cdd2e0b88..00c52fee903e 100644 --- a/controlplane/kubeadm/internal/workload_cluster.go +++ b/controlplane/kubeadm/internal/workload_cluster.go @@ -38,6 +38,7 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/rest" "k8s.io/client-go/util/retry" + "k8s.io/utils/ptr" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" bootstrapv1 "sigs.k8s.io/cluster-api/api/bootstrap/kubeadm/v1beta2" @@ -86,7 +87,6 @@ type WorkloadCluster interface { GetAPIServerCertificateExpiry(ctx context.Context, kubeadmConfig *bootstrapv1.KubeadmConfig, nodeName string) (*time.Time, error) // Upgrade related tasks. - UpdateKubernetesVersionInKubeadmConfigMap(version semver.Version) func(*bootstrapv1.ClusterConfiguration) UpdateImageRepositoryInKubeadmConfigMap(imageRepository string) func(*bootstrapv1.ClusterConfiguration) UpdateFeatureGatesInKubeadmConfigMap(kubeadmConfigSpec bootstrapv1.KubeadmConfigSpec, kubernetesVersion semver.Version) func(*bootstrapv1.ClusterConfiguration) UpdateEtcdLocalInKubeadmConfigMap(localEtcd *bootstrapv1.LocalEtcd) func(*bootstrapv1.ClusterConfiguration) @@ -198,13 +198,6 @@ func DefaultFeatureGates(kubeadmConfigSpec *bootstrapv1.KubeadmConfigSpec, kuber } } -// UpdateKubernetesVersionInKubeadmConfigMap updates the kubernetes version in the kubeadm config map. -func (w *Workload) UpdateKubernetesVersionInKubeadmConfigMap(version semver.Version) func(*bootstrapv1.ClusterConfiguration) { - return func(c *bootstrapv1.ClusterConfiguration) { - c.KubernetesVersion = fmt.Sprintf("v%s", version.String()) - } -} - // UpdateAPIServerInKubeadmConfigMap updates api server configuration in kubeadm config map. func (w *Workload) UpdateAPIServerInKubeadmConfigMap(apiServer bootstrapv1.APIServer) func(*bootstrapv1.ClusterConfiguration) { return func(c *bootstrapv1.ClusterConfiguration) { @@ -243,8 +236,7 @@ func (w *Workload) UpdateClusterConfiguration(ctx context.Context, version semve return errors.Errorf("unable to find %q in the kubeadm-config ConfigMap", clusterConfigurationKey) } - initConfiguration := &bootstrapv1.InitConfiguration{} - currentObj, err := kubeadmtypes.UnmarshalClusterConfiguration(currentData, initConfiguration) + currentObj, currentUpstreamData, err := kubeadmtypes.UnmarshalClusterConfiguration(currentData) if err != nil { return errors.Wrapf(err, "unable to decode %q in the kubeadm-config ConfigMap's from YAML", clusterConfigurationKey) } @@ -254,8 +246,16 @@ func (w *Workload) UpdateClusterConfiguration(ctx context.Context, version semve mutators[i](updatedObj) } - if !reflect.DeepEqual(currentObj, updatedObj) { - updatedData, err := kubeadmtypes.MarshalClusterConfigurationForVersion(initConfiguration, updatedObj, version) + updatedUpstreamData := currentUpstreamData.Clone() + + desiredKubernetesVersion := fmt.Sprintf("v%s", version.String()) + currentKubernetesVersion := ptr.Deref(currentUpstreamData.KubernetesVersion, "") + if currentKubernetesVersion != desiredKubernetesVersion { + updatedUpstreamData.KubernetesVersion = ptr.To(desiredKubernetesVersion) + } + + if !reflect.DeepEqual(currentObj, updatedObj) || !reflect.DeepEqual(currentUpstreamData, updatedUpstreamData) { + updatedData, err := kubeadmtypes.MarshalClusterConfigurationForVersion(updatedObj, version, updatedUpstreamData) if err != nil { return errors.Wrapf(err, "unable to encode %q kubeadm-config ConfigMap's to YAML", clusterConfigurationKey) } diff --git a/controlplane/kubeadm/internal/workload_cluster_coredns_test.go b/controlplane/kubeadm/internal/workload_cluster_coredns_test.go index 1a0686f11bcc..a459b025b42e 100644 --- a/controlplane/kubeadm/internal/workload_cluster_coredns_test.go +++ b/controlplane/kubeadm/internal/workload_cluster_coredns_test.go @@ -1012,6 +1012,7 @@ func TestUpdateCoreDNSImageInfoInKubeadmConfigMap(t *testing.T) { imageTag: v1.2.3 etcd: {} kind: ClusterConfiguration + kubernetesVersion: v1.23.1 networking: {} scheduler: {} `), diff --git a/controlplane/kubeadm/internal/workload_cluster_etcd_test.go b/controlplane/kubeadm/internal/workload_cluster_etcd_test.go index 2de2d148fb48..3430717945c2 100644 --- a/controlplane/kubeadm/internal/workload_cluster_etcd_test.go +++ b/controlplane/kubeadm/internal/workload_cluster_etcd_test.go @@ -72,6 +72,7 @@ func TestUpdateEtcdExternalInKubeadmConfigMap(t *testing.T) { - 1.2.3.4 keyFile: /tmp/key_file.key kind: ClusterConfiguration + kubernetesVersion: v1.23.1 networking: {} scheduler: {} `), @@ -81,6 +82,7 @@ func TestUpdateEtcdExternalInKubeadmConfigMap(t *testing.T) { clusterConfigurationData: utilyaml.Raw(` apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration + kubernetesVersion: v1.23.1 etcd: local: {} `), @@ -93,6 +95,7 @@ func TestUpdateEtcdExternalInKubeadmConfigMap(t *testing.T) { wantClusterConfiguration: utilyaml.Raw(` apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration + kubernetesVersion: v1.23.1 etcd: local: {} `), @@ -171,6 +174,7 @@ func TestUpdateEtcdLocalInKubeadmConfigMap(t *testing.T) { imageRepository: example.com/k8s imageTag: v1.6.0 kind: ClusterConfiguration + kubernetesVersion: v1.23.1 networking: {} scheduler: {} `), @@ -181,6 +185,7 @@ func TestUpdateEtcdLocalInKubeadmConfigMap(t *testing.T) { clusterConfigurationData: utilyaml.Raw(` apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration + kubernetesVersion: v1.23.1 etcd: external: {} `), @@ -199,6 +204,7 @@ func TestUpdateEtcdLocalInKubeadmConfigMap(t *testing.T) { wantClusterConfiguration: utilyaml.Raw(` apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration + kubernetesVersion: v1.23.1 etcd: external: {} `), @@ -238,6 +244,7 @@ func TestUpdateEtcdLocalInKubeadmConfigMap(t *testing.T) { imageRepository: example.com/k8s imageTag: v1.6.0 kind: ClusterConfiguration + kubernetesVersion: v1.31.1 networking: {} proxy: {} scheduler: {} @@ -249,6 +256,7 @@ func TestUpdateEtcdLocalInKubeadmConfigMap(t *testing.T) { clusterConfigurationData: utilyaml.Raw(` apiVersion: kubeadm.k8s.io/v1beta4 kind: ClusterConfiguration + kubernetesVersion: v1.31.1 etcd: external: {} `), @@ -267,6 +275,7 @@ func TestUpdateEtcdLocalInKubeadmConfigMap(t *testing.T) { wantClusterConfiguration: utilyaml.Raw(` apiVersion: kubeadm.k8s.io/v1beta4 kind: ClusterConfiguration + kubernetesVersion: v1.31.1 etcd: external: {} `), diff --git a/controlplane/kubeadm/internal/workload_cluster_test.go b/controlplane/kubeadm/internal/workload_cluster_test.go index c07d597bf69a..14fa860211cd 100644 --- a/controlplane/kubeadm/internal/workload_cluster_test.go +++ b/controlplane/kubeadm/internal/workload_cluster_test.go @@ -259,7 +259,7 @@ func TestUpdateUpdateClusterConfigurationInKubeadmConfigMap(t *testing.T) { wantErr: true, }, { - name: "no op if mutator does not apply changes", + name: "no op if mutator does not apply changes and Kubernetes version is up-to-date", version: semver.MustParse("1.23.2"), objs: []client.Object{&corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ @@ -270,12 +270,29 @@ func TestUpdateUpdateClusterConfigurationInKubeadmConfigMap(t *testing.T) { clusterConfigurationKey: utilyaml.Raw(` apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration - kubernetesVersion: v1.16.1 + kubernetesVersion: v1.23.2 `), }, }}, mutator: func(*bootstrapv1.ClusterConfiguration) {}, wantConfigMap: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: kubeadmConfigKey, + Namespace: metav1.NamespaceSystem, + }, + Data: map[string]string{ + clusterConfigurationKey: utilyaml.Raw(` + apiVersion: kubeadm.k8s.io/v1beta3 + kind: ClusterConfiguration + kubernetesVersion: v1.23.2 + `), + }, + }, + }, + { + name: "update if mutator does not apply changes and Kubernetes version is outdated", + version: semver.MustParse("1.23.2"), + objs: []client.Object{&corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: kubeadmConfigKey, Namespace: metav1.NamespaceSystem, @@ -287,6 +304,26 @@ func TestUpdateUpdateClusterConfigurationInKubeadmConfigMap(t *testing.T) { kubernetesVersion: v1.16.1 `), }, + }}, + mutator: func(*bootstrapv1.ClusterConfiguration) {}, + wantConfigMap: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: kubeadmConfigKey, + Namespace: metav1.NamespaceSystem, + }, + Data: map[string]string{ + clusterConfigurationKey: utilyaml.Raw(` + apiServer: {} + apiVersion: kubeadm.k8s.io/v1beta3 + controllerManager: {} + dns: {} + etcd: {} + kind: ClusterConfiguration + kubernetesVersion: v1.23.2 + networking: {} + scheduler: {} + `), + }, }, }, { @@ -302,11 +339,12 @@ func TestUpdateUpdateClusterConfigurationInKubeadmConfigMap(t *testing.T) { apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration kubernetesVersion: v1.16.1 + certificatesDir: bar `), }, }}, mutator: func(c *bootstrapv1.ClusterConfiguration) { - c.KubernetesVersion = "v1.23.2" + c.CertificatesDir = "foo" }, wantConfigMap: &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ @@ -317,6 +355,7 @@ func TestUpdateUpdateClusterConfigurationInKubeadmConfigMap(t *testing.T) { clusterConfigurationKey: utilyaml.Raw(` apiServer: {} apiVersion: kubeadm.k8s.io/v1beta3 + certificatesDir: foo controllerManager: {} dns: {} etcd: {} @@ -329,7 +368,7 @@ func TestUpdateUpdateClusterConfigurationInKubeadmConfigMap(t *testing.T) { }, }, { - name: "converts kubeadm api version during mutation if required", + name: "converts kubeadm api version during mutation if required while preserving upstream only data", version: semver.MustParse("1.32.0"), objs: []client.Object{&corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ @@ -340,12 +379,19 @@ func TestUpdateUpdateClusterConfigurationInKubeadmConfigMap(t *testing.T) { clusterConfigurationKey: utilyaml.Raw(` apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration - kubernetesVersion: v1.16.1 + certificatesDir: bar + clusterName: mycluster + controlPlaneEndpoint: myControlPlaneEndpoint:6443 + kubernetesVersion: v1.23.1 + networking: + dnsDomain: myDNSDomain + podSubnet: myPodSubnet + serviceSubnet: myServiceSubnet `), }, }}, mutator: func(c *bootstrapv1.ClusterConfiguration) { - c.KubernetesVersion = "v1.32.0" + c.CertificatesDir = "foo" }, wantConfigMap: &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ @@ -356,12 +402,18 @@ func TestUpdateUpdateClusterConfigurationInKubeadmConfigMap(t *testing.T) { clusterConfigurationKey: utilyaml.Raw(` apiServer: {} apiVersion: kubeadm.k8s.io/v1beta4 + certificatesDir: foo + clusterName: mycluster + controlPlaneEndpoint: myControlPlaneEndpoint:6443 controllerManager: {} dns: {} etcd: {} kind: ClusterConfiguration kubernetesVersion: v1.32.0 - networking: {} + networking: + dnsDomain: myDNSDomain + podSubnet: myPodSubnet + serviceSubnet: myServiceSubnet proxy: {} scheduler: {} `), @@ -396,53 +448,6 @@ func TestUpdateUpdateClusterConfigurationInKubeadmConfigMap(t *testing.T) { } } -func TestUpdateKubernetesVersionInKubeadmConfigMap(t *testing.T) { - tests := []struct { - name string - version semver.Version - clusterConfigurationData string - }{ - { - name: "updates the config map and changes the kubeadm API version", - version: semver.MustParse("1.32.2"), - clusterConfigurationData: utilyaml.Raw(` - apiVersion: kubeadm.k8s.io/v1beta3 - kind: ClusterConfiguration - kubernetesVersion: v1.16.1`), - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - g := NewWithT(t) - fakeClient := fake.NewClientBuilder().WithObjects(&corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: kubeadmConfigKey, - Namespace: metav1.NamespaceSystem, - }, - Data: map[string]string{ - clusterConfigurationKey: tt.clusterConfigurationData, - }, - }).Build() - - w := &Workload{ - Client: fakeClient, - } - - err := w.UpdateClusterConfiguration(ctx, tt.version, w.UpdateKubernetesVersionInKubeadmConfigMap(tt.version)) - g.Expect(err).ToNot(HaveOccurred()) - - var actualConfig corev1.ConfigMap - g.Expect(w.Client.Get( - ctx, - client.ObjectKey{Name: kubeadmConfigKey, Namespace: metav1.NamespaceSystem}, - &actualConfig, - )).To(Succeed()) - g.Expect(actualConfig.Data[clusterConfigurationKey]).To(ContainSubstring(tt.version.String())) - }) - } -} - func TestUpdateImageRepositoryInKubeadmConfigMap(t *testing.T) { tests := []struct { name string @@ -549,6 +554,7 @@ func TestUpdateApiServerInKubeadmConfigMap(t *testing.T) { dns: {} etcd: {} kind: ClusterConfiguration + kubernetesVersion: v1.23.1 networking: {} scheduler: {} `), @@ -597,6 +603,7 @@ func TestUpdateApiServerInKubeadmConfigMap(t *testing.T) { dns: {} etcd: {} kind: ClusterConfiguration + kubernetesVersion: v1.31.1 networking: {} proxy: {} scheduler: {} @@ -680,6 +687,7 @@ func TestUpdateControllerManagerInKubeadmConfigMap(t *testing.T) { dns: {} etcd: {} kind: ClusterConfiguration + kubernetesVersion: v1.23.1 networking: {} scheduler: {} `), @@ -755,6 +763,7 @@ func TestUpdateSchedulerInKubeadmConfigMap(t *testing.T) { dns: {} etcd: {} kind: ClusterConfiguration + kubernetesVersion: v1.23.1 networking: {} scheduler: extraArgs: @@ -928,7 +937,7 @@ func TestUpdateFeatureGatesInKubeadmConfigMap(t *testing.T) { { name: "it should not add ControlPlaneKubeletLocalMode feature gate for 1.30", clusterConfigurationData: utilyaml.Raw(` - apiVersion: kubeadm.k8s.io/v1beta4 + apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration`), kubernetesVersion: semver.MustParse("1.30.0"), newClusterConfiguration: &bootstrapv1.ClusterConfiguration{ @@ -936,7 +945,7 @@ func TestUpdateFeatureGatesInKubeadmConfigMap(t *testing.T) { }, wantClusterConfiguration: &bootstrapv1.ClusterConfiguration{ TypeMeta: metav1.TypeMeta{ - APIVersion: "kubeadm.k8s.io/v1beta4", + APIVersion: "kubeadm.k8s.io/v1beta3", Kind: "ClusterConfiguration", }, FeatureGates: nil, diff --git a/docs/book/src/developer/providers/migrations/v1.10-to-v1.11.md b/docs/book/src/developer/providers/migrations/v1.10-to-v1.11.md index c746b924f255..eca3b17e4a1a 100644 --- a/docs/book/src/developer/providers/migrations/v1.10-to-v1.11.md +++ b/docs/book/src/developer/providers/migrations/v1.10-to-v1.11.md @@ -34,6 +34,7 @@ proposal because most of the changes described below are a consequence of the wo * [Contract rules for IPAM provider](#contract-rules-for-ipam-provider) * [Contract rules for MachinePool](#contract-rules-for-machinepool) * [Deprecations](#deprecations) + * [clusterctl changes](#clusterctl-changes) * [Removals scheduled for future releases](#removals-scheduled-for-future-releases) * [Suggested changes for providers](#suggested-changes-for-providers) * [How to bump to CAPI V1.11 but keep implementing the deprecated v1beta1 contract](#how-to-bump-to-capi-v111-but-keep-implementing-the-deprecated-v1beta1-contract) @@ -89,6 +90,10 @@ proposal because most of the changes described below are a consequence of the wo - the old `status.conditions` based on custom cluster API condition types will continue to exist temporarily under `status.deprecated.v1beta1.conditions` for the sake of down conversions and to provide a temporary option for users willing to continue using old conditions. +- Please pay attention to field removals, e.g. if you are using GitOps tools, either migrate to v1beta2 or make sure + to stop setting the removed fields. The removed fields won't be preserved even if setting them via v1beta1 + (as they don't exist in v1beta2). + - For example, we removed the `clusterName` field from `KubeadmControlPlane.spec.kubeadmConfigSpec.clusterConfiguration` ### Cluster @@ -214,6 +219,15 @@ proposal because most of the changes described below are a consequence of the wo however, using different timeouts for init and join will be enabled only when v1beta1 is removed. - `spec.joinConfiguration.discovery.timeout` field has been removed. Use `spec.joinConfiguration.timeouts.tlsBootstrapSeconds` instead. - The `spec.useExperimentalRetryJoin` field (deprecated in CAPI v1.2!) has been removed. +- The following `spec.kubeadmConfigSpec.clusterConfiguration` fields have been removed because they are duplicates + to fields that already exist in the Cluster object: + - `networking.serviceSubnet` (can still be set via `Cluster.spec.clusterNetwork.services.cidrBlocks`) + - `networking.podSubnet` (can still be set via `Cluster.spec.clusterNetwork.pods.cidrBlocks`) + - `networking.dnsDomain` (can still be set via `Cluster.spec.clusterNetwork.serviceDomain`) + - `kubernetesVersion` (can still be set via `Machine.spec.version`) + - `controlPlaneEndpoint` (can still be set via `Cluster.spec.controlPlaneEndpoint`) + - `clusterName` (can still be set via `Cluster.metadata.name`) + Note: The ClusterConfiguration fields could previously be used to overwrite the fields from Cluster, now we only use the fields from Cluster. - Information about the initial provisioning process is now surfacing under the new `status.initialization` field. - `status.ready` has been replaced by `status.initialization.dataSecretCreated` - Support for terminal errors has been dropped (see [dataSecretCreated](#cluster-api-contract-changes)). @@ -252,6 +266,15 @@ KubeadmConfigTemplate `spec.template.spec` has been aligned to changes in the [K however, using different timeouts for init and join will be enabled only when v1beta1 is removed. - `spec.kubeadmConfigSpec.joinConfiguration.discovery.timeout` field has been removed. Use `spec.kubeadmConfigSpec.joinConfiguration.timeouts.tlsBootstrapSeconds` instead. - The `spec.kubeadmConfigSpec.useExperimentalRetryJoin` field (deprecated in CAPI v1.2!) has been removed. +- The following `spec.kubeadmConfigSpec.clusterConfiguration` fields have been removed because they are duplicates + to fields that already exist in the Cluster object: + - `networking.serviceSubnet` (can still be set via `Cluster.spec.clusterNetwork.services.cidrBlocks`) + - `networking.podSubnet` (can still be set via `Cluster.spec.clusterNetwork.pods.cidrBlocks`) + - `networking.dnsDomain` (can still be set via `Cluster.spec.clusterNetwork.serviceDomain`) + - `kubernetesVersion` (can still be set via `KubeadmControlPlane.spec.version`) + - `controlPlaneEndpoint` (can still be set via `Cluster.spec.controlPlaneEndpoint`) + - `clusterName` (can still be set via `Cluster.metadata.name`) + Note: The ClusterConfiguration fields could previously be used to overwrite the fields from Cluster, now we only use the fields from Cluster. - Replica counters fields are now consistent with replica counters from other resources. - `status.replicas` was made a pointer and omitempty was added - `status.readyReplicas` has now a new semantic based on machine's `Ready` condition diff --git a/internal/api/bootstrap/kubeadm/v1alpha3/conversion_test.go b/internal/api/bootstrap/kubeadm/v1alpha3/conversion_test.go index f6a65742303a..32cd53893d65 100644 --- a/internal/api/bootstrap/kubeadm/v1alpha3/conversion_test.go +++ b/internal/api/bootstrap/kubeadm/v1alpha3/conversion_test.go @@ -145,6 +145,14 @@ func spokeClusterConfiguration(obj *ClusterConfiguration, c randfill.Continue) { // ClusterConfiguration.UseHyperKubeImage has been removed in v1alpha4, so setting it to false in order to avoid v1beta1 --> --> v1beta1 round trip errors. obj.UseHyperKubeImage = false + + // Drop the following fields as they have been removed in v1beta2, so we don't have to preserve them. + obj.Networking.ServiceSubnet = "" + obj.Networking.PodSubnet = "" + obj.Networking.DNSDomain = "" + obj.KubernetesVersion = "" + obj.ControlPlaneEndpoint = "" + obj.ClusterName = "" } func hubBootstrapTokenString(in *bootstrapv1.BootstrapTokenString, _ randfill.Continue) { diff --git a/internal/api/bootstrap/kubeadm/v1alpha3/zz_generated.conversion.go b/internal/api/bootstrap/kubeadm/v1alpha3/zz_generated.conversion.go index a161215b0067..20d0bf38e6ba 100644 --- a/internal/api/bootstrap/kubeadm/v1alpha3/zz_generated.conversion.go +++ b/internal/api/bootstrap/kubeadm/v1alpha3/zz_generated.conversion.go @@ -259,16 +259,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*Networking)(nil), (*v1beta2.Networking)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha3_Networking_To_v1beta2_Networking(a.(*Networking), b.(*v1beta2.Networking), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*v1beta2.Networking)(nil), (*Networking)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta2_Networking_To_v1alpha3_Networking(a.(*v1beta2.Networking), b.(*Networking), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*Partition)(nil), (*v1beta2.Partition)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha3_Partition_To_v1beta2_Partition(a.(*Partition), b.(*v1beta2.Partition), scope) }); err != nil { @@ -538,11 +528,9 @@ func autoConvert_v1alpha3_ClusterConfiguration_To_v1beta2_ClusterConfiguration(i if err := Convert_v1alpha3_Etcd_To_v1beta2_Etcd(&in.Etcd, &out.Etcd, s); err != nil { return err } - if err := Convert_v1alpha3_Networking_To_v1beta2_Networking(&in.Networking, &out.Networking, s); err != nil { - return err - } - out.KubernetesVersion = in.KubernetesVersion - out.ControlPlaneEndpoint = in.ControlPlaneEndpoint + // WARNING: in.Networking requires manual conversion: does not exist in peer-type + // WARNING: in.KubernetesVersion requires manual conversion: does not exist in peer-type + // WARNING: in.ControlPlaneEndpoint requires manual conversion: does not exist in peer-type if err := Convert_v1alpha3_APIServer_To_v1beta2_APIServer(&in.APIServer, &out.APIServer, s); err != nil { return err } @@ -559,7 +547,7 @@ func autoConvert_v1alpha3_ClusterConfiguration_To_v1beta2_ClusterConfiguration(i out.ImageRepository = in.ImageRepository // WARNING: in.UseHyperKubeImage requires manual conversion: does not exist in peer-type out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates)) - out.ClusterName = in.ClusterName + // WARNING: in.ClusterName requires manual conversion: does not exist in peer-type return nil } @@ -567,11 +555,6 @@ func autoConvert_v1beta2_ClusterConfiguration_To_v1alpha3_ClusterConfiguration(i if err := Convert_v1beta2_Etcd_To_v1alpha3_Etcd(&in.Etcd, &out.Etcd, s); err != nil { return err } - if err := Convert_v1beta2_Networking_To_v1alpha3_Networking(&in.Networking, &out.Networking, s); err != nil { - return err - } - out.KubernetesVersion = in.KubernetesVersion - out.ControlPlaneEndpoint = in.ControlPlaneEndpoint if err := Convert_v1beta2_APIServer_To_v1alpha3_APIServer(&in.APIServer, &out.APIServer, s); err != nil { return err } @@ -587,7 +570,6 @@ func autoConvert_v1beta2_ClusterConfiguration_To_v1alpha3_ClusterConfiguration(i out.CertificatesDir = in.CertificatesDir out.ImageRepository = in.ImageRepository out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates)) - out.ClusterName = in.ClusterName return nil } @@ -1374,30 +1356,6 @@ func Convert_v1beta2_NTP_To_v1alpha3_NTP(in *v1beta2.NTP, out *NTP, s conversion return autoConvert_v1beta2_NTP_To_v1alpha3_NTP(in, out, s) } -func autoConvert_v1alpha3_Networking_To_v1beta2_Networking(in *Networking, out *v1beta2.Networking, s conversion.Scope) error { - out.ServiceSubnet = in.ServiceSubnet - out.PodSubnet = in.PodSubnet - out.DNSDomain = in.DNSDomain - return nil -} - -// Convert_v1alpha3_Networking_To_v1beta2_Networking is an autogenerated conversion function. -func Convert_v1alpha3_Networking_To_v1beta2_Networking(in *Networking, out *v1beta2.Networking, s conversion.Scope) error { - return autoConvert_v1alpha3_Networking_To_v1beta2_Networking(in, out, s) -} - -func autoConvert_v1beta2_Networking_To_v1alpha3_Networking(in *v1beta2.Networking, out *Networking, s conversion.Scope) error { - out.ServiceSubnet = in.ServiceSubnet - out.PodSubnet = in.PodSubnet - out.DNSDomain = in.DNSDomain - return nil -} - -// Convert_v1beta2_Networking_To_v1alpha3_Networking is an autogenerated conversion function. -func Convert_v1beta2_Networking_To_v1alpha3_Networking(in *v1beta2.Networking, out *Networking, s conversion.Scope) error { - return autoConvert_v1beta2_Networking_To_v1alpha3_Networking(in, out, s) -} - func autoConvert_v1alpha3_NodeRegistrationOptions_To_v1beta2_NodeRegistrationOptions(in *NodeRegistrationOptions, out *v1beta2.NodeRegistrationOptions, s conversion.Scope) error { out.Name = in.Name out.CRISocket = in.CRISocket diff --git a/internal/api/bootstrap/kubeadm/v1alpha4/conversion.go b/internal/api/bootstrap/kubeadm/v1alpha4/conversion.go index 05783228375e..9692b5b3d754 100644 --- a/internal/api/bootstrap/kubeadm/v1alpha4/conversion.go +++ b/internal/api/bootstrap/kubeadm/v1alpha4/conversion.go @@ -276,6 +276,10 @@ func Convert_v1beta2_KubeadmConfigSpec_To_v1alpha4_KubeadmConfigSpec(in *bootstr return autoConvert_v1beta2_KubeadmConfigSpec_To_v1alpha4_KubeadmConfigSpec(in, out, s) } +func Convert_v1alpha4_ClusterConfiguration_To_v1beta2_ClusterConfiguration(in *ClusterConfiguration, out *bootstrapv1.ClusterConfiguration, s apimachineryconversion.Scope) error { + return autoConvert_v1alpha4_ClusterConfiguration_To_v1beta2_ClusterConfiguration(in, out, s) +} + func Convert_v1beta2_InitConfiguration_To_v1alpha4_InitConfiguration(in *bootstrapv1.InitConfiguration, out *InitConfiguration, s apimachineryconversion.Scope) error { // InitConfiguration.Patches does not exist in kubeadm v1alpha4 API. return autoConvert_v1beta2_InitConfiguration_To_v1alpha4_InitConfiguration(in, out, s) diff --git a/internal/api/bootstrap/kubeadm/v1alpha4/conversion_test.go b/internal/api/bootstrap/kubeadm/v1alpha4/conversion_test.go index 3f0e5157a53f..f7a65fc7631a 100644 --- a/internal/api/bootstrap/kubeadm/v1alpha4/conversion_test.go +++ b/internal/api/bootstrap/kubeadm/v1alpha4/conversion_test.go @@ -57,6 +57,7 @@ func KubeadmConfigFuzzFuncs(_ runtimeserializer.CodecFactory) []interface{} { return []interface{}{ hubKubeadmConfigStatus, spokeKubeadmConfigSpec, + spokeClusterConfiguration, hubBootstrapTokenString, spokeBootstrapTokenString, spokeAPIServer, @@ -68,6 +69,7 @@ func KubeadmConfigFuzzFuncs(_ runtimeserializer.CodecFactory) []interface{} { func KubeadmConfigTemplateFuzzFuncs(_ runtimeserializer.CodecFactory) []interface{} { return []interface{}{ spokeKubeadmConfigSpec, + spokeClusterConfiguration, hubBootstrapTokenString, spokeBootstrapTokenString, spokeAPIServer, @@ -120,6 +122,18 @@ func spokeKubeadmConfigSpec(in *KubeadmConfigSpec, c randfill.Continue) { in.UseExperimentalRetryJoin = false } +func spokeClusterConfiguration(in *ClusterConfiguration, c randfill.Continue) { + c.FillNoCustom(in) + + // Drop the following fields as they have been removed in v1beta2, so we don't have to preserve them. + in.Networking.ServiceSubnet = "" + in.Networking.PodSubnet = "" + in.Networking.DNSDomain = "" + in.KubernetesVersion = "" + in.ControlPlaneEndpoint = "" + in.ClusterName = "" +} + func hubBootstrapTokenString(in *bootstrapv1.BootstrapTokenString, _ randfill.Continue) { in.ID = fakeID in.Secret = fakeSecret diff --git a/internal/api/bootstrap/kubeadm/v1alpha4/zz_generated.conversion.go b/internal/api/bootstrap/kubeadm/v1alpha4/zz_generated.conversion.go index 76da51876e18..ee1a1d10ddcd 100644 --- a/internal/api/bootstrap/kubeadm/v1alpha4/zz_generated.conversion.go +++ b/internal/api/bootstrap/kubeadm/v1alpha4/zz_generated.conversion.go @@ -84,11 +84,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*ClusterConfiguration)(nil), (*v1beta2.ClusterConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha4_ClusterConfiguration_To_v1beta2_ClusterConfiguration(a.(*ClusterConfiguration), b.(*v1beta2.ClusterConfiguration), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*v1beta2.ClusterConfiguration)(nil), (*ClusterConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta2_ClusterConfiguration_To_v1alpha4_ClusterConfiguration(a.(*v1beta2.ClusterConfiguration), b.(*ClusterConfiguration), scope) }); err != nil { @@ -284,16 +279,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*Networking)(nil), (*v1beta2.Networking)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha4_Networking_To_v1beta2_Networking(a.(*Networking), b.(*v1beta2.Networking), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*v1beta2.Networking)(nil), (*Networking)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta2_Networking_To_v1alpha4_Networking(a.(*v1beta2.Networking), b.(*Networking), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*Partition)(nil), (*v1beta2.Partition)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha4_Partition_To_v1beta2_Partition(a.(*Partition), b.(*v1beta2.Partition), scope) }); err != nil { @@ -329,6 +314,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*ClusterConfiguration)(nil), (*v1beta2.ClusterConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha4_ClusterConfiguration_To_v1beta2_ClusterConfiguration(a.(*ClusterConfiguration), b.(*v1beta2.ClusterConfiguration), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*corev1alpha4.Condition)(nil), (*v1.Condition)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha4_Condition_To_v1_Condition(a.(*corev1alpha4.Condition), b.(*v1.Condition), scope) }); err != nil { @@ -548,11 +538,9 @@ func autoConvert_v1alpha4_ClusterConfiguration_To_v1beta2_ClusterConfiguration(i if err := Convert_v1alpha4_Etcd_To_v1beta2_Etcd(&in.Etcd, &out.Etcd, s); err != nil { return err } - if err := Convert_v1alpha4_Networking_To_v1beta2_Networking(&in.Networking, &out.Networking, s); err != nil { - return err - } - out.KubernetesVersion = in.KubernetesVersion - out.ControlPlaneEndpoint = in.ControlPlaneEndpoint + // WARNING: in.Networking requires manual conversion: does not exist in peer-type + // WARNING: in.KubernetesVersion requires manual conversion: does not exist in peer-type + // WARNING: in.ControlPlaneEndpoint requires manual conversion: does not exist in peer-type if err := Convert_v1alpha4_APIServer_To_v1beta2_APIServer(&in.APIServer, &out.APIServer, s); err != nil { return err } @@ -568,24 +556,14 @@ func autoConvert_v1alpha4_ClusterConfiguration_To_v1beta2_ClusterConfiguration(i out.CertificatesDir = in.CertificatesDir out.ImageRepository = in.ImageRepository out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates)) - out.ClusterName = in.ClusterName + // WARNING: in.ClusterName requires manual conversion: does not exist in peer-type return nil } -// Convert_v1alpha4_ClusterConfiguration_To_v1beta2_ClusterConfiguration is an autogenerated conversion function. -func Convert_v1alpha4_ClusterConfiguration_To_v1beta2_ClusterConfiguration(in *ClusterConfiguration, out *v1beta2.ClusterConfiguration, s conversion.Scope) error { - return autoConvert_v1alpha4_ClusterConfiguration_To_v1beta2_ClusterConfiguration(in, out, s) -} - func autoConvert_v1beta2_ClusterConfiguration_To_v1alpha4_ClusterConfiguration(in *v1beta2.ClusterConfiguration, out *ClusterConfiguration, s conversion.Scope) error { if err := Convert_v1beta2_Etcd_To_v1alpha4_Etcd(&in.Etcd, &out.Etcd, s); err != nil { return err } - if err := Convert_v1beta2_Networking_To_v1alpha4_Networking(&in.Networking, &out.Networking, s); err != nil { - return err - } - out.KubernetesVersion = in.KubernetesVersion - out.ControlPlaneEndpoint = in.ControlPlaneEndpoint if err := Convert_v1beta2_APIServer_To_v1alpha4_APIServer(&in.APIServer, &out.APIServer, s); err != nil { return err } @@ -601,7 +579,6 @@ func autoConvert_v1beta2_ClusterConfiguration_To_v1alpha4_ClusterConfiguration(i out.CertificatesDir = in.CertificatesDir out.ImageRepository = in.ImageRepository out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates)) - out.ClusterName = in.ClusterName return nil } @@ -1416,30 +1393,6 @@ func Convert_v1beta2_NTP_To_v1alpha4_NTP(in *v1beta2.NTP, out *NTP, s conversion return autoConvert_v1beta2_NTP_To_v1alpha4_NTP(in, out, s) } -func autoConvert_v1alpha4_Networking_To_v1beta2_Networking(in *Networking, out *v1beta2.Networking, s conversion.Scope) error { - out.ServiceSubnet = in.ServiceSubnet - out.PodSubnet = in.PodSubnet - out.DNSDomain = in.DNSDomain - return nil -} - -// Convert_v1alpha4_Networking_To_v1beta2_Networking is an autogenerated conversion function. -func Convert_v1alpha4_Networking_To_v1beta2_Networking(in *Networking, out *v1beta2.Networking, s conversion.Scope) error { - return autoConvert_v1alpha4_Networking_To_v1beta2_Networking(in, out, s) -} - -func autoConvert_v1beta2_Networking_To_v1alpha4_Networking(in *v1beta2.Networking, out *Networking, s conversion.Scope) error { - out.ServiceSubnet = in.ServiceSubnet - out.PodSubnet = in.PodSubnet - out.DNSDomain = in.DNSDomain - return nil -} - -// Convert_v1beta2_Networking_To_v1alpha4_Networking is an autogenerated conversion function. -func Convert_v1beta2_Networking_To_v1alpha4_Networking(in *v1beta2.Networking, out *Networking, s conversion.Scope) error { - return autoConvert_v1beta2_Networking_To_v1alpha4_Networking(in, out, s) -} - func autoConvert_v1alpha4_NodeRegistrationOptions_To_v1beta2_NodeRegistrationOptions(in *NodeRegistrationOptions, out *v1beta2.NodeRegistrationOptions, s conversion.Scope) error { out.Name = in.Name out.CRISocket = in.CRISocket diff --git a/internal/api/controlplane/kubeadm/v1alpha3/conversion_test.go b/internal/api/controlplane/kubeadm/v1alpha3/conversion_test.go index 8da3a4e455e7..ad2a888b4c5e 100644 --- a/internal/api/controlplane/kubeadm/v1alpha3/conversion_test.go +++ b/internal/api/controlplane/kubeadm/v1alpha3/conversion_test.go @@ -138,6 +138,14 @@ func spokeKubeadmClusterConfiguration(obj *bootstrapv1alpha3.ClusterConfiguratio // ClusterConfiguration.UseHyperKubeImage has been removed in v1alpha4, so setting it to false in order to avoid v1alpha3 --> v1alpha4 --> v1alpha3 round trip errors. obj.UseHyperKubeImage = false + + // Drop the following fields as they have been removed in v1beta2, so we don't have to preserve them. + obj.Networking.ServiceSubnet = "" + obj.Networking.PodSubnet = "" + obj.Networking.DNSDomain = "" + obj.KubernetesVersion = "" + obj.ControlPlaneEndpoint = "" + obj.ClusterName = "" } func spokeKubeadmConfigSpec(in *bootstrapv1alpha3.KubeadmConfigSpec, c randfill.Continue) { diff --git a/internal/api/controlplane/kubeadm/v1alpha4/conversion_test.go b/internal/api/controlplane/kubeadm/v1alpha4/conversion_test.go index 69e54d206ea2..27a491952135 100644 --- a/internal/api/controlplane/kubeadm/v1alpha4/conversion_test.go +++ b/internal/api/controlplane/kubeadm/v1alpha4/conversion_test.go @@ -66,6 +66,7 @@ func KubeadmControlPlaneFuzzFuncs(_ runtimeserializer.CodecFactory) []interface{ hubBootstrapTokenString, spokeBootstrapTokenString, spokeKubeadmConfigSpec, + spokeClusterConfiguration, spokeAPIServer, spokeDiscovery, hubKubeadmConfigSpec, @@ -78,6 +79,7 @@ func KubeadmControlPlaneTemplateFuzzFuncs(_ runtimeserializer.CodecFactory) []in hubBootstrapTokenString, spokeBootstrapTokenString, spokeKubeadmConfigSpec, + spokeClusterConfiguration, spokeAPIServer, spokeDiscovery, hubKubeadmConfigSpec, @@ -161,6 +163,18 @@ func spokeKubeadmConfigSpec(in *bootstrapv1alpha4.KubeadmConfigSpec, c randfill. in.UseExperimentalRetryJoin = false } +func spokeClusterConfiguration(in *bootstrapv1alpha4.ClusterConfiguration, c randfill.Continue) { + c.FillNoCustom(in) + + // Drop the following fields as they have been removed in v1beta2, so we don't have to preserve them. + in.Networking.ServiceSubnet = "" + in.Networking.PodSubnet = "" + in.Networking.DNSDomain = "" + in.KubernetesVersion = "" + in.ControlPlaneEndpoint = "" + in.ClusterName = "" +} + func spokeAPIServer(in *bootstrapv1alpha4.APIServer, c randfill.Continue) { c.FillNoCustom(in)