Skip to content

Commit

Permalink
Rewrite Listeners in terms of an endpoint concept.
Browse files Browse the repository at this point in the history
Rewrite Listeners to model the concept of a logical network endpoint.
This change defines a Gateway more strongly as the network element to
which addresses can be attached, and Listeners as logical endpoints
within the network element.

The main goal of this change is to consolidate the name of an application
(i.e. the endpoint) into a single part of the API that is controlled
by one user persona. In this change, the application name is strictly
part of the Gateway spec and controlled by the cluster operator role,
while routes are controlled by the application owner.

The Listener protocol is now strongly defined to a core set of common
protocol stacks. This loss of flexibility improves clarity because it
makes it possible to specify how Listeners should be collapsed into
virtual hosts in an underlying proxy implementation.

This change doesn't update ListenerStatus, though clearly it no longer
makes complete sense. The most likely change needed for GatewayStatus
is to drop the Listeners field and fold listener errors directly into
the Conditions field.

Signed-off-by: James Peach <jpeach@vmware.com>
  • Loading branch information
jpeach committed May 13, 2020
1 parent 96e09e8 commit 2fb6ca4
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 67 deletions.
152 changes: 103 additions & 49 deletions api/v1alpha1/gateway_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ import (
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status

// Gateway represents an instantiation of a service-traffic handling infrastructure.
// Gateway represents an instantiation of a service-traffic handling
// infrastructure. The distinguishing characteristics of a gateway are
// that it has at least one IP address, and that it behaves as a network
// endpoint from the perspective of a client application.
type Gateway struct {
metav1.TypeMeta `json:",inline" protobuf:"bytes,1,opt,name=typeMeta"`
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,2,opt,name=metadata"`
Expand Down Expand Up @@ -54,78 +57,129 @@ type GatewayList struct {
type GatewaySpec struct {
// Class used for this Gateway. This is the name of a GatewayClass resource.
Class string `json:"class" protobuf:"bytes,1,opt,name=class"`
// Listeners associated with this Gateway. Listeners define what addresses,
// ports, protocols are bound on this Gateway.

// Listeners associated with this Gateway. Listeners define what addresses
// are bound on this Gateway. If no Listeners are provided, the GatewayClass
// may associate the Gateway with an address in an implementation-defined
// manner.
//
// +optional
Listeners []Listener `json:"listeners" protobuf:"bytes,2,rep,name=listeners"`
// Routes specifies a schema for associating routes with the Gateway using
// selectors. A route is a resource capable of servicing a request and allows
// a cluster operator to expose a cluster resource (i.e. Service) by
// externally-reachable URL, load-balance traffic and terminate SSL/TLS.
// Typically, a route is a "httproute" or "tcproute" in group
// "networking.x-k8s.io". However, an implementation may support other resources.

// Address requested for this gateway. This is optional and behavior
// can depend on the GatewayClass. If a value is set in the spec and
// the request address is invalid, the GatewayClass MUST indicate
// this in the associated entry in GatewayStatus.Listeners. If no
// addresses are specified, the GatewayClass may schedule the Gateway
// in an implementation-defined manner, providing it with an appropriate
// set of addresses.
//
// Support: Core
// Support:
//
Routes RouteBindingSelector `json:"routes" protobuf:"bytes,3,opt,name=routes"`
// +optional
Addresses []ListenerAddress `json:"endpoints" protobuf:bytes,3,rep,name=endpoints"`
}

// ProtocolType defines the application protocol accepted by a Listener.
type ProtocolType string

const (
// HTTPProtocol constant.
HTTPProtocol = "HTTP"
// HTTPSProtocol constant.
HTTPSProtocol = "HTTPS"
// HTTPProtocolType accepts cleartext HTTP sessions.
HTTPProtocolType ProtocolType = "HTTP"

// HTTPSProtocolType accepts HTTPS sessions.
HTTPSProtocolType ProtocolType = "HTTPS"

// TLSProtocolType accepts TLS sessions over TCP.
TLSProtocolType ProtocolType = "TLS"

// TLSProtocolType accepts TCP sessions.
TCPProtocolType ProtocolType = "TCP"
)

// Listener defines a
// Listener embodies the concept of a logical endpoint where a
// Gateway can accept network connections.
//
// The GatewayClass may collapse compatible Listener definitions
// into single implementation-defined acceptor.
//
// Listeners are considered compatible if the Protocol field is
// "HTTP", HTTPS or "TLS", the Hostname field is specified, and the
// Port field matches.
type Listener struct {
// Name is the listener's name and should be specified as an
// RFC 1035 DNS_LABEL [1]:
// Hostname is the fully qualified domain name of a network host,
// as defined by [RFC 3986](https://tools.ietf.org/html/rfc3986#section-3.2.2).
// Note the following deviations from the "host" part of the URI as defined in the RFC:
//
// [1] https://tools.ietf.org/html/rfc1035
// 1. IPs are not allowed.
// 2. The `:` delimiter is not respected because ports are not allowed.
//
// Each listener of a Gateway must have a unique name. Name is used
// for associating a listener in Gateway status.
// Hostname specifies the virtual hostname for protocol
// types that define this concept. If the protocol is "HTTP"
// or "HTTPS", Hostname is must be present and must not be an
// empty string.
//
// Support: Core
// Incoming requests are matched against Hostname before processing HTTPRoute
// rules. For example, if the request header contains host: foo.example.com,
// an HTTPRoute with hostname foo.example.com will match. However, an
// HTTPRoute with hostname example.com or bar.example.com will not match.
// If Hostname is unspecified, the Gateway routes all traffic based on
// the specified rules.
//
// +required
Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
// Address requested for this listener. This is optional and behavior
// can depend on GatewayClass. If a value is set in the spec and
// the request address is invalid, the GatewayClass MUST indicate
// this in the associated entry in GatewayStatus.Listeners.
// Hostname must be supplied required for "HTTP" and "HTTPS" protocols, and may
// be supplied for "TLS" protocol.
//
// Support:
// Support: Core
//
// +optional
Address *ListenerAddress `json:"address,omitempty" protobuf:"bytes,2,opt,name=address"`
// Port is a list of ports associated with the Address.
// +kubebuilder:validation:MinLength=1
Hostname string `json:"hostname,omitempty" protobuf:"bytes,1,opt,name=hostname"`

// Port is the network port. Multiple listeners may use the
// same port, subject to the Listener compatibility rules.
//
// Support:
// +optional
Port *int32 `json:"port,omitempty" protobuf:"varint,3,opt,name=port"`
// Protocol to use.
// Support: Core
//
// Support:
// +optional
Protocol *string `json:"protocol,omitempty" protobuf:"bytes,4,opt,name=protocol"`
// +required
Port int32 `json:"port,omitempty" protobuf:"varint,3,opt,name=port"`

// Protocol specifies the application protocol this listener expects to receive.
//
// Support: Core
//
// +required
Protocol ProtocolType `json:"protocol,omitempty" protobuf:"bytes,4,opt,name=protocol"`

// TLS is the TLS configuration for the Listener. If unspecified,
// the listener will not support TLS connections.
// the listener will not support TLS connections. If the Hostname
// field is also specified, this endpoint is must only accept TLS
// sessions where the client has requested the Hostname using the
// TLS Server Name Indication (SNI) extension.
//
// If no Hostname is specified, this Endpoint must not be collapsed
// into a shared acceptor by the Gateway.
//
// If the Protocol field is "HTTPS" or "TLS", this field is required.
//
// Support: Core
//
// +optional
TLS *TLSConfig `json:"tls,omitempty" protobuf:"bytes,5,opt,name=tls"`
// ExtensionRef for this Listener. The resource may be "configmaps" or
// an implementation-defined resource (for example, resource
// "mylisteners" in group "networking.acme.io"). Omitting or specifying
// the empty string for both the resource and group indicates that the
// resource is "configmaps". If the referent cannot be found, the
// listener's "InvalidListener" status condition will be true.
//
// Support: custom.
// +optional
ExtensionRef *ListenerExtensionObjectReference `json:"extensionRef,omitempty" protobuf:"bytes,6,opt,name=extensionRef"`

// Routes specifies a schema for associating routes with the Gateway using
// selectors. A route is a resource capable of servicing a request and allows
// a cluster operator to expose a cluster resource (i.e. Service) by
// externally-reachable URL, load-balance traffic and terminate SSL/TLS.
// Typically, a route is a "httproute" or "tcproute" in group
// "networking.x-k8s.io". However, an implementation may support other resources.
//
// The Routes selector must select a set of objects that
// are compatible with the application protocol specified in
// the Protocol field.
//
// Support: Core
//
Routes RouteBindingSelector `json:"routes" protobuf:"bytes,3,opt,name=routes"`
}

// AddressType defines how a network address is represented as a text string.
Expand Down
24 changes: 6 additions & 18 deletions api/v1alpha1/httproute_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ type HTTPRouteSpec struct {
// Hosts is a list of Host definitions.
Hosts []HTTPRouteHost `json:"hosts,omitempty" protobuf:"bytes,1,rep,name=hosts"`

// TODO(jpeach): finish updating for endpoints
//
// * Now that we don't have a hostname, pull routes in directly?
// * Where does the default host/route go? what does it mean?
// * Should the extensions ref go here?

// Default is the default host to use. Default.Hostnames must
// be an empty list.
//
Expand All @@ -33,24 +39,6 @@ type HTTPRouteSpec struct {

// HTTPRouteHost is the configuration for a given host.
type HTTPRouteHost struct {
// Hostname is the fully qualified domain name of a network host,
// as defined by RFC 3986. Note the following deviations from the
// "host" part of the URI as defined in the RFC:
//
// 1. IPs are not allowed.
// 2. The `:` delimiter is not respected because ports are not allowed.
//
// Incoming requests are matched against Hostname before processing HTTPRoute
// rules. For example, if the request header contains host: foo.example.com,
// an HTTPRoute with hostname foo.example.com will match. However, an
// HTTPRoute with hostname example.com or bar.example.com will not match.
// If Hostname is unspecified, the Gateway routes all traffic based on
// the specified rules.
//
// Support: Core
//
// +optional
Hostname string `json:"hostname,omitempty" protobuf:"bytes,1,opt,name=hostname"`

// Rules are a list of HTTP matchers, filters and actions.
Rules []HTTPRouteRule `json:"rules" protobuf:"bytes,2,rep,name=rules"`
Expand Down

0 comments on commit 2fb6ca4

Please sign in to comment.