From 06e4f39b4d9fd2c2ee7ad8059ac76ad104089682 Mon Sep 17 00:00:00 2001 From: zirain Date: Tue, 2 Apr 2024 09:28:50 +0800 Subject: [PATCH] api: Model OpenTelelemetry Sinks as a BackendRef (#3067) * api: Model OpenTelelemetry Sinks as a BackendRef Signed-off-by: zirain * update Signed-off-by: zirain * fix gen Signed-off-by: zirain --------- Signed-off-by: zirain --- api/v1alpha1/accesslogging_types.go | 14 +- api/v1alpha1/envoyproxy_metric_types.go | 13 + api/v1alpha1/tracing_types.go | 13 + api/v1alpha1/zz_generated.deepcopy.go | 19 +- .../gateway.envoyproxy.io_envoyproxies.yaml | 277 +++++++++++++++++- site/content/en/latest/api/extension_types.md | 21 +- test/cel-validation/envoyproxy_test.go | 248 ++++++++++++++++ tools/make/golang.mk | 7 + 8 files changed, 590 insertions(+), 22 deletions(-) diff --git a/api/v1alpha1/accesslogging_types.go b/api/v1alpha1/accesslogging_types.go index 483a224fab4..48694edb2a7 100644 --- a/api/v1alpha1/accesslogging_types.go +++ b/api/v1alpha1/accesslogging_types.go @@ -5,6 +5,8 @@ package v1alpha1 +import gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" + type ProxyAccessLog struct { // Disable disables access logging for managed proxies if set to true. Disable bool `json:"disable,omitempty"` @@ -92,16 +94,26 @@ type FileEnvoyProxyAccessLog struct { Path string `json:"path,omitempty"` } -// TODO: consider reuse ExtensionService? +// OpenTelemetryEnvoyProxyAccessLog defines the OpenTelemetry access log sink. +// +// +kubebuilder:validation:XValidation:message="BackendRef only support Service Kind.",rule="!has(self.backendRef) || !has(self.backendRef.kind) || self.backendRef.kind == 'Service'" type OpenTelemetryEnvoyProxyAccessLog struct { // Host define the extension service hostname. + // Deprecated: Use BackendRef instead. Host string `json:"host"` // Port defines the port the extension service is exposed on. + // Deprecated: Use BackendRef instead. // // +optional // +kubebuilder:validation:Minimum=0 // +kubebuilder:default=4317 Port int32 `json:"port,omitempty"` + // BackendRef references a Kubernetes object that represents the + // backend server to which the accesslog will be sent. + // Only service Kind is supported for now. + // + // +optional + BackendRef *gwapiv1.BackendObjectReference `json:"backendRef,omitempty"` // Resources is a set of labels that describe the source of a log entry, including envoy node info. // It's recommended to follow [semantic conventions](https://opentelemetry.io/docs/reference/specification/resource/semantic_conventions/). // +optional diff --git a/api/v1alpha1/envoyproxy_metric_types.go b/api/v1alpha1/envoyproxy_metric_types.go index 71fb42ca62b..4c45df39e36 100644 --- a/api/v1alpha1/envoyproxy_metric_types.go +++ b/api/v1alpha1/envoyproxy_metric_types.go @@ -5,6 +5,8 @@ package v1alpha1 +import gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" + type MetricSinkType string const ( @@ -47,16 +49,27 @@ type ProxyMetricSink struct { OpenTelemetry *ProxyOpenTelemetrySink `json:"openTelemetry,omitempty"` } +// ProxyOpenTelemetrySink defines the configuration for OpenTelemetry sink. +// +// +kubebuilder:validation:XValidation:message="BackendRef only support Service Kind.",rule="!has(self.backendRef) || !has(self.backendRef.kind) || self.backendRef.kind == 'Service'" type ProxyOpenTelemetrySink struct { // Host define the service hostname. + // Deprecated: Use BackendRef instead. Host string `json:"host"` // Port defines the port the service is exposed on. + // Deprecated: Use BackendRef instead. // // +optional // +kubebuilder:validation:Minimum=0 // +kubebuilder:validation:Maximum=65535 // +kubebuilder:default=4317 Port int32 `json:"port,omitempty"` + // BackendRef references a Kubernetes object that represents the + // backend server to which the metric will be sent. + // Only service Kind is supported for now. + // + // +optional + BackendRef *gwapiv1.BackendObjectReference `json:"backendRef,omitempty"` // TODO: add support for customizing OpenTelemetry sink in https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/stat_sinks/open_telemetry/v3/open_telemetry.proto#envoy-v3-api-msg-extensions-stat-sinks-open-telemetry-v3-sinkconfig } diff --git a/api/v1alpha1/tracing_types.go b/api/v1alpha1/tracing_types.go index 63529df54f2..7c86ba7c846 100644 --- a/api/v1alpha1/tracing_types.go +++ b/api/v1alpha1/tracing_types.go @@ -5,6 +5,8 @@ package v1alpha1 +import gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" + type ProxyTracing struct { // SamplingRate controls the rate at which traffic will be // selected for tracing if no prior sampling decision has been made. @@ -28,6 +30,9 @@ const ( TracingProviderTypeOpenTelemetry TracingProviderType = "OpenTelemetry" ) +// TracingProvider defines the tracing provider configuration. +// +// +kubebuilder:validation:XValidation:message="BackendRef only support Service Kind.",rule="!has(self.backendRef) || !has(self.backendRef.kind) || self.backendRef.kind == 'Service'" type TracingProvider struct { // Type defines the tracing provider type. // EG currently only supports OpenTelemetry. @@ -35,13 +40,21 @@ type TracingProvider struct { // +kubebuilder:default=OpenTelemetry Type TracingProviderType `json:"type"` // Host define the provider service hostname. + // Deprecated: Use BackendRef instead. Host string `json:"host"` // Port defines the port the provider service is exposed on. + // Deprecated: Use BackendRef instead. // // +optional // +kubebuilder:validation:Minimum=0 // +kubebuilder:default=4317 Port int32 `json:"port,omitempty"` + // BackendRef references a Kubernetes object that represents the + // backend server to which the accesslog will be sent. + // Only service Kind is supported for now. + // + // +optional + BackendRef *gwapiv1.BackendObjectReference `json:"backendRef"` } type CustomTagType string diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index d170dcf1f43..9b3bbab456b 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -2610,6 +2610,11 @@ func (in *OIDCProvider) DeepCopy() *OIDCProvider { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OpenTelemetryEnvoyProxyAccessLog) DeepCopyInto(out *OpenTelemetryEnvoyProxyAccessLog) { *out = *in + if in.BackendRef != nil { + in, out := &in.BackendRef, &out.BackendRef + *out = new(v1.BackendObjectReference) + (*in).DeepCopyInto(*out) + } if in.Resources != nil { in, out := &in.Resources, &out.Resources *out = make(map[string]string, len(*in)) @@ -2874,7 +2879,7 @@ func (in *ProxyMetricSink) DeepCopyInto(out *ProxyMetricSink) { if in.OpenTelemetry != nil { in, out := &in.OpenTelemetry, &out.OpenTelemetry *out = new(ProxyOpenTelemetrySink) - **out = **in + (*in).DeepCopyInto(*out) } } @@ -2925,6 +2930,11 @@ func (in *ProxyMetrics) DeepCopy() *ProxyMetrics { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ProxyOpenTelemetrySink) DeepCopyInto(out *ProxyOpenTelemetrySink) { *out = *in + if in.BackendRef != nil { + in, out := &in.BackendRef, &out.BackendRef + *out = new(v1.BackendObjectReference) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyOpenTelemetrySink. @@ -3012,7 +3022,7 @@ func (in *ProxyTracing) DeepCopyInto(out *ProxyTracing) { (*out)[key] = *val.DeepCopy() } } - out.Provider = in.Provider + in.Provider.DeepCopyInto(&out.Provider) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyTracing. @@ -3706,6 +3716,11 @@ func (in *Timeout) DeepCopy() *Timeout { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TracingProvider) DeepCopyInto(out *TracingProvider) { *out = *in + if in.BackendRef != nil { + in, out := &in.BackendRef, &out.BackendRef + *out = new(v1.BackendObjectReference) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TracingProvider. 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 4e092a8e739..4232d906453 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -5899,14 +5899,95 @@ spec: description: OpenTelemetry defines the OpenTelemetry accesslog sink. properties: + backendRef: + description: |- + BackendRef references a Kubernetes object that represents the + backend server to which the accesslog will be sent. + Only service Kind is supported for now. + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + + Defaults to "Service" when not specified. + + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + + Support: Core (Services with a type other than ExternalName) + + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' host: - description: Host define the extension service - hostname. + description: |- + Host define the extension service hostname. + Deprecated: Use BackendRef instead. type: string port: default: 4317 - description: Port defines the port the extension - service is exposed on. + description: |- + Port defines the port the extension service is exposed on. + Deprecated: Use BackendRef instead. format: int32 minimum: 0 type: integer @@ -5920,6 +6001,10 @@ spec: required: - host type: object + x-kubernetes-validations: + - message: BackendRef only support Service Kind. + rule: '!has(self.backendRef) || !has(self.backendRef.kind) + || self.backendRef.kind == ''Service''' type: description: Type defines the type of accesslog sink. @@ -6007,13 +6092,95 @@ spec: OpenTelemetry defines the configuration for OpenTelemetry sink. It's required if the sink type is OpenTelemetry. properties: + backendRef: + description: |- + BackendRef references a Kubernetes object that represents the + backend server to which the metric will be sent. + Only service Kind is supported for now. + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + + Defaults to "Service" when not specified. + + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + + Support: Core (Services with a type other than ExternalName) + + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == + ''Service'') ? has(self.port) : true' host: - description: Host define the service hostname. + description: |- + Host define the service hostname. + Deprecated: Use BackendRef instead. type: string port: default: 4317 - description: Port defines the port the service is - exposed on. + description: |- + Port defines the port the service is exposed on. + Deprecated: Use BackendRef instead. format: int32 maximum: 65535 minimum: 0 @@ -6021,6 +6188,10 @@ spec: required: - host type: object + x-kubernetes-validations: + - message: BackendRef only support Service Kind. + rule: '!has(self.backendRef) || !has(self.backendRef.kind) + || self.backendRef.kind == ''Service''' type: default: OpenTelemetry description: |- @@ -6111,13 +6282,95 @@ spec: Provider defines the tracing provider. Only OpenTelemetry is supported currently. properties: + backendRef: + description: |- + BackendRef references a Kubernetes object that represents the + backend server to which the accesslog will be sent. + Only service Kind is supported for now. + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + + Defaults to "Service" when not specified. + + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + + Support: Core (Services with a type other than ExternalName) + + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' host: - description: Host define the provider service hostname. + description: |- + Host define the provider service hostname. + Deprecated: Use BackendRef instead. type: string port: default: 4317 - description: Port defines the port the provider service - is exposed on. + description: |- + Port defines the port the provider service is exposed on. + Deprecated: Use BackendRef instead. format: int32 minimum: 0 type: integer @@ -6133,6 +6386,10 @@ spec: - host - type type: object + x-kubernetes-validations: + - message: BackendRef only support Service Kind. + rule: '!has(self.backendRef) || !has(self.backendRef.kind) + || self.backendRef.kind == ''Service''' samplingRate: default: 100 description: |- diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index a289a7530b8..63ef6b2f381 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -1793,15 +1793,16 @@ _Appears in:_ -TODO: consider reuse ExtensionService? +OpenTelemetryEnvoyProxyAccessLog defines the OpenTelemetry access log sink. _Appears in:_ - [ProxyAccessLogSink](#proxyaccesslogsink) | Field | Type | Required | Description | | --- | --- | --- | --- | -| `host` | _string_ | true | Host define the extension service hostname. | -| `port` | _integer_ | false | Port defines the port the extension service is exposed on. | +| `host` | _string_ | true | Host define the extension service hostname.
Deprecated: Use BackendRef instead. | +| `port` | _integer_ | false | Port defines the port the extension service is exposed on.
Deprecated: Use BackendRef instead. | +| `backendRef` | _[BackendObjectReference](#backendobjectreference)_ | false | BackendRef references a Kubernetes object that represents the
backend server to which the accesslog will be sent.
Only service Kind is supported for now. | | `resources` | _object (keys:string, values:string)_ | false | Resources is a set of labels that describe the source of a log entry, including envoy node info.
It's recommended to follow [semantic conventions](https://opentelemetry.io/docs/reference/specification/resource/semantic_conventions/). | @@ -2066,15 +2067,16 @@ _Appears in:_ - +ProxyOpenTelemetrySink defines the configuration for OpenTelemetry sink. _Appears in:_ - [ProxyMetricSink](#proxymetricsink) | Field | Type | Required | Description | | --- | --- | --- | --- | -| `host` | _string_ | true | Host define the service hostname. | -| `port` | _integer_ | false | Port defines the port the service is exposed on. | +| `host` | _string_ | true | Host define the service hostname.
Deprecated: Use BackendRef instead. | +| `port` | _integer_ | false | Port defines the port the service is exposed on.
Deprecated: Use BackendRef instead. | +| `backendRef` | _[BackendObjectReference](#backendobjectreference)_ | false | BackendRef references a Kubernetes object that represents the
backend server to which the metric will be sent.
Only service Kind is supported for now. | #### ProxyPrometheusProvider @@ -2673,7 +2675,7 @@ _Appears in:_ - +TracingProvider defines the tracing provider configuration. _Appears in:_ - [ProxyTracing](#proxytracing) @@ -2681,8 +2683,9 @@ _Appears in:_ | Field | Type | Required | Description | | --- | --- | --- | --- | | `type` | _[TracingProviderType](#tracingprovidertype)_ | true | Type defines the tracing provider type.
EG currently only supports OpenTelemetry. | -| `host` | _string_ | true | Host define the provider service hostname. | -| `port` | _integer_ | false | Port defines the port the provider service is exposed on. | +| `host` | _string_ | true | Host define the provider service hostname.
Deprecated: Use BackendRef instead. | +| `port` | _integer_ | false | Port defines the port the provider service is exposed on.
Deprecated: Use BackendRef instead. | +| `backendRef` | _[BackendObjectReference](#backendobjectreference)_ | false | BackendRef references a Kubernetes object that represents the
backend server to which the accesslog will be sent.
Only service Kind is supported for now. | #### TracingProviderType diff --git a/test/cel-validation/envoyproxy_test.go b/test/cel-validation/envoyproxy_test.go index cc414e314b6..b7850a084ad 100644 --- a/test/cel-validation/envoyproxy_test.go +++ b/test/cel-validation/envoyproxy_test.go @@ -17,6 +17,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" + gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" ) @@ -398,6 +399,126 @@ func TestEnvoyProxyProvider(t *testing.T) { }, wantErrors: []string{}, }, + { + desc: "accesslog-OpenTelemetry", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + AccessLog: &egv1a1.ProxyAccessLog{ + Settings: []egv1a1.ProxyAccessLogSetting{ + { + Format: egv1a1.ProxyAccessLogFormat{ + Type: "Text", + Text: ptr.To("[%START_TIME%]"), + }, + Sinks: []egv1a1.ProxyAccessLogSink{ + { + Type: egv1a1.ProxyAccessLogSinkTypeOpenTelemetry, + OpenTelemetry: &egv1a1.OpenTelemetryEnvoyProxyAccessLog{ + Host: "0.0.0.0", + Port: 8080, + }, + }, + }, + }, + }, + }, + }, + } + }, + }, + { + desc: "invalid-accesslog-backendref", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + AccessLog: &egv1a1.ProxyAccessLog{ + Settings: []egv1a1.ProxyAccessLogSetting{ + { + Format: egv1a1.ProxyAccessLogFormat{ + Type: "Text", + Text: ptr.To("[%START_TIME%]"), + }, + Sinks: []egv1a1.ProxyAccessLogSink{ + { + Type: egv1a1.ProxyAccessLogSinkTypeOpenTelemetry, + OpenTelemetry: &egv1a1.OpenTelemetryEnvoyProxyAccessLog{ + BackendRef: &gwapiv1.BackendObjectReference{ + Name: "fake-service", + Kind: ptr.To(gwapiv1.Kind("foo")), + }, + }, + }, + }, + }, + }, + }, + }, + } + }, + wantErrors: []string{"BackendRef only support Service Kind."}, + }, + { + desc: "accesslog-backendref", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + AccessLog: &egv1a1.ProxyAccessLog{ + Settings: []egv1a1.ProxyAccessLogSetting{ + { + Format: egv1a1.ProxyAccessLogFormat{ + Type: "Text", + Text: ptr.To("[%START_TIME%]"), + }, + Sinks: []egv1a1.ProxyAccessLogSink{ + { + Type: egv1a1.ProxyAccessLogSinkTypeOpenTelemetry, + OpenTelemetry: &egv1a1.OpenTelemetryEnvoyProxyAccessLog{ + BackendRef: &gwapiv1.BackendObjectReference{ + Name: "fake-service", + Kind: ptr.To(gwapiv1.Kind("Service")), + Port: ptr.To(gwapiv1.PortNumber(8080)), + }, + }, + }, + }, + }, + }, + }, + }, + } + }, + }, + { + desc: "accesslog-backendref-empty-kind", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + AccessLog: &egv1a1.ProxyAccessLog{ + Settings: []egv1a1.ProxyAccessLogSetting{ + { + Format: egv1a1.ProxyAccessLogFormat{ + Type: "Text", + Text: ptr.To("[%START_TIME%]"), + }, + Sinks: []egv1a1.ProxyAccessLogSink{ + { + Type: egv1a1.ProxyAccessLogSinkTypeOpenTelemetry, + OpenTelemetry: &egv1a1.OpenTelemetryEnvoyProxyAccessLog{ + BackendRef: &gwapiv1.BackendObjectReference{ + Name: "fake-service", + Port: ptr.To(gwapiv1.PortNumber(8080)), + }, + }, + }, + }, + }, + }, + }, + }, + } + }, + }, { desc: "ProxyMetricSink-with-TypeOpenTelemetry-but-no-openTelemetry", mutate: func(envoy *egv1a1.EnvoyProxy) { @@ -436,6 +557,133 @@ func TestEnvoyProxyProvider(t *testing.T) { }, wantErrors: []string{}, }, + { + desc: "ProxyMetrics-sinks-backendref", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + Metrics: &egv1a1.ProxyMetrics{ + Sinks: []egv1a1.ProxyMetricSink{ + { + Type: egv1a1.MetricSinkTypeOpenTelemetry, + OpenTelemetry: &egv1a1.ProxyOpenTelemetrySink{ + BackendRef: &gwapiv1.BackendObjectReference{ + Name: "fake-service", + Kind: ptr.To(gwapiv1.Kind("Service")), + Port: ptr.To(gwapiv1.PortNumber(8080)), + }, + }, + }, + }, + }, + }, + } + }, + wantErrors: []string{}, + }, + { + desc: "ProxyMetrics-sinks-backendref-empty-kind", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + Metrics: &egv1a1.ProxyMetrics{ + Sinks: []egv1a1.ProxyMetricSink{ + { + Type: egv1a1.MetricSinkTypeOpenTelemetry, + OpenTelemetry: &egv1a1.ProxyOpenTelemetrySink{ + BackendRef: &gwapiv1.BackendObjectReference{ + Name: "fake-service", + Port: ptr.To(gwapiv1.PortNumber(8080)), + }, + }, + }, + }, + }, + }, + } + }, + wantErrors: []string{}, + }, + { + desc: "ProxyMetrics-sinks-invalid-backendref", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + Metrics: &egv1a1.ProxyMetrics{ + Sinks: []egv1a1.ProxyMetricSink{ + { + Type: egv1a1.MetricSinkTypeOpenTelemetry, + OpenTelemetry: &egv1a1.ProxyOpenTelemetrySink{ + BackendRef: &gwapiv1.BackendObjectReference{ + Name: "fake-service", + Kind: ptr.To(gwapiv1.Kind("foo")), + Port: ptr.To(gwapiv1.PortNumber(8080)), + }, + }, + }, + }, + }, + }, + } + }, + wantErrors: []string{"BackendRef only support Service Kind."}, + }, + { + desc: "invalid-tracing-backendref", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + Tracing: &egv1a1.ProxyTracing{ + Provider: egv1a1.TracingProvider{ + Type: egv1a1.TracingProviderTypeOpenTelemetry, + BackendRef: &gwapiv1.BackendObjectReference{ + Name: "fake-service", + Kind: ptr.To(gwapiv1.Kind("foo")), + }, + }, + }, + }, + } + }, + wantErrors: []string{"BackendRef only support Service Kind."}, + }, + { + desc: "tracing-backendref-empty-kind", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + Tracing: &egv1a1.ProxyTracing{ + Provider: egv1a1.TracingProvider{ + Type: egv1a1.TracingProviderTypeOpenTelemetry, + BackendRef: &gwapiv1.BackendObjectReference{ + Name: "fake-service", + Port: ptr.To(gwapiv1.PortNumber(8080)), + }, + }, + }, + }, + } + }, + }, + { + desc: "tracing-backendref", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Telemetry: &egv1a1.ProxyTelemetry{ + Tracing: &egv1a1.ProxyTracing{ + Provider: egv1a1.TracingProvider{ + Type: egv1a1.TracingProviderTypeOpenTelemetry, + BackendRef: &gwapiv1.BackendObjectReference{ + Name: "fake-service", + Kind: ptr.To(gwapiv1.Kind("Service")), + Port: ptr.To(gwapiv1.PortNumber(8080)), + }, + }, + }, + }, + } + }, + }, { desc: "ProxyHpa-maxReplicas-is-required", mutate: func(envoy *egv1a1.EnvoyProxy) { diff --git a/tools/make/golang.mk b/tools/make/golang.mk index 8f30d4a667f..6ef30a956ef 100644 --- a/tools/make/golang.mk +++ b/tools/make/golang.mk @@ -61,6 +61,13 @@ go.test.coverage: $(tools/setup-envtest) ## Run go unit and integration tests in KUBEBUILDER_ASSETS="$(shell $(tools/setup-envtest) use $(ENVTEST_K8S_VERSION) -p path)" \ go test ./... --tags=integration,celvalidation -race -coverprofile=coverage.xml -covermode=atomic +.PHONY: go.test.cel +go.test.cel: manifests $(tools/setup-envtest) # Run the CEL validation tests + @$(LOG_TARGET) + go clean -testcache # Ensure we're not using cached test results + KUBEBUILDER_ASSETS="$(shell $(tools/setup-envtest) use $(ENVTEST_K8S_VERSION) -p path)" \ + go test ./test/cel-validation --tags=celvalidation -race + .PHONY: go.clean go.clean: ## Clean the building output files @$(LOG_TARGET)