Skip to content

Commit a7fecba

Browse files
authored
Merge pull request #799 from dgunzy/support-flux-reconcile-image-policy
Introduce `.spec.suspend` and `.status.lastHandledReconcileAt` for ImagePolicy
2 parents 1f35dcf + 627074a commit a7fecba

File tree

8 files changed

+334
-24
lines changed

8 files changed

+334
-24
lines changed

api/v1beta2/imagepolicy_types.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ type ImagePolicySpec struct {
6969
// +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$"
7070
// +optional
7171
Interval *metav1.Duration `json:"interval,omitempty"`
72+
73+
// This flag tells the controller to suspend subsequent policy reconciliations.
74+
// It does not apply to already started reconciliations. Defaults to false.
75+
// +optional
76+
Suspend bool `json:"suspend,omitempty"`
7277
}
7378

7479
// ReflectionPolicy describes a policy for if/when to reflect a value from the registry in a certain resource field.
@@ -178,6 +183,8 @@ type ImagePolicyStatus struct {
178183
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
179184
// +optional
180185
Conditions []metav1.Condition `json:"conditions,omitempty"`
186+
187+
meta.ReconcileRequestStatus `json:",inline"`
181188
}
182189

183190
// GetConditions returns the status conditions of the object.
@@ -219,8 +226,13 @@ func (in *ImagePolicy) GetDigestReflectionPolicy() ReflectionPolicy {
219226

220227
func (in *ImagePolicy) GetInterval() time.Duration {
221228
if in.GetDigestReflectionPolicy() == ReflectAlways {
229+
if in.Spec.Interval == nil || in.Spec.Interval.Duration == 0 {
230+
return 10 * time.Minute
231+
}
232+
222233
return in.Spec.Interval.Duration
223234
}
235+
224236
return 0
225237
}
226238

api/v1beta2/zz_generated.deepcopy.go

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

config/crd/bases/image.toolkit.fluxcd.io_imagepolicies.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,11 @@ spec:
169169
- range
170170
type: object
171171
type: object
172+
suspend:
173+
description: |-
174+
This flag tells the controller to suspend subsequent policy reconciliations.
175+
It does not apply to already started reconciliations. Defaults to false.
176+
type: boolean
172177
required:
173178
- imageRepositoryRef
174179
- policy
@@ -243,6 +248,12 @@ spec:
243248
- type
244249
type: object
245250
type: array
251+
lastHandledReconcileAt:
252+
description: |-
253+
LastHandledReconcileAt holds the value of the most recent
254+
reconcile request value, so a change of the annotation value
255+
can be detected.
256+
type: string
246257
latestRef:
247258
description: |-
248259
LatestRef gives the first in the list of images scanned by

docs/api/v1beta2/image-reflector.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,19 @@ reflection policy is set to &ldquo;Always&rdquo;.</p>
167167
<p>Defaults to 10m.</p>
168168
</td>
169169
</tr>
170+
<tr>
171+
<td>
172+
<code>suspend</code><br>
173+
<em>
174+
bool
175+
</em>
176+
</td>
177+
<td>
178+
<em>(Optional)</em>
179+
<p>This flag tells the controller to suspend subsequent policy reconciliations.
180+
It does not apply to already started reconciliations. Defaults to false.</p>
181+
</td>
182+
</tr>
170183
</table>
171184
</td>
172185
</tr>
@@ -349,6 +362,19 @@ reflection policy is set to &ldquo;Always&rdquo;.</p>
349362
<p>Defaults to 10m.</p>
350363
</td>
351364
</tr>
365+
<tr>
366+
<td>
367+
<code>suspend</code><br>
368+
<em>
369+
bool
370+
</em>
371+
</td>
372+
<td>
373+
<em>(Optional)</em>
374+
<p>This flag tells the controller to suspend subsequent policy reconciliations.
375+
It does not apply to already started reconciliations. Defaults to false.</p>
376+
</td>
377+
</tr>
352378
</tbody>
353379
</table>
354380
</div>
@@ -424,6 +450,21 @@ int64
424450
<em>(Optional)</em>
425451
</td>
426452
</tr>
453+
<tr>
454+
<td>
455+
<code>ReconcileRequestStatus</code><br>
456+
<em>
457+
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#ReconcileRequestStatus">
458+
github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus
459+
</a>
460+
</em>
461+
</td>
462+
<td>
463+
<p>
464+
(Members of <code>ReconcileRequestStatus</code> are embedded into this type.)
465+
</p>
466+
</td>
467+
</tr>
427468
</tbody>
428469
</table>
429470
</div>

internal/controller/imagepolicy_controller.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ func (imageRepositoryPredicate) Update(e event.UpdateEvent) bool {
179179

180180
func (r *ImagePolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, retErr error) {
181181
start := time.Now()
182+
log := ctrl.LoggerFrom(ctx)
182183

183184
// Fetch the ImagePolicy.
184185
obj := &imagev1.ImagePolicy{}
@@ -191,6 +192,13 @@ func (r *ImagePolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request)
191192

192193
// Always attempt to patch the object after each reconciliation.
193194
defer func() {
195+
// If the reconcile request annotation was set, consider it
196+
// handled (NB it doesn't matter here if it was changed since last
197+
// time)
198+
if token, ok := meta.ReconcileAnnotationValue(obj.GetAnnotations()); ok {
199+
obj.Status.SetLastHandledReconcileRequest(token)
200+
}
201+
194202
// Create patch options for patching the object.
195203
patchOpts := pkgreconcile.AddPatchOptions(obj, r.patchOptions, imagePolicyOwnedConditions, r.ControllerName)
196204
if err := serialPatcher.Patch(ctx, obj, patchOpts...); err != nil {
@@ -219,6 +227,12 @@ func (r *ImagePolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request)
219227
return ctrl.Result{Requeue: true}, nil
220228
}
221229

230+
// Return if the object is suspended.
231+
if obj.Spec.Suspend {
232+
log.Info("reconciliation is suspended for this object")
233+
return ctrl.Result{}, nil
234+
}
235+
222236
// Call subreconciler.
223237
result, retErr = r.reconcile(ctx, serialPatcher, obj)
224238
return
@@ -245,9 +259,12 @@ func composeImagePolicyReadyMessage(obj *imagev1.ImagePolicy) string {
245259
func (r *ImagePolicyReconciler) reconcile(ctx context.Context, sp *patch.SerialPatcher, obj *imagev1.ImagePolicy) (result ctrl.Result, retErr error) {
246260
oldObj := obj.DeepCopy()
247261

262+
// Set a default next reconcile time before processing the object.
263+
nextReconcileTime := obj.GetInterval()
264+
248265
// If there's no error and no requeue is requested, it's a success.
249266
isSuccess := func(res ctrl.Result, err error) bool {
250-
if err != nil || res.Requeue {
267+
if err != nil || res.RequeueAfter != nextReconcileTime {
251268
return false
252269
}
253270
return true
@@ -365,7 +382,8 @@ func (r *ImagePolicyReconciler) reconcile(ctx context.Context, sp *patch.SerialP
365382
// Let result finalizer compute the Ready condition.
366383
conditions.Delete(obj, meta.ReadyCondition)
367384

368-
result, retErr = ctrl.Result{RequeueAfter: obj.GetInterval()}, nil
385+
// Set the next reconcile time in the result based on the interval.
386+
result, retErr = ctrl.Result{RequeueAfter: nextReconcileTime}, nil
369387
return
370388
}
371389

0 commit comments

Comments
 (0)