Skip to content

Commit d7a7ff7

Browse files
committed
test/extended/operators/operators: Rework "start all core operators"
Drop namespace from output strings, because ClusterOperator is cluster-scoped [1]. Shift the 'available' variable down to the block of code that actually consumes it, and convert it from a map to a counter, because we don't care about displaying available operators. Rename 'unavailable' to the more generic 'unready'. Also rephrase the "still doing work" message to hinge on "ready", because "working" can sound like "as expectd" not "still has stuff to do" [1]. An unready operator may be available but progressing, etc., so 'unavailable' was too specific. Remove the 'break' from the wait-loop's ClusterOperator iteration. The previous logic would only list the first unavailable operator. With this commit we now list each unavailable operator while we wait. Reformat the tab-writer block to print each operator and its worst condition. The previous format had columns for progressing and available, but none for degraded status. It also had a single message column, making it unclear which condition's message was being displayed. The new format displays the full type, status, reason, and message of the worst condition for each operator. The new code also includes the worst condition (or, if all existing conditions for an operator were expected, any missing condition types) in the failing error message. This should be more actionable with less digging than the current messages, which just list the unsettled operator names [2]. [1]: https://github.com/openshift/api/blob/b98a784d8e6dc93c416b40cdf54bf3102f2b61d2/config/v1/types_cluster_operator.go#L9 [2]: https://bugzilla.redhat.com/show_bug.cgi?id=1829405#c1
1 parent 209bc1f commit d7a7ff7

1 file changed

Lines changed: 74 additions & 43 deletions

File tree

test/extended/operators/operators.go

