Skip to content

Commit 3a40b24

Browse files
MissingValueAtPathCondition message is conditioned on object health
1 parent 20217b4 commit 3a40b24

File tree

13 files changed

+521
-222
lines changed

13 files changed

+521
-222
lines changed

pkg/apis/v1alpha1/conditions.go

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -159,15 +159,14 @@ const (
159159
// -- RUNNABLE ConditionType - RunTemplateReady ConditionReasons
160160

161161
const (
162-
ReadyRunTemplateReason = "Ready"
163-
NotFoundRunTemplateReason = "RunTemplateNotFound"
164-
StampedObjectRejectedByAPIServerRunTemplateReason = "StampedObjectRejectedByAPIServer"
165-
OutputPathNotSatisfiedRunTemplateReason = "OutputPathNotSatisfied"
166-
TemplateStampFailureRunTemplateReason = "TemplateStampFailure"
167-
FailedToListCreatedObjectsReason = "FailedToListCreatedObjects"
168-
SetOfImmutableStampedObjectsIncludesNoHealthyObjectReason = "SetOfImmutableStampedObjectsIncludesNoHealthyObject"
169-
UnknownErrorReason = "UnknownError"
170-
ClientBuilderErrorResourcesSubmittedReason = "ClientBuilderError"
171-
SucceededStampedObjectConditionReason = "SucceededCondition"
172-
UnknownStampedObjectConditionReason = "Unknown"
162+
ReadyRunTemplateReason = "Ready"
163+
NotFoundRunTemplateReason = "RunTemplateNotFound"
164+
StampedObjectRejectedByAPIServerRunTemplateReason = "StampedObjectRejectedByAPIServer"
165+
OutputPathNotSatisfiedRunTemplateReason = "OutputPathNotSatisfied"
166+
TemplateStampFailureRunTemplateReason = "TemplateStampFailure"
167+
FailedToListCreatedObjectsReason = "FailedToListCreatedObjects"
168+
UnknownErrorReason = "UnknownError"
169+
ClientBuilderErrorResourcesSubmittedReason = "ClientBuilderError"
170+
SucceededStampedObjectConditionReason = "SucceededCondition"
171+
UnknownStampedObjectConditionReason = "Unknown"
173172
)

pkg/conditions/deliverable_conditions.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ func AddConditionForResourceSubmittedDeliverable(conditionManager *ConditionMana
120120
if typedErr.StampedObject == nil {
121121
(*conditionManager).AddPositive(MissingPassThroughInputCondition(typedErr.PassThroughInput, typedErr.GetQualifiedResource()))
122122
} else {
123-
(*conditionManager).AddPositive(MissingValueAtPathCondition(isOwner, typedErr.StampedObject, typedErr.JsonPathExpression(), typedErr.GetQualifiedResource()))
123+
(*conditionManager).AddPositive(MissingValueAtPathCondition(isOwner, typedErr.StampedObject, typedErr.JsonPathExpression(), typedErr.GetQualifiedResource(), typedErr.Healthy))
124124
}
125125
default:
126126
(*conditionManager).AddPositive(UnknownResourceErrorCondition(isOwner, typedErr))

pkg/conditions/owner_conditions.go

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,31 @@ func TemplateObjectRetrievalFailureCondition(isOwner bool, err error) metav1.Con
6161
}
6262
}
6363

64-
func MissingValueAtPathCondition(isOwner bool, obj *unstructured.Unstructured, expression string, qualifiedResource string) metav1.Condition {
64+
func MissingValueAtPathCondition(isOwner bool, obj *unstructured.Unstructured, expression string, qualifiedResource string, health metav1.ConditionStatus) metav1.Condition {
6565
var namespaceMsg string
6666
if obj.GetNamespace() != "" {
6767
namespaceMsg = fmt.Sprintf(" in namespace [%s]", obj.GetNamespace())
6868
}
69+
70+
var message string
71+
72+
switch health {
73+
case metav1.ConditionTrue:
74+
message = fmt.Sprintf("cannot read value [%s] from healthy object [%s/%s]%s, contact Platform Eng",
75+
expression, qualifiedResource, obj.GetName(), namespaceMsg)
76+
case metav1.ConditionFalse:
77+
message = fmt.Sprintf("cannot read value [%s] from unhealthy object [%s/%s]%s, examine object, particularly whether it is receiving proper inputs",
78+
expression, qualifiedResource, obj.GetName(), namespaceMsg)
79+
default:
80+
message = fmt.Sprintf("waiting to read value [%s] from object [%s/%s]%s",
81+
expression, qualifiedResource, obj.GetName(), namespaceMsg)
82+
}
83+
6984
return metav1.Condition{
70-
Type: getConditionType(isOwner),
71-
Status: metav1.ConditionUnknown,
72-
Reason: v1alpha1.MissingValueAtPathResourcesSubmittedReason,
73-
Message: fmt.Sprintf("waiting to read value [%s] from resource [%s/%s]%s",
74-
expression, qualifiedResource, obj.GetName(), namespaceMsg),
85+
Type: getConditionType(isOwner),
86+
Status: metav1.ConditionUnknown,
87+
Reason: v1alpha1.MissingValueAtPathResourcesSubmittedReason,
88+
Message: message,
7589
}
7690
}
7791

@@ -102,15 +116,6 @@ func BlueprintsFailedToListCreatedObjectsCondition(isOwner bool, err error) meta
102116
}
103117
}
104118

