From ae63b01373b40874fd2e04061d730d858cc77b1f Mon Sep 17 00:00:00 2001 From: stefanprodan Date: Thu, 19 Dec 2019 12:02:20 +0200 Subject: [PATCH] Implement Contour A/B testing --- pkg/router/contour.go | 116 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/pkg/router/contour.go b/pkg/router/contour.go index 67c241f2..c7e05b90 100644 --- a/pkg/router/contour.go +++ b/pkg/router/contour.go @@ -54,6 +54,47 @@ func (cr *ContourRouter) Reconcile(canary *flaggerv1.Canary) error { }, } + if len(canary.Spec.CanaryAnalysis.Match) > 0 { + newSpec = contourv1.HTTPProxySpec{ + Routes: []contourv1.Route{ + { + Conditions: cr.makeConditions(canary), + Services: []contourv1.Service{ + { + Name: primaryName, + Port: int(canary.Spec.Service.Port), + Weight: uint32(100), + }, + { + Name: canaryName, + Port: int(canary.Spec.Service.Port), + Weight: uint32(0), + }, + }, + }, + { + Conditions: []contourv1.Condition{ + { + Prefix: "/", + }, + }, + Services: []contourv1.Service{ + { + Name: primaryName, + Port: int(canary.Spec.Service.Port), + Weight: uint32(100), + }, + { + Name: canaryName, + Port: int(canary.Spec.Service.Port), + Weight: uint32(0), + }, + }, + }, + }, + } + } + proxy, err := cr.contourClient.ProjectcontourV1().HTTPProxies(canary.Namespace).Get(targetName, metav1.GetOptions{}) if errors.IsNotFound(err) { proxy = &contourv1.HTTPProxy{ @@ -193,9 +234,84 @@ func (cr *ContourRouter) SetRoutes( }, } + if len(canary.Spec.CanaryAnalysis.Match) > 0 { + proxy.Spec = contourv1.HTTPProxySpec{ + Routes: []contourv1.Route{ + { + Conditions: cr.makeConditions(canary), + Services: []contourv1.Service{ + { + Name: primaryName, + Port: int(canary.Spec.Service.Port), + Weight: uint32(primaryWeight), + }, + { + Name: canaryName, + Port: int(canary.Spec.Service.Port), + Weight: uint32(canaryWeight), + }, + }, + }, + { + Conditions: []contourv1.Condition{ + { + Prefix: "/", + }, + }, + Services: []contourv1.Service{ + { + Name: primaryName, + Port: int(canary.Spec.Service.Port), + Weight: uint32(100), + }, + { + Name: canaryName, + Port: int(canary.Spec.Service.Port), + Weight: uint32(0), + }, + }, + }, + }, + } + } + _, err = cr.contourClient.ProjectcontourV1().HTTPProxies(canary.Namespace).Update(proxy) if err != nil { return fmt.Errorf("HTTPProxy %s.%s update error %v", targetName, canary.Namespace, err) } return nil } + +func (cr *ContourRouter) makeConditions(canary *flaggerv1.Canary) []contourv1.Condition { + list := []contourv1.Condition{ + { + Prefix: "/", + }, + } + + if len(canary.Spec.CanaryAnalysis.Match) > 0 { + for _, match := range canary.Spec.CanaryAnalysis.Match { + for s, stringMatch := range match.Headers { + h := &contourv1.HeaderCondition{ + Name: s, + Exact: stringMatch.Exact, + } + if stringMatch.Suffix != "" { + h = &contourv1.HeaderCondition{ + Name: s, + Contains: stringMatch.Suffix, + } + } + if stringMatch.Prefix != "" { + h = &contourv1.HeaderCondition{ + Name: s, + Contains: stringMatch.Prefix, + } + } + list = append(list, contourv1.Condition{Header: h}) + } + } + } + + return list +}