Skip to content

Commit d6bbf0c

Browse files
committed
controller: enrich "HelmChart not ready" messages
This propagates the reason a HelmChart is (likely) not ready to the message of the Ready condition. The goal of this is to make it easier for people to reason about a potential failure that may be happening while retrieving the chart, without having to inspect the HelmChart itself. As at times, they may not have access (due to e.g. not being able to access the namespace, while the controller is allowed to create the object there), or are simply not aware of the fact that this object is created by the controller for them. Signed-off-by: Hidde Beydals <hidde@hhh.computer>
1 parent ee8177e commit d6bbf0c

File tree

2 files changed

+121
-3
lines changed

2 files changed

+121
-3
lines changed

internal/controller/helmrelease_controller.go

+27-3
Original file line numberDiff line numberDiff line change
@@ -276,9 +276,9 @@ func (r *HelmReleaseReconciler) reconcileRelease(ctx context.Context, patchHelpe
276276
return ctrl.Result{}, err
277277
}
278278

279-
// Check chart readiness.
280-
if hc.Generation != hc.Status.ObservedGeneration || !conditions.IsReady(hc) || hc.GetArtifact() == nil {
281-
msg := fmt.Sprintf("HelmChart '%s/%s' is not ready", hc.GetNamespace(), hc.GetName())
279+
// Check if the HelmChart is ready.
280+
if ready, reason := isHelmChartReady(hc); !ready {
281+
msg := fmt.Sprintf("HelmChart '%s/%s' is not ready: %s", hc.GetNamespace(), hc.GetName(), reason)
282282
log.Info(msg)
283283
conditions.MarkFalse(obj, meta.ReadyCondition, "HelmChartNotReady", msg)
284284
// Do not requeue immediately, when the artifact is created
@@ -703,3 +703,27 @@ func (r *HelmReleaseReconciler) requestsForHelmChartChange(ctx context.Context,
703703
}
704704
return reqs
705705
}
706+
707+
// isHelmChartReady returns true if the given HelmChart is ready, and a reason
708+
// why it is not ready otherwise.
709+
func isHelmChartReady(obj *sourcev1.HelmChart) (bool, string) {
710+
switch {
711+
case obj.Generation != obj.Status.ObservedGeneration:
712+
msg := "latest generation of HelmChart has not been processed"
713+
714+
// If the chart is not ready, we can likely provide a more
715+
// concise reason why.
716+
if conditions.IsFalse(obj, meta.ReadyCondition) {
717+
msg = conditions.GetMessage(obj, meta.ReadyCondition)
718+
}
719+
return false, msg
720+
case conditions.IsStalled(obj):
721+
return false, conditions.GetMessage(obj, meta.StalledCondition)
722+
case conditions.IsFalse(obj, meta.ReadyCondition):
723+
return false, conditions.GetMessage(obj, meta.ReadyCondition)
724+
case obj.Status.Artifact == nil:
725+
return false, "does not have an artifact"
726+
default:
727+
return true, ""
728+
}
729+
}

internal/controller/helmrelease_controller_test.go

+94
Original file line numberDiff line numberDiff line change
@@ -2206,3 +2206,97 @@ func TestValuesReferenceValidation(t *testing.T) {
22062206
})
22072207
}
22082208
}
2209+
2210+
func Test_isHelmChartReady(t *testing.T) {
2211+
mock := &sourcev1b2.HelmChart{
2212+
ObjectMeta: metav1.ObjectMeta{
2213+
Generation: 2,
2214+
},
2215+
Status: sourcev1b2.HelmChartStatus{
2216+
ObservedGeneration: 2,
2217+
Conditions: []metav1.Condition{
2218+
{
2219+
Type: meta.ReadyCondition,
2220+
Status: metav1.ConditionTrue,
2221+
},
2222+
},
2223+
Artifact: &sourcev1.Artifact{},
2224+
},
2225+
}
2226+
2227+
tests := []struct {
2228+
name string
2229+
obj *sourcev1b2.HelmChart
2230+
want bool
2231+
wantReason string
2232+
}{
2233+
{
2234+
name: "chart is ready",
2235+
obj: mock.DeepCopy(),
2236+
want: true,
2237+
},
2238+
{
2239+
name: "chart generation differs from observed generation while Ready=True",
2240+
obj: func() *sourcev1b2.HelmChart {
2241+
m := mock.DeepCopy()
2242+
m.Generation = 3
2243+
return m
2244+
}(),
2245+
want: false,
2246+
wantReason: "latest generation of HelmChart has not been processed",
2247+
},
2248+
{
2249+
name: "chart generation differs from observed generation while Ready=False",
2250+
obj: func() *sourcev1b2.HelmChart {
2251+
m := mock.DeepCopy()
2252+
m.Generation = 3
2253+
conditions.MarkFalse(m, meta.ReadyCondition, "Reason", "some reason")
2254+
return m
2255+
}(),
2256+
want: false,
2257+
wantReason: "some reason",
2258+
},
2259+
{
2260+
name: "chart has Ready=False",
2261+
obj: func() *sourcev1b2.HelmChart {
2262+
m := mock.DeepCopy()
2263+
conditions.MarkFalse(m, meta.ReadyCondition, "Reason", "some reason")
2264+
return m
2265+
}(),
2266+
want: false,
2267+
wantReason: "some reason",
2268+
},
2269+
{
2270+
name: "chart has Stalled=True",
2271+
obj: func() *sourcev1b2.HelmChart {
2272+
m := mock.DeepCopy()
2273+
conditions.MarkFalse(m, meta.ReadyCondition, "Reason", "some reason")
2274+
conditions.MarkStalled(m, "Reason", "some stalled reason")
2275+
return m
2276+
}(),
2277+
want: false,
2278+
wantReason: "some stalled reason",
2279+
},
2280+
{
2281+
name: "chart does not have an Artifact",
2282+
obj: func() *sourcev1b2.HelmChart {
2283+
m := mock.DeepCopy()
2284+
m.Status.Artifact = nil
2285+
return m
2286+
}(),
2287+
want: false,
2288+
wantReason: "does not have an artifact",
2289+
},
2290+
}
2291+
for _, tt := range tests {
2292+
t.Run(tt.name, func(t *testing.T) {
2293+
got, gotReason := isHelmChartReady(tt.obj)
2294+
if got != tt.want {
2295+
t.Errorf("isHelmChartReady() got = %v, want %v", got, tt.want)
2296+
}
2297+
if gotReason != tt.wantReason {
2298+
t.Errorf("isHelmChartReady() reason = %v, want %v", gotReason, tt.wantReason)
2299+
}
2300+
})
2301+
}
2302+
}

0 commit comments

Comments
 (0)