Skip to content

Commit cc45432

Browse files
authored
Merge pull request #3234 from sedefsavas/3170
🐛 KubeadmControlPlane shouldn't rely on hashing to determine if a Machine is outdated
2 parents 34f0443 + 38d8699 commit cc45432

File tree

12 files changed

+603
-138
lines changed

12 files changed

+603
-138
lines changed

api/v1alpha3/common_types.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ const (
3939
PausedAnnotation = "cluster.x-k8s.io/paused"
4040

4141
// TemplateClonedFromNameAnnotation is the infrastructure machine annotation that stores the name of the infrastructure template resource
42-
// that was cloned for the machine.
42+
// that was cloned for the machine. This annotation is set only during cloning a template. Older/adopted machines will not have this annotation.
4343
TemplateClonedFromNameAnnotation = "cluster.x-k8s.io/cloned-from-name"
4444

4545
// TemplateClonedFromGroupKindAnnotation is the infrastructure machine annotation that stores the group-kind of the infrastructure template resource
46-
// that was cloned for the machine.
46+
// that was cloned for the machine. This annotation is set only during cloning a template. Older/adopted machines will not have this annotation.
4747
TemplateClonedFromGroupKindAnnotation = "cluster.x-k8s.io/cloned-from-groupkind"
4848

4949
// ClusterSecretType defines the type of secret created by core components

controlplane/kubeadm/api/v1alpha3/kubeadm_control_plane_types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ const (
3131

3232
// SkipCoreDNSAnnotation annotation explicitly skips reconciling CoreDNS if set
3333
SkipCoreDNSAnnotation = "controlplane.cluster.x-k8s.io/skip-coredns"
34+
35+
// KubeadmClusterConfigurationAnnotation is a machine annotation that stores the json-marshalled string of KCP ClusterConfiguration.
36+
// This annotation is used to detect any changes in ClusterConfiguration and trigger machine rollout in KCP.
37+
KubeadmClusterConfigurationAnnotation = "controlplane.cluster.x-k8s.io/kubeadm-cluster-configuration"
3438
)
3539

3640
// KubeadmControlPlaneSpec defines the desired state of KubeadmControlPlane.

controlplane/kubeadm/controllers/controller.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,14 +291,14 @@ func (r *KubeadmControlPlaneReconciler) reconcile(ctx context.Context, cluster *
291291
conditions.SetAggregate(controlPlane.KCP, controlplanev1.MachinesReadyCondition, ownedMachines.ConditionGetters(), conditions.AddSourceRef())
292292

293293
// Control plane machines rollout due to configuration changes (e.g. upgrades) takes precedence over other operations.
294-
needRollout := controlPlane.MachinesNeedingRollout()
294+
needRollout := r.machinesNeedingRollout(ctx, controlPlane)
295295
switch {
296296
case len(needRollout) > 0:
297297
logger.Info("Rolling out Control Plane machines")
298298
// NOTE: we are using Status.UpdatedReplicas from the previous reconciliation only to provide a meaningful message
299299
// and this does not influence any reconciliation logic.
300300
conditions.MarkFalse(controlPlane.KCP, controlplanev1.MachinesSpecUpToDateCondition, controlplanev1.RollingUpdateInProgressReason, clusterv1.ConditionSeverityWarning, "Rolling %d replicas with outdated spec (%d replicas up to date)", len(needRollout), kcp.Status.UpdatedReplicas)
301-
return r.upgradeControlPlane(ctx, cluster, kcp, controlPlane)
301+
return r.upgradeControlPlane(ctx, cluster, kcp, controlPlane, needRollout)
302302
default:
303303
// make sure last upgrade operation is marked as completed.
304304
// NOTE: we are checking the condition already exists in order to avoid to set this condition at the first
@@ -327,7 +327,8 @@ func (r *KubeadmControlPlaneReconciler) reconcile(ctx context.Context, cluster *
327327
// We are scaling down
328328
case numMachines > desiredReplicas:
329329
logger.Info("Scaling down control plane", "Desired", desiredReplicas, "Existing", numMachines)
330-
return r.scaleDownControlPlane(ctx, cluster, kcp, controlPlane)
330+
// The last parameter (i.e. machines needing to be rolled out) should always be empty here.
331+
return r.scaleDownControlPlane(ctx, cluster, kcp, controlPlane, internal.FilterableMachineCollection{})
331332
}
332333

333334
// Get the workload cluster client.

controlplane/kubeadm/controllers/helpers.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package controllers
1818

1919
import (
2020
"context"
21+
"encoding/json"
2122
"strings"
2223

2324
"github.com/pkg/errors"
@@ -33,6 +34,7 @@ import (
3334
controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1alpha3"
3435
"sigs.k8s.io/cluster-api/controlplane/kubeadm/internal"
3536
"sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/hash"
37+
"sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/machinefilters"
3638
capierrors "sigs.k8s.io/cluster-api/errors"
3739
"sigs.k8s.io/cluster-api/util"
3840
"sigs.k8s.io/cluster-api/util/certs"
@@ -241,8 +243,36 @@ func (r *KubeadmControlPlaneReconciler) generateMachine(ctx context.Context, kcp
241243
},
242244
}
243245

246+
// Machine's bootstrap config may be missing ClusterConfiguration if it is not the first machine in the control plane.
247+
// We store ClusterConfiguration as annotation here to detect any changes in KCP ClusterConfiguration and rollout the machine if any.
248+
clusterConfig, err := json.Marshal(kcp.Spec.KubeadmConfigSpec.ClusterConfiguration)
249+
if err != nil {
250+
return errors.Wrap(err, "failed to marshal cluster configuration")
251+
}
252+
machine.SetAnnotations(map[string]string{controlplanev1.KubeadmClusterConfigurationAnnotation: string(clusterConfig)})
253+
244254
if err := r.Client.Create(ctx, machine); err != nil {
245-
return errors.Wrap(err, "Failed to create machine")
255+
return errors.Wrap(err, "failed to create machine")
246256
}
247257
return nil
248258
}
259+
260+
// machinesNeedingRollout return a list of machines that need to be rolled out.
261+
func (r *KubeadmControlPlaneReconciler) machinesNeedingRollout(ctx context.Context, c *internal.ControlPlane) internal.FilterableMachineCollection {
262+
now := metav1.Now()
263+
264+
// Ignore machines to be deleted.
265+
machines := c.Machines.Filter(machinefilters.Not(machinefilters.HasDeletionTimestamp))
266+
267+
// Return machines if their creation timestamp is older than the KCP.Spec.UpgradeAfter, or any machine with an outdated configuration.
268+
if c.KCP.Spec.UpgradeAfter != nil && c.KCP.Spec.UpgradeAfter.Before(&now) {
269+
return machines.Filter(machinefilters.Or(
270+
// Machines that are old.
271+
machinefilters.OlderThan(c.KCP.Spec.UpgradeAfter),
272+
// Machines that do not match with KCP config.
273+
machinefilters.Not(machinefilters.MatchesKCPConfiguration(ctx, r.Client, *c.KCP, *c.Cluster)),
274+
))
275+
}
276+
277+
return machines.Filter(machinefilters.Not(machinefilters.MatchesKCPConfiguration(ctx, r.Client, *c.KCP, *c.Cluster)))
278+
}

0 commit comments

Comments
 (0)