diff --git a/api/v1alpha1/dynamic_module_types.go b/api/v1alpha1/dynamic_module_types.go index e663d3d0ea..9ccce71a62 100644 --- a/api/v1alpha1/dynamic_module_types.go +++ b/api/v1alpha1/dynamic_module_types.go @@ -120,10 +120,10 @@ type DynamicModule struct { // +kubebuilder:validation:Pattern=`^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$` Name string `json:"name"` - // FilterName identifies a specific filter implementation within the dynamic - // module. A single shared library can contain multiple filter implementations. - // This value is passed to the module's HTTP filter config init function to - // select the appropriate implementation. + // FilterName identifies a specific HTTP filter implementation within the + // dynamic module. A single shared library can contain multiple filter + // implementations; this value is passed to the module's initialization + // function to select one. // If not specified, defaults to an empty string. // // +optional diff --git a/api/v1alpha1/loadbalancer_types.go b/api/v1alpha1/loadbalancer_types.go index 3fe06579b1..da8ed2d087 100644 --- a/api/v1alpha1/loadbalancer_types.go +++ b/api/v1alpha1/loadbalancer_types.go @@ -51,7 +51,6 @@ type LoadBalancer struct { // EnvoyProxy resource's dynamicModules allowlist. // // +optional - // +notImplementedHide DynamicModule *DynamicModuleLBPolicy `json:"dynamicModule,omitempty"` // EndpointOverride defines the configuration for endpoint override. @@ -91,7 +90,6 @@ const ( // BackendUtilizationLoadBalancerType load balancer policy. BackendUtilizationLoadBalancerType LoadBalancerType = "BackendUtilization" // DynamicModuleLoadBalancerType load balancer policy. - // +notImplementedHide DynamicModuleLoadBalancerType LoadBalancerType = "DynamicModule" ) @@ -236,8 +234,6 @@ type BackendUtilization struct { // The module must be registered in the EnvoyProxy resource's dynamicModules allowlist. // // See https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/load_balancing_policies/dynamic_modules/v3/dynamic_modules.proto -// -// +notImplementedHide type DynamicModuleLBPolicy struct { // Name references a dynamic module registered in the EnvoyProxy resource's // dynamicModules list. The referenced module must exist in the registry; @@ -248,18 +244,18 @@ type DynamicModuleLBPolicy struct { // +kubebuilder:validation:Pattern=`^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$` Name string `json:"name"` - // LBPolicyName identifies a specific load balancer implementation within - // the dynamic module. A single shared library can contain multiple LB - // policy implementations. This value is passed to the module's - // initialization function to select the appropriate implementation. + // PolicyName identifies a specific load balancing policy implementation + // within the dynamic module. A single shared library can contain multiple + // policy implementations; this value is passed to the module's + // initialization function to select one. + // If not specified, defaults to an empty string. // - // +kubebuilder:validation:MinLength=1 + // +optional // +kubebuilder:validation:MaxLength=253 - LBPolicyName string `json:"lbPolicyName"` + PolicyName *string `json:"policyName,omitempty"` - // Config is optional configuration for the module's load balancer - // implementation. This is serialized and passed to the module's - // initialization function. + // Config is the configuration for the dynamic module load balancer policy. + // This is serialized as JSON and passed to the module's initialization function. // // +optional Config *apiextensionsv1.JSON `json:"config,omitempty"` diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index ff395861b1..3e3efbd05c 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -2128,6 +2128,11 @@ func (in *DynamicModuleEntry) DeepCopy() *DynamicModuleEntry { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DynamicModuleLBPolicy) DeepCopyInto(out *DynamicModuleLBPolicy) { *out = *in + if in.PolicyName != nil { + in, out := &in.PolicyName, &out.PolicyName + *out = new(string) + **out = **in + } if in.Config != nil { in, out := &in.Config, &out.Config *out = new(apiextensionsv1.JSON) diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml index e9a2c99e6f..9d9397ff39 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml @@ -1197,19 +1197,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -1219,8 +1209,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml index e0bd5d49bc..8d9256daf7 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml @@ -68,10 +68,10 @@ spec: x-kubernetes-preserve-unknown-fields: true filterName: description: |- - FilterName identifies a specific filter implementation within the dynamic - module. A single shared library can contain multiple filter implementations. - This value is passed to the module's HTTP filter config init function to - select the appropriate implementation. + FilterName identifies a specific HTTP filter implementation within the + dynamic module. A single shared library can contain multiple filter + implementations; this value is passed to the module's initialization + function to select one. If not specified, defaults to an empty string. maxLength: 253 type: string @@ -1076,19 +1076,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -1098,8 +1088,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml index 8b19d5b1b0..25c408d6fc 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -12396,19 +12396,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -12418,8 +12408,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -13927,19 +13925,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -13949,8 +13937,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -15620,19 +15616,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -15642,8 +15628,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -17221,19 +17215,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -17243,8 +17227,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml index 34ba4c7907..55a8ede66a 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -1709,19 +1709,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -1731,8 +1721,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -3112,19 +3110,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -3134,8 +3122,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -4808,19 +4804,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -4830,8 +4816,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -6508,19 +6502,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -6530,8 +6514,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml index 3fc645eaf2..d85e048d8c 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml @@ -1196,19 +1196,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -1218,8 +1208,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml index 85c9878352..aa6aca3923 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml @@ -67,10 +67,10 @@ spec: x-kubernetes-preserve-unknown-fields: true filterName: description: |- - FilterName identifies a specific filter implementation within the dynamic - module. A single shared library can contain multiple filter implementations. - This value is passed to the module's HTTP filter config init function to - select the appropriate implementation. + FilterName identifies a specific HTTP filter implementation within the + dynamic module. A single shared library can contain multiple filter + implementations; this value is passed to the module's initialization + function to select one. If not specified, defaults to an empty string. maxLength: 253 type: string @@ -1075,19 +1075,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -1097,8 +1087,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml index 58f11213f9..e8eab8b236 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -12395,19 +12395,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -12417,8 +12407,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -13926,19 +13924,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -13948,8 +13936,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -15619,19 +15615,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -15641,8 +15627,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -17220,19 +17214,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -17242,8 +17226,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml index 8de423fd20..abafe70c92 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -1708,19 +1708,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -1730,8 +1720,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -3111,19 +3109,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -3133,8 +3121,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -4807,19 +4803,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -4829,8 +4815,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -6507,19 +6501,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -6529,8 +6513,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: diff --git a/examples/dynamic-module-lb-test/Dockerfile b/examples/dynamic-module-lb-test/Dockerfile new file mode 100644 index 0000000000..7c1e9ad170 --- /dev/null +++ b/examples/dynamic-module-lb-test/Dockerfile @@ -0,0 +1,17 @@ +# ENVOY_VERSION must match the target Envoy version for ABI compatibility. +ARG ENVOY_VERSION=dev + +FROM golang:1.26.2 AS builder + +WORKDIR /build +COPY go.mod ./ +RUN --mount=type=cache,target=/root/.cache/go-build --mount=type=cache,target=/go/pkg/mod \ + go mod download + +COPY . ./ +RUN --mount=type=cache,target=/root/.cache/go-build --mount=type=cache,target=/go/pkg/mod \ + CGO_ENABLED=1 go build -buildmode=c-shared -o /build/libfirst-host-lb.so . + +ARG ENVOY_VERSION +FROM docker.io/envoyproxy/envoy:distroless-${ENVOY_VERSION} +COPY --from=builder /build/libfirst-host-lb.so /usr/local/lib/libfirst-host-lb.so diff --git a/examples/dynamic-module-lb-test/Makefile b/examples/dynamic-module-lb-test/Makefile new file mode 100644 index 0000000000..71779c3d9e --- /dev/null +++ b/examples/dynamic-module-lb-test/Makefile @@ -0,0 +1,9 @@ + +IMAGE_PREFIX ?= envoyproxy/gateway- +APP_NAME ?= dynamic-module-lb-test +TAG ?= latest +ENVOY_VERSION ?= dev + +.PHONY: docker-buildx +docker-buildx: + docker buildx build . --build-arg ENVOY_VERSION=$(ENVOY_VERSION) -t $(IMAGE_PREFIX)$(APP_NAME):$(TAG) --load diff --git a/examples/dynamic-module-lb-test/go.mod b/examples/dynamic-module-lb-test/go.mod new file mode 100644 index 0000000000..af9aecb17b --- /dev/null +++ b/examples/dynamic-module-lb-test/go.mod @@ -0,0 +1,3 @@ +module github.com/envoyproxy/gateway/examples/dynamic-module-lb-test + +go 1.26.2 diff --git a/examples/dynamic-module-lb-test/main.go b/examples/dynamic-module-lb-test/main.go new file mode 100644 index 0000000000..3083d9d4ec --- /dev/null +++ b/examples/dynamic-module-lb-test/main.go @@ -0,0 +1,86 @@ +// 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 main implements a minimal dynamic module load balancer for e2e testing. +// It always selects the first healthy host at priority 0, which validates that +// the dynamic module LB policy pipeline works end-to-end. +package main + +/* +#include +#include +#include + +// Matches envoy_dynamic_module_type_envoy_buffer from abi.h. +typedef struct { + uintptr_t ptr; + size_t length; +} envoy_dynamic_module_type_envoy_buffer; + +// Matches the return type expected by Envoy for the program init callback. +typedef const void* envoy_dynamic_module_type_abi_version_module_ptr; +*/ +import "C" +import "unsafe" + +// abiVersion must match the Envoy dynamic modules ABI version. +var abiVersion = "v0.1.0\x00" + +//export envoy_dynamic_module_on_program_init +func envoy_dynamic_module_on_program_init() C.envoy_dynamic_module_type_abi_version_module_ptr { + return C.envoy_dynamic_module_type_abi_version_module_ptr(unsafe.Pointer(unsafe.StringData(abiVersion))) +} + +//export envoy_dynamic_module_on_lb_config_new +func envoy_dynamic_module_on_lb_config_new( + lbConfigEnvoyPtr unsafe.Pointer, + name C.envoy_dynamic_module_type_envoy_buffer, + config C.envoy_dynamic_module_type_envoy_buffer, +) unsafe.Pointer { + // Return a non-null sentinel to indicate success. + return unsafe.Pointer(uintptr(1)) +} + +//export envoy_dynamic_module_on_lb_config_destroy +func envoy_dynamic_module_on_lb_config_destroy(configModulePtr unsafe.Pointer) {} + +//export envoy_dynamic_module_on_lb_new +func envoy_dynamic_module_on_lb_new( + configModulePtr unsafe.Pointer, + lbEnvoyPtr unsafe.Pointer, +) unsafe.Pointer { + // Return a non-null sentinel to indicate success. + return unsafe.Pointer(uintptr(1)) +} + +// envoy_dynamic_module_on_lb_choose_host selects a host for an upstream request. +// This simple implementation always picks the first healthy host at priority 0. +// +//export envoy_dynamic_module_on_lb_choose_host +func envoy_dynamic_module_on_lb_choose_host( + lbEnvoyPtr unsafe.Pointer, + lbModulePtr unsafe.Pointer, + contextEnvoyPtr unsafe.Pointer, + resultPriority *C.uint32_t, + resultIndex *C.uint32_t, +) C.bool { + *resultPriority = 0 + *resultIndex = 0 + return true +} + +//export envoy_dynamic_module_on_lb_on_host_membership_update +func envoy_dynamic_module_on_lb_on_host_membership_update( + lbEnvoyPtr unsafe.Pointer, + lbModulePtr unsafe.Pointer, + numHostsAdded C.size_t, + numHostsRemoved C.size_t, +) { +} + +//export envoy_dynamic_module_on_lb_destroy +func envoy_dynamic_module_on_lb_destroy(lbModulePtr unsafe.Pointer) {} + +func main() {} diff --git a/internal/gatewayapi/backendtrafficpolicy.go b/internal/gatewayapi/backendtrafficpolicy.go index cb7c6787cc..8c2aa7e798 100644 --- a/internal/gatewayapi/backendtrafficpolicy.go +++ b/internal/gatewayapi/backendtrafficpolicy.go @@ -519,19 +519,49 @@ func (t *Translator) processBackendTrafficPolicyForRoute( } if policy.Spec.MergeType == nil { - // Set conditions for translation error if it got any - if err := t.translateBackendTrafficPolicyForRoute(policy, targetedRoute, currTarget, xdsIR, nil, nil); err != nil { - status.SetTranslationErrorForPolicyAncestors(&policy.Status, - ancestorRefs, - t.GatewayControllerName, - policy.Generation, - status.Error2ConditionMsg(err), - ) + if policyUsesDynamicModuleLoadBalancer(policy) { + // DynamicModule LB validation depends on the parent Gateway's EnvoyProxy + // allowlist, so translate once per unique IRKey (MergeGateways mode shares + // IRKeys across parents) and set status per ancestor. + errByIRKey := make(map[string]error) + translated := make(map[string]struct{}) + for i, pCtx := range parentRefCtxs { + gw := pCtx.GetGateway() + if gw == nil { + continue + } + gwNN := utils.NamespacedName(gw.Gateway) + irKey := t.IRKey(gwNN) + if _, done := translated[irKey]; !done { + translated[irKey] = struct{}{} + if err := t.translateBackendTrafficPolicyForRoute(policy, targetedRoute, currTarget, xdsIR, &gwNN, nil, gw.envoyProxy); err != nil { + errByIRKey[irKey] = err + } + } + if err := errByIRKey[irKey]; err != nil { + status.SetTranslationErrorForPolicyAncestor(&policy.Status, + ancestorRefs[i], + t.GatewayControllerName, + policy.Generation, + status.Error2ConditionMsg(err), + ) + } + } + } else { + if err := t.translateBackendTrafficPolicyForRoute(policy, targetedRoute, currTarget, xdsIR, nil, nil, nil); err != nil { + status.SetTranslationErrorForPolicyAncestors(&policy.Status, + ancestorRefs, + t.GatewayControllerName, + policy.Generation, + status.Error2ConditionMsg(err), + ) + } } } else { for _, parentRefCtx := range parentRefCtxs { for _, listener := range parentRefCtx.listeners { gwNN := utils.NamespacedName(listener.gateway.Gateway) + parentEnvoyProxy := listener.gateway.envoyProxy ancestorRef := getAncestorRefForPolicy(gwNN, &listener.Name) // Find Gateway listener level policy @@ -548,7 +578,7 @@ func (t *Translator) processBackendTrafficPolicyForRoute( gwPolicy := gatewayPolicyMap[gwMapKey] if gwPolicy == nil && listenerPolicy == nil { // not found, fall back to the current policy - if err := t.translateBackendTrafficPolicyForRoute(policy, targetedRoute, currTarget, xdsIR, &gwNN, &listener.Name); err != nil { + if err := t.translateBackendTrafficPolicyForRoute(policy, targetedRoute, currTarget, xdsIR, &gwNN, &listener.Name, parentEnvoyProxy); err != nil { status.SetConditionForPolicyAncestor(&policy.Status, &ancestorRef, t.GatewayControllerName, @@ -568,7 +598,7 @@ func (t *Translator) processBackendTrafficPolicyForRoute( // merge with parent policy if err := t.translateBackendTrafficPolicyForRouteWithMerge( policy, parentPolicy, currTarget, gwNN, &listener.Name, - targetedRoute, xdsIR, + targetedRoute, xdsIR, parentEnvoyProxy, ); err != nil { status.SetConditionForPolicyAncestor(&policy.Status, &ancestorRef, @@ -839,6 +869,15 @@ func resolveBackendTrafficPolicyRouteTargetRef( return route.RouteContext, nil } +// policyUsesDynamicModuleLoadBalancer reports whether the policy's load +// balancer configuration requires per-parent EnvoyProxy resolution. Only the +// DynamicModule LB type validates against EnvoyProxy.spec.dynamicModules; all +// other traffic features are gateway-independent. +func policyUsesDynamicModuleLoadBalancer(policy *egv1a1.BackendTrafficPolicy) bool { + return policy.Spec.LoadBalancer != nil && + policy.Spec.LoadBalancer.Type == egv1a1.DynamicModuleLoadBalancerType +} + func (t *Translator) translateBackendTrafficPolicyForRoute( policy *egv1a1.BackendTrafficPolicy, route RouteContext, @@ -846,8 +885,9 @@ func (t *Translator) translateBackendTrafficPolicyForRoute( xdsIR resource.XdsIRMap, policyTargetGatewayNN *types.NamespacedName, policyTargetListener *gwapiv1.SectionName, + envoyProxy *egv1a1.EnvoyProxy, ) error { - tf, errs := t.buildTrafficFeatures(policy) + tf, errs := t.buildTrafficFeatures(policy, envoyProxy) if tf == nil { // should not happen return nil @@ -871,6 +911,7 @@ func (t *Translator) translateBackendTrafficPolicyForRouteWithMerge( target policyTargetReferenceWithSectionName, policyTargetGatewayNN types.NamespacedName, policyTargetListener *gwapiv1.SectionName, route RouteContext, xdsIR resource.XdsIRMap, + envoyProxy *egv1a1.EnvoyProxy, ) error { mergedPolicy, err := t.mergeBackendTrafficPolicy(policy, parentPolicy) if err != nil { @@ -878,7 +919,7 @@ func (t *Translator) translateBackendTrafficPolicyForRouteWithMerge( } // Build traffic features from the merged policy - tf, errs := t.buildTrafficFeatures(mergedPolicy) + tf, errs := t.buildTrafficFeatures(mergedPolicy, envoyProxy) if tf == nil { // should not happen return nil @@ -893,13 +934,12 @@ func (t *Translator) translateBackendTrafficPolicyForRouteWithMerge( // 2. Only gateway policy has rate limits - preserve gateway policy's rule names // 3. Only route policy has rate limits - use route policy's rule names (default behavior) if policy.Spec.RateLimit != nil && parentPolicy.Spec.RateLimit != nil { - tfGW, _ := t.buildTrafficFeatures(parentPolicy) - tfRoute, _ := t.buildTrafficFeatures(policy) - - if tfGW != nil && tfRoute != nil && - tfGW.RateLimit != nil && tfRoute.RateLimit != nil { - - mergedRL, err := utils.Merge(tfGW.RateLimit, tfRoute.RateLimit, *policy.Spec.MergeType) + rlGW, gwErr := t.buildRateLimit(parentPolicy) + rlRoute, routeErr := t.buildRateLimit(policy) + if err := errors.Join(gwErr, routeErr); err != nil { + errs = errors.Join(errs, perr.WithMessage(err, "RateLimit")) + } else if rlGW != nil && rlRoute != nil { + mergedRL, err := utils.Merge(rlGW, rlRoute, *policy.Spec.MergeType) if err != nil { return fmt.Errorf("error merging rate limits: %w", err) } @@ -908,10 +948,11 @@ func (t *Translator) translateBackendTrafficPolicyForRouteWithMerge( } } else if policy.Spec.RateLimit == nil && parentPolicy.Spec.RateLimit != nil { // Case 2: Only gateway policy has rate limits - preserve gateway policy's rule names - tfGW, _ := t.buildTrafficFeatures(parentPolicy) - if tfGW != nil && tfGW.RateLimit != nil { - // Use the gateway policy's rate limit with its original rule names - tf.RateLimit = tfGW.RateLimit + rlGW, err := t.buildRateLimit(parentPolicy) + if err != nil { + errs = errors.Join(errs, perr.WithMessage(err, "RateLimit")) + } else if rlGW != nil { + tf.RateLimit = rlGW } } // Case 3: Only route policy has rate limits or neither has rate limits - use default behavior (tf already built from merged policy) @@ -1079,7 +1120,7 @@ func (t *Translator) mergeBackendTrafficPolicy(routePolicy, gwPolicy *egv1a1.Bac } // buildTrafficFeatures builds IR traffic features from a BackendTrafficPolicy. -func (t *Translator) buildTrafficFeatures(policy *egv1a1.BackendTrafficPolicy) (*ir.TrafficFeatures, error) { +func (t *Translator) buildTrafficFeatures(policy *egv1a1.BackendTrafficPolicy, envoyProxy *egv1a1.EnvoyProxy) (*ir.TrafficFeatures, error) { var ( rl *ir.RateLimit bl *ir.BandwidthLimit @@ -1114,7 +1155,7 @@ func (t *Translator) buildTrafficFeatures(policy *egv1a1.BackendTrafficPolicy) ( errs = errors.Join(errs, err) } } - if lb, err = buildLoadBalancer(&policy.Spec.ClusterSettings); err != nil { + if lb, err = buildLoadBalancer(&policy.Spec.ClusterSettings, envoyProxy); err != nil { err = perr.WithMessage(err, "LoadBalancer") errs = errors.Join(errs, err) } @@ -1238,7 +1279,7 @@ func (t *Translator) translateBackendTrafficPolicyForGateway( policy *egv1a1.BackendTrafficPolicy, target policyTargetReferenceWithSectionName, gateway *GatewayContext, xdsIR resource.XdsIRMap, ) error { - tf, errs := t.buildTrafficFeatures(policy) + tf, errs := t.buildTrafficFeatures(policy, gateway.envoyProxy) if tf == nil { // should not happen return errs diff --git a/internal/gatewayapi/backendtrafficpolicy_test.go b/internal/gatewayapi/backendtrafficpolicy_test.go index ab6b626ddf..8547487ead 100644 --- a/internal/gatewayapi/backendtrafficpolicy_test.go +++ b/internal/gatewayapi/backendtrafficpolicy_test.go @@ -214,7 +214,7 @@ func TestBuildTrafficFeaturesRejectsRequestBufferWithHTTPUpgrade(t *testing.T) { }, } - tf, err := tr.buildTrafficFeatures(policy) + tf, err := tr.buildTrafficFeatures(policy, nil) require.ErrorContains(t, err, "RequestBuffer: requestBuffer cannot be used together with httpUpgrade") require.NotNil(t, tf) }) @@ -240,7 +240,7 @@ func TestBuildTrafficFeaturesRejectsRequestBufferWithHTTPUpgrade(t *testing.T) { mergedPolicy, err := tr.mergeBackendTrafficPolicy(routePolicy, parentPolicy) require.NoError(t, err) - tf, err := tr.buildTrafficFeatures(mergedPolicy) + tf, err := tr.buildTrafficFeatures(mergedPolicy, nil) require.ErrorContains(t, err, "RequestBuffer: requestBuffer cannot be used together with httpUpgrade") require.NotNil(t, tf) }) diff --git a/internal/gatewayapi/clustersettings.go b/internal/gatewayapi/clustersettings.go index 29d2d918dc..2207ef1d93 100644 --- a/internal/gatewayapi/clustersettings.go +++ b/internal/gatewayapi/clustersettings.go @@ -55,7 +55,14 @@ func translateTrafficFeatures(policy *egv1a1.ClusterSettings) (*ir.TrafficFeatur ret.CircuitBreaker = cb } - if lb, err := buildLoadBalancer(policy); err != nil { + // translateTrafficFeatures serves non-BTP callers (SecurityPolicy, EnvoyExtensionPolicy, + // Listener). DynamicModule LB needs per-Gateway EnvoyProxy resolution which isn't + // available here, so reject it with a context-specific error rather than letting + // buildLoadBalancer surface a misleading "EnvoyProxy is required" message. + if policy.LoadBalancer != nil && policy.LoadBalancer.Type == egv1a1.DynamicModuleLoadBalancerType { + return nil, fmt.Errorf("DynamicModule load balancer policy is only supported in BackendTrafficPolicy") + } + if lb, err := buildLoadBalancer(policy, nil); err != nil { return nil, err } else { ret.LoadBalancer = lb @@ -312,7 +319,7 @@ func buildCircuitBreaker(policy *egv1a1.ClusterSettings) (*ir.CircuitBreaker, er return cb, nil } -func buildLoadBalancer(policy *egv1a1.ClusterSettings) (*ir.LoadBalancer, error) { +func buildLoadBalancer(policy *egv1a1.ClusterSettings, envoyProxy *egv1a1.EnvoyProxy) (*ir.LoadBalancer, error) { if policy.LoadBalancer == nil { return nil, nil } @@ -401,6 +408,31 @@ func buildLoadBalancer(policy *egv1a1.ClusterSettings) (*ir.LoadBalancer, error) Window: ir.MetaV1DurationPtr(d), } } + case egv1a1.DynamicModuleLoadBalancerType: + dm := policy.LoadBalancer.DynamicModule + if dm == nil { + return nil, fmt.Errorf("DynamicModule field is required when type is DynamicModule") + } + if envoyProxy == nil { + return nil, fmt.Errorf("EnvoyProxy is required for DynamicModule load balancer policy") + } + + resolved, err := resolveDynamicModuleEntry(dm.Name, envoyProxy) + if err != nil { + return nil, err + } + + lb = &ir.LoadBalancer{ + DynamicModuleLB: &ir.DynamicModuleLB{ + Name: dm.Name, + PolicyName: ptr.Deref(dm.PolicyName, ""), + Config: dm.Config, + DoNotClose: resolved.DoNotClose, + LoadGlobally: resolved.LoadGlobally, + Path: resolved.Path, + Remote: resolved.Remote, + }, + } } // Add ZoneAware loadbalancer settings @@ -436,6 +468,62 @@ func buildLoadBalancer(policy *egv1a1.ClusterSettings) (*ir.LoadBalancer, error) return lb, nil } +// resolvedDynamicModuleSource holds the resolved source information for a dynamic module entry. +type resolvedDynamicModuleSource struct { + Path string + Remote *ir.RemoteDynamicModuleSource + DoNotClose bool + LoadGlobally bool +} + +// resolveDynamicModuleEntry looks up a dynamic module by name from the EnvoyProxy's +// dynamicModules allowlist and validates/resolves its source configuration. +func resolveDynamicModuleEntry(name string, envoyProxy *egv1a1.EnvoyProxy) (*resolvedDynamicModuleSource, error) { + var entry *egv1a1.DynamicModuleEntry + if envoyProxy != nil { + for i := range envoyProxy.Spec.DynamicModules { + if envoyProxy.Spec.DynamicModules[i].Name == name { + entry = &envoyProxy.Spec.DynamicModules[i] + break + } + } + } + if entry == nil { + return nil, fmt.Errorf("dynamic module %q is not registered in the EnvoyProxy dynamicModules allowlist", name) + } + + resolved := &resolvedDynamicModuleSource{ + DoNotClose: ptr.Deref(entry.DoNotClose, false), + LoadGlobally: ptr.Deref(entry.LoadGlobally, false), + } + + switch sourceType := ptr.Deref(entry.Source.Type, egv1a1.LocalDynamicModuleSourceType); sourceType { + case egv1a1.RemoteDynamicModuleSourceType: + if entry.Source.Remote == nil || entry.Source.Remote.URL == "" { + return nil, fmt.Errorf("dynamic module %q has no remote source URL configured", name) + } + if entry.Source.Remote.SHA256 == "" { + return nil, fmt.Errorf("dynamic module %q has no remote source SHA256 configured", name) + } + if err := validateDynamicModuleRemoteURL(entry.Source.Remote.URL); err != nil { + return nil, fmt.Errorf("dynamic module %q has invalid remote source URL %q: %w", name, entry.Source.Remote.URL, err) + } + resolved.Remote = &ir.RemoteDynamicModuleSource{ + URL: entry.Source.Remote.URL, + SHA256: entry.Source.Remote.SHA256, + } + case egv1a1.LocalDynamicModuleSourceType: + if entry.Source.Local == nil || entry.Source.Local.Path == "" { + return nil, fmt.Errorf("dynamic module %q has no local source path configured", name) + } + resolved.Path = entry.Source.Local.Path + default: + return nil, fmt.Errorf("dynamic module %q has unsupported source type %q", name, sourceType) + } + + return resolved, nil +} + func buildConsistentHashLoadBalancer(policy egv1a1.LoadBalancer) (*ir.ConsistentHash, error) { consistentHash := &ir.ConsistentHash{} diff --git a/internal/gatewayapi/clustersettings_backendutilization_test.go b/internal/gatewayapi/clustersettings_backendutilization_test.go index 502c857f65..889864489e 100644 --- a/internal/gatewayapi/clustersettings_backendutilization_test.go +++ b/internal/gatewayapi/clustersettings_backendutilization_test.go @@ -32,7 +32,7 @@ func TestBuildLoadBalancer_BackendUtilization(t *testing.T) { }, } - lb, err := buildLoadBalancer(policy) + lb, err := buildLoadBalancer(policy, nil) require.NoError(t, err) require.NotNil(t, lb) require.NotNil(t, lb.BackendUtilization) diff --git a/internal/gatewayapi/clustersettings_dynamicmodule_test.go b/internal/gatewayapi/clustersettings_dynamicmodule_test.go new file mode 100644 index 0000000000..c2a96d22ab --- /dev/null +++ b/internal/gatewayapi/clustersettings_dynamicmodule_test.go @@ -0,0 +1,138 @@ +// 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 ( + "testing" + + "github.com/stretchr/testify/require" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + + egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" +) + +func TestBuildLoadBalancer_DynamicModule(t *testing.T) { + envoyProxy := &egv1a1.EnvoyProxy{ + Spec: egv1a1.EnvoyProxySpec{ + DynamicModules: []egv1a1.DynamicModuleEntry{ + { + Name: "my-module", + Source: egv1a1.DynamicModuleSource{ + Type: new(egv1a1.LocalDynamicModuleSourceType), + Local: &egv1a1.LocalDynamicModuleSource{ + Path: "/usr/local/lib/my-module.so", + }, + }, + }, + }, + }, + } + + policy := &egv1a1.ClusterSettings{ + LoadBalancer: &egv1a1.LoadBalancer{ + Type: egv1a1.DynamicModuleLoadBalancerType, + DynamicModule: &egv1a1.DynamicModuleLBPolicy{ + Name: "my-module", + PolicyName: new("round-robin-v2"), + Config: &apiextensionsv1.JSON{Raw: []byte(`{"key":"value"}`)}, + }, + }, + } + + lb, err := buildLoadBalancer(policy, envoyProxy) + require.NoError(t, err) + require.NotNil(t, lb) + require.NotNil(t, lb.DynamicModuleLB) + require.Equal(t, "my-module", lb.DynamicModuleLB.Name) + require.Equal(t, "round-robin-v2", lb.DynamicModuleLB.PolicyName) + require.NotNil(t, lb.DynamicModuleLB.Config) + require.Equal(t, "/usr/local/lib/my-module.so", lb.DynamicModuleLB.Path) +} + +func TestBuildLoadBalancer_DynamicModule_UnregisteredModule(t *testing.T) { + envoyProxy := &egv1a1.EnvoyProxy{ + Spec: egv1a1.EnvoyProxySpec{ + DynamicModules: []egv1a1.DynamicModuleEntry{ + { + Name: "other-module", + Source: egv1a1.DynamicModuleSource{ + Type: new(egv1a1.LocalDynamicModuleSourceType), + Local: &egv1a1.LocalDynamicModuleSource{ + Path: "/usr/local/lib/other.so", + }, + }, + }, + }, + }, + } + + policy := &egv1a1.ClusterSettings{ + LoadBalancer: &egv1a1.LoadBalancer{ + Type: egv1a1.DynamicModuleLoadBalancerType, + DynamicModule: &egv1a1.DynamicModuleLBPolicy{ + Name: "my-module", + PolicyName: new("round-robin-v2"), + }, + }, + } + + _, err := buildLoadBalancer(policy, envoyProxy) + require.Error(t, err) + require.Contains(t, err.Error(), "not registered") +} + +func TestBuildLoadBalancer_DynamicModule_NilEnvoyProxy(t *testing.T) { + policy := &egv1a1.ClusterSettings{ + LoadBalancer: &egv1a1.LoadBalancer{ + Type: egv1a1.DynamicModuleLoadBalancerType, + DynamicModule: &egv1a1.DynamicModuleLBPolicy{ + Name: "my-module", + PolicyName: new("round-robin-v2"), + }, + }, + } + + _, err := buildLoadBalancer(policy, nil) + require.Error(t, err) + require.Contains(t, err.Error(), "EnvoyProxy") +} + +func TestBuildLoadBalancer_DynamicModule_Remote(t *testing.T) { + envoyProxy := &egv1a1.EnvoyProxy{ + Spec: egv1a1.EnvoyProxySpec{ + DynamicModules: []egv1a1.DynamicModuleEntry{ + { + Name: "remote-module", + Source: egv1a1.DynamicModuleSource{ + Type: new(egv1a1.RemoteDynamicModuleSourceType), + Remote: &egv1a1.RemoteDynamicModuleSource{ + URL: "https://example.com/module.so", + SHA256: "abc123def456", + }, + }, + }, + }, + }, + } + + policy := &egv1a1.ClusterSettings{ + LoadBalancer: &egv1a1.LoadBalancer{ + Type: egv1a1.DynamicModuleLoadBalancerType, + DynamicModule: &egv1a1.DynamicModuleLBPolicy{ + Name: "remote-module", + PolicyName: new("custom-lb"), + }, + }, + } + + lb, err := buildLoadBalancer(policy, envoyProxy) + require.NoError(t, err) + require.NotNil(t, lb) + require.NotNil(t, lb.DynamicModuleLB) + require.NotNil(t, lb.DynamicModuleLB.Remote) + require.Equal(t, "https://example.com/module.so", lb.DynamicModuleLB.Remote.URL) + require.Equal(t, "abc123def456", lb.DynamicModuleLB.Remote.SHA256) +} diff --git a/internal/gatewayapi/envoyextensionpolicy.go b/internal/gatewayapi/envoyextensionpolicy.go index 030138cdb6..0a5e267576 100644 --- a/internal/gatewayapi/envoyextensionpolicy.go +++ b/internal/gatewayapi/envoyextensionpolicy.go @@ -1229,69 +1229,26 @@ func (t *Translator) buildDynamicModules( return nil, nil } - // Build registry lookup map from EnvoyProxy - registry := make(map[string]*egv1a1.DynamicModuleEntry) - if envoyProxy != nil { - for i := range envoyProxy.Spec.DynamicModules { - entry := &envoyProxy.Spec.DynamicModules[i] - registry[entry.Name] = entry - } - } - dmIRList := make([]ir.DynamicModule, 0, len(policy.Spec.DynamicModule)) for idx, dm := range policy.Spec.DynamicModule { name := irConfigNameForDynamicModule(policy, idx) - // Validate module exists in registry - entry, ok := registry[dm.Name] - if !ok { - errs = errors.Join(errs, fmt.Errorf("dynamic module %q is not registered in the EnvoyProxy dynamicModules allowlist", dm.Name)) + resolved, err := resolveDynamicModuleEntry(dm.Name, envoyProxy) + if err != nil { + errs = errors.Join(errs, err) continue } - filterName := ptr.Deref(dm.FilterName, "") - dmIR := ir.DynamicModule{ Name: name, - FilterName: filterName, + FilterName: ptr.Deref(dm.FilterName, ""), Config: dm.Config, - DoNotClose: ptr.Deref(entry.DoNotClose, false), - LoadGlobally: ptr.Deref(entry.LoadGlobally, false), + DoNotClose: resolved.DoNotClose, + LoadGlobally: resolved.LoadGlobally, TerminalFilter: ptr.Deref(dm.TerminalFilter, false), - } - - switch sourceType := ptr.Deref(entry.Source.Type, egv1a1.LocalDynamicModuleSourceType); sourceType { - case egv1a1.RemoteDynamicModuleSourceType: - if entry.Source.Remote == nil { - errs = errors.Join(errs, fmt.Errorf("dynamic module %q has no remote source configured", dm.Name)) - continue - } - if entry.Source.Remote.URL == "" { - errs = errors.Join(errs, fmt.Errorf("dynamic module %q has no remote source URL configured", dm.Name)) - continue - } - if entry.Source.Remote.SHA256 == "" { - errs = errors.Join(errs, fmt.Errorf("dynamic module %q has no remote source SHA256 configured", dm.Name)) - continue - } - if err := validateDynamicModuleRemoteURL(entry.Source.Remote.URL); err != nil { - errs = errors.Join(errs, fmt.Errorf("dynamic module %q has invalid remote source URL %q: %w", dm.Name, entry.Source.Remote.URL, err)) - continue - } - dmIR.Remote = &ir.RemoteDynamicModuleSource{ - URL: entry.Source.Remote.URL, - SHA256: entry.Source.Remote.SHA256, - } - case egv1a1.LocalDynamicModuleSourceType: - if entry.Source.Local == nil { - errs = errors.Join(errs, fmt.Errorf("dynamic module %q has no local source configured", dm.Name)) - continue - } - dmIR.Path = entry.Source.Local.Path - default: - errs = errors.Join(errs, fmt.Errorf("dynamic module %q has unsupported source type %q", dm.Name, sourceType)) - continue + Path: resolved.Path, + Remote: resolved.Remote, } dmIRList = append(dmIRList, dmIR) diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-dynamicmodule-lb-merge-gateways.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-dynamicmodule-lb-merge-gateways.in.yaml new file mode 100644 index 0000000000..56852f23c8 --- /dev/null +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-dynamicmodule-lb-merge-gateways.in.yaml @@ -0,0 +1,85 @@ +envoyProxyForGatewayClass: + apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyProxy + metadata: + namespace: envoy-gateway-system + name: test + spec: + mergeGateways: true + dynamicModules: + - name: custom-lb-module + source: + type: Local + local: + path: /usr/local/lib/custom_lb.so +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http + protocol: HTTP + port: 80 + hostname: "a.example.com" + allowedRoutes: + namespaces: + from: All +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-2 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http + protocol: HTTP + port: 8080 + hostname: "b.example.com" + allowedRoutes: + namespaces: + from: All +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-1 + spec: + hostnames: + - "a.example.com" + - "b.example.com" + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + sectionName: http + - namespace: envoy-gateway + name: gateway-2 + sectionName: http + rules: + - matches: + - path: + value: "/" + backendRefs: + - name: service-1 + port: 8080 +backendTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + namespace: default + name: policy-for-route + spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-1 + loadBalancer: + type: DynamicModule + dynamicModule: + name: custom-lb-module + policyName: weighted-random diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-dynamicmodule-lb-merge-gateways.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-dynamicmodule-lb-merge-gateways.out.yaml new file mode 100644 index 0000000000..ed53b900f1 --- /dev/null +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-dynamicmodule-lb-merge-gateways.out.yaml @@ -0,0 +1,379 @@ +backendTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + name: policy-for-route + namespace: default + spec: + loadBalancer: + dynamicModule: + name: custom-lb-module + policyName: weighted-random + type: DynamicModule + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-1 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: spec.targetRef is deprecated, use spec.targetRefs instead + reason: DeprecatedField + status: "True" + type: Warning + controllerName: gateway.envoyproxy.io/gatewayclass-controller + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-2 + namespace: envoy-gateway + sectionName: http + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: spec.targetRef is deprecated, use spec.targetRefs instead + reason: DeprecatedField + status: "True" + type: Warning + controllerName: gateway.envoyproxy.io/gatewayclass-controller +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + hostname: a.example.com + name: http + port: 80 + protocol: HTTP + status: + listeners: + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: gateway-2 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + hostname: b.example.com + name: http + port: 8080 + protocol: HTTP + status: + listeners: + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: httproute-1 + namespace: default + spec: + hostnames: + - a.example.com + - b.example.com + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + sectionName: http + - name: gateway-2 + namespace: envoy-gateway + sectionName: http + rules: + - backendRefs: + - name: service-1 + port: 8080 + matches: + - path: + value: / + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: envoy-gateway + sectionName: http + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-2 + namespace: envoy-gateway + sectionName: http +infraIR: + envoy-gateway-class: + proxy: + config: + apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyProxy + metadata: + name: test + namespace: envoy-gateway-system + spec: + dynamicModules: + - name: custom-lb-module + source: + local: + path: /usr/local/lib/custom_lb.so + type: Local + logging: {} + mergeGateways: true + status: {} + listeners: + - name: envoy-gateway/gateway-1/http + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + - name: envoy-gateway/gateway-2/http + ports: + - containerPort: 8080 + name: http-8080 + protocol: HTTP + servicePort: 8080 + metadata: + labels: + gateway.envoyproxy.io/owning-gatewayclass: envoy-gateway-class + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: envoy-gateway-class + namespace: envoy-gateway-system +xdsIR: + envoy-gateway-class: + accessLog: + json: + - path: /dev/stdout + globalResources: + proxyServiceCluster: + metadata: + kind: Service + name: envoy-envoy-gateway-class-3b1df594 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway-class + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + kind: Service + name: envoy-envoy-gateway-class-3b1df594 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway-class + protocol: TCP + http: + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - a.example.com + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway-1/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + routes: + - destination: + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: a.example.com + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + policies: + - kind: BackendTrafficPolicy + name: policy-for-route + namespace: default + name: httproute/default/httproute-1/rule/0/match/0/a_example_com + pathMatch: + distinct: false + name: "" + prefix: / + traffic: + loadBalancer: + dynamicModuleLB: + doNotClose: false + loadGlobally: false + name: custom-lb-module + path: /usr/local/lib/custom_lb.so + policyName: weighted-random + - address: 0.0.0.0 + externalPort: 8080 + hostnames: + - b.example.com + metadata: + kind: Gateway + name: gateway-2 + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway-2/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 8080 + routes: + - destination: + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: b.example.com + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + policies: + - kind: BackendTrafficPolicy + name: policy-for-route + namespace: default + name: httproute/default/httproute-1/rule/0/match/0/b_example_com + pathMatch: + distinct: false + name: "" + prefix: / + traffic: + loadBalancer: + dynamicModuleLB: + doNotClose: false + loadGlobally: false + name: custom-lb-module + path: /usr/local/lib/custom_lb.so + policyName: weighted-random + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-dynamicmodule-lb.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-dynamicmodule-lb.in.yaml new file mode 100644 index 0000000000..871a06d411 --- /dev/null +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-dynamicmodule-lb.in.yaml @@ -0,0 +1,71 @@ +envoyProxiesForGateways: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyProxy + metadata: + namespace: envoy-gateway + name: proxy-config + spec: + dynamicModules: + - name: custom-lb-module + source: + type: Local + local: + path: /usr/local/lib/custom_lb.so +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + infrastructure: + parametersRef: + group: gateway.envoyproxy.io + kind: EnvoyProxy + name: proxy-config + listeners: + - name: http + protocol: HTTP + port: 80 + allowedRoutes: + namespaces: + from: All +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-1 + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + sectionName: http + rules: + - matches: + - path: + value: "/" + backendRefs: + - name: service-1 + port: 8080 +backendTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + namespace: default + name: policy-for-route + spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-1 + loadBalancer: + type: DynamicModule + dynamicModule: + name: custom-lb-module + policyName: weighted-random + config: + key: value diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-dynamicmodule-lb.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-dynamicmodule-lb.out.yaml new file mode 100644 index 0000000000..31a2c7b502 --- /dev/null +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-dynamicmodule-lb.out.yaml @@ -0,0 +1,246 @@ +backendTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + name: policy-for-route + namespace: default + spec: + loadBalancer: + dynamicModule: + config: + key: value + name: custom-lb-module + policyName: weighted-random + type: DynamicModule + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-1 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: spec.targetRef is deprecated, use spec.targetRefs instead + reason: DeprecatedField + status: "True" + type: Warning + controllerName: gateway.envoyproxy.io/gatewayclass-controller +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + infrastructure: + parametersRef: + group: gateway.envoyproxy.io + kind: EnvoyProxy + name: proxy-config + listeners: + - allowedRoutes: + namespaces: + from: All + name: http + port: 80 + protocol: HTTP + status: + listeners: + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: httproute-1 + namespace: default + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + sectionName: http + rules: + - backendRefs: + - name: service-1 + port: 8080 + matches: + - path: + value: / + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: envoy-gateway + sectionName: http +infraIR: + envoy-gateway/gateway-1: + proxy: + config: + apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyProxy + metadata: + name: proxy-config + namespace: envoy-gateway + spec: + dynamicModules: + - name: custom-lb-module + source: + local: + path: /usr/local/lib/custom_lb.so + type: Local + logging: {} + status: {} + listeners: + - name: envoy-gateway/gateway-1/http + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: envoy-gateway/gateway-1 + namespace: envoy-gateway-system +xdsIR: + envoy-gateway/gateway-1: + accessLog: + json: + - path: /dev/stdout + globalResources: + proxyServiceCluster: + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-1-196ae069 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-1 + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-1-196ae069 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-1 + protocol: TCP + http: + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - '*' + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway-1/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + routes: + - destination: + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: gateway.envoyproxy.io + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + policies: + - kind: BackendTrafficPolicy + name: policy-for-route + namespace: default + name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io + pathMatch: + distinct: false + name: "" + prefix: / + traffic: + loadBalancer: + dynamicModuleLB: + config: + key: value + doNotClose: false + loadGlobally: false + name: custom-lb-module + path: /usr/local/lib/custom_lb.so + policyName: weighted-random + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-invalid-dynamicmodule-lb.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-invalid-dynamicmodule-lb.in.yaml new file mode 100644 index 0000000000..f6e4538e76 --- /dev/null +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-invalid-dynamicmodule-lb.in.yaml @@ -0,0 +1,69 @@ +envoyProxiesForGateways: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyProxy + metadata: + namespace: envoy-gateway + name: proxy-config + spec: + dynamicModules: + - name: allowed-module + source: + type: Local + local: + path: /usr/local/lib/allowed.so +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + infrastructure: + parametersRef: + group: gateway.envoyproxy.io + kind: EnvoyProxy + name: proxy-config + listeners: + - name: http + protocol: HTTP + port: 80 + allowedRoutes: + namespaces: + from: All +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-1 + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + sectionName: http + rules: + - matches: + - path: + value: "/" + backendRefs: + - name: service-1 + port: 8080 +backendTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + namespace: default + name: policy-with-unregistered-lb-module + spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-1 + loadBalancer: + type: DynamicModule + dynamicModule: + name: unregistered-lb-module + policyName: weighted-random diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-invalid-dynamicmodule-lb.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-invalid-dynamicmodule-lb.out.yaml new file mode 100644 index 0000000000..3773e3fd65 --- /dev/null +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-invalid-dynamicmodule-lb.out.yaml @@ -0,0 +1,233 @@ +backendTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + name: policy-with-unregistered-lb-module + namespace: default + spec: + loadBalancer: + dynamicModule: + name: unregistered-lb-module + policyName: weighted-random + type: DynamicModule + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-1 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + conditions: + - lastTransitionTime: null + message: 'LoadBalancer: dynamic module "unregistered-lb-module" is not registered + in the EnvoyProxy dynamicModules allowlist.' + reason: Invalid + status: "False" + type: Accepted + - lastTransitionTime: null + message: spec.targetRef is deprecated, use spec.targetRefs instead + reason: DeprecatedField + status: "True" + type: Warning + controllerName: gateway.envoyproxy.io/gatewayclass-controller +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + infrastructure: + parametersRef: + group: gateway.envoyproxy.io + kind: EnvoyProxy + name: proxy-config + listeners: + - allowedRoutes: + namespaces: + from: All + name: http + port: 80 + protocol: HTTP + status: + listeners: + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: httproute-1 + namespace: default + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + sectionName: http + rules: + - backendRefs: + - name: service-1 + port: 8080 + matches: + - path: + value: / + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: envoy-gateway + sectionName: http +infraIR: + envoy-gateway/gateway-1: + proxy: + config: + apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyProxy + metadata: + name: proxy-config + namespace: envoy-gateway + spec: + dynamicModules: + - name: allowed-module + source: + local: + path: /usr/local/lib/allowed.so + type: Local + logging: {} + status: {} + listeners: + - name: envoy-gateway/gateway-1/http + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: envoy-gateway/gateway-1 + namespace: envoy-gateway-system +xdsIR: + envoy-gateway/gateway-1: + accessLog: + json: + - path: /dev/stdout + globalResources: + proxyServiceCluster: + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-1-196ae069 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-1 + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-1-196ae069 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-1 + protocol: TCP + http: + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - '*' + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway-1/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + routes: + - destination: + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 + directResponse: + statusCode: 500 + hostname: gateway.envoyproxy.io + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io + pathMatch: + distinct: false + name: "" + prefix: / + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 diff --git a/internal/ir/xds.go b/internal/ir/xds.go index 9a1c7e91b3..5779ed7a6b 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -3004,6 +3004,8 @@ type LoadBalancer struct { ConsistentHash *ConsistentHash `json:"consistentHash,omitempty" yaml:"consistentHash,omitempty"` // BackendUtilization load balancer policy BackendUtilization *BackendUtilization `json:"backendUtilization,omitempty" yaml:"backendUtilization,omitempty"` + // DynamicModuleLB load balancer policy + DynamicModuleLB *DynamicModuleLB `json:"dynamicModuleLB,omitempty" yaml:"dynamicModuleLB,omitempty"` // PreferLocal defines the configuration related to the distribution of requests between locality zones. PreferLocal *PreferLocalZone `json:"preferLocal,omitempty" yaml:"preferLocal,omitempty"` // WeightedZones defines explicit weight-based traffic distribution across locality zones. @@ -3034,6 +3036,9 @@ func (l *LoadBalancer) Validate() error { if l.BackendUtilization != nil { matchCount++ } + if l.DynamicModuleLB != nil { + matchCount++ + } if matchCount != 1 { errs = errors.Join(errs, ErrLoadBalancerInvalid) } @@ -3073,6 +3078,18 @@ type BackendUtilization struct { KeepResponseHeaders *bool `json:"keepResponseHeaders,omitempty" yaml:"keepResponseHeaders,omitempty"` } +// DynamicModuleLB holds the configuration for a dynamic module load balancer policy. +// +k8s:deepcopy-gen=true +type DynamicModuleLB struct { + Name string `json:"name" yaml:"name"` + PolicyName string `json:"policyName" yaml:"policyName"` + Config *apiextensionsv1.JSON `json:"config,omitempty" yaml:"config,omitempty"` + Path string `json:"path,omitempty" yaml:"path,omitempty"` + Remote *RemoteDynamicModuleSource `json:"remote,omitempty" yaml:"remote,omitempty"` + DoNotClose bool `json:"doNotClose" yaml:"doNotClose"` + LoadGlobally bool `json:"loadGlobally" yaml:"loadGlobally"` +} + // ConsistentHash load balancer settings // +k8s:deepcopy-gen=true type ConsistentHash struct { diff --git a/internal/ir/xds_loadbalancer_dynamicmodule_test.go b/internal/ir/xds_loadbalancer_dynamicmodule_test.go new file mode 100644 index 0000000000..93d644c95d --- /dev/null +++ b/internal/ir/xds_loadbalancer_dynamicmodule_test.go @@ -0,0 +1,59 @@ +// 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 ir + +import ( + "testing" + + "github.com/stretchr/testify/require" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" +) + +func TestLoadBalancerValidate_DynamicModuleLB(t *testing.T) { + lb := LoadBalancer{ + DynamicModuleLB: &DynamicModuleLB{ + Name: "my-module", + PolicyName: "my-lb-policy", + }, + } + require.NoError(t, lb.Validate()) +} + +func TestLoadBalancerValidate_DynamicModuleLB_WithOther(t *testing.T) { + lb := LoadBalancer{ + DynamicModuleLB: &DynamicModuleLB{ + Name: "my-module", + PolicyName: "my-lb-policy", + }, + Random: &Random{}, + } + require.EqualError(t, lb.Validate(), ErrLoadBalancerInvalid.Error()) +} + +func TestDynamicModuleLB_WithConfig(t *testing.T) { + lb := LoadBalancer{ + DynamicModuleLB: &DynamicModuleLB{ + Name: "my-module", + PolicyName: "my-lb-policy", + Config: &apiextensionsv1.JSON{Raw: []byte(`{"key":"value"}`)}, + }, + } + require.NoError(t, lb.Validate()) +} + +func TestDynamicModuleLB_WithRemote(t *testing.T) { + lb := LoadBalancer{ + DynamicModuleLB: &DynamicModuleLB{ + Name: "my-module", + PolicyName: "my-lb-policy", + Remote: &RemoteDynamicModuleSource{ + URL: "https://example.com/module.so", + SHA256: "abc123", + }, + }, + } + require.NoError(t, lb.Validate()) +} diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go index 56d5300387..f54e60f938 100644 --- a/internal/ir/zz_generated.deepcopy.go +++ b/internal/ir/zz_generated.deepcopy.go @@ -1402,6 +1402,31 @@ func (in *DynamicModule) DeepCopy() *DynamicModule { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DynamicModuleLB) DeepCopyInto(out *DynamicModuleLB) { + *out = *in + if in.Config != nil { + in, out := &in.Config, &out.Config + *out = new(apiextensionsv1.JSON) + (*in).DeepCopyInto(*out) + } + if in.Remote != nil { + in, out := &in.Remote, &out.Remote + *out = new(RemoteDynamicModuleSource) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DynamicModuleLB. +func (in *DynamicModuleLB) DeepCopy() *DynamicModuleLB { + if in == nil { + return nil + } + out := new(DynamicModuleLB) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *EndpointOverride) DeepCopyInto(out *EndpointOverride) { *out = *in @@ -3074,6 +3099,11 @@ func (in *LoadBalancer) DeepCopyInto(out *LoadBalancer) { *out = new(BackendUtilization) (*in).DeepCopyInto(*out) } + if in.DynamicModuleLB != nil { + in, out := &in.DynamicModuleLB, &out.DynamicModuleLB + *out = new(DynamicModuleLB) + (*in).DeepCopyInto(*out) + } if in.PreferLocal != nil { in, out := &in.PreferLocal, &out.PreferLocal *out = new(PreferLocalZone) diff --git a/internal/xds/translator/cluster.go b/internal/xds/translator/cluster.go index 40249b03bb..939f432555 100644 --- a/internal/xds/translator/cluster.go +++ b/internal/xds/translator/cluster.go @@ -17,12 +17,14 @@ import ( endpointv3 "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" dfpv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/clusters/dynamic_forward_proxy/v3" commondfpv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/common/dynamic_forward_proxy/v3" + dmconfigv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/dynamic_modules/v3" codecv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/upstream_codec/v3" hcmv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3" preservecasev3 "github.com/envoyproxy/go-control-plane/envoy/extensions/http/header_formatters/preserve_case/v3" cswrrv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3" cluster_providedv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/cluster_provided/v3" commonv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/common/v3" + dmlbv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/dynamic_modules/v3" least_requestv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/least_request/v3" maglevv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/maglev/v3" override_hostv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/override_host/v3" @@ -452,6 +454,50 @@ func buildXdsCluster(args *xdsClusterArgs) (*buildClusterResult, error) { return nil, err } cluster.LoadBalancingPolicy = backendUtilizationPolicy + case args.loadBalancer.DynamicModuleLB != nil: + dm := args.loadBalancer.DynamicModuleLB + + // Name is the dlopen identifier; Module provides the binary source and + // overrides the default path-based resolution. + dmConfig := &dmconfigv3.DynamicModuleConfig{ + Name: dm.Name, + DoNotClose: dm.DoNotClose, + LoadGlobally: dm.LoadGlobally, + } + + if dm.Remote != nil || dm.Path != "" { + moduleSource, err := dynamicModuleAsyncDataSource(dm.Remote, dm.Path) + if err != nil { + return nil, err + } + dmConfig.Module = moduleSource + } + + dmlbConfig := &dmlbv3.DynamicModulesLoadBalancerConfig{ + DynamicModuleConfig: dmConfig, + LbPolicyName: dm.PolicyName, + } + + if dm.Config != nil && dm.Config.Raw != nil { + configAny, err := anypb.New(wrapperspb.String(string(dm.Config.Raw))) + if err != nil { + return nil, err + } + dmlbConfig.LbPolicyConfig = configAny + } + + typedDMLB, err := proto.ToAnyWithValidation(dmlbConfig) + if err != nil { + return nil, err + } + cluster.LoadBalancingPolicy = &clusterv3.LoadBalancingPolicy{ + Policies: []*clusterv3.LoadBalancingPolicy_Policy{{ + TypedExtensionConfig: &corev3.TypedExtensionConfig{ + Name: "envoy.load_balancing_policies.dynamic_modules", + TypedConfig: typedDMLB, + }, + }}, + } } if args.healthCheck != nil && args.healthCheck.Active != nil { diff --git a/internal/xds/translator/cluster_test.go b/internal/xds/translator/cluster_test.go index 368ef6cad2..6a45f6d1cb 100644 --- a/internal/xds/translator/cluster_test.go +++ b/internal/xds/translator/cluster_test.go @@ -13,6 +13,7 @@ import ( clusterv3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" endpointv3 "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" cswrrv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3" + dmlbv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/dynamic_modules/v3" override_hostv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/override_host/v3" wrr_localityv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/wrr_locality/v3" "github.com/google/go-cmp/cmp" @@ -21,6 +22,7 @@ import ( "google.golang.org/protobuf/testing/protocmp" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/wrapperspb" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "sigs.k8s.io/yaml" "github.com/envoyproxy/gateway/internal/ir" @@ -566,3 +568,107 @@ func TestGetHealthCheckOverridesHostname(t *testing.T) { }) } } + +func TestBuildClusterWithDynamicModuleLB(t *testing.T) { + args := &xdsClusterArgs{ + name: "test-cluster-dmlb", + endpointType: EndpointTypeStatic, + settings: []*ir.DestinationSetting{{ + Endpoints: []*ir.DestinationEndpoint{{Host: "127.0.0.1", Port: 8080}}, + }}, + loadBalancer: &ir.LoadBalancer{DynamicModuleLB: &ir.DynamicModuleLB{ + Name: "my-module", + PolicyName: "round-robin-v2", + Path: "/usr/local/lib/my-module.so", + }}, + } + + result, err := buildXdsCluster(args) + require.NoError(t, err) + require.NotNil(t, result) + cluster := result.cluster + require.NotNil(t, cluster) + + require.NotNil(t, cluster.LoadBalancingPolicy) + require.Len(t, cluster.LoadBalancingPolicy.Policies, 1) + + policy := cluster.LoadBalancingPolicy.Policies[0] + require.NotNil(t, policy) + require.NotNil(t, policy.TypedExtensionConfig) + require.Equal(t, "envoy.load_balancing_policies.dynamic_modules", policy.TypedExtensionConfig.Name) + require.NotNil(t, policy.TypedExtensionConfig.TypedConfig) + require.Equal(t, "type.googleapis.com/envoy.extensions.load_balancing_policies.dynamic_modules.v3.DynamicModulesLoadBalancerConfig", policy.TypedExtensionConfig.TypedConfig.TypeUrl) +} + +func TestBuildClusterWithDynamicModuleLBConfig(t *testing.T) { + args := &xdsClusterArgs{ + name: "test-cluster-dmlb-cfg", + endpointType: EndpointTypeStatic, + settings: []*ir.DestinationSetting{{ + Endpoints: []*ir.DestinationEndpoint{{Host: "127.0.0.1", Port: 8080}}, + }}, + loadBalancer: &ir.LoadBalancer{DynamicModuleLB: &ir.DynamicModuleLB{ + Name: "my-module", + PolicyName: "custom-lb", + Path: "/usr/local/lib/my-module.so", + Config: &apiextensionsv1.JSON{Raw: []byte(`{"key":"value"}`)}, + DoNotClose: true, + LoadGlobally: true, + }}, + } + + result, err := buildXdsCluster(args) + require.NoError(t, err) + require.NotNil(t, result) + cluster := result.cluster + + require.NotNil(t, cluster.LoadBalancingPolicy) + require.Len(t, cluster.LoadBalancingPolicy.Policies, 1) + + policy := cluster.LoadBalancingPolicy.Policies[0] + + dmlbConfig := &dmlbv3.DynamicModulesLoadBalancerConfig{} + err = policy.TypedExtensionConfig.TypedConfig.UnmarshalTo(dmlbConfig) + require.NoError(t, err) + require.Equal(t, "custom-lb", dmlbConfig.LbPolicyName) + require.NotNil(t, dmlbConfig.LbPolicyConfig) + require.NotNil(t, dmlbConfig.DynamicModuleConfig) + require.Equal(t, "my-module", dmlbConfig.DynamicModuleConfig.Name) + require.True(t, dmlbConfig.DynamicModuleConfig.DoNotClose) + require.True(t, dmlbConfig.DynamicModuleConfig.LoadGlobally) +} + +func TestBuildClusterWithDynamicModuleLBRemote(t *testing.T) { + args := &xdsClusterArgs{ + name: "test-cluster-dmlb-remote", + endpointType: EndpointTypeStatic, + settings: []*ir.DestinationSetting{{ + Endpoints: []*ir.DestinationEndpoint{{Host: "127.0.0.1", Port: 8080}}, + }}, + loadBalancer: &ir.LoadBalancer{DynamicModuleLB: &ir.DynamicModuleLB{ + Name: "my-module", + PolicyName: "remote-lb", + Remote: &ir.RemoteDynamicModuleSource{ + URL: "https://example.com/module.so", + SHA256: "abc123def456", + }, + }}, + } + + result, err := buildXdsCluster(args) + require.NoError(t, err) + require.NotNil(t, result) + cluster := result.cluster + + require.NotNil(t, cluster.LoadBalancingPolicy) + require.Len(t, cluster.LoadBalancingPolicy.Policies, 1) + + policy := cluster.LoadBalancingPolicy.Policies[0] + + dmlbConfig := &dmlbv3.DynamicModulesLoadBalancerConfig{} + err = policy.TypedExtensionConfig.TypedConfig.UnmarshalTo(dmlbConfig) + require.NoError(t, err) + require.Equal(t, "remote-lb", dmlbConfig.LbPolicyName) + require.NotNil(t, dmlbConfig.DynamicModuleConfig) + require.NotNil(t, dmlbConfig.DynamicModuleConfig.Module) +} diff --git a/internal/xds/translator/dynamicmodule.go b/internal/xds/translator/dynamicmodule.go index c117d29054..4f857a02b0 100644 --- a/internal/xds/translator/dynamicmodule.go +++ b/internal/xds/translator/dynamicmodule.go @@ -121,8 +121,14 @@ func dynamicModuleConfig(dm *ir.DynamicModule) (*dmfilterv3.DynamicModuleFilter, } func dynamicModuleSource(dm *ir.DynamicModule) (*corev3.AsyncDataSource, error) { - if dm.Remote != nil { - uc, err := url2Cluster(dm.Remote.URL) + return dynamicModuleAsyncDataSource(dm.Remote, dm.Path) +} + +// dynamicModuleAsyncDataSource builds an AsyncDataSource for a dynamic module, +// supporting both local file paths and remote HTTP sources. +func dynamicModuleAsyncDataSource(remote *ir.RemoteDynamicModuleSource, path string) (*corev3.AsyncDataSource, error) { + if remote != nil { + uc, err := url2Cluster(remote.URL) if err != nil { return nil, err } @@ -131,13 +137,13 @@ func dynamicModuleSource(dm *ir.DynamicModule) (*corev3.AsyncDataSource, error) Specifier: &corev3.AsyncDataSource_Remote{ Remote: &corev3.RemoteDataSource{ HttpUri: &corev3.HttpUri{ - Uri: dm.Remote.URL, + Uri: remote.URL, HttpUpstreamType: &corev3.HttpUri_Cluster{ Cluster: uc.name, }, Timeout: durationpb.New(defaultExtServiceRequestTimeout), }, - Sha256: dm.Remote.SHA256, + Sha256: remote.SHA256, }, }, }, nil @@ -147,7 +153,7 @@ func dynamicModuleSource(dm *ir.DynamicModule) (*corev3.AsyncDataSource, error) Specifier: &corev3.AsyncDataSource_Local{ Local: &corev3.DataSource{ Specifier: &corev3.DataSource_Filename{ - Filename: dm.Path, + Filename: path, }, }, }, diff --git a/internal/xds/translator/testdata/in/xds-ir/load-balancer.yaml b/internal/xds/translator/testdata/in/xds-ir/load-balancer.yaml index c59f30a804..c2689787ed 100644 --- a/internal/xds/translator/testdata/in/xds-ir/load-balancer.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/load-balancer.yaml @@ -254,3 +254,37 @@ http: - host: "1.2.3.4" port: 50000 name: "seventeenth-route-dest/backend/0" + - name: "eighteenth-route" + hostname: "*" + traffic: + loadBalancer: + dynamicModuleLB: + name: custom-lb-module + policyName: first-host + path: /usr/local/lib/custom_lb.so + destination: + name: "eighteenth-route-dest" + settings: + - endpoints: + - host: "1.2.3.4" + port: 50000 + name: "eighteenth-route-dest/backend/0" + - name: "nineteenth-route" + hostname: "*" + traffic: + loadBalancer: + dynamicModuleLB: + name: custom-lb-module-with-config + policyName: weighted-random + path: /usr/local/lib/custom_lb.so + doNotClose: true + loadGlobally: true + config: + key: value + destination: + name: "nineteenth-route-dest" + settings: + - endpoints: + - host: "1.2.3.4" + port: 50000 + name: "nineteenth-route-dest/backend/0" diff --git a/internal/xds/translator/testdata/out/xds-ir/load-balancer.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/load-balancer.clusters.yaml index cdde7a1721..142e23f678 100644 --- a/internal/xds/translator/testdata/out/xds-ir/load-balancer.clusters.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/load-balancer.clusters.yaml @@ -407,3 +407,62 @@ name: seventeenth-route-dest perConnectionBufferLimitBytes: 32768 type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: eighteenth-route-dest + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.dynamic_modules + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.dynamic_modules.v3.DynamicModulesLoadBalancerConfig + dynamicModuleConfig: + module: + local: + filename: /usr/local/lib/custom_lb.so + name: custom-lb-module + lbPolicyName: first-host + name: eighteenth-route-dest + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: nineteenth-route-dest + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.dynamic_modules + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.dynamic_modules.v3.DynamicModulesLoadBalancerConfig + dynamicModuleConfig: + doNotClose: true + loadGlobally: true + module: + local: + filename: /usr/local/lib/custom_lb.so + name: custom-lb-module-with-config + lbPolicyConfig: + '@type': type.googleapis.com/google.protobuf.StringValue + value: '{"key":"value"}' + lbPolicyName: weighted-random + name: nineteenth-route-dest + perConnectionBufferLimitBytes: 32768 + type: EDS diff --git a/internal/xds/translator/testdata/out/xds-ir/load-balancer.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/load-balancer.endpoints.yaml index 96451679b9..2d6eb48dee 100644 --- a/internal/xds/translator/testdata/out/xds-ir/load-balancer.endpoints.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/load-balancer.endpoints.yaml @@ -202,3 +202,27 @@ loadBalancingWeight: 1 locality: region: seventeenth-route-dest/backend/0 +- clusterName: eighteenth-route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.2.3.4 + portValue: 50000 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: eighteenth-route-dest/backend/0 +- clusterName: nineteenth-route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.2.3.4 + portValue: 50000 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: nineteenth-route-dest/backend/0 diff --git a/internal/xds/translator/testdata/out/xds-ir/load-balancer.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/load-balancer.routes.yaml index 9c2ef1a230..411b4f6558 100644 --- a/internal/xds/translator/testdata/out/xds-ir/load-balancer.routes.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/load-balancer.routes.yaml @@ -149,3 +149,17 @@ cluster: seventeenth-route-dest upgradeConfigs: - upgradeType: websocket + - match: + prefix: / + name: eighteenth-route + route: + cluster: eighteenth-route-dest + upgradeConfigs: + - upgradeType: websocket + - match: + prefix: / + name: nineteenth-route + route: + cluster: nineteenth-route-dest + upgradeConfigs: + - upgradeType: websocket diff --git a/internal/xds/translator/translator.go b/internal/xds/translator/translator.go index 76c2b0ffa8..1f09d7a94c 100644 --- a/internal/xds/translator/translator.go +++ b/internal/xds/translator/translator.go @@ -1172,6 +1172,13 @@ func addXdsCluster(tCtx *types.ResourceVersionTable, args *xdsClusterArgs) error return err } } + + if lb.DynamicModuleLB != nil && lb.DynamicModuleLB.Remote != nil { + if err := addClusterFromURL(lb.DynamicModuleLB.Remote.URL, nil, tCtx); err != nil { + return err + } + } + return nil } diff --git a/release-notes/current.yaml b/release-notes/current.yaml index 274c866955..0e51ab6bb1 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -13,6 +13,7 @@ security updates: | # New features or capabilities added in this release. new features: | + Added support for dynamic module load balancer policy. Added support for configuring optional health check configuration. Added support for shadow mode in local rate limiting. Added support for MergeType in SecurityPolicy to enable route-level policies to merge with parent Gateway/Listener policies, similar to BackendTrafficPolicy. diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 130bddae4d..3a9b06c67f 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -1440,7 +1440,7 @@ _Appears in:_ | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `name` | _string_ | true | | Name references a dynamic module registered in the EnvoyProxy resource's
dynamicModules list. The referenced module must exist in the registry;
otherwise, the policy will be rejected. | -| `filterName` | _string_ | false | | FilterName identifies a specific filter implementation within the dynamic
module. A single shared library can contain multiple filter implementations.
This value is passed to the module's HTTP filter config init function to
select the appropriate implementation.
If not specified, defaults to an empty string. | +| `filterName` | _string_ | false | | FilterName identifies a specific HTTP filter implementation within the
dynamic module. A single shared library can contain multiple filter
implementations; this value is passed to the module's initialization
function to select one.
If not specified, defaults to an empty string. | | `config` | _[JSON](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#json-v1-apiextensions-k8s-io)_ | false | | Config is the configuration for the dynamic module filter.
This is serialized as JSON and passed to the module's initialization function. | | `terminalFilter` | _boolean_ | false | false | TerminalFilter indicates that this dynamic module handles requests without
requiring an upstream backend. The module is responsible for generating and
sending the response to downstream directly.
Defaults to false. | @@ -1479,8 +1479,8 @@ _Appears in:_ | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `name` | _string_ | true | | Name references a dynamic module registered in the EnvoyProxy resource's
dynamicModules list. The referenced module must exist in the registry;
otherwise, the policy will be rejected. | -| `lbPolicyName` | _string_ | true | | LBPolicyName identifies a specific load balancer implementation within
the dynamic module. A single shared library can contain multiple LB
policy implementations. This value is passed to the module's
initialization function to select the appropriate implementation. | -| `config` | _[JSON](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#json-v1-apiextensions-k8s-io)_ | false | | Config is optional configuration for the module's load balancer
implementation. This is serialized and passed to the module's
initialization function. | +| `policyName` | _string_ | false | | PolicyName identifies a specific load balancing policy implementation
within the dynamic module. A single shared library can contain multiple
policy implementations; this value is passed to the module's
initialization function to select one.
If not specified, defaults to an empty string. | +| `config` | _[JSON](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#json-v1-apiextensions-k8s-io)_ | false | | Config is the configuration for the dynamic module load balancer policy.
This is serialized as JSON and passed to the module's initialization function. | #### DynamicModuleSource @@ -3957,6 +3957,7 @@ _Appears in:_ | `type` | _[LoadBalancerType](#loadbalancertype)_ | true | | Type decides the type of Load Balancer policy.
Valid LoadBalancerType values are
"ConsistentHash",
"LeastRequest",
"Random",
"RoundRobin",
"BackendUtilization",
"DynamicModule". | | `consistentHash` | _[ConsistentHash](#consistenthash)_ | false | | ConsistentHash defines the configuration when the load balancer type is
set to ConsistentHash | | `backendUtilization` | _[BackendUtilization](#backendutilization)_ | false | | BackendUtilization defines the configuration when the load balancer type is
set to BackendUtilization. | +| `dynamicModule` | _[DynamicModuleLBPolicy](#dynamicmodulelbpolicy)_ | false | | DynamicModule defines the configuration when the load balancer type is
set to DynamicModule. The referenced module must be registered in the
EnvoyProxy resource's dynamicModules allowlist. | | `endpointOverride` | _[EndpointOverride](#endpointoverride)_ | false | | EndpointOverride defines the configuration for endpoint override.
When specified, the load balancer will attempt to route requests to endpoints
based on the override information extracted from request headers or metadata.
If the override endpoints are not available, the configured load balancer policy will be used as fallback. | | `slowStart` | _[SlowStart](#slowstart)_ | false | | SlowStart defines the configuration related to the slow start load balancer policy.
If set, during slow start window, traffic sent to the newly added hosts will gradually increase.
Supported for RoundRobin, LeastRequest, and BackendUtilization load balancers. | | `zoneAware` | _[ZoneAware](#zoneaware)_ | false | | ZoneAware defines the configuration related to the distribution of requests between locality zones. | @@ -3978,7 +3979,7 @@ _Appears in:_ | `Random` | RandomLoadBalancerType load balancer policy.
| | `RoundRobin` | RoundRobinLoadBalancerType load balancer policy.
| | `BackendUtilization` | BackendUtilizationLoadBalancerType load balancer policy.
| -| `DynamicModule` | DynamicModuleLoadBalancerType load balancer policy.
+notImplementedHide
| +| `DynamicModule` | DynamicModuleLoadBalancerType load balancer policy.
| #### LocalDynamicModuleSource diff --git a/test/cel-validation/backendtrafficpolicy_test.go b/test/cel-validation/backendtrafficpolicy_test.go index 2d400f5705..0c58f7ea8d 100644 --- a/test/cel-validation/backendtrafficpolicy_test.go +++ b/test/cel-validation/backendtrafficpolicy_test.go @@ -985,9 +985,9 @@ func TestBackendTrafficPolicyTarget(t *testing.T) { LoadBalancer: &egv1a1.LoadBalancer{ Type: egv1a1.DynamicModuleLoadBalancerType, DynamicModule: &egv1a1.DynamicModuleLBPolicy{ - Name: "my-module", - LBPolicyName: "round-robin-v2", - Config: &apiextensionsv1.JSON{Raw: []byte(`{"key":"value"}`)}, + Name: "my-module", + PolicyName: new("round-robin-v2"), + Config: &apiextensionsv1.JSON{Raw: []byte(`{"key":"value"}`)}, }, }, }, @@ -1012,8 +1012,8 @@ func TestBackendTrafficPolicyTarget(t *testing.T) { LoadBalancer: &egv1a1.LoadBalancer{ Type: egv1a1.DynamicModuleLoadBalancerType, DynamicModule: &egv1a1.DynamicModuleLBPolicy{ - Name: "my-module", - LBPolicyName: "round-robin-v2", + Name: "my-module", + PolicyName: new("round-robin-v2"), }, }, }, @@ -1063,8 +1063,8 @@ func TestBackendTrafficPolicyTarget(t *testing.T) { LoadBalancer: &egv1a1.LoadBalancer{ Type: egv1a1.RoundRobinLoadBalancerType, DynamicModule: &egv1a1.DynamicModuleLBPolicy{ - Name: "my-module", - LBPolicyName: "round-robin-v2", + Name: "my-module", + PolicyName: new("round-robin-v2"), }, }, }, @@ -1092,8 +1092,8 @@ func TestBackendTrafficPolicyTarget(t *testing.T) { LoadBalancer: &egv1a1.LoadBalancer{ Type: egv1a1.DynamicModuleLoadBalancerType, DynamicModule: &egv1a1.DynamicModuleLBPolicy{ - Name: "my-module", - LBPolicyName: "round-robin-v2", + Name: "my-module", + PolicyName: new("round-robin-v2"), }, SlowStart: &egv1a1.SlowStart{Window: new(gwapiv1.Duration("10ms"))}, }, @@ -1122,8 +1122,8 @@ func TestBackendTrafficPolicyTarget(t *testing.T) { LoadBalancer: &egv1a1.LoadBalancer{ Type: egv1a1.DynamicModuleLoadBalancerType, DynamicModule: &egv1a1.DynamicModuleLBPolicy{ - Name: "my-module", - LBPolicyName: "round-robin-v2", + Name: "my-module", + PolicyName: new("round-robin-v2"), }, ZoneAware: &egv1a1.ZoneAware{PreferLocal: &egv1a1.PreferLocalZone{}}, }, @@ -1152,8 +1152,8 @@ func TestBackendTrafficPolicyTarget(t *testing.T) { LoadBalancer: &egv1a1.LoadBalancer{ Type: egv1a1.DynamicModuleLoadBalancerType, DynamicModule: &egv1a1.DynamicModuleLBPolicy{ - Name: "my-module", - LBPolicyName: "round-robin-v2", + Name: "my-module", + PolicyName: new("round-robin-v2"), }, EndpointOverride: &egv1a1.EndpointOverride{ ExtractFrom: []egv1a1.EndpointOverrideExtractFrom{ diff --git a/test/e2e/testdata/dynamic-module-lb.yaml b/test/e2e/testdata/dynamic-module-lb.yaml new file mode 100644 index 0000000000..2d4c64005a --- /dev/null +++ b/test/e2e/testdata/dynamic-module-lb.yaml @@ -0,0 +1,77 @@ +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: EnvoyProxy +metadata: + name: dynamic-module-lb-proxy + namespace: gateway-conformance-infra +spec: + ipFamily: IPv4 + provider: + type: Kubernetes + kubernetes: + envoyDeployment: + container: + image: envoyproxy/gateway-dynamic-module-lb-test:latest + env: + - name: GODEBUG + value: cgocheck=0 + - name: ENVOY_DYNAMIC_MODULES_SEARCH_PATH + value: /usr/local/lib + dynamicModules: + - name: first-host-lb + source: + local: + path: /usr/local/lib/libfirst-host-lb.so +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: dynamic-module-lb-gateway + namespace: gateway-conformance-infra +spec: + gatewayClassName: "{GATEWAY_CLASS_NAME}" + infrastructure: + parametersRef: + group: gateway.envoyproxy.io + kind: EnvoyProxy + name: dynamic-module-lb-proxy + listeners: + - name: http + port: 80 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: dynamic-module-lb-route + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: dynamic-module-lb-gateway + rules: + - matches: + - path: + type: PathPrefix + value: /dynamic-module-lb + backendRefs: + - name: infra-backend-v1 + port: 8080 +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: BackendTrafficPolicy +metadata: + name: dynamic-module-lb-policy + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: dynamic-module-lb-route + loadBalancer: + type: DynamicModule + dynamicModule: + name: first-host-lb + policyName: first_host diff --git a/test/e2e/tests/dynamic_module_lb.go b/test/e2e/tests/dynamic_module_lb.go new file mode 100644 index 0000000000..f3717c3312 --- /dev/null +++ b/test/e2e/tests/dynamic_module_lb.go @@ -0,0 +1,67 @@ +// 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. + +//go:build e2e + +package tests + +import ( + "testing" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" + "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/kubernetes" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + + "github.com/envoyproxy/gateway/internal/gatewayapi" + "github.com/envoyproxy/gateway/internal/gatewayapi/resource" +) + +func init() { + ConformanceTests = append(ConformanceTests, DynamicModuleLBTest) +} + +var DynamicModuleLBTest = suite.ConformanceTest{ + ShortName: "DynamicModuleLB", + Description: "Test dynamic module load balancer policy that routes traffic to the first healthy host", + Manifests: []string{"testdata/dynamic-module-lb.yaml"}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + t.Run("http route with dynamic module lb policy", func(t *testing.T) { + ns := "gateway-conformance-infra" + routeNN := types.NamespacedName{Name: "dynamic-module-lb-route", Namespace: ns} + gwNN := types.NamespacedName{Name: "dynamic-module-lb-gateway", Namespace: ns} + gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), &gwapiv1.HTTPRoute{}, false, routeNN) + + ancestorRef := gwapiv1.ParentReference{ + Group: gatewayapi.GroupPtr(gwapiv1.GroupName), + Kind: gatewayapi.KindPtr(resource.KindGateway), + Namespace: gatewayapi.NamespacePtr(gwNN.Namespace), + Name: gwapiv1.ObjectName(gwNN.Name), + } + BackendTrafficPolicyMustBeAccepted(t, suite.Client, types.NamespacedName{Name: "dynamic-module-lb-policy", Namespace: ns}, suite.ControllerName, ancestorRef) + + // Wait for the Envoy proxy pods to be running and ready. + gwPodNamespace := GetGatewayResourceNamespace() + WaitForPods(t, suite.Client, gwPodNamespace, map[string]string{ + "gateway.envoyproxy.io/owning-gateway-name": gwNN.Name, + "gateway.envoyproxy.io/owning-gateway-namespace": gwNN.Namespace, + }, corev1.PodRunning, &PodReady) + + expectedResponse := http.ExpectedResponse{ + Request: http.Request{ + Path: "/dynamic-module-lb", + }, + Response: http.Response{ + StatusCodes: []int{200}, + }, + Namespace: ns, + } + + http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, expectedResponse) + }) + }, +} diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml index 00fbbaec7a..b5e28ad7b1 100644 --- a/test/helm/gateway-crds-helm/all.out.yaml +++ b/test/helm/gateway-crds-helm/all.out.yaml @@ -23724,19 +23724,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -23746,8 +23736,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -28332,10 +28330,10 @@ spec: x-kubernetes-preserve-unknown-fields: true filterName: description: |- - FilterName identifies a specific filter implementation within the dynamic - module. A single shared library can contain multiple filter implementations. - This value is passed to the module's HTTP filter config init function to - select the appropriate implementation. + FilterName identifies a specific HTTP filter implementation within the + dynamic module. A single shared library can contain multiple filter + implementations; this value is passed to the module's initialization + function to select one. If not specified, defaults to an empty string. maxLength: 253 type: string @@ -29340,19 +29338,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -29362,8 +29350,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -43723,19 +43719,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -43745,8 +43731,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -45254,19 +45248,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -45276,8 +45260,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -46947,19 +46939,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -46969,8 +46951,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -48548,19 +48538,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -48570,8 +48550,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -51608,19 +51596,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -51630,8 +51608,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -53011,19 +52997,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -53033,8 +53009,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -54707,19 +54691,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -54729,8 +54703,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -56407,19 +56389,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -56429,8 +56401,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: diff --git a/test/helm/gateway-crds-helm/e2e.out.yaml b/test/helm/gateway-crds-helm/e2e.out.yaml index 9886bff5e0..e57425f840 100644 --- a/test/helm/gateway-crds-helm/e2e.out.yaml +++ b/test/helm/gateway-crds-helm/e2e.out.yaml @@ -1697,19 +1697,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -1719,8 +1709,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -6305,10 +6303,10 @@ spec: x-kubernetes-preserve-unknown-fields: true filterName: description: |- - FilterName identifies a specific filter implementation within the dynamic - module. A single shared library can contain multiple filter implementations. - This value is passed to the module's HTTP filter config init function to - select the appropriate implementation. + FilterName identifies a specific HTTP filter implementation within the + dynamic module. A single shared library can contain multiple filter + implementations; this value is passed to the module's initialization + function to select one. If not specified, defaults to an empty string. maxLength: 253 type: string @@ -7313,19 +7311,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -7335,8 +7323,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -21696,19 +21692,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -21718,8 +21704,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -23227,19 +23221,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -23249,8 +23233,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -24920,19 +24912,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -24942,8 +24924,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -26521,19 +26511,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -26543,8 +26523,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -29581,19 +29569,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -29603,8 +29581,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -30984,19 +30970,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -31006,8 +30982,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -32680,19 +32664,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -32702,8 +32676,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -34380,19 +34362,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -34402,8 +34374,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: diff --git a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml index 4781857643..b5f1757643 100644 --- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml +++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml @@ -1697,19 +1697,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -1719,8 +1709,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -6305,10 +6303,10 @@ spec: x-kubernetes-preserve-unknown-fields: true filterName: description: |- - FilterName identifies a specific filter implementation within the dynamic - module. A single shared library can contain multiple filter implementations. - This value is passed to the module's HTTP filter config init function to - select the appropriate implementation. + FilterName identifies a specific HTTP filter implementation within the + dynamic module. A single shared library can contain multiple filter + implementations; this value is passed to the module's initialization + function to select one. If not specified, defaults to an empty string. maxLength: 253 type: string @@ -7313,19 +7311,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -7335,8 +7323,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -21696,19 +21692,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -21718,8 +21704,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -23227,19 +23221,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -23249,8 +23233,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -24920,19 +24912,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -24942,8 +24924,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -26521,19 +26511,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -26543,8 +26523,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -29581,19 +29569,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -29603,8 +29581,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -30984,19 +30970,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -31006,8 +30982,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -32680,19 +32664,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -32702,8 +32676,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: @@ -34380,19 +34362,9 @@ spec: properties: config: description: |- - Config is optional configuration for the module's load balancer - implementation. This is serialized and passed to the module's - initialization function. + Config is the configuration for the dynamic module load balancer policy. + This is serialized as JSON and passed to the module's initialization function. x-kubernetes-preserve-unknown-fields: true - lbPolicyName: - description: |- - LBPolicyName identifies a specific load balancer implementation within - the dynamic module. A single shared library can contain multiple LB - policy implementations. This value is passed to the module's - initialization function to select the appropriate implementation. - maxLength: 253 - minLength: 1 - type: string name: description: |- Name references a dynamic module registered in the EnvoyProxy resource's @@ -34402,8 +34374,16 @@ spec: minLength: 1 pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ type: string + policyName: + description: |- + PolicyName identifies a specific load balancing policy implementation + within the dynamic module. A single shared library can contain multiple + policy implementations; this value is passed to the module's + initialization function to select one. + If not specified, defaults to an empty string. + maxLength: 253 + type: string required: - - lbPolicyName - name type: object endpointOverride: diff --git a/tools/make/examples.mk b/tools/make/examples.mk index ca1f592b7a..0ae92e89a7 100644 --- a/tools/make/examples.mk +++ b/tools/make/examples.mk @@ -1,4 +1,4 @@ -EXAMPLE_APPS := simple-extension-server extension-server envoy-ext-auth grpc-ext-proc preserve-case-backend static-file-server dynamic-module-test backend-utilization +EXAMPLE_APPS := simple-extension-server extension-server envoy-ext-auth grpc-ext-proc preserve-case-backend static-file-server dynamic-module-test dynamic-module-lb-test backend-utilization EXAMPLE_IMAGE_PREFIX ?= envoyproxy/gateway- EXAMPLE_TAG ?= latest diff --git a/tools/osv-scanner/license-scan-config.toml b/tools/osv-scanner/license-scan-config.toml index d7afa24a5c..c2ae14a39e 100644 --- a/tools/osv-scanner/license-scan-config.toml +++ b/tools/osv-scanner/license-scan-config.toml @@ -75,3 +75,10 @@ name = "cyphar.com/go-pathrs" ecosystem = "Go" license.ignore = true reason = "https://github.com/cncf/foundation/issues/1154" + +# Remove this once go-control-plane/contrib gets a proper release tag +[[PackageOverrides]] +name = "github.com/envoyproxy/go-control-plane/contrib" +ecosystem = "Go" +license.override = ["Apache-2.0"] +reason = "go-control-plane is Apache-2.0 licensed, but the pseudo-version prevents license detection"