21
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
22
k8sv1 "sigs.k8s.io/gateway-api/apis/v1"
23
k8s "sigs.k8s.io/gateway-api/apis/v1alpha2"
25
"istio.io/istio/pilot/pkg/features"
26
"istio.io/istio/pilot/pkg/model/kstatus"
27
"istio.io/istio/pkg/config"
28
"istio.io/istio/pkg/config/schema/gvk"
29
"istio.io/istio/pkg/maps"
30
"istio.io/istio/pkg/ptr"
31
"istio.io/istio/pkg/slices"
32
"istio.io/istio/pkg/util/sets"
36
type RouteParentResult struct {
38
OriginalReference k8s.ParentReference
40
DeniedReason *ParentError
42
RouteError *ConfigError
45
func createRouteStatus(parentResults []RouteParentResult, obj config.Config, currentParents []k8s.RouteParentStatus) []k8s.RouteParentStatus {
46
parents := make([]k8s.RouteParentStatus, 0, len(parentResults))
50
for _, r := range currentParents {
51
if r.ControllerName != k8sv1.GatewayController(features.ManagedGatewayController) {
53
parents = append(parents, r)
59
seen := map[k8s.ParentReference][]RouteParentResult{}
60
seenReasons := sets.New[ParentErrorReason]()
61
successCount := map[k8s.ParentReference]int{}
62
for _, incoming := range parentResults {
65
if incoming.DeniedReason == nil {
66
successCount[incoming.OriginalReference]++
68
seen[incoming.OriginalReference] = append(seen[incoming.OriginalReference], incoming)
69
if incoming.DeniedReason != nil {
70
seenReasons.Insert(incoming.DeniedReason.Reason)
72
seenReasons.Insert(ParentNoError)
75
reasonRanking := []ParentErrorReason{
79
ParentErrorNotAllowed,
80
ParentErrorNoHostname,
81
ParentErrorParentRefConflict,
84
ParentErrorNotAccepted,
87
report := map[k8s.ParentReference]RouteParentResult{}
88
for _, wantReason := range reasonRanking {
89
if !seenReasons.Contains(wantReason) {
93
for k, refs := range seen {
94
for _, ref := range refs {
95
reason := ParentNoError
96
if ref.DeniedReason != nil {
97
reason = ref.DeniedReason.Reason
99
if wantReason != reason {
103
exist, f := report[k]
105
if ref.DeniedReason != nil {
106
if exist.DeniedReason != nil {
108
exist.DeniedReason.Message += "; " + ref.DeniedReason.Message
110
exist.DeniedReason = ref.DeniedReason
124
for k, gw := range report {
125
msg := "Route was valid"
126
if successCount[k] > 1 {
127
msg = fmt.Sprintf("Route was valid, bound to %d parents", successCount[k])
129
conds := map[string]*condition{
130
string(k8s.RouteConditionAccepted): {
131
reason: string(k8s.RouteReasonAccepted),
134
string(k8s.RouteConditionResolvedRefs): {
135
reason: string(k8s.RouteReasonResolvedRefs),
136
message: "All references resolved",
139
if gw.RouteError != nil {
145
conds[string(k8s.RouteConditionResolvedRefs)].error = gw.RouteError
147
if gw.DeniedReason != nil {
148
conds[string(k8s.RouteConditionAccepted)].error = &ConfigError{
149
Reason: ConfigErrorReason(gw.DeniedReason.Reason),
150
Message: gw.DeniedReason.Message,
154
var currentConditions []metav1.Condition
155
currentStatus := slices.FindFunc(currentParents, func(s k8sv1.RouteParentStatus) bool {
156
return parentRefString(s.ParentRef) == parentRefString(gw.OriginalReference)
158
if currentStatus != nil {
159
currentConditions = currentStatus.Conditions
161
parents = append(parents, k8s.RouteParentStatus{
162
ParentRef: gw.OriginalReference,
163
ControllerName: k8sv1.GatewayController(features.ManagedGatewayController),
164
Conditions: setConditions(obj.Generation, currentConditions, conds),
169
sort.SliceStable(parents, func(i, j int) bool {
170
return parentRefString(parents[i].ParentRef) > parentRefString(parents[j].ParentRef)
175
type ParentErrorReason string
178
ParentErrorNotAccepted = ParentErrorReason(k8sv1.RouteReasonNoMatchingParent)
179
ParentErrorNotAllowed = ParentErrorReason(k8s.RouteReasonNotAllowedByListeners)
180
ParentErrorNoHostname = ParentErrorReason(k8s.RouteReasonNoMatchingListenerHostname)
181
ParentErrorParentRefConflict = ParentErrorReason("ParentRefConflict")
182
ParentNoError = ParentErrorReason("")
185
type ConfigErrorReason = string
189
InvalidRefNotPermitted ConfigErrorReason = ConfigErrorReason(k8s.RouteReasonRefNotPermitted)
191
InvalidDestination ConfigErrorReason = "InvalidDestination"
192
InvalidAddress ConfigErrorReason = ConfigErrorReason(k8sv1.GatewayReasonUnsupportedAddress)
194
InvalidDestinationPermit ConfigErrorReason = ConfigErrorReason(k8s.RouteReasonRefNotPermitted)
196
InvalidDestinationKind ConfigErrorReason = ConfigErrorReason(k8s.RouteReasonInvalidKind)
198
InvalidDestinationNotFound ConfigErrorReason = ConfigErrorReason(k8s.RouteReasonBackendNotFound)
200
InvalidParentRef ConfigErrorReason = "InvalidParentReference"
202
InvalidFilter ConfigErrorReason = "InvalidFilter"
204
InvalidTLS ConfigErrorReason = ConfigErrorReason(k8sv1.ListenerReasonInvalidCertificateRef)
206
InvalidListenerRefNotPermitted ConfigErrorReason = ConfigErrorReason(k8sv1.ListenerReasonRefNotPermitted)
208
InvalidConfiguration ConfigErrorReason = "InvalidConfiguration"
209
InvalidResources ConfigErrorReason = ConfigErrorReason(k8sv1.GatewayReasonNoResources)
210
DeprecateFieldUsage = "DeprecatedField"
214
type ParentError struct {
215
Reason ParentErrorReason
220
type ConfigError struct {
221
Reason ConfigErrorReason
225
type condition struct {
232
status metav1.ConditionStatus
241
func setConditions(generation int64, existingConditions []metav1.Condition, conditions map[string]*condition) []metav1.Condition {
243
for _, k := range slices.Sort(maps.Keys(conditions)) {
244
cond := conditions[k]
245
setter := kstatus.UpdateConditionIfChanged
246
if cond.setOnce != "" {
247
setter = func(conditions []metav1.Condition, condition metav1.Condition) []metav1.Condition {
248
return kstatus.CreateCondition(conditions, condition, cond.setOnce)
258
if cond.error != nil {
259
existingConditions = setter(existingConditions, metav1.Condition{
261
Status: kstatus.InvertStatus(cond.status),
262
ObservedGeneration: generation,
263
LastTransitionTime: metav1.Now(),
264
Reason: cond.error.Reason,
265
Message: cond.error.Message,
268
status := cond.status
270
status = kstatus.StatusTrue
272
existingConditions = setter(existingConditions, metav1.Condition{
275
ObservedGeneration: generation,
276
LastTransitionTime: metav1.Now(),
278
Message: cond.message,
282
return existingConditions
285
func reportListenerAttachedRoutes(index int, obj config.Config, i int32) {
286
obj.Status.(*kstatus.WrappedStatus).Mutate(func(s config.Status) config.Status {
287
gs := s.(*k8s.GatewayStatus)
288
for index >= len(gs.Listeners) {
289
gs.Listeners = append(gs.Listeners, k8s.ListenerStatus{})
291
status := gs.Listeners[index]
292
status.AttachedRoutes = i
293
gs.Listeners[index] = status
298
func reportListenerCondition(index int, l k8s.Listener, obj config.Config, conditions map[string]*condition) {
299
obj.Status.(*kstatus.WrappedStatus).Mutate(func(s config.Status) config.Status {
300
gs := s.(*k8s.GatewayStatus)
301
for index >= len(gs.Listeners) {
302
gs.Listeners = append(gs.Listeners, k8s.ListenerStatus{})
304
cond := gs.Listeners[index].Conditions
305
supported, valid := generateSupportedKinds(l)
307
conditions[string(k8sv1.ListenerConditionResolvedRefs)] = &condition{
308
reason: string(k8sv1.ListenerReasonInvalidRouteKinds),
309
status: metav1.ConditionFalse,
310
message: "Invalid route kinds",
313
gs.Listeners[index] = k8s.ListenerStatus{
316
SupportedKinds: supported,
317
Conditions: setConditions(obj.Generation, cond, conditions),
323
func generateSupportedKinds(l k8s.Listener) ([]k8s.RouteGroupKind, bool) {
324
supported := []k8s.RouteGroupKind{}
326
case k8sv1.HTTPProtocolType, k8sv1.HTTPSProtocolType:
328
supported = []k8s.RouteGroupKind{
329
{Group: (*k8s.Group)(ptr.Of(gvk.HTTPRoute.Group)), Kind: k8s.Kind(gvk.HTTPRoute.Kind)},
330
{Group: (*k8s.Group)(ptr.Of(gvk.GRPCRoute.Group)), Kind: k8s.Kind(gvk.GRPCRoute.Kind)},
332
case k8sv1.TCPProtocolType:
333
supported = []k8s.RouteGroupKind{{Group: (*k8s.Group)(ptr.Of(gvk.TCPRoute.Group)), Kind: k8s.Kind(gvk.TCPRoute.Kind)}}
334
case k8sv1.TLSProtocolType:
335
if l.TLS != nil && l.TLS.Mode != nil && *l.TLS.Mode == k8sv1.TLSModePassthrough {
336
supported = []k8s.RouteGroupKind{{Group: (*k8s.Group)(ptr.Of(gvk.TLSRoute.Group)), Kind: k8s.Kind(gvk.TLSRoute.Kind)}}
338
supported = []k8s.RouteGroupKind{{Group: (*k8s.Group)(ptr.Of(gvk.TCPRoute.Group)), Kind: k8s.Kind(gvk.TCPRoute.Kind)}}
342
if l.AllowedRoutes != nil && len(l.AllowedRoutes.Kinds) > 0 {
344
intersection := []k8s.RouteGroupKind{}
345
for _, s := range supported {
346
for _, kind := range l.AllowedRoutes.Kinds {
347
if routeGroupKindEqual(s, kind) {
348
intersection = append(intersection, s)
353
return intersection, len(intersection) == len(l.AllowedRoutes.Kinds)
355
return supported, true
359
func routeGroupKindEqual(rgk1, rgk2 k8s.RouteGroupKind) bool {
360
return rgk1.Kind == rgk2.Kind && getGroup(rgk1) == getGroup(rgk2)
363
func getGroup(rgk k8s.RouteGroupKind) k8s.Group {
364
return ptr.OrDefault(rgk.Group, k8s.Group(gvk.KubernetesGateway.Group))