Skip to content

Commit fafa0d1

Browse files
norman-zonrudrakhp
authored andcommitted
feat(api): Add filterContext field to Lua type in EnvoyExtensionPolicy (envoyproxy#8730)
* feat: add filterContext field to Lua EnvoyExtensionPolicy (envoyproxy#8715) Add an optional `filterContext` field (map[string]string) to the Lua type in EnvoyExtensionPolicySpec. This exposes Envoy's existing LuaPerRoute.filter_context so that a shared Lua script can be parameterized differently per route via request_handle:filterContext(). Without this, users must either duplicate the entire script inline with hardcoded values or resort to EnvoyPatchPolicy to manually patch xDS. Changes: - api: add FilterContext to Lua struct - ir: add FilterContext to IR Lua struct - gatewayapi: pass FilterContext from API to IR in buildLua() - xds: set FilterContext on LuaPerRoute in patchRoute(), converting map[string]string to structpb.Struct - tests: update gatewayapi/xds translator testdata, add e2e test - docs: add FilterContext section to Lua extension task guide Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com> * feat: update release notes Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com> * chore: regenerate test output and helm CRD files Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com> * fix: add missing mocks Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com> * fix(e2e): use retry pattern for lua filter context test Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com> * fix(api): use apiextensionsv1.JSON for Lua filterContext Address review feedback on envoyproxy#8730: - Change FilterContext field type from map[string]string to *apiextensionsv1.JSON in both the API (lua_types.go) and IR (xds.go), matching the existing pattern used by Wasm.Config and DynamicModule.Config. - Drop json/yaml struct tags from ir.Lua.FilterContext, consistent with the other untagged fields on that struct. - Update the xDS translator to unmarshal FilterContext.Raw into structpb.Struct via protojson.Unmarshal, replacing the previous string-only map iteration. - Regenerate deepcopy, CRD manifests, and test fixtures. Users can now pass non-string JSON values (numbers, bools, nested objects) in filterContext without stringifying them. Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com> * fix(e2e): use request_handle:filterContext() and dynamicMetadata to propagate filter context in Lua test filterContext() is only available on request_handle, not response_handle. Read the value in envoy_on_request and store it via dynamicMetadata, then retrieve it in envoy_on_response to set the X-Lua-Filter-Context header. Fixes TestE2E/LuaHTTP/http_route_with_lua_filter_context Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com> * fix(e2e): simplify lua filter context script to use response_handle:filterContext() directly The previous script had a nil-value bug: - ctx["custom_value"] returns nil when filterContext() wraps an empty struct - Storing nil via dynamicMetadata and then using it in headers():add() caused a silent Lua error, so the response header was never set Fix by calling response_handle:filterContext() directly in envoy_on_response, which is available on both request and response handles per Envoy's C++ source. Also add a nil guard for val before calling headers():add() to be safe. Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com> * fix(e2e): use dynamicMetadata to bridge lua filter context between phases Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com> * fix(e2e): simplify lua filter context by storing value string directly Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com> * fix(e2e): read Lua filterContext via ctx:get() instead of table indexing filterContext() returns a MetadataMapWrapper whose only Lua methods are get and __pairs; its metatable __index points at the methods table, so ctx["custom_value"] resolves to a method lookup and always returns nil. Read values via ctx:get("custom_value") instead. The per-route filter config is re-resolved on the response path, so the response handle exposes filterContext directly; the dynamicMetadata bridge is unnecessary and the script is now a single response-phase function. Update the luavalidator mock so StreamHandle:filterContext() returns the Metadata wrapper (with a :get method) matching real Envoy, add a validator test for the get() syntax, and fix the docs examples accordingly. Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com> --------- Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com> Signed-off-by: Rudrakh Panigrahi <rudrakh97@gmail.com> Co-authored-by: Rudrakh Panigrahi <rudrakh97@gmail.com>
1 parent 0ab5d11 commit fafa0d1

27 files changed

Lines changed: 325 additions & 5 deletions

api/v1alpha1/lua_types.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55

66
package v1alpha1
77

8-
import gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
8+
import (
9+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
10+
gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
11+
)
912

1013
// LuaValueType defines the types of values for Lua supported by Envoy Gateway.
1114
// +kubebuilder:validation:Enum=Inline;ValueRef
@@ -45,4 +48,11 @@ type Lua struct {
4548
// +optional
4649
// +unionMember
4750
ValueRef *gwapiv1.LocalObjectReference `json:"valueRef,omitempty"`
51+
// FilterContext is the filter context configuration for the Lua script.
52+
// This must be a JSON object (key/value pairs). The values are made available
53+
// to the Lua script via request_handle:filterContext(). This allows a shared
54+
// script to be parameterized differently per EnvoyExtensionPolicy/route.
55+
//
56+
// +optional
57+
FilterContext *apiextensionsv1.JSON `json:"filterContext,omitempty"`
4858
}

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,6 +1641,13 @@ spec:
16411641
Lua defines a Lua extension
16421642
Only one of Inline or ValueRef must be set
16431643
properties:
1644+
filterContext:
1645+
description: |-
1646+
FilterContext is the filter context configuration for the Lua script.
1647+
This must be a JSON object (key/value pairs). The values are made available
1648+
to the Lua script via request_handle:filterContext(). This allows a shared
1649+
script to be parameterized differently per EnvoyExtensionPolicy/route.
1650+
x-kubernetes-preserve-unknown-fields: true
16441651
inline:
16451652
description: Inline contains the source code as an inline string.
16461653
type: string

charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1640,6 +1640,13 @@ spec:
16401640
Lua defines a Lua extension
16411641
Only one of Inline or ValueRef must be set
16421642
properties:
1643+
filterContext:
1644+
description: |-
1645+
FilterContext is the filter context configuration for the Lua script.
1646+
This must be a JSON object (key/value pairs). The values are made available
1647+
to the Lua script via request_handle:filterContext(). This allows a shared
1648+
script to be parameterized differently per EnvoyExtensionPolicy/route.
1649+
x-kubernetes-preserve-unknown-fields: true
16431650
inline:
16441651
description: Inline contains the source code as an inline string.
16451652
type: string

internal/gatewayapi/envoyextensionpolicy.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -774,8 +774,9 @@ func (t *Translator) buildLua(
774774
return nil, fmt.Errorf("validation failed for lua body in policy with name %v: %w", name, err)
775775
}
776776
return &ir.Lua{
777-
Name: name,
778-
Code: luaCode,
777+
Name: name,
778+
Code: luaCode,
779+
FilterContext: lua.FilterContext,
779780
}, nil
780781
}
781782

internal/gatewayapi/luavalidator/lua_validator_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,19 @@ func Test_BasicValidation(t *testing.T) {
181181
},
182182
expectedErrSubstring: "",
183183
},
184+
{
185+
name: "stream:filterContext:get",
186+
code: `function envoy_on_response(response_handle)
187+
local ctx = response_handle:filterContext()
188+
if ctx ~= nil then
189+
local custom_value = ctx:get("custom_value")
190+
if custom_value ~= nil then
191+
response_handle:headers():add("X-Lua-Filter-Context", custom_value)
192+
end
193+
end
194+
end`,
195+
expectedErrSubstring: "",
196+
},
184197
}
185198
for _, tt := range tests {
186199
t.Run(tt.name, func(t *testing.T) {

internal/gatewayapi/luavalidator/mocks.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,10 @@ function StreamHandle:connectionStreamInfo()
587587
return ConnectionStreamInfo
588588
end
589589

590+
function StreamHandle:filterContext()
591+
return Metadata
592+
end
593+
590594
function StreamHandle:setUpstreamOverrideHost(host, strict)
591595
end
592596

internal/gatewayapi/testdata/envoyextensionpolicy-with-invalid-lua-validation-disabled.out.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ xdsIR:
215215
print("Value is greater than 5")
216216
end
217217
end
218+
FilterContext: null
218219
Name: envoyextensionpolicy/default/policy-for-http-route/lua/0
219220
hostname: www.example.com
220221
isHTTP2: false

internal/gatewayapi/testdata/envoyextensionpolicy-with-invalid-lua-validation-syntax.out.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ xdsIR:
317317
end
318318
return envoy.lua.ResponseStatus.Continue
319319
end
320+
FilterContext: null
320321
Name: envoyextensionpolicy/default/policy-for-http-route/lua/0
321322
hostname: www.example.com
322323
isHTTP2: false

internal/gatewayapi/testdata/envoyextensionpolicy-with-invalid-lua.out.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ xdsIR:
292292
luas:
293293
- Code: function envoy_on_request(request_handle) request_handle:logInfo('Goodbye.')
294294
end
295+
FilterContext: null
295296
Name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/lua/0
296297
hostname: www.example.com
297298
isHTTP2: false
@@ -327,6 +328,7 @@ xdsIR:
327328
luas:
328329
- Code: function envoy_on_request(request_handle) request_handle:logInfo('Goodbye.')
329330
end
331+
FilterContext: null
330332
Name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/lua/0
331333
hostname: www.example.com
332334
isHTTP2: false

0 commit comments

Comments
 (0)