Skip to content

Commit 671f240

Browse files
author
Yuvaraj Kakaraparthi
committed
address review comments
1 parent 337937e commit 671f240

File tree

7 files changed

+62
-52
lines changed

7 files changed

+62
-52
lines changed

exp/runtime/api/v1alpha1/extensionconfig_types.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,5 +209,7 @@ const (
209209
InjectCAFromSecretAnnotation string = "runtime.cluster.x-k8s.io/inject-ca-from-secret"
210210

211211
// PendingHooksAnnotation is the annotation used to keep a track of pending runtime hooks.
212-
PendingHooksAnnotation string = "hooks.x-cluster.k8s.io/pending-hooks"
212+
// The annotation will be used to track the intent to call a hook as soon as an operation completes;
213+
// the intent will be removed as soon as the hook call completes successfully.
214+
PendingHooksAnnotation string = "runtime.cluster.x-k8s.io/pending-hooks"
213215
)

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: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -317,9 +317,10 @@ func (r *Reconciler) computeControlPlaneVersion(ctx context.Context, s *scope.Sc
317317

318318
// Call the AfterControlPlaneUpgrade now that the control plane is upgraded.
319319
if feature.Gates.Enabled(feature.RuntimeSDK) {
320-
// Call the hook only if it is marked. If it is not marked it means we don't need ot call the
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
321321
// hook because we didn't go through an upgrade or we already called the hook after the upgrade.
322322
if hooks.IsPending(runtimehooksv1.AfterControlPlaneUpgrade, s.Current.Cluster) {
323+
// Call all the registered extension for the hook.
323324
hookRequest := &runtimehooksv1.AfterControlPlaneUpgradeRequest{
324325
Cluster: *s.Current.Cluster,
325326
KubernetesVersion: desiredVersion,
@@ -328,14 +329,17 @@ func (r *Reconciler) computeControlPlaneVersion(ctx context.Context, s *scope.Sc
328329
if err := r.RuntimeClient.CallAllExtensions(ctx, runtimehooksv1.AfterControlPlaneUpgrade, s.Current.Cluster, hookRequest, hookResponse); err != nil {
329330
return "", errors.Wrapf(err, "error calling the %s hook", runtimecatalog.HookName(runtimehooksv1.AfterControlPlaneUpgrade))
330331
}
332+
// Add the response to the tracker so we can later update condition or requeue when required.
331333
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.
332338
if hookResponse.RetryAfterSeconds != 0 {
333-
// We have to block the upgrade of the Machine deployments.
334339
s.UpgradeTracker.MachineDeployments.HoldUpgrades(true)
335340
} else {
336-
// We are done with the hook for now. We don't need to call it anymore. Unmark it.
337341
if err := hooks.MarkAsDone(ctx, r.Client, s.Current.Cluster, runtimehooksv1.AfterControlPlaneUpgrade); err != nil {
338-
return "", errors.Wrapf(err, "failed to unmark the %s hook", runtimecatalog.HookName(runtimehooksv1.AfterControlPlaneUpgrade))
342+
return "", errors.Wrapf(err, "failed to remove the %s hook from pending hooks tracker", runtimecatalog.HookName(runtimehooksv1.AfterControlPlaneUpgrade))
339343
}
340344
}
341345
}
@@ -377,16 +381,17 @@ func (r *Reconciler) computeControlPlaneVersion(ctx context.Context, s *scope.Sc
377381
if err := r.RuntimeClient.CallAllExtensions(ctx, runtimehooksv1.BeforeClusterUpgrade, s.Current.Cluster, hookRequest, hookResponse); err != nil {
378382
return "", errors.Wrapf(err, "failed to call %s hook", runtimecatalog.HookName(runtimehooksv1.BeforeClusterUpgrade))
379383
}
384+
// Add the response to the tracker so we can later update condition or requeue when required.
380385
s.HookResponseTracker.Add(runtimehooksv1.BeforeClusterUpgrade, hookResponse)
381386
if hookResponse.RetryAfterSeconds != 0 {
382387
// Cannot pickup the new version right now. Need to try again later.
383388
return *currentVersion, nil
384389
}
385390

386391
// We are picking up the new version here.
387-
// Mark the AfterControlPlaneUpgrade and the AfterClusterUpgrade hooks so that we call them once we are done with the upgrade.
392+
// Track the intent of calling the AfterControlPlaneUpgrade and the AfterClusterUpgrade hooks once we are done with the upgrade.
388393
if err := hooks.MarkAsPending(ctx, r.Client, s.Current.Cluster, runtimehooksv1.AfterControlPlaneUpgrade, runtimehooksv1.AfterClusterUpgrade); err != nil {
389-
return "", errors.Wrapf(err, "failed to mark the %s hook", []string{runtimecatalog.HookName(runtimehooksv1.AfterControlPlaneUpgrade), runtimecatalog.HookName(runtimehooksv1.AfterClusterUpgrade)})
394+
return "", errors.Wrapf(err, "failed to mark the %s hook as pending", []string{runtimecatalog.HookName(runtimehooksv1.AfterControlPlaneUpgrade), runtimecatalog.HookName(runtimehooksv1.AfterClusterUpgrade)})
390395
}
391396
}
392397

internal/controllers/topology/cluster/desired_state_test.go

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,7 @@ func TestComputeControlPlaneVersion(t *testing.T) {
908908
name string
909909
s *scope.Scope
910910
hookResponse *runtimehooksv1.AfterControlPlaneUpgradeResponse
911-
wantMarked bool
911+
wantIntentToCall bool
912912
wantHookToBeCalled bool
913913
wantAllowMDUpgrades bool
914914
wantErr bool
@@ -937,12 +937,12 @@ func TestComputeControlPlaneVersion(t *testing.T) {
937937
UpgradeTracker: scope.NewUpgradeTracker(),
938938
HookResponseTracker: scope.NewHookResponseTracker(),
939939
},
940-
wantMarked: false,
940+
wantIntentToCall: false,
941941
wantHookToBeCalled: false,
942942
wantErr: false,
943943
},
944944
{
945-
name: "should not call hook if the control plane is provisioning - hook is marked",
945+
name: "should not call hook if the control plane is provisioning - there is intent to call hook",
946946
s: &scope.Scope{
947947
Blueprint: &scope.ClusterBlueprint{
948948
Topology: &clusterv1.Topology{
@@ -968,12 +968,12 @@ func TestComputeControlPlaneVersion(t *testing.T) {
968968
UpgradeTracker: scope.NewUpgradeTracker(),
969969
HookResponseTracker: scope.NewHookResponseTracker(),
970970
},
971-
wantMarked: true,
971+
wantIntentToCall: true,
972972
wantHookToBeCalled: false,
973973
wantErr: false,
974974
},
975975
{
976-
name: "should not call hook if the control plane is upgrading - hook is marked",
976+
name: "should not call hook if the control plane is upgrading - there is intent to call hook",
977977
s: &scope.Scope{
978978
Blueprint: &scope.ClusterBlueprint{
979979
Topology: &clusterv1.Topology{
@@ -999,12 +999,12 @@ func TestComputeControlPlaneVersion(t *testing.T) {
999999
UpgradeTracker: scope.NewUpgradeTracker(),
10001000
HookResponseTracker: scope.NewHookResponseTracker(),
10011001
},
1002-
wantMarked: true,
1002+
wantIntentToCall: true,
10031003
wantHookToBeCalled: false,
10041004
wantErr: false,
10051005
},
10061006
{
1007-
name: "should call hook if the control plane is at desired version - non blocking response should unmark hook and allow MD upgrades",
1007+
name: "should call hook if the control plane is at desired version - non blocking response should remove hook from pending hooks list and allow MD upgrades",
10081008
s: &scope.Scope{
10091009
Blueprint: &scope.ClusterBlueprint{
10101010
Topology: &clusterv1.Topology{
@@ -1031,13 +1031,13 @@ func TestComputeControlPlaneVersion(t *testing.T) {
10311031
HookResponseTracker: scope.NewHookResponseTracker(),
10321032
},
10331033
hookResponse: nonBlockingResponse,
1034-
wantMarked: false,
1034+
wantIntentToCall: false,
10351035
wantHookToBeCalled: true,
10361036
wantAllowMDUpgrades: true,
10371037
wantErr: false,
10381038
},
10391039
{
1040-
name: "should call hook if the control plane is at desired version - blocking response should leave the hook as marked and block MD upgrades",
1040+
name: "should call hook if the control plane is at desired version - blocking response should leave the hook in pending hooks list and block MD upgrades",
10411041
s: &scope.Scope{
10421042
Blueprint: &scope.ClusterBlueprint{
10431043
Topology: &clusterv1.Topology{
@@ -1064,13 +1064,13 @@ func TestComputeControlPlaneVersion(t *testing.T) {
10641064
HookResponseTracker: scope.NewHookResponseTracker(),
10651065
},
10661066
hookResponse: blockingResponse,
1067-
wantMarked: true,
1067+
wantIntentToCall: true,
10681068
wantHookToBeCalled: true,
10691069
wantAllowMDUpgrades: false,
10701070
wantErr: false,
10711071
},
10721072
{
1073-
name: "should call hook if the control plane is at desired version - failure response should leave the hook as marked",
1073+
name: "should call hook if the control plane is at desired version - failure response should leave the hook in pending hooks list",
10741074
s: &scope.Scope{
10751075
Blueprint: &scope.ClusterBlueprint{
10761076
Topology: &clusterv1.Topology{
@@ -1097,7 +1097,7 @@ func TestComputeControlPlaneVersion(t *testing.T) {
10971097
HookResponseTracker: scope.NewHookResponseTracker(),
10981098
},
10991099
hookResponse: failureResponse,
1100-
wantMarked: true,
1100+
wantIntentToCall: true,
11011101
wantHookToBeCalled: true,
11021102
wantErr: true,
11031103
},
@@ -1124,7 +1124,7 @@ func TestComputeControlPlaneVersion(t *testing.T) {
11241124

11251125
_, err := r.computeControlPlaneVersion(ctx, tt.s)
11261126
g.Expect(fakeRuntimeClient.CallAllCount(runtimehooksv1.AfterControlPlaneUpgrade) == 1).To(Equal(tt.wantHookToBeCalled))
1127-
g.Expect(hooks.IsPending(runtimehooksv1.AfterControlPlaneUpgrade, tt.s.Current.Cluster)).To(Equal(tt.wantMarked))
1127+
g.Expect(hooks.IsPending(runtimehooksv1.AfterControlPlaneUpgrade, tt.s.Current.Cluster)).To(Equal(tt.wantIntentToCall))
11281128
g.Expect(err != nil).To(Equal(tt.wantErr))
11291129
if tt.wantHookToBeCalled && !tt.wantErr {
11301130
g.Expect(tt.s.UpgradeTracker.MachineDeployments.AllowUpgrade()).To(Equal(tt.wantAllowMDUpgrades))
@@ -1133,7 +1133,7 @@ func TestComputeControlPlaneVersion(t *testing.T) {
11331133
}
11341134
})
11351135

1136-
t.Run("marking AfterClusterUpgrade and AfterControlPlaneUpgrade hooks", func(t *testing.T) {
1136+
t.Run("register intent to call AfterClusterUpgrade and AfterControlPlaneUpgrade hooks", func(t *testing.T) {
11371137
defer utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.RuntimeSDK, true)()
11381138

11391139
catalog := runtimecatalog.New()
@@ -1201,7 +1201,7 @@ func TestComputeControlPlaneVersion(t *testing.T) {
12011201
desiredVersion, err := r.computeControlPlaneVersion(ctx, s)
12021202
g := NewWithT(t)
12031203
g.Expect(err).To(BeNil())
1204-
// When successfully picking up the new version the AfterControlPlaneUpgrade and AfterClusterUpgrade hooks should be marked
1204+
// When successfully picking up the new version the intent to call AfterControlPlaneUpgrade and AfterClusterUpgrade hooks should be registered.
12051205
g.Expect(desiredVersion).To(Equal("v1.2.3"))
12061206
g.Expect(hooks.IsPending(runtimehooksv1.AfterControlPlaneUpgrade, s.Current.Cluster)).To(BeTrue())
12071207
g.Expect(hooks.IsPending(runtimehooksv1.AfterClusterUpgrade, s.Current.Cluster)).To(BeTrue())

internal/controllers/topology/cluster/reconcile_state.go

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -202,18 +202,18 @@ func (r *Reconciler) callAfterHooks(ctx context.Context, s *scope.Scope) error {
202202
}
203203

204204
func (r *Reconciler) callAfterControlPlaneInitialized(ctx context.Context, s *scope.Scope) error {
205-
/*
206-
TODO: Working comment - DELETE AFTER:
207-
- If the cluster topology is being created then mark the AfterControlPlaneInitialized hook so that we can call it later.
208-
*/
205+
// If the cluster topology is being created then track to intent to call the AfterControlPlaneInitialized hook so that we can call it later.
209206
if s.Current.Cluster.Spec.InfrastructureRef == nil && s.Current.Cluster.Spec.ControlPlaneRef == nil {
210207
if err := hooks.MarkAsPending(ctx, r.Client, s.Current.Cluster, runtimehooksv1.AfterControlPlaneInitialized); err != nil {
211-
return errors.Wrapf(err, "failed to mark %s hook", runtimecatalog.HookName(runtimehooksv1.AfterControlPlaneInitialized))
208+
return errors.Wrapf(err, "failed to remove the %s hook from pending hooks tracker", runtimecatalog.HookName(runtimehooksv1.AfterControlPlaneInitialized))
212209
}
213210
}
214211

212+
// 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
213+
// hook because already called the hook after the control plane is initialized.
215214
if hooks.IsPending(runtimehooksv1.AfterControlPlaneInitialized, s.Current.Cluster) {
216215
if isControlPlaneInitialized(s.Current.Cluster) {
216+
// The control plane is initialized for the first time. Call all the registered extensions for the hook.
217217
hookRequest := &runtimehooksv1.AfterControlPlaneInitializedRequest{
218218
Cluster: *s.Current.Cluster,
219219
}
@@ -233,8 +233,6 @@ func (r *Reconciler) callAfterControlPlaneInitialized(ctx context.Context, s *sc
233233

234234
func isControlPlaneInitialized(cluster *clusterv1.Cluster) bool {
235235
for _, condition := range cluster.GetConditions() {
236-
// TODO: Should we check for the ControlPlaneInitialized condition or the ControlPlaneReadyCondition?
237-
// From the description of the hook it looks like it should be the ControlPlaneReadyCondition - but need to double check.
238236
if condition.Type == clusterv1.ControlPlaneInitializedCondition {
239237
if condition.Status == corev1.ConditionTrue {
240238
return true
@@ -245,23 +243,26 @@ func isControlPlaneInitialized(cluster *clusterv1.Cluster) bool {
245243
}
246244

247245
func (r *Reconciler) callAfterClusterUpgrade(ctx context.Context, s *scope.Scope) error {
248-
/*
249-
TODO: Working comment - DELETE LATER:
250-
- if the AfterClusterUpgrade hook is pending then check that the cluster is fully upgraded. If it is fully upgraded then call the hook.
251-
- A cluster is full upgraded if
252-
- Control plane is not upgrading
253-
- Control plane is not scaling
254-
- Control plane is not pending an upgrade
255-
- MachineDeployments are not currently rolling out
256-
- MAchineDeployments are not about to roll out
257-
- MachineDeployments are not pending an upgrade
258-
*/
246+
// 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
247+
// hook because we didn't go through an upgrade or we already called the hook after the upgrade.
259248
if hooks.IsPending(runtimehooksv1.AfterClusterUpgrade, s.Current.Cluster) {
249+
// Call the registered extensions for the hook after the cluster is fully upgraded.
250+
// A clusters is considered fully upgraded if:
251+
// - Control plane is not upgrading
252+
// - Control plane is not scaling
253+
// - Control plane is not pending an upgrade
254+
// - MachineDeployments are not currently rolling out
255+
// - MAchineDeployments are not about to roll out
256+
// - MachineDeployments are not pending an upgrade
257+
258+
// Check if the control plane is upgrading.
260259
cpUpgrading, err := contract.ControlPlane().IsUpgrading(s.Current.ControlPlane.Object)
261260
if err != nil {
262261
return errors.Wrap(err, "failed to check if control plane is upgrading")
263262
}
264263

264+
// Check if the control plane is scaling. If the control plane does not support replicas
265+
// it will be considered as not scaling.
265266
var cpScaling bool
266267
if s.Blueprint.Topology.ControlPlane.Replicas != nil {
267268
cpScaling, err = contract.ControlPlane().IsScaling(s.Current.ControlPlane.Object)
@@ -272,7 +273,7 @@ func (r *Reconciler) callAfterClusterUpgrade(ctx context.Context, s *scope.Scope
272273

273274
if !cpUpgrading && !cpScaling && !s.UpgradeTracker.ControlPlane.PendingUpgrade && // Control Plane checks
274275
len(s.UpgradeTracker.MachineDeployments.RolloutNames()) == 0 && // Machine deployments are not rollout out or not about to roll out
275-
!s.UpgradeTracker.MachineDeployments.PendingUpgrade() { // Machine Deployments is are not pending an upgrade
276+
!s.UpgradeTracker.MachineDeployments.PendingUpgrade() { // Machine Deployments are not pending an upgrade
276277
// Everything is stable and the cluster can be considered fully upgraded.
277278
hookRequest := &runtimehooksv1.AfterClusterUpgradeRequest{
278279
Cluster: *s.Current.Cluster,
@@ -283,11 +284,9 @@ func (r *Reconciler) callAfterClusterUpgrade(ctx context.Context, s *scope.Scope
283284
return errors.Wrapf(err, "failed to call %s hook", runtimecatalog.HookName(runtimehooksv1.AfterClusterUpgrade))
284285
}
285286
s.HookResponseTracker.Add(runtimehooksv1.AfterClusterUpgrade, hookResponse)
286-
// The hook is successfully called. We can unmark the hook.
287-
// TODO: follow up check - what if the cluster object in current is not updated with the latest tracking annotation.
288-
// Is that possible?
287+
// The hook is successfully called; we can remove this hook from the list of pending-hooks.
289288
if err := hooks.MarkAsDone(ctx, r.Client, s.Current.Cluster, runtimehooksv1.AfterClusterUpgrade); err != nil {
290-
return errors.Wrapf(err, "failed to unmark the %s hook", runtimecatalog.HookName(runtimehooksv1.AfterClusterUpgrade))
289+
return errors.Wrapf(err, "failed to remove the %s hook from pending hooks tracker", runtimecatalog.HookName(runtimehooksv1.AfterClusterUpgrade))
291290
}
292291
}
293292
}

internal/controllers/topology/cluster/scope/upgradetracker.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ func (m *MachineDeploymentUpgradeTracker) RolloutNames() []string {
7878
return m.rollingOutNames.List()
7979
}
8080

81-
// HoldUpgrades is used to set if any subsequent upgrade operations should be paused.
81+
// HoldUpgrades is used to set if any subsequent upgrade operations should be paused,
82+
// e.g. because a AfterControlPlaneUpgrade hook response asked to do so.
8283
// If HoldUpgrades is called with `true` then AllowUpgrade would return false.
8384
func (m *MachineDeploymentUpgradeTracker) HoldUpgrades(val bool) {
8485
m.holdUpgrades = val

internal/hooks/tracking.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ import (
3030
"sigs.k8s.io/cluster-api/util/patch"
3131
)
3232

33-
// MarkAsPending sets the information on the object to signify that the hook is marked.
34-
func MarkAsPending(ctx context.Context, c client.Client, obj client.Object, hooks ...runtimecatalog.Hook) (retErr error) {
33+
// MarkAsPending adds to the object's PendingHooksAnnotation the intent to execute a hook after an operation completes.
34+
// Usually this function is called when an operation is starting in order to track the intent to call an After<operation> hook later in the process.
35+
func MarkAsPending(ctx context.Context, c client.Client, obj client.Object, hooks ...runtimecatalog.Hook) error {
3536
patchHelper, err := patch.NewHelper(obj, c)
3637
if err != nil {
3738
return errors.Wrap(err, "failed to create patch helper")
@@ -56,7 +57,7 @@ func MarkAsPending(ctx context.Context, c client.Client, obj client.Object, hook
5657
return nil
5758
}
5859

59-
// IsPending returns true if the hook is marked on the object.
60+
// IsPending returns true if there is an intent to call a hook being tracked in the object's PendingHooksAnnotation.
6061
func IsPending(hook runtimecatalog.Hook, obj client.Object) bool {
6162
hookName := runtimecatalog.HookName(hook)
6263
annotations := obj.GetAnnotations()
@@ -66,8 +67,10 @@ func IsPending(hook runtimecatalog.Hook, obj client.Object) bool {
6667
return isInCommaSeparatedList(annotations[runtimev1.PendingHooksAnnotation], hookName)
6768
}
6869

69-
// MarkAsDone removes the information on the object that represents that the hook is pending.
70-
func MarkAsDone(ctx context.Context, c client.Client, obj client.Object, hooks ...runtimecatalog.Hook) (retErr error) {
70+
// MarkAsDone removes the intent to call a Hook from the object's PendingHooksAnnotation.
71+
// Usually this func is called after all the registered extensions for the Hook returned an answer without requests
72+
// to hold on to the object's lifecycle (retryAfterSeconds).
73+
func MarkAsDone(ctx context.Context, c client.Client, obj client.Object, hooks ...runtimecatalog.Hook) error {
7174
patchHelper, err := patch.NewHelper(obj, c)
7275
if err != nil {
7376
return errors.Wrap(err, "failed to create patch helper")

0 commit comments

Comments
 (0)