diff --git a/api/core/v1beta1/cluster_types.go b/api/core/v1beta1/cluster_types.go index 51aa4e2c5dea..2d69ed28d49b 100644 --- a/api/core/v1beta1/cluster_types.go +++ b/api/core/v1beta1/cluster_types.go @@ -682,6 +682,10 @@ type MachineDeploymentTopology struct { // +kubebuilder:validation:MaxLength=256 Class string `json:"class"` + // version is the Kubernetes version of the worker group, can only be used if auto-upgrade is disabled. + // +optional + Version *string `json:"version,omitempty"` + // name is the unique identifier for this MachineDeploymentTopology. // The value is used with other unique identifiers to create a MachineDeployment's Name // (e.g. cluster's name, etc). In case the name is greater than the allowed maximum length, diff --git a/api/core/v1beta1/zz_generated.conversion.go b/api/core/v1beta1/zz_generated.conversion.go index cb077715089e..1a5b7cc7d9b9 100644 --- a/api/core/v1beta1/zz_generated.conversion.go +++ b/api/core/v1beta1/zz_generated.conversion.go @@ -2538,6 +2538,7 @@ func autoConvert_v1beta1_MachineDeploymentTopology_To_v1beta2_MachineDeploymentT return err } out.Class = in.Class + out.Version = (*string)(unsafe.Pointer(in.Version)) out.Name = in.Name if err := v1.Convert_Pointer_string_To_string(&in.FailureDomain, &out.FailureDomain, s); err != nil { return err @@ -2558,6 +2559,7 @@ func autoConvert_v1beta2_MachineDeploymentTopology_To_v1beta1_MachineDeploymentT if err := Convert_v1beta2_ObjectMeta_To_v1beta1_ObjectMeta(&in.Metadata, &out.Metadata, s); err != nil { return err } + out.Version = (*string)(unsafe.Pointer(in.Version)) out.Class = in.Class out.Name = in.Name if err := v1.Convert_string_To_Pointer_string(&in.FailureDomain, &out.FailureDomain, s); err != nil { diff --git a/api/core/v1beta1/zz_generated.deepcopy.go b/api/core/v1beta1/zz_generated.deepcopy.go index a1b090669cb4..7aef9141aeed 100644 --- a/api/core/v1beta1/zz_generated.deepcopy.go +++ b/api/core/v1beta1/zz_generated.deepcopy.go @@ -1451,6 +1451,11 @@ func (in *MachineDeploymentStrategy) DeepCopy() *MachineDeploymentStrategy { func (in *MachineDeploymentTopology) DeepCopyInto(out *MachineDeploymentTopology) { *out = *in in.Metadata.DeepCopyInto(&out.Metadata) + if in.Version != nil { + in, out := &in.Version, &out.Version + *out = new(string) + **out = **in + } if in.FailureDomain != nil { in, out := &in.FailureDomain, &out.FailureDomain *out = new(string) diff --git a/api/core/v1beta1/zz_generated.openapi.go b/api/core/v1beta1/zz_generated.openapi.go index 13a78b23719c..a744c1fb89c1 100644 --- a/api/core/v1beta1/zz_generated.openapi.go +++ b/api/core/v1beta1/zz_generated.openapi.go @@ -2560,6 +2560,13 @@ func schema_cluster_api_api_core_v1beta1_MachineDeploymentTopology(ref common.Re Format: "", }, }, + "version": { + SchemaProps: spec.SchemaProps{ + Description: "version is the Kubernetes version of the worker group, can only be used if auto-upgrade is disabled.", + Type: []string{"string"}, + Format: "", + }, + }, "name": { SchemaProps: spec.SchemaProps{ Description: "name is the unique identifier for this MachineDeploymentTopology. The value is used with other unique identifiers to create a MachineDeployment's Name (e.g. cluster's name, etc). In case the name is greater than the allowed maximum length, the values are hashed together.", diff --git a/api/core/v1beta2/cluster_types.go b/api/core/v1beta2/cluster_types.go index 15ba5cc50b4a..e06739f5d51e 100644 --- a/api/core/v1beta2/cluster_types.go +++ b/api/core/v1beta2/cluster_types.go @@ -818,6 +818,12 @@ type MachineDeploymentTopology struct { // +optional Metadata ObjectMeta `json:"metadata,omitempty,omitzero"` + //TODO: validation with auto-upgrade + + // version is the Kubernetes version of the worker group, can only be used if auto-upgrade is disabled. + // +optional + Version *string `json:"version,omitempty"` + // class is the name of the MachineDeploymentClass used to create the set of worker nodes. // This should match one of the deployment classes defined in the ClusterClass object // mentioned in the `Cluster.Spec.Class` field. diff --git a/api/core/v1beta2/zz_generated.deepcopy.go b/api/core/v1beta2/zz_generated.deepcopy.go index bedf1cfdf308..dd94e754dd89 100644 --- a/api/core/v1beta2/zz_generated.deepcopy.go +++ b/api/core/v1beta2/zz_generated.deepcopy.go @@ -1909,6 +1909,11 @@ func (in *MachineDeploymentStrategyRollingUpdate) DeepCopy() *MachineDeploymentS func (in *MachineDeploymentTopology) DeepCopyInto(out *MachineDeploymentTopology) { *out = *in in.Metadata.DeepCopyInto(&out.Metadata) + if in.Version != nil { + in, out := &in.Version, &out.Version + *out = new(string) + **out = **in + } if in.Replicas != nil { in, out := &in.Replicas, &out.Replicas *out = new(int32) diff --git a/api/core/v1beta2/zz_generated.openapi.go b/api/core/v1beta2/zz_generated.openapi.go index e903b3e2786c..cafa112e9653 100644 --- a/api/core/v1beta2/zz_generated.openapi.go +++ b/api/core/v1beta2/zz_generated.openapi.go @@ -3378,6 +3378,13 @@ func schema_cluster_api_api_core_v1beta2_MachineDeploymentTopology(ref common.Re Ref: ref("sigs.k8s.io/cluster-api/api/core/v1beta2.ObjectMeta"), }, }, + "version": { + SchemaProps: spec.SchemaProps{ + Description: "version is the Kubernetes version of the worker group, can only be used if auto-upgrade is disabled.", + Type: []string{"string"}, + Format: "", + }, + }, "class": { SchemaProps: spec.SchemaProps{ Description: "class is the name of the MachineDeploymentClass used to create the set of worker nodes. This should match one of the deployment classes defined in the ClusterClass object mentioned in the `Cluster.Spec.Class` field.", diff --git a/bootstrap/kubeadm/config/default/manager_image_patch.yaml b/bootstrap/kubeadm/config/default/manager_image_patch.yaml index 21edd7e47b4a..0e637418dca8 100644 --- a/bootstrap/kubeadm/config/default/manager_image_patch.yaml +++ b/bootstrap/kubeadm/config/default/manager_image_patch.yaml @@ -7,5 +7,5 @@ spec: template: spec: containers: - - image: gcr.io/k8s-staging-cluster-api/kubeadm-bootstrap-controller:main + - image: igor-test-bootstrap-arm64:dev name: manager diff --git a/config/crd/bases/cluster.x-k8s.io_clusters.yaml b/config/crd/bases/cluster.x-k8s.io_clusters.yaml index 98eeb9d4fd14..0799d0ce52bf 100644 --- a/config/crd/bases/cluster.x-k8s.io_clusters.yaml +++ b/config/crd/bases/cluster.x-k8s.io_clusters.yaml @@ -1722,6 +1722,11 @@ spec: - name x-kubernetes-list-type: map type: object + version: + description: version is the Kubernetes version of the + worker group, can only be used if auto-upgrade is + disabled. + type: string required: - class - name @@ -3235,6 +3240,11 @@ spec: - name x-kubernetes-list-type: map type: object + version: + description: version is the Kubernetes version of the + worker group, can only be used if auto-upgrade is + disabled. + type: string required: - class - name diff --git a/config/default/manager_image_patch.yaml b/config/default/manager_image_patch.yaml index 95f09097b7f8..7157ed589648 100644 --- a/config/default/manager_image_patch.yaml +++ b/config/default/manager_image_patch.yaml @@ -7,5 +7,5 @@ spec: template: spec: containers: - - image: gcr.io/k8s-staging-cluster-api/cluster-api-controller:main + - image: igor-test-arm64:dev name: manager diff --git a/exp/topology/desiredstate/desired_state.go b/exp/topology/desiredstate/desired_state.go index c8b1fe972973..4f3fa98b2127 100644 --- a/exp/topology/desiredstate/desired_state.go +++ b/exp/topology/desiredstate/desired_state.go @@ -107,6 +107,8 @@ func (g *generator) Generate(ctx context.Context, s *scope.Scope) (*scope.Cluste } } + //TODO: remove MD from here if using user-managed + // Mark all the MachineDeployments that are currently upgrading. // This captured information is used for: // - Building the TopologyReconciled condition. @@ -934,6 +936,11 @@ func (g *generator) computeMachineDeployment(ctx context.Context, s *scope.Scope // the current control plane and the version defined in the topology. func (g *generator) computeMachineDeploymentVersion(s *scope.Scope, machineDeploymentTopology clusterv1.MachineDeploymentTopology, currentMDState *scope.MachineDeploymentState) string { desiredVersion := s.Blueprint.Topology.Version + if machineDeploymentTopology.Version != nil { + // Return early if the auto-upgrade is disabled. + return *machineDeploymentTopology.Version + } + // If creating a new machine deployment, mark it as pending if the control plane is not // yet stable. Creating a new MD while the control plane is upgrading can lead to unexpected race conditions. // Example: join could fail if the load balancers are slow in detecting when CP machines are diff --git a/internal/api/core/v1alpha4/zz_generated.conversion.go b/internal/api/core/v1alpha4/zz_generated.conversion.go index aac08636eb23..f6b1e25046b9 100644 --- a/internal/api/core/v1alpha4/zz_generated.conversion.go +++ b/internal/api/core/v1alpha4/zz_generated.conversion.go @@ -1270,6 +1270,7 @@ func autoConvert_v1beta2_MachineDeploymentTopology_To_v1alpha4_MachineDeployment if err := Convert_v1beta2_ObjectMeta_To_v1alpha4_ObjectMeta(&in.Metadata, &out.Metadata, s); err != nil { return err } + // WARNING: in.Version requires manual conversion: does not exist in peer-type out.Class = in.Class out.Name = in.Name // WARNING: in.FailureDomain requires manual conversion: does not exist in peer-type diff --git a/internal/controllers/machineset/machineset_preflight.go b/internal/controllers/machineset/machineset_preflight.go index 0be375c78367..c9a205daf6ea 100644 --- a/internal/controllers/machineset/machineset_preflight.go +++ b/internal/controllers/machineset/machineset_preflight.go @@ -212,6 +212,7 @@ func (r *Reconciler) kubeadmVersionPreflightCheck(cpSemver, msSemver semver.Vers return nil } +// TODO: this preflight check should always be skipped for MachineSets that are removed from topology auto version mgmt func (r *Reconciler) controlPlaneVersionPreflightCheck(cluster *clusterv1.Cluster, cpVersion, msVersion string) preflightCheckErrorMessage { if feature.Gates.Enabled(feature.ClusterTopology) && cluster.Spec.Topology != nil { if cpVersion != msVersion {