Skip to content

Commit

Permalink
add header-value annotation
Browse files Browse the repository at this point in the history
add new annotation (header-value)
parse it and propogate to lua script
alter balancer rule to include it into the canary routing logic
add e2e tests
  • Loading branch information
minherz committed Jan 5, 2019
1 parent 9ddaf27 commit 0455a6a
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 13 deletions.
16 changes: 11 additions & 5 deletions internal/ingress/annotations/canary/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@ type canary struct {

// Config returns the configuration rules for setting up the Canary
type Config struct {
Enabled bool
Weight int
Header string
Cookie string
Enabled bool
Weight int
Header string
HeaderValue string
Cookie string
}

// NewParser parses the ingress for canary related annotations
Expand Down Expand Up @@ -62,12 +63,17 @@ func (c canary) Parse(ing *extensions.Ingress) (interface{}, error) {
config.Header = ""
}

config.HeaderValue, err = parser.GetStringAnnotation("canary-by-header-value", ing)
if err != nil {
config.HeaderValue = ""
}

config.Cookie, err = parser.GetStringAnnotation("canary-by-cookie", ing)
if err != nil {
config.Cookie = ""
}

if !config.Enabled && (config.Weight > 0 || len(config.Header) > 0 || len(config.Cookie) > 0) {
if !config.Enabled && (config.Weight > 0 || len(config.Header) > 0 || len(config.HeaderValue) > 0 || len(config.Cookie) > 0) {
return nil, errors.NewInvalidAnnotationConfiguration("canary", "configured but not enabled")
}

Expand Down
14 changes: 8 additions & 6 deletions internal/ingress/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -689,9 +689,10 @@ func (n *NGINXController) createUpstreams(data []*ingress.Ingress, du *ingress.B
if anns.Canary.Enabled {
upstreams[defBackend].NoServer = true
upstreams[defBackend].TrafficShapingPolicy = ingress.TrafficShapingPolicy{
Weight: anns.Canary.Weight,
Header: anns.Canary.Header,
Cookie: anns.Canary.Cookie,
Weight: anns.Canary.Weight,
Header: anns.Canary.Header,
HeaderValue: anns.Canary.HeaderValue,
Cookie: anns.Canary.Cookie,
}
}

Expand Down Expand Up @@ -754,9 +755,10 @@ func (n *NGINXController) createUpstreams(data []*ingress.Ingress, du *ingress.B
if anns.Canary.Enabled {
upstreams[name].NoServer = true
upstreams[name].TrafficShapingPolicy = ingress.TrafficShapingPolicy{
Weight: anns.Canary.Weight,
Header: anns.Canary.Header,
Cookie: anns.Canary.Cookie,
Weight: anns.Canary.Weight,
Header: anns.Canary.Header,
HeaderValue: anns.Canary.HeaderValue,
Cookie: anns.Canary.Cookie,
}
}

Expand Down
2 changes: 2 additions & 0 deletions internal/ingress/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ type TrafficShapingPolicy struct {
Weight int `json:"weight"`
// Header on which to redirect requests to this backend
Header string `json:"header"`
// HeaderValue on which to redirect requests to this backend
HeaderValue string `json:"headerValue"`
// Cookie on which to redirect requests to this backend
Cookie string `json:"cookie"`
}
Expand Down
3 changes: 3 additions & 0 deletions internal/ingress/types_equals.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,9 @@ func (tsp1 TrafficShapingPolicy) Equal(tsp2 TrafficShapingPolicy) bool {
if tsp1.Header != tsp2.Header {
return false
}
if tsp1.HeaderValue != tsp2.HeaderValue {
return false
}
if tsp1.Cookie != tsp2.Cookie {
return false
}
Expand Down
6 changes: 5 additions & 1 deletion rootfs/etc/nginx/lua/balancer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,11 @@ local function route_to_alternative_balancer(balancer)

local header = ngx.var["http_" .. clean_target_header]
if header then
if header == "always" then
if traffic_shaping_policy.headerValue then
if traffic_shaping_policy.headerValue == header then
return true
end
elseif header == "always" then
return true
elseif header == "never" then
return false
Expand Down
82 changes: 81 additions & 1 deletion test/e2e/annotations/canary.go
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ var _ = framework.IngressNginxDescribe("Annotations - canary", func() {
})
})

Context("when canaried by header", func() {
Context("when canaried by header with no value", func() {
It("should route requests to the correct upstream", func() {
host := "foo"
annotations := map[string]string{}
Expand Down Expand Up @@ -458,6 +458,86 @@ var _ = framework.IngressNginxDescribe("Annotations - canary", func() {
})
})

Context("when canaried by header with value", func() {
It("should route requests to the correct upstream", func() {
host := "foo"
annotations := map[string]string{}

ing := framework.NewSingleIngress(host, "/", host, f.IngressController.Namespace, "http-svc", 80, &annotations)
f.EnsureIngress(ing)

f.WaitForNginxServer(host,
func(server string) bool {
return Expect(server).Should(ContainSubstring("server_name foo"))
})

canaryAnnotations := map[string]string{
"nginx.ingress.kubernetes.io/canary": "true",
"nginx.ingress.kubernetes.io/canary-by-header": "CanaryByHeader",
"nginx.ingress.kubernetes.io/canary-by-header-value": "DoCanary",
}

canaryIngName := fmt.Sprintf("%v-canary", host)

canaryIng := framework.NewSingleIngress(canaryIngName, "/", host, f.IngressController.Namespace, "http-svc-canary",
80, &canaryAnnotations)
f.EnsureIngress(canaryIng)

time.Sleep(waitForLuaSync)

By("routing requests to the canary upstream when header is set to 'DoCanary'")

resp, body, errs := gorequest.New().
Get(f.IngressController.HTTPURL).
Set("Host", host).
Set("CanaryByHeader", "DoCanary").
End()

Expect(errs).Should(BeEmpty())
Expect(resp.StatusCode).Should(Equal(http.StatusOK))
Expect(body).Should(ContainSubstring("http-svc-canary"))

By("routing requests to the mainline upstream when header is set to 'always'")

resp, body, errs = gorequest.New().
Get(f.IngressController.HTTPURL).
Set("Host", host).
Set("CanaryByHeader", "always").
End()

Expect(errs).Should(BeEmpty())
Expect(resp.StatusCode).Should(Equal(http.StatusOK))
Expect(body).Should(ContainSubstring("http-svc"))
Expect(body).ShouldNot(ContainSubstring("http-svc-canary"))

By("routing requests to the mainline upstream when header is set to 'never'")

resp, body, errs = gorequest.New().
Get(f.IngressController.HTTPURL).
Set("Host", host).
Set("CanaryByHeader", "never").
End()

Expect(errs).Should(BeEmpty())
Expect(resp.StatusCode).Should(Equal(http.StatusOK))
Expect(body).Should(ContainSubstring("http-svc"))
Expect(body).ShouldNot(ContainSubstring("http-svc-canary"))

By("routing requests to the mainline upstream when header is set to anything else")

resp, body, errs = gorequest.New().
Get(f.IngressController.HTTPURL).
Set("Host", host).
Set("CanaryByHeader", "otherheadervalue").
End()

Expect(errs).Should(BeEmpty())
Expect(resp.StatusCode).Should(Equal(http.StatusOK))
Expect(body).Should(ContainSubstring("http-svc"))
Expect(body).ShouldNot(ContainSubstring("http-svc-canary"))
})
})

Context("when canaried by cookie", func() {
It("should route requests to the correct upstream", func() {
host := "foo"
Expand Down

0 comments on commit 0455a6a

Please sign in to comment.