Skip to content

Commit 1a41ac5

Browse files
committed
Add function to check the status of the owner of an object
Function verifies: - Ready condition is True - observedGeneration matches generation
1 parent 6ba873b commit 1a41ac5

3 files changed

Lines changed: 605 additions & 0 deletions

File tree

modules/common/object/metadata.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)