From a286625ad9d77223f1edd0815839bea388723ff8 Mon Sep 17 00:00:00 2001 From: Keerthan Ekbote Date: Tue, 11 May 2021 13:10:28 -0400 Subject: [PATCH] updated gloo unit tests Signed-off-by: Keerthan Ekbote intermediate commit Signed-off-by: Keerthan Ekbote updated gloo unit tests Signed-off-by: Keerthan Ekbote copy config from upstream ref to flagger-generateed upstreams Signed-off-by: Keerthan Ekbote removed unneeded types Signed-off-by: Keerthan Ekbote make fmt Signed-off-by: Keerthan Ekbote added code-generator to replace Signed-off-by: Keerthan Ekbote reverted go.mod Signed-off-by: Keerthan Ekbote fixed struct Signed-off-by: Keerthan Ekbote updated e2es with new upstream ref Signed-off-by: Keerthan Ekbote Add note to docs about upstreamRef Signed-off-by: Kevin Dorosh Fix typo, improve clarity Signed-off-by: Kevin Dorosh --- artifacts/flagger/crd.yaml | 15 + charts/flagger/crds/crd.yaml | 15 + .../tutorials/gloo-progressive-delivery.md | 14 +- kustomize/base/flagger/crd.yaml | 15 + pkg/apis/flagger/v1beta1/canary.go | 5 + .../flagger/v1beta1/zz_generated.deepcopy.go | 5 + pkg/apis/gloo/gloo/v1/types.go | 89 +++++- .../gloo/gloo/v1/zz_generated.deepcopy.go | 283 +++++++++++++++++- pkg/router/gloo.go | 53 +++- test/gloo/test-canary.sh | 25 ++ 10 files changed, 503 insertions(+), 16 deletions(-) diff --git a/artifacts/flagger/crd.yaml b/artifacts/flagger/crd.yaml index 3aeaa433..1f2749df 100644 --- a/artifacts/flagger/crd.yaml +++ b/artifacts/flagger/crd.yaml @@ -129,6 +129,21 @@ spec: - Ingress name: type: string + upstreamRef: + description: Gloo Upstream selector + type: object + required: [ "apiVersion", "kind", "name" ] + properties: + apiVersion: + type: string + kind: + type: string + enum: + - Upstream + name: + type: string + namespace: + type: string service: description: Kubernetes Service spec type: object diff --git a/charts/flagger/crds/crd.yaml b/charts/flagger/crds/crd.yaml index 3aeaa433..1f2749df 100644 --- a/charts/flagger/crds/crd.yaml +++ b/charts/flagger/crds/crd.yaml @@ -129,6 +129,21 @@ spec: - Ingress name: type: string + upstreamRef: + description: Gloo Upstream selector + type: object + required: [ "apiVersion", "kind", "name" ] + properties: + apiVersion: + type: string + kind: + type: string + enum: + - Upstream + name: + type: string + namespace: + type: string service: description: Kubernetes Service spec type: object diff --git a/docs/gitbook/tutorials/gloo-progressive-delivery.md b/docs/gitbook/tutorials/gloo-progressive-delivery.md index fd92ce8f..a661f0a1 100644 --- a/docs/gitbook/tutorials/gloo-progressive-delivery.md +++ b/docs/gitbook/tutorials/gloo-progressive-delivery.md @@ -10,8 +10,8 @@ and Flagger to automate canary releases and A/B testing. Flagger requires a Kubernetes cluster **v1.16** or newer and Gloo Edge ingress **1.6.0** or newer. This guide was written for Flagger version **1.6.0** or higher. Prior versions of Flagger -used Gloo upstream groups to handle canaries, but newer versions of Flagger use Gloo -route tables to handle canaries as well as A/B testing. +used Gloo `UpstreamGroup`s to handle canaries, but newer versions of Flagger use Gloo +`RouteTable`s to handle canaries as well as A/B testing. Install Gloo with Helm v3: @@ -36,7 +36,7 @@ helm upgrade -i flagger flagger/flagger \ ## Bootstrap Flagger takes a Kubernetes deployment and optionally a horizontal pod autoscaler (HPA), -then creates a series of objects (Kubernetes deployments, ClusterIP services and Gloo route tables groups). +then creates a series of objects (Kubernetes deployments, ClusterIP services, Gloo route tables and upstreams). These objects expose the application outside the cluster and drive the canary analysis and promotion. Create a test namespace: @@ -94,6 +94,14 @@ metadata: name: podinfo namespace: test spec: + # upstreamRef (optional) + # defines an upstream to copy the spec from when flagger generates new upstreams. + # necessary to copy over TLS config, circuit breakers, etc. (anything nonstandard) +# upstreamRef: +# apiVersion: gloo.solo.io/v1 +# kind: Upstream +# name: podinfo-upstream +# namespace: gloo-system provider: gloo # deployment reference targetRef: diff --git a/kustomize/base/flagger/crd.yaml b/kustomize/base/flagger/crd.yaml index 3aeaa433..1f2749df 100644 --- a/kustomize/base/flagger/crd.yaml +++ b/kustomize/base/flagger/crd.yaml @@ -129,6 +129,21 @@ spec: - Ingress name: type: string + upstreamRef: + description: Gloo Upstream selector + type: object + required: [ "apiVersion", "kind", "name" ] + properties: + apiVersion: + type: string + kind: + type: string + enum: + - Upstream + name: + type: string + namespace: + type: string service: description: Kubernetes Service spec type: object diff --git a/pkg/apis/flagger/v1beta1/canary.go b/pkg/apis/flagger/v1beta1/canary.go index 7579b7c2..0e6c533c 100644 --- a/pkg/apis/flagger/v1beta1/canary.go +++ b/pkg/apis/flagger/v1beta1/canary.go @@ -77,6 +77,11 @@ type CanarySpec struct { // +optional IngressRef *CrossNamespaceObjectReference `json:"ingressRef,omitempty"` + // Reference to Gloo Upstream resource. Upstream config is copied from + // the referenced upstream to the upstreams generated by flagger. + // +optional + UpstreamRef *CrossNamespaceObjectReference `json:"upstreamRef,omitempty"` + // Service defines how ClusterIP services, service mesh or ingress routing objects are generated Service CanaryService `json:"service"` diff --git a/pkg/apis/flagger/v1beta1/zz_generated.deepcopy.go b/pkg/apis/flagger/v1beta1/zz_generated.deepcopy.go index 5e568ec3..28fa6465 100644 --- a/pkg/apis/flagger/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/flagger/v1beta1/zz_generated.deepcopy.go @@ -411,6 +411,11 @@ func (in *CanarySpec) DeepCopyInto(out *CanarySpec) { *out = new(CrossNamespaceObjectReference) **out = **in } + if in.UpstreamRef != nil { + in, out := &in.UpstreamRef, &out.UpstreamRef + *out = new(CrossNamespaceObjectReference) + **out = **in + } in.Service.DeepCopyInto(&out.Service) if in.Analysis != nil { in, out := &in.Analysis, &out.Analysis diff --git a/pkg/apis/gloo/gloo/v1/types.go b/pkg/apis/gloo/gloo/v1/types.go index 38fde7da..7348f338 100644 --- a/pkg/apis/gloo/gloo/v1/types.go +++ b/pkg/apis/gloo/gloo/v1/types.go @@ -1,6 +1,7 @@ package v1 import ( + v1 "github.com/fluxcd/flagger/pkg/apis/gloo/gateway/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -16,7 +17,14 @@ type Upstream struct { } type UpstreamSpec struct { - Kube KubeUpstream `json:"kube,omitempty"` + Kube *KubeUpstream `json:"kube,omitempty"` + SslConfig *UpstreamSslConfig `json:"sslConfig,omitempty"` + CircuitBreakers *CircuitBreakerConfig `json:"circuitBreakers,omitempty"` + ConnectionConfig *ConnectionConfig `json:"connectionConfig,omitempty"` + UseHttp2 bool `json:"useHttp2,omitempty"` + InitialStreamWindowSize uint32 `json:"initialStreamWindowSize,omitempty"` + InitialConnectionWindowSize uint32 `json:"initialConnectionWindowSize,omitempty"` + HttpProxyHostname string `json:"httpProxyHostName,omitempty"` } type KubeUpstream struct { @@ -26,6 +34,85 @@ type KubeUpstream struct { Selector map[string]string `json:"selector,omitempty"` } +type UpstreamSslConfig struct { + Sni string `json:"sni,omitempty"` + VerifySubjectAltName []string `json:"verifySubjectAltName,omitempty"` + Parameters *SslParameters `json:"parameters,omitempty"` + AlpnProtocols []string `json:"alpnProtocols,omitempty"` + + /** SSLSecrets -- only one of these should be set */ + *UpstreamSslConfig_Sds `json:"sds,omitempty"` + SecretRef *v1.ResourceRef `json:"secretRef,omitempty"` + *UpstreamSslConfig_SslFiles `json:"sslFiles,omitempty"` +} + +// SSLFiles reference paths to certificates which can be read by the proxy off of its local filesystem +type UpstreamSslConfig_SslFiles struct { + TlsCert string `json:"tlsCert,omitempty"` + TlsKey string `json:"tlsKey,omitempty"` + RootCa string `json:"rootCa,omitempty"` +} + +// Use secret discovery service. +type UpstreamSslConfig_Sds struct { + TargetUri string `json:"targetUri,omitempty"` + CertificatesSecretName string `json:"certificatesSecretName,omitempty"` + ValidationContextName string `json:"validationContextName,omitempty"` + + /** SDSBuilder -- onle one of the following can be set */ + CallCredentials *CallCredentials `json:"callCredentials,omitempty"` + ClusterName string `json:"clusterName,omitempty"` +} + +type CallCredentials struct { + FileCredentialSource *CallCredentials_FileCredentialSource `json:"fileCredentialSource,omitempty"` +} + +type CallCredentials_FileCredentialSource struct { + TokenFileName string `json:"tokenFileName,omitempty"` + Header string `json:"header,omitempty"` +} + +type SslParameters struct { + MinimumProtocolVersion int32 `json:"minimumProtocolVersion,omitempty"` + MaximumProtocolVersion int32 `json:"maximumProtocolVersion,omitempty"` + CipherSuites []string `json:"cipherSuites,omitempty"` + EcdhCurves []string `json:"ecdhCurves,omitempty"` +} + +type CircuitBreakerConfig struct { + MaxConnections uint32 `json:"maxConnections,omitempty"` + MaxPendingRequests uint32 `json:"maxPendingRequests,omitempty"` + MaxRequests uint32 `json:"maxRequests,omitempty"` + MaxRetries uint32 `json:"maxRetries,omitempty"` +} + +type ConnectionConfig struct { + MaxRequestsPerConnection uint32 `json:"maxRequestsPerConnection,omitempty"` + ConnectTimeout *Duration `json:"connectTimeout,omitempty"` + TcpKeepalive *ConnectionConfig_TcpKeepAlive `json:"tcpKeepalive,omitempty"` + PerConnectionBufferLimitBytes uint32 `json:"perConnectionBufferLimitBytes,omitempty"` + CommonHttpProtocolOptions *ConnectionConfig_HttpProtocolOptions `json:"commonHttpProtocolOptions,omitempty"` +} + +type ConnectionConfig_TcpKeepAlive struct { + KeepaliveProbes uint32 `json:"keepaliveProbes,omitempty"` + KeepaliveTime *Duration `json:"keepaliveTime,omitempty"` + KeepaliveInterval *Duration `json:"keepaliveInterval,omitempty"` +} + +type ConnectionConfig_HttpProtocolOptions struct { + IdleTimeout *Duration `json:"idleTimeout,omitempty"` + MaxHeadersCount uint32 `json:"maxHeadersCount,omitempty"` + MaxStreamDuration *Duration `json:"maxStreamDuration,omitempty"` + HeadersWithUnderscoresAction uint32 `json:"headersWithUnderscoresAction,omitempty"` +} + +type Duration struct { + Seconds int64 `json:"seconds,omitempty"` + Nanos int32 `json:"nanos,omitempty"` +} + // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // UpstreamList is a list of Upstream resources diff --git a/pkg/apis/gloo/gloo/v1/zz_generated.deepcopy.go b/pkg/apis/gloo/gloo/v1/zz_generated.deepcopy.go index 002cbbbe..edf42622 100644 --- a/pkg/apis/gloo/gloo/v1/zz_generated.deepcopy.go +++ b/pkg/apis/gloo/gloo/v1/zz_generated.deepcopy.go @@ -21,9 +21,162 @@ limitations under the License. package v1 import ( + gatewayv1 "github.com/fluxcd/flagger/pkg/apis/gloo/gateway/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CallCredentials) DeepCopyInto(out *CallCredentials) { + *out = *in + if in.FileCredentialSource != nil { + in, out := &in.FileCredentialSource, &out.FileCredentialSource + *out = new(CallCredentials_FileCredentialSource) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CallCredentials. +func (in *CallCredentials) DeepCopy() *CallCredentials { + if in == nil { + return nil + } + out := new(CallCredentials) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CallCredentials_FileCredentialSource) DeepCopyInto(out *CallCredentials_FileCredentialSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CallCredentials_FileCredentialSource. +func (in *CallCredentials_FileCredentialSource) DeepCopy() *CallCredentials_FileCredentialSource { + if in == nil { + return nil + } + out := new(CallCredentials_FileCredentialSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CircuitBreakerConfig) DeepCopyInto(out *CircuitBreakerConfig) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CircuitBreakerConfig. +func (in *CircuitBreakerConfig) DeepCopy() *CircuitBreakerConfig { + if in == nil { + return nil + } + out := new(CircuitBreakerConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConnectionConfig) DeepCopyInto(out *ConnectionConfig) { + *out = *in + if in.ConnectTimeout != nil { + in, out := &in.ConnectTimeout, &out.ConnectTimeout + *out = new(Duration) + **out = **in + } + if in.TcpKeepalive != nil { + in, out := &in.TcpKeepalive, &out.TcpKeepalive + *out = new(ConnectionConfig_TcpKeepAlive) + (*in).DeepCopyInto(*out) + } + if in.CommonHttpProtocolOptions != nil { + in, out := &in.CommonHttpProtocolOptions, &out.CommonHttpProtocolOptions + *out = new(ConnectionConfig_HttpProtocolOptions) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConnectionConfig. +func (in *ConnectionConfig) DeepCopy() *ConnectionConfig { + if in == nil { + return nil + } + out := new(ConnectionConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConnectionConfig_HttpProtocolOptions) DeepCopyInto(out *ConnectionConfig_HttpProtocolOptions) { + *out = *in + if in.IdleTimeout != nil { + in, out := &in.IdleTimeout, &out.IdleTimeout + *out = new(Duration) + **out = **in + } + if in.MaxStreamDuration != nil { + in, out := &in.MaxStreamDuration, &out.MaxStreamDuration + *out = new(Duration) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConnectionConfig_HttpProtocolOptions. +func (in *ConnectionConfig_HttpProtocolOptions) DeepCopy() *ConnectionConfig_HttpProtocolOptions { + if in == nil { + return nil + } + out := new(ConnectionConfig_HttpProtocolOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConnectionConfig_TcpKeepAlive) DeepCopyInto(out *ConnectionConfig_TcpKeepAlive) { + *out = *in + if in.KeepaliveTime != nil { + in, out := &in.KeepaliveTime, &out.KeepaliveTime + *out = new(Duration) + **out = **in + } + if in.KeepaliveInterval != nil { + in, out := &in.KeepaliveInterval, &out.KeepaliveInterval + *out = new(Duration) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConnectionConfig_TcpKeepAlive. +func (in *ConnectionConfig_TcpKeepAlive) DeepCopy() *ConnectionConfig_TcpKeepAlive { + if in == nil { + return nil + } + out := new(ConnectionConfig_TcpKeepAlive) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Duration) DeepCopyInto(out *Duration) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Duration. +func (in *Duration) DeepCopy() *Duration { + if in == nil { + return nil + } + out := new(Duration) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KubeUpstream) DeepCopyInto(out *KubeUpstream) { *out = *in @@ -47,6 +200,32 @@ func (in *KubeUpstream) DeepCopy() *KubeUpstream { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SslParameters) DeepCopyInto(out *SslParameters) { + *out = *in + if in.CipherSuites != nil { + in, out := &in.CipherSuites, &out.CipherSuites + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.EcdhCurves != nil { + in, out := &in.EcdhCurves, &out.EcdhCurves + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SslParameters. +func (in *SslParameters) DeepCopy() *SslParameters { + if in == nil { + return nil + } + out := new(SslParameters) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Upstream) DeepCopyInto(out *Upstream) { *out = *in @@ -110,7 +289,26 @@ func (in *UpstreamList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *UpstreamSpec) DeepCopyInto(out *UpstreamSpec) { *out = *in - in.Kube.DeepCopyInto(&out.Kube) + if in.Kube != nil { + in, out := &in.Kube, &out.Kube + *out = new(KubeUpstream) + (*in).DeepCopyInto(*out) + } + if in.SslConfig != nil { + in, out := &in.SslConfig, &out.SslConfig + *out = new(UpstreamSslConfig) + (*in).DeepCopyInto(*out) + } + if in.CircuitBreakers != nil { + in, out := &in.CircuitBreakers, &out.CircuitBreakers + *out = new(CircuitBreakerConfig) + **out = **in + } + if in.ConnectionConfig != nil { + in, out := &in.ConnectionConfig, &out.ConnectionConfig + *out = new(ConnectionConfig) + (*in).DeepCopyInto(*out) + } return } @@ -123,3 +321,86 @@ func (in *UpstreamSpec) DeepCopy() *UpstreamSpec { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UpstreamSslConfig) DeepCopyInto(out *UpstreamSslConfig) { + *out = *in + if in.VerifySubjectAltName != nil { + in, out := &in.VerifySubjectAltName, &out.VerifySubjectAltName + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Parameters != nil { + in, out := &in.Parameters, &out.Parameters + *out = new(SslParameters) + (*in).DeepCopyInto(*out) + } + if in.AlpnProtocols != nil { + in, out := &in.AlpnProtocols, &out.AlpnProtocols + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.UpstreamSslConfig_Sds != nil { + in, out := &in.UpstreamSslConfig_Sds, &out.UpstreamSslConfig_Sds + *out = new(UpstreamSslConfig_Sds) + (*in).DeepCopyInto(*out) + } + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(gatewayv1.ResourceRef) + **out = **in + } + if in.UpstreamSslConfig_SslFiles != nil { + in, out := &in.UpstreamSslConfig_SslFiles, &out.UpstreamSslConfig_SslFiles + *out = new(UpstreamSslConfig_SslFiles) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpstreamSslConfig. +func (in *UpstreamSslConfig) DeepCopy() *UpstreamSslConfig { + if in == nil { + return nil + } + out := new(UpstreamSslConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UpstreamSslConfig_Sds) DeepCopyInto(out *UpstreamSslConfig_Sds) { + *out = *in + if in.CallCredentials != nil { + in, out := &in.CallCredentials, &out.CallCredentials + *out = new(CallCredentials) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpstreamSslConfig_Sds. +func (in *UpstreamSslConfig_Sds) DeepCopy() *UpstreamSslConfig_Sds { + if in == nil { + return nil + } + out := new(UpstreamSslConfig_Sds) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UpstreamSslConfig_SslFiles) DeepCopyInto(out *UpstreamSslConfig_SslFiles) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpstreamSslConfig_SslFiles. +func (in *UpstreamSslConfig_SslFiles) DeepCopy() *UpstreamSslConfig_SslFiles { + if in == nil { + return nil + } + out := new(UpstreamSslConfig_SslFiles) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/router/gloo.go b/pkg/router/gloo.go index 9edb5a6d..e5dc9bcd 100644 --- a/pkg/router/gloo.go +++ b/pkg/router/gloo.go @@ -255,8 +255,12 @@ func (gr *GlooRouter) createFlaggerUpstream(canary *flaggerv1.Canary, upstreamNa } _, err = upstreamClient.Get(context.TODO(), upstreamName, metav1.GetOptions{}) if errors.IsNotFound(err) { - canaryUs := gr.getGlooUpstreamKubeService(canary, svc, upstreamName) - _, err := gr.glooClient.GlooV1().Upstreams(canary.Namespace).Create(context.TODO(), canaryUs, metav1.CreateOptions{}) + glooUpstreamWithConfig, err := gr.getGlooConfigUpstream(canary) + if err != nil { + return err + } + canaryUs := gr.getGlooUpstreamKubeService(canary, svc, upstreamName, glooUpstreamWithConfig) + _, err = gr.glooClient.GlooV1().Upstreams(canary.Namespace).Create(context.TODO(), canaryUs, metav1.CreateOptions{}) if err != nil { return fmt.Errorf("upstream %s.%s create query error: %w", upstreamName, canary.Namespace, err) } @@ -266,7 +270,29 @@ func (gr *GlooRouter) createFlaggerUpstream(canary *flaggerv1.Canary, upstreamNa return nil } -func (gr *GlooRouter) getGlooUpstreamKubeService(canary *flaggerv1.Canary, svc *corev1.Service, upstreamName string) *gloov1.Upstream { +func (gr *GlooRouter) getGlooUpstreamKubeService(canary *flaggerv1.Canary, svc *corev1.Service, upstreamName string, glooUpstreamWithConfig *gloov1.Upstream) *gloov1.Upstream { + + upstreamSpec := gloov1.UpstreamSpec{} + if glooUpstreamWithConfig != nil { + configSpec := glooUpstreamWithConfig.Spec + upstreamSpec = gloov1.UpstreamSpec{ + SslConfig: configSpec.SslConfig, + CircuitBreakers: configSpec.CircuitBreakers, + ConnectionConfig: configSpec.ConnectionConfig, + UseHttp2: configSpec.UseHttp2, + InitialStreamWindowSize: configSpec.InitialStreamWindowSize, + InitialConnectionWindowSize: configSpec.InitialConnectionWindowSize, + HttpProxyHostname: configSpec.HttpProxyHostname, + } + + } + upstreamSpec.Kube = &gloov1.KubeUpstream{ + ServiceName: svc.GetName(), + ServiceNamespace: canary.Namespace, + ServicePort: canary.Spec.Service.Port, + Selector: svc.Spec.Selector, + } + return &gloov1.Upstream{ ObjectMeta: metav1.ObjectMeta{ Name: upstreamName, @@ -279,17 +305,22 @@ func (gr *GlooRouter) getGlooUpstreamKubeService(canary *flaggerv1.Canary, svc * }), }, }, - Spec: gloov1.UpstreamSpec{ - Kube: gloov1.KubeUpstream{ - ServiceName: svc.GetName(), - ServiceNamespace: canary.Namespace, - ServicePort: canary.Spec.Service.Port, - Selector: svc.Spec.Selector, - }, - }, + Spec: upstreamSpec, } } +func (gr *GlooRouter) getGlooConfigUpstream(canary *flaggerv1.Canary) (*gloov1.Upstream, error) { + configUpstreamRef := canary.Spec.UpstreamRef + if configUpstreamRef == nil { + return nil, nil + } + configUpstream, err := gr.glooClient.GlooV1().Upstreams(configUpstreamRef.Namespace).Get(context.TODO(), configUpstreamRef.Name, metav1.GetOptions{}) + if err != nil { + return nil, fmt.Errorf("config upstream %s.%s get query error: %w", configUpstreamRef.Name, canary.Namespace, err) + } + return configUpstream, nil +} + func getMatchers(canary *flaggerv1.Canary) []gatewayv1.Matcher { headerMatchers := getHeaderMatchers(canary) diff --git a/test/gloo/test-canary.sh b/test/gloo/test-canary.sh index 95932b48..224e0eed 100755 --- a/test/gloo/test-canary.sh +++ b/test/gloo/test-canary.sh @@ -25,6 +25,23 @@ spec: namespace: test EOF +# Create upstream that will have config that will be applied to generated flagger upstreams +# but will be used for no other reason +cat <