diff --git a/pkg/apis/flagger/v1alpha3/types.go b/pkg/apis/flagger/v1alpha3/types.go index 6937440db..dfbf51a60 100755 --- a/pkg/apis/flagger/v1alpha3/types.go +++ b/pkg/apis/flagger/v1alpha3/types.go @@ -109,14 +109,14 @@ type CanaryStatus struct { // CanaryService is used to create ClusterIP services // and Istio Virtual Service type CanaryService struct { - Port int32 `json:"port"` - Gateways []string `json:"gateways"` - Hosts []string `json:"hosts"` - Match []istiov1alpha3.HTTPMatchRequest `json:"match,omitempty"` - Rewrite *istiov1alpha3.HTTPRewrite `json:"rewrite,omitempty"` - Timeout string `json:"timeout,omitempty"` - Retries *istiov1alpha3.HTTPRetry `json:"retries,omitempty"` - AppendHeaders map[string]string `json:"appendHeaders,omitempty"` + Port int32 `json:"port"` + Gateways []string `json:"gateways"` + Hosts []string `json:"hosts"` + Match []istiov1alpha3.HTTPMatchRequest `json:"match,omitempty"` + Rewrite *istiov1alpha3.HTTPRewrite `json:"rewrite,omitempty"` + Timeout string `json:"timeout,omitempty"` + Retries *istiov1alpha3.HTTPRetry `json:"retries,omitempty"` + Headers *istiov1alpha3.Headers `json:"headers,omitempty"` } // CanaryAnalysis is used to describe how the analysis should be done diff --git a/pkg/apis/flagger/v1alpha3/zz_generated.deepcopy.go b/pkg/apis/flagger/v1alpha3/zz_generated.deepcopy.go index fd5f8347d..8f28a1d94 100644 --- a/pkg/apis/flagger/v1alpha3/zz_generated.deepcopy.go +++ b/pkg/apis/flagger/v1alpha3/zz_generated.deepcopy.go @@ -161,12 +161,10 @@ func (in *CanaryService) DeepCopyInto(out *CanaryService) { *out = new(istiov1alpha3.HTTPRetry) **out = **in } - if in.AppendHeaders != nil { - in, out := &in.AppendHeaders, &out.AppendHeaders - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } + if in.Headers != nil { + in, out := &in.Headers, &out.Headers + *out = new(istiov1alpha3.Headers) + (*in).DeepCopyInto(*out) } return } diff --git a/pkg/apis/istio/v1alpha3/virtual_service.go b/pkg/apis/istio/v1alpha3/virtual_service.go index c0298a66e..8b4c12f06 100644 --- a/pkg/apis/istio/v1alpha3/virtual_service.go +++ b/pkg/apis/istio/v1alpha3/virtual_service.go @@ -345,11 +345,11 @@ type HTTPRoute struct { type Headers struct { // Header manipulation rules to apply before forwarding a request // to the destination service - Request HeaderOperations `json:"request,omitempty"` + Request *HeaderOperations `json:"request,omitempty"` // Header manipulation rules to apply before returning a response // to the caller - Response HeaderOperations `json:"response,omitempty"` + Response *HeaderOperations `json:"response,omitempty"` } // HeaderOperations Describes the header manipulations to apply diff --git a/pkg/apis/istio/v1alpha3/zz_generated.deepcopy.go b/pkg/apis/istio/v1alpha3/zz_generated.deepcopy.go index f36199896..2d137c8c8 100644 --- a/pkg/apis/istio/v1alpha3/zz_generated.deepcopy.go +++ b/pkg/apis/istio/v1alpha3/zz_generated.deepcopy.go @@ -339,8 +339,16 @@ func (in *HeaderOperations) DeepCopy() *HeaderOperations { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Headers) DeepCopyInto(out *Headers) { *out = *in - in.Request.DeepCopyInto(&out.Request) - in.Response.DeepCopyInto(&out.Response) + if in.Request != nil { + in, out := &in.Request, &out.Request + *out = new(HeaderOperations) + (*in).DeepCopyInto(*out) + } + if in.Response != nil { + in, out := &in.Response, &out.Response + *out = new(HeaderOperations) + (*in).DeepCopyInto(*out) + } return } diff --git a/pkg/router/istio.go b/pkg/router/istio.go index 17b802c96..3a62dc972 100644 --- a/pkg/router/istio.go +++ b/pkg/router/istio.go @@ -24,12 +24,12 @@ type IstioRouter struct { } // Sync creates or updates the Istio virtual service -func (ir *IstioRouter) Sync(cd *flaggerv1.Canary) error { - targetName := cd.Spec.TargetRef.Name +func (ir *IstioRouter) Sync(canary *flaggerv1.Canary) error { + targetName := canary.Spec.TargetRef.Name primaryName := fmt.Sprintf("%s-primary", targetName) // set hosts and add the ClusterIP service host if it doesn't exists - hosts := cd.Spec.Service.Hosts + hosts := canary.Spec.Service.Hosts var hasServiceHost bool for _, h := range hosts { if h == targetName { @@ -42,7 +42,7 @@ func (ir *IstioRouter) Sync(cd *flaggerv1.Canary) error { } // set gateways and add the mesh gateway if it doesn't exists - gateways := cd.Spec.Service.Gateways + gateways := canary.Spec.Service.Gateways var hasMeshGateway bool for _, g := range gateways { if g == "mesh" { @@ -60,7 +60,7 @@ func (ir *IstioRouter) Sync(cd *flaggerv1.Canary) error { Destination: istiov1alpha3.Destination{ Host: primaryName, Port: istiov1alpha3.PortSelector{ - Number: uint32(cd.Spec.Service.Port), + Number: uint32(canary.Spec.Service.Port), }, }, Weight: 100, @@ -69,36 +69,37 @@ func (ir *IstioRouter) Sync(cd *flaggerv1.Canary) error { Destination: istiov1alpha3.Destination{ Host: fmt.Sprintf("%s-canary", targetName), Port: istiov1alpha3.PortSelector{ - Number: uint32(cd.Spec.Service.Port), + Number: uint32(canary.Spec.Service.Port), }, }, Weight: 0, }, } + newSpec := istiov1alpha3.VirtualServiceSpec{ Hosts: hosts, Gateways: gateways, Http: []istiov1alpha3.HTTPRoute{ { - Match: cd.Spec.Service.Match, - Rewrite: cd.Spec.Service.Rewrite, - Timeout: cd.Spec.Service.Timeout, - Retries: cd.Spec.Service.Retries, - AppendHeaders: cd.Spec.Service.AppendHeaders, + Match: canary.Spec.Service.Match, + Rewrite: canary.Spec.Service.Rewrite, + Timeout: canary.Spec.Service.Timeout, + Retries: canary.Spec.Service.Retries, + AppendHeaders: setHeaders(canary), Route: route, }, }, } - virtualService, err := ir.istioClient.NetworkingV1alpha3().VirtualServices(cd.Namespace).Get(targetName, metav1.GetOptions{}) + virtualService, err := ir.istioClient.NetworkingV1alpha3().VirtualServices(canary.Namespace).Get(targetName, metav1.GetOptions{}) // insert if errors.IsNotFound(err) { virtualService = &istiov1alpha3.VirtualService{ ObjectMeta: metav1.ObjectMeta{ Name: targetName, - Namespace: cd.Namespace, + Namespace: canary.Namespace, OwnerReferences: []metav1.OwnerReference{ - *metav1.NewControllerRef(cd, schema.GroupVersionKind{ + *metav1.NewControllerRef(canary, schema.GroupVersionKind{ Group: flaggerv1.SchemeGroupVersion.Group, Version: flaggerv1.SchemeGroupVersion.Version, Kind: flaggerv1.CanaryKind, @@ -107,17 +108,17 @@ func (ir *IstioRouter) Sync(cd *flaggerv1.Canary) error { }, Spec: newSpec, } - _, err = ir.istioClient.NetworkingV1alpha3().VirtualServices(cd.Namespace).Create(virtualService) + _, err = ir.istioClient.NetworkingV1alpha3().VirtualServices(canary.Namespace).Create(virtualService) if err != nil { - return fmt.Errorf("VirtualService %s.%s create error %v", targetName, cd.Namespace, err) + return fmt.Errorf("VirtualService %s.%s create error %v", targetName, canary.Namespace, err) } - ir.logger.With("canary", fmt.Sprintf("%s.%s", cd.Name, cd.Namespace)). - Infof("VirtualService %s.%s created", virtualService.GetName(), cd.Namespace) + ir.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)). + Infof("VirtualService %s.%s created", virtualService.GetName(), canary.Namespace) return nil } if err != nil { - return fmt.Errorf("VirtualService %s.%s query error %v", targetName, cd.Namespace, err) + return fmt.Errorf("VirtualService %s.%s query error %v", targetName, canary.Namespace, err) } // update service but keep the original destination weights @@ -128,12 +129,12 @@ func (ir *IstioRouter) Sync(cd *flaggerv1.Canary) error { if len(virtualService.Spec.Http) > 0 { vtClone.Spec.Http[0].Route = virtualService.Spec.Http[0].Route } - _, err = ir.istioClient.NetworkingV1alpha3().VirtualServices(cd.Namespace).Update(vtClone) + _, err = ir.istioClient.NetworkingV1alpha3().VirtualServices(canary.Namespace).Update(vtClone) if err != nil { - return fmt.Errorf("VirtualService %s.%s update error %v", targetName, cd.Namespace, err) + return fmt.Errorf("VirtualService %s.%s update error %v", targetName, canary.Namespace, err) } - ir.logger.With("canary", fmt.Sprintf("%s.%s", cd.Name, cd.Namespace)). - Infof("VirtualService %s.%s updated", virtualService.GetName(), cd.Namespace) + ir.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)). + Infof("VirtualService %s.%s updated", virtualService.GetName(), canary.Namespace) } } @@ -200,7 +201,7 @@ func (ir *IstioRouter) SetRoutes( Rewrite: canary.Spec.Service.Rewrite, Timeout: canary.Spec.Service.Timeout, Retries: canary.Spec.Service.Retries, - AppendHeaders: canary.Spec.Service.AppendHeaders, + AppendHeaders: setHeaders(canary), Route: []istiov1alpha3.DestinationWeight{ { Destination: istiov1alpha3.Destination{ @@ -231,3 +232,15 @@ func (ir *IstioRouter) SetRoutes( } return nil } + +// setHeaders applies headers before forwarding a request to the destination service +// compatible with Istio 1.0.x and 1.1.0 +func setHeaders(canary *flaggerv1.Canary) (headers map[string]string) { + if canary.Spec.Service.Headers != nil && + canary.Spec.Service.Headers.Request != nil && + len(canary.Spec.Service.Headers.Request.Set) > 0 { + headers = canary.Spec.Service.Headers.Request.Set + } + + return +}