@@ -95,17 +95,72 @@ func (f *Function) RunFunction(ctx context.Context, req *fnv1.RunFunctionRequest
9595 return rsp , nil
9696 }
9797
98- results , err := f .azureQuery .azQuery (ctx , azureCreds , in )
99- if err != nil {
100- response .Fatal (rsp , err )
101- f .log .Info ("FAILURE: " , "failure" , fmt .Sprint (err ))
98+ // Check if target already has data before executing the query
99+ var shouldExecuteQuery = true
100+
101+ switch {
102+ case strings .HasPrefix (in .Target , "status." ):
103+ // Check if the target field in status already exists
104+ oxr , err := request .GetObservedCompositeResource (req )
105+ if err != nil {
106+ response .Fatal (rsp , errors .Wrap (err , "cannot get observed composite resource" ))
107+ return rsp , nil
108+ }
109+
110+ xrStatus := make (map [string ]interface {})
111+ err = oxr .Resource .GetValueInto ("status" , & xrStatus )
112+ if err == nil {
113+ // Check if the target field already has data
114+ statusField := strings .TrimPrefix (in .Target , "status." )
115+ if hasData , _ := targetHasData (xrStatus , statusField ); hasData {
116+ f .log .Info ("Target already has data, skipping query" , "target" , in .Target )
117+
118+ // Set success condition and return
119+ response .ConditionTrue (rsp , "FunctionSuccess" , "SkippedQuery" ).
120+ WithMessage ("Target already has data, skipped query to avoid throttling" ).
121+ TargetCompositeAndClaim ()
122+ return rsp , nil
123+ }
124+ }
125+ case strings .HasPrefix (in .Target , "context." ):
126+ // Check if the target field in context already exists
127+ contextMap := req .GetContext ().AsMap ()
128+ contextField := strings .TrimPrefix (in .Target , "context." )
129+ if hasData , _ := targetHasData (contextMap , contextField ); hasData {
130+ f .log .Info ("Target already has data, skipping query" , "target" , in .Target )
131+
132+ // Set success condition and return
133+ response .ConditionTrue (rsp , "FunctionSuccess" , "SkippedQuery" ).
134+ WithMessage ("Target already has data, skipped query to avoid throttling" ).
135+ TargetCompositeAndClaim ()
136+ return rsp , nil
137+ }
138+ default :
139+ response .Fatal (rsp , errors .Errorf ("Unrecognized target field: %s" , in .Target ))
102140 return rsp , nil
103141 }
104- // Print the obtained query results
105- f .log .Info ("Query:" , "query" , in .Query )
106- f .log .Info ("Results:" , "results" , fmt .Sprint (results .Data ))
107- response .Normalf (rsp , "Query: %q" , in .Query )
108142
143+ // Only execute the query if necessary
144+ var results armresourcegraph.ClientResourcesResponse
145+ if shouldExecuteQuery {
146+ var err error
147+ results , err = f .azureQuery .azQuery (ctx , azureCreds , in )
148+ if err != nil {
149+ response .Fatal (rsp , err )
150+ f .log .Info ("FAILURE: " , "failure" , fmt .Sprint (err ))
151+ return rsp , nil
152+ }
153+ // Print the obtained query results
154+ f .log .Info ("Query:" , "query" , in .Query )
155+ f .log .Info ("Results:" , "results" , fmt .Sprint (results .Data ))
156+ response .Normalf (rsp , "Query: %q" , in .Query )
157+ } else {
158+ // We should never reach here due to early returns above, but just in case
159+ response .Normalf (rsp , "Skipped query: %q" , in .Query )
160+ return rsp , nil
161+ }
162+
163+ // Now check if the target is valid and write to the target
109164 switch {
110165 case strings .HasPrefix (in .Target , "status." ):
111166 err = putQueryResultToStatus (req , rsp , in , results , f )
@@ -370,3 +425,52 @@ func putQueryResultToContext(req *fnv1.RunFunctionRequest, rsp *fnv1.RunFunction
370425 rsp .Context = updatedContext
371426 return nil
372427}
428+
429+ // targetHasData checks if a target field already has data
430+ func targetHasData (data map [string ]interface {}, key string ) (bool , error ) {
431+ parts , err := ParseNestedKey (key )
432+ if err != nil {
433+ return false , err
434+ }
435+
436+ currentValue := interface {}(data )
437+ for _ , k := range parts {
438+ // Check if the current value is a map
439+ if nestedMap , ok := currentValue .(map [string ]interface {}); ok {
440+ // Get the next value in the nested map
441+ if nextValue , exists := nestedMap [k ]; exists {
442+ currentValue = nextValue
443+ } else {
444+ // Key doesn't exist, so no data
445+ return false , nil
446+ }
447+ } else {
448+ // Not a map, so can't traverse further
449+ return false , nil
450+ }
451+ }
452+
453+ // If we've reached here, the key exists
454+ // Check if it has meaningful data (not nil and not empty)
455+ if currentValue == nil {
456+ return false , nil
457+ }
458+
459+ // Check for empty maps
460+ if nestedMap , ok := currentValue .(map [string ]interface {}); ok {
461+ return len (nestedMap ) > 0 , nil
462+ }
463+
464+ // Check for empty slices
465+ if slice , ok := currentValue .([]interface {}); ok {
466+ return len (slice ) > 0 , nil
467+ }
468+
469+ // For strings, check if empty
470+ if str , ok := currentValue .(string ); ok {
471+ return str != "" , nil
472+ }
473+
474+ // For other types (numbers, booleans), consider them as having data
475+ return true , nil
476+ }
0 commit comments