105-
func NoHealthyImmutableObjectsCondition(isOwner bool, err error) metav1.Condition {
106-
return metav1.Condition{
107-
Type: getConditionType(isOwner),
108-
Status: metav1.ConditionFalse,
109-
Reason: v1alpha1.SetOfImmutableStampedObjectsIncludesNoHealthyObjectReason,
110-
Message: err.Error(),
111-
}
112-
}
113-
114119
func UnknownResourceErrorCondition(isOwner bool, err error) metav1.Condition {
115120
return metav1.Condition{
116121
Type: getConditionType(isOwner),

pkg/conditions/owner_conditions_test.go

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package conditions_test
1717
import (
1818
. "github.com/onsi/ginkgo"
1919
. "github.com/onsi/gomega"
20+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2021
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2122
"k8s.io/apimachinery/pkg/runtime/schema"
2223

@@ -38,18 +39,49 @@ var _ = Describe("Conditions", func() {
3839
})
3940

4041
Context("stamped object has a namespace", func() {
41-
It("has the correct message", func() {
42+
var healthy metav1.ConditionStatus
43+
BeforeEach(func() {
4244
obj.SetNamespace("my-ns")
45+
})
46+
47+
Context("healthy is true", func() {
48+
BeforeEach(func() {
49+
healthy = metav1.ConditionTrue
50+
})
51+
52+
It("has the correct message", func() {
53+
condition := conditions.MissingValueAtPathCondition(true, obj, "spec.foo", "widget.thing.io", healthy)
54+
Expect(condition.Message).To(Equal("cannot read value [spec.foo] from healthy object [widget.thing.io/my-widget] in namespace [my-ns], contact Platform Eng"))
55+
})
56+
})
57+
58+
Context("healthy is false", func() {
59+
BeforeEach(func() {
60+
healthy = metav1.ConditionFalse
61+
})
62+
63+
It("has the correct message", func() {
64+
condition := conditions.MissingValueAtPathCondition(true, obj, "spec.foo", "widget.thing.io", healthy)
65+
Expect(condition.Message).To(Equal("cannot read value [spec.foo] from unhealthy object [widget.thing.io/my-widget] in namespace [my-ns], examine object, particularly whether it is receiving proper inputs"))
66+
})
67+
})
68+
69+
Context("healthy is unknown", func() {
70+
BeforeEach(func() {
71+
healthy = metav1.ConditionUnknown
72+
})
4373

44-
condition := conditions.MissingValueAtPathCondition(true, obj, "spec.foo", "widget.thing.io")
45-
Expect(condition.Message).To(Equal("waiting to read value [spec.foo] from resource [widget.thing.io/my-widget] in namespace [my-ns]"))
74+
It("has the correct message", func() {
75+
condition := conditions.MissingValueAtPathCondition(true, obj, "spec.foo", "widget.thing.io", healthy)
76+
Expect(condition.Message).To(Equal("waiting to read value [spec.foo] from object [widget.thing.io/my-widget] in namespace [my-ns]"))
77+
})
4678
})
4779
})
4880

4981
Context("stamped object does not have a namespace", func() {
5082
It("has the correct message", func() {
51-
condition := conditions.MissingValueAtPathCondition(true, obj, "spec.foo", "widget.thing.io")
52-
Expect(condition.Message).To(Equal("waiting to read value [spec.foo] from resource [widget.thing.io/my-widget]"))
83+
condition := conditions.MissingValueAtPathCondition(true, obj, "spec.foo", "widget.thing.io", metav1.ConditionUnknown)
84+
Expect(condition.Message).To(Equal("waiting to read value [spec.foo] from object [widget.thing.io/my-widget]"))
5385
})
5486
})
5587
})

pkg/conditions/workload_conditions.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,11 @@ func AddConditionForResourceSubmittedWorkload(conditionManager *ConditionManager
8888
(*conditionManager).AddPositive(TemplateRejectedByAPIServerCondition(isOwner, typedErr))
8989
case cerrors.ListCreatedObjectsError:
9090
(*conditionManager).AddPositive(BlueprintsFailedToListCreatedObjectsCondition(isOwner, typedErr))
91-
case cerrors.NoHealthyImmutableObjectsError:
92-
(*conditionManager).AddPositive(NoHealthyImmutableObjectsCondition(isOwner, typedErr))
9391
case cerrors.RetrieveOutputError:
9492
if typedErr.StampedObject == nil {
9593
(*conditionManager).AddPositive(MissingPassThroughInputCondition(typedErr.PassThroughInput, typedErr.GetQualifiedResource()))
9694
} else {
97-
(*conditionManager).AddPositive(MissingValueAtPathCondition(isOwner, typedErr.StampedObject, typedErr.JsonPathExpression(), typedErr.GetQualifiedResource()))
95+
(*conditionManager).AddPositive(MissingValueAtPathCondition(isOwner, typedErr.StampedObject, typedErr.JsonPathExpression(), typedErr.GetQualifiedResource(), typedErr.Healthy))
9896
}
9997
case cerrors.ResolveTemplateOptionError:
10098
(*conditionManager).AddPositive(ResolveTemplateOptionsErrorCondition(isOwner, typedErr))

pkg/controllers/deliverable_reconciler_test.go

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@ var _ = Describe("DeliverableReconciler", func() {
796796
var retrieveError cerrors.RetrieveOutputError
797797
var wrappedError error
798798
var stampedObject *unstructured.Unstructured
799+
var healthy metav1.ConditionStatus
799800

800801
JustBeforeEach(func() {
801802
stampedObject = &unstructured.Unstructured{}
@@ -814,6 +815,7 @@ var _ = Describe("DeliverableReconciler", func() {
814815
BlueprintType: cerrors.Delivery,
815816
StampedObject: stampedObject,
816817
QualifiedResource: "mything.thing.io",
818+
Healthy: healthy,
817819
}
818820

819821
rlzr.RealizeStub = func(ctx context.Context, resourceRealizer realizer.ResourceRealizer, deliveryName string, resources []realizer.OwnerResource, statuses statuses.ResourceStatuses) error {
@@ -950,9 +952,37 @@ var _ = Describe("DeliverableReconciler", func() {
950952
wrappedError = stamp.NewJsonPathError("this.wont.find.anything", errors.New("some error"))
951953
})
952954

953-
It("calls the condition manager to report", func() {
954-
_, _ = reconciler.Reconcile(ctx, req)
955-
Expect(conditionManager.AddPositiveArgsForCall(1)).To(Equal(conditions.MissingValueAtPathCondition(true, stampedObject, "this.wont.find.anything", "mything.thing.io")))
955+
Context("and the RetrieveOutputError reports object as healthy", func() {
956+
BeforeEach(func() {
957+
healthy = metav1.ConditionTrue
958+
})
959+
960+
It("calls the condition manager to report", func() {
961+
_, _ = reconciler.Reconcile(ctx, req)
962+
Expect(conditionManager.AddPositiveArgsForCall(1)).To(Equal(conditions.MissingValueAtPathCondition(true, stampedObject, "this.wont.find.anything", "mything.thing.io", metav1.ConditionTrue)))
963+
})
964+
})
965+
966+
Context("and the RetrieveOutputError reports object as unhealthy", func() {
967+
BeforeEach(func() {
968+
healthy = metav1.ConditionFalse
969+
})
970+
971+
It("calls the condition manager to report", func() {
972+
_, _ = reconciler.Reconcile(ctx, req)
973+
Expect(conditionManager.AddPositiveArgsForCall(1)).To(Equal(conditions.MissingValueAtPathCondition(true, stampedObject, "this.wont.find.anything", "mything.thing.io", metav1.ConditionFalse)))
974+
})
975+
})
976+
977+
Context("and the RetrieveOutputError reports object health as unknown", func() {
978+
BeforeEach(func() {
979+
healthy = metav1.ConditionUnknown
980+
})
981+
982+
It("calls the condition manager to report", func() {
983+
_, _ = reconciler.Reconcile(ctx, req)
984+
Expect(conditionManager.AddPositiveArgsForCall(1)).To(Equal(conditions.MissingValueAtPathCondition(true, stampedObject, "this.wont.find.anything", "mything.thing.io", metav1.ConditionUnknown)))
985+
})
956986
})
957987

958988
It("does not return an error", func() {

pkg/controllers/workload_reconciler_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -850,8 +850,9 @@ var _ = Describe("WorkloadReconciler", func() {
850850

851851
It("calls the condition manager to report", func() {
852852
_, _ = reconciler.Reconcile(ctx, req)
853-
Expect(conditionManager.AddPositiveArgsForCall(1)).To(
854-
Equal(conditions.MissingValueAtPathCondition(true, stampedObject, "this.wont.find.anything", "mything.thing.io")))
853+
var emptyConditionStatus metav1.ConditionStatus
854+
Expect(conditionManager.AddPositiveArgsForCall(1)).
855+
To(Equal(conditions.MissingValueAtPathCondition(true, stampedObject, "this.wont.find.anything", "mything.thing.io", emptyConditionStatus)))
855856
})
856857

857858
It("does not return an error", func() {

pkg/errors/errors.go

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"strings"
2020

2121
kerrors "k8s.io/apimachinery/pkg/api/errors"
22+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2223
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2324
)
2425

@@ -131,6 +132,7 @@ type RetrieveOutputError struct {
131132
BlueprintType string
132133
QualifiedResource string
133134
PassThroughInput string
135+
Healthy metav1.ConditionStatus
134136
}
135137

136138
func (e RetrieveOutputError) Error() string {
@@ -193,15 +195,6 @@ type NoHealthyImmutableObjectsError struct {
193195
BlueprintType string
194196
}
195197

196-
func (e NoHealthyImmutableObjectsError) Error() string {
197-
return fmt.Errorf("unable to retrieve outputs for resource [%s] in %s [%s]: %w",
198-
e.ResourceName,
199-
e.BlueprintType,
200-
e.BlueprintName,
201-
e.Err,
202-
).Error()
203-
}
204-
205198
func WrapUnhandledError(err error) error {
206199
if IsUnhandledErrorType(err) {
207200
return NewUnhandledError(err)

pkg/realizer/component.go

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -206,32 +206,23 @@ func (r *resourceRealizer) doImmutable(ctx context.Context, resource OwnerResour
206206

207207
var output *templates.Output
208208

209-
if latestSuccessfulObject == nil {
210-
for _, obj := range allRunnableStampedObjects {
211-
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-
}
218-
}
219-
220-
log.V(logger.DEBUG).Info("no objects are in an unknown state and none are healthy, cannot proceed")
221-
return template, stampedObject, nil, passThrough, templateName, errors.NoHealthyImmutableObjectsError{
222-
Err: fmt.Errorf("failed to find any healthy object in the set of immutable stamped objects"),
223-
ResourceName: resource.Name,
224-
BlueprintName: blueprintName,
225-
BlueprintType: errors.SupplyChain,
226-
}
227-
}
228-
229209
output, err = stampReader.Output(latestSuccessfulObject)
230210

231211
if err != nil {
232-
qualifiedResource, rErr := utils.GetQualifiedResource(mapper, latestSuccessfulObject)
212+
var (
213+
qualifiedResource string
214+
rErr error
215+
objectToReport *unstructured.Unstructured
216+
)
217+
if latestSuccessfulObject == nil {
218+
objectToReport = stampedObject
219+
} else {
220+
objectToReport = latestSuccessfulObject
221+
}
222+
223+
qualifiedResource, rErr = utils.GetQualifiedResource(mapper, objectToReport)
233224
if rErr != nil {
234-
log.Error(err, "failed to retrieve qualified resource name", "object", latestSuccessfulObject)
225+
log.Error(err, "failed to retrieve qualified resource name", "object", objectToReport)
235226
qualifiedResource = "could not fetch - see the log line for 'failed to retrieve qualified resource name'"
236227
}
237228

0 commit comments

Comments
 (0)