@@ -15,6 +15,7 @@ import (
1515 batchv1 "k8s.io/api/batch/v1"
1616 corev1 "k8s.io/api/core/v1"
1717 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
18+ "k8s.io/apimachinery/pkg/runtime"
1819 "k8s.io/apimachinery/pkg/runtime/schema"
1920 kstatus "sigs.k8s.io/cli-utils/pkg/kstatus/status"
2021
@@ -43,6 +44,30 @@ func NewStatusAnalyzer(reconcilerName string) StatusAnalyzer {
4344
4445// Implement the StatusAnalyzer interface.
4546func (s * statusAnalyzer ) ComputeStatus (object * unstructured.Unstructured ) (Status , error ) {
47+ type ObjectCondition struct {
48+ Type string `json:"type"`
49+ Status corev1.ConditionStatus `json:"status"`
50+ ObservedGeneration * int64 `json:"observedGeneration"`
51+ }
52+ type ObjectStatus struct {
53+ ObservedGeneration * int64 `json:"observedGeneration"`
54+ Conditions []ObjectCondition
55+ }
56+ type Object struct {
57+ Status ObjectStatus `json:"status"`
58+ }
59+
60+ obj := & Object {}
61+ if err := runtime .DefaultUnstructuredConverter .FromUnstructured (object .Object , obj ); err != nil {
62+ return UnknownStatus , err
63+ }
64+ var readyCondition * ObjectCondition
65+ for i , condition := range obj .Status .Conditions {
66+ if condition .Type == conditionTypeReady {
67+ readyCondition = & obj .Status .Conditions [i ]
68+ }
69+ }
70+
4671 var extraConditions []string
4772
4873 // parse hints from annotations
@@ -60,50 +85,39 @@ func (s *statusAnalyzer) ComputeStatus(object *unstructured.Unstructured) (Statu
6085 }
6186 switch strcase .ToKebab (key ) {
6287 case types .StatusHintHasObservedGeneration :
63- // add an impossible status.observedGeneration if there is none, but the hint says there will be one
6488 if hasValue {
6589 return UnknownStatus , fmt .Errorf ("status hint %s does not take a value" , types .StatusHintHasObservedGeneration )
6690 }
67- _ , found , err := unstructured .NestedInt64 (object .Object , "status" , "observedGeneration" )
68- if err != nil {
69- return UnknownStatus , err
70- }
71- if ! found {
72- if err := unstructured .SetNestedField (object .Object , int64 (- 1 ), "status" , "observedGeneration" ); err != nil {
73- return UnknownStatus , err
91+ if obj .Status .ObservedGeneration == nil {
92+ if readyCondition != nil && readyCondition .ObservedGeneration != nil {
93+ // add the ready condition's observed generation (if present) as observed generation if there is none, but the hint says there will be one
94+ if err := unstructured .SetNestedField (object .Object , * readyCondition .ObservedGeneration , "status" , "observedGeneration" ); err != nil {
95+ return UnknownStatus , err
96+ }
97+ } else {
98+ // otherwise add an impossible observed generation if there is none, but the hint says there will be one
99+ if err := unstructured .SetNestedField (object .Object , int64 (- 1 ), "status" , "observedGeneration" ); err != nil {
100+ return UnknownStatus , err
101+ }
74102 }
75103 }
76104 case types .StatusHintHasReadyCondition :
77- // add an Unknown Ready condition if there is none, but the hint says there will be one
78105 if hasValue {
79106 return UnknownStatus , fmt .Errorf ("status hint %s does not take a value" , types .StatusHintHasReadyCondition )
80107 }
81- foundReadyCondition := false
82- conditions , found , err := unstructured .NestedSlice (object .Object , "status" , "conditions" )
83- if err != nil {
84- return UnknownStatus , err
85- }
86- if ! found {
87- conditions = make ([]any , 0 )
88- }
89- for _ , condition := range conditions {
90- if condition , ok := condition .(map [string ]any ); ok {
91- condType , found , err := unstructured .NestedString (condition , "type" )
92- if err != nil {
93- return UnknownStatus , err
94- }
95- if found && condType == conditionTypeReady {
96- foundReadyCondition = true
97- break
98- }
108+ if readyCondition == nil {
109+ // add a ready condition with status 'Unknown' if there is none, but the hint says there will be one
110+ conditions , _ , err := unstructured .NestedSlice (object .Object , "status" , "conditions" )
111+ if err != nil {
112+ // TODO: this error should never occur because it was verified above that status.conditions has the right type
113+ return UnknownStatus , err
99114 }
100- }
101- if ! foundReadyCondition {
102115 conditions = append (conditions , map [string ]any {
103116 "type" : conditionTypeReady ,
104117 "status" : string (corev1 .ConditionUnknown ),
105118 })
106119 if err := unstructured .SetNestedSlice (object .Object , conditions , "status" , "conditions" ); err != nil {
120+ // TODO: this error should never occur because it was verified above that status.conditions can be digged
107121 return UnknownStatus , err
108122 }
109123 }
@@ -135,13 +149,9 @@ func (s *statusAnalyzer) ComputeStatus(object *unstructured.Unstructured) (Statu
135149
136150 // check extra conditions
137151 if status == CurrentStatus && len (extraConditions ) > 0 {
138- objc , err := kstatus .GetObjectWithConditions (object .UnstructuredContent ())
139- if err != nil {
140- return UnknownStatus , err
141- }
142152 for _ , condition := range extraConditions {
143153 found := false
144- for _ , cond := range objc .Status .Conditions {
154+ for _ , cond := range obj .Status .Conditions {
145155 if cond .Type == condition {
146156 found = true
147157 if cond .Status != corev1 .ConditionTrue {
@@ -161,11 +171,7 @@ func (s *statusAnalyzer) ComputeStatus(object *unstructured.Unstructured) (Statu
161171 // other than kstatus we want to consider jobs as InProgress if its pods are still running, resp. did not (yet) finish successfully
162172 if status == CurrentStatus {
163173 done := false
164- objc , err := kstatus .GetObjectWithConditions (object .UnstructuredContent ())
165- if err != nil {
166- return UnknownStatus , err
167- }
168- for _ , cond := range objc .Status .Conditions {
174+ for _ , cond := range obj .Status .Conditions {
169175 if cond .Type == string (batchv1 .JobComplete ) && cond .Status == corev1 .ConditionTrue {
170176 done = true
171177 break
0 commit comments