77 "reflect"
88 "strings"
99
10+ "github.com/argoproj/argo-cd/v2/common"
11+
1012 "github.com/argoproj/gitops-engine/pkg/health"
1113 "github.com/argoproj/gitops-engine/pkg/utils/kube"
1214 "github.com/argoproj/gitops-engine/pkg/utils/text"
@@ -18,7 +20,6 @@ import (
1820 "github.com/argoproj/argo-cd/v2/pkg/apiclient/application"
1921 "github.com/argoproj/argo-cd/v2/pkg/apiclient/events"
2022 appv1reg "github.com/argoproj/argo-cd/v2/pkg/apis/application"
21- "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
2223 appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
2324 "github.com/argoproj/argo-cd/v2/reposerver/apiclient"
2425)
@@ -55,27 +56,64 @@ func (s *applicationEventReporter) shouldSendResourceEvent(a *appv1.Application,
5556 return true
5657}
5758
59+ func isChildApp (a * appv1.Application ) bool {
60+ if a .Labels != nil {
61+ return a .Labels [common .LabelKeyAppInstance ] != ""
62+ }
63+ return false
64+ }
65+
66+ func getAppAsResource (a * appv1.Application ) * appv1.ResourceStatus {
67+ return & appv1.ResourceStatus {
68+ Name : a .Name ,
69+ Namespace : a .Namespace ,
70+ Version : "v1alpha1" ,
71+ Kind : "Application" ,
72+ Group : "argoproj.io" ,
73+ Status : a .Status .Sync .Status ,
74+ Health : & a .Status .Health ,
75+ }
76+ }
77+
78+ func (s * applicationEventReporter ) getDesiredManifests (ctx context.Context , a * appv1.Application , logCtx * log.Entry ) (* apiclient.ManifestResponse , error , bool ) {
79+ // get the desired state manifests of the application
80+ desiredManifests , err := s .server .GetManifests (ctx , & application.ApplicationManifestQuery {
81+ Name : & a .Name ,
82+ Revision : a .Status .Sync .Revision ,
83+ })
84+ if err != nil {
85+ if ! strings .Contains (err .Error (), "Manifest generation error" ) {
86+ return nil , fmt .Errorf ("failed to get application desired state manifests: %w" , err ), false
87+ }
88+ // if it's manifest generation error we need to still report the actual state
89+ // of the resources, but since we can't get the desired state, we will report
90+ // each resource with empty desired state
91+ logCtx .WithError (err ).Warn ("failed to get application desired state manifests, reporting actual state only" )
92+ desiredManifests = & apiclient.ManifestResponse {Manifests : []* apiclient.Manifest {}}
93+ return desiredManifests , nil , true // will ignore requiresPruning=true to not delete resources with actual state
94+ }
95+ return desiredManifests , nil , false
96+ }
97+
5898func (s * applicationEventReporter ) streamApplicationEvents (
5999 ctx context.Context ,
60100 a * appv1.Application ,
61101 es * events.EventSource ,
62102 stream events.Eventing_StartEventSourceServer ,
63103 ts string ,
64- processRootApp bool ,
65104) error {
66105 var (
67- logCtx = log .WithField ("application" , a .Name )
68- manifestGenErr bool
106+ logCtx = log .WithField ("application" , a .Name )
69107 )
70108
71109 logCtx .Info ("streaming application events" )
72110
73- isChildApp := false
74- if a . Labels != nil {
75- isChildApp = a . Labels [ "app.kubernetes.io/instance" ] != ""
111+ appTree , err := s . server . getAppResources ( ctx , a )
112+ if err != nil {
113+ return fmt . Errorf ( "failed to get application resources tree: %w" , err )
76114 }
77115
78- if ! isChildApp || processRootApp {
116+ if ! isChildApp ( a ) {
79117 // application events for child apps would be sent by its parent app
80118 // as resource event
81119 appEvent , err := s .getApplicationEventPayload (ctx , a , es , ts )
@@ -92,106 +130,113 @@ func (s *applicationEventReporter) streamApplicationEvents(
92130 if err := stream .Send (appEvent ); err != nil {
93131 return fmt .Errorf ("failed to send event for resource %s/%s: %w" , a .Namespace , a .Name , err )
94132 }
95- }
133+ } else {
134+ parentApp := a .Labels [common .LabelKeyAppInstance ]
96135
97- // get the desired state manifests of the application
98- desiredManifests , err := s .server .GetManifests (ctx , & application.ApplicationManifestQuery {
99- Name : & a .Name ,
100- Revision : a .Status .Sync .Revision ,
101- })
102- if err != nil {
103- if ! strings .Contains (err .Error (), "Manifest generation error" ) {
104- return fmt .Errorf ("failed to get application desired state manifests: %w" , err )
136+ parentApplicationEntity , err := s .server .Get (ctx , & application.ApplicationQuery {
137+ Name : & parentApp ,
138+ })
139+ if err != nil {
140+ return fmt .Errorf ("failed to get application event: %w" , err )
105141 }
106- // if it's manifest generation error we need to still report the actual state
107- // of the resources, but since we can't get the desired state, we will report
108- // each resource with empty desired state
109- logCtx .WithError (err ).Warn ("failed to get application desired state manifests, reporting actual state only" )
110- desiredManifests = & apiclient.ManifestResponse {Manifests : []* apiclient.Manifest {}}
111- manifestGenErr = true // will ignore requiresPruning=true to not delete resources with actual state
142+
143+ rs := getAppAsResource (a )
144+
145+ desiredManifests , err , manifestGenErr := s .getDesiredManifests (ctx , parentApplicationEntity , logCtx )
146+ if err != nil {
147+ return err
148+ }
149+
150+ s .processResource (ctx , * rs , parentApplicationEntity , logCtx , ts , desiredManifests , stream , appTree , es , manifestGenErr )
112151 }
113152
114- appTree , err := s .server . getAppResources (ctx , a )
153+ desiredManifests , err , manifestGenErr := s .getDesiredManifests (ctx , a , logCtx )
115154 if err != nil {
116- return fmt . Errorf ( "failed to get application resources tree: %w" , err )
155+ return err
117156 }
118157
119158 // for each resource in the application get desired and actual state,
120159 // then stream the event
121160 for _ , rs := range a .Status .Resources {
122- logCtx = logCtx .WithFields (log.Fields {
123- "gvk" : fmt .Sprintf ("%s/%s/%s" , rs .Group , rs .Version , rs .Kind ),
124- "resource" : fmt .Sprintf ("%s/%s" , rs .Namespace , rs .Name ),
125- })
126-
127- if ! s .shouldSendResourceEvent (a , rs ) {
161+ if isApp (rs ) {
128162 continue
129163 }
164+ s .processResource (ctx , rs , a , logCtx , ts , desiredManifests , stream , appTree , es , manifestGenErr )
165+ }
130166
131- // get resource desired state
132- desiredState := getResourceDesiredState (& rs , desiredManifests , logCtx )
133-
134- // get resource actual state
135- actualState , err := s .server .GetResource (ctx , & application.ApplicationResourceRequest {
136- Name : & a .Name ,
137- Namespace : rs .Namespace ,
138- ResourceName : rs .Name ,
139- Version : rs .Version ,
140- Group : rs .Group ,
141- Kind : rs .Kind ,
142- })
143- if err != nil {
144- if ! strings .Contains (err .Error (), "not found" ) {
145- logCtx .WithError (err ).Error ("failed to get actual state" )
146- continue
147- }
167+ return nil
168+ }
148169
149- // empty actual state
150- actualState = & application.ApplicationResourceResponse {Manifest : "" }
151- }
170+ func (s * applicationEventReporter ) processResource (ctx context.Context , rs appv1.ResourceStatus , a * appv1.Application , logCtx * log.Entry , ts string , desiredManifests * apiclient.ManifestResponse , stream events.Eventing_StartEventSourceServer , appTree * appv1.ApplicationTree , es * events.EventSource , manifestGenErr bool ) {
171+ logCtx = logCtx .WithFields (log.Fields {
172+ "gvk" : fmt .Sprintf ("%s/%s/%s" , rs .Group , rs .Version , rs .Kind ),
173+ "resource" : fmt .Sprintf ("%s/%s" , rs .Namespace , rs .Name ),
174+ })
152175
153- var mr * apiclient.ManifestResponse = desiredManifests
154- if isApp (rs ) {
155- app := & v1alpha1.Application {}
156- if err := json .Unmarshal ([]byte (actualState .Manifest ), app ); err != nil {
157- logWithAppStatus (a , logCtx , ts ).WithError (err ).Error ("failed to unmarshal child application resource" )
158- }
159- resourceDesiredManifests , err := s .server .GetManifests (ctx , & application.ApplicationManifestQuery {
160- Name : & rs .Name ,
161- Revision : app .Status .Sync .Revision ,
162- })
163- if err != nil {
164- logWithAppStatus (a , logCtx , ts ).WithError (err ).Error ("failed to get resource desired manifest" )
165- } else {
166- mr = resourceDesiredManifests
167- }
168- }
176+ if ! s .shouldSendResourceEvent (a , rs ) {
177+ return
178+ }
169179
170- ev , err := getResourceEventPayload (a , & rs , es , actualState , desiredState , mr , appTree , manifestGenErr , ts )
171- if err != nil {
172- logCtx .WithError (err ).Error ("failed to get event payload" )
173- continue
180+ // get resource desired state
181+ desiredState := getResourceDesiredState (& rs , desiredManifests , logCtx )
182+
183+ // get resource actual state
184+ actualState , err := s .server .GetResource (ctx , & application.ApplicationResourceRequest {
185+ Name : & a .Name ,
186+ Namespace : rs .Namespace ,
187+ ResourceName : rs .Name ,
188+ Version : rs .Version ,
189+ Group : rs .Group ,
190+ Kind : rs .Kind ,
191+ })
192+ if err != nil {
193+ if ! strings .Contains (err .Error (), "not found" ) {
194+ logCtx .WithError (err ).Error ("failed to get actual state" )
195+ return
174196 }
175197
176- appRes := appv1.Application {}
177- if isApp (rs ) && actualState .Manifest != "" && json .Unmarshal ([]byte (actualState .Manifest ), & appRes ) == nil {
178- logWithAppStatus (& appRes , logCtx , ts ).Info ("streaming resource event" )
198+ // empty actual state
199+ actualState = & application.ApplicationResourceResponse {Manifest : "" }
200+ }
201+
202+ var mr * apiclient.ManifestResponse = desiredManifests
203+ if isApp (rs ) {
204+ app := & appv1.Application {}
205+ if err := json .Unmarshal ([]byte (actualState .Manifest ), app ); err != nil {
206+ logWithAppStatus (a , logCtx , ts ).WithError (err ).Error ("failed to unmarshal child application resource" )
207+ }
208+ resourceDesiredManifests , err := s .server .GetManifests (ctx , & application.ApplicationManifestQuery {
209+ Name : & rs .Name ,
210+ Revision : app .Status .Sync .Revision ,
211+ })
212+ if err != nil {
213+ logWithAppStatus (a , logCtx , ts ).WithError (err ).Error ("failed to get resource desired manifest" )
179214 } else {
180- logCtx . Info ( "streaming resource event" )
215+ mr = resourceDesiredManifests
181216 }
217+ }
182218
183- if err := stream .Send (ev ); err != nil {
184- logCtx .WithError (err ).Error ("failed to send even" )
185- continue
186- }
219+ ev , err := getResourceEventPayload (a , & rs , es , actualState , desiredState , mr , appTree , manifestGenErr , ts )
220+ if err != nil {
221+ logCtx .WithError (err ).Error ("failed to get event payload" )
222+ return
223+ }
187224
188- if err := s .server .cache .SetLastResourceEvent (a , rs , resourceEventCacheExpiration ); err != nil {
189- logCtx .WithError (err ).Error ("failed to cache resource event" )
190- continue
191- }
225+ appRes := appv1.Application {}
226+ if isApp (rs ) && actualState .Manifest != "" && json .Unmarshal ([]byte (actualState .Manifest ), & appRes ) == nil {
227+ logWithAppStatus (& appRes , logCtx , ts ).Info ("streaming resource event" )
228+ } else {
229+ logCtx .Info ("streaming resource event" )
192230 }
193231
194- return nil
232+ if err := stream .Send (ev ); err != nil {
233+ logCtx .WithError (err ).Error ("failed to send even" )
234+ return
235+ }
236+
237+ if err := s .server .cache .SetLastResourceEvent (a , rs , resourceEventCacheExpiration ); err != nil {
238+ logCtx .WithError (err ).Error ("failed to cache resource event" )
239+ }
195240}
196241
197242func (s * applicationEventReporter ) shouldSendApplicationEvent (ae * appv1.ApplicationWatchEvent ) bool {
0 commit comments