Skip to content

Commit f586a58

Browse files
committed
Add OCI revision to events
Signed-off-by: Matheus Pimenta <[email protected]>
1 parent 550576e commit f586a58

9 files changed

+241
-22
lines changed

api/v1/kustomization_types.go

+8
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,14 @@ type KustomizationStatus struct {
263263
// +optional
264264
LastAppliedRevision string `json:"lastAppliedRevision,omitempty"`
265265

266+
// The last successfully applied origin revision.
267+
// Equals the origin revision of the applied Artifact from the referenced Source.
268+
// Usually present on the Metadata of the applied Artifact and depends on the
269+
// Source type, e.g. for OCI it's the value associated with the key
270+
// "org.opencontainers.image.revision".
271+
// +optional
272+
LastAppliedOriginRevision string `json:"lastAppliedOriginRevision,omitempty"`
273+
266274
// LastAttemptedRevision is the revision of the last reconciliation attempt.
267275
// +optional
268276
LastAttemptedRevision string `json:"lastAttemptedRevision,omitempty"`

config/crd/bases/kustomize.toolkit.fluxcd.io_kustomizations.yaml

+8
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,14 @@ spec:
520520
required:
521521
- entries
522522
type: object
523+
lastAppliedOriginRevision:
524+
description: |-
525+
The last successfully applied origin revision.
526+
Equals the origin revision of the applied Artifact from the referenced Source.
527+
Usually present on the Metadata of the applied Artifact and depends on the
528+
Source type, e.g. for OCI it's the value associated with the key
529+
"org.opencontainers.image.revision".
530+
type: string
523531
lastAppliedRevision:
524532
description: |-
525533
The last successfully applied revision.

docs/api/v1/kustomize.md

+16
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,22 @@ Equals the Revision of the applied Artifact from the referenced Source.</p>
994994
</tr>
995995
<tr>
996996
<td>
997+
<code>lastAppliedOriginRevision</code><br>
998+
<em>
999+
string
1000+
</em>
1001+
</td>
1002+
<td>
1003+
<em>(Optional)</em>
1004+
<p>The last successfully applied origin revision.
1005+
Equals the origin revision of the applied Artifact from the referenced Source.
1006+
Usually present on the Metadata of the applied Artifact and depends on the
1007+
Source type, e.g. for OCI it&rsquo;s the value associated with the key
1008+
&ldquo;org.opencontainers.image.revision&rdquo;.</p>
1009+
</td>
1010+
</tr>
1011+
<tr>
1012+
<td>
9971013
<code>lastAttemptedRevision</code><br>
9981014
<em>
9991015
string

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ require (
1919
github.com/fluxcd/cli-utils v0.36.0-flux.11
2020
github.com/fluxcd/kustomize-controller/api v1.4.0
2121
github.com/fluxcd/pkg/apis/acl v0.5.0
22-
github.com/fluxcd/pkg/apis/event v0.13.0
22+
github.com/fluxcd/pkg/apis/event v0.15.0
2323
github.com/fluxcd/pkg/apis/kustomize v1.8.0
2424
github.com/fluxcd/pkg/apis/meta v1.9.0
2525
github.com/fluxcd/pkg/http/fetch v0.14.0

go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,8 @@ github.com/fluxcd/cli-utils v0.36.0-flux.11 h1:W0y2uvCVkcE8bgV9jgoGSjzWbLFiNq1Aj
181181
github.com/fluxcd/cli-utils v0.36.0-flux.11/go.mod h1:WZ7xUpZbK+O6HBxA5UWqzWTLSSltdmj4wS1LstS5Dqs=
182182
github.com/fluxcd/pkg/apis/acl v0.5.0 h1:+ykKezgerKUlZwSYFUy03lPMOIAyWlqvMNNLIWWqOhk=
183183
github.com/fluxcd/pkg/apis/acl v0.5.0/go.mod h1:IVDZx3MAoDWjlLrJHMF9Z27huFuXAEQlnbWw0M6EcTs=
184-
github.com/fluxcd/pkg/apis/event v0.13.0 h1:m5qHAhYIC0+mRFy5OC8FZxBVBGJM3qxJ/sEg2Vgx4T8=
185-
github.com/fluxcd/pkg/apis/event v0.13.0/go.mod h1:aRK2AONnjjSNW61B6Iy3SW4YHozACntnJeGm3fFqDqA=
184+
github.com/fluxcd/pkg/apis/event v0.15.0 h1:k1suqIfVxnhEeKlGkvlHAbOYXjY8wRixT/OZcIuakqA=
185+
github.com/fluxcd/pkg/apis/event v0.15.0/go.mod h1:aRK2AONnjjSNW61B6Iy3SW4YHozACntnJeGm3fFqDqA=
186186
github.com/fluxcd/pkg/apis/kustomize v1.8.0 h1:HH6YRa3SMS72KK4cUyb9m5sK/dZH+Eti1qhjWDCgwKg=
187187
github.com/fluxcd/pkg/apis/kustomize v1.8.0/go.mod h1:QCKIFj1ocdndaWSkrLs5JKvdGNYyTzQX1ZB3lYTwma0=
188188
github.com/fluxcd/pkg/apis/meta v1.9.0 h1:wPgm7bWNJZ/ImS5GqikOxt362IgLPFBG73dZ27uWRiQ=

internal/controller/constants.go

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
Copyright 2025 The Flux authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package controller
18+
19+
const OCIArtifactOriginRevisionAnnotation = "org.opencontainers.image.revision"

internal/controller/kustomization_controller.go

+38-16
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques
193193
time.Since(reconcileStart).String(),
194194
obj.Spec.Interval.Duration.String())
195195
log.Info(msg, "revision", obj.Status.LastAttemptedRevision)
196-
r.event(obj, obj.Status.LastAppliedRevision, eventv1.EventSeverityInfo, msg,
196+
r.event(obj, obj.Status.LastAppliedRevision, obj.Status.LastAppliedOriginRevision, eventv1.EventSeverityInfo, msg,
197197
map[string]string{
198198
kustomizev1.GroupVersion.Group + "/" + eventv1.MetaCommitStatusKey: eventv1.MetaCommitStatusUpdateValue,
199199
})
@@ -234,7 +234,7 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques
234234
if acl.IsAccessDenied(err) {
235235
conditions.MarkFalse(obj, meta.ReadyCondition, apiacl.AccessDeniedReason, "%s", err)
236236
log.Error(err, "Access denied to cross-namespace source")
237-
r.event(obj, "unknown", eventv1.EventSeverityError, err.Error(), nil)
237+
r.event(obj, "", "", eventv1.EventSeverityError, err.Error(), nil)
238238
return ctrl.Result{RequeueAfter: obj.GetRetryInterval()}, nil
239239
}
240240

@@ -249,14 +249,16 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques
249249
log.Info(msg)
250250
return ctrl.Result{RequeueAfter: r.requeueDependency}, nil
251251
}
252+
revision := artifactSource.GetArtifact().Revision
253+
originRevision := getOriginRevision(artifactSource)
252254

253255
// Check dependencies and requeue the reconciliation if the check fails.
254256
if len(obj.Spec.DependsOn) > 0 {
255257
if err := r.checkDependencies(ctx, obj, artifactSource); err != nil {
256258
conditions.MarkFalse(obj, meta.ReadyCondition, meta.DependencyNotReadyReason, "%s", err)
257259
msg := fmt.Sprintf("Dependencies do not meet ready condition, retrying in %s", r.requeueDependency.String())
258260
log.Info(msg)
259-
r.event(obj, artifactSource.GetArtifact().Revision, eventv1.EventSeverityInfo, msg, nil)
261+
r.event(obj, revision, originRevision, eventv1.EventSeverityInfo, msg, nil)
260262
return ctrl.Result{RequeueAfter: r.requeueDependency}, nil
261263
}
262264
log.Info("All dependencies are ready, proceeding with reconciliation")
@@ -279,8 +281,8 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques
279281
time.Since(reconcileStart).String(),
280282
obj.GetRetryInterval().String()),
281283
"revision",
282-
artifactSource.GetArtifact().Revision)
283-
r.event(obj, artifactSource.GetArtifact().Revision, eventv1.EventSeverityError,
284+
revision)
285+
r.event(obj, revision, originRevision, eventv1.EventSeverityError,
284286
reconcileErr.Error(), nil)
285287
return ctrl.Result{RequeueAfter: obj.GetRetryInterval()}, nil
286288
}
@@ -298,6 +300,7 @@ func (r *KustomizationReconciler) reconcile(
298300

299301
// Update status with the reconciliation progress.
300302
revision := src.GetArtifact().Revision
303+
originRevision := getOriginRevision(src)
301304
progressingMsg := fmt.Sprintf("Fetching manifests for revision %s with a timeout of %s", revision, obj.GetTimeout().String())
302305
conditions.MarkUnknown(obj, meta.ReadyCondition, meta.ProgressingReason, "%s", "Reconciliation in progress")
303306
conditions.MarkReconciling(obj, meta.ProgressingReason, "%s", progressingMsg)
@@ -419,7 +422,7 @@ func (r *KustomizationReconciler) reconcile(
419422
}
420423

421424
// Validate and apply resources in stages.
422-
drifted, changeSet, err := r.apply(ctx, resourceManager, obj, revision, objects)
425+
drifted, changeSet, err := r.apply(ctx, resourceManager, obj, revision, originRevision, objects)
423426
if err != nil {
424427
conditions.MarkFalse(obj, meta.ReadyCondition, meta.ReconciliationFailedReason, "%s", err)
425428
return err
@@ -444,7 +447,7 @@ func (r *KustomizationReconciler) reconcile(
444447
}
445448

446449
// Run garbage collection for stale resources that do not have pruning disabled.
447-
if _, err := r.prune(ctx, resourceManager, obj, revision, staleObjects); err != nil {
450+
if _, err := r.prune(ctx, resourceManager, obj, revision, originRevision, staleObjects); err != nil {
448451
conditions.MarkFalse(obj, meta.ReadyCondition, meta.PruneFailedReason, "%s", err)
449452
return err
450453
}
@@ -456,15 +459,17 @@ func (r *KustomizationReconciler) reconcile(
456459
patcher,
457460
obj,
458461
revision,
462+
originRevision,
459463
isNewRevision,
460464
drifted,
461465
changeSet.ToObjMetadataSet()); err != nil {
462466
conditions.MarkFalse(obj, meta.ReadyCondition, meta.HealthCheckFailedReason, "%s", err)
463467
return err
464468
}
465469

466-
// Set last applied revision.
470+
// Set last applied revisions.
467471
obj.Status.LastAppliedRevision = revision
472+
obj.Status.LastAppliedOriginRevision = originRevision
468473

469474
// Mark the object as ready.
470475
conditions.MarkTrue(obj,
@@ -656,6 +661,7 @@ func (r *KustomizationReconciler) apply(ctx context.Context,
656661
manager *ssa.ResourceManager,
657662
obj *kustomizev1.Kustomization,
658663
revision string,
664+
originRevision string,
659665
objects []*unstructured.Unstructured) (bool, *ssa.ChangeSet, error) {
660666
log := ctrl.LoggerFrom(ctx)
661667

@@ -841,7 +847,7 @@ func (r *KustomizationReconciler) apply(ctx context.Context,
841847
// emit event only if the server-side apply resulted in changes
842848
applyLog := strings.TrimSuffix(changeSetLog.String(), "\n")
843849
if applyLog != "" {
844-
r.event(obj, revision, eventv1.EventSeverityInfo, applyLog, nil)
850+
r.event(obj, revision, originRevision, eventv1.EventSeverityInfo, applyLog, nil)
845851
}
846852

847853
return applyLog != "", resultSet, nil
@@ -852,6 +858,7 @@ func (r *KustomizationReconciler) checkHealth(ctx context.Context,
852858
patcher *patch.SerialPatcher,
853859
obj *kustomizev1.Kustomization,
854860
revision string,
861+
originRevision string,
855862
isNewRevision bool,
856863
drifted bool,
857864
objects object.ObjMetadataSet) error {
@@ -910,7 +917,7 @@ func (r *KustomizationReconciler) checkHealth(ctx context.Context,
910917
// Emit recovery event if the previous health check failed.
911918
msg := fmt.Sprintf("Health check passed in %s", time.Since(checkStart).String())
912919
if !wasHealthy || (isNewRevision && drifted) {
913-
r.event(obj, revision, eventv1.EventSeverityInfo, msg, nil)
920+
r.event(obj, revision, originRevision, eventv1.EventSeverityInfo, msg, nil)
914921
}
915922

916923
conditions.MarkTrue(obj, meta.HealthyCondition, meta.SucceededReason, "%s", msg)
@@ -925,6 +932,7 @@ func (r *KustomizationReconciler) prune(ctx context.Context,
925932
manager *ssa.ResourceManager,
926933
obj *kustomizev1.Kustomization,
927934
revision string,
935+
originRevision string,
928936
objects []*unstructured.Unstructured) (bool, error) {
929937
if !obj.Spec.Prune {
930938
return false, nil
@@ -949,7 +957,7 @@ func (r *KustomizationReconciler) prune(ctx context.Context,
949957
// emit event only if the prune operation resulted in changes
950958
if changeSet != nil && len(changeSet.Entries) > 0 {
951959
log.Info(fmt.Sprintf("garbage collection completed: %s", changeSet.String()))
952-
r.event(obj, revision, eventv1.EventSeverityInfo, changeSet.String(), nil)
960+
r.event(obj, revision, originRevision, eventv1.EventSeverityInfo, changeSet.String(), nil)
953961
return true, nil
954962
}
955963

@@ -1004,19 +1012,19 @@ func (r *KustomizationReconciler) finalize(ctx context.Context,
10041012

10051013
changeSet, err := resourceManager.DeleteAll(ctx, objects, opts)
10061014
if err != nil {
1007-
r.event(obj, obj.Status.LastAppliedRevision, eventv1.EventSeverityError, "pruning for deleted resource failed", nil)
1015+
r.event(obj, obj.Status.LastAppliedRevision, obj.Status.LastAppliedOriginRevision, eventv1.EventSeverityError, "pruning for deleted resource failed", nil)
10081016
// Return the error so we retry the failed garbage collection
10091017
return ctrl.Result{}, err
10101018
}
10111019

10121020
if changeSet != nil && len(changeSet.Entries) > 0 {
1013-
r.event(obj, obj.Status.LastAppliedRevision, eventv1.EventSeverityInfo, changeSet.String(), nil)
1021+
r.event(obj, obj.Status.LastAppliedRevision, obj.Status.LastAppliedOriginRevision, eventv1.EventSeverityInfo, changeSet.String(), nil)
10141022
}
10151023
} else {
10161024
// when the account to impersonate is gone, log the stale objects and continue with the finalization
10171025
msg := fmt.Sprintf("unable to prune objects: \n%s", ssautil.FmtUnstructuredList(objects))
10181026
log.Error(fmt.Errorf("skiping pruning, failed to find account to impersonate"), msg)
1019-
r.event(obj, obj.Status.LastAppliedRevision, eventv1.EventSeverityError, msg, nil)
1027+
r.event(obj, obj.Status.LastAppliedRevision, obj.Status.LastAppliedOriginRevision, eventv1.EventSeverityError, msg, nil)
10201028
}
10211029
}
10221030

@@ -1027,13 +1035,16 @@ func (r *KustomizationReconciler) finalize(ctx context.Context,
10271035
}
10281036

10291037
func (r *KustomizationReconciler) event(obj *kustomizev1.Kustomization,
1030-
revision, severity, msg string,
1038+
revision, originRevision, severity, msg string,
10311039
metadata map[string]string) {
10321040
if metadata == nil {
10331041
metadata = map[string]string{}
10341042
}
10351043
if revision != "" {
1036-
metadata[kustomizev1.GroupVersion.Group+"/revision"] = revision
1044+
metadata[kustomizev1.GroupVersion.Group+"/"+eventv1.MetaRevisionKey] = revision
1045+
}
1046+
if originRevision != "" {
1047+
metadata[kustomizev1.GroupVersion.Group+"/"+eventv1.MetaOriginRevisionKey] = originRevision
10371048
}
10381049

10391050
reason := severity
@@ -1108,3 +1119,14 @@ func (r *KustomizationReconciler) patch(ctx context.Context,
11081119

11091120
return nil
11101121
}
1122+
1123+
// getOriginRevision returns the origin revision of the source artifact,
1124+
// or the empty string if it's not present, or if the artifact itself
1125+
// is not present.
1126+
func getOriginRevision(src sourcev1.Source) string {
1127+
a := src.GetArtifact()
1128+
if a == nil {
1129+
return ""
1130+
}
1131+
return a.Metadata[OCIArtifactOriginRevisionAnnotation]
1132+
}

0 commit comments

Comments
 (0)