Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions api/runtime/hooks/v1alpha1/inplaceupdate_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ type Patch struct {
Patch []byte `json:"patch,omitempty"`
}

// IsDefined returns true if one of the fields of Patch is set.
func (p *Patch) IsDefined() bool {
return p.PatchType != "" || len(p.Patch) > 0
}

// CanUpdateMachine is the hook that will be called to determine if an extension
// can handle specific machine changes for in-place updates.
func CanUpdateMachine(*CanUpdateMachineRequest, *CanUpdateMachineResponse) {}
Expand Down
3 changes: 3 additions & 0 deletions controlplane/kubeadm/controllers/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ import (

"sigs.k8s.io/cluster-api/controllers/clustercache"
kubeadmcontrolplanecontrollers "sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/controllers"
runtimeclient "sigs.k8s.io/cluster-api/exp/runtime/client"
)

// KubeadmControlPlaneReconciler reconciles a KubeadmControlPlane object.
type KubeadmControlPlaneReconciler struct {
Client client.Client
SecretCachingClient client.Client
RuntimeClient runtimeclient.Client
ClusterCache clustercache.ClusterCache

EtcdDialTimeout time.Duration
Expand All @@ -50,6 +52,7 @@ func (r *KubeadmControlPlaneReconciler) SetupWithManager(ctx context.Context, mg
return (&kubeadmcontrolplanecontrollers.KubeadmControlPlaneReconciler{
Client: r.Client,
SecretCachingClient: r.SecretCachingClient,
RuntimeClient: r.RuntimeClient,
ClusterCache: r.ClusterCache,
EtcdDialTimeout: r.EtcdDialTimeout,
EtcdCallTimeout: r.EtcdCallTimeout,
Expand Down
19 changes: 14 additions & 5 deletions controlplane/kubeadm/internal/controllers/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import (
clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2"
"sigs.k8s.io/cluster-api/controllers/clustercache"
"sigs.k8s.io/cluster-api/controlplane/kubeadm/internal"
runtimeclient "sigs.k8s.io/cluster-api/exp/runtime/client"
"sigs.k8s.io/cluster-api/feature"
"sigs.k8s.io/cluster-api/internal/contract"
"sigs.k8s.io/cluster-api/internal/util/ssa"
Expand Down Expand Up @@ -80,6 +81,7 @@ const (
type KubeadmControlPlaneReconciler struct {
Client client.Client
SecretCachingClient client.Client
RuntimeClient runtimeclient.Client
controller controller.Controller
recorder record.EventRecorder
ClusterCache clustercache.ClusterCache
Expand All @@ -97,10 +99,13 @@ type KubeadmControlPlaneReconciler struct {
managementClusterUncached internal.ManagementCluster
ssaCache ssa.Cache

// Only used for testing
overrideTryInPlaceUpdateFunc func(ctx context.Context, controlPlane *internal.ControlPlane, machineToInPlaceUpdate *clusterv1.Machine, machineUpToDateResult internal.UpToDateResult) (bool, ctrl.Result, error)
overrideScaleUpControlPlaneFunc func(ctx context.Context, controlPlane *internal.ControlPlane) (ctrl.Result, error)
overrideScaleDownControlPlaneFunc func(ctx context.Context, controlPlane *internal.ControlPlane, machineToDelete *clusterv1.Machine) (ctrl.Result, error)
// Only used for testing.
overrideTryInPlaceUpdateFunc func(ctx context.Context, controlPlane *internal.ControlPlane, machineToInPlaceUpdate *clusterv1.Machine, machineUpToDateResult internal.UpToDateResult) (bool, ctrl.Result, error)
overrideScaleUpControlPlaneFunc func(ctx context.Context, controlPlane *internal.ControlPlane) (ctrl.Result, error)
overrideScaleDownControlPlaneFunc func(ctx context.Context, controlPlane *internal.ControlPlane, machineToDelete *clusterv1.Machine) (ctrl.Result, error)
overridePreflightChecksFunc func(ctx context.Context, controlPlane *internal.ControlPlane, excludeFor ...*clusterv1.Machine) ctrl.Result
overrideCanUpdateMachineFunc func(ctx context.Context, machine *clusterv1.Machine, machineUpToDateResult internal.UpToDateResult) (bool, error)
overrideCanExtensionsUpdateMachine func(ctx context.Context, machine *clusterv1.Machine, machineUpToDateResult internal.UpToDateResult, extensionHandlers []string) (bool, []string, error)
}

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

predicateLog := ctrl.LoggerFrom(ctx).WithValues("controller", "kubeadmcontrolplane")
c, err := ctrl.NewControllerManagedBy(mgr).
Expand Down Expand Up @@ -814,7 +822,8 @@ func (r *KubeadmControlPlaneReconciler) syncMachines(ctx context.Context, contro
if err != nil {
return errors.Wrapf(err, "failed to update Machine: %s", klog.KObj(m))
}
// Note: Ensure ControlPlane has the latest version of the Machine.
// Note: Ensure ControlPlane has the latest version of the Machine. This is required because
// e.g. the in-place update code that is called later has to use the latest version of the Machine.
controlPlane.Machines[machineName] = updatedMachine
if _, ok := controlPlane.MachinesNotUpToDate[machineName]; ok {
controlPlane.MachinesNotUpToDate[machineName] = updatedMachine
Expand Down
24 changes: 23 additions & 1 deletion controlplane/kubeadm/internal/controllers/inplace.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package controllers
import (
"context"

"github.com/pkg/errors"
ctrl "sigs.k8s.io/controller-runtime"

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

// Always fallback to scale down until in-place is implemented.
// Run preflight checks to ensure that the control plane is stable before proceeding with in-place update operation.
if resultForAllMachines := r.preflightChecks(ctx, controlPlane); !resultForAllMachines.IsZero() {
// If the control plane is not stable, check if the issues are only for machineToInPlaceUpdate.
if result := r.preflightChecks(ctx, controlPlane, machineToInPlaceUpdate); result.IsZero() {
// The issues are only for machineToInPlaceUpdate, fallback to scale down.
// Note: The consequence of this is that a Machine with issues is scaled down and not in-place updated.
return true, ctrl.Result{}, nil
}

return false, resultForAllMachines, nil
}

canUpdate, err := r.canUpdateMachine(ctx, machineToInPlaceUpdate, machineUpToDateResult)
if err != nil {
return false, ctrl.Result{}, errors.Wrapf(err, "failed to determine if Machine %s can be updated in-place", machineToInPlaceUpdate.Name)
}

if !canUpdate {
return true, ctrl.Result{}, nil
}

// Always fallback to scale down until triggering in-place updates is implemented.
return true, ctrl.Result{}, nil
}
Loading