Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: revisions info reporting with multi-sourced apps support #333

Merged
merged 26 commits into from
Oct 5, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9ecb8eb
event-reporter: added utils methods to retrieve revisions metadata fo…
oleksandr-codefresh Sep 10, 2024
37f5a05
event-reporter: report all revisions metadata instead single to suppo…
oleksandr-codefresh Sep 11, 2024
bf0e87a
event-reporter: added revision sha to reported value in anotations - …
oleksandr-codefresh Sep 25, 2024
e757883
Merge branch 'release-2.12' of github.com:codefresh-io/argo-cd into C…
oleksandr-codefresh Sep 25, 2024
1ad1112
event-reporter: added change revisions sha to reported value in anota…
oleksandr-codefresh Sep 25, 2024
3dd3f0d
event-reporter: updated changelog
oleksandr-codefresh Sep 25, 2024
54258ef
event-reporter: changes to anotations repoting - app.meta.revisions-m…
oleksandr-codefresh Sep 27, 2024
a9c0b2c
event-reporter: changes after pr review
oleksandr-codefresh Sep 27, 2024
7e1f1c2
Merge branch 'release-2.12' of github.com:codefresh-io/argo-cd into C…
oleksandr-codefresh Sep 27, 2024
472aa63
event-reporter: fixed unit tests
oleksandr-codefresh Sep 27, 2024
9bc3265
event-reporter: fix lint issues
oleksandr-codefresh Sep 27, 2024
c3becdc
Merge branch 'release-2.12' of github.com:codefresh-io/argo-cd into C…
pasha-codefresh Sep 30, 2024
d3ccc7d
Merge branch 'CR-23842-revisions-info-reporting' of github.com:codefr…
pasha-codefresh Sep 30, 2024
006f6db
event-reporter: changes after pr reviev, fixing typo, added dedicated…
oleksandr-codefresh Sep 30, 2024
c6d1667
Merge branch 'CR-23842-revisions-info-reporting' of github.com:codefr…
oleksandr-codefresh Sep 30, 2024
fb704ae
event-reporter: refactoring of getApplicationLegacyRevisionDetails me…
oleksandr-codefresh Sep 30, 2024
91272b6
event-reporter / app_revision_test.go: added some tests to AddCommits…
oleksandr-codefresh Sep 30, 2024
a8cc45e
event-reporter / app_revision_test.go: added tests for GetRevisionsDe…
oleksandr-codefresh Oct 1, 2024
02c14a3
event-reporter: updated app client to support sourceIndex param in no…
oleksandr-codefresh Oct 1, 2024
09fddac
event-reporter / app_revision.go: added sourceIndex param to applicat…
oleksandr-codefresh Oct 1, 2024
ea8cdce
Merge branch 'release-2.12' of github.com:codefresh-io/argo-cd into C…
oleksandr-codefresh Oct 1, 2024
29db9f8
event-reporter: lint fix
oleksandr-codefresh Oct 1, 2024
b395e00
event-reporter: fix lint issues
oleksandr-codefresh Oct 1, 2024
d5c22f3
event-reporter: fix lint issues
oleksandr-codefresh Oct 1, 2024
dc7b414
event-reporter: added back regacy logic with setting of commit detail…
oleksandr-codefresh Oct 4, 2024
33e0b97
event-reporter: added condition to not send empty array for ChangeRev…
oleksandr-codefresh Oct 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion changelog/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
### Features
- feat: monorepo controller v1.0.0
- feat: event-reporter: report change revisions metadata in app annotations
80 changes: 73 additions & 7 deletions event_reporter/reporter/app_revision.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,82 @@ package reporter
import (
"context"

"github.com/argoproj/argo-cd/v2/event_reporter/utils"
"github.com/argoproj/argo-cd/v2/pkg/apiclient/application"

appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
log "github.com/sirupsen/logrus"
)

