Skip to content

Commit

Permalink
event-reporter: report all revisions metadata instead single to suppo…
Browse files Browse the repository at this point in the history
…rt multisourced apps
  • Loading branch information
oleksandr-codefresh committed Sep 23, 2024
1 parent 9ecb8eb commit 0b50690
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 66 deletions.
51 changes: 31 additions & 20 deletions event_reporter/reporter/app_revision.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,19 @@ import (
log "github.com/sirupsen/logrus"
)

func (s *applicationEventReporter) getApplicationRevisionDetails(ctx context.Context, a *appv1.Application, revision string) (*appv1.RevisionMetadata, error) {
project := a.Spec.GetProject()
return s.applicationServiceClient.RevisionMetadata(ctx, &application.RevisionMetadataQuery{
Name: &a.Name,
AppNamespace: &a.Namespace,
Revision: &revision,
Project: &project,
})
// 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]
}

func (s *applicationEventReporter) getCommitRevisionsDetails(ctx context.Context, a *appv1.Application, revisions []string) ([]*appv1.RevisionMetadata, error) {
Expand All @@ -41,21 +46,27 @@ func (s *applicationEventReporter) getCommitRevisionsDetails(ctx context.Context
func (s *applicationEventReporter) getApplicationRevisionsMetadata(ctx context.Context, logCtx *log.Entry, a *appv1.Application) (*utils.AppSyncRevisionsMetadata, error) {
result := &utils.AppSyncRevisionsMetadata{}

// can be the latest revision of repository
operationSyncRevisionsMetadata, err := s.getCommitRevisionsDetails(ctx, a, utils.GetOperationSyncRevisions(a))
if source, _ := a.Spec.GetNonRefSource(); !source.IsHelm() && (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.getCommitRevisionsDetails(ctx, a, utils.GetOperationSyncRevisions(a))

if err != nil {
logCtx.WithError(err).Warnf("failed to get application(%s) revisions metadata, resuming", a.GetName())
}
if err != nil {
logCtx.WithError(err).Warnf("failed to get application(%s) sync revisions metadata, resuming", a.GetName())
}

if operationSyncRevisionsMetadata != nil {
result.SyncRevisions = operationSyncRevisionsMetadata
}
// latest revision of repository where changes to app resource were actually made; empty if no changeRevisionі present
operationChangeRevisionsMetadata, err := s.getCommitRevisionsDetails(ctx, a, utils.GetOperationChangeRevisions(a))
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
operationChangeRevisionsMetadata, err := s.getCommitRevisionsDetails(ctx, a, utils.GetOperationChangeRevisions(a))

if err == nil && operationChangeRevisionsMetadata != nil {
result.ChangeRevisions = operationChangeRevisionsMetadata
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
Expand Down
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
63 changes: 34 additions & 29 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 {
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,19 @@ 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))
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())
} 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
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
40 changes: 39 additions & 1 deletion event_reporter/utils/app_revision.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ func AddCommitDetailsToLabels(u *unstructured.Unstructured, revisionMetadata *ap
return u
}

var annotationRevisionKey = "app.meta.revisions-metadata"

func AddCommitsDetailsToAnnotations(unstrApp *unstructured.Unstructured, revisionsMetadata *AppSyncRevisionsMetadata) *unstructured.Unstructured {
if revisionsMetadata == nil || unstrApp == nil {
return unstrApp
Expand All @@ -142,7 +144,43 @@ func AddCommitsDetailsToAnnotations(unstrApp *unstructured.Unstructured, revisio
return unstrApp
}

_ = unstructured.SetNestedField(unstrApp.Object, jsonRevisionsMetadata, "metadata", "annotations", "app.meta.revisions-metadata")
_ = unstructured.SetNestedField(unstrApp.Object, string(jsonRevisionsMetadata), "metadata", "annotations", annotationRevisionKey)

return unstrApp
}

func AddCommitsDetailsToAppAnnotations(app appv1.Application, revisionsMetadata *AppSyncRevisionsMetadata) appv1.Application {
if revisionsMetadata == nil {
return app
}

if app.ObjectMeta.Annotations == nil {
app.ObjectMeta.Annotations = map[string]string{}
}

jsonRevisionsMetadata, err := json.Marshal(revisionsMetadata)

if err != nil {
return app
}

app.ObjectMeta.Annotations[annotationRevisionKey] = string(jsonRevisionsMetadata)

return app
}

func AddCommitsDetailsToAppLabels(app *appv1.Application, revisionMetadata *appv1.RevisionMetadata) *appv1.Application {
if revisionMetadata == nil {
return app
}

if app.ObjectMeta.Labels == nil {
app.ObjectMeta.Labels = map[string]string{}
}

app.ObjectMeta.Labels["app.meta.commit-date"] = revisionMetadata.Date.Format("2006-01-02T15:04:05.000Z")
app.ObjectMeta.Labels["app.meta.commit-author"] = revisionMetadata.Author
app.ObjectMeta.Labels["app.meta.commit-message"] = revisionMetadata.Message

return app
}
16 changes: 16 additions & 0 deletions pkg/apis/application/v1alpha1/types_codefresh.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,19 @@ func (a *Application) SetDefaultTypeMeta() {
APIVersion: SchemeGroupVersion.String(),
}
}

func (a *ApplicationSpec) GetNonRefSource() (*ApplicationSource, int) {
if a.HasMultipleSources() {
for idx, source := range a.Sources {
if !source.IsRef() {
return &source, idx
}
}
}

if a.Source != nil { // single source app
return a.Source, -1
}

return nil, -2
}
1 change: 1 addition & 0 deletions pkg/codefresh/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type GraphQLQuery struct {
}

func (c *CodefreshClient) SendEvent(ctx context.Context, appName string, event *events.Event) error {
return nil
return WithRetry(&DefaultBackoff, func() error {
url, err := url.JoinPath(c.cfConfig.BaseURL, "/2.0/api/events")
if err != nil {
Expand Down

0 comments on commit 0b50690

Please sign in to comment.