Lines changed: 74 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"context"
66
"fmt"
77
"os"
8+
"sort"
89
"strings"
910
"text/tabwriter"
1011
"time"
@@ -80,7 +81,6 @@ var _ = g.Describe("[sig-arch][Early] Managed cluster should", func() {
8081
}
8182

8283
// gate on all clusteroperators being ready
83-
available := make(map[string]struct{})
8484
g.By(fmt.Sprintf("waiting for all cluster operators to be stable at the same time"))
8585
coc := dc.Resource(schema.GroupVersionResource{Group: "config.openshift.io", Resource: "clusteroperators", Version: "v1"})
8686
lastErr = nil
@@ -101,68 +101,65 @@ var _ = g.Describe("[sig-arch][Early] Managed cluster should", func() {
101101
return false, nil
102102
}
103103

104-
var unavailable []objx.Map
105-
var unavailableNames []string
104+
var unready []string
106105
for _, co := range items {
107-
if condition(co, "Available").Get("status").String() != "True" {
108-
ns := co.Get("metadata.namespace").String()
109-
name := co.Get("metadata.name").String()
110-
unavailableNames = append(unavailableNames, fmt.Sprintf("%s/%s", ns, name))
111-
unavailable = append(unavailable, co)
112-
break
113-
}
114-
if condition(co, "Progressing").Get("status").String() != "False" {
115-
ns := co.Get("metadata.namespace").String()
116-
name := co.Get("metadata.name").String()
117-
unavailableNames = append(unavailableNames, fmt.Sprintf("%s/%s", ns, name))
118-
unavailable = append(unavailable, co)
119-
break
120-
}
121-
if condition(co, "Failing").Get("status").String() != "False" {
122-
ns := co.Get("metadata.namespace").String()
123-
name := co.Get("metadata.name").String()
124-
unavailableNames = append(unavailableNames, fmt.Sprintf("%s/%s", ns, name))
125-
unavailable = append(unavailable, co)
126-
break
106+
badConditions, missingTypes := surprisingConditions(co)
107+
if len(badConditions) > 0 || len(missingTypes) > 0 {
108+
unready = append(unready, co.Get("metadata.name").String())
127109
}
128110
}
129-
if len(unavailable) > 0 {
130-
e2e.Logf("Operators still doing work: %s", strings.Join(unavailableNames, ", "))
111+
if len(unready) > 0 {
112+
sort.Strings(unready)
113+
e2e.Logf("Operators still unready: %s", strings.Join(unready, ", "))
131114
return false, nil
132115
}
133116
return true, nil
134117
})
135118

136119
o.Expect(lastErr).NotTo(o.HaveOccurred())
137-
var unavailable []string
120+
ready := 0
121+
var unready []string
138122
buf := &bytes.Buffer{}
139123
w := tabwriter.NewWriter(buf, 0, 4, 1, ' ', 0)
140-
fmt.Fprintf(w, "NAMESPACE\tNAME\tPROGRESSING\tAVAILABLE\tVERSION\tMESSAGE\n")
124+
fmt.Fprintf(w, "NAME\tTYPE\tSTATUS\tREASON\tMESSAGE\n")
141125
for _, co := range lastCOs {
142-
ns := co.Get("metadata.namespace").String()
143126
name := co.Get("metadata.name").String()
144-
if condition(co, "Available").Get("status").String() != "True" {
145-
unavailable = append(unavailable, fmt.Sprintf("%s/%s", ns, name))
127+
badConditions, missingTypes := surprisingConditions(co)
128+
if len(badConditions) > 0 {
129+
worstCondition := badConditions[0]
130+
unready = append(unready, fmt.Sprintf("%s (%s=%s %s: %s)",
131+
name,
132+
worstCondition.Type,
133+
worstCondition.Status,
134+
worstCondition.Reason,
135+
worstCondition.Message,
136+
))
137+
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n",
138+
name,
139+
worstCondition.Type,
140+
worstCondition.Status,
141+
worstCondition.Reason,
142+
worstCondition.Message,
143+
)
144+
} else if len(missingTypes) > 0 {
145+
missingTypeStrings := make([]string, 0, len(missingTypes))
146+
for _, missingType := range missingTypes {
147+
missingTypeStrings = append(missingTypeStrings, string(missingType))
148+
}
149+
unready = append(unready, fmt.Sprintf("%s (missing: %s)", name, strings.Join(missingTypeStrings, ", ")))
146150
} else {
147-
available[fmt.Sprintf("%s/%s", ns, name)] = struct{}{}
151+
ready++
148152
}
149-
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\n",
150-
ns,
151-
name,
152-
condition(co, "Progressing").Get("status").String(),
153-
condition(co, "Available").Get("status").String(),
154-
co.Get("status.version").String(),
155-
condition(co, "Failing").Get("message").String(),
156-
)
157153
}
158154
w.Flush()
159155
e2e.Logf("ClusterOperators:\n%s", buf.String())
160156

161-
if len(unavailable) > 0 {
162-
e2e.Failf("Some cluster operators never became available %s", strings.Join(unavailable, ", "))
157+
if len(unready) > 0 {
158+
sort.Strings(unready)
159+
e2e.Failf("Some cluster operators never became ready: %s", strings.Join(unready, ", "))
163160
}
164-
// Check at least one core operator is available
165-
if len(available) == 0 {
161+
// Check at least one core operator is ready
162+
if ready == 0 {
166163
e2e.Failf("There must be at least one cluster operator")
167164
}
168165
})
@@ -265,3 +262,37 @@ func condition(cv objx.Map, condition string) objx.Map {
265262
}
266263
return objx.Map(nil)
267264
}
265+
266+
// surprisingConditions returns conditions with surprising statuses
267+
// (Available=False, Degraded=True, etc.) in order of descending
268+
// severity (e.g. Available=False is more severe than Degraded=True).
269+
// It also returns a slice of types for which a condition entry was
270+
// expected but not supplied on the ClusterOperator.
271+
func surprisingConditions(co objx.Map) ([]configv1.ClusterOperatorStatusCondition, []configv1.ClusterStatusConditionType) {
272+
var badConditions []configv1.ClusterOperatorStatusCondition
273+
var missingTypes []configv1.ClusterStatusConditionType
274+
for _, conditionType := range []configv1.ClusterStatusConditionType{
275+
configv1.OperatorAvailable,
276+
configv1.OperatorDegraded,
277+
configv1.OperatorProgressing,
278+
} {
279+
cond := condition(co, string(conditionType))
280+
if len(cond) == 0 {
281+
missingTypes = append(missingTypes, conditionType)
282+
} else {
283+
expected := configv1.ConditionFalse
284+
if conditionType == configv1.OperatorAvailable {
285+
expected = configv1.ConditionTrue
286+
}
287+
if cond.Get("status").String() != string(expected) {
288+
badConditions = append(badConditions, configv1.ClusterOperatorStatusCondition{
289+
Type: conditionType,
290+
Status: configv1.ConditionStatus(cond.Get("status").String()),
291+
Reason: cond.Get("reason").String(),
292+
Message: cond.Get("message").String(),
293+
})
294+
}
295+
}
296+
}
297+
return badConditions, missingTypes
298+
}

0 commit comments

Comments
 (0)