Skip to content

Commit

Permalink
Add EnvoyPatchPolicy support to Gateway API lib
Browse files Browse the repository at this point in the history
Relates to envoyproxy#24

Signed-off-by: Arko Dasgupta <arko@tetrate.io>
  • Loading branch information
arkodg committed Jul 6, 2023
1 parent a655293 commit ab905b2
Show file tree
Hide file tree
Showing 12 changed files with 206 additions and 15 deletions.
4 changes: 2 additions & 2 deletions api/v1alpha1/envoypatchpolicy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package v1alpha1

import (
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
)
Expand Down Expand Up @@ -107,8 +108,7 @@ type JSONPatchOperation struct {
// Refer to https://datatracker.ietf.org/doc/html/rfc6901 for more details.
Path string `json:"path"`
// Value is the new value of the path location.
// +kubebuilder:validation:MinLength=1
Value string `json:"value"`
Value apiextensionsv1.JSON `json:"value"`
}

// EnvoyPatchPolicyStatus defines the state of EnvoyPatchPolicy
Expand Down
7 changes: 5 additions & 2 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 @@ -65,8 +65,7 @@ spec:
type: string
value:
description: Value is the new value of the path location.
minLength: 1
type: string
x-kubernetes-preserve-unknown-fields: true
required:
- op
- path
Expand Down
2 changes: 1 addition & 1 deletion docs/latest/api/extension_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ _Appears in:_
| --- | --- |
| `op` _[JSONPatchOperationType](#jsonpatchoperationtype)_ | Op is the type of operation to perform |
| `path` _string_ | Path is the location of the target document/field where the operation will be performed Refer to https://datatracker.ietf.org/doc/html/rfc6901 for more details. |
| `value` _string_ | Value is the new value of the path location. |
| `value` _[JSON](#json)_ | Value is the new value of the path location. |


## JSONPatchOperationType
Expand Down
2 changes: 1 addition & 1 deletion internal/gatewayapi/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type AddressesTranslator interface {
func (t *Translator) ProcessAddresses(gateways []*GatewayContext, xdsIR XdsIRMap, infraIR InfraIRMap, resources *Resources) {
for _, gateway := range gateways {
// Infra IR already exist
irKey := irStringKey(gateway.Gateway)
irKey := irStringKey(gateway.Gateway.Namespace, gateway.Gateway.Name)
gwInfraIR := infraIR[irKey]

var ipAddr []string
Expand Down
58 changes: 58 additions & 0 deletions internal/gatewayapi/envoypatchpolicy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright Envoy Gateway Authors
// SPDX-License-Identifier: Apache-2.0
// The full text of the Apache license is available in the LICENSE file at
// the root of the repo.

package gatewayapi

import (
"sort"

gwv1b1 "sigs.k8s.io/gateway-api/apis/v1beta1"

egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
"github.com/envoyproxy/gateway/internal/ir"
)

func (t *Translator) ProcessEnvoyPatchPolicies(envoyPatchPolicies []*egv1a1.EnvoyPatchPolicy, xdsIR XdsIRMap) {
// Sort based on priority
sort.Slice(envoyPatchPolicies, func(i, j int) bool {
return envoyPatchPolicies[i].Spec.Priority < envoyPatchPolicies[j].Spec.Priority
})

for _, policy := range envoyPatchPolicies {
// Ensure policy can only target a Gateway
if policy.Spec.TargetRef.Group != gwv1b1.GroupName || policy.Spec.TargetRef.Kind != KindGateway {
// TODO: Update Status
continue
}

// Ensure Policy and target Gateway are in the same namespace
targetNs := policy.Spec.TargetRef.Namespace
if targetNs == nil || policy.Namespace != string(*targetNs) {
// TODO: Update Status
continue
}

// Get the IR
// It must exist since the gateways have already been processed
irKey := irStringKey(string(*targetNs), string(policy.Spec.TargetRef.Name))
gwXdsIR, ok := xdsIR[irKey]
if !ok {
// TODO: Update Status
continue
}

// Save the patch
for _, patch := range policy.Spec.JSONPatches {
irPatch := ir.JSONPatchConfig{}
irPatch.Type = string(patch.Type)
irPatch.Name = patch.Name
irPatch.Operation.Op = string(patch.Operation.Op)
irPatch.Operation.Path = patch.Operation.Path
irPatch.Operation.Value = patch.Operation.Value

gwXdsIR.JSONPatches = append(gwXdsIR.JSONPatches, &irPatch)
}
}
}
4 changes: 2 additions & 2 deletions internal/gatewayapi/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,8 @@ type crossNamespaceTo struct {
name string
}

func irStringKey(gateway *v1beta1.Gateway) string {
return fmt.Sprintf("%s-%s", gateway.Namespace, gateway.Name)
func irStringKey(gatewayNs, gatewayName string) string {
return fmt.Sprintf("%s-%s", gatewayNs, gatewayName)
}

func irHTTPListenerName(listener *ListenerContext) string {
Expand Down
2 changes: 1 addition & 1 deletion internal/gatewayapi/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap
// to the Xds IR.
for _, gateway := range gateways {
// init IR per gateway
irKey := irStringKey(gateway.Gateway)
irKey := irStringKey(gateway.Gateway.Namespace, gateway.Gateway.Name)
gwXdsIR := &ir.Xds{}
gwInfraIR := ir.NewInfra()
gwInfraIR.Proxy.Name = irKey
Expand Down
8 changes: 4 additions & 4 deletions internal/gatewayapi/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, route
}
}

irKey := irStringKey(listener.gateway)
irKey := irStringKey(listener.gateway.Namespace, listener.gateway.Name)
irListener := xdsIR[irKey].GetHTTPListener(irHTTPListenerName(listener))
if irListener != nil {
if GetRouteType(route) == KindGRPCRoute {
Expand Down Expand Up @@ -629,7 +629,7 @@ func (t *Translator) processTLSRouteParentRefs(tlsRoute *TLSRouteContext, resour

hasHostnameIntersection = true

irKey := irStringKey(listener.gateway)
irKey := irStringKey(listener.gateway.Namespace, listener.gateway.Name)
containerPort := servicePortToContainerPort(int32(listener.Port))
// Create the TCP Listener while parsing the TLSRoute since
// the listener directly links to a routeDestination.
Expand Down Expand Up @@ -764,7 +764,7 @@ func (t *Translator) processUDPRouteParentRefs(udpRoute *UDPRouteContext, resour
continue
}
accepted = true
irKey := irStringKey(listener.gateway)
irKey := irStringKey(listener.gateway.Namespace, listener.gateway.Name)
containerPort := servicePortToContainerPort(int32(listener.Port))
// Create the UDP Listener while parsing the UDPRoute since
// the listener directly links to a routeDestination.
Expand Down Expand Up @@ -896,7 +896,7 @@ func (t *Translator) processTCPRouteParentRefs(tcpRoute *TCPRouteContext, resour
continue
}
accepted = true
irKey := irStringKey(listener.gateway)
irKey := irStringKey(listener.gateway.Namespace, listener.gateway.Name)
containerPort := servicePortToContainerPort(int32(listener.Port))
// Create the TCP Listener while parsing the TCPRoute since
// the listener directly links to a routeDestination.
Expand Down
56 changes: 56 additions & 0 deletions internal/gatewayapi/testdata/envoypatchpolicy-valid.in.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
envoyPatchPolicies:
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyPatchPolicy
metadata:
namespace: envoy-gateway
name: edit-conn-buffer-bytes
spec:
type: "JSONPatch"
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: gateway-1
namespace: envoy-gateway
jsonPatches:
- type: "type.googleapis.com/envoy.config.listener.v3.Listener"
name: "envoy-gateway-gateway-1-http"
operation:
op: replace
path: "/per_connection_buffer_limit_bytes"
value: "1024"
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyPatchPolicy
metadata:
namespace: envoy-gateway
name: edit-ignore-global-limit
spec:
type: "JSONPatch"
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: gateway-1
namespace: envoy-gateway
# Higher priority
priority: -1
jsonPatches:
- type: "type.googleapis.com/envoy.config.listener.v3.Listener"
name: "envoy-gateway-gateway-1-http"
operation:
op: replace
path: "/ignore_global_conn_limit"
value: "true"
gateways:
- apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
namespace: envoy-gateway
name: gateway-1
spec:
gatewayClassName: envoy-gateway-class
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: Same
72 changes: 72 additions & 0 deletions internal/gatewayapi/testdata/envoypatchpolicy-valid.out.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
gateways:
- apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
namespace: envoy-gateway
name: gateway-1
spec:
gatewayClassName: envoy-gateway-class
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: Same
status:
listeners:
- name: http
supportedKinds:
- group: gateway.networking.k8s.io
kind: HTTPRoute
- group: gateway.networking.k8s.io
kind: GRPCRoute
attachedRoutes: 0
conditions:
- type: Programmed
status: "True"
reason: Programmed
message: Sending translated listener configuration to the data plane
- type: Accepted
status: "True"
reason: Accepted
message: Listener has been successfully translated
xdsIR:
envoy-gateway-gateway-1:
accessLog:
text:
- path: /dev/stdout
http:
- name: envoy-gateway-gateway-1-http
address: 0.0.0.0
port: 10080
hostnames:
- "*"
jsonPatches:
- type: "type.googleapis.com/envoy.config.listener.v3.Listener"
name: "envoy-gateway-gateway-1-http"
operation:
op: replace
path: "/ignore_global_conn_limit"
value: "true"
- type: "type.googleapis.com/envoy.config.listener.v3.Listener"
name: "envoy-gateway-gateway-1-http"
operation:
op: replace
path: "/per_connection_buffer_limit_bytes"
value: "1024"
infraIR:
envoy-gateway-gateway-1:
proxy:
metadata:
labels:
gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway
gateway.envoyproxy.io/owning-gateway-name: gateway-1
name: envoy-gateway-gateway-1
listeners:
- address: ""
ports:
- name: http
protocol: "HTTP"
servicePort: 80
containerPort: 10080
3 changes: 3 additions & 0 deletions internal/gatewayapi/translator.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ func (t *Translator) Translate(resources *Resources) *TranslateResult {
// Process all Listeners for all relevant Gateways.
t.ProcessListeners(gateways, xdsIR, infraIR, resources)

// Process EnvoyPatchPolicies
t.ProcessEnvoyPatchPolicies(resources.EnvoyPatchPolicies, xdsIR)

// Process all Addresses for all relevant Gateways.
t.ProcessAddresses(gateways, xdsIR, infraIR, resources)

Expand Down

0 comments on commit ab905b2

Please sign in to comment.