func (s *applicationEventReporter) getApplicationRevisionDetails(ctx context.Context, a *appv1.Application, revision string) (*appv1.RevisionMetadata, error) {
// treats multi-sourced apps as single source and gets first revision details
func getApplicationLegacyRevisionDetails(a *appv1.Application, revisionsMetadata *utils.AppSyncRevisionsMetadata) *appv1.RevisionMetadata {
_, sourceIdx := a.Spec.GetNonRefSource()

if sourceIdx == -1 { // single source app
sourceIdx = 0
}

if revisionsMetadata.SyncRevisions == nil || len(revisionsMetadata.SyncRevisions) == 0 {
return nil
}

return revisionsMetadata.SyncRevisions[sourceIdx].Metadata
}

func (s *applicationEventReporter) getRevisionsDetails(ctx context.Context, a *appv1.Application, revisions []string) ([]*utils.RevisionWithMetadata, error) {
project := a.Spec.GetProject()
return s.applicationServiceClient.RevisionMetadata(ctx, &application.RevisionMetadataQuery{
Name: &a.Name,
AppNamespace: &a.Namespace,
Revision: &revision,
Project: &project,
})
rms := make([]*utils.RevisionWithMetadata, 0)

for idx, revision := range revisions {
// report just revision for helm sources
if (a.Spec.HasMultipleSources() && a.Spec.Sources[idx].IsHelm()) || (a.Spec.Source != nil && a.Spec.Source.IsHelm()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move this condition into dedicated types . Make it a.Spec.IsHelm(idx)

rms = append(rms, &utils.RevisionWithMetadata{
Revision: revision,
})
continue
}

rm, err := s.applicationServiceClient.RevisionMetadata(ctx, &application.RevisionMetadataQuery{
Name: &a.Name,
AppNamespace: &a.Namespace,
Revision: &revision,
Project: &project,
})
if err != nil {
return nil, err
}
rms = append(rms, &utils.RevisionWithMetadata{
Revision: revision,
Metadata: rm,
})
}

return rms, nil
}

func (s *applicationEventReporter) getApplicationRevisionsMetadata(ctx context.Context, logCtx *log.Entry, a *appv1.Application) (*utils.AppSyncRevisionsMetadata, error) {
result := &utils.AppSyncRevisionsMetadata{}

if a.Status.Sync.Revision != "" || a.Status.Sync.Revisions != nil || (a.Status.History != nil && len(a.Status.History) > 0) {
// can be the latest revision of repository
operationSyncRevisionsMetadata, err := s.getRevisionsDetails(ctx, a, utils.GetOperationSyncRevisions(a))
if err != nil {
logCtx.WithError(err).Warnf("failed to get application(%s) sync revisions metadata, resuming", a.GetName())
}

if err == nil && operationSyncRevisionsMetadata != nil {
result.SyncRevisions = operationSyncRevisionsMetadata
}
// latest revision of repository where changes to app resource were actually made; empty if no changeRevisionі present
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

operationChangeRevisionsMetadata, err := s.getRevisionsDetails(ctx, a, utils.GetOperationChangeRevisions(a))
if err != nil {
logCtx.WithError(err).Warnf("failed to get application(%s) change revisions metadata, resuming", a.GetName())
}

if err == nil && operationChangeRevisionsMetadata != nil {
result.ChangeRevisions = operationChangeRevisionsMetadata
}
}

return result, nil
}
32 changes: 16 additions & 16 deletions event_reporter/reporter/application_event_reporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,14 +166,13 @@ func (s *applicationEventReporter) StreamApplicationEvents(

// helm app hasnt revision
// TODO: add check if it helm application
parentOperationRevision := utils.GetOperationRevision(parentApplicationEntity)
parentRevisionMetadata, err := s.getApplicationRevisionDetails(ctx, parentApplicationEntity, parentOperationRevision)
parentAppSyncRevisionsMetadata, err := s.getApplicationRevisionsMetadata(ctx, logCtx, parentApplicationEntity)
if err != nil {
logCtx.WithError(err).Warn("failed to get parent application's revision metadata, resuming")
}

utils.SetHealthStatusIfMissing(rs)
err = s.processResource(ctx, *rs, parentApplicationEntity, logCtx, ts, parentDesiredManifests, appTree, manifestGenErr, a, parentRevisionMetadata, appInstanceLabelKey, trackingMethod, desiredManifests.ApplicationVersions)
err = s.processResource(ctx, *rs, parentApplicationEntity, logCtx, ts, parentDesiredManifests, appTree, manifestGenErr, a, parentAppSyncRevisionsMetadata, appInstanceLabelKey, trackingMethod, desiredManifests.ApplicationVersions)
if err != nil {
s.metricsServer.IncErroredEventsCounter(metrics.MetricChildAppEventType, metrics.MetricEventUnknownErrorType, a.Name)
return err
Expand Down Expand Up @@ -203,7 +202,7 @@ func (s *applicationEventReporter) StreamApplicationEvents(
s.metricsServer.ObserveEventProcessingDurationHistogramDuration(a.Name, metrics.MetricParentAppEventType, reconcileDuration)
}

revisionMetadata, _ := s.getApplicationRevisionDetails(ctx, a, utils.GetOperationRevision(a))
revisionsMetadata, _ := s.getApplicationRevisionsMetadata(ctx, logCtx, a)
// for each resource in the application get desired and actual state,
// then stream the event
for _, rs := range a.Status.Resources {
Expand All @@ -215,7 +214,7 @@ func (s *applicationEventReporter) StreamApplicationEvents(
s.metricsServer.IncCachedIgnoredEventsCounter(metrics.MetricResourceEventType, a.Name)
continue
}
err := s.processResource(ctx, rs, a, logCtx, ts, desiredManifests, appTree, manifestGenErr, nil, revisionMetadata, appInstanceLabelKey, trackingMethod, nil)
err := s.processResource(ctx, rs, a, logCtx, ts, desiredManifests, appTree, manifestGenErr, nil, revisionsMetadata, appInstanceLabelKey, trackingMethod, nil)
if err != nil {
s.metricsServer.IncErroredEventsCounter(metrics.MetricResourceEventType, metrics.MetricEventUnknownErrorType, a.Name)
return err
Expand All @@ -227,21 +226,22 @@ func (s *applicationEventReporter) StreamApplicationEvents(
func (s *applicationEventReporter) getAppForResourceReporting(
rs appv1.ResourceStatus,
ctx context.Context,
logCtx *log.Entry,
a *appv1.Application,
revisionMetadata *appv1.RevisionMetadata,
) (*appv1.Application, *appv1.RevisionMetadata) {
syncRevisionsMetadata *utils.AppSyncRevisionsMetadata,
) (*appv1.Application, *utils.AppSyncRevisionsMetadata) {
if rs.Kind != "Rollout" { // for rollout it's crucial to report always correct operationSyncRevision
return a, revisionMetadata
return a, syncRevisionsMetadata
}

latestAppStatus, err := s.appLister.Applications(a.Namespace).Get(a.Name)
if err != nil {
return a, revisionMetadata
return a, syncRevisionsMetadata
}

revisionMetadataToReport, err := s.getApplicationRevisionDetails(ctx, latestAppStatus, utils.GetOperationRevision(latestAppStatus))
revisionMetadataToReport, err := s.getApplicationRevisionsMetadata(ctx, logCtx, latestAppStatus)
if err != nil {
return a, revisionMetadata
return a, syncRevisionsMetadata
}

return latestAppStatus, revisionMetadataToReport
Expand All @@ -257,7 +257,7 @@ func (s *applicationEventReporter) processResource(
appTree *appv1.ApplicationTree,
manifestGenErr bool,
originalApplication *appv1.Application,
revisionMetadata *appv1.RevisionMetadata,
revisionsMetadata *utils.AppSyncRevisionsMetadata,
appInstanceLabelKey string,
trackingMethod appv1.TrackingMethod,
applicationVersions *apiclient.ApplicationVersions,
Expand All @@ -283,12 +283,12 @@ func (s *applicationEventReporter) processResource(
return nil
}

parentApplicationToReport, revisionMetadataToReport := s.getAppForResourceReporting(rs, ctx, parentApplication, revisionMetadata)
parentApplicationToReport, revisionMetadataToReport := s.getAppForResourceReporting(rs, ctx, logCtx, parentApplication, revisionsMetadata)

var originalAppRevisionMetadata *appv1.RevisionMetadata = nil
var originalAppRevisionMetadata *utils.AppSyncRevisionsMetadata = nil

if originalApplication != nil {
originalAppRevisionMetadata, _ = s.getApplicationRevisionDetails(ctx, originalApplication, utils.GetOperationRevision(originalApplication))
originalAppRevisionMetadata, _ = s.getApplicationRevisionsMetadata(ctx, logCtx, originalApplication)
}

ev, err := getResourceEventPayload(parentApplicationToReport, &rs, actualState, desiredState, appTree, manifestGenErr, ts, originalApplication, revisionMetadataToReport, originalAppRevisionMetadata, appInstanceLabelKey, trackingMethod, applicationVersions)
Expand All @@ -305,7 +305,7 @@ func (s *applicationEventReporter) processResource(
appName = appRes.Name
} else {
utils.LogWithResourceStatus(logCtx, rs).Info("streaming resource event")
appName = rs.Name
appName = parentApplication.Name
}

if err := s.codefreshClient.SendEvent(ctx, appName, ev); err != nil {
Expand Down
64 changes: 34 additions & 30 deletions event_reporter/reporter/event_payload.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ func getResourceEventPayload(
manifestGenErr bool,
ts string,
originalApplication *appv1.Application, // passed when rs is application
revisionMetadata *appv1.RevisionMetadata,
originalAppRevisionMetadata *appv1.RevisionMetadata, // passed when rs is application
revisionsMetadata *utils.AppSyncRevisionsMetadata,
originalAppRevisionsMetadata *utils.AppSyncRevisionsMetadata, // passed when rs is application
appInstanceLabelKey string,
trackingMethod appv1.TrackingMethod,
applicationVersions *apiclient.ApplicationVersions,
Expand All @@ -50,11 +50,15 @@ func getResourceEventPayload(

object := []byte(*actualState.Manifest)

if originalAppRevisionMetadata != nil && len(object) != 0 {
if originalAppRevisionsMetadata != nil && len(object) != 0 {
actualObject, err := appv1.UnmarshalToUnstructured(*actualState.Manifest)

if err == nil {
actualObject = utils.AddCommitDetailsToLabels(actualObject, originalAppRevisionMetadata)
actualObject = utils.AddCommitsDetailsToAnnotations(actualObject, originalAppRevisionsMetadata)
if originalApplication != nil {
actualObject = utils.AddCommitDetailsToLabels(actualObject, getApplicationLegacyRevisionDetails(originalApplication, originalAppRevisionsMetadata))
}

object, err = actualObject.MarshalJSON()
if err != nil {
return nil, fmt.Errorf("failed to marshal unstructured object: %w", err)
Expand All @@ -74,8 +78,11 @@ func getResourceEventPayload(
u.SetKind(rs.Kind)
u.SetName(rs.Name)
u.SetNamespace(rs.Namespace)
if originalAppRevisionMetadata != nil {
u = utils.AddCommitDetailsToLabels(u, originalAppRevisionMetadata)
if originalAppRevisionsMetadata != nil {
u = utils.AddCommitsDetailsToAnnotations(u, originalAppRevisionsMetadata)
if originalApplication != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imho it is redundant

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

u = utils.AddCommitDetailsToLabels(u, getApplicationLegacyRevisionDetails(originalApplication, originalAppRevisionsMetadata))
}
}

object, err = u.MarshalJSON()
Expand All @@ -88,8 +95,11 @@ func getResourceEventPayload(
if err != nil {
return nil, fmt.Errorf("failed to add destination namespace to manifest: %w", err)
}
if originalAppRevisionMetadata != nil {
unstructuredWithNamespace = utils.AddCommitDetailsToLabels(unstructuredWithNamespace, originalAppRevisionMetadata)
if originalAppRevisionsMetadata != nil {
unstructuredWithNamespace = utils.AddCommitsDetailsToAnnotations(unstructuredWithNamespace, originalAppRevisionsMetadata)
if originalApplication != nil {
unstructuredWithNamespace = utils.AddCommitDetailsToLabels(unstructuredWithNamespace, getApplicationLegacyRevisionDetails(originalApplication, originalAppRevisionsMetadata))
}
}

object, _ = unstructuredWithNamespace.MarshalJSON()
Expand Down Expand Up @@ -166,10 +176,13 @@ func getResourceEventPayload(
TrackingMethod: string(trackingMethod),
}

if revisionMetadata != nil {
source.CommitMessage = revisionMetadata.Message
source.CommitAuthor = revisionMetadata.Author
source.CommitDate = &revisionMetadata.Date
if revisionsMetadata != nil && revisionsMetadata.SyncRevisions != nil {
revisionMetadata := getApplicationLegacyRevisionDetails(parentApplication, revisionsMetadata)
if revisionMetadata != nil {
source.CommitMessage = revisionMetadata.Message
source.CommitAuthor = revisionMetadata.Author
source.CommitDate = &revisionMetadata.Date
}
}

if rs.Health != nil {
Expand Down Expand Up @@ -225,27 +238,18 @@ func (s *applicationEventReporter) getApplicationEventPayload(
syncFinished = a.Status.OperationState.FinishedAt
}

applicationSource := a.Spec.GetSource()
if !applicationSource.IsHelm() && (a.Status.Sync.Revision != "" || (a.Status.History != nil && len(a.Status.History) > 0)) {
revisionMetadata, err := s.getApplicationRevisionDetails(ctx, a, utils.GetOperationRevision(a))

if err != nil {
if !strings.Contains(err.Error(), "not found") {
return nil, fmt.Errorf("failed to get revision metadata: %w", err)
}

logCtx.Warnf("failed to get revision metadata: %s, reporting application deletion event", err.Error())
} else {
if obj.ObjectMeta.Labels == nil {
obj.ObjectMeta.Labels = map[string]string{}
}

obj.ObjectMeta.Labels["app.meta.commit-date"] = revisionMetadata.Date.Format("2006-01-02T15:04:05.000Z")
obj.ObjectMeta.Labels["app.meta.commit-author"] = revisionMetadata.Author
obj.ObjectMeta.Labels["app.meta.commit-message"] = revisionMetadata.Message
revisionsMetadata, err := s.getApplicationRevisionsMetadata(ctx, logCtx, a)
if err != nil {
if !strings.Contains(err.Error(), "not found") {
return nil, fmt.Errorf("failed to get revision metadata: %w", err)
}

logCtx.Warnf("failed to get revision metadata: %s, reporting application deletion event", err.Error())
}

utils.AddCommitsDetailsToAppAnnotations(obj, revisionsMetadata)
utils.AddCommitsDetailsToAppLabels(&obj, getApplicationLegacyRevisionDetails(&obj, revisionsMetadata))

object, err := json.Marshal(&obj)
if err != nil {
return nil, fmt.Errorf("failed to marshal application event")
Expand Down
30 changes: 20 additions & 10 deletions event_reporter/reporter/event_payload_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"encoding/json"
"testing"

"github.com/argoproj/argo-cd/v2/event_reporter/utils"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -18,7 +20,13 @@ import (

func TestGetResourceEventPayload(t *testing.T) {
t.Run("Deleting timestamp is empty", func(t *testing.T) {
app := v1alpha1.Application{}
app := v1alpha1.Application{
Spec: v1alpha1.ApplicationSpec{
Source: &v1alpha1.ApplicationSource{
RepoURL: "test",
},
},
}
rs := v1alpha1.ResourceStatus{}

man := "{ \"key\" : \"manifest\" }"
Expand All @@ -30,10 +38,14 @@ func TestGetResourceEventPayload(t *testing.T) {
CompiledManifest: "{ \"key\" : \"manifest\" }",
}
appTree := v1alpha1.ApplicationTree{}
revisionMetadata := v1alpha1.RevisionMetadata{
Author: "demo usert",
Date: metav1.Time{},
Message: "some message",
revisionMetadata := utils.AppSyncRevisionsMetadata{
SyncRevisions: []*utils.RevisionWithMetadata{{
Metadata: &v1alpha1.RevisionMetadata{
Author: "demo usert",
Date: metav1.Time{},
Message: "some message",
},
}},
}

event, err := getResourceEventPayload(&app, &rs, &actualState, &desiredState, &appTree, true, "", nil, &revisionMetadata, nil, common.LabelKeyAppInstance, argo.TrackingMethodLabel, &repoApiclient.ApplicationVersions{})
Expand All @@ -48,7 +60,7 @@ func TestGetResourceEventPayload(t *testing.T) {
assert.Equal(t, "{ \"key\" : \"manifest\" }", eventPayload.Source.ActualManifest)
})

t.Run("Deleting timestamp is empty", func(t *testing.T) {
t.Run("Deleting timestamp not empty", func(t *testing.T) {
app := v1alpha1.Application{
ObjectMeta: metav1.ObjectMeta{
DeletionTimestamp: &metav1.Time{},
Expand All @@ -64,10 +76,8 @@ func TestGetResourceEventPayload(t *testing.T) {
CompiledManifest: "{ \"key\" : \"manifest\" }",
}
appTree := v1alpha1.ApplicationTree{}
revisionMetadata := v1alpha1.RevisionMetadata{
Author: "demo usert",
Date: metav1.Time{},
Message: "some message",
revisionMetadata := utils.AppSyncRevisionsMetadata{
SyncRevisions: []*utils.RevisionWithMetadata{},
}

event, err := getResourceEventPayload(&app, &rs, &actualState, &desiredState, &appTree, true, "", nil, &revisionMetadata, nil, common.LabelKeyAppInstance, argo.TrackingMethodLabel, &repoApiclient.ApplicationVersions{})
Expand Down
Loading
Loading