Skip to content

Commit 33c245f

Browse files
committed
KCP: Implement CanUpdateMachine
1 parent 3f1bdf1 commit 33c245f

File tree

25 files changed

+2217
-170
lines changed

25 files changed

+2217
-170
lines changed

api/runtime/hooks/v1alpha1/inplaceupdate_types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ type Patch struct {
9090
Patch []byte `json:"patch,omitempty"`
9191
}
9292

93+
// IsDefined returns true if one of the fields of Patch is set.
94+
func (p *Patch) IsDefined() bool {
95+
return p.PatchType != "" || len(p.Patch) > 0
96+
}
97+
9398
// CanUpdateMachine is the hook that will be called to determine if an extension
9499
// can handle specific machine changes for in-place updates.
95100
func CanUpdateMachine(*CanUpdateMachineRequest, *CanUpdateMachineResponse) {}

controlplane/kubeadm/controllers/alias.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@ import (
2727

2828
"sigs.k8s.io/cluster-api/controllers/clustercache"
2929
kubeadmcontrolplanecontrollers "sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/controllers"
30+
runtimeclient "sigs.k8s.io/cluster-api/exp/runtime/client"
3031
)
3132

3233
// KubeadmControlPlaneReconciler reconciles a KubeadmControlPlane object.
3334
type KubeadmControlPlaneReconciler struct {
3435
Client client.Client
3536
SecretCachingClient client.Client
37+
RuntimeClient runtimeclient.Client
3638
ClusterCache clustercache.ClusterCache
3739

3840
EtcdDialTimeout time.Duration
@@ -50,6 +52,7 @@ func (r *KubeadmControlPlaneReconciler) SetupWithManager(ctx context.Context, mg
5052
return (&kubeadmcontrolplanecontrollers.KubeadmControlPlaneReconciler{
5153
Client: r.Client,
5254
SecretCachingClient: r.SecretCachingClient,
55+
RuntimeClient: r.RuntimeClient,
5356
ClusterCache: r.ClusterCache,
5457
EtcdDialTimeout: r.EtcdDialTimeout,
5558
EtcdCallTimeout: r.EtcdCallTimeout,

controlplane/kubeadm/internal/controllers/controller.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import (
4646
clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2"
4747
"sigs.k8s.io/cluster-api/controllers/clustercache"
4848
"sigs.k8s.io/cluster-api/controlplane/kubeadm/internal"
49+
runtimeclient "sigs.k8s.io/cluster-api/exp/runtime/client"
4950
"sigs.k8s.io/cluster-api/feature"
5051
"sigs.k8s.io/cluster-api/internal/contract"
5152
"sigs.k8s.io/cluster-api/internal/util/ssa"
@@ -80,6 +81,7 @@ const (
8081
type KubeadmControlPlaneReconciler struct {
8182
Client client.Client
8283
SecretCachingClient client.Client
84+
RuntimeClient runtimeclient.Client
8385
controller controller.Controller
8486
recorder record.EventRecorder
8587
ClusterCache clustercache.ClusterCache
@@ -97,10 +99,13 @@ type KubeadmControlPlaneReconciler struct {
9799
managementClusterUncached internal.ManagementCluster
98100
ssaCache ssa.Cache
99101

100-
// Only used for testing
101-
overrideTryInPlaceUpdateFunc func(ctx context.Context, controlPlane *internal.ControlPlane, machineToInPlaceUpdate *clusterv1.Machine, machineUpToDateResult internal.UpToDateResult) (bool, ctrl.Result, error)
102-
overrideScaleUpControlPlaneFunc func(ctx context.Context, controlPlane *internal.ControlPlane) (ctrl.Result, error)
103-
overrideScaleDownControlPlaneFunc func(ctx context.Context, controlPlane *internal.ControlPlane, machineToDelete *clusterv1.Machine) (ctrl.Result, error)
102+
// Only used for testing.
103+
overrideTryInPlaceUpdateFunc func(ctx context.Context, controlPlane *internal.ControlPlane, machineToInPlaceUpdate *clusterv1.Machine, machineUpToDateResult internal.UpToDateResult) (bool, ctrl.Result, error)
104+
overrideScaleUpControlPlaneFunc func(ctx context.Context, controlPlane *internal.ControlPlane) (ctrl.Result, error)
105+
overrideScaleDownControlPlaneFunc func(ctx context.Context, controlPlane *internal.ControlPlane, machineToDelete *clusterv1.Machine) (ctrl.Result, error)
106+
overridePreflightChecksFunc func(ctx context.Context, controlPlane *internal.ControlPlane, excludeFor ...*clusterv1.Machine) ctrl.Result
107+
overrideCanUpdateMachineFunc func(ctx context.Context, machine *clusterv1.Machine, machineUpToDateResult internal.UpToDateResult) (bool, error)
108+
overrideCanExtensionsUpdateMachine func(ctx context.Context, machine *clusterv1.Machine, machineUpToDateResult internal.UpToDateResult, extensionHandlers []string) (bool, []string, error)
104109
}
105110

106111
func (r *KubeadmControlPlaneReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error {
@@ -115,6 +120,9 @@ func (r *KubeadmControlPlaneReconciler) SetupWithManager(ctx context.Context, mg
115120
"EtcdDialTimeout and EtcdCallTimeout must not be 0 and " +
116121
"RemoteConditionsGracePeriod must not be < 2m")
117122
}
123+
if feature.Gates.Enabled(feature.InPlaceUpdates) && r.RuntimeClient == nil {
124+
return errors.New("RuntimeClient must not be nil when InPlaceUpdates feature gate is enabled")
125+
}
118126

119127
predicateLog := ctrl.LoggerFrom(ctx).WithValues("controller", "kubeadmcontrolplane")
120128
c, err := ctrl.NewControllerManagedBy(mgr).
@@ -814,7 +822,8 @@ func (r *KubeadmControlPlaneReconciler) syncMachines(ctx context.Context, contro
814822
if err != nil {
815823
return errors.Wrapf(err, "failed to update Machine: %s", klog.KObj(m))
816824
}
817-
// Note: Ensure ControlPlane has the latest version of the Machine.
825+
// Note: Ensure ControlPlane has the latest version of the Machine. This is required because
826+
// e.g. the in-place update code that is called later has to use the latest version of the Machine.
818827
controlPlane.Machines[machineName] = updatedMachine
819828
if _, ok := controlPlane.MachinesNotUpToDate[machineName]; ok {
820829
controlPlane.MachinesNotUpToDate[machineName] = updatedMachine

controlplane/kubeadm/internal/controllers/inplace.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package controllers
1919
import (
2020
"context"
2121

22+
"github.com/pkg/errors"
2223
ctrl "sigs.k8s.io/controller-runtime"
2324

2425
clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2"
@@ -35,6 +36,26 @@ func (r *KubeadmControlPlaneReconciler) tryInPlaceUpdate(
3536
return r.overrideTryInPlaceUpdateFunc(ctx, controlPlane, machineToInPlaceUpdate, machineUpToDateResult)
3637
}
3738

38-
// Always fallback to scale down until in-place is implemented.
39+
// Run preflight checks to ensure that the control plane is stable before proceeding with in-place update operation.
40+
if resultForAllMachines := r.preflightChecks(ctx, controlPlane); !resultForAllMachines.IsZero() {
41+
// We should not block a scale down of an unhealthy Machine that would work.
42+
if result := r.preflightChecks(ctx, controlPlane, machineToInPlaceUpdate); result.IsZero() {
43+
// Fallback to scale down.
44+
return true, ctrl.Result{}, nil
45+
}
46+
47+
return false, resultForAllMachines, nil
48+
}
49+
50+
canUpdate, err := r.canUpdateMachine(ctx, machineToInPlaceUpdate, machineUpToDateResult)
51+
if err != nil {
52+
return false, ctrl.Result{}, errors.Wrapf(err, "failed to determine if Machine %s can be updated in-place", machineToInPlaceUpdate.Name)
53+
}
54+
55+
if !canUpdate {
56+
return true, ctrl.Result{}, nil
57+
}
58+
59+
// Always fallback to scale down until triggering in-place updates is implemented.
3960
return true, ctrl.Result{}, nil
4061
}

0 commit comments

Comments
 (0)