diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go index 47c1df0a7b1..82663b9b692 100644 --- a/internal/gatewayapi/listener.go +++ b/internal/gatewayapi/listener.go @@ -260,6 +260,50 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * } irAccessLog.JSON = append(irAccessLog.JSON, al) } + case egv1a1.ProxyAccessLogSinkTypeALS: + if sink.ALS == nil { + continue + } + + var logName string + if sink.ALS.LogName != nil { + logName = *sink.ALS.LogName + } else { + logName = fmt.Sprintf("%s/%s", envoyproxy.Namespace, envoyproxy.Name) + } + + // TODO: how to get authority from the backendRefs? + ds, err := t.processBackendRefs(sink.ALS.BackendRefs, envoyproxy.Namespace, resources) + if err != nil { + return nil, err + } + + al := &ir.ALSAccessLog{ + LogName: logName, + Destination: ir.RouteDestination{ + Name: fmt.Sprintf("accesslog-%d", idx), // TODO: rename this, so that we can share backend with tracing? + Settings: ds, + }, + Type: sink.ALS.Type, + } + + if al.Type == egv1a1.ALSEnvoyProxyAccessLogTypeHTTP { + http := &ir.ALSAccessLogHTTP{ + RequestHeaders: sink.ALS.HTTP.RequestHeaders, + ResponseHeaders: sink.ALS.HTTP.ResponseHeaders, + ResponseTrailers: sink.ALS.HTTP.ResponseTrailers, + } + al.HTTP = http + } + + switch accessLog.Format.Type { + case egv1a1.ProxyAccessLogFormatTypeJSON: + al.Attributes = accessLog.Format.JSON + case egv1a1.ProxyAccessLogFormatTypeText: + al.Text = accessLog.Format.Text + } + + irAccessLog.ALS = append(irAccessLog.ALS, al) case egv1a1.ProxyAccessLogSinkTypeOpenTelemetry: if sink.OpenTelemetry == nil { continue diff --git a/internal/gatewayapi/testdata/envoyproxy-accesslog-als-json.in.yaml b/internal/gatewayapi/testdata/envoyproxy-accesslog-als-json.in.yaml new file mode 100644 index 00000000000..fb56d69ab47 --- /dev/null +++ b/internal/gatewayapi/testdata/envoyproxy-accesslog-als-json.in.yaml @@ -0,0 +1,132 @@ +envoyproxy: + apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyProxy + metadata: + namespace: envoy-gateway-system + name: test + spec: + telemetry: + accessLog: + settings: + - format: + type: JSON + json: + attr1: val1 + attr2: val2 + sinks: + - type: ALS + als: + logName: accesslog + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + type: HTTP + - type: ALS + als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + type: TCP + provider: + type: Kubernetes + kubernetes: + envoyService: + type: LoadBalancer + envoyDeployment: + replicas: 2 + container: + env: + - name: env_a + value: env_a_value + - name: env_b + value: env_b_name + image: "envoyproxy/envoy:distroless-dev" + resources: + requests: + cpu: 100m + memory: 512Mi + securityContext: + runAsUser: 2000 + allowPrivilegeEscalation: false + pod: + annotations: + key1: val1 + key2: val2 + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: cloud.google.com/gke-nodepool + operator: In + values: + - router-node + tolerations: + - effect: NoSchedule + key: node-type + operator: Exists + value: "router" + securityContext: + runAsUser: 1000 + runAsGroup: 3000 + fsGroup: 2000 + fsGroupChangePolicy: "OnRootMismatch" + volumes: + - name: certs + secret: + secretName: envoy-cert +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http + protocol: HTTP + port: 80 + allowedRoutes: + namespaces: + from: Same +services: +- apiVersion: v1 + kind: Service + metadata: + name: envoy-als + namespace: monitoring + spec: + type: ClusterIP + ports: + - name: grpc + port: 9000 + protocol: TCP + targetPort: 9000 +endpointSlices: +- apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + name: endpointslice-envoy-als + namespace: monitoring + labels: + kubernetes.io/service-name: envoy-als + addressType: IPv4 + ports: + - name: grpc + protocol: TCP + port: 9090 + endpoints: + - addresses: + - "10.240.0.10" + conditions: + ready: true diff --git a/internal/gatewayapi/testdata/envoyproxy-accesslog-als-json.out.yaml b/internal/gatewayapi/testdata/envoyproxy-accesslog-als-json.out.yaml new file mode 100755 index 00000000000..35ed0198385 --- /dev/null +++ b/internal/gatewayapi/testdata/envoyproxy-accesslog-als-json.out.yaml @@ -0,0 +1,193 @@ +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + creationTimestamp: null + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: Same + name: http + port: 80 + protocol: HTTP + status: + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +infraIR: + envoy-gateway/gateway-1: + proxy: + config: + apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyProxy + metadata: + creationTimestamp: null + name: test + namespace: envoy-gateway-system + spec: + logging: {} + provider: + kubernetes: + envoyDeployment: + container: + env: + - name: env_a + value: env_a_value + - name: env_b + value: env_b_name + image: envoyproxy/envoy:distroless-dev + resources: + requests: + cpu: 100m + memory: 512Mi + securityContext: + allowPrivilegeEscalation: false + runAsUser: 2000 + pod: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: cloud.google.com/gke-nodepool + operator: In + values: + - router-node + annotations: + key1: val1 + key2: val2 + securityContext: + fsGroup: 2000 + fsGroupChangePolicy: OnRootMismatch + runAsGroup: 3000 + runAsUser: 1000 + tolerations: + - effect: NoSchedule + key: node-type + operator: Exists + value: router + volumes: + - name: certs + secret: + secretName: envoy-cert + replicas: 2 + envoyService: + type: LoadBalancer + type: Kubernetes + telemetry: + accessLog: + settings: + - format: + json: + attr1: val1 + attr2: val2 + type: JSON + sinks: + - als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + logName: accesslog + type: HTTP + type: ALS + - als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + type: TCP + type: ALS + status: {} + listeners: + - address: null + name: envoy-gateway/gateway-1/http + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + name: envoy-gateway/gateway-1 +xdsIR: + envoy-gateway/gateway-1: + accessLog: + als: + - attributes: + attr1: val1 + attr2: val2 + destination: + name: accesslog-0 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + name: accesslog + type: HTTP + - attributes: + attr1: val1 + attr2: val2 + destination: + name: accesslog-0 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + name: envoy-gateway-system/test + type: TCP + http: + - address: 0.0.0.0 + hostnames: + - '*' + isHTTP2: false + name: envoy-gateway/gateway-1/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 diff --git a/internal/gatewayapi/testdata/envoyproxy-accesslog-with-bad-sinks.in.yaml b/internal/gatewayapi/testdata/envoyproxy-accesslog-with-bad-sinks.in.yaml index cccabc9cd4d..58277d8a3b5 100644 --- a/internal/gatewayapi/testdata/envoyproxy-accesslog-with-bad-sinks.in.yaml +++ b/internal/gatewayapi/testdata/envoyproxy-accesslog-with-bad-sinks.in.yaml @@ -14,6 +14,7 @@ envoyproxy: [%START_TIME%] "%REQ(:METHOD)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"\n sinks: - type: File + - type: ALS - type: OpenTelemetry provider: type: Kubernetes diff --git a/internal/gatewayapi/testdata/envoyproxy-accesslog-with-bad-sinks.out.yaml b/internal/gatewayapi/testdata/envoyproxy-accesslog-with-bad-sinks.out.yaml index 05a1560000c..462c04f21a4 100644 --- a/internal/gatewayapi/testdata/envoyproxy-accesslog-with-bad-sinks.out.yaml +++ b/internal/gatewayapi/testdata/envoyproxy-accesslog-with-bad-sinks.out.yaml @@ -108,6 +108,7 @@ infraIR: type: Text sinks: - type: File + - type: ALS - type: OpenTelemetry status: {} listeners: diff --git a/internal/gatewayapi/testdata/envoyproxy-accesslog.in.yaml b/internal/gatewayapi/testdata/envoyproxy-accesslog.in.yaml index 0d691420576..180ae20f6fb 100644 --- a/internal/gatewayapi/testdata/envoyproxy-accesslog.in.yaml +++ b/internal/gatewayapi/testdata/envoyproxy-accesslog.in.yaml @@ -16,6 +16,28 @@ envoyproxy: - type: File file: path: /dev/stdout + - type: ALS + als: + logName: accesslog + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + type: HTTP + - type: ALS + als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + type: TCP - type: OpenTelemetry openTelemetry: host: otel-collector.monitoring.svc.cluster.local @@ -85,3 +107,34 @@ gateways: allowedRoutes: namespaces: from: Same +services: +- apiVersion: v1 + kind: Service + metadata: + name: envoy-als + namespace: monitoring + spec: + type: ClusterIP + ports: + - name: grpc + port: 9000 + protocol: TCP + targetPort: 9000 +endpointSlices: +- apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + name: endpointslice-envoy-als + namespace: monitoring + labels: + kubernetes.io/service-name: envoy-als + addressType: IPv4 + ports: + - name: grpc + protocol: TCP + port: 9090 + endpoints: + - addresses: + - "10.240.0.10" + conditions: + ready: true diff --git a/internal/gatewayapi/testdata/envoyproxy-accesslog.out.yaml b/internal/gatewayapi/testdata/envoyproxy-accesslog.out.yaml index 1c4c5b68347..28b37f6e876 100644 --- a/internal/gatewayapi/testdata/envoyproxy-accesslog.out.yaml +++ b/internal/gatewayapi/testdata/envoyproxy-accesslog.out.yaml @@ -110,6 +110,28 @@ infraIR: - file: path: /dev/stdout type: File + - als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + logName: accesslog + type: HTTP + type: ALS + - als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + type: TCP + type: ALS - openTelemetry: host: otel-collector.monitoring.svc.cluster.local port: 4317 @@ -133,6 +155,38 @@ infraIR: xdsIR: envoy-gateway/gateway-1: accessLog: + als: + - destination: + name: accesslog-0 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + name: accesslog + text: | + [%START_TIME%] "%REQ(:METHOD)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"\n + type: HTTP + - destination: + name: accesslog-0 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + name: envoy-gateway-system/test + text: | + [%START_TIME%] "%REQ(:METHOD)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"\n + type: TCP openTelemetry: - authority: otel-collector.monitoring.svc.cluster.local destination: diff --git a/internal/ir/xds.go b/internal/ir/xds.go index 9de48f29b33..7d52e0243e6 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -1601,6 +1601,7 @@ type RateLimitValue struct { type AccessLog struct { Text []*TextAccessLog `json:"text,omitempty" yaml:"text,omitempty"` JSON []*JSONAccessLog `json:"json,omitempty" yaml:"json,omitempty"` + ALS []*ALSAccessLog `json:"als,omitempty" yaml:"als,omitempty"` OpenTelemetry []*OpenTelemetryAccessLog `json:"openTelemetry,omitempty" yaml:"openTelemetry,omitempty"` } @@ -1618,6 +1619,25 @@ type JSONAccessLog struct { Path string `json:"path" yaml:"path"` } +// ALSAccessLog holds the configuration for gRPC ALS access logging. +// +k8s:deepcopy-gen=true +type ALSAccessLog struct { + LogName string `json:"name" yaml:"name"` + Destination RouteDestination `json:"destination,omitempty" yaml:"destination,omitempty"` + Type egv1a1.ALSEnvoyProxyAccessLogType `json:"type" yaml:"type"` + Text *string `json:"text,omitempty" yaml:"text,omitempty"` + Attributes map[string]string `json:"attributes,omitempty" yaml:"attributes,omitempty"` + HTTP *ALSAccessLogHTTP `json:"http,omitempty" yaml:"http,omitempty"` +} + +// ALSAccessLogHTTP holds the configuration for HTTP ALS access logging. +// +k8s:deepcopy-gen=true +type ALSAccessLogHTTP struct { + RequestHeaders []string `json:"requestHeaders,omitempty" yaml:"requestHeaders,omitempty"` + ResponseHeaders []string `json:"responseHeaders,omitempty" yaml:"responseHeaders,omitempty"` + ResponseTrailers []string `json:"responseTrailers,omitempty" yaml:"responseTrailers,omitempty"` +} + // OpenTelemetryAccessLog holds the configuration for OpenTelemetry access logging. // +k8s:deepcopy-gen=true type OpenTelemetryAccessLog struct { diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go index 69e10d9dc94..ef6477f22f0 100644 --- a/internal/ir/zz_generated.deepcopy.go +++ b/internal/ir/zz_generated.deepcopy.go @@ -16,6 +16,69 @@ import ( "sigs.k8s.io/gateway-api/apis/v1alpha2" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ALSAccessLog) DeepCopyInto(out *ALSAccessLog) { + *out = *in + in.Destination.DeepCopyInto(&out.Destination) + if in.Text != nil { + in, out := &in.Text, &out.Text + *out = new(string) + **out = **in + } + if in.Attributes != nil { + in, out := &in.Attributes, &out.Attributes + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.HTTP != nil { + in, out := &in.HTTP, &out.HTTP + *out = new(ALSAccessLogHTTP) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ALSAccessLog. +func (in *ALSAccessLog) DeepCopy() *ALSAccessLog { + if in == nil { + return nil + } + out := new(ALSAccessLog) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ALSAccessLogHTTP) DeepCopyInto(out *ALSAccessLogHTTP) { + *out = *in + if in.RequestHeaders != nil { + in, out := &in.RequestHeaders, &out.RequestHeaders + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.ResponseHeaders != nil { + in, out := &in.ResponseHeaders, &out.ResponseHeaders + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.ResponseTrailers != nil { + in, out := &in.ResponseTrailers, &out.ResponseTrailers + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ALSAccessLogHTTP. +func (in *ALSAccessLogHTTP) DeepCopy() *ALSAccessLogHTTP { + if in == nil { + return nil + } + out := new(ALSAccessLogHTTP) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AccessLog) DeepCopyInto(out *AccessLog) { *out = *in @@ -41,6 +104,17 @@ func (in *AccessLog) DeepCopyInto(out *AccessLog) { } } } + if in.ALS != nil { + in, out := &in.ALS, &out.ALS + *out = make([]*ALSAccessLog, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(ALSAccessLog) + (*in).DeepCopyInto(*out) + } + } + } if in.OpenTelemetry != nil { in, out := &in.OpenTelemetry, &out.OpenTelemetry *out = make([]*OpenTelemetryAccessLog, len(*in)) diff --git a/internal/provider/kubernetes/indexers.go b/internal/provider/kubernetes/indexers.go index 9b4a3f17a1f..2e17239032f 100644 --- a/internal/provider/kubernetes/indexers.go +++ b/internal/provider/kubernetes/indexers.go @@ -155,23 +155,29 @@ func backendEnvoyProxyTelemetryIndexFunc(rawObj client.Object) []string { func accessLogRefs(ep *egv1a1.EnvoyProxy) []string { var refs []string - if ep.Spec.Telemetry == nil || ep.Spec.Telemetry.Metrics == nil { + if ep.Spec.Telemetry == nil || ep.Spec.Telemetry.AccessLog == nil { return refs } - for _, sink := range ep.Spec.Telemetry.Metrics.Sinks { - if sink.OpenTelemetry != nil { - otel := sink.OpenTelemetry - if otel.BackendRefs != nil { - for _, ref := range otel.BackendRefs { - if ref.Kind == nil || string(*ref.Kind) == gatewayapi.KindService { - refs = append(refs, - types.NamespacedName{ - Namespace: gatewayapi.NamespaceDerefOr(ref.Namespace, ep.Namespace), - Name: string(ref.Name), - }.String(), - ) - } + for _, setting := range ep.Spec.Telemetry.AccessLog.Settings { + for _, sink := range setting.Sinks { + var backendRefs []egv1a1.BackendRef + if sink.OpenTelemetry != nil { + backendRefs = append(backendRefs, sink.OpenTelemetry.BackendRefs...) + } + + if sink.ALS != nil { + backendRefs = append(backendRefs, sink.ALS.BackendRefs...) + } + + for _, ref := range backendRefs { + if ref.Kind == nil || string(*ref.Kind) == gatewayapi.KindService { + refs = append(refs, + types.NamespacedName{ + Namespace: gatewayapi.NamespaceDerefOr(ref.Namespace, ep.Namespace), + Name: string(ref.Name), + }.String(), + ) } } } diff --git a/internal/xds/translator/accesslog.go b/internal/xds/translator/accesslog.go index ce58b507c96..1406dcf7515 100644 --- a/internal/xds/translator/accesslog.go +++ b/internal/xds/translator/accesslog.go @@ -6,6 +6,7 @@ package translator import ( + "encoding/json" "errors" "sort" "strings" @@ -24,6 +25,7 @@ import ( "google.golang.org/protobuf/types/known/anypb" "google.golang.org/protobuf/types/known/structpb" + "github.com/envoyproxy/gateway/api/v1alpha1" "github.com/envoyproxy/gateway/internal/ir" "github.com/envoyproxy/gateway/internal/utils/protocov" "github.com/envoyproxy/gateway/internal/xds/types" @@ -170,6 +172,74 @@ func buildXdsAccessLog(al *ir.AccessLog, forListener bool) []*accesslog.AccessLo }, }) } + // handle ALS access logs + for _, als := range al.ALS { + cc := &grpcaccesslog.CommonGrpcAccessLogConfig{ + LogName: als.LogName, + GrpcService: &cfgcore.GrpcService{ + TargetSpecifier: &cfgcore.GrpcService_EnvoyGrpc_{ + EnvoyGrpc: &cfgcore.GrpcService_EnvoyGrpc{ + ClusterName: als.Destination.Name, + }, + }, + }, + TransportApiVersion: cfgcore.ApiVersion_V3, + } + + // include text and json format as metadata when initiating stream + md := make([]*cfgcore.HeaderValue, 0, 2) + + if als.Text != nil && *als.Text != "" { + md = append(md, &cfgcore.HeaderValue{ + Key: "x-accesslog-text", + Value: strings.ReplaceAll(strings.Trim(*als.Text, "\x00\n\r"), "\x00\n\r", " "), + }) + } + + if len(als.Attributes) > 0 { + if attr, err := json.Marshal(als.Attributes); err == nil { + md = append(md, &cfgcore.HeaderValue{ + Key: "x-accesslog-attr", + Value: string(attr), + }) + } + } + + cc.GrpcService.InitialMetadata = md + + switch als.Type { + case v1alpha1.ALSEnvoyProxyAccessLogTypeHTTP: + al := &grpcaccesslog.HttpGrpcAccessLogConfig{ + CommonConfig: cc, + } + + if als.HTTP != nil { + al.AdditionalRequestHeadersToLog = als.HTTP.RequestHeaders + al.AdditionalResponseHeadersToLog = als.HTTP.ResponseHeaders + al.AdditionalResponseTrailersToLog = als.HTTP.ResponseTrailers + } + + accesslogAny, _ := anypb.New(al) + accessLogs = append(accessLogs, &accesslog.AccessLog{ + Name: "envoy.access_loggers.http_grpc", + ConfigType: &accesslog.AccessLog_TypedConfig{ + TypedConfig: accesslogAny, + }, + }) + case v1alpha1.ALSEnvoyProxyAccessLogTypeTCP: + al := &grpcaccesslog.TcpGrpcAccessLogConfig{ + CommonConfig: cc, + } + + accesslogAny, _ := anypb.New(al) + accessLogs = append(accessLogs, &accesslog.AccessLog{ + Name: "envoy.access_loggers.tcp_grpc", + ConfigType: &accesslog.AccessLog_TypedConfig{ + TypedConfig: accesslogAny, + }, + }) + } + } // handle open telemetry access logs for _, otel := range al.OpenTelemetry { al := &otelaccesslog.OpenTelemetryAccessLogConfig{ @@ -387,6 +457,19 @@ func processClusterForAccessLog(tCtx *types.ResourceVersionTable, al *ir.AccessL return nil } + // add clusters for ALS access logs + for _, als := range al.ALS { + if err := addXdsCluster(tCtx, &xdsClusterArgs{ + name: als.Destination.Name, + settings: als.Destination.Settings, + tSocket: nil, + endpointType: EndpointTypeStatic, + }); err != nil && !errors.Is(err, ErrXdsClusterExists) { + return err + } + } + + // add clusters for Open Telemetry access logs for _, otel := range al.OpenTelemetry { if err := addXdsCluster(tCtx, &xdsClusterArgs{ name: otel.Destination.Name, diff --git a/internal/xds/translator/testdata/in/xds-ir/accesslog-als-tcp.yaml b/internal/xds/translator/testdata/in/xds-ir/accesslog-als-tcp.yaml new file mode 100644 index 00000000000..2d8f0c6aa48 --- /dev/null +++ b/internal/xds/translator/testdata/in/xds-ir/accesslog-als-tcp.yaml @@ -0,0 +1,23 @@ +name: "accesslog" +accesslog: + json: + - json: + start_time: "%START_TIME%" + method: "%REQ(:METHOD)%" + path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%" + protocol: "%PROTOCOL%" + response_code: "%RESPONSE_CODE%" + als: + - destination: + name: accesslog/monitoring/envoy-als/port/9000 + settings: + - addressType: IP + endpoints: + - host: 1.1.1.1 + port: 9000 + protocol: GRPC + weight: 1 + attributes: + attr1: value1 + attr2: value2 + type: TCP diff --git a/internal/xds/translator/testdata/in/xds-ir/accesslog.yaml b/internal/xds/translator/testdata/in/xds-ir/accesslog.yaml index 07d910197a7..26f0f5663f8 100644 --- a/internal/xds/translator/testdata/in/xds-ir/accesslog.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/accesslog.yaml @@ -12,6 +12,29 @@ accesslog: path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%" protocol: "%PROTOCOL%" response_code: "%RESPONSE_CODE%" + als: + - destination: + name: accesslog/monitoring/envoy-als/port/9000 + settings: + - addressType: IP + endpoints: + - host: 1.1.1.1 + port: 9000 + protocol: GRPC + weight: 1 + text: | + [%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%" + attributes: + attr1: value1 + attr2: value2 + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + type: HTTP openTelemetry: - text: | [%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%" diff --git a/internal/xds/translator/testdata/out/xds-ir/accesslog-als-tcp.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/accesslog-als-tcp.clusters.yaml new file mode 100755 index 00000000000..18b309bb74d --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/accesslog-als-tcp.clusters.yaml @@ -0,0 +1,22 @@ +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: accesslog/monitoring/envoy-als/port/9000 + lbPolicy: LEAST_REQUEST + name: accesslog/monitoring/envoy-als/port/9000 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: {} diff --git a/internal/xds/translator/testdata/out/xds-ir/accesslog-als-tcp.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/accesslog-als-tcp.endpoints.yaml new file mode 100755 index 00000000000..9159d4e31f2 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/accesslog-als-tcp.endpoints.yaml @@ -0,0 +1,12 @@ +- clusterName: accesslog/monitoring/envoy-als/port/9000 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.1.1.1 + portValue: 9000 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: accesslog/monitoring/envoy-als/port/9000/backend/0 diff --git a/internal/xds/translator/testdata/out/xds-ir/accesslog-als-tcp.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/accesslog-als-tcp.listeners.yaml new file mode 100755 index 00000000000..fe51488c706 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/accesslog-als-tcp.listeners.yaml @@ -0,0 +1 @@ +[] diff --git a/internal/xds/translator/testdata/out/xds-ir/accesslog-als-tcp.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/accesslog-als-tcp.routes.yaml new file mode 100755 index 00000000000..fe51488c706 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/accesslog-als-tcp.routes.yaml @@ -0,0 +1 @@ +[] diff --git a/internal/xds/translator/testdata/out/xds-ir/accesslog.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/accesslog.clusters.yaml index b8874bf24f9..6ba4705c13f 100644 --- a/internal/xds/translator/testdata/out/xds-ir/accesslog.clusters.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/accesslog.clusters.yaml @@ -15,6 +15,28 @@ outlierDetection: {} perConnectionBufferLimitBytes: 32768 type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: accesslog/monitoring/envoy-als/port/9000 + lbPolicy: LEAST_REQUEST + name: accesslog/monitoring/envoy-als/port/9000 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: {} - circuitBreakers: thresholds: - maxRetries: 1024 diff --git a/internal/xds/translator/testdata/out/xds-ir/accesslog.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/accesslog.endpoints.yaml index 20c80b3aaaa..2ce2e6da08c 100644 --- a/internal/xds/translator/testdata/out/xds-ir/accesslog.endpoints.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/accesslog.endpoints.yaml @@ -10,3 +10,15 @@ loadBalancingWeight: 1 locality: region: direct-route-dest/backend/0 +- clusterName: accesslog/monitoring/envoy-als/port/9000 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.1.1.1 + portValue: 9000 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: accesslog/monitoring/envoy-als/port/9000/backend/0 diff --git a/internal/xds/translator/testdata/out/xds-ir/accesslog.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/accesslog.listeners.yaml index 8e582b05b7e..21621ff674e 100644 --- a/internal/xds/translator/testdata/out/xds-ir/accesslog.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/accesslog.listeners.yaml @@ -26,6 +26,32 @@ response_code: '%RESPONSE_CODE%' start_time: '%START_TIME%' path: /dev/stdout + - filter: + responseFlagFilter: + flags: + - NR + name: envoy.access_loggers.http_grpc + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.HttpGrpcAccessLogConfig + additionalRequestHeadersToLog: + - x-client-ip-address + additionalResponseHeadersToLog: + - cache-control + additionalResponseTrailersToLog: + - expires + commonConfig: + grpcService: + envoyGrpc: + clusterName: accesslog/monitoring/envoy-als/port/9000 + initialMetadata: + - key: x-accesslog-text + value: '[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% + %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% + %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" + "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"' + - key: x-accesslog-attr + value: '{"attr1":"value1","attr2":"value2"}' + transportApiVersion: V3 - filter: responseFlagFilter: flags: @@ -88,6 +114,29 @@ response_code: '%RESPONSE_CODE%' start_time: '%START_TIME%' path: /dev/stdout + - name: envoy.access_loggers.http_grpc + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.HttpGrpcAccessLogConfig + additionalRequestHeadersToLog: + - x-client-ip-address + additionalResponseHeadersToLog: + - cache-control + additionalResponseTrailersToLog: + - expires + commonConfig: + grpcService: + envoyGrpc: + clusterName: accesslog/monitoring/envoy-als/port/9000 + initialMetadata: + - key: x-accesslog-text + value: '[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% + %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% + %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% + "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" + "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"' + - key: x-accesslog-attr + value: '{"attr1":"value1","attr2":"value2"}' + transportApiVersion: V3 - name: envoy.access_loggers.open_telemetry typedConfig: '@type': type.googleapis.com/envoy.extensions.access_loggers.open_telemetry.v3.OpenTelemetryAccessLogConfig