Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/v1alpha1/trafficrouting_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ type TrafficRoutingRef struct {
// IngressTrafficRouting configuration for ingress controller to control traffic routing
type IngressTrafficRouting struct {
// ClassType refers to the type of `Ingress`.
// current support nginx, aliyun-alb. default is nginx.
// current support nginx, aliyun-alb, aws-alb. default is nginx.
// +optional
ClassType string `json:"classType,omitempty"`
// Name refers to the name of an `Ingress` resource in the same namespace as the `Rollout`
Expand Down
6 changes: 3 additions & 3 deletions config/crd/bases/rollouts.kruise.io_rollouts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -447,9 +447,9 @@ spec:
to route traffic, e.g. Nginx, Alb.
properties:
classType:
description: |-
ClassType refers to the type of `Ingress`.
current support nginx, aliyun-alb. default is nginx.
description: ClassType refers to the type of `Ingress`.
current support nginx, aliyun-alb, aws-alb. default
is nginx.
type: string
name:
description: Name refers to the name of an `Ingress`
Expand Down
6 changes: 3 additions & 3 deletions config/crd/bases/rollouts.kruise.io_trafficroutings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,9 @@ spec:
route traffic, e.g. Nginx, Alb.
properties:
classType:
description: |-
ClassType refers to the type of `Ingress`.
current support nginx, aliyun-alb. default is nginx.
description: ClassType refers to the type of `Ingress`.
current support nginx, aliyun-alb, aws-alb. default is
nginx.
type: string
name:
description: Name refers to the name of an `Ingress` resource
Expand Down
54 changes: 54 additions & 0 deletions lua_configuration/trafficrouting_ingress/aws-alb.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
local annotations = obj.annotations or {}

-- Remove any prior ALB canary annotations
annotations["alb.ingress.kubernetes.io/actions.canary"] = nil
annotations["alb.ingress.kubernetes.io/conditions.canary"] = nil

-- Compute weights
local cw = tonumber(obj.weight) or 0
if cw < 0 then cw = 0 end
if cw > 100 then cw = 100 end
local sw = 100 - cw

-- Build the forward action with *both* target‐groups
local action = {
Type = "forward",
ForwardConfig = {
TargetGroups = {
{ ServiceName = obj.stableService, ServicePort = "80", Weight = sw },
{ ServiceName = obj.canaryService, ServicePort = "80", Weight = cw },
}
}
}
annotations["alb.ingress.kubernetes.io/actions.canary"] = action

-- Build conditions if any
if obj.matches then
local conds = {}
for _, match in ipairs(obj.matches) do
for _, hdr in ipairs(match.headers or {}) do
if hdr.name == "canary-by-cookie" then
table.insert(conds, {
Field = "http-cookie",
HttpCookieConfig = { CookieName = hdr.value, Values = { hdr.value } },
})
elseif hdr.name == "SourceIp" then
table.insert(conds, {
Field = "source-ip",
SourceIpConfig = { Values = { hdr.value } },
})
else
table.insert(conds, {
Field = "http-header",
HttpHeaderConfig = {
HttpHeaderName = hdr.name,
Values = { hdr.value },
},
})
end
end
end
annotations["alb.ingress.kubernetes.io/conditions.canary"] = conds
end

return annotations
2 changes: 2 additions & 0 deletions pkg/trafficrouting/network/ingress/ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,13 +236,15 @@ func (r *ingressController) executeLuaForCanary(annotations map[string]string, w
Annotations map[string]string
Weight string
Matches []v1beta1.HttpRouteMatch
StableService string
CanaryService string
RequestHeaderModifier *gatewayv1beta1.HTTPHeaderFilter
}
data := &LuaData{
Annotations: annotations,
Weight: fmt.Sprintf("%d", *weight),
Matches: matches,
StableService: r.conf.StableService,
CanaryService: r.conf.CanaryService,
RequestHeaderModifier: headerModifier,
}
Expand Down
98 changes: 98 additions & 0 deletions pkg/trafficrouting/network/ingress/ingress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,58 @@ var (
annotations[conditionKey] = json.encode(conditions)
return annotations
`,
fmt.Sprintf("%s.aws-alb", configuration.LuaTrafficRoutingIngressTypePrefix): `
-- aws-alb.lua
local annotations = obj.annotations or {}
annotations["alb.ingress.kubernetes.io/actions.canary"] = nil
annotations["alb.ingress.kubernetes.io/conditions.canary"] = nil

local cw = tonumber(obj.weight) or 0
if cw < 0 then cw = 0 end
if cw > 100 then cw = 100 end
local sw = 100 - cw

local action = {
Type = "forward",
ForwardConfig = {
TargetGroups = {
{ ServiceName = obj.stableService, ServicePort = "80", Weight = sw },
{ ServiceName = obj.canaryService, ServicePort = "80", Weight = cw },
}
}
}
annotations["alb.ingress.kubernetes.io/actions.canary"] = json.encode(action)

if obj.matches then
local conds = {}
for _, m in ipairs(obj.matches) do
for _, hdr in ipairs(m.headers or {}) do
if hdr.name == "canary-by-cookie" then
table.insert(conds, {
Field = "http-cookie",
HttpCookieConfig = { CookieName = hdr.value, Values = { hdr.value } }
})
elseif hdr.name == "SourceIp" then
table.insert(conds, {
Field = "source-ip",
SourceIpConfig = { Values = { hdr.value } }
})
else
table.insert(conds, {
Field = "http-header",
HttpHeaderConfig = {
HttpHeaderName = hdr.name,
Values = { hdr.value }
}
})
end
end
end
annotations["alb.ingress.kubernetes.io/conditions.canary"] = json.encode(conds)
end

return annotations
`,
},
}

Expand Down Expand Up @@ -658,6 +710,52 @@ func TestEnsureRoutes(t *testing.T) {
return expect
},
},
{
name: "ensure routes test aws-alb forward+conditions",
ingressType: "aws-alb",
getConfigmap: func() *corev1.ConfigMap {
return demoConf.DeepCopy()
},
getIngress: func() []*netv1.Ingress {
canary := demoIngress.DeepCopy()
canary.Name = "echoserver-canary"

// Expect both stable(80%) and canary(0%) in JSON
canary.Annotations["alb.ingress.kubernetes.io/actions.canary"] =
`{"Type":"forward","ForwardConfig":{"TargetGroups":[{"ServiceName":"echoserver","ServicePort":"80","Weight":100},{"ServiceName":"echoserver-canary","ServicePort":"80","Weight":0}]}}`
// And any header‐match condition
canary.Annotations["alb.ingress.kubernetes.io/conditions.canary"] =
`[{"Field":"http-header","HttpHeaderConfig":{"HttpHeaderName":"user_id","Values":["123456"]}}]`

canary.Spec.Rules[0].HTTP.Paths = canary.Spec.Rules[0].HTTP.Paths[:1]
canary.Spec.Rules[0].HTTP.Paths[0].Backend.Service.Name = "echoserver-canary"
return []*netv1.Ingress{demoIngress.DeepCopy(), canary}
},
getRoutes: func() *v1beta1.CanaryStep {
return &v1beta1.CanaryStep{
TrafficRoutingStrategy: v1beta1.TrafficRoutingStrategy{
Traffic: utilpointer.String("0"),
Matches: []v1beta1.HttpRouteMatch{{
Headers: []gatewayv1beta1.HTTPHeaderMatch{{
Name: "user_id",
Value: "123456",
}},
}},
},
}
},
expectIngress: func() *netv1.Ingress {
e := demoIngress.DeepCopy()
e.Name = "echoserver-canary"
e.Annotations = map[string]string{
"alb.ingress.kubernetes.io/actions.canary": `{"Type":"forward","ForwardConfig":{"TargetGroups":[{"ServiceName":"echoserver","ServicePort":"80","Weight":100},{"ServiceName":"echoserver-canary","ServicePort":"80","Weight":0}]}}`,
"alb.ingress.kubernetes.io/conditions.canary": `[{"Field":"http-header","HttpHeaderConfig":{"HttpHeaderName":"user_id","Values":["123456"]}}]`,
}
e.Spec.Rules[0].HTTP.Paths = e.Spec.Rules[0].HTTP.Paths[:1]
e.Spec.Rules[0].HTTP.Paths[0].Backend.Service.Name = "echoserver-canary"
return e
},
},
}

config := Config{
Expand Down
Loading