Skip to content

Commit 20217b4

Browse files
Todd Ritchiewaciumawanjohi
andcommitted
[#1315] Fix for workload prematurely being declared unhealthy
Co-authored-by: Waciuma Wanjohi <lwanjohi@vmware.com>
1 parent 0413778 commit 20217b4

File tree

2 files changed

+85
-5
lines changed

2 files changed

+85
-5
lines changed

pkg/realizer/component.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,15 @@ func (r *resourceRealizer) doImmutable(ctx context.Context, resource OwnerResour
209209
if latestSuccessfulObject == nil {
210210
for _, obj := range allRunnableStampedObjects {
211211
log.V(logger.DEBUG).Info("failed to retrieve output from any object", "considered", obj)
212+
213+
// terminate without error early if an Unknown health is discovered as it may become healthy later
214+
if healthcheck.DetermineStampedObjectHealth(healthRule, obj) == "Unknown" {
215+
log.V(logger.DEBUG).Info("immutable object still has unknown dependents, halting render")
216+
return template, stampedObject, nil, passThrough, templateName, nil
217+
}
212218
}
213219

220+
log.V(logger.DEBUG).Info("no objects are in an unknown state and none are healthy, cannot proceed")
214221
return template, stampedObject, nil, passThrough, templateName, errors.NoHealthyImmutableObjectsError{
215222
Err: fmt.Errorf("failed to find any healthy object in the set of immutable stamped objects"),
216223
ResourceName: resource.Name,

pkg/realizer/component_test.go

Lines changed: 78 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import (
4141
"github.com/vmware-tanzu/cartographer/pkg/repository"
4242
"github.com/vmware-tanzu/cartographer/pkg/repository/repositoryfakes"
4343
"github.com/vmware-tanzu/cartographer/pkg/templates"
44+
"github.com/vmware-tanzu/cartographer/tests/resources"
4445
)
4546

4647
var _ = Describe("Resource", func() {
@@ -271,13 +272,14 @@ var _ = Describe("Resource", func() {
271272
fakeOwnerRepo.ListUnstructuredReturns([]*unstructured.Unstructured{stampedObjectWithTime}, nil)
272273
})
273274

274-
When("no returned object meets the healthRule", func() {
275+
When("at least one returned object has unknown health", func() {
275276
BeforeEach(func() {
276277
templateAPI.Spec.TemplateSpec.HealthRule = &v1alpha1.HealthRule{
277278
SingleConditionType: "Ready",
278279
}
279280
})
280-
It("creates a stamped object, but returns an error and no output", func() {
281+
282+
It("does not error", func() {
281283
template, returnedStampedObject, out, isPassThrough, templateRefName, err := r.Do(ctx, resource, blueprintName, outputs, fakeMapper)
282284
Expect(template).ToNot(BeNil())
283285
Expect(isPassThrough).To(BeFalse())
@@ -308,9 +310,80 @@ var _ = Describe("Resource", func() {
308310
Expect(stampedObject.Object["data"]).To(Equal(map[string]interface{}{"player_current_lives": "some-url", "some_other_info": "some-revision"}))
309311
Expect(metadataValues["labels"]).To(Equal(map[string]interface{}{"expected-labels-from-labeler-placeholder": "labeler"}))
310312

311-
Expect(err).To(HaveOccurred())
312-
Expect(err.Error()).To(ContainSubstring("unable to retrieve outputs for resource [resource-1] in supply chain [supply-chain-name]: failed to find any healthy object in the set of immutable stamped objects"))
313-
Expect(reflect.TypeOf(err).String()).To(Equal("errors.NoHealthyImmutableObjectsError"))
313+
Expect(err).NotTo(HaveOccurred())
314+
})
315+
})
316+
317+
When("no returned object has unknown health", func() {
318+
When("no returned object meets the healthRule", func() {
319+
BeforeEach(func() {
320+
templateAPI.Spec.TemplateSpec.HealthRule = &v1alpha1.HealthRule{
321+
SingleConditionType: "Succeeded",
322+
}
323+
324+
status := resources.TestStatus{
325+
ObservedGeneration: 1,
326+
Conditions: []metav1.Condition{{
327+
Type: "Succeeded",
328+
Status: "False",
329+
LastTransitionTime: metav1.Now(),
330+
Reason: "",
331+
}},
332+
}
333+
334+
obj := unstructured.Unstructured{}
335+
err := json.Unmarshal(templateAPI.Spec.TemplateSpec.Template.Raw, &obj)
336+
Expect(err).NotTo(HaveOccurred())
337+
338+
// easiest way to stitch the status into the unstructured.unstructured is to
339+
// marshal and unmarshal so it's in the same state as the stamped object in the mock
340+
statusObj, _ := json.Marshal(status)
341+
var statusUnstructured map[string]interface{}
342+
err = json.Unmarshal(statusObj, &statusUnstructured)
343+
Expect(err).NotTo(HaveOccurred())
344+
345+
obj.SetUnstructuredContent(map[string]interface{}{
346+
"status": statusUnstructured,
347+
})
348+
349+
fakeOwnerRepo.ListUnstructuredReturns([]*unstructured.Unstructured{&obj}, nil)
350+
})
351+
352+
It("creates a stamped object, but returns an error and no output", func() {
353+
template, _, out, isPassThrough, templateRefName, err := r.Do(ctx, resource, blueprintName, outputs, fakeMapper)
354+
Expect(template).ToNot(BeNil())
355+
Expect(isPassThrough).To(BeFalse())
356+
Expect(templateRefName).To(Equal("image-template-1"))
357+
//Expect(returnedStampedObject.Object).To(Equal(expectedObject.Object))
358+
Expect(out).To(BeNil())
359+
360+
Expect(fakeOwnerRepo.EnsureImmutableObjectExistsOnClusterCallCount()).To(Equal(1))
361+
362+
_, stampedObject, _ := fakeOwnerRepo.EnsureImmutableObjectExistsOnClusterArgsForCall(0)
363+
364+
//Expect(returnedStampedObject).To(Equal(stampedObject))
365+
366+
metadata := stampedObject.Object["metadata"]
367+
metadataValues, ok := metadata.(map[string]interface{})
368+
Expect(ok).To(BeTrue())
369+
Expect(metadataValues["name"]).To(Equal("example-config-map"))
370+
Expect(metadataValues["ownerReferences"]).To(Equal([]interface{}{
371+
map[string]interface{}{
372+
"apiVersion": "",
373+
"kind": "",
374+
"name": "",
375+
"uid": "",
376+
"controller": true,
377+
"blockOwnerDeletion": true,
378+
},
379+
}))
380+
Expect(stampedObject.Object["data"]).To(Equal(map[string]interface{}{"player_current_lives": "some-url", "some_other_info": "some-revision"}))
381+
Expect(metadataValues["labels"]).To(Equal(map[string]interface{}{"expected-labels-from-labeler-placeholder": "labeler"}))
382+
383+
Expect(err).To(HaveOccurred())
384+
Expect(err.Error()).To(ContainSubstring("unable to retrieve outputs for resource [resource-1] in supply chain [supply-chain-name]: failed to find any healthy object in the set of immutable stamped objects"))
385+
Expect(reflect.TypeOf(err).String()).To(Equal("errors.NoHealthyImmutableObjectsError"))
386+
})
314387
})
315388
})
316389

0 commit comments

Comments
 (0)