diff --git a/examples/gateway/00-crds.yaml b/examples/gateway/00-crds.yaml index b611f7a510d..3ac64810dd1 100644 --- a/examples/gateway/00-crds.yaml +++ b/examples/gateway/00-crds.yaml @@ -78,6 +78,9 @@ spec: minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ type: string + x-kubernetes-validations: + - message: Value is immutable + rule: self == oldSelf description: description: Description helps describe a GatewayClass with more details. maxLength: 64 @@ -132,7 +135,9 @@ spec: reason: Waiting status: Unknown type: Accepted - description: Status defines the current state of GatewayClass. + description: "Status defines the current state of GatewayClass. \n Implementations + MUST populate status on all GatewayClass resources which specify their + controller name." properties: conditions: default: @@ -215,27 +220,6 @@ spec: x-kubernetes-list-map-keys: - type x-kubernetes-list-type: map - routabilities: - description: "Routabilities specifies a list of supported routabilities - offered by the GatewayClass. The first entry in this list will be - the default routability used when Gateways of this class are created. - \n Implementations MAY provide a pre-defined set of GatewayClasses - that limit the routability choices of a Gateway. \n Implementations - MUST populate this list with the GatewayRoutability values that - are supported by this GatewayClass. \n " - items: - description: "GatewayRoutability represents the routability of a - Gateway \n The pre-defined values listed in this package can be - compared semantically. `Public` has a larger scope than `Private`, - while `Private` has a larger scope than `Cluster`. \n Implementations - can define custom routability values by specifying a vendor prefix - followed by a slash '/' and a custom name ie. `dev.example.com/my-routability`." - maxLength: 253 - minLength: 1 - pattern: ^Public|Private|Cluster|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-_]+$ - type: string - maxItems: 8 - type: array type: object required: - spec @@ -299,6 +283,9 @@ spec: minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ type: string + x-kubernetes-validations: + - message: Value is immutable + rule: self == oldSelf description: description: Description helps describe a GatewayClass with more details. maxLength: 64 @@ -353,7 +340,9 @@ spec: reason: Waiting status: Unknown type: Accepted - description: Status defines the current state of GatewayClass. + description: "Status defines the current state of GatewayClass. \n Implementations + MUST populate status on all GatewayClass resources which specify their + controller name." properties: conditions: default: @@ -436,27 +425,6 @@ spec: x-kubernetes-list-map-keys: - type x-kubernetes-list-type: map - routabilities: - description: "Routabilities specifies a list of supported routabilities - offered by the GatewayClass. The first entry in this list will be - the default routability used when Gateways of this class are created. - \n Implementations MAY provide a pre-defined set of GatewayClasses - that limit the routability choices of a Gateway. \n Implementations - MUST populate this list with the GatewayRoutability values that - are supported by this GatewayClass. \n " - items: - description: "GatewayRoutability represents the routability of a - Gateway \n The pre-defined values listed in this package can be - compared semantically. `Public` has a larger scope than `Private`, - while `Private` has a larger scope than `Cluster`. \n Implementations - can define custom routability values by specifying a vendor prefix - followed by a slash '/' and a custom name ie. `dev.example.com/my-routability`." - maxLength: 253 - minLength: 1 - pattern: ^Public|Private|Cluster|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-_]+$ - type: string - maxItems: 8 - type: array type: object required: - spec @@ -547,10 +515,24 @@ spec: manner, assigning an appropriate set of Addresses. \n The implementation MUST bind all Listeners to every GatewayAddress that it assigns to the Gateway and add a corresponding entry in GatewayStatus.Addresses. - \n Support: Extended" + \n Support: Extended \n " items: description: GatewayAddress describes an address that can be bound to a Gateway. + oneOf: + - properties: + type: + enum: + - IPAddress + value: + anyOf: + - format: ipv4 + - format: ipv6 + - properties: + type: + not: + enum: + - IPAddress properties: type: default: IPAddress @@ -569,38 +551,26 @@ spec: required: - value type: object + x-kubernetes-validations: + - message: Hostname value must only contain valid characters (matching + ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$) + rule: 'self.type == ''Hostname'' ? self.value.matches(''^(\\*\\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$''): + true' maxItems: 16 type: array + x-kubernetes-validations: + - message: IPAddress values must be unique + rule: 'self.all(a1, a1.type == ''IPAddress'' ? self.exists_one(a2, + a2.type == a1.type && a2.value == a1.value) : true )' + - message: Hostname values must be unique + rule: 'self.all(a1, a1.type == ''Hostname'' ? self.exists_one(a2, + a2.type == a1.type && a2.value == a1.value) : true )' gatewayClassName: description: GatewayClassName used for this Gateway. This is the name of a GatewayClass resource. maxLength: 253 minLength: 1 type: string - infrastructure: - description: "Infrastructure defines infrastructure level attributes - about this Gateway instance. \n " - properties: - routability: - description: "Routability allows the Gateway to specify the accessibility - of its addresses. Setting this property will override the default - value defined by the GatewayClass. \n If the desired Gateway - routability is incompatible with the GatewayClass implementations - MUST set the condition `Accepted` to `False` with `Reason` set - to `UnsupportedRoutability`. \n The default value of routability - is implementation specific and MUST remain consistent for Gateways - with the same gatewayClassName \n Implementations MUST clearly - document if they support updates to this field. The default - expectation should be that changes to this field are not supported - unless an implementation specifies otherwise. \n If a Gateway - is mutated but does not support the desired routability it MUST - set the `Accepted` and `Programmed` conditions to `False` with - `Reason` set to `UnsupportedRoutability`." - maxLength: 253 - minLength: 1 - pattern: ^Public|Private|Cluster|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-_]+$ - type: string - type: object listeners: description: "Listeners associated with this Gateway. Listeners define logical endpoints that are bound on this Gateway's addresses. At @@ -933,6 +903,11 @@ spec: maxProperties: 16 type: object type: object + x-kubernetes-validations: + - message: certificateRefs must be set and not empty when TLSModeType + is Terminate + rule: 'self.mode == ''Terminate'' ? size(self.certificateRefs) + > 0 : true' required: - name - port @@ -944,6 +919,23 @@ spec: x-kubernetes-list-map-keys: - name x-kubernetes-list-type: map + x-kubernetes-validations: + - message: tls must be set for protocols ['HTTPS', 'TLS'] + rule: 'self.all(l, l.protocol in [''HTTPS'', ''TLS''] ? has(l.tls) + : true)' + - message: tls must be empty for protocols ['HTTP', 'TCP', 'UDP'] + rule: 'self.all(l, l.protocol in [''HTTP'', ''TCP'', ''UDP''] ? + !has(l.tls) : true)' + - message: hostname must be empty for protocols ['TCP', 'UDP'] + rule: 'self.all(l, l.protocol in [''TCP'', ''UDP''] ? (!has(l.hostname) + || l.hostname == '''') : true)' + - message: Listener name must be unique within the Gateway + rule: self.all(l1, self.exists_one(l2, l1.name == l2.name)) + - message: Combination of port, protocol and hostname must be unique + for each listener + rule: 'self.all(l1, self.exists_one(l2, l1.port == l2.port && l1.protocol + == l2.protocol && (has(l1.hostname) && has(l2.hostname) ? l1.hostname + == l2.hostname : true)))' required: - gatewayClassName - listeners @@ -967,26 +959,25 @@ spec: description: "Addresses lists the IP addresses that have actually been bound to the Gateway. These addresses may differ from the addresses in the Spec, e.g. if the Gateway automatically assigns an address - from a reserved pool. \n Implementations that support GatewayRoutability - MUST include an address that has the same routable semantics as - defined in the Gateway spec. \n Implementations MAY add additional - addresses in status, but they MUST be semantically less than the - scope of the requested scope. For example if a user requests a `Private` - routable Gateway then an additional address MAY have a routability - of `Cluster` but MUST NOT include `Public`." + from a reserved pool. \n " items: description: GatewayStatusAddress describes an address that is bound to a Gateway. + oneOf: + - properties: + type: + enum: + - IPAddress + value: + anyOf: + - format: ipv4 + - format: ipv6 + - properties: + type: + not: + enum: + - IPAddress properties: - routability: - description: "Routability specifies the routable bounds of this - address Predefined values are: 'Private', 'Public', Cluster - Other values MUST have a vendor prefix. \n Implementations - that support Routability MUST populate this field \n " - maxLength: 253 - minLength: 1 - pattern: ^Public|Private|Cluster|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-_]+$ - type: string type: default: IPAddress description: Type of the address. @@ -1004,6 +995,11 @@ spec: required: - value type: object + x-kubernetes-validations: + - message: Hostname value must only contain valid characters (matching + ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$) + rule: 'self.type == ''Hostname'' ? self.value.matches(''^(\\*\\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$''): + true' maxItems: 16 type: array conditions: @@ -1292,10 +1288,24 @@ spec: manner, assigning an appropriate set of Addresses. \n The implementation MUST bind all Listeners to every GatewayAddress that it assigns to the Gateway and add a corresponding entry in GatewayStatus.Addresses. - \n Support: Extended" + \n Support: Extended \n " items: description: GatewayAddress describes an address that can be bound to a Gateway. + oneOf: + - properties: + type: + enum: + - IPAddress + value: + anyOf: + - format: ipv4 + - format: ipv6 + - properties: + type: + not: + enum: + - IPAddress properties: type: default: IPAddress @@ -1314,38 +1324,26 @@ spec: required: - value type: object + x-kubernetes-validations: + - message: Hostname value must only contain valid characters (matching + ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$) + rule: 'self.type == ''Hostname'' ? self.value.matches(''^(\\*\\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$''): + true' maxItems: 16 type: array + x-kubernetes-validations: + - message: IPAddress values must be unique + rule: 'self.all(a1, a1.type == ''IPAddress'' ? self.exists_one(a2, + a2.type == a1.type && a2.value == a1.value) : true )' + - message: Hostname values must be unique + rule: 'self.all(a1, a1.type == ''Hostname'' ? self.exists_one(a2, + a2.type == a1.type && a2.value == a1.value) : true )' gatewayClassName: description: GatewayClassName used for this Gateway. This is the name of a GatewayClass resource. maxLength: 253 minLength: 1 type: string - infrastructure: - description: "Infrastructure defines infrastructure level attributes - about this Gateway instance. \n " - properties: - routability: - description: "Routability allows the Gateway to specify the accessibility - of its addresses. Setting this property will override the default - value defined by the GatewayClass. \n If the desired Gateway - routability is incompatible with the GatewayClass implementations - MUST set the condition `Accepted` to `False` with `Reason` set - to `UnsupportedRoutability`. \n The default value of routability - is implementation specific and MUST remain consistent for Gateways - with the same gatewayClassName \n Implementations MUST clearly - document if they support updates to this field. The default - expectation should be that changes to this field are not supported - unless an implementation specifies otherwise. \n If a Gateway - is mutated but does not support the desired routability it MUST - set the `Accepted` and `Programmed` conditions to `False` with - `Reason` set to `UnsupportedRoutability`." - maxLength: 253 - minLength: 1 - pattern: ^Public|Private|Cluster|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-_]+$ - type: string - type: object listeners: description: "Listeners associated with this Gateway. Listeners define logical endpoints that are bound on this Gateway's addresses. At @@ -1678,6 +1676,11 @@ spec: maxProperties: 16 type: object type: object + x-kubernetes-validations: + - message: certificateRefs must be set and not empty when TLSModeType + is Terminate + rule: 'self.mode == ''Terminate'' ? size(self.certificateRefs) + > 0 : true' required: - name - port @@ -1689,6 +1692,23 @@ spec: x-kubernetes-list-map-keys: - name x-kubernetes-list-type: map + x-kubernetes-validations: + - message: tls must be set for protocols ['HTTPS', 'TLS'] + rule: 'self.all(l, l.protocol in [''HTTPS'', ''TLS''] ? has(l.tls) + : true)' + - message: tls must be empty for protocols ['HTTP', 'TCP', 'UDP'] + rule: 'self.all(l, l.protocol in [''HTTP'', ''TCP'', ''UDP''] ? + !has(l.tls) : true)' + - message: hostname must be empty for protocols ['TCP', 'UDP'] + rule: 'self.all(l, l.protocol in [''TCP'', ''UDP''] ? (!has(l.hostname) + || l.hostname == '''') : true)' + - message: Listener name must be unique within the Gateway + rule: self.all(l1, self.exists_one(l2, l1.name == l2.name)) + - message: Combination of port, protocol and hostname must be unique + for each listener + rule: 'self.all(l1, self.exists_one(l2, l1.port == l2.port && l1.protocol + == l2.protocol && (has(l1.hostname) && has(l2.hostname) ? l1.hostname + == l2.hostname : true)))' required: - gatewayClassName - listeners @@ -1712,26 +1732,25 @@ spec: description: "Addresses lists the IP addresses that have actually been bound to the Gateway. These addresses may differ from the addresses in the Spec, e.g. if the Gateway automatically assigns an address - from a reserved pool. \n Implementations that support GatewayRoutability - MUST include an address that has the same routable semantics as - defined in the Gateway spec. \n Implementations MAY add additional - addresses in status, but they MUST be semantically less than the - scope of the requested scope. For example if a user requests a `Private` - routable Gateway then an additional address MAY have a routability - of `Cluster` but MUST NOT include `Public`." + from a reserved pool. \n " items: description: GatewayStatusAddress describes an address that is bound to a Gateway. + oneOf: + - properties: + type: + enum: + - IPAddress + value: + anyOf: + - format: ipv4 + - format: ipv6 + - properties: + type: + not: + enum: + - IPAddress properties: - routability: - description: "Routability specifies the routable bounds of this - address Predefined values are: 'Private', 'Public', Cluster - Other values MUST have a vendor prefix. \n Implementations - that support Routability MUST populate this field \n " - maxLength: 253 - minLength: 1 - pattern: ^Public|Private|Cluster|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-_]+$ - type: string type: default: IPAddress description: Type of the address. @@ -1749,6 +1768,11 @@ spec: required: - value type: object + x-kubernetes-validations: + - message: Hostname value must only contain valid characters (matching + ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$) + rule: 'self.type == ''Hostname'' ? self.value.matches(''^(\\*\\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$''): + true' maxItems: 16 type: array conditions: @@ -2237,7 +2261,7 @@ spec: Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n - Support: Extended \n " + Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -2327,7 +2351,9 @@ spec: extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" + filters. \n Support: Implementation-specific \n + This filter can be used multiple times within + the same rule." properties: group: description: Group is the group of the referent. @@ -2465,7 +2491,10 @@ spec: description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from - that destination are ignored. \n Support: Extended" + that destination are ignored. \n This filter can + be used multiple times within the same rule. Note + that not all implementations will be able to support + mirroring to multiple backends. \n Support: Extended" properties: backendRef: description: "BackendRef references a resource @@ -2554,6 +2583,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' required: - backendRef type: object @@ -2777,6 +2810,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' maxItems: 16 type: array filters: @@ -2789,8 +2826,8 @@ spec: all implementations that support GRPCRoute. - Implementers are encouraged to support extended filters. - Implementation-specific custom filters have no API guarantees across implementations. - \n Specifying a core filter multiple times has unspecified - or implementation-specific conformance. \n If an implementation + \n Specifying the same filter multiple times is not supported + unless explicitly indicated in the filter. \n If an implementation can not support a combinations of filters, they must clearly document that limitation. In cases where incompatible or unsupported filters are specified and cause the `Accepted` condition to @@ -2811,7 +2848,8 @@ spec: extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" + filters. \n Support: Implementation-specific \n This + filter can be used multiple times within the same rule." properties: group: description: Group is the group of the referent. For @@ -2941,7 +2979,10 @@ spec: description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are - ignored. \n Support: Extended" + ignored. \n This filter can be used multiple times within + the same rule. Note that not all implementations will + be able to support mirroring to multiple backends. \n + Support: Extended" properties: backendRef: description: "BackendRef references a resource where @@ -3023,6 +3064,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' required: - backendRef type: object @@ -3491,7 +3536,7 @@ spec: the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. - \n Support: Extended \n " + \n Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -3774,7 +3819,7 @@ spec: Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n - Support: Extended \n " + Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -3865,7 +3910,8 @@ spec: extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" + filters. \n This filter can be used multiple times + within the same rule. \n Support: Implementation-specific" properties: group: description: Group is the group of the referent. @@ -4003,7 +4049,10 @@ spec: description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from - that destination are ignored. \n Support: Extended" + that destination are ignored. \n This filter can + be used multiple times within the same rule. Note + that not all implementations will be able to support + mirroring to multiple backends. \n Support: Extended" properties: backendRef: description: "BackendRef references a resource @@ -4092,6 +4141,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' required: - backendRef type: object @@ -4181,6 +4234,23 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' port: description: "Port is the port to be used in the value of the `Location` header in the @@ -4469,12 +4539,97 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' type: object required: - type type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil + if the filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type + != ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type + == ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil + if the filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type + != ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for + RequestMirror filter.type + rule: '!(!has(self.requestMirror) && self.type == + ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the + filter.type is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != + ''RequestRedirect'')' + - message: filter.requestRedirect must be specified + for RequestRedirect filter.type + rule: '!(!has(self.requestRedirect) && self.type == + ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for + ExtensionRef filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' maxItems: 16 type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestHeaderModifier'') + ? self.exists_one(f, f.type == ''RequestHeaderModifier'') + : true' + - message: ResponseHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''ResponseHeaderModifier'') + ? self.exists_one(f, f.type == ''ResponseHeaderModifier'') + : true' + - message: RequestRedirect filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestRedirect'') + ? self.exists_one(f, f.type == ''RequestRedirect'') + : true' + - message: URLRewrite filter cannot be repeated + rule: 'self.exists(f, f.type == ''URLRewrite'') ? self.exists_one(f, + f.type == ''URLRewrite'') : true' group: default: "" description: Group is the group of the referent. For example, @@ -4550,6 +4705,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' maxItems: 16 type: array filters: @@ -4562,9 +4721,9 @@ spec: all implementations. - Implementers are encouraged to support extended filters. - Implementation-specific custom filters have no API guarantees across implementations. \n Specifying - a core filter multiple times has unspecified or implementation-specific - conformance. \n All filters are expected to be compatible - with each other except for the URLRewrite and RequestRedirect + the same filter multiple times is not supported unless explicitly + indicated in the filter. \n All filters are expected to be + compatible with each other except for the URLRewrite and RequestRedirect filters, which may not be combined. If an implementation can not support other combinations of filters, they must clearly document that limitation. In cases where incompatible or unsupported @@ -4586,7 +4745,8 @@ spec: extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" + filters. \n This filter can be used multiple times within + the same rule. \n Support: Implementation-specific" properties: group: description: Group is the group of the referent. For @@ -4716,7 +4876,10 @@ spec: description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are - ignored. \n Support: Extended" + ignored. \n This filter can be used multiple times within + the same rule. Note that not all implementations will + be able to support mirroring to multiple backends. \n + Support: Extended" properties: backendRef: description: "BackendRef references a resource where @@ -4798,6 +4961,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' required: - backendRef type: object @@ -4880,6 +5047,23 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when type is + set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when type + is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' port: description: "Port is the port to be used in the value of the `Location` header in the response. \n If @@ -5147,12 +5331,89 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when type is + set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when type + is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' type: object required: - type type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil if the + filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type != + ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type == + ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil if the + filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type != + ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for RequestMirror + filter.type + rule: '!(!has(self.requestMirror) && self.type == ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the filter.type + is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != ''RequestRedirect'')' + - message: filter.requestRedirect must be specified for RequestRedirect + filter.type + rule: '!(!has(self.requestRedirect) && self.type == ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for ExtensionRef + filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' maxItems: 16 type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') && + self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestHeaderModifier'') + ? self.exists_one(f, f.type == ''RequestHeaderModifier'') + : true' + - message: ResponseHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''ResponseHeaderModifier'') + ? self.exists_one(f, f.type == ''ResponseHeaderModifier'') + : true' + - message: RequestRedirect filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestRedirect'') ? self.exists_one(f, + f.type == ''RequestRedirect'') : true' + - message: URLRewrite filter cannot be repeated + rule: 'self.exists(f, f.type == ''URLRewrite'') ? self.exists_one(f, + f.type == ''URLRewrite'') : true' matches: default: - path: @@ -5296,6 +5557,53 @@ spec: maxLength: 1024 type: string type: object + x-kubernetes-validations: + - message: value must be an absolute path and start with + '/' when type one of ['Exact', 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? self.value.startsWith(''/'') : true' + - message: must not contain '//' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''//'') : true' + - message: must not contain '/./' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''/./'') : true' + - message: must not contain '/../' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''/../'') : true' + - message: must not contain '%2f' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''%2f'') : true' + - message: must not contain '%2F' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''%2F'') : true' + - message: must not contain '#' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''#'') : true' + - message: must not end with '/..' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.endsWith(''/..'') : true' + - message: must not end with '/.' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.endsWith(''/.'') : true' + - message: type must be one of ['Exact', 'PathPrefix', + 'RegularExpression'] + rule: self.type == 'Exact' || self.type == 'PathPrefix' + || self.type == 'RegularExpression' + - message: must only contain valid characters (matching + ^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$) + for types ['Exact', 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? self.value.matches(r"""^(?:[-A-Za-z0-9/._~!$&''()*+,;=:@]|[%][0-9a-fA-F]{2})+$""") + : true' queryParams: description: "QueryParams specifies HTTP query parameter matchers. Multiple match values are ANDed together, @@ -5362,6 +5670,46 @@ spec: maxItems: 8 type: array type: object + x-kubernetes-validations: + - message: RequestRedirect filter must not be used together with + backendRefs + rule: '(has(self.backendRefs) && size(self.backendRefs) > 0) ? + (!has(self.filters) || self.filters.all(f, !has(f.requestRedirect))): + true' + - message: When using RequestRedirect filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + ? ((size(self.matches) != 1 || !has(self.matches[0].path) || + self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: When using URLRewrite filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' + - message: Within backendRefs, when using RequestRedirect filter + with path.replacePrefixMatch, exactly one PathPrefix match must + be specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + )) ? ((size(self.matches) != 1 || !has(self.matches[0].path) + || self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: Within backendRefs, When using URLRewrite filter with + path.replacePrefixMatch, exactly one PathPrefix match must be + specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) )) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' maxItems: 16 type: array type: object @@ -5575,7 +5923,7 @@ spec: the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. - \n Support: Extended \n " + \n Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -5830,7 +6178,7 @@ spec: Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n - Support: Extended \n " + Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -5921,7 +6269,8 @@ spec: extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" + filters. \n This filter can be used multiple times + within the same rule. \n Support: Implementation-specific" properties: group: description: Group is the group of the referent. @@ -6059,7 +6408,10 @@ spec: description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from - that destination are ignored. \n Support: Extended" + that destination are ignored. \n This filter can + be used multiple times within the same rule. Note + that not all implementations will be able to support + mirroring to multiple backends. \n Support: Extended" properties: backendRef: description: "BackendRef references a resource @@ -6148,6 +6500,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' required: - backendRef type: object @@ -6237,6 +6593,23 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' port: description: "Port is the port to be used in the value of the `Location` header in the @@ -6525,12 +6898,97 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' type: object required: - type type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil + if the filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type + != ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type + == ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil + if the filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type + != ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for + RequestMirror filter.type + rule: '!(!has(self.requestMirror) && self.type == + ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the + filter.type is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != + ''RequestRedirect'')' + - message: filter.requestRedirect must be specified + for RequestRedirect filter.type + rule: '!(!has(self.requestRedirect) && self.type == + ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for + ExtensionRef filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' maxItems: 16 type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestHeaderModifier'') + ? self.exists_one(f, f.type == ''RequestHeaderModifier'') + : true' + - message: ResponseHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''ResponseHeaderModifier'') + ? self.exists_one(f, f.type == ''ResponseHeaderModifier'') + : true' + - message: RequestRedirect filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestRedirect'') + ? self.exists_one(f, f.type == ''RequestRedirect'') + : true' + - message: URLRewrite filter cannot be repeated + rule: 'self.exists(f, f.type == ''URLRewrite'') ? self.exists_one(f, + f.type == ''URLRewrite'') : true' group: default: "" description: Group is the group of the referent. For example, @@ -6606,6 +7064,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' maxItems: 16 type: array filters: @@ -6618,9 +7080,9 @@ spec: all implementations. - Implementers are encouraged to support extended filters. - Implementation-specific custom filters have no API guarantees across implementations. \n Specifying - a core filter multiple times has unspecified or implementation-specific - conformance. \n All filters are expected to be compatible - with each other except for the URLRewrite and RequestRedirect + the same filter multiple times is not supported unless explicitly + indicated in the filter. \n All filters are expected to be + compatible with each other except for the URLRewrite and RequestRedirect filters, which may not be combined. If an implementation can not support other combinations of filters, they must clearly document that limitation. In cases where incompatible or unsupported @@ -6642,7 +7104,8 @@ spec: extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" + filters. \n This filter can be used multiple times within + the same rule. \n Support: Implementation-specific" properties: group: description: Group is the group of the referent. For @@ -6772,7 +7235,10 @@ spec: description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are - ignored. \n Support: Extended" + ignored. \n This filter can be used multiple times within + the same rule. Note that not all implementations will + be able to support mirroring to multiple backends. \n + Support: Extended" properties: backendRef: description: "BackendRef references a resource where @@ -6854,6 +7320,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' required: - backendRef type: object @@ -6936,6 +7406,23 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when type is + set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when type + is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' port: description: "Port is the port to be used in the value of the `Location` header in the response. \n If @@ -7203,12 +7690,89 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when type is + set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when type + is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' type: object required: - type type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil if the + filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type != + ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type == + ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil if the + filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type != + ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for RequestMirror + filter.type + rule: '!(!has(self.requestMirror) && self.type == ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the filter.type + is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != ''RequestRedirect'')' + - message: filter.requestRedirect must be specified for RequestRedirect + filter.type + rule: '!(!has(self.requestRedirect) && self.type == ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for ExtensionRef + filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' maxItems: 16 type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') && + self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestHeaderModifier'') + ? self.exists_one(f, f.type == ''RequestHeaderModifier'') + : true' + - message: ResponseHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''ResponseHeaderModifier'') + ? self.exists_one(f, f.type == ''ResponseHeaderModifier'') + : true' + - message: RequestRedirect filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestRedirect'') ? self.exists_one(f, + f.type == ''RequestRedirect'') : true' + - message: URLRewrite filter cannot be repeated + rule: 'self.exists(f, f.type == ''URLRewrite'') ? self.exists_one(f, + f.type == ''URLRewrite'') : true' matches: default: - path: @@ -7352,6 +7916,53 @@ spec: maxLength: 1024 type: string type: object + x-kubernetes-validations: + - message: value must be an absolute path and start with + '/' when type one of ['Exact', 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? self.value.startsWith(''/'') : true' + - message: must not contain '//' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''//'') : true' + - message: must not contain '/./' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''/./'') : true' + - message: must not contain '/../' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''/../'') : true' + - message: must not contain '%2f' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''%2f'') : true' + - message: must not contain '%2F' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''%2F'') : true' + - message: must not contain '#' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''#'') : true' + - message: must not end with '/..' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.endsWith(''/..'') : true' + - message: must not end with '/.' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.endsWith(''/.'') : true' + - message: type must be one of ['Exact', 'PathPrefix', + 'RegularExpression'] + rule: self.type == 'Exact' || self.type == 'PathPrefix' + || self.type == 'RegularExpression' + - message: must only contain valid characters (matching + ^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$) + for types ['Exact', 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? self.value.matches(r"""^(?:[-A-Za-z0-9/._~!$&''()*+,;=:@]|[%][0-9a-fA-F]{2})+$""") + : true' queryParams: description: "QueryParams specifies HTTP query parameter matchers. Multiple match values are ANDed together, @@ -7418,6 +8029,46 @@ spec: maxItems: 8 type: array type: object + x-kubernetes-validations: + - message: RequestRedirect filter must not be used together with + backendRefs + rule: '(has(self.backendRefs) && size(self.backendRefs) > 0) ? + (!has(self.filters) || self.filters.all(f, !has(f.requestRedirect))): + true' + - message: When using RequestRedirect filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + ? ((size(self.matches) != 1 || !has(self.matches[0].path) || + self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: When using URLRewrite filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' + - message: Within backendRefs, when using RequestRedirect filter + with path.replacePrefixMatch, exactly one PathPrefix match must + be specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + )) ? ((size(self.matches) != 1 || !has(self.matches[0].path) + || self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: Within backendRefs, When using URLRewrite filter with + path.replacePrefixMatch, exactly one PathPrefix match must be + specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) )) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' maxItems: 16 type: array type: object @@ -7631,7 +8282,7 @@ spec: the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. - \n Support: Extended \n " + \n Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -8137,7 +8788,7 @@ spec: Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n - Support: Extended \n " + Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -8269,6 +8920,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' maxItems: 16 minItems: 1 type: array @@ -8489,7 +9144,7 @@ spec: the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. - \n Support: Extended \n " + \n Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -8755,7 +9410,7 @@ spec: Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n - Support: Extended \n " + Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -8890,6 +9545,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' maxItems: 16 minItems: 1 type: array @@ -9110,7 +9769,7 @@ spec: the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. - \n Support: Extended \n " + \n Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -9330,7 +9989,7 @@ spec: Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n - Support: Extended \n " + Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -9462,6 +10121,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' maxItems: 16 minItems: 1 type: array @@ -9682,7 +10345,7 @@ spec: the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. - \n Support: Extended \n " + \n Support: Extended \n " format: int32 maximum: 65535 minimum: 1 diff --git a/examples/render/contour-gateway-provisioner.yaml b/examples/render/contour-gateway-provisioner.yaml index e9af3ba5362..4a6bdc76ca4 100644 --- a/examples/render/contour-gateway-provisioner.yaml +++ b/examples/render/contour-gateway-provisioner.yaml @@ -8049,6 +8049,9 @@ spec: minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ type: string + x-kubernetes-validations: + - message: Value is immutable + rule: self == oldSelf description: description: Description helps describe a GatewayClass with more details. maxLength: 64 @@ -8103,7 +8106,9 @@ spec: reason: Waiting status: Unknown type: Accepted - description: Status defines the current state of GatewayClass. + description: "Status defines the current state of GatewayClass. \n Implementations + MUST populate status on all GatewayClass resources which specify their + controller name." properties: conditions: default: @@ -8186,27 +8191,6 @@ spec: x-kubernetes-list-map-keys: - type x-kubernetes-list-type: map - routabilities: - description: "Routabilities specifies a list of supported routabilities - offered by the GatewayClass. The first entry in this list will be - the default routability used when Gateways of this class are created. - \n Implementations MAY provide a pre-defined set of GatewayClasses - that limit the routability choices of a Gateway. \n Implementations - MUST populate this list with the GatewayRoutability values that - are supported by this GatewayClass. \n " - items: - description: "GatewayRoutability represents the routability of a - Gateway \n The pre-defined values listed in this package can be - compared semantically. `Public` has a larger scope than `Private`, - while `Private` has a larger scope than `Cluster`. \n Implementations - can define custom routability values by specifying a vendor prefix - followed by a slash '/' and a custom name ie. `dev.example.com/my-routability`." - maxLength: 253 - minLength: 1 - pattern: ^Public|Private|Cluster|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-_]+$ - type: string - maxItems: 8 - type: array type: object required: - spec @@ -8270,6 +8254,9 @@ spec: minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ type: string + x-kubernetes-validations: + - message: Value is immutable + rule: self == oldSelf description: description: Description helps describe a GatewayClass with more details. maxLength: 64 @@ -8324,7 +8311,9 @@ spec: reason: Waiting status: Unknown type: Accepted - description: Status defines the current state of GatewayClass. + description: "Status defines the current state of GatewayClass. \n Implementations + MUST populate status on all GatewayClass resources which specify their + controller name." properties: conditions: default: @@ -8407,27 +8396,6 @@ spec: x-kubernetes-list-map-keys: - type x-kubernetes-list-type: map - routabilities: - description: "Routabilities specifies a list of supported routabilities - offered by the GatewayClass. The first entry in this list will be - the default routability used when Gateways of this class are created. - \n Implementations MAY provide a pre-defined set of GatewayClasses - that limit the routability choices of a Gateway. \n Implementations - MUST populate this list with the GatewayRoutability values that - are supported by this GatewayClass. \n " - items: - description: "GatewayRoutability represents the routability of a - Gateway \n The pre-defined values listed in this package can be - compared semantically. `Public` has a larger scope than `Private`, - while `Private` has a larger scope than `Cluster`. \n Implementations - can define custom routability values by specifying a vendor prefix - followed by a slash '/' and a custom name ie. `dev.example.com/my-routability`." - maxLength: 253 - minLength: 1 - pattern: ^Public|Private|Cluster|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-_]+$ - type: string - maxItems: 8 - type: array type: object required: - spec @@ -8518,10 +8486,24 @@ spec: manner, assigning an appropriate set of Addresses. \n The implementation MUST bind all Listeners to every GatewayAddress that it assigns to the Gateway and add a corresponding entry in GatewayStatus.Addresses. - \n Support: Extended" + \n Support: Extended \n " items: description: GatewayAddress describes an address that can be bound to a Gateway. + oneOf: + - properties: + type: + enum: + - IPAddress + value: + anyOf: + - format: ipv4 + - format: ipv6 + - properties: + type: + not: + enum: + - IPAddress properties: type: default: IPAddress @@ -8540,38 +8522,26 @@ spec: required: - value type: object + x-kubernetes-validations: + - message: Hostname value must only contain valid characters (matching + ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$) + rule: 'self.type == ''Hostname'' ? self.value.matches(''^(\\*\\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$''): + true' maxItems: 16 type: array + x-kubernetes-validations: + - message: IPAddress values must be unique + rule: 'self.all(a1, a1.type == ''IPAddress'' ? self.exists_one(a2, + a2.type == a1.type && a2.value == a1.value) : true )' + - message: Hostname values must be unique + rule: 'self.all(a1, a1.type == ''Hostname'' ? self.exists_one(a2, + a2.type == a1.type && a2.value == a1.value) : true )' gatewayClassName: description: GatewayClassName used for this Gateway. This is the name of a GatewayClass resource. maxLength: 253 minLength: 1 type: string - infrastructure: - description: "Infrastructure defines infrastructure level attributes - about this Gateway instance. \n " - properties: - routability: - description: "Routability allows the Gateway to specify the accessibility - of its addresses. Setting this property will override the default - value defined by the GatewayClass. \n If the desired Gateway - routability is incompatible with the GatewayClass implementations - MUST set the condition `Accepted` to `False` with `Reason` set - to `UnsupportedRoutability`. \n The default value of routability - is implementation specific and MUST remain consistent for Gateways - with the same gatewayClassName \n Implementations MUST clearly - document if they support updates to this field. The default - expectation should be that changes to this field are not supported - unless an implementation specifies otherwise. \n If a Gateway - is mutated but does not support the desired routability it MUST - set the `Accepted` and `Programmed` conditions to `False` with - `Reason` set to `UnsupportedRoutability`." - maxLength: 253 - minLength: 1 - pattern: ^Public|Private|Cluster|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-_]+$ - type: string - type: object listeners: description: "Listeners associated with this Gateway. Listeners define logical endpoints that are bound on this Gateway's addresses. At @@ -8904,6 +8874,11 @@ spec: maxProperties: 16 type: object type: object + x-kubernetes-validations: + - message: certificateRefs must be set and not empty when TLSModeType + is Terminate + rule: 'self.mode == ''Terminate'' ? size(self.certificateRefs) + > 0 : true' required: - name - port @@ -8915,6 +8890,23 @@ spec: x-kubernetes-list-map-keys: - name x-kubernetes-list-type: map + x-kubernetes-validations: + - message: tls must be set for protocols ['HTTPS', 'TLS'] + rule: 'self.all(l, l.protocol in [''HTTPS'', ''TLS''] ? has(l.tls) + : true)' + - message: tls must be empty for protocols ['HTTP', 'TCP', 'UDP'] + rule: 'self.all(l, l.protocol in [''HTTP'', ''TCP'', ''UDP''] ? + !has(l.tls) : true)' + - message: hostname must be empty for protocols ['TCP', 'UDP'] + rule: 'self.all(l, l.protocol in [''TCP'', ''UDP''] ? (!has(l.hostname) + || l.hostname == '''') : true)' + - message: Listener name must be unique within the Gateway + rule: self.all(l1, self.exists_one(l2, l1.name == l2.name)) + - message: Combination of port, protocol and hostname must be unique + for each listener + rule: 'self.all(l1, self.exists_one(l2, l1.port == l2.port && l1.protocol + == l2.protocol && (has(l1.hostname) && has(l2.hostname) ? l1.hostname + == l2.hostname : true)))' required: - gatewayClassName - listeners @@ -8938,26 +8930,25 @@ spec: description: "Addresses lists the IP addresses that have actually been bound to the Gateway. These addresses may differ from the addresses in the Spec, e.g. if the Gateway automatically assigns an address - from a reserved pool. \n Implementations that support GatewayRoutability - MUST include an address that has the same routable semantics as - defined in the Gateway spec. \n Implementations MAY add additional - addresses in status, but they MUST be semantically less than the - scope of the requested scope. For example if a user requests a `Private` - routable Gateway then an additional address MAY have a routability - of `Cluster` but MUST NOT include `Public`." + from a reserved pool. \n " items: description: GatewayStatusAddress describes an address that is bound to a Gateway. + oneOf: + - properties: + type: + enum: + - IPAddress + value: + anyOf: + - format: ipv4 + - format: ipv6 + - properties: + type: + not: + enum: + - IPAddress properties: - routability: - description: "Routability specifies the routable bounds of this - address Predefined values are: 'Private', 'Public', Cluster - Other values MUST have a vendor prefix. \n Implementations - that support Routability MUST populate this field \n " - maxLength: 253 - minLength: 1 - pattern: ^Public|Private|Cluster|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-_]+$ - type: string type: default: IPAddress description: Type of the address. @@ -8975,6 +8966,11 @@ spec: required: - value type: object + x-kubernetes-validations: + - message: Hostname value must only contain valid characters (matching + ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$) + rule: 'self.type == ''Hostname'' ? self.value.matches(''^(\\*\\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$''): + true' maxItems: 16 type: array conditions: @@ -9263,10 +9259,24 @@ spec: manner, assigning an appropriate set of Addresses. \n The implementation MUST bind all Listeners to every GatewayAddress that it assigns to the Gateway and add a corresponding entry in GatewayStatus.Addresses. - \n Support: Extended" + \n Support: Extended \n " items: description: GatewayAddress describes an address that can be bound to a Gateway. + oneOf: + - properties: + type: + enum: + - IPAddress + value: + anyOf: + - format: ipv4 + - format: ipv6 + - properties: + type: + not: + enum: + - IPAddress properties: type: default: IPAddress @@ -9285,38 +9295,26 @@ spec: required: - value type: object + x-kubernetes-validations: + - message: Hostname value must only contain valid characters (matching + ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$) + rule: 'self.type == ''Hostname'' ? self.value.matches(''^(\\*\\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$''): + true' maxItems: 16 type: array + x-kubernetes-validations: + - message: IPAddress values must be unique + rule: 'self.all(a1, a1.type == ''IPAddress'' ? self.exists_one(a2, + a2.type == a1.type && a2.value == a1.value) : true )' + - message: Hostname values must be unique + rule: 'self.all(a1, a1.type == ''Hostname'' ? self.exists_one(a2, + a2.type == a1.type && a2.value == a1.value) : true )' gatewayClassName: description: GatewayClassName used for this Gateway. This is the name of a GatewayClass resource. maxLength: 253 minLength: 1 type: string - infrastructure: - description: "Infrastructure defines infrastructure level attributes - about this Gateway instance. \n " - properties: - routability: - description: "Routability allows the Gateway to specify the accessibility - of its addresses. Setting this property will override the default - value defined by the GatewayClass. \n If the desired Gateway - routability is incompatible with the GatewayClass implementations - MUST set the condition `Accepted` to `False` with `Reason` set - to `UnsupportedRoutability`. \n The default value of routability - is implementation specific and MUST remain consistent for Gateways - with the same gatewayClassName \n Implementations MUST clearly - document if they support updates to this field. The default - expectation should be that changes to this field are not supported - unless an implementation specifies otherwise. \n If a Gateway - is mutated but does not support the desired routability it MUST - set the `Accepted` and `Programmed` conditions to `False` with - `Reason` set to `UnsupportedRoutability`." - maxLength: 253 - minLength: 1 - pattern: ^Public|Private|Cluster|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-_]+$ - type: string - type: object listeners: description: "Listeners associated with this Gateway. Listeners define logical endpoints that are bound on this Gateway's addresses. At @@ -9649,6 +9647,11 @@ spec: maxProperties: 16 type: object type: object + x-kubernetes-validations: + - message: certificateRefs must be set and not empty when TLSModeType + is Terminate + rule: 'self.mode == ''Terminate'' ? size(self.certificateRefs) + > 0 : true' required: - name - port @@ -9660,6 +9663,23 @@ spec: x-kubernetes-list-map-keys: - name x-kubernetes-list-type: map + x-kubernetes-validations: + - message: tls must be set for protocols ['HTTPS', 'TLS'] + rule: 'self.all(l, l.protocol in [''HTTPS'', ''TLS''] ? has(l.tls) + : true)' + - message: tls must be empty for protocols ['HTTP', 'TCP', 'UDP'] + rule: 'self.all(l, l.protocol in [''HTTP'', ''TCP'', ''UDP''] ? + !has(l.tls) : true)' + - message: hostname must be empty for protocols ['TCP', 'UDP'] + rule: 'self.all(l, l.protocol in [''TCP'', ''UDP''] ? (!has(l.hostname) + || l.hostname == '''') : true)' + - message: Listener name must be unique within the Gateway + rule: self.all(l1, self.exists_one(l2, l1.name == l2.name)) + - message: Combination of port, protocol and hostname must be unique + for each listener + rule: 'self.all(l1, self.exists_one(l2, l1.port == l2.port && l1.protocol + == l2.protocol && (has(l1.hostname) && has(l2.hostname) ? l1.hostname + == l2.hostname : true)))' required: - gatewayClassName - listeners @@ -9683,26 +9703,25 @@ spec: description: "Addresses lists the IP addresses that have actually been bound to the Gateway. These addresses may differ from the addresses in the Spec, e.g. if the Gateway automatically assigns an address - from a reserved pool. \n Implementations that support GatewayRoutability - MUST include an address that has the same routable semantics as - defined in the Gateway spec. \n Implementations MAY add additional - addresses in status, but they MUST be semantically less than the - scope of the requested scope. For example if a user requests a `Private` - routable Gateway then an additional address MAY have a routability - of `Cluster` but MUST NOT include `Public`." + from a reserved pool. \n " items: description: GatewayStatusAddress describes an address that is bound to a Gateway. + oneOf: + - properties: + type: + enum: + - IPAddress + value: + anyOf: + - format: ipv4 + - format: ipv6 + - properties: + type: + not: + enum: + - IPAddress properties: - routability: - description: "Routability specifies the routable bounds of this - address Predefined values are: 'Private', 'Public', Cluster - Other values MUST have a vendor prefix. \n Implementations - that support Routability MUST populate this field \n " - maxLength: 253 - minLength: 1 - pattern: ^Public|Private|Cluster|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-_]+$ - type: string type: default: IPAddress description: Type of the address. @@ -9720,6 +9739,11 @@ spec: required: - value type: object + x-kubernetes-validations: + - message: Hostname value must only contain valid characters (matching + ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$) + rule: 'self.type == ''Hostname'' ? self.value.matches(''^(\\*\\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$''): + true' maxItems: 16 type: array conditions: @@ -10208,7 +10232,7 @@ spec: Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n - Support: Extended \n " + Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -10298,7 +10322,9 @@ spec: extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" + filters. \n Support: Implementation-specific \n + This filter can be used multiple times within + the same rule." properties: group: description: Group is the group of the referent. @@ -10436,7 +10462,10 @@ spec: description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from - that destination are ignored. \n Support: Extended" + that destination are ignored. \n This filter can + be used multiple times within the same rule. Note + that not all implementations will be able to support + mirroring to multiple backends. \n Support: Extended" properties: backendRef: description: "BackendRef references a resource @@ -10525,6 +10554,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' required: - backendRef type: object @@ -10748,6 +10781,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' maxItems: 16 type: array filters: @@ -10760,8 +10797,8 @@ spec: all implementations that support GRPCRoute. - Implementers are encouraged to support extended filters. - Implementation-specific custom filters have no API guarantees across implementations. - \n Specifying a core filter multiple times has unspecified - or implementation-specific conformance. \n If an implementation + \n Specifying the same filter multiple times is not supported + unless explicitly indicated in the filter. \n If an implementation can not support a combinations of filters, they must clearly document that limitation. In cases where incompatible or unsupported filters are specified and cause the `Accepted` condition to @@ -10782,7 +10819,8 @@ spec: extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" + filters. \n Support: Implementation-specific \n This + filter can be used multiple times within the same rule." properties: group: description: Group is the group of the referent. For @@ -10912,7 +10950,10 @@ spec: description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are - ignored. \n Support: Extended" + ignored. \n This filter can be used multiple times within + the same rule. Note that not all implementations will + be able to support mirroring to multiple backends. \n + Support: Extended" properties: backendRef: description: "BackendRef references a resource where @@ -10994,6 +11035,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' required: - backendRef type: object @@ -11462,7 +11507,7 @@ spec: the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. - \n Support: Extended \n " + \n Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -11745,7 +11790,7 @@ spec: Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n - Support: Extended \n " + Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -11836,7 +11881,8 @@ spec: extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" + filters. \n This filter can be used multiple times + within the same rule. \n Support: Implementation-specific" properties: group: description: Group is the group of the referent. @@ -11974,7 +12020,10 @@ spec: description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from - that destination are ignored. \n Support: Extended" + that destination are ignored. \n This filter can + be used multiple times within the same rule. Note + that not all implementations will be able to support + mirroring to multiple backends. \n Support: Extended" properties: backendRef: description: "BackendRef references a resource @@ -12063,6 +12112,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' required: - backendRef type: object @@ -12152,6 +12205,23 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' port: description: "Port is the port to be used in the value of the `Location` header in the @@ -12440,12 +12510,97 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' type: object required: - type type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil + if the filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type + != ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type + == ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil + if the filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type + != ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for + RequestMirror filter.type + rule: '!(!has(self.requestMirror) && self.type == + ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the + filter.type is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != + ''RequestRedirect'')' + - message: filter.requestRedirect must be specified + for RequestRedirect filter.type + rule: '!(!has(self.requestRedirect) && self.type == + ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for + ExtensionRef filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' maxItems: 16 type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestHeaderModifier'') + ? self.exists_one(f, f.type == ''RequestHeaderModifier'') + : true' + - message: ResponseHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''ResponseHeaderModifier'') + ? self.exists_one(f, f.type == ''ResponseHeaderModifier'') + : true' + - message: RequestRedirect filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestRedirect'') + ? self.exists_one(f, f.type == ''RequestRedirect'') + : true' + - message: URLRewrite filter cannot be repeated + rule: 'self.exists(f, f.type == ''URLRewrite'') ? self.exists_one(f, + f.type == ''URLRewrite'') : true' group: default: "" description: Group is the group of the referent. For example, @@ -12521,6 +12676,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' maxItems: 16 type: array filters: @@ -12533,9 +12692,9 @@ spec: all implementations. - Implementers are encouraged to support extended filters. - Implementation-specific custom filters have no API guarantees across implementations. \n Specifying - a core filter multiple times has unspecified or implementation-specific - conformance. \n All filters are expected to be compatible - with each other except for the URLRewrite and RequestRedirect + the same filter multiple times is not supported unless explicitly + indicated in the filter. \n All filters are expected to be + compatible with each other except for the URLRewrite and RequestRedirect filters, which may not be combined. If an implementation can not support other combinations of filters, they must clearly document that limitation. In cases where incompatible or unsupported @@ -12557,7 +12716,8 @@ spec: extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" + filters. \n This filter can be used multiple times within + the same rule. \n Support: Implementation-specific" properties: group: description: Group is the group of the referent. For @@ -12687,7 +12847,10 @@ spec: description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are - ignored. \n Support: Extended" + ignored. \n This filter can be used multiple times within + the same rule. Note that not all implementations will + be able to support mirroring to multiple backends. \n + Support: Extended" properties: backendRef: description: "BackendRef references a resource where @@ -12769,6 +12932,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' required: - backendRef type: object @@ -12851,6 +13018,23 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when type is + set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when type + is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' port: description: "Port is the port to be used in the value of the `Location` header in the response. \n If @@ -13118,12 +13302,89 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when type is + set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when type + is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' type: object required: - type type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil if the + filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type != + ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type == + ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil if the + filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type != + ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for RequestMirror + filter.type + rule: '!(!has(self.requestMirror) && self.type == ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the filter.type + is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != ''RequestRedirect'')' + - message: filter.requestRedirect must be specified for RequestRedirect + filter.type + rule: '!(!has(self.requestRedirect) && self.type == ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for ExtensionRef + filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' maxItems: 16 type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') && + self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestHeaderModifier'') + ? self.exists_one(f, f.type == ''RequestHeaderModifier'') + : true' + - message: ResponseHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''ResponseHeaderModifier'') + ? self.exists_one(f, f.type == ''ResponseHeaderModifier'') + : true' + - message: RequestRedirect filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestRedirect'') ? self.exists_one(f, + f.type == ''RequestRedirect'') : true' + - message: URLRewrite filter cannot be repeated + rule: 'self.exists(f, f.type == ''URLRewrite'') ? self.exists_one(f, + f.type == ''URLRewrite'') : true' matches: default: - path: @@ -13267,6 +13528,53 @@ spec: maxLength: 1024 type: string type: object + x-kubernetes-validations: + - message: value must be an absolute path and start with + '/' when type one of ['Exact', 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? self.value.startsWith(''/'') : true' + - message: must not contain '//' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''//'') : true' + - message: must not contain '/./' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''/./'') : true' + - message: must not contain '/../' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''/../'') : true' + - message: must not contain '%2f' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''%2f'') : true' + - message: must not contain '%2F' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''%2F'') : true' + - message: must not contain '#' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''#'') : true' + - message: must not end with '/..' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.endsWith(''/..'') : true' + - message: must not end with '/.' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.endsWith(''/.'') : true' + - message: type must be one of ['Exact', 'PathPrefix', + 'RegularExpression'] + rule: self.type == 'Exact' || self.type == 'PathPrefix' + || self.type == 'RegularExpression' + - message: must only contain valid characters (matching + ^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$) + for types ['Exact', 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? self.value.matches(r"""^(?:[-A-Za-z0-9/._~!$&''()*+,;=:@]|[%][0-9a-fA-F]{2})+$""") + : true' queryParams: description: "QueryParams specifies HTTP query parameter matchers. Multiple match values are ANDed together, @@ -13333,6 +13641,46 @@ spec: maxItems: 8 type: array type: object + x-kubernetes-validations: + - message: RequestRedirect filter must not be used together with + backendRefs + rule: '(has(self.backendRefs) && size(self.backendRefs) > 0) ? + (!has(self.filters) || self.filters.all(f, !has(f.requestRedirect))): + true' + - message: When using RequestRedirect filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + ? ((size(self.matches) != 1 || !has(self.matches[0].path) || + self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: When using URLRewrite filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' + - message: Within backendRefs, when using RequestRedirect filter + with path.replacePrefixMatch, exactly one PathPrefix match must + be specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + )) ? ((size(self.matches) != 1 || !has(self.matches[0].path) + || self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: Within backendRefs, When using URLRewrite filter with + path.replacePrefixMatch, exactly one PathPrefix match must be + specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) )) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' maxItems: 16 type: array type: object @@ -13546,7 +13894,7 @@ spec: the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. - \n Support: Extended \n " + \n Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -13801,7 +14149,7 @@ spec: Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n - Support: Extended \n " + Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -13892,7 +14240,8 @@ spec: extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" + filters. \n This filter can be used multiple times + within the same rule. \n Support: Implementation-specific" properties: group: description: Group is the group of the referent. @@ -14030,7 +14379,10 @@ spec: description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from - that destination are ignored. \n Support: Extended" + that destination are ignored. \n This filter can + be used multiple times within the same rule. Note + that not all implementations will be able to support + mirroring to multiple backends. \n Support: Extended" properties: backendRef: description: "BackendRef references a resource @@ -14119,6 +14471,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' required: - backendRef type: object @@ -14208,6 +14564,23 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' port: description: "Port is the port to be used in the value of the `Location` header in the @@ -14496,12 +14869,97 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' type: object required: - type type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil + if the filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type + != ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type + == ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil + if the filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type + != ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for + RequestMirror filter.type + rule: '!(!has(self.requestMirror) && self.type == + ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the + filter.type is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != + ''RequestRedirect'')' + - message: filter.requestRedirect must be specified + for RequestRedirect filter.type + rule: '!(!has(self.requestRedirect) && self.type == + ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for + ExtensionRef filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' maxItems: 16 type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestHeaderModifier'') + ? self.exists_one(f, f.type == ''RequestHeaderModifier'') + : true' + - message: ResponseHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''ResponseHeaderModifier'') + ? self.exists_one(f, f.type == ''ResponseHeaderModifier'') + : true' + - message: RequestRedirect filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestRedirect'') + ? self.exists_one(f, f.type == ''RequestRedirect'') + : true' + - message: URLRewrite filter cannot be repeated + rule: 'self.exists(f, f.type == ''URLRewrite'') ? self.exists_one(f, + f.type == ''URLRewrite'') : true' group: default: "" description: Group is the group of the referent. For example, @@ -14577,6 +15035,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' maxItems: 16 type: array filters: @@ -14589,9 +15051,9 @@ spec: all implementations. - Implementers are encouraged to support extended filters. - Implementation-specific custom filters have no API guarantees across implementations. \n Specifying - a core filter multiple times has unspecified or implementation-specific - conformance. \n All filters are expected to be compatible - with each other except for the URLRewrite and RequestRedirect + the same filter multiple times is not supported unless explicitly + indicated in the filter. \n All filters are expected to be + compatible with each other except for the URLRewrite and RequestRedirect filters, which may not be combined. If an implementation can not support other combinations of filters, they must clearly document that limitation. In cases where incompatible or unsupported @@ -14613,7 +15075,8 @@ spec: extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" + filters. \n This filter can be used multiple times within + the same rule. \n Support: Implementation-specific" properties: group: description: Group is the group of the referent. For @@ -14743,7 +15206,10 @@ spec: description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are - ignored. \n Support: Extended" + ignored. \n This filter can be used multiple times within + the same rule. Note that not all implementations will + be able to support mirroring to multiple backends. \n + Support: Extended" properties: backendRef: description: "BackendRef references a resource where @@ -14825,6 +15291,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' required: - backendRef type: object @@ -14907,6 +15377,23 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when type is + set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when type + is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' port: description: "Port is the port to be used in the value of the `Location` header in the response. \n If @@ -15174,12 +15661,89 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when type is + set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when type + is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' type: object required: - type type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil if the + filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type != + ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type == + ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil if the + filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type != + ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for RequestMirror + filter.type + rule: '!(!has(self.requestMirror) && self.type == ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the filter.type + is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != ''RequestRedirect'')' + - message: filter.requestRedirect must be specified for RequestRedirect + filter.type + rule: '!(!has(self.requestRedirect) && self.type == ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for ExtensionRef + filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' maxItems: 16 type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') && + self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestHeaderModifier'') + ? self.exists_one(f, f.type == ''RequestHeaderModifier'') + : true' + - message: ResponseHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''ResponseHeaderModifier'') + ? self.exists_one(f, f.type == ''ResponseHeaderModifier'') + : true' + - message: RequestRedirect filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestRedirect'') ? self.exists_one(f, + f.type == ''RequestRedirect'') : true' + - message: URLRewrite filter cannot be repeated + rule: 'self.exists(f, f.type == ''URLRewrite'') ? self.exists_one(f, + f.type == ''URLRewrite'') : true' matches: default: - path: @@ -15323,6 +15887,53 @@ spec: maxLength: 1024 type: string type: object + x-kubernetes-validations: + - message: value must be an absolute path and start with + '/' when type one of ['Exact', 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? self.value.startsWith(''/'') : true' + - message: must not contain '//' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''//'') : true' + - message: must not contain '/./' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''/./'') : true' + - message: must not contain '/../' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''/../'') : true' + - message: must not contain '%2f' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''%2f'') : true' + - message: must not contain '%2F' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''%2F'') : true' + - message: must not contain '#' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''#'') : true' + - message: must not end with '/..' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.endsWith(''/..'') : true' + - message: must not end with '/.' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.endsWith(''/.'') : true' + - message: type must be one of ['Exact', 'PathPrefix', + 'RegularExpression'] + rule: self.type == 'Exact' || self.type == 'PathPrefix' + || self.type == 'RegularExpression' + - message: must only contain valid characters (matching + ^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$) + for types ['Exact', 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? self.value.matches(r"""^(?:[-A-Za-z0-9/._~!$&''()*+,;=:@]|[%][0-9a-fA-F]{2})+$""") + : true' queryParams: description: "QueryParams specifies HTTP query parameter matchers. Multiple match values are ANDed together, @@ -15389,6 +16000,46 @@ spec: maxItems: 8 type: array type: object + x-kubernetes-validations: + - message: RequestRedirect filter must not be used together with + backendRefs + rule: '(has(self.backendRefs) && size(self.backendRefs) > 0) ? + (!has(self.filters) || self.filters.all(f, !has(f.requestRedirect))): + true' + - message: When using RequestRedirect filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + ? ((size(self.matches) != 1 || !has(self.matches[0].path) || + self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: When using URLRewrite filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' + - message: Within backendRefs, when using RequestRedirect filter + with path.replacePrefixMatch, exactly one PathPrefix match must + be specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + )) ? ((size(self.matches) != 1 || !has(self.matches[0].path) + || self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: Within backendRefs, When using URLRewrite filter with + path.replacePrefixMatch, exactly one PathPrefix match must be + specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) )) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' maxItems: 16 type: array type: object @@ -15602,7 +16253,7 @@ spec: the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. - \n Support: Extended \n " + \n Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -16108,7 +16759,7 @@ spec: Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n - Support: Extended \n " + Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -16240,6 +16891,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' maxItems: 16 minItems: 1 type: array @@ -16460,7 +17115,7 @@ spec: the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. - \n Support: Extended \n " + \n Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -16726,7 +17381,7 @@ spec: Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n - Support: Extended \n " + Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -16861,6 +17516,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' maxItems: 16 minItems: 1 type: array @@ -17081,7 +17740,7 @@ spec: the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. - \n Support: Extended \n " + \n Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -17301,7 +17960,7 @@ spec: Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n - Support: Extended \n " + Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -17433,6 +18092,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' maxItems: 16 minItems: 1 type: array @@ -17653,7 +18316,7 @@ spec: the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. - \n Support: Extended \n " + \n Support: Extended \n " format: int32 maximum: 65535 minimum: 1 diff --git a/examples/render/contour-gateway.yaml b/examples/render/contour-gateway.yaml index 3fdf0661a1f..a3905b693c4 100644 --- a/examples/render/contour-gateway.yaml +++ b/examples/render/contour-gateway.yaml @@ -8752,6 +8752,9 @@ spec: minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ type: string + x-kubernetes-validations: + - message: Value is immutable + rule: self == oldSelf description: description: Description helps describe a GatewayClass with more details. maxLength: 64 @@ -8806,7 +8809,9 @@ spec: reason: Waiting status: Unknown type: Accepted - description: Status defines the current state of GatewayClass. + description: "Status defines the current state of GatewayClass. \n Implementations + MUST populate status on all GatewayClass resources which specify their + controller name." properties: conditions: default: @@ -8889,27 +8894,6 @@ spec: x-kubernetes-list-map-keys: - type x-kubernetes-list-type: map - routabilities: - description: "Routabilities specifies a list of supported routabilities - offered by the GatewayClass. The first entry in this list will be - the default routability used when Gateways of this class are created. - \n Implementations MAY provide a pre-defined set of GatewayClasses - that limit the routability choices of a Gateway. \n Implementations - MUST populate this list with the GatewayRoutability values that - are supported by this GatewayClass. \n " - items: - description: "GatewayRoutability represents the routability of a - Gateway \n The pre-defined values listed in this package can be - compared semantically. `Public` has a larger scope than `Private`, - while `Private` has a larger scope than `Cluster`. \n Implementations - can define custom routability values by specifying a vendor prefix - followed by a slash '/' and a custom name ie. `dev.example.com/my-routability`." - maxLength: 253 - minLength: 1 - pattern: ^Public|Private|Cluster|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-_]+$ - type: string - maxItems: 8 - type: array type: object required: - spec @@ -8973,6 +8957,9 @@ spec: minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ type: string + x-kubernetes-validations: + - message: Value is immutable + rule: self == oldSelf description: description: Description helps describe a GatewayClass with more details. maxLength: 64 @@ -9027,7 +9014,9 @@ spec: reason: Waiting status: Unknown type: Accepted - description: Status defines the current state of GatewayClass. + description: "Status defines the current state of GatewayClass. \n Implementations + MUST populate status on all GatewayClass resources which specify their + controller name." properties: conditions: default: @@ -9110,27 +9099,6 @@ spec: x-kubernetes-list-map-keys: - type x-kubernetes-list-type: map - routabilities: - description: "Routabilities specifies a list of supported routabilities - offered by the GatewayClass. The first entry in this list will be - the default routability used when Gateways of this class are created. - \n Implementations MAY provide a pre-defined set of GatewayClasses - that limit the routability choices of a Gateway. \n Implementations - MUST populate this list with the GatewayRoutability values that - are supported by this GatewayClass. \n " - items: - description: "GatewayRoutability represents the routability of a - Gateway \n The pre-defined values listed in this package can be - compared semantically. `Public` has a larger scope than `Private`, - while `Private` has a larger scope than `Cluster`. \n Implementations - can define custom routability values by specifying a vendor prefix - followed by a slash '/' and a custom name ie. `dev.example.com/my-routability`." - maxLength: 253 - minLength: 1 - pattern: ^Public|Private|Cluster|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-_]+$ - type: string - maxItems: 8 - type: array type: object required: - spec @@ -9221,10 +9189,24 @@ spec: manner, assigning an appropriate set of Addresses. \n The implementation MUST bind all Listeners to every GatewayAddress that it assigns to the Gateway and add a corresponding entry in GatewayStatus.Addresses. - \n Support: Extended" + \n Support: Extended \n " items: description: GatewayAddress describes an address that can be bound to a Gateway. + oneOf: + - properties: + type: + enum: + - IPAddress + value: + anyOf: + - format: ipv4 + - format: ipv6 + - properties: + type: + not: + enum: + - IPAddress properties: type: default: IPAddress @@ -9243,38 +9225,26 @@ spec: required: - value type: object + x-kubernetes-validations: + - message: Hostname value must only contain valid characters (matching + ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$) + rule: 'self.type == ''Hostname'' ? self.value.matches(''^(\\*\\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$''): + true' maxItems: 16 type: array + x-kubernetes-validations: + - message: IPAddress values must be unique + rule: 'self.all(a1, a1.type == ''IPAddress'' ? self.exists_one(a2, + a2.type == a1.type && a2.value == a1.value) : true )' + - message: Hostname values must be unique + rule: 'self.all(a1, a1.type == ''Hostname'' ? self.exists_one(a2, + a2.type == a1.type && a2.value == a1.value) : true )' gatewayClassName: description: GatewayClassName used for this Gateway. This is the name of a GatewayClass resource. maxLength: 253 minLength: 1 type: string - infrastructure: - description: "Infrastructure defines infrastructure level attributes - about this Gateway instance. \n " - properties: - routability: - description: "Routability allows the Gateway to specify the accessibility - of its addresses. Setting this property will override the default - value defined by the GatewayClass. \n If the desired Gateway - routability is incompatible with the GatewayClass implementations - MUST set the condition `Accepted` to `False` with `Reason` set - to `UnsupportedRoutability`. \n The default value of routability - is implementation specific and MUST remain consistent for Gateways - with the same gatewayClassName \n Implementations MUST clearly - document if they support updates to this field. The default - expectation should be that changes to this field are not supported - unless an implementation specifies otherwise. \n If a Gateway - is mutated but does not support the desired routability it MUST - set the `Accepted` and `Programmed` conditions to `False` with - `Reason` set to `UnsupportedRoutability`." - maxLength: 253 - minLength: 1 - pattern: ^Public|Private|Cluster|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-_]+$ - type: string - type: object listeners: description: "Listeners associated with this Gateway. Listeners define logical endpoints that are bound on this Gateway's addresses. At @@ -9607,6 +9577,11 @@ spec: maxProperties: 16 type: object type: object + x-kubernetes-validations: + - message: certificateRefs must be set and not empty when TLSModeType + is Terminate + rule: 'self.mode == ''Terminate'' ? size(self.certificateRefs) + > 0 : true' required: - name - port @@ -9618,6 +9593,23 @@ spec: x-kubernetes-list-map-keys: - name x-kubernetes-list-type: map + x-kubernetes-validations: + - message: tls must be set for protocols ['HTTPS', 'TLS'] + rule: 'self.all(l, l.protocol in [''HTTPS'', ''TLS''] ? has(l.tls) + : true)' + - message: tls must be empty for protocols ['HTTP', 'TCP', 'UDP'] + rule: 'self.all(l, l.protocol in [''HTTP'', ''TCP'', ''UDP''] ? + !has(l.tls) : true)' + - message: hostname must be empty for protocols ['TCP', 'UDP'] + rule: 'self.all(l, l.protocol in [''TCP'', ''UDP''] ? (!has(l.hostname) + || l.hostname == '''') : true)' + - message: Listener name must be unique within the Gateway + rule: self.all(l1, self.exists_one(l2, l1.name == l2.name)) + - message: Combination of port, protocol and hostname must be unique + for each listener + rule: 'self.all(l1, self.exists_one(l2, l1.port == l2.port && l1.protocol + == l2.protocol && (has(l1.hostname) && has(l2.hostname) ? l1.hostname + == l2.hostname : true)))' required: - gatewayClassName - listeners @@ -9641,26 +9633,25 @@ spec: description: "Addresses lists the IP addresses that have actually been bound to the Gateway. These addresses may differ from the addresses in the Spec, e.g. if the Gateway automatically assigns an address - from a reserved pool. \n Implementations that support GatewayRoutability - MUST include an address that has the same routable semantics as - defined in the Gateway spec. \n Implementations MAY add additional - addresses in status, but they MUST be semantically less than the - scope of the requested scope. For example if a user requests a `Private` - routable Gateway then an additional address MAY have a routability - of `Cluster` but MUST NOT include `Public`." + from a reserved pool. \n " items: description: GatewayStatusAddress describes an address that is bound to a Gateway. + oneOf: + - properties: + type: + enum: + - IPAddress + value: + anyOf: + - format: ipv4 + - format: ipv6 + - properties: + type: + not: + enum: + - IPAddress properties: - routability: - description: "Routability specifies the routable bounds of this - address Predefined values are: 'Private', 'Public', Cluster - Other values MUST have a vendor prefix. \n Implementations - that support Routability MUST populate this field \n " - maxLength: 253 - minLength: 1 - pattern: ^Public|Private|Cluster|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-_]+$ - type: string type: default: IPAddress description: Type of the address. @@ -9678,6 +9669,11 @@ spec: required: - value type: object + x-kubernetes-validations: + - message: Hostname value must only contain valid characters (matching + ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$) + rule: 'self.type == ''Hostname'' ? self.value.matches(''^(\\*\\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$''): + true' maxItems: 16 type: array conditions: @@ -9966,10 +9962,24 @@ spec: manner, assigning an appropriate set of Addresses. \n The implementation MUST bind all Listeners to every GatewayAddress that it assigns to the Gateway and add a corresponding entry in GatewayStatus.Addresses. - \n Support: Extended" + \n Support: Extended \n " items: description: GatewayAddress describes an address that can be bound to a Gateway. + oneOf: + - properties: + type: + enum: + - IPAddress + value: + anyOf: + - format: ipv4 + - format: ipv6 + - properties: + type: + not: + enum: + - IPAddress properties: type: default: IPAddress @@ -9988,38 +9998,26 @@ spec: required: - value type: object + x-kubernetes-validations: + - message: Hostname value must only contain valid characters (matching + ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$) + rule: 'self.type == ''Hostname'' ? self.value.matches(''^(\\*\\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$''): + true' maxItems: 16 type: array + x-kubernetes-validations: + - message: IPAddress values must be unique + rule: 'self.all(a1, a1.type == ''IPAddress'' ? self.exists_one(a2, + a2.type == a1.type && a2.value == a1.value) : true )' + - message: Hostname values must be unique + rule: 'self.all(a1, a1.type == ''Hostname'' ? self.exists_one(a2, + a2.type == a1.type && a2.value == a1.value) : true )' gatewayClassName: description: GatewayClassName used for this Gateway. This is the name of a GatewayClass resource. maxLength: 253 minLength: 1 type: string - infrastructure: - description: "Infrastructure defines infrastructure level attributes - about this Gateway instance. \n " - properties: - routability: - description: "Routability allows the Gateway to specify the accessibility - of its addresses. Setting this property will override the default - value defined by the GatewayClass. \n If the desired Gateway - routability is incompatible with the GatewayClass implementations - MUST set the condition `Accepted` to `False` with `Reason` set - to `UnsupportedRoutability`. \n The default value of routability - is implementation specific and MUST remain consistent for Gateways - with the same gatewayClassName \n Implementations MUST clearly - document if they support updates to this field. The default - expectation should be that changes to this field are not supported - unless an implementation specifies otherwise. \n If a Gateway - is mutated but does not support the desired routability it MUST - set the `Accepted` and `Programmed` conditions to `False` with - `Reason` set to `UnsupportedRoutability`." - maxLength: 253 - minLength: 1 - pattern: ^Public|Private|Cluster|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-_]+$ - type: string - type: object listeners: description: "Listeners associated with this Gateway. Listeners define logical endpoints that are bound on this Gateway's addresses. At @@ -10352,6 +10350,11 @@ spec: maxProperties: 16 type: object type: object + x-kubernetes-validations: + - message: certificateRefs must be set and not empty when TLSModeType + is Terminate + rule: 'self.mode == ''Terminate'' ? size(self.certificateRefs) + > 0 : true' required: - name - port @@ -10363,6 +10366,23 @@ spec: x-kubernetes-list-map-keys: - name x-kubernetes-list-type: map + x-kubernetes-validations: + - message: tls must be set for protocols ['HTTPS', 'TLS'] + rule: 'self.all(l, l.protocol in [''HTTPS'', ''TLS''] ? has(l.tls) + : true)' + - message: tls must be empty for protocols ['HTTP', 'TCP', 'UDP'] + rule: 'self.all(l, l.protocol in [''HTTP'', ''TCP'', ''UDP''] ? + !has(l.tls) : true)' + - message: hostname must be empty for protocols ['TCP', 'UDP'] + rule: 'self.all(l, l.protocol in [''TCP'', ''UDP''] ? (!has(l.hostname) + || l.hostname == '''') : true)' + - message: Listener name must be unique within the Gateway + rule: self.all(l1, self.exists_one(l2, l1.name == l2.name)) + - message: Combination of port, protocol and hostname must be unique + for each listener + rule: 'self.all(l1, self.exists_one(l2, l1.port == l2.port && l1.protocol + == l2.protocol && (has(l1.hostname) && has(l2.hostname) ? l1.hostname + == l2.hostname : true)))' required: - gatewayClassName - listeners @@ -10386,26 +10406,25 @@ spec: description: "Addresses lists the IP addresses that have actually been bound to the Gateway. These addresses may differ from the addresses in the Spec, e.g. if the Gateway automatically assigns an address - from a reserved pool. \n Implementations that support GatewayRoutability - MUST include an address that has the same routable semantics as - defined in the Gateway spec. \n Implementations MAY add additional - addresses in status, but they MUST be semantically less than the - scope of the requested scope. For example if a user requests a `Private` - routable Gateway then an additional address MAY have a routability - of `Cluster` but MUST NOT include `Public`." + from a reserved pool. \n " items: description: GatewayStatusAddress describes an address that is bound to a Gateway. + oneOf: + - properties: + type: + enum: + - IPAddress + value: + anyOf: + - format: ipv4 + - format: ipv6 + - properties: + type: + not: + enum: + - IPAddress properties: - routability: - description: "Routability specifies the routable bounds of this - address Predefined values are: 'Private', 'Public', Cluster - Other values MUST have a vendor prefix. \n Implementations - that support Routability MUST populate this field \n " - maxLength: 253 - minLength: 1 - pattern: ^Public|Private|Cluster|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-_]+$ - type: string type: default: IPAddress description: Type of the address. @@ -10423,6 +10442,11 @@ spec: required: - value type: object + x-kubernetes-validations: + - message: Hostname value must only contain valid characters (matching + ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$) + rule: 'self.type == ''Hostname'' ? self.value.matches(''^(\\*\\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$''): + true' maxItems: 16 type: array conditions: @@ -10911,7 +10935,7 @@ spec: Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n - Support: Extended \n " + Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -11001,7 +11025,9 @@ spec: extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" + filters. \n Support: Implementation-specific \n + This filter can be used multiple times within + the same rule." properties: group: description: Group is the group of the referent. @@ -11139,7 +11165,10 @@ spec: description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from - that destination are ignored. \n Support: Extended" + that destination are ignored. \n This filter can + be used multiple times within the same rule. Note + that not all implementations will be able to support + mirroring to multiple backends. \n Support: Extended" properties: backendRef: description: "BackendRef references a resource @@ -11228,6 +11257,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' required: - backendRef type: object @@ -11451,6 +11484,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' maxItems: 16 type: array filters: @@ -11463,8 +11500,8 @@ spec: all implementations that support GRPCRoute. - Implementers are encouraged to support extended filters. - Implementation-specific custom filters have no API guarantees across implementations. - \n Specifying a core filter multiple times has unspecified - or implementation-specific conformance. \n If an implementation + \n Specifying the same filter multiple times is not supported + unless explicitly indicated in the filter. \n If an implementation can not support a combinations of filters, they must clearly document that limitation. In cases where incompatible or unsupported filters are specified and cause the `Accepted` condition to @@ -11485,7 +11522,8 @@ spec: extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" + filters. \n Support: Implementation-specific \n This + filter can be used multiple times within the same rule." properties: group: description: Group is the group of the referent. For @@ -11615,7 +11653,10 @@ spec: description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are - ignored. \n Support: Extended" + ignored. \n This filter can be used multiple times within + the same rule. Note that not all implementations will + be able to support mirroring to multiple backends. \n + Support: Extended" properties: backendRef: description: "BackendRef references a resource where @@ -11697,6 +11738,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' required: - backendRef type: object @@ -12165,7 +12210,7 @@ spec: the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. - \n Support: Extended \n " + \n Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -12448,7 +12493,7 @@ spec: Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n - Support: Extended \n " + Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -12539,7 +12584,8 @@ spec: extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" + filters. \n This filter can be used multiple times + within the same rule. \n Support: Implementation-specific" properties: group: description: Group is the group of the referent. @@ -12677,7 +12723,10 @@ spec: description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from - that destination are ignored. \n Support: Extended" + that destination are ignored. \n This filter can + be used multiple times within the same rule. Note + that not all implementations will be able to support + mirroring to multiple backends. \n Support: Extended" properties: backendRef: description: "BackendRef references a resource @@ -12766,6 +12815,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' required: - backendRef type: object @@ -12855,6 +12908,23 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' port: description: "Port is the port to be used in the value of the `Location` header in the @@ -13143,12 +13213,97 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' type: object required: - type type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil + if the filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type + != ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type + == ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil + if the filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type + != ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for + RequestMirror filter.type + rule: '!(!has(self.requestMirror) && self.type == + ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the + filter.type is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != + ''RequestRedirect'')' + - message: filter.requestRedirect must be specified + for RequestRedirect filter.type + rule: '!(!has(self.requestRedirect) && self.type == + ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for + ExtensionRef filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' maxItems: 16 type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestHeaderModifier'') + ? self.exists_one(f, f.type == ''RequestHeaderModifier'') + : true' + - message: ResponseHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''ResponseHeaderModifier'') + ? self.exists_one(f, f.type == ''ResponseHeaderModifier'') + : true' + - message: RequestRedirect filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestRedirect'') + ? self.exists_one(f, f.type == ''RequestRedirect'') + : true' + - message: URLRewrite filter cannot be repeated + rule: 'self.exists(f, f.type == ''URLRewrite'') ? self.exists_one(f, + f.type == ''URLRewrite'') : true' group: default: "" description: Group is the group of the referent. For example, @@ -13224,6 +13379,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' maxItems: 16 type: array filters: @@ -13236,9 +13395,9 @@ spec: all implementations. - Implementers are encouraged to support extended filters. - Implementation-specific custom filters have no API guarantees across implementations. \n Specifying - a core filter multiple times has unspecified or implementation-specific - conformance. \n All filters are expected to be compatible - with each other except for the URLRewrite and RequestRedirect + the same filter multiple times is not supported unless explicitly + indicated in the filter. \n All filters are expected to be + compatible with each other except for the URLRewrite and RequestRedirect filters, which may not be combined. If an implementation can not support other combinations of filters, they must clearly document that limitation. In cases where incompatible or unsupported @@ -13260,7 +13419,8 @@ spec: extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" + filters. \n This filter can be used multiple times within + the same rule. \n Support: Implementation-specific" properties: group: description: Group is the group of the referent. For @@ -13390,7 +13550,10 @@ spec: description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are - ignored. \n Support: Extended" + ignored. \n This filter can be used multiple times within + the same rule. Note that not all implementations will + be able to support mirroring to multiple backends. \n + Support: Extended" properties: backendRef: description: "BackendRef references a resource where @@ -13472,6 +13635,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' required: - backendRef type: object @@ -13554,6 +13721,23 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when type is + set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when type + is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' port: description: "Port is the port to be used in the value of the `Location` header in the response. \n If @@ -13821,12 +14005,89 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when type is + set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when type + is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' type: object required: - type type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil if the + filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type != + ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type == + ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil if the + filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type != + ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for RequestMirror + filter.type + rule: '!(!has(self.requestMirror) && self.type == ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the filter.type + is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != ''RequestRedirect'')' + - message: filter.requestRedirect must be specified for RequestRedirect + filter.type + rule: '!(!has(self.requestRedirect) && self.type == ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for ExtensionRef + filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' maxItems: 16 type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') && + self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestHeaderModifier'') + ? self.exists_one(f, f.type == ''RequestHeaderModifier'') + : true' + - message: ResponseHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''ResponseHeaderModifier'') + ? self.exists_one(f, f.type == ''ResponseHeaderModifier'') + : true' + - message: RequestRedirect filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestRedirect'') ? self.exists_one(f, + f.type == ''RequestRedirect'') : true' + - message: URLRewrite filter cannot be repeated + rule: 'self.exists(f, f.type == ''URLRewrite'') ? self.exists_one(f, + f.type == ''URLRewrite'') : true' matches: default: - path: @@ -13970,6 +14231,53 @@ spec: maxLength: 1024 type: string type: object + x-kubernetes-validations: + - message: value must be an absolute path and start with + '/' when type one of ['Exact', 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? self.value.startsWith(''/'') : true' + - message: must not contain '//' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''//'') : true' + - message: must not contain '/./' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''/./'') : true' + - message: must not contain '/../' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''/../'') : true' + - message: must not contain '%2f' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''%2f'') : true' + - message: must not contain '%2F' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''%2F'') : true' + - message: must not contain '#' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''#'') : true' + - message: must not end with '/..' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.endsWith(''/..'') : true' + - message: must not end with '/.' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.endsWith(''/.'') : true' + - message: type must be one of ['Exact', 'PathPrefix', + 'RegularExpression'] + rule: self.type == 'Exact' || self.type == 'PathPrefix' + || self.type == 'RegularExpression' + - message: must only contain valid characters (matching + ^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$) + for types ['Exact', 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? self.value.matches(r"""^(?:[-A-Za-z0-9/._~!$&''()*+,;=:@]|[%][0-9a-fA-F]{2})+$""") + : true' queryParams: description: "QueryParams specifies HTTP query parameter matchers. Multiple match values are ANDed together, @@ -14036,6 +14344,46 @@ spec: maxItems: 8 type: array type: object + x-kubernetes-validations: + - message: RequestRedirect filter must not be used together with + backendRefs + rule: '(has(self.backendRefs) && size(self.backendRefs) > 0) ? + (!has(self.filters) || self.filters.all(f, !has(f.requestRedirect))): + true' + - message: When using RequestRedirect filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + ? ((size(self.matches) != 1 || !has(self.matches[0].path) || + self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: When using URLRewrite filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' + - message: Within backendRefs, when using RequestRedirect filter + with path.replacePrefixMatch, exactly one PathPrefix match must + be specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + )) ? ((size(self.matches) != 1 || !has(self.matches[0].path) + || self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: Within backendRefs, When using URLRewrite filter with + path.replacePrefixMatch, exactly one PathPrefix match must be + specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) )) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' maxItems: 16 type: array type: object @@ -14249,7 +14597,7 @@ spec: the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. - \n Support: Extended \n " + \n Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -14504,7 +14852,7 @@ spec: Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n - Support: Extended \n " + Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -14595,7 +14943,8 @@ spec: extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" + filters. \n This filter can be used multiple times + within the same rule. \n Support: Implementation-specific" properties: group: description: Group is the group of the referent. @@ -14733,7 +15082,10 @@ spec: description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from - that destination are ignored. \n Support: Extended" + that destination are ignored. \n This filter can + be used multiple times within the same rule. Note + that not all implementations will be able to support + mirroring to multiple backends. \n Support: Extended" properties: backendRef: description: "BackendRef references a resource @@ -14822,6 +15174,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' required: - backendRef type: object @@ -14911,6 +15267,23 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' port: description: "Port is the port to be used in the value of the `Location` header in the @@ -15199,12 +15572,97 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' type: object required: - type type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil + if the filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type + != ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type + == ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil + if the filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type + != ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for + RequestMirror filter.type + rule: '!(!has(self.requestMirror) && self.type == + ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the + filter.type is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != + ''RequestRedirect'')' + - message: filter.requestRedirect must be specified + for RequestRedirect filter.type + rule: '!(!has(self.requestRedirect) && self.type == + ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for + ExtensionRef filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' maxItems: 16 type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestHeaderModifier'') + ? self.exists_one(f, f.type == ''RequestHeaderModifier'') + : true' + - message: ResponseHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''ResponseHeaderModifier'') + ? self.exists_one(f, f.type == ''ResponseHeaderModifier'') + : true' + - message: RequestRedirect filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestRedirect'') + ? self.exists_one(f, f.type == ''RequestRedirect'') + : true' + - message: URLRewrite filter cannot be repeated + rule: 'self.exists(f, f.type == ''URLRewrite'') ? self.exists_one(f, + f.type == ''URLRewrite'') : true' group: default: "" description: Group is the group of the referent. For example, @@ -15280,6 +15738,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' maxItems: 16 type: array filters: @@ -15292,9 +15754,9 @@ spec: all implementations. - Implementers are encouraged to support extended filters. - Implementation-specific custom filters have no API guarantees across implementations. \n Specifying - a core filter multiple times has unspecified or implementation-specific - conformance. \n All filters are expected to be compatible - with each other except for the URLRewrite and RequestRedirect + the same filter multiple times is not supported unless explicitly + indicated in the filter. \n All filters are expected to be + compatible with each other except for the URLRewrite and RequestRedirect filters, which may not be combined. If an implementation can not support other combinations of filters, they must clearly document that limitation. In cases where incompatible or unsupported @@ -15316,7 +15778,8 @@ spec: extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" + filters. \n This filter can be used multiple times within + the same rule. \n Support: Implementation-specific" properties: group: description: Group is the group of the referent. For @@ -15446,7 +15909,10 @@ spec: description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are - ignored. \n Support: Extended" + ignored. \n This filter can be used multiple times within + the same rule. Note that not all implementations will + be able to support mirroring to multiple backends. \n + Support: Extended" properties: backendRef: description: "BackendRef references a resource where @@ -15528,6 +15994,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' required: - backendRef type: object @@ -15610,6 +16080,23 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when type is + set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when type + is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' port: description: "Port is the port to be used in the value of the `Location` header in the response. \n If @@ -15877,12 +16364,89 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: replaceFullPath must be set when type is + set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be set when type + is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' type: object required: - type type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil if the + filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type != + ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type == + ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil if the + filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type != + ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for RequestMirror + filter.type + rule: '!(!has(self.requestMirror) && self.type == ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the filter.type + is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != ''RequestRedirect'')' + - message: filter.requestRedirect must be specified for RequestRedirect + filter.type + rule: '!(!has(self.requestRedirect) && self.type == ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for ExtensionRef + filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' maxItems: 16 type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') && + self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestHeaderModifier'') + ? self.exists_one(f, f.type == ''RequestHeaderModifier'') + : true' + - message: ResponseHeaderModifier filter cannot be repeated + rule: 'self.exists(f, f.type == ''ResponseHeaderModifier'') + ? self.exists_one(f, f.type == ''ResponseHeaderModifier'') + : true' + - message: RequestRedirect filter cannot be repeated + rule: 'self.exists(f, f.type == ''RequestRedirect'') ? self.exists_one(f, + f.type == ''RequestRedirect'') : true' + - message: URLRewrite filter cannot be repeated + rule: 'self.exists(f, f.type == ''URLRewrite'') ? self.exists_one(f, + f.type == ''URLRewrite'') : true' matches: default: - path: @@ -16026,6 +16590,53 @@ spec: maxLength: 1024 type: string type: object + x-kubernetes-validations: + - message: value must be an absolute path and start with + '/' when type one of ['Exact', 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? self.value.startsWith(''/'') : true' + - message: must not contain '//' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''//'') : true' + - message: must not contain '/./' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''/./'') : true' + - message: must not contain '/../' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''/../'') : true' + - message: must not contain '%2f' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''%2f'') : true' + - message: must not contain '%2F' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''%2F'') : true' + - message: must not contain '#' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.contains(''#'') : true' + - message: must not end with '/..' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.endsWith(''/..'') : true' + - message: must not end with '/.' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? !self.value.endsWith(''/.'') : true' + - message: type must be one of ['Exact', 'PathPrefix', + 'RegularExpression'] + rule: self.type == 'Exact' || self.type == 'PathPrefix' + || self.type == 'RegularExpression' + - message: must only contain valid characters (matching + ^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$) + for types ['Exact', 'PathPrefix'] + rule: '(self.type == ''Exact'' || self.type == ''PathPrefix'') + ? self.value.matches(r"""^(?:[-A-Za-z0-9/._~!$&''()*+,;=:@]|[%][0-9a-fA-F]{2})+$""") + : true' queryParams: description: "QueryParams specifies HTTP query parameter matchers. Multiple match values are ANDed together, @@ -16092,6 +16703,46 @@ spec: maxItems: 8 type: array type: object + x-kubernetes-validations: + - message: RequestRedirect filter must not be used together with + backendRefs + rule: '(has(self.backendRefs) && size(self.backendRefs) > 0) ? + (!has(self.filters) || self.filters.all(f, !has(f.requestRedirect))): + true' + - message: When using RequestRedirect filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + ? ((size(self.matches) != 1 || !has(self.matches[0].path) || + self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: When using URLRewrite filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' + - message: Within backendRefs, when using RequestRedirect filter + with path.replacePrefixMatch, exactly one PathPrefix match must + be specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + )) ? ((size(self.matches) != 1 || !has(self.matches[0].path) + || self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: Within backendRefs, When using URLRewrite filter with + path.replacePrefixMatch, exactly one PathPrefix match must be + specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) )) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' maxItems: 16 type: array type: object @@ -16305,7 +16956,7 @@ spec: the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. - \n Support: Extended \n " + \n Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -16811,7 +17462,7 @@ spec: Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n - Support: Extended \n " + Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -16943,6 +17594,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' maxItems: 16 minItems: 1 type: array @@ -17163,7 +17818,7 @@ spec: the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. - \n Support: Extended \n " + \n Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -17429,7 +18084,7 @@ spec: Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n - Support: Extended \n " + Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -17564,6 +18219,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' maxItems: 16 minItems: 1 type: array @@ -17784,7 +18443,7 @@ spec: the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. - \n Support: Extended \n " + \n Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -18004,7 +18663,7 @@ spec: Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n - Support: Extended \n " + Support: Extended \n " format: int32 maximum: 65535 minimum: 1 @@ -18136,6 +18795,10 @@ spec: required: - name type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' maxItems: 16 minItems: 1 type: array @@ -18356,7 +19019,7 @@ spec: the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. - \n Support: Extended \n " + \n Support: Extended \n " format: int32 maximum: 65535 minimum: 1 diff --git a/go.mod b/go.mod index 994cbbcaef6..4a1bc5f96c3 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,7 @@ require ( k8s.io/klog/v2 v2.100.1 sigs.k8s.io/controller-runtime v0.15.0 sigs.k8s.io/controller-tools v0.12.1 - sigs.k8s.io/gateway-api v0.7.1-0.20230724142925-a89369a8b66d + sigs.k8s.io/gateway-api v0.7.1-0.20230804170825-f638d3fe75a6 sigs.k8s.io/kustomize/kyaml v0.14.2 ) diff --git a/go.sum b/go.sum index 2889ed706cf..d7d47163ac5 100644 --- a/go.sum +++ b/go.sum @@ -824,10 +824,10 @@ sigs.k8s.io/controller-runtime v0.15.0 h1:ML+5Adt3qZnMSYxZ7gAverBLNPSMQEibtzAgp0 sigs.k8s.io/controller-runtime v0.15.0/go.mod h1:7ngYvp1MLT+9GeZ+6lH3LOlcHkp/+tzA/fmHa4iq9kk= sigs.k8s.io/controller-tools v0.12.1 h1:GyQqxzH5wksa4n3YDIJdJJOopztR5VDM+7qsyg5yE4U= sigs.k8s.io/controller-tools v0.12.1/go.mod h1:rXlpTfFHZMpZA8aGq9ejArgZiieHd+fkk/fTatY8A2M= -sigs.k8s.io/gateway-api v0.7.1-0.20230718212805-cce52879057c h1:ecZRi0imX3npKn18Gnau//tby3jQGQ0aUfVMmj928WQ= -sigs.k8s.io/gateway-api v0.7.1-0.20230718212805-cce52879057c/go.mod h1:dURDctqw4goqoC0/uYL0Faa6F3J9+p0YK3hXkGeFqcg= -sigs.k8s.io/gateway-api v0.7.1-0.20230724142925-a89369a8b66d h1:LJbOuboYa7qkKl6q4YeaFWPebdBnzEmhmNPt3l1KZlA= -sigs.k8s.io/gateway-api v0.7.1-0.20230724142925-a89369a8b66d/go.mod h1:eilE0qyBTXs7VhQuGtUa3ji4IMM7TNtVCWR3+IdPosI= +sigs.k8s.io/gateway-api v0.7.1-0.20230731132839-62040436fa98 h1:SuGnW3nG+UFoiqxgDuK0NKrQg570chJX7K3UOamXS/E= +sigs.k8s.io/gateway-api v0.7.1-0.20230731132839-62040436fa98/go.mod h1:eilE0qyBTXs7VhQuGtUa3ji4IMM7TNtVCWR3+IdPosI= +sigs.k8s.io/gateway-api v0.7.1-0.20230804170825-f638d3fe75a6 h1:eZlWSniKH/uhRBp5p3PRffW8VusGjkwDpugQQzELCNs= +sigs.k8s.io/gateway-api v0.7.1-0.20230804170825-f638d3fe75a6/go.mod h1:eilE0qyBTXs7VhQuGtUa3ji4IMM7TNtVCWR3+IdPosI= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kustomize/kyaml v0.14.2 h1:9WSwztbzwGszG1bZTziQUmVMrJccnyrLb5ZMKpJGvXw=