in pkg/ingress/kube/gateway/istio/conditions.go [45:173]
func createRouteStatus(parentResults []RouteParentResult, obj config.Config, currentParents []k8s.RouteParentStatus) []k8s.RouteParentStatus {
parents := make([]k8s.RouteParentStatus, 0, len(parentResults))
// Fill in all the gateways that are already present but not owned by us. This is non-trivial as there may be multiple
// gateway controllers that are exposing their status on the same route. We need to attempt to manage ours properly (including
// removing gateway references when they are removed), without mangling other Controller's status.
for _, r := range currentParents {
if r.ControllerName != constants.ManagedGatewayController {
// We don't own this status, so keep it around
parents = append(parents, r)
}
}
// Collect all of our unique parent references. There may be multiple when we have a route without section name,
// but reference a parent with multiple sections.
// While we process these internally for-each sectionName, in the status we are just supposed to report one merged entry
seen := map[k8s.ParentReference][]RouteParentResult{}
seenReasons := sets.New[ParentErrorReason]()
successCount := map[k8s.ParentReference]int{}
for _, incoming := range parentResults {
// We will append it if it is our first occurrence, or the existing one has an error. This means
// if *any* section has no errors, we will declare Admitted
if incoming.DeniedReason == nil {
successCount[incoming.OriginalReference]++
}
seen[incoming.OriginalReference] = append(seen[incoming.OriginalReference], incoming)
if incoming.DeniedReason != nil {
seenReasons.Insert(incoming.DeniedReason.Reason)
} else {
seenReasons.Insert(ParentNoError)
}
}
reasonRanking := []ParentErrorReason{
// No errors is preferred
ParentNoError,
// All route level errors
ParentErrorNotAllowed,
ParentErrorNoHostname,
ParentErrorParentRefConflict,
// Failures to match the Port or SectionName. These are last so that if we bind to 1 listener we
// just report errors for that 1 listener instead of for all sections we didn't bind to
ParentErrorNotAccepted,
}
// Next we want to collapse these. We need to report 1 type of error, or none.
report := map[k8s.ParentReference]RouteParentResult{}
for _, wantReason := range reasonRanking {
if !seenReasons.Contains(wantReason) {
continue
}
// We found our highest priority ranking, now we need to collapse this into a single message
for k, refs := range seen {
for _, ref := range refs {
reason := ParentNoError
if ref.DeniedReason != nil {
reason = ref.DeniedReason.Reason
}
if wantReason != reason {
// Skip this one, it is for a less relevant reason
continue
}
exist, f := report[k]
if f {
if ref.DeniedReason != nil {
if exist.DeniedReason != nil {
// join the error
exist.DeniedReason.Message += "; " + ref.DeniedReason.Message
} else {
exist.DeniedReason = ref.DeniedReason
}
}
} else {
exist = ref
}
report[k] = exist
}
}
// Once we find the best reason, do not consider any others
break
}
// Now we fill in all the parents we do own
for k, gw := range report {
msg := "Route was valid"
if successCount[k] > 1 {
msg = fmt.Sprintf("Route was valid, bound to %d parents", successCount[k])
}
conds := map[string]*condition{
string(k8s.RouteConditionAccepted): {
reason: string(k8s.RouteReasonAccepted),
message: msg,
},
string(k8s.RouteConditionResolvedRefs): {
reason: string(k8s.RouteReasonResolvedRefs),
message: "All references resolved",
},
}
if gw.RouteError != nil {
// Currently, the spec is not clear on where errors should be reported. The provided resources are:
// * Accepted - used to describe errors binding to parents
// * ResolvedRefs - used to describe errors about binding to objects
// But no general errors
// For now, we will treat all general route errors as "Ref" errors.
conds[string(k8s.RouteConditionResolvedRefs)].error = gw.RouteError
}
if gw.DeniedReason != nil {
conds[string(k8s.RouteConditionAccepted)].error = &ConfigError{
Reason: ConfigErrorReason(gw.DeniedReason.Reason),
Message: gw.DeniedReason.Message,
}
}
var currentConditions []metav1.Condition
currentStatus := slices.FindFunc(currentParents, func(s k8sbeta.RouteParentStatus) bool {
return parentRefString(s.ParentRef) == parentRefString(gw.OriginalReference)
})
if currentStatus != nil {
currentConditions = currentStatus.Conditions
}
parents = append(parents, k8s.RouteParentStatus{
ParentRef: gw.OriginalReference,
ControllerName: constants.ManagedGatewayController,
Conditions: setConditions(obj.Generation, currentConditions, conds),
})
}
// Ensure output is deterministic.
// TODO: will we fight over other controllers doing similar (but not identical) ordering?
sort.SliceStable(parents, func(i, j int) bool {
return parentRefString(parents[i].ParentRef) > parentRefString(parents[j].ParentRef)
})
return parents
}