* inject headerModifier to the luaData

* fix lua script and test case
* use ptr instead of struct
* add requestHeaderModifier to testcase debugging toolkit

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>
This commit is contained in:
Megrez Lu 2024-06-25 18:26:13 +08:00
parent db761a979c
commit 34a1848e25
9 changed files with 186 additions and 42 deletions

2
.gitignore vendored
View File

@ -29,3 +29,5 @@ test/e2e/generated/bindata.go
.vscode
.DS_Store
lua_configuration/networking.istio.io/**/testdata/*.lua

View File

@ -100,11 +100,12 @@ func objectToTable(path string) error {
Annotations: testCase.Original.GetAnnotations(),
Spec: testCase.Original.Object["spec"],
},
Matches: step.TrafficRoutingStrategy.Matches,
CanaryWeight: *weight,
StableWeight: 100 - *weight,
CanaryService: canaryService,
StableService: stableService,
Matches: step.TrafficRoutingStrategy.Matches,
CanaryWeight: *weight,
StableWeight: 100 - *weight,
CanaryService: canaryService,
StableService: stableService,
RequestHeaderModifier: step.TrafficRoutingStrategy.RequestHeaderModifier,
}
uList[fmt.Sprintf("step_%d", i)] = data
}
@ -128,11 +129,12 @@ func objectToTable(path string) error {
Annotations: testCase.Original.GetAnnotations(),
Spec: testCase.Original.Object["spec"],
},
Matches: matches,
CanaryWeight: *weight,
StableWeight: 100 - *weight,
CanaryService: canaryService,
StableService: stableService,
Matches: matches,
CanaryWeight: *weight,
StableWeight: 100 - *weight,
CanaryService: canaryService,
StableService: stableService,
RequestHeaderModifier: trafficRouting.Spec.Strategy.RequestHeaderModifier,
}
uList["steps_0"] = data
} else {

View File

@ -19,6 +19,10 @@ rollout:
- type: RegularExpression
name: name
value: ".*demo"
requestHeaderModifier:
set:
- name: "header-foo"
value: "bar"
- matches:
- headers:
- type: Exact
@ -66,6 +70,10 @@ expected:
exact: pc
name:
regex: .*demo
headers:
request:
set:
header-foo: bar
route:
- destination:
host: svc-demo-canary

View File

@ -13,6 +13,10 @@ trafficRouting:
- type: RegularExpression
name: name
value: ".*demo"
requestHeaderModifier:
set:
- name: "header-foo"
value: "bar"
objectRef:
- service: svc-demo
customNetworkRefs:
@ -51,6 +55,10 @@ expected:
exact: pc
name:
regex: .*demo
headers:
request:
set:
header-foo: bar
route:
- destination:
host: svc-demo

View File

@ -14,6 +14,10 @@ trafficRouting:
- type: RegularExpression
name: name
value: ".*demo"
requestHeaderModifier:
set:
- name: "header-foo"
value: "bar"
objectRef:
- service: svc-demo
customNetworkRefs:
@ -50,6 +54,10 @@ expected:
- headers:
name:
regex: .*demo
headers:
request:
set:
header-foo: bar
route:
- destination:
host: svc-demo
@ -58,6 +66,10 @@ expected:
- headers:
user-agent:
exact: pc
headers:
request:
set:
header-foo: bar
route:
- destination:
host: svc-demo

View File

@ -43,7 +43,7 @@ function CalculateWeight(route, stableWeight, n)
end
-- generate routes with matches, insert a rule before other rules, only support http headers, cookies etc.
function GenerateRoutesWithMatches(spec, matches, stableService, canaryService)
function GenerateRoutesWithMatches(spec, matches, stableService, canaryService, requestHeaderModifier)
for _, match in ipairs(matches) do
local route = {}
route["match"] = {}
@ -81,6 +81,23 @@ function GenerateRoutesWithMatches(spec, matches, stableService, canaryService)
end
end
table.insert(route["match"], vsMatch)
if requestHeaderModifier then
route["headers"] = {}
route["headers"]["request"] = {}
for action, headers in pairs(requestHeaderModifier) do
if action == "set" or action == "add" then
route["headers"]["request"][action] = {}
for _, header in ipairs(headers) do
route["headers"]["request"][action][header["name"]] = header["value"]
end
elseif action == "remove" then
route["headers"]["request"]["remove"] = {}
for _, rHeader in ipairs(headers) do
table.insert(route["headers"]["request"]["remove"], rHeader)
end
end
end
end
route.route = {
{
destination = {}
@ -130,7 +147,7 @@ end
if (obj.matches and next(obj.matches) ~= nil)
then
GenerateRoutesWithMatches(spec, obj.matches, obj.stableService, obj.canaryService)
GenerateRoutesWithMatches(spec, obj.matches, obj.stableService, obj.canaryService, obj.requestHeaderModifier)
else
GenerateRoutes(spec, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, "http")
GenerateRoutes(spec, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, "tcp")

View File

@ -39,6 +39,7 @@ import (
"k8s.io/klog/v2"
utilpointer "k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client"
gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
)
const (
@ -47,12 +48,13 @@ const (
)
type LuaData struct {
Data Data
CanaryWeight int32
StableWeight int32
Matches []v1beta1.HttpRouteMatch
CanaryService string
StableService string
Data Data
CanaryWeight int32
StableWeight int32
Matches []v1beta1.HttpRouteMatch
CanaryService string
StableService string
RequestHeaderModifier *gatewayv1beta1.HTTPRequestHeaderFilter
}
type Data struct {
Spec interface{} `json:"spec,omitempty"`
@ -268,13 +270,15 @@ func (r *customController) executeLuaForCanary(spec Data, strategy *v1beta1.Traf
// so we need to pass weight=-1 to indicate the case where weight is nil.
weight = utilpointer.Int32(-1)
}
data := &LuaData{
Data: spec,
CanaryWeight: *weight,
StableWeight: 100 - *weight,
Matches: matches,
CanaryService: r.conf.CanaryService,
StableService: r.conf.StableService,
Data: spec,
CanaryWeight: *weight,
StableWeight: 100 - *weight,
Matches: matches,
CanaryService: r.conf.CanaryService,
StableService: r.conf.StableService,
RequestHeaderModifier: strategy.RequestHeaderModifier,
}
unObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(data)

View File

@ -414,6 +414,78 @@ func TestEnsureRoutes(t *testing.T) {
return done, hasError
},
},
{
name: "Do header-based traffic routing and set header for VirtualService",
getRoutes: func() *v1beta1.TrafficRoutingStrategy {
headerTypeExact := gatewayv1beta1.HeaderMatchExact
return &v1beta1.TrafficRoutingStrategy{
Matches: []v1beta1.HttpRouteMatch{
{
Headers: []gatewayv1beta1.HTTPHeaderMatch{
{
Type: &headerTypeExact,
Name: "user_id",
Value: "123456",
},
},
},
},
RequestHeaderModifier: &gatewayv1beta1.HTTPRequestHeaderFilter{
Set: []gatewayv1beta1.HTTPHeader{
{
Name: "x-env-flag",
Value: "canary",
},
},
},
}
},
getUnstructureds: func() []*unstructured.Unstructured {
objects := make([]*unstructured.Unstructured, 0)
u := &unstructured.Unstructured{}
_ = u.UnmarshalJSON([]byte(virtualServiceDemo))
u.SetAPIVersion("networking.istio.io/v1alpha3")
objects = append(objects, u)
return objects
},
getConfig: func() Config {
return Config{
Key: "rollout-demo",
StableService: "echoserver",
CanaryService: "echoserver-canary",
TrafficConf: []v1beta1.ObjectRef{
{
APIVersion: "networking.istio.io/v1alpha3",
Kind: "VirtualService",
Name: "echoserver",
},
},
}
},
expectUnstructureds: func() []*unstructured.Unstructured {
objects := make([]*unstructured.Unstructured, 0)
u := &unstructured.Unstructured{}
_ = u.UnmarshalJSON([]byte(virtualServiceDemo))
annotations := map[string]string{
OriginalSpecAnnotation: `{"spec":{"hosts":["echoserver.example.com"],"http":[{"route":[{"destination":{"host":"echoserver"}}]}]},"annotations":{"virtual":"test"}}`,
"virtual": "test",
}
u.SetAnnotations(annotations)
specStr := `{"hosts":["echoserver.example.com"],"http":[{"headers":{"request":{"set":{"x-env-flag":"canary"}}},"match":[{"headers":{"user_id":{"exact":"123456"}}}],"route":[{"destination":{"host":"echoserver-canary"}}]},{"route":[{"destination":{"host":"echoserver"}}]}]}`
var spec interface{}
_ = json.Unmarshal([]byte(specStr), &spec)
u.Object["spec"] = spec
objects = append(objects, u)
return objects
},
expectState: func() (bool, bool) {
done := false
hasError := false
return done, hasError
},
},
{
name: "test2, do traffic routing but failed to execute lua",
getRoutes: func() *v1beta1.TrafficRoutingStrategy {
@ -638,11 +710,12 @@ func TestLuaScript(t *testing.T) {
Annotations: testCase.Original.GetAnnotations(),
Spec: testCase.Original.Object["spec"],
},
Matches: step.TrafficRoutingStrategy.Matches,
CanaryWeight: *weight,
StableWeight: 100 - *weight,
CanaryService: canaryService,
StableService: stableService,
Matches: step.TrafficRoutingStrategy.Matches,
CanaryWeight: *weight,
StableWeight: 100 - *weight,
CanaryService: canaryService,
StableService: stableService,
RequestHeaderModifier: step.TrafficRoutingStrategy.RequestHeaderModifier,
}
nSpec, err := executeLua(data, script)
if err != nil {
@ -678,11 +751,12 @@ func TestLuaScript(t *testing.T) {
Annotations: testCase.Original.GetAnnotations(),
Spec: testCase.Original.Object["spec"],
},
Matches: matches,
CanaryWeight: *weight,
StableWeight: 100 - *weight,
CanaryService: canaryService,
StableService: stableService,
Matches: matches,
CanaryWeight: *weight,
StableWeight: 100 - *weight,
CanaryService: canaryService,
StableService: stableService,
RequestHeaderModifier: trafficRouting.Spec.Strategy.RequestHeaderModifier,
}
nSpec, err := executeLua(data, script)
if err != nil {

View File

@ -94,7 +94,7 @@ function CalculateWeight(route, stableWeight, n)
end
-- generate routes with matches, insert a rule before other rules
function GenerateMatchedRoutes(spec, matches, stableService, canaryService, stableWeight, canaryWeight, protocol)
function GenerateMatchedRoutes(spec, matches, stableService, canaryService, stableWeight, canaryWeight, requestHeaderModifier, protocol)
local hasRule, stableServiceSubsets = FindStableServiceSubsets(spec, stableService, protocol)
if (not hasRule) then
return
@ -136,6 +136,23 @@ function GenerateMatchedRoutes(spec, matches, stableService, canaryService, stab
end
end
table.insert(route["match"], vsMatch)
if requestHeaderModifier then
route["headers"] = {}
route["headers"]["request"] = {}
for action, headers in pairs(requestHeaderModifier) do
if action == "set" or action == "add" then
route["headers"]["request"][action] = {}
for _, header in ipairs(headers) do
route["headers"]["request"][action][header["name"]] = header["value"]
end
elseif action == "remove" then
route["headers"]["request"]["remove"] = {}
for _, rHeader in ipairs(headers) do
table.insert(route["headers"]["request"]["remove"], rHeader)
end
end
end
end
route.route = {
{
destination = {}
@ -187,7 +204,7 @@ function GenerateMatchedRoutes(spec, matches, stableService, canaryService, stab
end
-- generate routes without matches, change every rule
function GenerateRoutes(spec, stableService, canaryService, stableWeight, canaryWeight, protocol)
function GenerateRoutes(spec, stableService, canaryService, stableWeight, canaryWeight, requestHeaderModifier, protocol)
local matchedRules = FindMatchedRules(spec, stableService, protocol)
for _, rule in ipairs(matchedRules) do
local canary
@ -218,12 +235,12 @@ function GenerateRoutes(spec, stableService, canaryService, stableWeight, canary
end
if (obj.matches) then
GenerateMatchedRoutes(spec, obj.matches, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, "http")
GenerateMatchedRoutes(spec, obj.matches, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, "tcp")
GenerateMatchedRoutes(spec, obj.matches, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, "tls")
GenerateMatchedRoutes(spec, obj.matches, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, obj.requestHeaderModifier, "http")
GenerateMatchedRoutes(spec, obj.matches, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, obj.requestHeaderModifier,"tcp")
GenerateMatchedRoutes(spec, obj.matches, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, obj.requestHeaderModifier,"tls")
else
GenerateRoutes(spec, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, "http")
GenerateRoutes(spec, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, "tcp")
GenerateRoutes(spec, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, "tls")
GenerateRoutes(spec, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, obj.requestHeaderModifier, "http")
GenerateRoutes(spec, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, obj.requestHeaderModifier, "tcp")
GenerateRoutes(spec, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, obj.requestHeaderModifier, "tls")
end
return obj.data