knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/reconciler/reconcile_common.go (about) 1 /* 2 Copyright 2020 The Knative Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 https://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package reconciler 18 19 import ( 20 "context" 21 "reflect" 22 "time" 23 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 26 "knative.dev/pkg/apis" 27 duckv1 "knative.dev/pkg/apis/duck/v1" 28 "knative.dev/pkg/logging" 29 ) 30 31 const failedGenerationBump = "NewObservedGenFailure" 32 33 // DefaultTimeout is used in some downstream reconcilers to put a context 34 // deadline on reconciliation. It is a variable so that it can be exposed by 35 // entrypoints as a flag, e.g. via flag.DurationVar 36 var DefaultTimeout = 30 * time.Second 37 38 const ( 39 // DoReconcileKind is the function name for reconciling the resource (as a leader). 40 DoReconcileKind = "ReconcileKind" 41 // DoFinalizeKind is the function name for finalizing the resource (as a leader). 42 DoFinalizeKind = "FinalizeKind" 43 // DoObserveKind is the function name for observing the resource (as a non leader). 44 DoObserveKind = "ObserveKind" 45 // DoObserveFinalizeKind is the function name for observing finalization of the resource (as a non leader). 46 // 47 // Deprecated: This will be deleted soon. 48 DoObserveFinalizeKind = "ObserveFinalizeKind" 49 ) 50 51 // PreProcessReconcile contains logic to apply before reconciliation of a resource. 52 func PreProcessReconcile(ctx context.Context, resource duckv1.KRShaped) { 53 newStatus := resource.GetStatus() 54 55 // We may be reading a version of the object that was stored at an older version 56 // and may not have had all of the assumed defaults specified. This won't result 57 // in this getting written back to the API Server, but lets downstream logic make 58 // assumptions about defaulting. 59 if d, ok := resource.(apis.Defaultable); ok { 60 d.SetDefaults(ctx) 61 } 62 63 // Ensure conditions are initialized before we modify. 64 condSet := resource.GetConditionSet() 65 manager := condSet.Manage(newStatus) 66 manager.InitializeConditions() 67 68 if newStatus.ObservedGeneration != resource.GetGeneration() { 69 // Reset Ready/Successful to unknown. The reconciler is expected to overwrite this. 70 manager.MarkUnknown(condSet.GetTopLevelConditionType(), failedGenerationBump, "unsuccessfully observed a new generation") 71 } 72 } 73 74 // PostProcessReconcile contains logic to apply after reconciliation of a resource. 75 func PostProcessReconcile(ctx context.Context, resource, oldResource duckv1.KRShaped) { 76 logger := logging.FromContext(ctx) 77 status := resource.GetStatus() 78 mgr := resource.GetConditionSet().Manage(status) 79 80 // Bump observed generation to denote that we have processed this 81 // generation regardless of success or failure. 82 status.ObservedGeneration = resource.GetGeneration() 83 84 if rc := mgr.GetTopLevelCondition(); rc == nil { 85 logger.Warn("A reconciliation included no top-level condition") 86 } else if rc.Reason == failedGenerationBump { 87 logger.Warn("A reconciler observed a new generation without updating the resource status") 88 } 89 90 groomConditionsTransitionTime(resource, oldResource) 91 } 92 93 // groomConditionsTransitionTime ensures that the LastTransitionTime only advances for resources 94 // where the condition has changed during reconciliation. This also ensures that all advanced 95 // conditions share the same timestamp. 96 func groomConditionsTransitionTime(resource, oldResource duckv1.KRShaped) { 97 now := apis.VolatileTime{Inner: metav1.NewTime(time.Now())} 98 sts := resource.GetStatus() 99 for i := range sts.Conditions { 100 cond := &sts.Conditions[i] 101 102 if oldCond := oldResource.GetStatus().GetCondition(cond.Type); oldCond != nil { 103 cond.LastTransitionTime = oldCond.LastTransitionTime 104 if reflect.DeepEqual(cond, oldCond) { 105 continue 106 } 107 } 108 109 cond.LastTransitionTime = now 110 } 111 }