@@ -207,6 +207,7 @@ func Render(ctx context.Context, log logging.Logger, in Inputs) (Outputs, error)
207207 d := & fnv1.State {}
208208
209209 results := make ([]unstructured.Unstructured , 0 )
210+ conditions := make ([]xpv1.Condition , 0 )
210211
211212 // The Function context starts empty.
212213 fctx := & structpb.Struct {Fields : map [string ]* structpb.Value {}}
@@ -271,6 +272,26 @@ func Render(ctx context.Context, log logging.Logger, in Inputs) (Outputs, error)
271272 // We intentionally discard/ignore this after the last Function runs.
272273 fctx = rsp .GetContext ()
273274
275+ for _ , c := range rsp .GetConditions () {
276+ var status corev1.ConditionStatus
277+ switch c .GetStatus () {
278+ case fnv1 .Status_STATUS_CONDITION_TRUE :
279+ status = corev1 .ConditionTrue
280+ case fnv1 .Status_STATUS_CONDITION_FALSE :
281+ status = corev1 .ConditionFalse
282+ case fnv1 .Status_STATUS_CONDITION_UNKNOWN , fnv1 .Status_STATUS_CONDITION_UNSPECIFIED :
283+ status = corev1 .ConditionUnknown
284+ }
285+
286+ conditions = append (conditions , xpv1.Condition {
287+ Type : xpv1 .ConditionType (c .GetType ()),
288+ Status : status ,
289+ LastTransitionTime : conditionTime (),
290+ Reason : xpv1 .ConditionReason (c .GetReason ()),
291+ Message : c .GetMessage (),
292+ })
293+ }
294+
274295 // Results of fatal severity stop the Composition process.
275296 for _ , rs := range rsp .GetResults () {
276297 switch rs .GetSeverity () { //nolint:exhaustive // We intentionally have a broad default case.
@@ -335,11 +356,20 @@ func Render(ctx context.Context, log logging.Logger, in Inputs) (Outputs, error)
335356 if len (unready ) > 0 {
336357 xrCond = xpv1 .Creating ().WithMessage (fmt .Sprintf ("Unready resources: %s" , resource .StableNAndSomeMore (resource .DefaultFirstN , unready )))
337358 }
338- // lastTransitionTime would just be noise, but we can't drop it as it's a
339- // required field and null is not allowed, so we set a random time.
340- xrCond .LastTransitionTime = metav1 .NewTime (time .Date (2024 , time .January , 1 , 0 , 0 , 0 , 0 , time .UTC ))
359+ xrCond .LastTransitionTime = conditionTime ()
341360 xr .SetConditions (xrCond )
342361
362+ for _ , c := range conditions {
363+ if xpv1 .IsSystemConditionType (c .Type ) {
364+ // Do not let users update system conditions.
365+ continue
366+ }
367+ // update the XR with the current condition. If it targets the claim, we
368+ // could also set it on the claim here, but we don't support Claims in
369+ // render yet.
370+ xr .SetConditions (c )
371+ }
372+
343373 out := Outputs {CompositeResource : xr , ComposedResources : desired , Results : results }
344374 if fctx != nil {
345375 out .Context = & unstructured.Unstructured {Object : map [string ]any {
@@ -414,3 +444,9 @@ func (f *FilteringFetcher) Fetch(_ context.Context, rs *fnv1.ResourceSelector) (
414444
415445 return out , nil
416446}
447+
448+ func conditionTime () metav1.Time {
449+ // lastTransitionTime for conditions would just be noise, but we can't drop it
450+ // as it's a required field and null is not allowed, so we set a random time.
451+ return metav1 .NewTime (time .Date (2024 , time .January , 1 , 0 , 0 , 0 , 0 , time .UTC ))
452+ }
0 commit comments