Skip to content

Commit 8d7f010

Browse files
authored
Merge pull request kubernetes-sigs#6629 from ykakarap/runtime-sdk_lifecycle-hooks_tracking-hooks
✨ Implements AfterControlPlaneInitialized, AfterControlPlaneUpgrade and AfterClusterUpgrade hooks
2 parents 447bc5b + 671f240 commit 8d7f010

File tree

10 files changed

+1749
-261
lines changed

10 files changed

+1749
-261
lines changed

exp/runtime/api/v1alpha1/extensionconfig_types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,4 +206,9 @@ const (
206206
// object wants injection of CAs. It takes the form of a reference to a Secret
207207
// as namespace/name.
208208
InjectCAFromSecretAnnotation string = "runtime.cluster.x-k8s.io/inject-ca-from-secret"
209+
210+
// PendingHooksAnnotation is the annotation used to keep a track of pending runtime hooks.
211+
// The annotation will be used to track the intent to call a hook as soon as an operation completes;
212+
// the intent will be removed as soon as the hook call completes successfully.
213+
PendingHooksAnnotation string = "runtime.cluster.x-k8s.io/pending-hooks"
209214
)

exp/runtime/hooks/api/v1alpha1/lifecyclehooks_types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ func init() {
188188
catalogBuilder.RegisterHook(AfterControlPlaneInitialized, &runtimecatalog.HookMeta{
189189
Tags: []string{"Lifecycle Hooks"},
190190
Summary: "Called after the Control Plane is available for the first time",
191-
Description: "This non-blocking hook is called after the ControlPlane for the Cluster is marked as available for the first time",
191+
Description: "This non-blocking hook is called after the ControlPlane for the Cluster reachable for the first time",
192192
})
193193

194194
catalogBuilder.RegisterHook(BeforeClusterUpgrade, &runtimecatalog.HookMeta{

internal/controllers/topology/cluster/desired_state.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"sigs.k8s.io/cluster-api/feature"
3636
"sigs.k8s.io/cluster-api/internal/contract"
3737
"sigs.k8s.io/cluster-api/internal/controllers/topology/cluster/scope"
38+
"sigs.k8s.io/cluster-api/internal/hooks"
3839
tlog "sigs.k8s.io/cluster-api/internal/log"
3940
runtimecatalog "sigs.k8s.io/cluster-api/internal/runtime/catalog"
4041
)
@@ -313,6 +314,37 @@ func (r *Reconciler) computeControlPlaneVersion(ctx context.Context, s *scope.Sc
313314
// Nb. We do not return early in the function if the control plane is already at the desired version so as
314315
// to know if the control plane is being upgraded. This information
315316
// is required when updating the TopologyReconciled condition on the cluster.
317+
318+
// Call the AfterControlPlaneUpgrade now that the control plane is upgraded.
319+
if feature.Gates.Enabled(feature.RuntimeSDK) {
320+
// Call the hook only if we are tracking the intent to do so. If it is not tracked it means we don't need to call the
321+
// hook because we didn't go through an upgrade or we already called the hook after the upgrade.
322+
if hooks.IsPending(runtimehooksv1.AfterControlPlaneUpgrade, s.Current.Cluster) {
323+
// Call all the registered extension for the hook.
324+
hookRequest := &runtimehooksv1.AfterControlPlaneUpgradeRequest{
325+
Cluster: *s.Current.Cluster,
326+
KubernetesVersion: desiredVersion,
327+
}
328+
hookResponse := &runtimehooksv1.AfterControlPlaneUpgradeResponse{}
329+
if err := r.RuntimeClient.CallAllExtensions(ctx, runtimehooksv1.AfterControlPlaneUpgrade, s.Current.Cluster, hookRequest, hookResponse); err != nil {
330+
return "", errors.Wrapf(err, "error calling the %s hook", runtimecatalog.HookName(runtimehooksv1.AfterControlPlaneUpgrade))
331+
}
332+
// Add the response to the tracker so we can later update condition or requeue when required.
333+
s.HookResponseTracker.Add(runtimehooksv1.AfterControlPlaneUpgrade, hookResponse)
334+
335+
// If the extension responds to hold off on starting Machine deployments upgrades,
336+
// change the UpgradeTracker accordingly, otherwise the hook call is completed and we
337+
// can remove this hook from the list of pending-hooks.
338+
if hookResponse.RetryAfterSeconds != 0 {
339+
s.UpgradeTracker.MachineDeployments.HoldUpgrades(true)
340+
} else {
341+
if err := hooks.MarkAsDone(ctx, r.Client, s.Current.Cluster, runtimehooksv1.AfterControlPlaneUpgrade); err != nil {
342+
return "", errors.Wrapf(err, "failed to remove the %s hook from pending hooks tracker", runtimecatalog.HookName(runtimehooksv1.AfterControlPlaneUpgrade))
343+
}
344+
}
345+
}
346+
}
347+
316348
return *currentVersion, nil
317349
}
318350

@@ -349,14 +381,21 @@ func (r *Reconciler) computeControlPlaneVersion(ctx context.Context, s *scope.Sc
349381
if err := r.RuntimeClient.CallAllExtensions(ctx, runtimehooksv1.BeforeClusterUpgrade, s.Current.Cluster, hookRequest, hookResponse); err != nil {
350382
return "", errors.Wrapf(err, "failed to call %s hook", runtimecatalog.HookName(runtimehooksv1.BeforeClusterUpgrade))
351383
}
384+
// Add the response to the tracker so we can later update condition or requeue when required.
352385
s.HookResponseTracker.Add(runtimehooksv1.BeforeClusterUpgrade, hookResponse)
353386
if hookResponse.RetryAfterSeconds != 0 {
354387
// Cannot pickup the new version right now. Need to try again later.
355388
return *currentVersion, nil
356389
}
390+
391+
// We are picking up the new version here.
392+
// Track the intent of calling the AfterControlPlaneUpgrade and the AfterClusterUpgrade hooks once we are done with the upgrade.
393+
if err := hooks.MarkAsPending(ctx, r.Client, s.Current.Cluster, runtimehooksv1.AfterControlPlaneUpgrade, runtimehooksv1.AfterClusterUpgrade); err != nil {
394+
return "", errors.Wrapf(err, "failed to mark the %s hook as pending", []string{runtimecatalog.HookName(runtimehooksv1.AfterControlPlaneUpgrade), runtimecatalog.HookName(runtimehooksv1.AfterClusterUpgrade)})
395+
}
357396
}
358397

359-
// Control plane and machine deployments are stable.
398+
// Control plane and machine deployments are stable. All the required hook are called.
360399
// Ready to pick up the topology version.
361400
return desiredVersion, nil
362401
}

0 commit comments

Comments
 (0)