@@ -31,6 +31,8 @@ import (
3131
3232 k8s_errors "k8s.io/apimachinery/pkg/api/errors"
3333 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
34+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
35+ "k8s.io/apimachinery/pkg/runtime/schema"
3436)
3537
3638// CheckOwnerRefExist - returns true if the owner is already in the owner ref list
@@ -114,3 +116,112 @@ func EnsureOwnerRef(
114116
115117 return nil
116118}
119+
120+ // IsOwnerServiceReady checks if the owner service that owns this object is ready.
121+ // Returns true if the owner is ready, false if not ready, and error only for unexpected failures.
122+ // If there's no owner with controller=true, it returns true (safe to proceed).
123+ func IsOwnerServiceReady (
124+ ctx context.Context ,
125+ h * helper.Helper ,
126+ obj client.Object ,
127+ ) (bool , error ) {
128+ // Find the controller owner reference (e.g., Cinder, Nova, etc.)
129+ var ownerRef * metav1.OwnerReference
130+ for _ , owner := range obj .GetOwnerReferences () {
131+ if owner .Controller != nil && * owner .Controller {
132+ ownerRef = & owner
133+ break
134+ }
135+ }
136+
137+ // If no controlling owner, safe to proceed
138+ if ownerRef == nil {
139+ h .GetLogger ().Info ("No controller owner found, owner is considered ready" )
140+ return true , nil
141+ }
142+
143+ // Parse the APIVersion to extract group and version
144+ gv , err := schema .ParseGroupVersion (ownerRef .APIVersion )
145+ if err != nil {
146+ h .GetLogger ().Error (err , "Failed to parse owner APIVersion" , "apiVersion" , ownerRef .APIVersion )
147+ return false , err
148+ }
149+
150+ // Fetch the owner resource using unstructured client
151+ owner := & unstructured.Unstructured {}
152+ owner .SetGroupVersionKind (schema.GroupVersionKind {
153+ Group : gv .Group ,
154+ Version : gv .Version ,
155+ Kind : ownerRef .Kind ,
156+ })
157+
158+ err = h .GetClient ().Get (ctx , types.NamespacedName {
159+ Name : ownerRef .Name ,
160+ Namespace : obj .GetNamespace (),
161+ }, owner )
162+
163+ if err != nil {
164+ if k8s_errors .IsNotFound (err ) {
165+ // Owner deleted, safe to proceed
166+ h .GetLogger ().Info ("Owner resource not found, owner is considered ready" , "kind" , ownerRef .Kind , "name" , ownerRef .Name )
167+ return true , nil
168+ }
169+ // Unexpected error, log and return error
170+ h .GetLogger ().Error (err , "Failed to fetch owner resource" , "kind" , ownerRef .Kind , "name" , ownerRef .Name )
171+ return false , err
172+ }
173+
174+ // Check status.conditions for Ready condition
175+ conditions , found , err := unstructured .NestedSlice (owner .Object , "status" , "conditions" )
176+ if err != nil || ! found {
177+ h .GetLogger ().Info ("No conditions found in owner status, waiting" , "kind" , ownerRef .Kind , "name" , ownerRef .Name )
178+ return false , nil
179+ }
180+
181+ // Look for Ready condition with status=True
182+ isReady := false
183+ for _ , c := range conditions {
184+ condition , ok := c .(map [string ]any )
185+ if ! ok {
186+ continue
187+ }
188+
189+ condType , _ , _ := unstructured .NestedString (condition , "type" )
190+ status , _ , _ := unstructured .NestedString (condition , "status" )
191+
192+ if condType == "Ready" && status == "True" {
193+ isReady = true
194+ break
195+ }
196+ }
197+
198+ if ! isReady {
199+ h .GetLogger ().Info ("Owner service not ready, waiting" , "kind" , ownerRef .Kind , "name" , ownerRef .Name )
200+ return false , nil
201+ }
202+
203+ // Check if owner has reconciled (observedGeneration matches generation)
204+ generation , foundGen , err := unstructured .NestedInt64 (owner .Object , "metadata" , "generation" )
205+ if err != nil || ! foundGen {
206+ h .GetLogger ().Info ("Could not get owner generation, waiting" , "kind" , ownerRef .Kind , "name" , ownerRef .Name )
207+ return false , nil
208+ }
209+
210+ observedGeneration , foundObsGen , err := unstructured .NestedInt64 (owner .Object , "status" , "observedGeneration" )
211+ if err != nil || ! foundObsGen {
212+ h .GetLogger ().Info ("Could not get owner observedGeneration, waiting" , "kind" , ownerRef .Kind , "name" , ownerRef .Name )
213+ return false , nil
214+ }
215+
216+ if observedGeneration != generation {
217+ h .GetLogger ().Info ("Owner service has not reconciled yet (observedGeneration != generation), waiting" ,
218+ "kind" , ownerRef .Kind ,
219+ "name" , ownerRef .Name ,
220+ "generation" , generation ,
221+ "observedGeneration" , observedGeneration )
222+ return false , nil
223+ }
224+
225+ h .GetLogger ().Info ("Owner service is ready and has reconciled, safe to proceed" , "kind" , ownerRef .Kind , "name" , ownerRef .Name )
226+ return true , nil
227+ }
0 commit comments