@@ -40,6 +40,13 @@ func (f *Function) RunFunction(ctx context.Context, req *fnv1.RunFunctionRequest
4040
4141 rsp := response .To (req , response .DefaultTTL )
4242
43+ // Ensure oxr to dxr gets propagated and we keep status around
44+ if err := f .propagateDesiredXR (req , rsp ); err != nil {
45+ return rsp , nil //nolint:nilerr // errors are handled in rsp. We should not error main function and proceed with reconciliation
46+ }
47+ // Ensure the context is preserved
48+ f .preserveContext (req , rsp )
49+
4350 // Parse input and get credentials
4451 in , azureCreds , err := f .parseInputAndCredentials (req , rsp )
4552 if err != nil {
@@ -66,6 +73,9 @@ func (f *Function) RunFunction(ctx context.Context, req *fnv1.RunFunctionRequest
6673
6774 // Check if we should skip the query
6875 if f .shouldSkipQuery (req , in , rsp ) {
76+ // Set success condition
77+ response .ConditionTrue (rsp , "FunctionSuccess" , "Success" ).
78+ TargetCompositeAndClaim ()
6979 return rsp , nil
7080 }
7181
@@ -174,9 +184,11 @@ func (f *Function) checkStatusTargetHasData(req *fnv1.RunFunctionRequest, in *v1
174184
175185 xrStatus := make (map [string ]interface {})
176186 err = oxr .Resource .GetValueInto ("status" , & xrStatus )
187+
177188 if err == nil {
178189 // Check if the target field already has data
179190 statusField := strings .TrimPrefix (in .Target , "status." )
191+
180192 if hasData , _ := targetHasData (xrStatus , statusField ); hasData {
181193 f .log .Info ("Target already has data, skipping query" , "target" , in .Target )
182194
@@ -187,6 +199,8 @@ func (f *Function) checkStatusTargetHasData(req *fnv1.RunFunctionRequest, in *v1
187199 return true
188200 }
189201 }
202+
203+ // If we got here, either there was an error or the field doesn't have data
190204 return false
191205}
192206
@@ -531,3 +545,58 @@ func targetHasData(data map[string]interface{}, key string) (bool, error) {
531545 // For other types (numbers, booleans), consider them as having data
532546 return true , nil
533547}
548+
549+ // propagateDesiredXR ensures the desired XR is properly propagated without changing existing data
550+ func (f * Function ) propagateDesiredXR (req * fnv1.RunFunctionRequest , rsp * fnv1.RunFunctionResponse ) error {
551+ oxr , err := request .GetObservedCompositeResource (req )
552+ if err != nil {
553+ response .Fatal (rsp , errors .Wrap (err , "cannot get observed composite resource" ))
554+ return err
555+ }
556+
557+ // The composite resource desired by previous functions in the pipeline
558+ dxr , err := request .GetDesiredCompositeResource (req )
559+ if err != nil {
560+ response .Fatal (rsp , errors .Wrap (err , "cannot get desired composite resource" ))
561+ return err
562+ }
563+
564+ // If dxr is empty, initialize it from oxr
565+ if dxr .Resource .GetKind () == "" {
566+ f .log .Info ("Initializing Desired XR from Observed XR" )
567+ dxr .Resource .SetAPIVersion (oxr .Resource .GetAPIVersion ())
568+ dxr .Resource .SetKind (oxr .Resource .GetKind ())
569+ dxr .Resource .SetName (oxr .Resource .GetName ())
570+
571+ // Copy status from observed XR
572+ xrStatus := make (map [string ]interface {})
573+ err = oxr .Resource .GetValueInto ("status" , & xrStatus )
574+ if err == nil && len (xrStatus ) > 0 {
575+ f .log .Info ("Copying status from Observed XR to Desired XR" )
576+ if err := dxr .Resource .SetValue ("status" , xrStatus ); err != nil {
577+ f .log .Info ("Error setting status in Desired XR" , "error" , err )
578+ return err
579+ }
580+ }
581+ }
582+
583+ // Save the desired XR in the response
584+ if err := response .SetDesiredCompositeResource (rsp , dxr ); err != nil {
585+ response .Fatal (rsp , errors .Wrapf (err , "cannot set desired composite resource in %T" , rsp ))
586+ return err
587+ }
588+
589+ f .log .Info ("Successfully propagated Desired XR" )
590+ return nil
591+ }
592+
593+ // preserveContext ensures the context is preserved in the response
594+ func (f * Function ) preserveContext (req * fnv1.RunFunctionRequest , rsp * fnv1.RunFunctionResponse ) {
595+ // Get the existing context from the request
596+ existingContext := req .GetContext ()
597+ if existingContext != nil {
598+ // Copy the existing context to the response
599+ rsp .Context = existingContext
600+ f .log .Info ("Preserved existing context in response" )
601+ }
602+ }
0 commit comments