From bc002a67f61376e46f5dd9449d0c06353f7e328a Mon Sep 17 00:00:00 2001 From: sh2 Date: Mon, 23 Oct 2023 17:53:39 +0800 Subject: [PATCH 1/3] add missing test cases for envoyproxy validate methods Signed-off-by: sh2 --- .../validation/envoyproxy_validate.go | 5 +- .../validation/envoyproxy_validate_test.go | 91 ++++++++++++++++++- 2 files changed, 93 insertions(+), 3 deletions(-) diff --git a/api/v1alpha1/validation/envoyproxy_validate.go b/api/v1alpha1/validation/envoyproxy_validate.go index 1ba367ef0b8..a05ab1043c9 100644 --- a/api/v1alpha1/validation/envoyproxy_validate.go +++ b/api/v1alpha1/validation/envoyproxy_validate.go @@ -24,7 +24,7 @@ import ( _ "github.com/envoyproxy/gateway/internal/xds/extensions" // register the generated types to support protojson unmarshalling ) -// Validate validates the provided EnvoyProxy. +// ValidateEnvoyProxy validates the provided EnvoyProxy. func ValidateEnvoyProxy(proxy *egv1a1.EnvoyProxy) error { var errs []error if proxy == nil { @@ -96,7 +96,8 @@ func validateService(spec *egv1a1.EnvoyProxySpec) []error { errs = append(errs, fmt.Errorf("allocateLoadBalancerNodePorts can only be set for %v type", egv1a1.ServiceTypeLoadBalancer)) } } - if serviceType, serviceLoadBalancerIP := spec.Provider.Kubernetes.EnvoyService.Type, spec.Provider.Kubernetes.EnvoyService.LoadBalancerIP; serviceType != nil && serviceLoadBalancerIP != nil { + if serviceType, serviceLoadBalancerIP := + spec.Provider.Kubernetes.EnvoyService.Type, spec.Provider.Kubernetes.EnvoyService.LoadBalancerIP; serviceType != nil && serviceLoadBalancerIP != nil { if *serviceType != egv1a1.ServiceTypeLoadBalancer { errs = append(errs, fmt.Errorf("loadBalancerIP can only be set for %v type", egv1a1.ServiceTypeLoadBalancer)) } diff --git a/api/v1alpha1/validation/envoyproxy_validate_test.go b/api/v1alpha1/validation/envoyproxy_validate_test.go index 7f4b4b7a952..d35004169fd 100644 --- a/api/v1alpha1/validation/envoyproxy_validate_test.go +++ b/api/v1alpha1/validation/envoyproxy_validate_test.go @@ -276,7 +276,27 @@ func TestValidateEnvoyProxy(t *testing.T) { }, expected: false, }, - + { + name: "envoy service with valid loadBalancerIP but not 'LoadBalancer' type", + proxy: &egv1a1.EnvoyProxy{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "test", + }, + Spec: egv1a1.EnvoyProxySpec{ + Provider: &egv1a1.EnvoyProxyProvider{ + Type: egv1a1.ProviderTypeKubernetes, + Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ + EnvoyService: &egv1a1.KubernetesServiceSpec{ + Type: egv1a1.GetKubernetesServiceType(egv1a1.ServiceTypeClusterIP), + LoadBalancerIP: ptr.To("10.11.12.13"), + }, + }, + }, + }, + }, + expected: false, + }, { name: "valid user bootstrap replace type", proxy: &egv1a1.EnvoyProxy{ @@ -353,6 +373,23 @@ func TestValidateEnvoyProxy(t *testing.T) { }, expected: false, }, + { + name: "should valid when accesslog is disabled", + proxy: &egv1a1.EnvoyProxy{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "test", + }, + Spec: egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + AccessLog: &egv1a1.ProxyAccessLog{ + Disable: true, + }, + }, + }, + }, + expected: true, + }, { name: "should invalid when accesslog enabled using Text format, but `text` field being empty", proxy: &egv1a1.EnvoyProxy{ @@ -376,6 +413,29 @@ func TestValidateEnvoyProxy(t *testing.T) { }, expected: false, }, + { + name: "should invalid when accesslog enabled using JSON format, but `json` field being empty", + proxy: &egv1a1.EnvoyProxy{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "test", + }, + Spec: egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + AccessLog: &egv1a1.ProxyAccessLog{ + Settings: []egv1a1.ProxyAccessLogSetting{ + { + Format: egv1a1.ProxyAccessLogFormat{ + Type: egv1a1.ProxyAccessLogFormatTypeJSON, + }, + }, + }, + }, + }, + }, + }, + expected: false, + }, { name: "should invalid when accesslog enabled using File sink, but `file` field being empty", proxy: &egv1a1.EnvoyProxy{ @@ -405,6 +465,35 @@ func TestValidateEnvoyProxy(t *testing.T) { }, expected: false, }, + { + name: "should invalid when accesslog enabled using OpenTelemetry sink, but `openTelemetry` field being empty", + proxy: &egv1a1.EnvoyProxy{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "test", + }, + Spec: egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + AccessLog: &egv1a1.ProxyAccessLog{ + Settings: []egv1a1.ProxyAccessLogSetting{ + { + Format: egv1a1.ProxyAccessLogFormat{ + Type: egv1a1.ProxyAccessLogFormatTypeText, + Text: pointer.String("[%START_TIME%]"), + }, + Sinks: []egv1a1.ProxyAccessLogSink{ + { + Type: egv1a1.ProxyAccessLogSinkTypeOpenTelemetry, + }, + }, + }, + }, + }, + }, + }, + }, + expected: false, + }, } for i := range testCases { From 48821799e60d5aeb17d9887a1481279833c1d668 Mon Sep 17 00:00:00 2001 From: sh2 Date: Thu, 26 Oct 2023 10:58:01 +0800 Subject: [PATCH 2/3] typo: correct method comment Signed-off-by: sh2 --- api/v1alpha1/validation/envoygateway_validate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/v1alpha1/validation/envoygateway_validate.go b/api/v1alpha1/validation/envoygateway_validate.go index 657cb9ee73d..591abcc8310 100644 --- a/api/v1alpha1/validation/envoygateway_validate.go +++ b/api/v1alpha1/validation/envoygateway_validate.go @@ -15,7 +15,7 @@ import ( "github.com/envoyproxy/gateway/api/v1alpha1" ) -// Validate validates the provided EnvoyGateway. +// ValidateEnvoyGateway validates the provided EnvoyGateway. func ValidateEnvoyGateway(eg *v1alpha1.EnvoyGateway) error { switch { case eg == nil: From 7162222d3975f3b0708979f5f27086e753751970 Mon Sep 17 00:00:00 2001 From: sh2 Date: Sun, 12 Nov 2023 15:57:46 +0800 Subject: [PATCH 3/3] add CEL for envoy proxy telemetry and test cases Signed-off-by: sh2 --- api/v1alpha1/accesslogging_types.go | 9 + api/v1alpha1/envoyproxy_metric_types.go | 7 + api/v1alpha1/shared_types.go | 8 +- .../validation/envoygateway_validate.go | 2 +- .../validation/envoyproxy_validate.go | 3 +- .../validation/envoyproxy_validate_test.go | 91 +------ .../gateway.envoyproxy.io_envoyproxies.yaml | 25 ++ site/content/en/latest/api/extension_types.md | 4 +- test/cel-validation/envoyproxy_test.go | 223 +++++++++++++++++- 9 files changed, 269 insertions(+), 103 deletions(-) diff --git a/api/v1alpha1/accesslogging_types.go b/api/v1alpha1/accesslogging_types.go index ba877c9fc6a..483a224fab4 100644 --- a/api/v1alpha1/accesslogging_types.go +++ b/api/v1alpha1/accesslogging_types.go @@ -35,6 +35,9 @@ const ( // ProxyAccessLogFormat defines the format of accesslog. // By default accesslogs are written to standard output. // +union +// +// +kubebuilder:validation:XValidation:rule="self.type == 'Text' ? has(self.text) : !has(self.text)",message="If AccessLogFormat type is Text, text field needs to be set." +// +kubebuilder:validation:XValidation:rule="self.type == 'JSON' ? has(self.json) : !has(self.json)",message="If AccessLogFormat type is JSON, json field needs to be set." type ProxyAccessLogFormat struct { // Type defines the type of accesslog format. // +kubebuilder:validation:Enum=Text;JSON @@ -65,9 +68,15 @@ const ( ProxyAccessLogSinkTypeOpenTelemetry ProxyAccessLogSinkType = "OpenTelemetry" ) +// ProxyAccessLogSink defines the sink of accesslog. +// +union +// +// +kubebuilder:validation:XValidation:rule="self.type == 'File' ? has(self.file) : !has(self.file)",message="If AccessLogSink type is File, file field needs to be set." +// +kubebuilder:validation:XValidation:rule="self.type == 'OpenTelemetry' ? has(self.openTelemetry) : !has(self.openTelemetry)",message="If AccessLogSink type is OpenTelemetry, openTelemetry field needs to be set." type ProxyAccessLogSink struct { // Type defines the type of accesslog sink. // +kubebuilder:validation:Enum=File;OpenTelemetry + // +unionDiscriminator Type ProxyAccessLogSinkType `json:"type,omitempty"` // File defines the file accesslog sink. // +optional diff --git a/api/v1alpha1/envoyproxy_metric_types.go b/api/v1alpha1/envoyproxy_metric_types.go index 2dce4655ecd..71fb42ca62b 100644 --- a/api/v1alpha1/envoyproxy_metric_types.go +++ b/api/v1alpha1/envoyproxy_metric_types.go @@ -29,14 +29,21 @@ type ProxyMetrics struct { EnableVirtualHostStats bool `json:"enableVirtualHostStats,omitempty"` } +// ProxyMetricSink defines the sink of metrics. +// Default metrics sink is OpenTelemetry. +// +union +// +// +kubebuilder:validation:XValidation:rule="self.type == 'OpenTelemetry' ? has(self.openTelemetry) : !has(self.openTelemetry)",message="If MetricSink type is OpenTelemetry, openTelemetry field needs to be set." type ProxyMetricSink struct { // Type defines the metric sink type. // EG currently only supports OpenTelemetry. // +kubebuilder:validation:Enum=OpenTelemetry // +kubebuilder:default=OpenTelemetry + // +unionDiscriminator Type MetricSinkType `json:"type"` // OpenTelemetry defines the configuration for OpenTelemetry sink. // It's required if the sink type is OpenTelemetry. + // +optional OpenTelemetry *ProxyOpenTelemetrySink `json:"openTelemetry,omitempty"` } diff --git a/api/v1alpha1/shared_types.go b/api/v1alpha1/shared_types.go index 532d4001b4c..1764558d706 100644 --- a/api/v1alpha1/shared_types.go +++ b/api/v1alpha1/shared_types.go @@ -260,16 +260,16 @@ type StringMatch struct { type StringMatchType string const ( - // MatchExact :the input string must match exactly the match value. + // StringMatchExact :the input string must match exactly the match value. StringMatchExact StringMatchType = "Exact" - // MatchPrefix :the input string must start with the match value. + // StringMatchPrefix :the input string must start with the match value. StringMatchPrefix StringMatchType = "Prefix" - // MatchSuffix :the input string must end with the match value. + // StringMatchSuffix :the input string must end with the match value. StringMatchSuffix StringMatchType = "Suffix" - // MatchRegularExpression :The input string must match the regular expression + // StringMatchRegularExpression :The input string must match the regular expression // specified in the match value. // The regex string must adhere to the syntax documented in // https://github.com/google/re2/wiki/Syntax. diff --git a/api/v1alpha1/validation/envoygateway_validate.go b/api/v1alpha1/validation/envoygateway_validate.go index 591abcc8310..657cb9ee73d 100644 --- a/api/v1alpha1/validation/envoygateway_validate.go +++ b/api/v1alpha1/validation/envoygateway_validate.go @@ -15,7 +15,7 @@ import ( "github.com/envoyproxy/gateway/api/v1alpha1" ) -// ValidateEnvoyGateway validates the provided EnvoyGateway. +// Validate validates the provided EnvoyGateway. func ValidateEnvoyGateway(eg *v1alpha1.EnvoyGateway) error { switch { case eg == nil: diff --git a/api/v1alpha1/validation/envoyproxy_validate.go b/api/v1alpha1/validation/envoyproxy_validate.go index 2c2a12b8400..6c608f0e0f7 100644 --- a/api/v1alpha1/validation/envoyproxy_validate.go +++ b/api/v1alpha1/validation/envoyproxy_validate.go @@ -98,8 +98,7 @@ func validateService(spec *egv1a1.EnvoyProxySpec) []error { errs = append(errs, fmt.Errorf("allocateLoadBalancerNodePorts can only be set for %v type", egv1a1.ServiceTypeLoadBalancer)) } } - if serviceType, serviceLoadBalancerIP := - spec.Provider.Kubernetes.EnvoyService.Type, spec.Provider.Kubernetes.EnvoyService.LoadBalancerIP; serviceType != nil && serviceLoadBalancerIP != nil { + if serviceType, serviceLoadBalancerIP := spec.Provider.Kubernetes.EnvoyService.Type, spec.Provider.Kubernetes.EnvoyService.LoadBalancerIP; serviceType != nil && serviceLoadBalancerIP != nil { if *serviceType != egv1a1.ServiceTypeLoadBalancer { errs = append(errs, fmt.Errorf("loadBalancerIP can only be set for %v type", egv1a1.ServiceTypeLoadBalancer)) } diff --git a/api/v1alpha1/validation/envoyproxy_validate_test.go b/api/v1alpha1/validation/envoyproxy_validate_test.go index c8eb782dfbf..0bfc5558e1b 100644 --- a/api/v1alpha1/validation/envoyproxy_validate_test.go +++ b/api/v1alpha1/validation/envoyproxy_validate_test.go @@ -276,27 +276,7 @@ func TestValidateEnvoyProxy(t *testing.T) { }, expected: false, }, - { - name: "envoy service with valid loadBalancerIP but not 'LoadBalancer' type", - proxy: &egv1a1.EnvoyProxy{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.EnvoyProxySpec{ - Provider: &egv1a1.EnvoyProxyProvider{ - Type: egv1a1.ProviderTypeKubernetes, - Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ - EnvoyService: &egv1a1.KubernetesServiceSpec{ - Type: egv1a1.GetKubernetesServiceType(egv1a1.ServiceTypeClusterIP), - LoadBalancerIP: ptr.To("10.11.12.13"), - }, - }, - }, - }, - }, - expected: false, - }, + { name: "valid user bootstrap replace type", proxy: &egv1a1.EnvoyProxy{ @@ -373,23 +353,6 @@ func TestValidateEnvoyProxy(t *testing.T) { }, expected: false, }, - { - name: "should valid when accesslog is disabled", - proxy: &egv1a1.EnvoyProxy{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.EnvoyProxySpec{ - Telemetry: &egv1a1.ProxyTelemetry{ - AccessLog: &egv1a1.ProxyAccessLog{ - Disable: true, - }, - }, - }, - }, - expected: true, - }, { name: "should invalid when accesslog enabled using Text format, but `text` field being empty", proxy: &egv1a1.EnvoyProxy{ @@ -413,29 +376,6 @@ func TestValidateEnvoyProxy(t *testing.T) { }, expected: false, }, - { - name: "should invalid when accesslog enabled using JSON format, but `json` field being empty", - proxy: &egv1a1.EnvoyProxy{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.EnvoyProxySpec{ - Telemetry: &egv1a1.ProxyTelemetry{ - AccessLog: &egv1a1.ProxyAccessLog{ - Settings: []egv1a1.ProxyAccessLogSetting{ - { - Format: egv1a1.ProxyAccessLogFormat{ - Type: egv1a1.ProxyAccessLogFormatTypeJSON, - }, - }, - }, - }, - }, - }, - }, - expected: false, - }, { name: "should invalid when accesslog enabled using File sink, but `file` field being empty", proxy: &egv1a1.EnvoyProxy{ @@ -509,35 +449,6 @@ func TestValidateEnvoyProxy(t *testing.T) { }, expected: true, }, - { - name: "should invalid when accesslog enabled using OpenTelemetry sink, but `openTelemetry` field being empty", - proxy: &egv1a1.EnvoyProxy{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.EnvoyProxySpec{ - Telemetry: &egv1a1.ProxyTelemetry{ - AccessLog: &egv1a1.ProxyAccessLog{ - Settings: []egv1a1.ProxyAccessLogSetting{ - { - Format: egv1a1.ProxyAccessLogFormat{ - Type: egv1a1.ProxyAccessLogFormatTypeText, - Text: pointer.String("[%START_TIME%]"), - }, - Sinks: []egv1a1.ProxyAccessLogSink{ - { - Type: egv1a1.ProxyAccessLogSinkTypeOpenTelemetry, - }, - }, - }, - }, - }, - }, - }, - }, - expected: false, - }, } for i := range testCases { diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml index 17f135598e2..2b937371634 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -5350,9 +5350,18 @@ spec: - JSON type: string type: object + x-kubernetes-validations: + - message: If AccessLogFormat type is Text, text field + needs to be set. + rule: 'self.type == ''Text'' ? has(self.text) : !has(self.text)' + - message: If AccessLogFormat type is JSON, json field + needs to be set. + rule: 'self.type == ''JSON'' ? has(self.json) : !has(self.json)' sinks: description: Sinks defines the sinks of accesslog. items: + description: ProxyAccessLogSink defines the sink of + accesslog. properties: file: description: File defines the file accesslog sink. @@ -5397,6 +5406,15 @@ spec: - OpenTelemetry type: string type: object + x-kubernetes-validations: + - message: If AccessLogSink type is File, file field + needs to be set. + rule: 'self.type == ''File'' ? has(self.file) : + !has(self.file)' + - message: If AccessLogSink type is OpenTelemetry, + openTelemetry field needs to be set. + rule: 'self.type == ''OpenTelemetry'' ? has(self.openTelemetry) + : !has(self.openTelemetry)' minItems: 1 type: array required: @@ -5459,6 +5477,8 @@ spec: description: Sinks defines the metric sinks where metrics are sent to. items: + description: ProxyMetricSink defines the sink of metrics. + Default metrics sink is OpenTelemetry. properties: openTelemetry: description: OpenTelemetry defines the configuration @@ -5489,6 +5509,11 @@ spec: required: - type type: object + x-kubernetes-validations: + - message: If MetricSink type is OpenTelemetry, openTelemetry + field needs to be set. + rule: 'self.type == ''OpenTelemetry'' ? has(self.openTelemetry) + : !has(self.openTelemetry)' type: array type: object tracing: diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 174ab89e45a..3f699cc8e47 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -1160,7 +1160,7 @@ _Appears in:_ - +ProxyAccessLogSink defines the sink of accesslog. _Appears in:_ - [ProxyAccessLogSetting](#proxyaccesslogsetting) @@ -1227,7 +1227,7 @@ _Appears in:_ - +ProxyMetricSink defines the sink of metrics. Default metrics sink is OpenTelemetry. _Appears in:_ - [ProxyMetrics](#proxymetrics) diff --git a/test/cel-validation/envoyproxy_test.go b/test/cel-validation/envoyproxy_test.go index 1d029655f7c..ac949ff971d 100644 --- a/test/cel-validation/envoyproxy_test.go +++ b/test/cel-validation/envoyproxy_test.go @@ -38,10 +38,8 @@ func TestEnvoyProxyProvider(t *testing.T) { wantErrors []string }{ { - desc: "nil provider", - mutate: func(envoy *egv1a1.EnvoyProxy) { - - }, + desc: "nil provider", + mutate: func(envoy *egv1a1.EnvoyProxy) {}, wantErrors: []string{}, }, { @@ -204,6 +202,223 @@ func TestEnvoyProxyProvider(t *testing.T) { }, wantErrors: []string{"loadBalancerIP can only be set for LoadBalancer type"}, }, + { + desc: "invalid-ProxyAccessLogFormat", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + AccessLog: &egv1a1.ProxyAccessLog{ + Settings: []egv1a1.ProxyAccessLogSetting{ + { + Format: egv1a1.ProxyAccessLogFormat{ + Type: "foo", + }, + }, + }, + }, + }, + } + }, + wantErrors: []string{"Unsupported value: \"foo\": supported values: \"Text\", \"JSON\""}, + }, + { + desc: "ProxyAccessLogFormat-with-TypeText-but-no-text", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + AccessLog: &egv1a1.ProxyAccessLog{ + Settings: []egv1a1.ProxyAccessLogSetting{ + { + Format: egv1a1.ProxyAccessLogFormat{ + Type: egv1a1.ProxyAccessLogFormatTypeText, + }, + Sinks: []egv1a1.ProxyAccessLogSink{ + { + Type: egv1a1.ProxyAccessLogSinkTypeFile, + File: &egv1a1.FileEnvoyProxyAccessLog{ + Path: "foo/bar", + }, + }, + }, + }, + }, + }, + }, + } + }, + wantErrors: []string{"If AccessLogFormat type is Text, text field needs to be set"}, + }, + { + desc: "ProxyAccessLogFormat-with-TypeJSON-but-no-json", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + AccessLog: &egv1a1.ProxyAccessLog{ + Settings: []egv1a1.ProxyAccessLogSetting{ + { + Format: egv1a1.ProxyAccessLogFormat{ + Type: egv1a1.ProxyAccessLogFormatTypeJSON, + }, + Sinks: []egv1a1.ProxyAccessLogSink{ + { + Type: egv1a1.ProxyAccessLogSinkTypeFile, + File: &egv1a1.FileEnvoyProxyAccessLog{ + Path: "foo/bar", + }, + }, + }, + }, + }, + }, + }, + } + }, + wantErrors: []string{"If AccessLogFormat type is JSON, json field needs to be set"}, + }, + { + desc: "ProxyAccessLogFormat-with-TypeJSON-but-got-text", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + AccessLog: &egv1a1.ProxyAccessLog{ + Settings: []egv1a1.ProxyAccessLogSetting{ + { + Format: egv1a1.ProxyAccessLogFormat{ + Type: egv1a1.ProxyAccessLogFormatTypeJSON, + Text: ptr.To("[%START_TIME%]"), + }, + Sinks: []egv1a1.ProxyAccessLogSink{ + { + Type: egv1a1.ProxyAccessLogSinkTypeFile, + File: &egv1a1.FileEnvoyProxyAccessLog{ + Path: "foo/bar", + }, + }, + }, + }, + }, + }, + }, + } + }, + wantErrors: []string{"If AccessLogFormat type is JSON, json field needs to be set"}, + }, + { + desc: "ProxyAccessLogSink-with-TypeFile-but-no-file", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + AccessLog: &egv1a1.ProxyAccessLog{ + Settings: []egv1a1.ProxyAccessLogSetting{ + { + Format: egv1a1.ProxyAccessLogFormat{ + Type: egv1a1.ProxyAccessLogFormatTypeText, + Text: ptr.To("[%START_TIME%]"), + }, + Sinks: []egv1a1.ProxyAccessLogSink{ + { + Type: egv1a1.ProxyAccessLogSinkTypeFile, + }, + }, + }, + }, + }, + }, + } + }, + wantErrors: []string{"If AccessLogSink type is File, file field needs to be set"}, + }, + { + desc: "ProxyAccessLogSink-with-TypeOpenTelemetry-but-no-openTelemetry", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + AccessLog: &egv1a1.ProxyAccessLog{ + Settings: []egv1a1.ProxyAccessLogSetting{ + { + Format: egv1a1.ProxyAccessLogFormat{ + Type: egv1a1.ProxyAccessLogFormatTypeText, + Text: ptr.To("[%START_TIME%]"), + }, + Sinks: []egv1a1.ProxyAccessLogSink{ + { + Type: egv1a1.ProxyAccessLogSinkTypeOpenTelemetry, + }, + }, + }, + }, + }, + }, + } + }, + wantErrors: []string{"If AccessLogSink type is OpenTelemetry, openTelemetry field needs to be set"}, + }, + { + desc: "ProxyAccessLog-settings-pass", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + AccessLog: &egv1a1.ProxyAccessLog{ + Settings: []egv1a1.ProxyAccessLogSetting{ + { + Format: egv1a1.ProxyAccessLogFormat{ + Type: egv1a1.ProxyAccessLogFormatTypeText, + Text: ptr.To("[%START_TIME%]"), + }, + Sinks: []egv1a1.ProxyAccessLogSink{ + { + Type: egv1a1.ProxyAccessLogSinkTypeFile, + File: &egv1a1.FileEnvoyProxyAccessLog{ + Path: "foo/bar", + }, + }, + }, + }, + }, + }, + }, + } + }, + wantErrors: []string{}, + }, + { + desc: "ProxyMetricSink-with-TypeOpenTelemetry-but-no-openTelemetry", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + Metrics: &egv1a1.ProxyMetrics{ + Sinks: []egv1a1.ProxyMetricSink{ + { + Type: egv1a1.MetricSinkTypeOpenTelemetry, + }, + }, + }, + }, + } + }, + wantErrors: []string{"If MetricSink type is OpenTelemetry, openTelemetry field needs to be set"}, + }, + { + desc: "ProxyMetrics-sinks-pass", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + Metrics: &egv1a1.ProxyMetrics{ + Sinks: []egv1a1.ProxyMetricSink{ + { + Type: egv1a1.MetricSinkTypeOpenTelemetry, + OpenTelemetry: &egv1a1.ProxyOpenTelemetrySink{ + Host: "0.0.0.0", + Port: 3217, + }, + }, + }, + }, + }, + } + }, + wantErrors: []string{}, + }, } for _, tc := range cases {