Skip to content

Commit 438bd7d

Browse files
authored
add component suspension (#418)
* add component suspension * add suspension option to docs
1 parent 763b5d5 commit 438bd7d

5 files changed

Lines changed: 72 additions & 2 deletions

File tree

pkg/component/component.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,17 @@ func assertImpersonationConfiguration[T Component](component T) (ImpersonationCo
7777
return nil, false
7878
}
7979

80+
// Check if given component or its spec implements SuspensionConfiguration (and return it).
81+
func assertSuspensionConfiguration[T Component](component T) (SuspensionConfiguration, bool) {
82+
if suspensionConfiguration, ok := Component(component).(SuspensionConfiguration); ok {
83+
return suspensionConfiguration, true
84+
}
85+
if suspensionConfiguration, ok := getSpec(component).(SuspensionConfiguration); ok {
86+
return suspensionConfiguration, true
87+
}
88+
return nil, false
89+
}
90+
8091
// Check if given component or its spec implements RequeueConfiguration (and return it).
8192
func assertRequeueConfiguration[T Component](component T) (RequeueConfiguration, bool) {
8293
if requeueConfiguration, ok := Component(component).(RequeueConfiguration); ok {
@@ -176,6 +187,11 @@ func (s *ImpersonationSpec) GetImpersonationGroups() []string {
176187
return nil
177188
}
178189

190+
// Implement the SuspensionConfiguration interface.
191+
func (s *SuspensionSpec) IsSuspended() bool {
192+
return s.Suspend
193+
}
194+
179195
// Implement the RequeueConfiguration interface.
180196
func (s *RequeueSpec) GetRequeueInterval() time.Duration {
181197
if s.RequeueInterval != nil {

pkg/component/reconciler.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ const (
7676
ReadyConditionReasonReady = "Ready"
7777
ReadyConditionReasonError = "Error"
7878
ReadyConditionReasonTimeout = "Timeout"
79+
ReadyConditionReasonSuspended = "Suspended"
7980
ReadyConditionReasonDeletionRetrying = "DeletionRetrying"
8081
ReadyConditionReasonDeletionBlocked = "DeletionBlocked"
8182
ReadyConditionReasonDeletionProcessing = "DeletionProcessing"
@@ -456,6 +457,13 @@ func (r *Reconciler[T]) Reconcile(ctx context.Context, req ctrl.Request) (result
456457
return ctrl.Result{RequeueAfter: time.Millisecond}, nil
457458
}
458459

460+
if component.GetDeletionTimestamp().IsZero() {
461+
if suspensionConfiguration, ok := assertSuspensionConfiguration(component); ok && suspensionConfiguration.IsSuspended() {
462+
status.SetState(StatePending, ReadyConditionReasonSuspended, "Reconciliation is suspended")
463+
return ctrl.Result{RequeueAfter: r.backoff.Next(req, ReadyConditionReasonSuspended)}, nil
464+
}
465+
}
466+
459467
// resolve references
460468
componentDigest, err = resolveReferences(ctx, r.client, r.hookClient, component)
461469
if err != nil {

pkg/component/types.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ type ImpersonationConfiguration interface {
6363
GetImpersonationGroups() []string
6464
}
6565

66+
// The SuspensionConfiguration interface is meant to be implemented by components (or their spec) which offer
67+
// the ability to suspend reconciliation.
68+
type SuspensionConfiguration interface {
69+
// Whether the reconciliation (apply) or the implementing component is supended. If true the component goes
70+
// into Pending state with reason Suspended. Note that deletion is not affected by this suspension.
71+
IsSuspended() bool
72+
}
73+
6674
// The RequeueConfiguration interface is meant to be implemented by components (or their spec) which offer
6775
// tweaking the requeue interval (by default, it would be 10 minutes).
6876
type RequeueConfiguration interface {
@@ -170,6 +178,16 @@ var _ ImpersonationConfiguration = &ImpersonationSpec{}
170178

171179
// +kubebuilder:object:generate=true
172180

181+
// SuspensionSpec defines whether the reconciliation (apply) or the implementing component is suspended.
182+
// Components providing SuspensionConfiguration may include this into their spec.
183+
type SuspensionSpec struct {
184+
Suspend bool `json:"suspend,omitempty"`
185+
}
186+
187+
var _ SuspensionConfiguration = &SuspensionSpec{}
188+
189+
// +kubebuilder:object:generate=true
190+
173191
// RequeueSpec defines the requeue interval, that is, the interval after which components will be re-reconciled after a successful reconciliation.
174192
// Components providing RequeueConfiguration may include this into their spec.
175193
type RequeueSpec struct {

pkg/component/zz_generated.deepcopy.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

website/content/en/docs/concepts/types.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,21 @@ type ImpersonationConfiguration interface {
122122

123123
to use different user/groups for the deployment of dependent objects.
124124

125-
Note that, as mentioned above, the interfaces `PlacementConfiguration`, `ClientConfiguration` and `ImpersonationConfiguration` can be implemented by the component
126-
itself as well as by its spec type. In the theoretical case that both is the case, the implementation on the component level takes higher precedence.
125+
Sometimes it is desired to suspend the reconciliation of a component. In offer this, the compoent (or its spec) can implement the interface
126+
127+
```go
128+
package component
129+
130+
// The SuspensionConfiguration interface is meant to be implemented by components (or their spec) which offer
131+
// the ability to suspend reconciliation.
132+
type SuspensionConfiguration interface {
133+
// Whether the reconciliation (apply) or the implementing component is supended. If true the component goes
134+
// into Pending state with reason Suspended. Note that deletion is not affected by this suspension.
135+
IsSuspended() bool
136+
}
137+
```
138+
139+
Note that, as mentioned above, the interfaces `PlacementConfiguration`, `ClientConfiguration`, `ImpersonationConfiguration` and `SuspensionConfiguration` can be implemented by the component itself as well as by its spec type. In the theoretical case that both implement it, the component takes higher precedence.
127140

128141
## The Generator interface
129142

0 commit comments

Comments
 (0)