Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(translator): implement backend API #3495

Merged
merged 13 commits into from
Jun 4, 2024
31 changes: 9 additions & 22 deletions api/v1alpha1/backend_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ const (
// AppProtocolType defines various backend applications protocols supported by Envoy Gateway
//
// +kubebuilder:validation:Enum=gateway.envoyproxy.io/h2c;gateway.envoyproxy.io/ws;gateway.envoyproxy.io/wss
// +notImplementedHide
type AppProtocolType string

const (
Expand All @@ -37,7 +36,6 @@ const (
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[?(@.type=="Accepted")].reason`
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
// +notImplementedHide
type Backend struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand All @@ -49,35 +47,32 @@ type Backend struct {
Status BackendStatus `json:"status,omitempty"`
}

// BackendEndpoint describes a backend endpoint, which can be either a fully-qualified domain name, IPv4 address or unix domain socket
// BackendEndpoint describes a backend endpoint, which can be either a fully-qualified domain name, IP address or unix domain socket
// corresponding to Envoy's Address: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/address.proto#config-core-v3-address
//
// +kubebuilder:validation:XValidation:rule="(has(self.fqdn) || has(self.ipv4) || has(self.unix))",message="one of fqdn, ipv4 or unix must be specified"
// +kubebuilder:validation:XValidation:rule="((has(self.fqdn) && !(has(self.ipv4) || has(self.unix))) || (has(self.ipv4) && !(has(self.fqdn) || has(self.unix))) || (has(self.unix) && !(has(self.ipv4) || has(self.fqdn))))",message="only one of fqdn, ipv4 or unix can be specified"
// +notImplementedHide
// +kubebuilder:validation:XValidation:rule="(has(self.fqdn) || has(self.ip) || has(self.unix))",message="one of fqdn, ip or unix must be specified"
// +kubebuilder:validation:XValidation:rule="((has(self.fqdn) && !(has(self.ip) || has(self.unix))) || (has(self.ip) && !(has(self.fqdn) || has(self.unix))) || (has(self.unix) && !(has(self.ip) || has(self.fqdn))))",message="only one of fqdn, ip or unix can be specified"
type BackendEndpoint struct {
// FQDN defines a FQDN endpoint
//
// +optional
FQDN *FQDNEndpoint `json:"fqdn,omitempty"`

// IPv4 defines an IPv4 endpoint
// IP defines an IP endpoint. Currently, only IPv4 Addresses are supported.
//
// +optional
IPv4 *IPv4Endpoint `json:"ipv4,omitempty"`
IP *IPEndpoint `json:"ip,omitempty"`

// Unix defines the unix domain socket endpoint
//
// +optional
Unix *UnixSocket `json:"unix,omitempty"`
}

// IPv4Endpoint describes TCP/UDP socket address, corresponding to Envoy's Socket Address
// IPEndpoint describes TCP/UDP socket address, corresponding to Envoy's Socket Address
// https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/address.proto#config-core-v3-socketaddress
//
// +notImplementedHide
type IPv4Endpoint struct {
// Address defines the IPv4 address of the backend endpoint.
type IPEndpoint struct {
// Address defines the IP address of the backend endpoint.
//
// +kubebuilder:validation:MinLength=7
// +kubebuilder:validation:MaxLength=15
Expand All @@ -93,14 +88,12 @@ type IPv4Endpoint struct {

// FQDNEndpoint describes TCP/UDP socket address, corresponding to Envoy's Socket Address
// https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/address.proto#config-core-v3-socketaddress
//
// +notImplementedHide
type FQDNEndpoint struct {
// Hostname defines the FQDN hostname of the backend endpoint.
//
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
// +kubebuilder:validation:Pattern=`^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`
// +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9]))*$`
Hostname string `json:"hostname"`

// Port defines the port of the backend endpoint.
Expand All @@ -112,16 +105,12 @@ type FQDNEndpoint struct {

// UnixSocket describes TCP/UDP unix domain socket address, corresponding to Envoy's Pipe
// https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/address.proto#config-core-v3-pipe
//
// +notImplementedHide
type UnixSocket struct {
// Path defines the unix domain socket path of the backend endpoint.
Path string `json:"path"`
}

// BackendSpec describes the desired state of BackendSpec.
//
// +notImplementedHide
type BackendSpec struct {
// Endpoints defines the endpoints to be used when connecting to the backend.
//
Expand Down Expand Up @@ -167,7 +156,6 @@ const (
)

// BackendStatus defines the state of Backend
// +notImplementedHide
type BackendStatus struct {
// Conditions describe the current conditions of the Backend.
//
Expand All @@ -181,7 +169,6 @@ type BackendStatus struct {
// BackendList contains a list of Backend resources.
//
// +kubebuilder:object:root=true
// +notImplementedHide
type BackendList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Expand Down
4 changes: 2 additions & 2 deletions api/v1alpha1/envoygateway_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -493,13 +493,13 @@ type ExtensionService struct {
BackendEndpoint `json:",inline"`

// Host define the extension service hostname.
// Deprecated: use the appropriate transport attribute instead (FQDN,IPv4,Unix)
// Deprecated: use the appropriate transport attribute instead (FQDN,IP,Unix)
//
// +optional
Host string `json:"host,omitempty"`

// Port defines the port the extension service is exposed on.
// Deprecated: use the appropriate transport attribute instead (FQDN,IPv4,Unix)
// Deprecated: use the appropriate transport attribute instead (FQDN,IP,Unix)
//
// +optional
// +kubebuilder:validation:Minimum=0
Expand Down
4 changes: 2 additions & 2 deletions api/v1alpha1/ext_proc_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ type ExtProc struct {
//
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=1
// +kubebuilder:validation:XValidation:message="BackendRefs only supports Service kind.",rule="self.all(f, f.kind == 'Service')"
// +kubebuilder:validation:XValidation:message="BackendRefs only supports Core group.",rule="self.all(f, f.group == '')"
// +kubebuilder:validation:XValidation:message="BackendRefs only supports Service and Backend kind.",rule="self.all(f, f.kind == 'Service' || f.kind == 'Backend')"
// +kubebuilder:validation:XValidation:message="BackendRefs only supports Core and gateway.envoyproxy.io group.",rule="self.all(f, f.group == '' || f.group == 'gateway.envoyproxy.io')"
BackendRefs []BackendRef `json:"backendRefs"`

// MessageTimeout is the timeout for a response to be returned from the external processor
Expand Down
8 changes: 4 additions & 4 deletions api/v1alpha1/validation/envoygateway_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,12 @@
}

switch {
case eg.ExtensionManager.Service.Host == "" && eg.ExtensionManager.Service.FQDN == nil && eg.ExtensionManager.Service.Unix == nil && eg.ExtensionManager.Service.IPv4 == nil:
case eg.ExtensionManager.Service.Host == "" && eg.ExtensionManager.Service.FQDN == nil && eg.ExtensionManager.Service.Unix == nil && eg.ExtensionManager.Service.IP == nil:

Check warning on line 89 in api/v1alpha1/validation/envoygateway_validate.go

View check run for this annotation

Codecov / codecov/patch

api/v1alpha1/validation/envoygateway_validate.go#L89

Added line #L89 was not covered by tests
return fmt.Errorf("extension service must contain a configured target")

case eg.ExtensionManager.Service.FQDN != nil && (eg.ExtensionManager.Service.IPv4 != nil || eg.ExtensionManager.Service.Unix != nil || eg.ExtensionManager.Service.Host != ""),
eg.ExtensionManager.Service.IPv4 != nil && (eg.ExtensionManager.Service.FQDN != nil || eg.ExtensionManager.Service.Unix != nil || eg.ExtensionManager.Service.Host != ""),
eg.ExtensionManager.Service.Unix != nil && (eg.ExtensionManager.Service.IPv4 != nil || eg.ExtensionManager.Service.FQDN != nil || eg.ExtensionManager.Service.Host != ""):
case eg.ExtensionManager.Service.FQDN != nil && (eg.ExtensionManager.Service.IP != nil || eg.ExtensionManager.Service.Unix != nil || eg.ExtensionManager.Service.Host != ""),
eg.ExtensionManager.Service.IP != nil && (eg.ExtensionManager.Service.FQDN != nil || eg.ExtensionManager.Service.Unix != nil || eg.ExtensionManager.Service.Host != ""),
eg.ExtensionManager.Service.Unix != nil && (eg.ExtensionManager.Service.IP != nil || eg.ExtensionManager.Service.FQDN != nil || eg.ExtensionManager.Service.Host != ""):

Check warning on line 94 in api/v1alpha1/validation/envoygateway_validate.go

View check run for this annotation

Codecov / codecov/patch

api/v1alpha1/validation/envoygateway_validate.go#L94

Added line #L94 was not covered by tests

return fmt.Errorf("only one backend target can be configured for the extension manager")

Expand Down
2 changes: 1 addition & 1 deletion api/v1alpha1/validation/envoygateway_validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ func TestValidateEnvoyGateway(t *testing.T) {
Hostname: "foo.example.com",
Port: 8080,
},
IPv4: &v1alpha1.IPv4Endpoint{
IP: &v1alpha1.IPEndpoint{
Address: "10.9.8.7",
Port: 8080,
},
Expand Down
4 changes: 2 additions & 2 deletions api/v1alpha1/validation/envoyproxy_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@

for _, serviceLoadBalancerSourceRange := range serviceLoadBalancerSourceRanges {
if ip, _, err := net.ParseCIDR(serviceLoadBalancerSourceRange); err != nil || ip.To4() == nil {
errs = append(errs, fmt.Errorf("loadBalancerSourceRange:%s is an invalid IPv4 subnet", serviceLoadBalancerSourceRange))
errs = append(errs, fmt.Errorf("loadBalancerSourceRange:%s is an invalid IP subnet", serviceLoadBalancerSourceRange))

Check warning on line 133 in api/v1alpha1/validation/envoyproxy_validate.go

View check run for this annotation

Codecov / codecov/patch

api/v1alpha1/validation/envoyproxy_validate.go#L133

Added line #L133 was not covered by tests
}
}
}
Expand All @@ -140,7 +140,7 @@
}

if ip, err := netip.ParseAddr(*serviceLoadBalancerIP); err != nil || !ip.Unmap().Is4() {
errs = append(errs, fmt.Errorf("loadBalancerIP:%s is an invalid IPv4 address", *serviceLoadBalancerIP))
errs = append(errs, fmt.Errorf("loadBalancerIP:%s is an invalid IP address", *serviceLoadBalancerIP))
}
}
if patch := spec.Provider.Kubernetes.EnvoyService.Patch; patch != nil {
Expand Down
14 changes: 7 additions & 7 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ spec:
to the backend.
items:
description: |-
BackendEndpoint describes a backend endpoint, which can be either a fully-qualified domain name, IPv4 address or unix domain socket
BackendEndpoint describes a backend endpoint, which can be either a fully-qualified domain name, IP address or unix domain socket
corresponding to Envoy's Address: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/address.proto#config-core-v3-address
properties:
fqdn:
Expand All @@ -80,7 +80,7 @@ spec:
endpoint.
maxLength: 253
minLength: 1
pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9]))*$
type: string
port:
description: Port defines the port of the backend endpoint.
Expand All @@ -92,11 +92,12 @@ spec:
- hostname
- port
type: object
ipv4:
description: IPv4 defines an IPv4 endpoint
ip:
description: IP defines an IP endpoint. Currently, only IPv4
Addresses are supported.
properties:
address:
description: Address defines the IPv4 address of the backend
description: Address defines the IP address of the backend
endpoint.
maxLength: 15
minLength: 7
Expand Down Expand Up @@ -124,12 +125,12 @@ spec:
type: object
type: object
x-kubernetes-validations:
- message: one of fqdn, ipv4 or unix must be specified
rule: (has(self.fqdn) || has(self.ipv4) || has(self.unix))
- message: only one of fqdn, ipv4 or unix can be specified
rule: ((has(self.fqdn) && !(has(self.ipv4) || has(self.unix)))
|| (has(self.ipv4) && !(has(self.fqdn) || has(self.unix))) ||
(has(self.unix) && !(has(self.ipv4) || has(self.fqdn))))
- message: one of fqdn, ip or unix must be specified
rule: (has(self.fqdn) || has(self.ip) || has(self.unix))
- message: only one of fqdn, ip or unix can be specified
rule: ((has(self.fqdn) && !(has(self.ip) || has(self.unix))) ||
(has(self.ip) && !(has(self.fqdn) || has(self.unix))) || (has(self.unix)
&& !(has(self.ip) || has(self.fqdn))))
maxItems: 4
minItems: 1
type: array
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,11 @@ spec:
minItems: 1
type: array
x-kubernetes-validations:
- message: BackendRefs only supports Service kind.
rule: self.all(f, f.kind == 'Service')
- message: BackendRefs only supports Core group.
rule: self.all(f, f.group == '')
- message: BackendRefs only supports Service and Backend kind.
rule: self.all(f, f.kind == 'Service' || f.kind == 'Backend')
- message: BackendRefs only supports Core and gateway.envoyproxy.io
group.
rule: self.all(f, f.group == '' || f.group == 'gateway.envoyproxy.io')
failOpen:
description: |-
FailOpen defines if requests or responses that cannot be processed due to connectivity to the
Expand Down
2 changes: 2 additions & 0 deletions charts/gateway-helm/templates/_rbac.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ resources:
- backendtrafficpolicies
- securitypolicies
- envoyextensionpolicies
- backends
verbs:
- get
- list
Expand All @@ -85,6 +86,7 @@ resources:
- backendtrafficpolicies/status
- securitypolicies/status
- envoyextensionpolicies/status
- backends/status
verbs:
- update
{{- end }}
Expand Down
1 change: 1 addition & 0 deletions examples/redis/redis.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ data:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
extensionApis:
enableEnvoyPatchPolicy: true
enableBackend: true
rateLimit:
backend:
type: Redis
Expand Down
3 changes: 3 additions & 0 deletions internal/cmd/egctl/translate.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ func translateGatewayAPIToIR(resources *gatewayapi.Resources) (*gatewayapi.Trans
GlobalRateLimitEnabled: true,
EndpointRoutingDisabled: true,
EnvoyPatchPolicyEnabled: true,
BackendEnabled: true,
}

// Fix the services in the resources section so that they have an IP address - this prevents nasty
Expand Down Expand Up @@ -309,6 +310,7 @@ func translateGatewayAPIToGatewayAPI(resources *gatewayapi.Resources) (gatewayap
GlobalRateLimitEnabled: true,
EndpointRoutingDisabled: true,
EnvoyPatchPolicyEnabled: true,
BackendEnabled: true,
}
gRes, _ := gTranslator.Translate(resources)
// Update the status of the GatewayClass based on EnvoyProxy validation
Expand Down Expand Up @@ -341,6 +343,7 @@ func translateGatewayAPIToXds(dnsDomain string, resourceType string, resources *
GlobalRateLimitEnabled: true,
EndpointRoutingDisabled: true,
EnvoyPatchPolicyEnabled: true,
BackendEnabled: true,
}
gRes, _ := gTranslator.Translate(resources)

Expand Down
4 changes: 2 additions & 2 deletions internal/extension/registry/extension_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ func getExtensionServerAddress(service *v1alpha1.ExtensionService) string {
switch {
case service.FQDN != nil:
serverAddr = fmt.Sprintf("%s:%d", service.FQDN.Hostname, service.FQDN.Port)
case service.IPv4 != nil:
serverAddr = fmt.Sprintf("%s:%d", service.IPv4.Address, service.IPv4.Port)
case service.IP != nil:
serverAddr = fmt.Sprintf("%s:%d", service.IP.Address, service.IP.Port)
case service.Unix != nil:
serverAddr = fmt.Sprintf("unix://%s", service.Unix.Path)
case service.Host != "":
Expand Down
4 changes: 2 additions & 2 deletions internal/extension/registry/extension_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ func TestGetExtensionServerAddress(t *testing.T) {
Expected: "extserver.svc.cluster.local:5050",
},
{
Name: "has an IPv4",
Name: "has an IP",
Service: &v1alpha1.ExtensionService{
BackendEndpoint: v1alpha1.BackendEndpoint{
IPv4: &v1alpha1.IPv4Endpoint{
IP: &v1alpha1.IPEndpoint{
Address: "10.10.10.10",
Port: 5050,
},
Expand Down
Loading