From 1fa24e4b3600a82c825acca787dc6d9194cde7e5 Mon Sep 17 00:00:00 2001 From: Rob Scott Date: Mon, 4 Apr 2022 14:23:17 -0700 Subject: [PATCH] Gateway API v0.5.0 API Review --- apis/v1alpha2/gateway_types.go | 70 ++----- apis/v1alpha2/gatewayclass_types.go | 1 + apis/v1alpha2/httproute_types.go | 177 ++++++++++++++++-- apis/v1alpha2/object_reference_types.go | 13 +- ...olicy_types.go => referencegrant_types.go} | 38 ++-- apis/v1alpha2/shared_types.go | 157 +++++++++++++--- apis/v1alpha2/tlsroute_types.go | 2 +- apis/v1alpha2/zz_generated.deepcopy.go | 133 +++++++++---- apis/v1alpha2/zz_generated.register.go | 4 +- 9 files changed, 433 insertions(+), 162 deletions(-) rename apis/v1alpha2/{referencepolicy_types.go => referencegrant_types.go} (76%) diff --git a/apis/v1alpha2/gateway_types.go b/apis/v1alpha2/gateway_types.go index 064fded34f..4749f1ea0a 100644 --- a/apis/v1alpha2/gateway_types.go +++ b/apis/v1alpha2/gateway_types.go @@ -135,7 +135,7 @@ type GatewaySpec struct { // it assigns to the Gateway and add a corresponding entry in // GatewayStatus.Addresses. // - // Support: Core + // Support: Extended // // +optional // +kubebuilder:validation:MaxItems=16 @@ -145,7 +145,8 @@ type GatewaySpec struct { // Listener embodies the concept of a logical endpoint where a Gateway accepts // network connections. type Listener struct { - // Name is the name of the Listener. + // Name is the name of the Listener. This name MUST be unique within a + // Gateway. // // Support: Core Name SectionName `json:"name"` @@ -171,6 +172,10 @@ type Listener struct { // accepted. For more information, refer to the Route specific Hostnames // documentation. // + // Hostnames that are prefixed with a wildcard label (`*.`) are interpreted + // as a suffix match. That means that a match for `*.example.com` would match + // both `test.example.com`, and `foo.test.example.com`, but not `example.com`. + // // Support: Core // // +optional @@ -309,8 +314,8 @@ type GatewayTLSConfig struct { // a Listener, but this behavior is implementation-specific. // // References to a resource in different namespace are invalid UNLESS there - // is a ReferencePolicy in the target namespace that allows the certificate - // to be attached. If a ReferencePolicy does not allow this reference, the + // is a ReferenceGrant in the target namespace that allows the certificate + // to be attached. If a ReferenceGrant does not allow this reference, the // "ResolvedRefs" condition MUST be set to False for this listener with the // "InvalidCertificateRef" reason. // @@ -320,13 +325,13 @@ type GatewayTLSConfig struct { // CertificateRefs can reference to standard Kubernetes resources, i.e. // Secret, or implementation-specific custom resources. // - // Support: Core - A single reference to a Kubernetes Secret + // Support: Core - A single reference to a Kubernetes Secret of type kubernetes.io/tls // // Support: Implementation-specific (More than one reference or other resource types) // // +optional // +kubebuilder:validation:MaxItems=64 - CertificateRefs []*SecretObjectReference `json:"certificateRefs,omitempty"` + CertificateRefs []SecretObjectReference `json:"certificateRefs,omitempty"` // Options are a list of key/value pairs to enable extended TLS // configuration for each implementation. For example, configuring the @@ -381,7 +386,7 @@ type AllowedRoutes struct { // with the application protocol specified in the Listener's Protocol field. // If an implementation does not support or recognize this resource type, it // MUST set the "ResolvedRefs" condition to False for this Listener with the - // "InvalidRoutesRef" reason. + // "InvalidRouteKinds" reason. // // Support: Core // @@ -462,40 +467,6 @@ type GatewayAddress struct { Value string `json:"value"` } -// AddressType defines how a network address is represented as a text string. -// -// If the requested address is unsupported, the controller -// should raise the "Detached" listener status condition on -// the Gateway with the "UnsupportedAddress" reason. -// -// +kubebuilder:validation:Enum=IPAddress;Hostname;NamedAddress -type AddressType string - -const ( - // A textual representation of a numeric IP address. IPv4 - // addresses must be in dotted-decimal form. IPv6 addresses - // must be in a standard IPv6 text representation - // (see [RFC 5952](https://tools.ietf.org/html/rfc5952)). - // - // Support: Extended - IPAddressType AddressType = "IPAddress" - - // A Hostname represents a DNS based ingress point. This is similar to the - // corresponding hostname field in Kubernetes load balancer status. For - // example, this concept may be used for cloud load balancers where a DNS - // name is used to expose a load balancer. - // - // Support: Extended - HostnameAddressType AddressType = "Hostname" - - // A NamedAddress provides a way to reference a specific IP address by name. - // For example, this may be a name or other unique identifier that refers - // to a resource on a cloud provider such as a static IP. - // - // Support: Implementation-Specific - NamedAddressType AddressType = "NamedAddress" -) - // GatewayStatus defines the observed state of Gateway. type GatewayStatus struct { // Addresses lists the IP addresses that have actually been @@ -673,7 +644,6 @@ const ( // // * "HostnameConflict" // * "ProtocolConflict" - // * "RouteConflict" // // Possible reasons for this condition to be False are: // @@ -695,13 +665,6 @@ const ( // number, but have conflicting protocol specifications. ListenerReasonProtocolConflict ListenerConditionReason = "ProtocolConflict" - // This reason is used with the "Conflicted" condition when the route - // resources selected for this Listener conflict with other - // specified properties of the Listener (e.g. Protocol). - // For example, a Listener that specifies "UDP" as the protocol - // but a route selector that resolves "TCPRoute" objects. - ListenerReasonRouteConflict ListenerConditionReason = "RouteConflict" - // This reason is used with the "Conflicted" condition when the condition // is False. ListenerReasonNoConflicts ListenerConditionReason = "NoConflicts" @@ -721,7 +684,6 @@ const ( // Possible reasons for this condition to be true are: // // * "PortUnavailable" - // * "UnsupportedExtension" // * "UnsupportedProtocol" // * "UnsupportedAddress" // @@ -742,12 +704,6 @@ const ( // * The port is not supported by the implementation. ListenerReasonPortUnavailable ListenerConditionReason = "PortUnavailable" - // This reason is used with the "Detached" condition when the - // controller detects that an implementation-specific Listener - // extension is being requested, but is not able to support - // the extension. - ListenerReasonUnsupportedExtension ListenerConditionReason = "UnsupportedExtension" - // This reason is used with the "Detached" condition when the // Listener could not be attached to be Gateway because its // protocol type is not supported. @@ -801,7 +757,7 @@ const ( // This reason is used with the "ResolvedRefs" condition when // one of the Listener's Routes has a BackendRef to an object in // another namespace, where the object in the other namespace does - // not have a ReferencePolicy explicitly allowing the reference. + // not have a ReferenceGrant explicitly allowing the reference. ListenerReasonRefNotPermitted ListenerConditionReason = "RefNotPermitted" ) diff --git a/apis/v1alpha2/gatewayclass_types.go b/apis/v1alpha2/gatewayclass_types.go index 699bc78c8a..e73b6b36dd 100644 --- a/apis/v1alpha2/gatewayclass_types.go +++ b/apis/v1alpha2/gatewayclass_types.go @@ -27,6 +27,7 @@ import ( // +kubebuilder:subresource:status // +kubebuilder:storageversion // +kubebuilder:printcolumn:name="Controller",type=string,JSONPath=`.spec.controllerName` +// +kubebuilder:printcolumn:name="Accepted",type=string,JSONPath=`.status.conditions[?(@.type=="Accepted")].status` // +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` // +kubebuilder:printcolumn:name="Description",type=string,JSONPath=`.spec.description`,priority=1 diff --git a/apis/v1alpha2/httproute_types.go b/apis/v1alpha2/httproute_types.go index 4d18183122..f10f3ea8d6 100644 --- a/apis/v1alpha2/httproute_types.go +++ b/apis/v1alpha2/httproute_types.go @@ -74,8 +74,13 @@ type HTTPRouteSpec struct { // * A Listener with `*.example.com` as the hostname matches HTTPRoutes // that have either not specified any hostnames or have specified at least // one hostname that matches the Listener hostname. For example, - // `test.example.com` and `*.example.com` would both match. On the other - // hand, `example.com` and `test.example.net` would not match. + // `*.example.com`, `test.example.com`, and `foo.test.example.com` would + // all match. On the other hand, `example.com` and `test.example.net` would + // not match. + // + // Hostnames that are prefixed with a wildcard label (`*.`) are interpreted + // as a suffix match. That means that a match for `*.example.com` would match + // both `test.example.com`, and `foo.test.example.com`, but not `example.com`. // // If both the Listener and HTTPRoute have specified hostnames, any // HTTPRoute hostnames that do not match the Listener hostname MUST be @@ -152,12 +157,15 @@ type HTTPRouteRule struct { // // * The oldest Route based on creation timestamp. // * The Route appearing first in alphabetical order by - // "/". + // "{namespace}/{name}". // // If ties still exist within the Route that has been given precedence, // matching precedence MUST be granted to the first matching rule meeting // the above criteria. // + // When no rules matching a request have been successfully attached to the + // parent a request is coming from, a HTTP 404 status code MUST be returned. + // // +optional // +kubebuilder:validation:MaxItems=8 // +kubebuilder:default={{path:{ type: "PathPrefix", value: "/"}}} @@ -179,6 +187,12 @@ type HTTPRouteRule struct { // Specifying a core filter multiple times has unspecified or custom // conformance. // + // 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 all cases where incompatible or unsupported + // filters are specified, implementations MUST add a warning condition to status. + // // Support: Core // // +optional @@ -187,13 +201,25 @@ type HTTPRouteRule struct { // BackendRefs defines the backend(s) where matching requests should be // sent. - - // If unspecified or invalid (refers to a non-existent resource or a Service - // with no endpoints), the rule performs no forwarding. If there are also no - // filters specified that would result in a response being sent, a HTTP 503 - // status code is returned. 503 responses must be sent so that the overall - // weight is respected; if an invalid backend is requested to have 80% of - // requests, then 80% of requests must get a 503 instead. + // + // A 404 status code MUST be returned if there are no BackendRefs or filters + // specified that would result in a response being sent. + // + // A BackendRef is considered invalid when it refers to: + // + // * an unknown or unsupported kind of resource + // * a resource that does not exist + // * a resource in another namespace when the reference has not been + // explicitly allowed by a ReferenceGrant (or equivalent concept). + // + // When a BackendRef is invalid, 404 status codes MUST be returned for + // requests that would have otherwise been routed to an invalid backend. If + // multiple backends are specified, and some are invalid, the proportion of + // requests that would otherwise have been routed to an invalid backend + // MUST receive a 404 status code. + // + // When a BackendRef refers to a Service that has no ready endpoints, it is + // recommended to return a 503 status code. // // Support: Core for Kubernetes Service // Support: Custom for any other resource @@ -227,11 +253,10 @@ const ( // Matches based on a URL path prefix split by `/`. Matching is // case sensitive and done on a path element by element basis. A // path element refers to the list of labels in the path split by - // the `/` separator. A request is a match for path _p_ if every - // _p_ is an element-wise prefix of the request path. + // the `/` separator. When specified, a trailing `/` is ignored. // - // For example, `/abc`, `/abc/` and `/abc/def` match the prefix - // `/abc`, but `/abcd` does not. + // For example, the paths `/abc`, `/abc/`, and `/abc/def` would all match + // the prefix `/abc`, but the path `/abcd` would not. // // "PathPrefix" is semantically equivalent to the "Prefix" path type in the // Kubernetes Ingress API. @@ -495,6 +520,8 @@ type HTTPRouteFilter struct { // that filter MUST receive a HTTP error response. // // +unionDiscriminator + // +kubebuilder:validation:Enum=RequestHeaderModifier;RequestMirror;RequestRedirect;ExtensionRef + // Type HTTPRouteFilterType `json:"type"` // RequestHeaderModifier defines a schema for a filter that modifies request @@ -522,6 +549,13 @@ type HTTPRouteFilter struct { // +optional RequestRedirect *HTTPRequestRedirectFilter `json:"requestRedirect,omitempty"` + // URLRewrite defines a schema for a filter that modifies a request during forwarding. + // Support: Extended + // + // + // +optional + URLRewrite *HTTPURLRewriteFilter `json:"urlRewrite,omitempty"` + // ExtensionRef is an optional, implementation-specific extension to the // "filter" behavior. For example, resource "myroutefilter" in group // "networking.example.net"). ExtensionRef MUST NOT be used for core and @@ -534,7 +568,6 @@ type HTTPRouteFilter struct { } // HTTPRouteFilterType identifies a type of HTTPRoute filter. -// +kubebuilder:validation:Enum=RequestHeaderModifier;RequestMirror;RequestRedirect;ExtensionRef type HTTPRouteFilterType string const ( @@ -548,13 +581,26 @@ const ( // HTTPRouteFilterRequestRedirect can be used to redirect a request to // another location. This filter can also be used for HTTP to HTTPS - // redirects. + // redirects. This may not be used on the same Route rule or BackendRef as a + // URLRewrite filter. // // Support in HTTPRouteRule: Core // // Support in HTTPBackendRef: Extended HTTPRouteFilterRequestRedirect HTTPRouteFilterType = "RequestRedirect" + // HTTPRouteFilterURLRewrite can be used to modify a request during + // forwarding. At most one of these filters may be used on a Route rule. + // This may not be used on the same Route rule or BackendRef as a + // RequestRedirect filter. + // + // Support in HTTPRouteRule: Extended + // + // Support in HTTPBackendRef: Extended + // + // + HTTPRouteFilterURLRewrite HTTPRouteFilterType = "URLRewrite" + // HTTPRouteFilterRequestMirror can be used to mirror HTTP requests to a // different backend. The responses from this backend MUST be ignored by // the Gateway. @@ -664,7 +710,63 @@ type HTTPRequestHeaderFilter struct { Remove []string `json:"remove,omitempty"` } -// HTTPRequestRedirectFilter defines configuration for the RequestRedirect filter. +// HTTPPathModifierType defines the type of path redirect or rewrite. +type HTTPPathModifierType string + +const ( + // This type of modifier indicates that the full path will be replaced + // by the specified value. + FullPathHTTPPathModifier HTTPPathModifierType = "ReplaceFullPath" + + // This type of modifier indicates that any prefix path matches will be + // replaced by the substitution value. For example, a path with a prefix + // match of "/foo" and a ReplacePrefixMatch substitution of "/bar" will have + // the "/foo" prefix replaced with "/bar" in matching requests. + // + // Note that this matches the behavior of the PathPrefix match type. This + // matches full path elements. A path element refers to the list of labels + // in the path split by the `/` separator. When specified, a trailing `/` is + // ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + // match the prefix `/abc`, but the path `/abcd` would not. + PrefixMatchHTTPPathModifier HTTPPathModifierType = "ReplacePrefixMatch" +) + +// HTTPPathModifier defines configuration for path modifiers. +// +type HTTPPathModifier struct { + // Type defines the type of path modifier. Additional types may be + // added in a future release of the API. + // + // + // +kubebuilder:validation:Enum=ReplaceFullPath;ReplacePrefixMatch + Type HTTPPathModifierType `json:"type"` + + // ReplaceFullPath specifies the value with which to replace the full path + // of a request during a rewrite or redirect. + // + // + // +kubebuilder:validation:MaxLength=1024 + // +optional + ReplaceFullPath *string `json:"replaceFullPath,omitempty"` + + // ReplacePrefixMatch specifies the value with which to replace the prefix + // match of a request during a rewrite or redirect. For example, a request + // to "/foo/bar" with a prefix match of "/foo" would be modified to "/bar". + // + // Note that this matches the behavior of the PathPrefix match type. This + // matches full path elements. A path element refers to the list of labels + // in the path split by the `/` separator. When specified, a trailing `/` is + // ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + // match the prefix `/abc`, but the path `/abcd` would not. + // + // + // +kubebuilder:validation:MaxLength=1024 + // +optional + ReplacePrefixMatch *string `json:"replacePrefixMatch,omitempty"` +} + +// HTTPRequestRedirect defines a filter that redirects a request. This filter +// MUST NOT be used on the same Route rule as a HTTPURLRewrite filter. type HTTPRequestRedirectFilter struct { // Scheme is the scheme to be used in the value of the `Location` // header in the response. @@ -685,6 +787,16 @@ type HTTPRequestRedirectFilter struct { // +optional Hostname *PreciseHostname `json:"hostname,omitempty"` + // Path defines parameters used to modify the path of the incoming request. + // The modified path is then used to construct the `Location` header. When + // empty, the request path is used as-is. + // + // Support: Extended + // + // + // +optional + Path *HTTPPathModifier `json:"path,omitempty"` + // Port is the port to be used in the value of the `Location` // header in the response. // When empty, port (if specified) of the request is used. @@ -704,6 +816,31 @@ type HTTPRequestRedirectFilter struct { StatusCode *int `json:"statusCode,omitempty"` } +// HTTPURLRewriteFilter defines a filter that modifies a request during +// forwarding. At most one of these filters may be used on a Route rule. This +// MUST NOT be used on the same Route rule as a HTTPRequestRedirect filter. +// +// +// Support: Extended +type HTTPURLRewriteFilter struct { + // Hostname is the value to be used to replace the Host header value during + // forwarding. + // + // Support: Extended + // + // + // +optional + Hostname *PreciseHostname `json:"hostname,omitempty"` + + // Path defines a path rewrite. + // + // Support: Extended + // + // + // +optional + Path *HTTPPathModifier `json:"path,omitempty"` +} + // HTTPRequestMirrorFilter defines configuration for the RequestMirror filter. type HTTPRequestMirrorFilter struct { // BackendRef references a resource where mirrored requests are sent. @@ -714,7 +851,7 @@ type HTTPRequestMirrorFilter struct { // this backend in the underlying implementation. // // If there is a cross-namespace reference to an *existing* object - // that is not allowed by a ReferencePolicy, the controller must ensure the + // that is not allowed by a ReferenceGrant, the controller must ensure the // "ResolvedRefs" condition on the Route is set to `status: False`, // with the "RefNotPermitted" reason and not configure this backend in the // underlying implementation. @@ -737,8 +874,8 @@ type HTTPBackendRef struct { // configure this backend in the underlying implementation. // // If there is a cross-namespace reference to an *existing* object - // that is not covered by a ReferencePolicy, the controller must ensure the - // "ResolvedRefs" condition on the Route is set to `status: true`, + // that is not covered by a ReferenceGrant, the controller must ensure the + // "ResolvedRefs" condition on the Route is set to `status: False`, // with the "RefNotPermitted" reason and not configure this backend in the // underlying implementation. // diff --git a/apis/v1alpha2/object_reference_types.go b/apis/v1alpha2/object_reference_types.go index 12730b9ed6..8365168106 100644 --- a/apis/v1alpha2/object_reference_types.go +++ b/apis/v1alpha2/object_reference_types.go @@ -65,9 +65,9 @@ type SecretObjectReference struct { // Namespace is the namespace of the backend. When unspecified, the local // namespace is inferred. // - // Note that when a namespace is specified, a ReferencePolicy object + // Note that when a namespace is specified, a ReferenceGrant object // is required in the referent namespace to allow that namespace's - // owner to accept the reference. See the ReferencePolicy documentation + // owner to accept the reference. See the ReferenceGrant documentation // for details. // // Support: Core @@ -80,9 +80,9 @@ type SecretObjectReference struct { // specific to BackendRef. It includes a few additional fields and features // than a regular ObjectReference. // -// Note that when a namespace is specified, a ReferencePolicy object +// Note that when a namespace is specified, a ReferenceGrant object // is required in the referent namespace to allow that namespace's -// owner to accept the reference. See the ReferencePolicy documentation +// owner to accept the reference. See the ReferenceGrant documentation // for details. // // The API object must be valid in the cluster; the Group and Kind must @@ -100,6 +100,7 @@ type BackendObjectReference struct { Group *Group `json:"group,omitempty"` // Kind is kind of the referent. For example "HTTPRoute" or "Service". + // Defaults to "Service" when not specified. // // +optional // +kubebuilder:default=Service @@ -111,9 +112,9 @@ type BackendObjectReference struct { // Namespace is the namespace of the backend. When unspecified, the local // namespace is inferred. // - // Note that when a namespace is specified, a ReferencePolicy object + // Note that when a namespace is specified, a ReferenceGrant object // is required in the referent namespace to allow that namespace's - // owner to accept the reference. See the ReferencePolicy documentation + // owner to accept the reference. See the ReferenceGrant documentation // for details. // // Support: Core diff --git a/apis/v1alpha2/referencepolicy_types.go b/apis/v1alpha2/referencegrant_types.go similarity index 76% rename from apis/v1alpha2/referencepolicy_types.go rename to apis/v1alpha2/referencegrant_types.go index aac24b1b92..65dd4685e3 100644 --- a/apis/v1alpha2/referencepolicy_types.go +++ b/apis/v1alpha2/referencegrant_types.go @@ -20,29 +20,29 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" // +genclient // +kubebuilder:object:root=true -// +kubebuilder:resource:categories=gateway-api,shortName=refpol +// +kubebuilder:resource:categories=gateway-api,shortName=refgrant // +kubebuilder:storageversion // +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` -// ReferencePolicy identifies kinds of resources in other namespaces that are +// ReferenceGrant identifies kinds of resources in other namespaces that are // trusted to reference the specified kinds of resources in the same namespace // as the policy. // -// Each ReferencePolicy can be used to represent a unique trust relationship. +// Each ReferenceGrant can be used to represent a unique trust relationship. // Additional Reference Policies can be used to add to the set of trusted // sources of inbound references for the namespace they are defined within. // // All cross-namespace references in Gateway API (with the exception of cross-namespace -// Gateway-route attachment) require a ReferencePolicy. +// Gateway-route attachment) require a ReferenceGrant. // // Support: Core // -type ReferencePolicy struct { +type ReferenceGrant struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - // Spec defines the desired state of ReferencePolicy. - Spec ReferencePolicySpec `json:"spec,omitempty"` + // Spec defines the desired state of ReferenceGrant. + Spec ReferenceGrantSpec `json:"spec,omitempty"` // Note that `Status` sub-resource has been excluded at the // moment as it was difficult to work out the design. @@ -50,16 +50,16 @@ type ReferencePolicy struct { } // +kubebuilder:object:root=true -// ReferencePolicyList contains a list of ReferencePolicy. -type ReferencePolicyList struct { +// ReferenceGrantList contains a list of ReferenceGrant. +type ReferenceGrantList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []ReferencePolicy `json:"items"` + Items []ReferenceGrant `json:"items"` } -// ReferencePolicySpec identifies a cross namespace relationship that is trusted +// ReferenceGrantSpec identifies a cross namespace relationship that is trusted // for Gateway API. -type ReferencePolicySpec struct { +type ReferenceGrantSpec struct { // From describes the trusted namespaces and kinds that can reference the // resources described in "To". Each entry in this list must be considered // to be an additional place that references can be valid from, or to put @@ -69,7 +69,7 @@ type ReferencePolicySpec struct { // // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 - From []ReferencePolicyFrom `json:"from"` + From []ReferenceGrantFrom `json:"from"` // To describes the resources that may be referenced by the resources // described in "From". Each entry in this list must be considered to be an @@ -80,11 +80,11 @@ type ReferencePolicySpec struct { // // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 - To []ReferencePolicyTo `json:"to"` + To []ReferenceGrantTo `json:"to"` } -// ReferencePolicyFrom describes trusted namespaces and kinds. -type ReferencePolicyFrom struct { +// ReferenceGrantFrom describes trusted namespaces and kinds. +type ReferenceGrantFrom struct { // Group is the group of the referent. // When empty, the Kubernetes core API group is inferred. // @@ -107,9 +107,9 @@ type ReferencePolicyFrom struct { Namespace Namespace `json:"namespace"` } -// ReferencePolicyTo describes what Kinds are allowed as targets of the +// ReferenceGrantTo describes what Kinds are allowed as targets of the // references. -type ReferencePolicyTo struct { +type ReferenceGrantTo struct { // Group is the group of the referent. // When empty, the Kubernetes core API group is inferred. // @@ -123,7 +123,7 @@ type ReferencePolicyTo struct { // * Service Kind Kind `json:"kind"` - // Name is the name of the referent. When unspecified or empty, this policy + // Name is the name of the referent. When unspecified, this policy // refers to all resources of the specified Group and Kind in the local // namespace. // diff --git a/apis/v1alpha2/shared_types.go b/apis/v1alpha2/shared_types.go index f1c0069a1d..0599489a83 100644 --- a/apis/v1alpha2/shared_types.go +++ b/apis/v1alpha2/shared_types.go @@ -20,18 +20,14 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// ParentRef identifies an API object (usually a Gateway) that can be considered +// ParentReference identifies an API object (usually a Gateway) that can be considered // a parent of this resource (usually a route). The only kind of parent resource // with "Core" support is Gateway. This API may be extended in the future to // support additional kinds of parent resources, such as HTTPRoute. // // The API object must be valid in the cluster; the Group and Kind must // be registered in the cluster for this reference to be valid. -// -// References to objects with invalid Group and Kind are not valid, and must -// be rejected by the implementation, with appropriate Conditions set -// on the containing object. -type ParentRef struct { +type ParentReference struct { // Group is the group of the referent. // // Support: Core @@ -65,7 +61,9 @@ type ParentRef struct { // SectionName is the name of a section within the target resource. In the // following resources, SectionName is interpreted as the following: // - // * Gateway: Listener Name + // * Gateway: Listener Name. When both Port (experimental) and SectionName + // are specified, the name and port of the selected listener must match + // both specified values. // // Implementations MAY choose to support attaching Routes to other resources. // If that is the case, they MUST clearly document how SectionName is @@ -84,6 +82,35 @@ type ParentRef struct { // // +optional SectionName *SectionName `json:"sectionName,omitempty"` + + // Port is the network port this Route targets. It can be interpreted + // differently based on the type of parent resource. + // + // When the parent resource is a Gateway, this targets all listeners + // listening on the specified port that also support this kind of Route(and + // select this Route). It's not recommended to set `Port` unless the + // networking behaviors specified in a Route must apply to a specific port + // as opposed to a listener(s) whose port(s) may be changed. When both Port + // and SectionName are specified, the name and port of the selected listener + // must match both specified values. + // + // Implementations MAY choose to support other parent resources. + // Implementations supporting other types of parent resources MUST clearly + // document how/if Port is interpreted. + // + // For the purpose of status, an attachment is considered successful as + // long as the parent resource accepts it partially. For example, Gateway + // listeners can restrict which Routes can attach to them by Route kind, + // namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + // from the referencing 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. + // + // Support: Extended + // + // +optional + // + Port *PortNumber `json:"port,omitempty"` } // CommonRouteSpec defines the common attributes that all Routes MUST include @@ -111,7 +138,7 @@ type CommonRouteSpec struct { // // +optional // +kubebuilder:validation:MaxItems=32 - ParentRefs []ParentRef `json:"parentRefs,omitempty"` + ParentRefs []ParentReference `json:"parentRefs,omitempty"` } // PortNumber defines a network port. @@ -123,9 +150,9 @@ type PortNumber int32 // BackendRef defines how a Route should forward a request to a Kubernetes // resource. // -// Note that when a namespace is specified, a ReferencePolicy object +// Note that when a namespace is specified, a ReferenceGrant object // is required in the referent namespace to allow that namespace's -// owner to accept the reference. See the ReferencePolicy documentation +// owner to accept the reference. See the ReferenceGrant documentation // for details. type BackendRef struct { // BackendObjectReference references a Kubernetes object. @@ -155,14 +182,65 @@ type BackendRef struct { // RouteConditionType is a type of condition for a route. type RouteConditionType string +// RouteConditionReason is a reason for a route condition. +type RouteConditionReason string + const ( // This condition indicates whether the route has been accepted or rejected // by a Gateway, and why. - ConditionRouteAccepted RouteConditionType = "Accepted" + // + // Possible reasons for this condition to be true are: + // + // * "Accepted" + // + // Possible reasons for this condition to be False are: + // + // * "NotAllowedByListeners" + // * "NoMatchingListenerHostname" + // + // Controllers may raise this condition with other reasons, + // but should prefer to use the reasons listed above to improve + // interoperability. + RouteConditionAccepted RouteConditionType = "Accepted" + + // This reason is used with the "Accepted" condition when the Route has been + // accepted by the Gateway. + RouteReasonAccepted RouteConditionReason = "Accepted" + + // This reason is used with the "Accepted" condition when the route has not + // been accepted by a Gateway because the Gateway has no Listener whose + // allowedRoutes criteria permit the route + RouteReasonNotAllowedByListeners RouteConditionReason = "NotAllowedByListeners" + + // This reason is used with the "Accepted" condition when the Gateway has no + // compatible Listeners whose Hostname matches the route + RouteReasonNoMatchingListenerHostname RouteConditionReason = "NoMatchingListenerHostname" // This condition indicates whether the controller was able to resolve all // the object references for the Route. - ConditionRouteResolvedRefs RouteConditionType = "ResolvedRefs" + // + // Possible reasons for this condition to be true are: + // + // * "ResolvedRefs" + // + // Possible reasons for this condition to be false are: + // + // * "RefNotPermitted" + // + // Controllers may raise this condition with other reasons, + // but should prefer to use the reasons listed above to improve + // interoperability. + RouteConditionResolvedRefs RouteConditionType = "ResolvedRefs" + + // This reason is used with the "ResolvedRefs" condition when the condition + // is true. + RouteReasonResolvedRefs RouteConditionReason = "ResolvedRefs" + + // This reason is used with the "ResolvedRefs" condition when + // one of the Listener's Routes has a BackendRef to an object in + // another namespace, where the object in the other namespace does + // not have a ReferenceGrant explicitly allowing the reference. + RouteReasonRefNotPermitted RouteConditionReason = "RefNotPermitted" ) // RouteParentStatus describes the status of a route with respect to an @@ -170,7 +248,7 @@ const ( type RouteParentStatus struct { // ParentRef corresponds with a ParentRef in the spec that this // RouteParentStatus struct describes the status of. - ParentRef ParentRef `json:"parentRef"` + ParentRef ParentReference `json:"parentRef"` // ControllerName is a domain/path string that indicates the name of the // controller that wrote this status. This corresponds with the @@ -181,6 +259,10 @@ type RouteParentStatus struct { // The format of this field is DOMAIN "/" PATH, where DOMAIN and PATH are // valid Kubernetes names // (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). + // + // Controllers MUST populate this field when writing status. Controllers should ensure that + // entries to status populated with their ControllerName are cleaned up when they are no + // longer necessary. ControllerName GatewayController `json:"controllerName"` // Conditions describes the status of the route with respect to the Gateway. @@ -252,14 +334,9 @@ type RouteStatus struct { // +kubebuilder:validation:Pattern=`^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$` type Hostname string -// PreciseHostname is the fully qualified domain name of a network host. This matches -// the RFC 1123 definition of a hostname with 2 notable exceptions: -// -// 1. IPs are not allowed. -// 2. A hostname may not be prefixed with a wildcard label (`*.`). -// -// Hostname can be "precise" which is a domain name without the terminating -// dot of a network host (e.g. "foo.example.com"). +// PreciseHostname is the fully qualified domain name of a network host. This +// matches the RFC 1123 definition of a hostname with 1 notable exception that +// numeric IP addresses are not allowed. // // Note that as per RFC1035 and RFC1123, a *label* must consist of lower case // alphanumeric characters or '-', and must start and end with an alphanumeric @@ -401,3 +478,41 @@ type AnnotationKey string // +kubebuilder:validation:MinLength=0 // +kubebuilder:validation:MaxLength=4096 type AnnotationValue string + +// AddressType defines how a network address is represented as a text string. +// This may take two possible forms: +// +// * A predefined CamelCase string identifier (currently limited to `IPAddress` or `Hostname`) +// * A domain-prefixed string identifier (like `acme.io/CustomAddressType`) +// +// Values `IPAddress` and `Hostname` have Extended support. +// +// All other values, including domain-prefixed values have Custom support, +// which are used in implementation-specific behaviors. +// +// +kubebuilder:validation:MinLength=1 +// +kubebuilder:validation:MaxLength=253 +// +kubebuilder:validation:Pattern=`^([a-zA-Z0-9])+$|^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])\/[a-zA-Z0-9]+$` +type AddressType string + +const ( + // A textual representation of a numeric IP address. IPv4 + // addresses must be in dotted-decimal form. IPv6 addresses + // must be in a standard IPv6 text representation + // (see [RFC 5952](https://tools.ietf.org/html/rfc5952)). + // + // This type is intended for specific addresses. Address ranges are not + // supported (e.g. you can not use a CIDR range like 127.0.0.0/24 as an + // IPAddress). + // + // Support: Extended + IPAddressType AddressType = "IPAddress" + + // A Hostname represents a DNS based ingress point. This is similar to the + // corresponding hostname field in Kubernetes load balancer status. For + // example, this concept may be used for cloud load balancers where a DNS + // name is used to expose a load balancer. + // + // Support: Extended + HostnameAddressType AddressType = "Hostname" +) diff --git a/apis/v1alpha2/tlsroute_types.go b/apis/v1alpha2/tlsroute_types.go index e8f3faa7f1..6143b79c25 100644 --- a/apis/v1alpha2/tlsroute_types.go +++ b/apis/v1alpha2/tlsroute_types.go @@ -105,7 +105,7 @@ type TLSRouteRule struct { // a Service with no endpoints), the rule performs no forwarding; if no // filters are specified that would result in a response being sent, the // underlying implementation must actively reject request attempts to this - // backend, by rejecting the connection or returning a 503 status code. + // backend, by rejecting the connection or returning a 404 status code. // Request rejections must respect weight; if an invalid backend is // requested to have 80% of requests, then 80% of requests must be rejected // instead. diff --git a/apis/v1alpha2/zz_generated.deepcopy.go b/apis/v1alpha2/zz_generated.deepcopy.go index 84204a2634..c8d3d6bbb3 100644 --- a/apis/v1alpha2/zz_generated.deepcopy.go +++ b/apis/v1alpha2/zz_generated.deepcopy.go @@ -114,7 +114,7 @@ func (in *CommonRouteSpec) DeepCopyInto(out *CommonRouteSpec) { *out = *in if in.ParentRefs != nil { in, out := &in.ParentRefs, &out.ParentRefs - *out = make([]ParentRef, len(*in)) + *out = make([]ParentReference, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } @@ -391,13 +391,9 @@ func (in *GatewayTLSConfig) DeepCopyInto(out *GatewayTLSConfig) { } if in.CertificateRefs != nil { in, out := &in.CertificateRefs, &out.CertificateRefs - *out = make([]*SecretObjectReference, len(*in)) + *out = make([]SecretObjectReference, len(*in)) for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(SecretObjectReference) - (*in).DeepCopyInto(*out) - } + (*in)[i].DeepCopyInto(&(*out)[i]) } } if in.Options != nil { @@ -502,6 +498,31 @@ func (in *HTTPPathMatch) DeepCopy() *HTTPPathMatch { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPPathModifier) DeepCopyInto(out *HTTPPathModifier) { + *out = *in + if in.ReplaceFullPath != nil { + in, out := &in.ReplaceFullPath, &out.ReplaceFullPath + *out = new(string) + **out = **in + } + if in.ReplacePrefixMatch != nil { + in, out := &in.ReplacePrefixMatch, &out.ReplacePrefixMatch + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPPathModifier. +func (in *HTTPPathModifier) DeepCopy() *HTTPPathModifier { + if in == nil { + return nil + } + out := new(HTTPPathModifier) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *HTTPQueryParamMatch) DeepCopyInto(out *HTTPQueryParamMatch) { *out = *in @@ -581,6 +602,11 @@ func (in *HTTPRequestRedirectFilter) DeepCopyInto(out *HTTPRequestRedirectFilter *out = new(PreciseHostname) **out = **in } + if in.Path != nil { + in, out := &in.Path, &out.Path + *out = new(HTTPPathModifier) + (*in).DeepCopyInto(*out) + } if in.Port != nil { in, out := &in.Port, &out.Port *out = new(PortNumber) @@ -648,6 +674,11 @@ func (in *HTTPRouteFilter) DeepCopyInto(out *HTTPRouteFilter) { *out = new(HTTPRequestRedirectFilter) (*in).DeepCopyInto(*out) } + if in.URLRewrite != nil { + in, out := &in.URLRewrite, &out.URLRewrite + *out = new(HTTPURLRewriteFilter) + (*in).DeepCopyInto(*out) + } if in.ExtensionRef != nil { in, out := &in.ExtensionRef, &out.ExtensionRef *out = new(LocalObjectReference) @@ -816,6 +847,31 @@ func (in *HTTPRouteStatus) DeepCopy() *HTTPRouteStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPURLRewriteFilter) DeepCopyInto(out *HTTPURLRewriteFilter) { + *out = *in + if in.Hostname != nil { + in, out := &in.Hostname, &out.Hostname + *out = new(PreciseHostname) + **out = **in + } + if in.Path != nil { + in, out := &in.Path, &out.Path + *out = new(HTTPPathModifier) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPURLRewriteFilter. +func (in *HTTPURLRewriteFilter) DeepCopy() *HTTPURLRewriteFilter { + if in == nil { + return nil + } + out := new(HTTPURLRewriteFilter) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Listener) DeepCopyInto(out *Listener) { *out = *in @@ -911,7 +967,7 @@ func (in *ParametersReference) DeepCopy() *ParametersReference { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ParentRef) DeepCopyInto(out *ParentRef) { +func (in *ParentReference) DeepCopyInto(out *ParentReference) { *out = *in if in.Group != nil { in, out := &in.Group, &out.Group @@ -933,14 +989,19 @@ func (in *ParentRef) DeepCopyInto(out *ParentRef) { *out = new(SectionName) **out = **in } + if in.Port != nil { + in, out := &in.Port, &out.Port + *out = new(PortNumber) + **out = **in + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParentRef. -func (in *ParentRef) DeepCopy() *ParentRef { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParentReference. +func (in *ParentReference) DeepCopy() *ParentReference { if in == nil { return nil } - out := new(ParentRef) + out := new(ParentReference) in.DeepCopyInto(out) return out } @@ -966,25 +1027,25 @@ func (in *PolicyTargetReference) DeepCopy() *PolicyTargetReference { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ReferencePolicy) DeepCopyInto(out *ReferencePolicy) { +func (in *ReferenceGrant) DeepCopyInto(out *ReferenceGrant) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReferencePolicy. -func (in *ReferencePolicy) DeepCopy() *ReferencePolicy { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReferenceGrant. +func (in *ReferenceGrant) DeepCopy() *ReferenceGrant { if in == nil { return nil } - out := new(ReferencePolicy) + out := new(ReferenceGrant) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ReferencePolicy) DeepCopyObject() runtime.Object { +func (in *ReferenceGrant) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -992,46 +1053,46 @@ func (in *ReferencePolicy) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ReferencePolicyFrom) DeepCopyInto(out *ReferencePolicyFrom) { +func (in *ReferenceGrantFrom) DeepCopyInto(out *ReferenceGrantFrom) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReferencePolicyFrom. -func (in *ReferencePolicyFrom) DeepCopy() *ReferencePolicyFrom { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReferenceGrantFrom. +func (in *ReferenceGrantFrom) DeepCopy() *ReferenceGrantFrom { if in == nil { return nil } - out := new(ReferencePolicyFrom) + out := new(ReferenceGrantFrom) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ReferencePolicyList) DeepCopyInto(out *ReferencePolicyList) { +func (in *ReferenceGrantList) DeepCopyInto(out *ReferenceGrantList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]ReferencePolicy, len(*in)) + *out = make([]ReferenceGrant, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReferencePolicyList. -func (in *ReferencePolicyList) DeepCopy() *ReferencePolicyList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReferenceGrantList. +func (in *ReferenceGrantList) DeepCopy() *ReferenceGrantList { if in == nil { return nil } - out := new(ReferencePolicyList) + out := new(ReferenceGrantList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ReferencePolicyList) DeepCopyObject() runtime.Object { +func (in *ReferenceGrantList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1039,34 +1100,34 @@ func (in *ReferencePolicyList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ReferencePolicySpec) DeepCopyInto(out *ReferencePolicySpec) { +func (in *ReferenceGrantSpec) DeepCopyInto(out *ReferenceGrantSpec) { *out = *in if in.From != nil { in, out := &in.From, &out.From - *out = make([]ReferencePolicyFrom, len(*in)) + *out = make([]ReferenceGrantFrom, len(*in)) copy(*out, *in) } if in.To != nil { in, out := &in.To, &out.To - *out = make([]ReferencePolicyTo, len(*in)) + *out = make([]ReferenceGrantTo, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReferencePolicySpec. -func (in *ReferencePolicySpec) DeepCopy() *ReferencePolicySpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReferenceGrantSpec. +func (in *ReferenceGrantSpec) DeepCopy() *ReferenceGrantSpec { if in == nil { return nil } - out := new(ReferencePolicySpec) + out := new(ReferenceGrantSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ReferencePolicyTo) DeepCopyInto(out *ReferencePolicyTo) { +func (in *ReferenceGrantTo) DeepCopyInto(out *ReferenceGrantTo) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name @@ -1075,12 +1136,12 @@ func (in *ReferencePolicyTo) DeepCopyInto(out *ReferencePolicyTo) { } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReferencePolicyTo. -func (in *ReferencePolicyTo) DeepCopy() *ReferencePolicyTo { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReferenceGrantTo. +func (in *ReferenceGrantTo) DeepCopy() *ReferenceGrantTo { if in == nil { return nil } - out := new(ReferencePolicyTo) + out := new(ReferenceGrantTo) in.DeepCopyInto(out) return out } diff --git a/apis/v1alpha2/zz_generated.register.go b/apis/v1alpha2/zz_generated.register.go index 94dc2ff41b..7505084fa4 100644 --- a/apis/v1alpha2/zz_generated.register.go +++ b/apis/v1alpha2/zz_generated.register.go @@ -64,8 +64,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { &GatewayList{}, &HTTPRoute{}, &HTTPRouteList{}, - &ReferencePolicy{}, - &ReferencePolicyList{}, + &ReferenceGrant{}, + &ReferenceGrantList{}, &TCPRoute{}, &TCPRouteList{}, &TLSRoute{},