Skip to content

Commit

Permalink
Add OCI revision to events
Browse files Browse the repository at this point in the history
Signed-off-by: Matheus Pimenta <[email protected]>
  • Loading branch information
matheuscscp committed Jan 21, 2025
1 parent 550576e commit cdd7060
Show file tree
Hide file tree
Showing 9 changed files with 245 additions and 22 deletions.
8 changes: 8 additions & 0 deletions api/v1/kustomization_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,14 @@ type KustomizationStatus struct {
// +optional
LastAppliedRevision string `json:"lastAppliedRevision,omitempty"`

// The last successfully applied origin revision.
// Equals the origin revision of the applied Artifact from the referenced Source.
// Usually present on the Metadata of the applied Artifact and depends on the
// Source type, e.g. for OCI it's the value associated with the key
// "org.opencontainers.image.revision".
// +optional
LastAppliedOriginRevision string `json:"lastAppliedOriginRevision,omitempty"`

// LastAttemptedRevision is the revision of the last reconciliation attempt.
// +optional
LastAttemptedRevision string `json:"lastAttemptedRevision,omitempty"`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,14 @@ spec:
required:
- entries
type: object
lastAppliedOriginRevision:
description: |-
The last successfully applied origin revision.
Equals the origin revision of the applied Artifact from the referenced Source.
Usually present on the Metadata of the applied Artifact and depends on the
Source type, e.g. for OCI it's the value associated with the key
"org.opencontainers.image.revision".
type: string
lastAppliedRevision:
description: |-
The last successfully applied revision.
Expand Down
16 changes: 16 additions & 0 deletions docs/api/v1/kustomize.md
Original file line number Diff line number Diff line change
Expand Up @@ -994,6 +994,22 @@ Equals the Revision of the applied Artifact from the referenced Source.</p>
</tr>
<tr>
<td>
<code>lastAppliedOriginRevision</code><br>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>The last successfully applied origin revision.
Equals the origin revision of the applied Artifact from the referenced Source.
Usually present on the Metadata of the applied Artifact and depends on the
Source type, e.g. for OCI it&rsquo;s the value associated with the key
&ldquo;org.opencontainers.image.revision&rdquo;.</p>
</td>
</tr>
<tr>
<td>
<code>lastAttemptedRevision</code><br>
<em>
string
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ require (
github.com/fluxcd/cli-utils v0.36.0-flux.11
github.com/fluxcd/kustomize-controller/api v1.4.0
github.com/fluxcd/pkg/apis/acl v0.5.0
github.com/fluxcd/pkg/apis/event v0.13.0
github.com/fluxcd/pkg/apis/event v0.15.0
github.com/fluxcd/pkg/apis/kustomize v1.8.0
github.com/fluxcd/pkg/apis/meta v1.9.0
github.com/fluxcd/pkg/http/fetch v0.14.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,8 @@ github.com/fluxcd/cli-utils v0.36.0-flux.11 h1:W0y2uvCVkcE8bgV9jgoGSjzWbLFiNq1Aj
github.com/fluxcd/cli-utils v0.36.0-flux.11/go.mod h1:WZ7xUpZbK+O6HBxA5UWqzWTLSSltdmj4wS1LstS5Dqs=
github.com/fluxcd/pkg/apis/acl v0.5.0 h1:+ykKezgerKUlZwSYFUy03lPMOIAyWlqvMNNLIWWqOhk=
github.com/fluxcd/pkg/apis/acl v0.5.0/go.mod h1:IVDZx3MAoDWjlLrJHMF9Z27huFuXAEQlnbWw0M6EcTs=
github.com/fluxcd/pkg/apis/event v0.13.0 h1:m5qHAhYIC0+mRFy5OC8FZxBVBGJM3qxJ/sEg2Vgx4T8=
github.com/fluxcd/pkg/apis/event v0.13.0/go.mod h1:aRK2AONnjjSNW61B6Iy3SW4YHozACntnJeGm3fFqDqA=
github.com/fluxcd/pkg/apis/event v0.15.0 h1:k1suqIfVxnhEeKlGkvlHAbOYXjY8wRixT/OZcIuakqA=
github.com/fluxcd/pkg/apis/event v0.15.0/go.mod h1:aRK2AONnjjSNW61B6Iy3SW4YHozACntnJeGm3fFqDqA=
github.com/fluxcd/pkg/apis/kustomize v1.8.0 h1:HH6YRa3SMS72KK4cUyb9m5sK/dZH+Eti1qhjWDCgwKg=
github.com/fluxcd/pkg/apis/kustomize v1.8.0/go.mod h1:QCKIFj1ocdndaWSkrLs5JKvdGNYyTzQX1ZB3lYTwma0=
github.com/fluxcd/pkg/apis/meta v1.9.0 h1:wPgm7bWNJZ/ImS5GqikOxt362IgLPFBG73dZ27uWRiQ=
Expand Down
19 changes: 19 additions & 0 deletions internal/controller/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
Copyright 2025 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package controller

const OCIArtifactOriginRevisionAnnotation = "org.opencontainers.image.revision"
54 changes: 38 additions & 16 deletions internal/controller/kustomization_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques
time.Since(reconcileStart).String(),
obj.Spec.Interval.Duration.String())
log.Info(msg, "revision", obj.Status.LastAttemptedRevision)
r.event(obj, obj.Status.LastAppliedRevision, eventv1.EventSeverityInfo, msg,
r.event(obj, obj.Status.LastAppliedRevision, obj.Status.LastAppliedOriginRevision, eventv1.EventSeverityInfo, msg,
map[string]string{
kustomizev1.GroupVersion.Group + "/" + eventv1.MetaCommitStatusKey: eventv1.MetaCommitStatusUpdateValue,
})
Expand Down Expand Up @@ -234,7 +234,7 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques
if acl.IsAccessDenied(err) {
conditions.MarkFalse(obj, meta.ReadyCondition, apiacl.AccessDeniedReason, "%s", err)
log.Error(err, "Access denied to cross-namespace source")
r.event(obj, "unknown", eventv1.EventSeverityError, err.Error(), nil)
r.event(obj, "", "", eventv1.EventSeverityError, err.Error(), nil)
return ctrl.Result{RequeueAfter: obj.GetRetryInterval()}, nil
}

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

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

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

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

// Run garbage collection for stale resources that do not have pruning disabled.
if _, err := r.prune(ctx, resourceManager, obj, revision, staleObjects); err != nil {
if _, err := r.prune(ctx, resourceManager, obj, revision, originRevision, staleObjects); err != nil {
conditions.MarkFalse(obj, meta.ReadyCondition, meta.PruneFailedReason, "%s", err)
return err
}
Expand All @@ -456,15 +459,17 @@ func (r *KustomizationReconciler) reconcile(
patcher,
obj,
revision,
originRevision,
isNewRevision,
drifted,
changeSet.ToObjMetadataSet()); err != nil {
conditions.MarkFalse(obj, meta.ReadyCondition, meta.HealthCheckFailedReason, "%s", err)
return err
}

// Set last applied revision.
// Set last applied revisions.
obj.Status.LastAppliedRevision = revision
obj.Status.LastAppliedOriginRevision = originRevision

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

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

return applyLog != "", resultSet, nil
Expand All @@ -852,6 +858,7 @@ func (r *KustomizationReconciler) checkHealth(ctx context.Context,
patcher *patch.SerialPatcher,
obj *kustomizev1.Kustomization,
revision string,
originRevision string,
isNewRevision bool,
drifted bool,
objects object.ObjMetadataSet) error {
Expand Down Expand Up @@ -910,7 +917,7 @@ func (r *KustomizationReconciler) checkHealth(ctx context.Context,
// Emit recovery event if the previous health check failed.
msg := fmt.Sprintf("Health check passed in %s", time.Since(checkStart).String())
if !wasHealthy || (isNewRevision && drifted) {
r.event(obj, revision, eventv1.EventSeverityInfo, msg, nil)
r.event(obj, revision, originRevision, eventv1.EventSeverityInfo, msg, nil)
}

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

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

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

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

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

func (r *KustomizationReconciler) event(obj *kustomizev1.Kustomization,
revision, severity, msg string,
revision, originRevision, severity, msg string,
metadata map[string]string) {
if metadata == nil {
metadata = map[string]string{}
}
if revision != "" {
metadata[kustomizev1.GroupVersion.Group+"/revision"] = revision
metadata[kustomizev1.GroupVersion.Group+"/"+eventv1.MetaRevisionKey] = revision
}
if originRevision != "" {
metadata[kustomizev1.GroupVersion.Group+"/"+eventv1.MetaOriginRevisionKey] = originRevision
}

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

return nil
}

// getOriginRevision returns the origin revision of the source artifact,
// or the empty string if it's not present, or if the artifact itself
// is not present.
func getOriginRevision(src sourcev1.Source) string {
a := src.GetArtifact()
if a == nil {
return ""
}
return a.Metadata[OCIArtifactOriginRevisionAnnotation]
}
Loading

0 comments on commit cdd7060

Please sign in to comment.