From 2e8b4f9917161741a3e5677af0a8e791aaae1175 Mon Sep 17 00:00:00 2001 From: mrproliu <741550557@qq.com> Date: Tue, 2 Jul 2024 07:37:42 +0000 Subject: [PATCH] Support Fetch Cilium Observability data to monitoring Cilium Service network traffic (#12393) --- .licenserc.yaml | 1 + dist-material/release-docs/LICENSE | 5 + dist-material/release-docs/LICENSE.tpl | 3 + docs/en/changes/changes.md | 7 +- docs/en/concepts-and-designs/oal.md | 5 + .../concepts-and-designs/scope-definitions.md | 104 ++- docs/en/guides/How-to-build.md | 1 + .../backend/backend-k8s-monitoring-cilium.md | 108 +++ .../setup/backend/backend-k8s-monitoring.md | 3 + .../setup/backend/configuration-vocabulary.md | 9 + docs/menu.yml | 2 + oap-server-bom/pom.xml | 5 + .../skywalking/oal/rt/grammar/OALLexer.g4 | 6 + .../skywalking/oal/rt/grammar/OALParser.g4 | 3 +- .../oap/server/core/analysis/Layer.java | 8 +- .../endpoint/HubbleEndpointDispatcher.java | 34 + .../HubbleInstanceTrafficDispatcher.java | 35 + .../HubbleEndpointCallRelationDispatcher.java | 45 + ...ServiceInstanceCallRelationDispatcher.java | 60 ++ .../HubbleServiceCallRelationDispatcher.java | 64 ++ .../HubbleServiceTrafficDispatcher.java | 34 + .../analysis/metrics/LabelCountMetrics.java | 90 ++ .../ui/template/UITemplateInitializer.java | 1 + .../server/core/source/CiliumEndpoint.java | 49 + .../core/source/CiliumEndpointRelation.java | 68 ++ .../oap/server/core/source/CiliumMetrics.java | 78 ++ .../oap/server/core/source/CiliumService.java | 48 + .../core/source/CiliumServiceInstance.java | 51 + .../source/CiliumServiceInstanceRelation.java | 68 ++ .../core/source/CiliumServiceRelation.java | 62 ++ .../core/source/DefaultScopeDefine.java | 7 + .../cilium-fetcher-plugin/pom.xml | 53 ++ .../fetcher/cilium/CiliumFetcherConfig.java | 34 + .../fetcher/cilium/CiliumFetcherModule.java | 34 + .../fetcher/cilium/CiliumFetcherProvider.java | 99 ++ .../fetcher/cilium/CiliumOALDefine.java | 33 + .../cilium/handler/CiliumFlowListener.java | 474 ++++++++++ .../fetcher/cilium/handler/DNSCodes.java | 50 + .../fetcher/cilium/handler/KafkaCodes.java | 151 +++ .../cilium/handler/ServiceMetadata.java | 87 ++ .../fetcher/cilium/nodes/CiliumNode.java | 94 ++ .../cilium/nodes/CiliumNodeManager.java | 311 +++++++ .../nodes/CiliumNodeUpdateListener.java | 37 + .../fetcher/cilium/nodes/ClientBuilder.java | 26 + .../fetcher/cilium/nodes/GrpcStubBuilder.java | 70 ++ ...ing.oap.server.library.module.ModuleDefine | 19 + ...g.oap.server.library.module.ModuleProvider | 19 + .../cilium/nodes/CiliumNodeManagerTest.java | 159 ++++ .../fetcher-proto/pom.xml | 164 ++++ .../main/proto/cilium/hubble/flow/flow.proto | 869 ++++++++++++++++++ .../cilium/hubble/observer/observer.proto | 310 +++++++ .../main/proto/cilium/hubble/peer/peer.proto | 61 ++ .../proto/cilium/hubble/relay/relay.proto | 42 + oap-server/server-fetcher-plugin/pom.xml | 22 + .../server/grpc/ssl/DynamicSslContext.java | 2 +- .../server/library/util}/FieldsHelper.java | 123 +-- .../library/util}/FieldsHelperTest.java | 50 +- .../envoy/EnvoyMetricReceiverProvider.java | 4 +- .../als/mx/MetaExchangeALSHTTPAnalyzer.java | 3 +- .../envoy/als/mx/ServiceMetaInfoAdapter.java | 25 +- .../mx/MetaExchangeTCPAccessLogAnalyzer.java | 4 +- .../ClusterManagerMetricsAdapterTest.java | 6 +- ...atterTest.java => FieldFormatterTest.java} | 2 +- .../src/test/resources/field-helper.msg | 89 -- oap-server/server-starter/pom.xml | 5 + .../src/main/resources/application.yml | 12 + .../main/resources/component-libraries.yml | 3 + .../resources/metadata-service-mapping.yaml | 2 +- .../src/main/resources/oal/cilium.oal | 200 ++++ .../cilium_service/cilium-endpoint.json | 304 ++++++ .../cilium_service/cilium-root.json | 167 ++++ .../cilium-service-instance-relation.json | 395 ++++++++ .../cilium-service-instance.json | 481 ++++++++++ .../cilium-service-relation.json | 483 ++++++++++ .../cilium_service/cilium-service.json | 564 ++++++++++++ .../ui-initialized-templates/menu.yaml | 9 + skywalking-ui | 2 +- 77 files changed, 7031 insertions(+), 186 deletions(-) create mode 100644 docs/en/setup/backend/backend-k8s-monitoring-cilium.md create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/endpoint/HubbleEndpointDispatcher.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/instance/HubbleInstanceTrafficDispatcher.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/endpoint/HubbleEndpointCallRelationDispatcher.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/instance/HubbleServiceInstanceCallRelationDispatcher.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/service/HubbleServiceCallRelationDispatcher.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/service/HubbleServiceTrafficDispatcher.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/LabelCountMetrics.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumEndpoint.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumEndpointRelation.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumMetrics.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumService.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumServiceInstance.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumServiceInstanceRelation.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumServiceRelation.java create mode 100644 oap-server/server-fetcher-plugin/cilium-fetcher-plugin/pom.xml create mode 100644 oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/CiliumFetcherConfig.java create mode 100644 oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/CiliumFetcherModule.java create mode 100644 oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/CiliumFetcherProvider.java create mode 100644 oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/CiliumOALDefine.java create mode 100644 oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/handler/CiliumFlowListener.java create mode 100644 oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/handler/DNSCodes.java create mode 100644 oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/handler/KafkaCodes.java create mode 100644 oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/handler/ServiceMetadata.java create mode 100644 oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/CiliumNode.java create mode 100644 oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/CiliumNodeManager.java create mode 100644 oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/CiliumNodeUpdateListener.java create mode 100644 oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/ClientBuilder.java create mode 100644 oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/GrpcStubBuilder.java create mode 100644 oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleDefine create mode 100644 oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider create mode 100644 oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/test/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/CiliumNodeManagerTest.java create mode 100644 oap-server/server-fetcher-plugin/fetcher-proto/pom.xml create mode 100644 oap-server/server-fetcher-plugin/fetcher-proto/src/main/proto/cilium/hubble/flow/flow.proto create mode 100644 oap-server/server-fetcher-plugin/fetcher-proto/src/main/proto/cilium/hubble/observer/observer.proto create mode 100644 oap-server/server-fetcher-plugin/fetcher-proto/src/main/proto/cilium/hubble/peer/peer.proto create mode 100644 oap-server/server-fetcher-plugin/fetcher-proto/src/main/proto/cilium/hubble/relay/relay.proto rename oap-server/{server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/als/mx => server-library/library-util/src/main/java/org/apache/skywalking/oap/server/library/util}/FieldsHelper.java (66%) rename oap-server/{server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/als/mx => server-library/library-util/src/test/java/org/apache/skywalking/oap/server/library/util}/FieldsHelperTest.java (63%) rename oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/als/k8s/{ServiceNameFormatterTest.java => FieldFormatterTest.java} (99%) delete mode 100644 oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/resources/field-helper.msg create mode 100644 oap-server/server-starter/src/main/resources/oal/cilium.oal create mode 100644 oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-endpoint.json create mode 100644 oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-root.json create mode 100644 oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-service-instance-relation.json create mode 100644 oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-service-instance.json create mode 100644 oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-service-relation.json create mode 100644 oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-service.json diff --git a/.licenserc.yaml b/.licenserc.yaml index 445d5362c1d4..e9f54c08041d 100644 --- a/.licenserc.yaml +++ b/.licenserc.yaml @@ -60,6 +60,7 @@ header: - '**/src/main/proto/jaeger/**' - '**/src/main/proto/mixer/**' - '**/src/main/proto/policy/**' + - '**/src/main/proto/cilium/**' - '**/src/main/proto/prometheus/client_model/metrics.proto' - '**/src/main/proto/protoc-gen-swagger/**' - '**/src/main/proto/validate/validate.proto' diff --git a/dist-material/release-docs/LICENSE b/dist-material/release-docs/LICENSE index efce54ed310b..7cbf202b2713 100644 --- a/dist-material/release-docs/LICENSE +++ b/dist-material/release-docs/LICENSE @@ -241,6 +241,8 @@ The text of each license is the standard Apache 2.0 license. https://mvnrepository.com/artifact/com.linecorp.armeria/armeria/1.27.3 Apache-2.0 https://mvnrepository.com/artifact/com.linecorp.armeria/armeria-graphql/1.27.3 Apache-2.0 https://mvnrepository.com/artifact/com.linecorp.armeria/armeria-graphql-protocol/1.27.3 Apache-2.0 + https://mvnrepository.com/artifact/com.linecorp.armeria/armeria-grpc/1.27.3 Apache-2.0 + https://mvnrepository.com/artifact/com.linecorp.armeria/armeria-grpc-protocol/1.27.3 Apache-2.0 https://mvnrepository.com/artifact/com.linecorp.armeria/armeria-protobuf/1.27.3 Apache-2.0 https://mvnrepository.com/artifact/com.orbitz.consul/consul-client/1.5.3 Apache-2.0 https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp/3.14.9 Apache-2.0 @@ -295,6 +297,7 @@ The text of each license is the standard Apache 2.0 license. https://mvnrepository.com/artifact/io.grpc/grpc-netty/1.63.0 Apache-2.0 https://mvnrepository.com/artifact/io.grpc/grpc-protobuf/1.63.0 Apache-2.0 https://mvnrepository.com/artifact/io.grpc/grpc-protobuf-lite/1.63.0 Apache-2.0 + https://mvnrepository.com/artifact/io.grpc/grpc-services/1.61.0 Apache-2.0 https://mvnrepository.com/artifact/io.grpc/grpc-stub/1.63.0 Apache-2.0 https://mvnrepository.com/artifact/io.grpc/grpc-util/1.63.0 Apache-2.0 https://mvnrepository.com/artifact/io.micrometer/micrometer-commons/1.12.2 Apache-2.0 @@ -371,6 +374,7 @@ The text of each license is the standard Apache 2.0 license. https://mvnrepository.com/artifact/org.xerial.snappy/snappy-java/1.1.8.4 Apache-2.0 https://mvnrepository.com/artifact/org.yaml/snakeyaml/2.0 Apache-2.0 https://npmjs.com/package/typescript/v/4.7.4 4.7.4 Apache-2.0 + https://github.com/cilium/cilium/tree/v1.15.6/api/v1 Apache-2.0 ======================================================================== BSD-2-Clause licenses @@ -544,6 +548,7 @@ The text of each license is also included in licenses/LICENSE-[project].txt. https://npmjs.com/package/nanoid/v/3.3.7 3.3.7 MIT https://mvnrepository.com/artifact/org.checkerframework/checker-qual/3.33.0 MIT https://mvnrepository.com/artifact/org.codehaus.mojo/animal-sniffer-annotations/1.23 MIT + https://mvnrepository.com/artifact/org.curioswitch.curiostack/protobuf-jackson/2.2.0 MIT https://npmjs.com/package/pinia/v/2.0.28 2.0.28 MIT https://npmjs.com/package/pinia/node_modules/vue-demi/v/0.13.11 0.13.11 MIT https://npmjs.com/package/postcss/v/8.4.33 8.4.33 MIT diff --git a/dist-material/release-docs/LICENSE.tpl b/dist-material/release-docs/LICENSE.tpl index 5479740ec7ba..738f07ec2370 100644 --- a/dist-material/release-docs/LICENSE.tpl +++ b/dist-material/release-docs/LICENSE.tpl @@ -30,6 +30,9 @@ The text of each license is also included in licenses/LICENSE-[project].txt. https://npmjs.com/package/{{ .Name }}/v/{{ .Version }} {{ .Version }} {{ .LicenseID }} {{- end }} {{- end }} + {{- if eq .LicenseID "Apache-2.0" }} + https://github.com/cilium/cilium/tree/v1.15.6/api/v1 Apache-2.0 + {{- end }} {{ end }} ======================================================================= The zipkin-lens.jar dependency has more front-end dependencies in it and the front-end dependencies' licenses diff --git a/docs/en/changes/changes.md b/docs/en/changes/changes.md index 97dc783e79ef..000dd37544c1 100644 --- a/docs/en/changes/changes.md +++ b/docs/en/changes/changes.md @@ -22,9 +22,14 @@ * [Break Change] Update Nacos version to 2.3.2. Nacos 1.x server can't serve as cluster coordinator and configuration server. * Support tracing trace query(SkyWalking and Zipkin) for debugging. * Fix BanyanDB metrics query: used the wrong `Downsampling` type to find the schema. +* Support fetch cilium flow to monitoring network traffic between cilium services. +* Support `labelCount` function in the OAL engine. #### UI - +* Highlight search log keywords. +* Add Error URL in the browser log. +* Add a SolonMVC icon. +* Adding cilium icon and i18n for menu. #### Documentation diff --git a/docs/en/concepts-and-designs/oal.md b/docs/en/concepts-and-designs/oal.md index 1f88901b90e8..34e55074ef6f 100644 --- a/docs/en/concepts-and-designs/oal.md +++ b/docs/en/concepts-and-designs/oal.md @@ -102,6 +102,11 @@ In this case, see `p99`, `p95`, `p90`, `p75`, and `p50` of all incoming requests In this case, the p99 value of all incoming requests. The parameter is precise to a latency at p99, such as in the above case, and 120ms and 124ms are considered to produce the same response time. +- `labelCount`. The count of the label value. +> drop_reason_count = from(CiliumService.*).filter(verdict == "dropped").labelCount(dropReason); + +In this case, the count of the drop reason of each Cilium service. + ## Metrics name The metrics name for storage implementor, alarm and query modules. The type inference is supported by core. diff --git a/docs/en/concepts-and-designs/scope-definitions.md b/docs/en/concepts-and-designs/scope-definitions.md index 1047c6383960..1d2e5ab53cfb 100644 --- a/docs/en/concepts-and-designs/scope-definitions.md +++ b/docs/en/concepts-and-designs/scope-definitions.md @@ -566,4 +566,106 @@ For `K8SEndpoint` and `K8SEndpointRelation`, they only have the following **prot | componentId | The ID of component used in this call. | | string | | destServiceName | The dest service name in kubernetes. | | string | | destServiceName | The layer in kubernetes dest service. | | string | -| destEndpointName | The endpoint name detect in kubernetes dest service. | | string | \ No newline at end of file +| destEndpointName | The endpoint name detect in kubernetes dest service. | | string | + +### SCOPES with `Cilium` Prefix + +All metrics starting with `Cilium` are derived from Cilium monitoring by Cilium Hubble. + +#### Service, Service Instance and relations + +For all `CiliumService`, `CiliumServiceInstance`, `CiliumServiceRelation` and `CiliumServiceInstanceRelation`, they all have the +following **L4**/**L7** metric contents. + +| Name | Remarks | Group Key | Type | +|-----------------------|-----------------------------------------------------------------------------|-----------|--------| +| verdict | The metrics verdict from Flow. The value may be `forwarded` and `dropped`. | | string | +| type | The metrics type from Flow. The value may be `tcp`, `http`, `dns`, `kakfa`. | | string | +| direction | The metrics direction from Flow. The value may be `ingress` and `egress`. | | string | +| dropReason | When the verdict is `dropped`, the drop reason would be recorded. | | string | +| http.url | The URL of the HTTP request. | | string | +| http.code | The Response code of the HTTP response. | | int | +| http.protocol | The protocol of the HTTP request. | | string | +| http.method | The method of the HTTP request. | | string | +| kafka.errorCode | The error code of the Kafka request. | | int | +| kafka.errorCodeString | The error code explaination of the Kafka request. | | string | +| kafka.apiVersion | The API version of the Kafka request. | | string | +| kafka.apiKey | The API key of the Kafka request. | | string | +| kafka.correlationId | The correlation ID of the Kafka request. | | string | +| kafka.topic | The topic of the Kafka request. | | string | +| dns.domain | The domain of the DNS request. | | string | +| dns.queryType | The query type of the DNS request. | | string | +| dns.rcode | The response code of the DNS request. | | int | +| dns.recodeString | The response code explaination of the DNS request. | | string | +| dns.ttl | The TTL of the DNS request. | | int | +| dns.ipCount | The count of the IP addresses of the DNS responsed. | | int | +| duration | The duration(millisecond) of the L7 response. | | long | +| success | Is the response success of the L7 response. | | bool | + +##### SCOPE `CiliumService` + +| Name | Remarks | Group Key | Type | +|-------------|--------------------------------------------------------------------|-----------|--------| +| name | The service name in Cilium. | | string | +| layer | The layer in Cilium service. | | string | +| detectPoint | Where the relation is detected. The value may be client or server. | | enum | + +##### SCOPE `CiliumServiceInstance` + +| Name | Remarks | Group Key | Type | +|---------------------|--------------------------------------------------------------------|-----------|--------| +| serviceName | The service name in Cilium. | | string | +| serviceInstanceName | The pod name in Cilium. | | string | +| layer | The layer of Cilium service. | | string | +| detectPoint | Where the relation is detected. The value may be client or server. | | enum | + +##### SCOPE `CiliumServiceRelation` + +| Name | Remarks | Group Key | Type | +|-------------------|--------------------------------------------------------------------|-----------|--------| +| sourceServiceName | The source service name in Cilium. | | string | +| sourceLayer | The source layer service in Cilium. | | string | +| detectPoint | Where the relation is detected. The value may be client or server. | | enum | +| componentId | The ID of component used in this call. | | int | +| destServiceName | The dest service name in Cilium. | | string | +| destLayer | The dest layer service in Cilium. | | string | + +##### SCOPE `CiliumServiceInstanceRelation` + +| Name | Remarks | Group Key | Type | +|---------------------------|--------------------------------------------------------------------|-----------|--------| +| sourceServiceName | The source service name in Cilium. | | string | +| sourceServiceInstanceName | The source pod name in Cilium. | | string | +| sourceLayer | The source layer service in Cilium. | | string | +| detectPoint | Where the relation is detected. The value may be client or server. | | enum | +| componentId | The ID of component used in this call. | | int | +| destServiceName | The dest service name in Cilium. | | string | +| destServiceInstanceName | The dest pod name in Cilium. | | string | +| destLayer | The dest layer service in Cilium. | | string | + +#### Endpoint and Endpoint Relation + +For `CiliumEndpoint` and `CiliumEndpointRelation`, they have all the fields of **L4**/**L7** metric contents, but the `type` only would be `http`, `dns` or `kafka`. + +##### SCOPE `CiliumEndpoint` + +| Name | Remarks | Group Key | Type | +|--------------|---------------------------------------------------------|-----------|--------| +| serviceName | The service name in Cilium. | | string | +| layer | The layer in Cilium service. | | string | +| endpointName | The endpoint name detect in Cilium service. | | string | + +##### SCOPE `CiliumEndpointRelation` + +| Name | Remarks | Group Key | Type | +|--------------------|--------------------------------------------------------------------|-----------|--------| +| sourceServiceName | The source service name in Cilium. | | string | +| sourceLayer | The layer in Cilium source service. | | enum | +| sourceEndpointName | The endpoint name detect in Cilium source service. | | string | +| detectPoint | Where the relation is detected. The value may be client or server. | | enum | +| componentId | The ID of component used in this call. | | int | +| destServiceName | The dest service name in Cilium. | | string | +| destLayer | The layer in Cilium dest service. | | enum | +| destEndpointName | The endpoint name detect in Cilium dest service. | | string | + + diff --git a/docs/en/guides/How-to-build.md b/docs/en/guides/How-to-build.md index bb3862f90761..ed2200193f54 100644 --- a/docs/en/guides/How-to-build.md +++ b/docs/en/guides/How-to-build.md @@ -84,4 +84,5 @@ Refer to [Build docker image](../../../docker) for more details. * `grpc-java` and `java` folders in **oap-server/exporter/target/generated-sources/protobuf** * `grpc-java` and `java` folders in **oap-server/server-configuration/grpc-configuration-sync/target/generated-sources/protobuf** * `grpc-java` and `java` folders in **oap-server/server-alarm-plugin/target/generated-sources/protobuf** + * `grpc-java` and `java` folders in **oap-server/server-fetcher-plugin/fetcher-proto/target/generated-sources/protobuf** * `antlr4` folder in **oap-server/oal-grammar/target/generated-sources** diff --git a/docs/en/setup/backend/backend-k8s-monitoring-cilium.md b/docs/en/setup/backend/backend-k8s-monitoring-cilium.md new file mode 100644 index 000000000000..4dcfd7634189 --- /dev/null +++ b/docs/en/setup/backend/backend-k8s-monitoring-cilium.md @@ -0,0 +1,108 @@ +# Kubernetes (K8s) monitoring from Rover + +SkyWalking uses the Cilium Fetcher to gather traffic data between services from Cilium Hubble via the Observe API. It then leverages the [OAL System](./../../concepts-and-designs/oal.md) for metrics and entity analysis. + +## Data flow + +SkyWalking fetches Cilium Node and Observability Data from gRPC API, analysis to generate entity and using [OAL](./../../concepts-and-designs/oal.md) to generating metrics. + +## API Requirements + +1. [Peers API](https://github.com/cilium/cilium/blob/main/api/v1/peer/peer_grpc.pb.go#L33-L39): Listen the hubble node in the cluster, OAP would communicate with Hubble node to obtain Observe data. +2. [Observe API](https://github.com/cilium/cilium/blob/main/api/v1/observer/observer_grpc.pb.go#L41): Fetch the Flow data from Hubble node. + +## Setup +1. Please following the [Setup Hubble Observability documentation](https://docs.cilium.io/en/stable/gettingstarted/hubble_setup/) to setting the Hubble for provided API. +2. To activate Cilium receiver module, set `selector=default` in the YAML or `set SW_CILIUM_FETCHER=default` through the system environment variable. +```yaml +cilium-fetcher: + selector: ${SW_CILIUM_FETCHER:default} + default: + # Host name and port of Hubble peer component + peerHost: ${SW_CILIUM_FETCHER_PEER_HOST:hubble-peer.kube-system.svc.cluster.local} + peerPort: ${SW_CILIUM_FETCHER_PEER_PORT:80} + fetchFailureRetrySecond: ${SW_CILIUM_FETCHER_FETCH_FAILURE_RETRY_SECOND:10} + sslConnection: ${SW_CILIUM_FETCHER_SSL_CONNECTION:false} + sslPrivateKeyFile: ${SW_CILIUM_FETCHER_PRIVATE_KEY_FILE_PATH:} + sslCertChainFile: ${SW_CILIUM_FETCHER_CERT_CHAIN_FILE_PATH:} + sslCaFile: ${SW_CILIUM_FETCHER_CA_FILE_PATH:} + convertClientAsServerTraffic: ${SW_CILIUM_FETCHER_CONVERT_CLIENT_AS_SERVER_TRAFFIC:true} +``` +3. If enabled the [TLS certificate within the Hubble](https://docs.cilium.io/en/stable/gettingstarted/hubble-configuration/#tls-certificates), please update these few configurations. + 1. `peerPort`: usually should be updated to the `443`. + 2. `sslConnection`: should be set to `true`. + 3. `sslPrivateKeyFile`: the path of the private key file. + 4. `sslCertChainFile`: the path of the certificate chain file. + 5. `sslCaFile`: the path of the CA file. + +## Generated Entities + +SkyWalking fetch the flow from Cilium, analyzes the source and destination endpoint to parse out the following corresponding entities: +1. Service +2. Service Instance +3. Service Endpoint +4. Service Relation +5. Service Instance Relation +6. Service Endpoint Relation + +## Generate Metrics + +For each of the above-mentioned entities, metrics such as L4 and L7 protocols can be analyzed. + +### L4 Metrics + +Record the relevant metrics for every service read/write packages with other services. + +| Name | Unit | Description | +|---------------------------|---------------|---------------------------------------------------------------------------| +| Read Package CPM | Count | Total Read Package from other Service counts per minutes. | +| Write Package CPM | Count | Total Write Package from other Service counts per minutes. | +| Drop Package CPM | Count | Total Drop Package from other Service counts per minutes. | +| Drop Package Reason Count | Labeled Count | Total Read Package reason(labeled) from other Service counts per minutes. | + +### Protocol + +Based on each transfer data analysis, extract the information of the 7-layer network protocol. + +NOTE: By default, Cilium only reports L4 metrics. If you need L7 metrics, +they must be explicitly specified in each service's CiliumNetworkPolicy. For details please [refer to this document](https://docs.cilium.io/en/latest/security/). + +#### HTTP + +| Name | Unit | Description | +|--------------------|-------------|---------------------------------------------------------| +| CPM | Count | HTTP Request calls per minutes. | +| Duration | Nanoseconds | Total HTTP Response use duration. | +| Success CPM | Count | Total HTTP Response success(status < 500) count. | +| Status 1/2/3/4/5xx | Count | HTTP Response status code group by 1xx/2xx/3xx/4xx/5xx. | + +#### DNS + +| Name | Unit | Description | +|-------------|-------------|--------------------------------------------------------| +| CPM | Count | DNS Request calls per minutes. | +| Duration | Nanoseconds | Total DNS Response use duration. | +| Success CPM | Count | Total DNS Response success(code == 0) count. | +| Error Count | Label Count | DNS Response error count with error description label. | + +#### Kafka + +| Name | Unit | Description | +|-------------|-------------|----------------------------------------------------------| +| CPM | Count | Kafka Request calls per minutes. | +| Duration | Nanoseconds | Total Kafka Response use duration. | +| Success CPM | Count | Total Kafka Response success(errorCode == 0) count. | +| Error Count | Label Count | Kafka Response error count with error description label. | + +## Load Balance for Cilium Fetcher with OAP cluster + +The Cilium Fetcher module relies on the Cluster module, when the Cilium Fetcher module starts up, +it obtains information about all Cilium nodes and node information in the OAP cluster through Peers API on each OAP node. + +Additionally, it averagely distributes collected Cilium nodes to every OAP node. +Moreover, it ensures that a single Cilium node is not monitored by multiple OAP nodes. + +## Customizations +You can customize your own metrics/dashboard panel. +The metrics definition and expression rules are found in `/config/oal/cilium.oal`, please refer the [Scope Declaration Documentation](../../concepts-and-designs/scope-definitions.md#scopes-with-cilium-prefix). +The Cilium dashboard panel configurations are found in `/config/ui-initialized-templates/cilium_service`. diff --git a/docs/en/setup/backend/backend-k8s-monitoring.md b/docs/en/setup/backend/backend-k8s-monitoring.md index b483ba006fbd..3c94a445a4f1 100644 --- a/docs/en/setup/backend/backend-k8s-monitoring.md +++ b/docs/en/setup/backend/backend-k8s-monitoring.md @@ -13,6 +13,9 @@ ways to monitor deployments on Kubernetes. 2. Rover is a SkyWalking native eBPF agent to collect network Access Logs to support topology-aware and metrics analysis. Meanwhile, due to the power of eBPF, it could profile running services written by C++, Rust, Golang, etc. Read [Rover setup guide](./backend-k8s-monitoring-rover.md) for more details. +3. If Cilium is installed in Kubernetes, use Cilium Fetcher to collect network traffic data of services through Cilium Hubble APIs. + This data can be used to create topology maps and to provide L4 and L7 layer metrics. + Read [Cilium Fetcher setup guide](./backend-k8s-monitoring-cilium.md) for more details. SkyWalking deeply integrates with Kubernetes to help users understand the status of their applications on Kubernetes. Cillium with Hubble is in our v10 plan. \ No newline at end of file diff --git a/docs/en/setup/backend/configuration-vocabulary.md b/docs/en/setup/backend/configuration-vocabulary.md index e721922c5260..8f89debe52a2 100644 --- a/docs/en/setup/backend/configuration-vocabulary.md +++ b/docs/en/setup/backend/configuration-vocabulary.md @@ -241,6 +241,15 @@ The Configuration Vocabulary lists all available configurations provided by `app | - | - | topicNameOfManagements | Kafka topic name for service instance reporting and registration. | - | skywalking-managements | | - | - | topicNameOfLogs | Kafka topic name for native proto log data. | - | skywalking-logs | | - | - | topicNameOfJsonLogs | Kafka topic name for native json log data. | - | skywalking-logs-json | +| cilium-fetcher | default | Read Cilium Observe protocol data to collect Cilium Service status. | - | - | | +| - | - | peerHost | The Cilium Peer Service Host. | SW_CILIUM_FETCHER_PEER_HOST | hubble-peer.kube-system.svc.cluster.local | +| - | - | peerPort | The Cilium Peer Service Port. | SW_CILIUM_FETCHER_PEER_PORT | 80 | +| - | - | fetchFailureRetrySecond | The Cilium fetch observe data failure retry interval(second). | SW_CILIUM_FETCHER_FETCH_FAILURE_RETRY_SECOND | 10 | +| - | - | sslConnection | The Cilium fetch protocol is TLS enabled or not. | eSW_CILIUM_FETCHER_SSL_CONNECTION | false | +| - | - | sslPrivateKeyFile | The Cilium TLS fetch private key file path. | SW_CILIUM_FETCHER_PRIVATE_KEY_FILE_PATH | "" | +| - | - | sslCertChainFile | The Cilium TLS fetch cert chain file path. | SW_CILIUM_FETCHER_CERT_CHAIN_FILE_PATH | "" | +| - | - | sslCaFile | The Cilium TLS fetch rot CA Certification file path. | SW_CILIUM_FETCHER_CA_FILE_PATH | "" | +| - | - | convertClientAsServerTraffic | The Cilium flow data should convert client to the server side not. If convert, then the server side flow would be ignored. | SW_CILIUM_FETCHER_CONVERT_CLIENT_AS_SERVER_TRAFFIC | true | | receiver-browser | default | gRPC services that accept browser performance data and error log. | - | - | - | | - | - | sampleRate | Sampling rate for receiving trace. Precise to 1/10000. 10000 means sampling rate of 100% by default. | SW_RECEIVER_BROWSER_SAMPLE_RATE | 10000 | | query | graphql | - | GraphQL query implementation. | - | | diff --git a/docs/menu.yml b/docs/menu.yml index 005d5fdd25cf..7e9a4ccbcada 100644 --- a/docs/menu.yml +++ b/docs/menu.yml @@ -82,6 +82,8 @@ catalog: path: "/en/setup/backend/backend-k8s-monitoring-rover" - name: "Profile Pod's Network" path: "/en/setup/backend/backend-k8s-network-monitoring" + - name: "Cilium" + path: "/en/setup/backend/backend-k8s-monitoring-cilium" - name: "Infrastructure Monitoring" catalog: - name: "Linux Monitoring" diff --git a/oap-server-bom/pom.xml b/oap-server-bom/pom.xml index 4076469305dd..7a8d5571e2f4 100644 --- a/oap-server-bom/pom.xml +++ b/oap-server-bom/pom.xml @@ -552,6 +552,11 @@ + + com.linecorp.armeria + armeria-grpc + ${armeria.version} + org.apache.httpcomponents httpcore diff --git a/oap-server/oal-grammar/src/main/antlr4/org/apache/skywalking/oal/rt/grammar/OALLexer.g4 b/oap-server/oal-grammar/src/main/antlr4/org/apache/skywalking/oal/rt/grammar/OALLexer.g4 index 6139cd181d3d..ea6eb5612c7a 100644 --- a/oap-server/oal-grammar/src/main/antlr4/org/apache/skywalking/oal/rt/grammar/OALLexer.g4 +++ b/oap-server/oal-grammar/src/main/antlr4/org/apache/skywalking/oal/rt/grammar/OALLexer.g4 @@ -58,6 +58,12 @@ SRC_K8S_ENDPOINT: 'K8SEndpoint'; SRC_K8S_SERVICE_RELATION: 'K8SServiceRelation'; SRC_K8S_SERVICE_INSTANCE_RELATION: 'K8SServiceInstanceRelation'; SRC_K8S_ENDPOINT_RELATION: 'K8SEndpointRelation'; +SRC_CILIUM_SERVICE: 'CiliumService'; +SRC_CILIUM_SERVICE_INSTANCE: 'CiliumServiceInstance'; +SRC_CILIUM_ENDPOINT: 'CiliumEndpoint'; +SRC_CILIUM_SERVICE_RELATION: 'CiliumServiceRelation'; +SRC_CILIUM_SERVICE_INSTANCE_RELATION: 'CiliumServiceInstanceRelation'; +SRC_CILIUM_ENDPOINT_RELATION: 'CiliumEndpointRelation'; // Browser keywords diff --git a/oap-server/oal-grammar/src/main/antlr4/org/apache/skywalking/oal/rt/grammar/OALParser.g4 b/oap-server/oal-grammar/src/main/antlr4/org/apache/skywalking/oal/rt/grammar/OALParser.g4 index fdab8d4ff0cd..153d0c1f8462 100644 --- a/oap-server/oal-grammar/src/main/antlr4/org/apache/skywalking/oal/rt/grammar/OALParser.g4 +++ b/oap-server/oal-grammar/src/main/antlr4/org/apache/skywalking/oal/rt/grammar/OALParser.g4 @@ -58,7 +58,8 @@ source SRC_BROWSER_APP_PERF | SRC_BROWSER_APP_PAGE_PERF | SRC_BROWSER_APP_SINGLE_VERSION_PERF | SRC_BROWSER_APP_TRAFFIC | SRC_BROWSER_APP_PAGE_TRAFFIC | SRC_BROWSER_APP_SINGLE_VERSION_TRAFFIC | SRC_EVENT | SRC_MQ_ACCESS | SRC_MQ_ENDPOINT_ACCESS | - SRC_K8S_SERVICE | SRC_K8S_SERVICE_INSTANCE | SRC_K8S_ENDPOINT | SRC_K8S_SERVICE_RELATION | SRC_K8S_SERVICE_INSTANCE_RELATION | SRC_K8S_ENDPOINT_RELATION + SRC_K8S_SERVICE | SRC_K8S_SERVICE_INSTANCE | SRC_K8S_ENDPOINT | SRC_K8S_SERVICE_RELATION | SRC_K8S_SERVICE_INSTANCE_RELATION | SRC_K8S_ENDPOINT_RELATION | + SRC_CILIUM_SERVICE | SRC_CILIUM_SERVICE_INSTANCE | SRC_CILIUM_ENDPOINT | SRC_CILIUM_SERVICE_RELATION | SRC_CILIUM_SERVICE_INSTANCE_RELATION | SRC_CILIUM_ENDPOINT_RELATION ; disableSource diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Layer.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Layer.java index fd77ac782f74..0f9b6b8f80ec 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Layer.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Layer.java @@ -228,7 +228,13 @@ public enum Layer { /** * ActiveMQ is a popular open source, multi-protocol, Java-based message broker. */ - ACTIVEMQ(37, true); + ACTIVEMQ(37, true), + + /** + * Cilium is open source software for providing and transparently securing network connectivity and load balancing + * between application workloads such as application containers or processes. + */ + CILIUM_SERVICE(38, true); private final int value; /** diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/endpoint/HubbleEndpointDispatcher.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/endpoint/HubbleEndpointDispatcher.java new file mode 100644 index 000000000000..d7abf0898b3a --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/endpoint/HubbleEndpointDispatcher.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.analysis.manual.endpoint; + +import org.apache.skywalking.oap.server.core.analysis.SourceDispatcher; +import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor; +import org.apache.skywalking.oap.server.core.source.CiliumEndpoint; + +public class HubbleEndpointDispatcher implements SourceDispatcher { + @Override + public void dispatch(CiliumEndpoint source) { + final EndpointTraffic traffic = new EndpointTraffic(); + traffic.setTimeBucket(source.getTimeBucket()); + traffic.setName(source.getEndpointName()); + traffic.setServiceId(source.getServiceId()); + MetricsStreamProcessor.getInstance().in(traffic); + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/instance/HubbleInstanceTrafficDispatcher.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/instance/HubbleInstanceTrafficDispatcher.java new file mode 100644 index 000000000000..5273f68b33fa --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/instance/HubbleInstanceTrafficDispatcher.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.analysis.manual.instance; + +import org.apache.skywalking.oap.server.core.analysis.SourceDispatcher; +import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor; +import org.apache.skywalking.oap.server.core.source.CiliumServiceInstance; + +public class HubbleInstanceTrafficDispatcher implements SourceDispatcher { + @Override + public void dispatch(CiliumServiceInstance source) { + final InstanceTraffic traffic = new InstanceTraffic(); + traffic.setTimeBucket(source.getTimeBucket()); + traffic.setName(source.getServiceInstanceName()); + traffic.setServiceId(source.getServiceId()); + traffic.setLastPingTimestamp(source.getTimeBucket()); + MetricsStreamProcessor.getInstance().in(traffic); + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/endpoint/HubbleEndpointCallRelationDispatcher.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/endpoint/HubbleEndpointCallRelationDispatcher.java new file mode 100644 index 000000000000..99a693184362 --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/endpoint/HubbleEndpointCallRelationDispatcher.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.analysis.manual.relation.endpoint; + +import org.apache.skywalking.oap.server.core.analysis.SourceDispatcher; +import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor; +import org.apache.skywalking.oap.server.core.source.CiliumEndpointRelation; + +public class HubbleEndpointCallRelationDispatcher implements SourceDispatcher { + @Override + public void dispatch(CiliumEndpointRelation source) { + switch (source.getDetectPoint()) { + case SERVER: + serverSide(source); + break; + default: + } + } + + private void serverSide(CiliumEndpointRelation source) { + EndpointRelationServerSideMetrics metrics = new EndpointRelationServerSideMetrics(); + metrics.setTimeBucket(source.getTimeBucket()); + metrics.setSourceEndpoint(source.getSourceEndpointId()); + metrics.setDestEndpoint(source.getDestEndpointId()); + metrics.setComponentId(source.getComponentId()); + metrics.setEntityId(source.getEntityId()); + MetricsStreamProcessor.getInstance().in(metrics); + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/instance/HubbleServiceInstanceCallRelationDispatcher.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/instance/HubbleServiceInstanceCallRelationDispatcher.java new file mode 100644 index 000000000000..853065966185 --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/instance/HubbleServiceInstanceCallRelationDispatcher.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.analysis.manual.relation.instance; + +import org.apache.skywalking.oap.server.core.analysis.SourceDispatcher; +import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor; +import org.apache.skywalking.oap.server.core.source.CiliumServiceInstanceRelation; + +public class HubbleServiceInstanceCallRelationDispatcher implements SourceDispatcher { + @Override + public void dispatch(CiliumServiceInstanceRelation source) { + switch (source.getDetectPoint()) { + case SERVER: + serverSide(source); + break; + case CLIENT: + clientSide(source); + break; + } + } + + private void serverSide(CiliumServiceInstanceRelation source) { + ServiceInstanceRelationServerSideMetrics metrics = new ServiceInstanceRelationServerSideMetrics(); + metrics.setTimeBucket(source.getTimeBucket()); + metrics.setSourceServiceId(source.getSourceServiceId()); + metrics.setSourceServiceInstanceId(source.getSourceServiceInstanceId()); + metrics.setDestServiceId(source.getDestServiceId()); + metrics.setDestServiceInstanceId(source.getDestServiceInstanceId()); + metrics.setEntityId(source.getEntityId()); + MetricsStreamProcessor.getInstance().in(metrics); + } + + private void clientSide(CiliumServiceInstanceRelation source) { + ServiceInstanceRelationClientSideMetrics metrics = new ServiceInstanceRelationClientSideMetrics(); + metrics.setTimeBucket(source.getTimeBucket()); + metrics.setSourceServiceId(source.getSourceServiceId()); + metrics.setSourceServiceInstanceId(source.getSourceServiceInstanceId()); + metrics.setDestServiceId(source.getDestServiceId()); + metrics.setDestServiceInstanceId(source.getDestServiceInstanceId()); + metrics.setEntityId(source.getEntityId()); + MetricsStreamProcessor.getInstance().in(metrics); + } + +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/service/HubbleServiceCallRelationDispatcher.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/service/HubbleServiceCallRelationDispatcher.java new file mode 100644 index 000000000000..4be0b2a379c6 --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/service/HubbleServiceCallRelationDispatcher.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.analysis.manual.relation.service; + +import org.apache.skywalking.oap.server.core.analysis.SourceDispatcher; +import org.apache.skywalking.oap.server.core.analysis.metrics.IntList; +import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor; +import org.apache.skywalking.oap.server.core.source.CiliumServiceRelation; + +public class HubbleServiceCallRelationDispatcher implements SourceDispatcher { + @Override + public void dispatch(CiliumServiceRelation source) { + switch (source.getDetectPoint()) { + case SERVER: + serverSide(source); + break; + case CLIENT: + clientSide(source); + break; + } + } + + private void serverSide(CiliumServiceRelation source) { + final ServiceRelationServerSideMetrics metrics = new ServiceRelationServerSideMetrics(); + metrics.setTimeBucket(source.getTimeBucket()); + metrics.setSourceServiceId(source.getSourceServiceId()); + metrics.setDestServiceId(source.getDestServiceId()); + if (source.getComponentId() != 0) { + final IntList componentIds = metrics.getComponentIds(); + componentIds.add(source.getComponentId()); + } + metrics.setEntityId(source.getEntityId()); + MetricsStreamProcessor.getInstance().in(metrics); + } + + private void clientSide(CiliumServiceRelation source) { + ServiceRelationClientSideMetrics metrics = new ServiceRelationClientSideMetrics(); + metrics.setTimeBucket(source.getTimeBucket()); + metrics.setSourceServiceId(source.getSourceServiceId()); + metrics.setDestServiceId(source.getDestServiceId()); + if (source.getComponentId() != 0) { + final IntList componentIds = metrics.getComponentIds(); + componentIds.add(source.getComponentId()); + } + metrics.setEntityId(source.getEntityId()); + MetricsStreamProcessor.getInstance().in(metrics); + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/service/HubbleServiceTrafficDispatcher.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/service/HubbleServiceTrafficDispatcher.java new file mode 100644 index 000000000000..57f17780c2ed --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/service/HubbleServiceTrafficDispatcher.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.analysis.manual.service; + +import org.apache.skywalking.oap.server.core.analysis.SourceDispatcher; +import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor; +import org.apache.skywalking.oap.server.core.source.CiliumService; + +public class HubbleServiceTrafficDispatcher implements SourceDispatcher { + @Override + public void dispatch(CiliumService source) { + final ServiceTraffic traffic = new ServiceTraffic(); + traffic.setTimeBucket(source.getTimeBucket()); + traffic.setName(source.getServiceName()); + traffic.setLayer(source.getLayer()); + MetricsStreamProcessor.getInstance().in(traffic); + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/LabelCountMetrics.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/LabelCountMetrics.java new file mode 100644 index 000000000000..d433d9a14ea3 --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/LabelCountMetrics.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.analysis.metrics; + +import lombok.Getter; +import lombok.Setter; +import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.Arg; +import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.ConstOne; +import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.Entrance; +import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.MetricsFunction; +import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB; +import org.apache.skywalking.oap.server.core.storage.annotation.Column; +import org.apache.skywalking.oap.server.core.storage.annotation.ElasticSearch; + +@MetricsFunction(functionName = "labelCount") +public abstract class LabelCountMetrics extends Metrics implements LabeledValueHolder { + protected static final String DATASET = "dataset"; + protected static final String VALUE = "datatable_value"; + + protected static final String LABEL_NAME = "n"; + + @Getter + @Setter + @Column(name = DATASET, storageOnly = true) + @BanyanDB.MeasureField + private DataTable dataset; + + @Getter + @Setter + @Column(name = VALUE, dataType = Column.ValueDataType.LABELED_VALUE, storageOnly = true) + @ElasticSearch.Column(legacyName = "value") + @BanyanDB.MeasureField + private DataTable value; + + private boolean isCalculated; + + public LabelCountMetrics() { + this.dataset = new DataTable(30); + this.value = new DataTable(30); + } + + @Entrance + public final void combine(@Arg String label, @ConstOne long count) { + this.isCalculated = false; + this.dataset.valueAccumulation(label, count); + } + + @Override + public boolean combine(Metrics metrics) { + this.isCalculated = false; + final LabelCountMetrics labelCountMetrics = (LabelCountMetrics) metrics; + this.dataset.append(labelCountMetrics.dataset); + return true; + } + + @Override + public void calculate() { + if (isCalculated) { + return; + } + + // convert dataset to labeled value + for (String key : this.dataset.keys()) { + final DataLabel label = new DataLabel(); + label.put(LABEL_NAME, key); + this.value.put(label, this.dataset.get(key)); + } + } + + @Override + public DataTable getValue() { + return this.value; + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateInitializer.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateInitializer.java index b37c5828e9df..7c11cee66a6b 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateInitializer.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateInitializer.java @@ -75,6 +75,7 @@ public class UITemplateInitializer { Layer.ROCKETMQ.name(), Layer.CLICKHOUSE.name(), Layer.ACTIVEMQ.name(), + Layer.CILIUM_SERVICE.name(), "custom" }; private final UITemplateManagementService uiTemplateManagementService; diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumEndpoint.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumEndpoint.java new file mode 100644 index 000000000000..2b2b9762caf1 --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumEndpoint.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.source; + +import lombok.Data; +import org.apache.skywalking.oap.server.core.analysis.IDManager; +import org.apache.skywalking.oap.server.core.analysis.Layer; + +import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.ENDPOINT_CATALOG_NAME; +import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.CILIUM_ENDPOINT; + +@Data +@ScopeDeclaration(id = CILIUM_ENDPOINT, name = "CiliumEndpoint", catalog = ENDPOINT_CATALOG_NAME) +@ScopeDefaultColumn.VirtualColumnDefinition(fieldName = "entityId", columnName = "entity_id", isID = true, type = String.class) +public class CiliumEndpoint extends CiliumMetrics { + private volatile String entityId; + + private String serviceId; + private String serviceName; + private String endpointName; + public Layer layer; + + @Override + public int scope() { + return CILIUM_ENDPOINT; + } + + @Override + public void prepare() { + serviceId = IDManager.ServiceID.buildId(serviceName, layer.isNormal()); + entityId = IDManager.EndpointID.buildId(serviceId, endpointName); + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumEndpointRelation.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumEndpointRelation.java new file mode 100644 index 000000000000..62c5814671a1 --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumEndpointRelation.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.source; + +import lombok.Data; +import org.apache.skywalking.oap.server.core.analysis.IDManager; +import org.apache.skywalking.oap.server.core.analysis.Layer; + +import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.ENDPOINT_RELATION_CATALOG_NAME; +import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.CILIUM_ENDPOINT_REALATION; + +@Data +@ScopeDeclaration(id = CILIUM_ENDPOINT_REALATION, name = "CiliumEndpointRelation", catalog = ENDPOINT_RELATION_CATALOG_NAME) +@ScopeDefaultColumn.VirtualColumnDefinition(fieldName = "entityId", columnName = "entity_id", isID = true, type = String.class) +public class CiliumEndpointRelation extends CiliumMetrics { + private volatile String entityId; + + private String sourceServiceId; + private String sourceServiceName; + private String sourceEndpointId; + private String sourceEndpointName; + private Layer sourceLayer; + + private DetectPoint detectPoint; + private int componentId; + + private String destServiceId; + private String destServiceName; + private String destEndpointId; + private String destEndpointName; + private Layer destLayer; + + private boolean success; + private long duration; + + @Override + public int scope() { + return CILIUM_ENDPOINT_REALATION; + } + + @Override + public void prepare() { + sourceServiceId = IDManager.ServiceID.buildId(sourceServiceName, sourceLayer.isNormal()); + sourceEndpointId = IDManager.EndpointID.buildId(sourceServiceId, sourceEndpointName); + destServiceId = IDManager.ServiceID.buildId(destServiceName, destLayer.isNormal()); + destEndpointId = IDManager.EndpointID.buildId(destServiceId, destEndpointName); + + entityId = IDManager.EndpointID.buildRelationId(new IDManager.EndpointID.EndpointRelationDefine( + sourceServiceId, sourceEndpointName, destServiceId, destEndpointName + )); + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumMetrics.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumMetrics.java new file mode 100644 index 000000000000..8f2368dbefb2 --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumMetrics.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.source; + +import lombok.Data; + +@Data +public abstract class CiliumMetrics extends Source { + public static final String VERDICT_FORWARDED = "forwarded"; + public static final String VERDICT_DROPPED = "dropped"; + + public static final String TYPE_TCP = "tcp"; + public static final String TYPE_HTTP = "http"; + public static final String TYPE_DNS = "dns"; + public static final String TYPE_KAFKA = "kafka"; + + public static final String DIRECTION_INGRESS = "ingress"; + public static final String DIRECTION_EGRESS = "egress"; + + // Basic information + private String verdict; + private String type; + private String direction; + + // For Dropped Package Reason + private String dropReason; + + // For L7 metrics + private HTTPMetrics http; + private KafkaMetrics kafka; + private DNSMetrics dns; + private long duration; + private boolean success; + + @Data + public static class HTTPMetrics { + private String url; + private int code; + private String protocol; + private String method; + } + + @Data + public static class KafkaMetrics { + private int errorCode; + private String errorCodeString; + private int apiVersion; + private String apiKey; + private int correlationId; + private String topic; + } + + @Data + public static class DNSMetrics { + private String domain; + private String queryType; + private int rcode; + private String rcodeString; + private int ttl; + private int ipCount; + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumService.java new file mode 100644 index 000000000000..7518694142f4 --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumService.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.source; + +import lombok.Data; +import org.apache.skywalking.oap.server.core.analysis.IDManager; +import org.apache.skywalking.oap.server.core.analysis.Layer; + +import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.CILIUM_SERVICE; +import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.SERVICE_CATALOG_NAME; + +@Data +@ScopeDeclaration(id = CILIUM_SERVICE, name = "CiliumService", catalog = SERVICE_CATALOG_NAME) +@ScopeDefaultColumn.VirtualColumnDefinition(fieldName = "entityId", columnName = "entity_id", isID = true, type = String.class) +public class CiliumService extends CiliumMetrics { + private volatile String entityId; + + private String serviceName; + public Layer layer; + + private DetectPoint detectPoint; + + @Override + public int scope() { + return CILIUM_SERVICE; + } + + @Override + public void prepare() { + entityId = IDManager.ServiceID.buildId(serviceName, layer.isNormal()); + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumServiceInstance.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumServiceInstance.java new file mode 100644 index 000000000000..eb59938cbf98 --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumServiceInstance.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.source; + +import lombok.Data; +import org.apache.skywalking.oap.server.core.analysis.IDManager; +import org.apache.skywalking.oap.server.core.analysis.Layer; + +import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.CILIUM_SERVICE_INSTANCE; +import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.SERVICE_INSTANCE_CATALOG_NAME; + +@Data +@ScopeDeclaration(id = CILIUM_SERVICE_INSTANCE, name = "CiliumServiceInstance", catalog = SERVICE_INSTANCE_CATALOG_NAME) +@ScopeDefaultColumn.VirtualColumnDefinition(fieldName = "entityId", columnName = "entity_id", isID = true, type = String.class) +public class CiliumServiceInstance extends CiliumMetrics { + private volatile String entityId; + + private String serviceId; + private String serviceName; + private String serviceInstanceName; + public Layer layer; + + private DetectPoint detectPoint; + + @Override + public int scope() { + return CILIUM_SERVICE_INSTANCE; + } + + @Override + public void prepare() { + serviceId = IDManager.ServiceID.buildId(serviceName, layer.isNormal()); + entityId = IDManager.ServiceInstanceID.buildId(serviceId, serviceInstanceName); + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumServiceInstanceRelation.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumServiceInstanceRelation.java new file mode 100644 index 000000000000..ebfc66a3d58b --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumServiceInstanceRelation.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.source; + +import lombok.Data; +import org.apache.skywalking.oap.server.core.analysis.IDManager; +import org.apache.skywalking.oap.server.core.analysis.Layer; + +import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.CILIUM_SERVICE_INSTANCE_RELATION; +import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.SERVICE_INSTANCE_RELATION_CATALOG_NAME; + +@Data +@ScopeDeclaration(id = CILIUM_SERVICE_INSTANCE_RELATION, name = "CiliumServiceInstanceRelation", catalog = SERVICE_INSTANCE_RELATION_CATALOG_NAME) +@ScopeDefaultColumn.VirtualColumnDefinition(fieldName = "entityId", columnName = "entity_id", isID = true, type = String.class) +public class CiliumServiceInstanceRelation extends CiliumMetrics { + private volatile String entityId; + + private String sourceServiceId; + private String sourceServiceName; + private String sourceServiceInstanceId; + private String sourceServiceInstanceName; + private Layer sourceLayer; + + private DetectPoint detectPoint; + private int componentId; + + private String destServiceId; + private String destServiceName; + private String destServiceInstanceId; + private String destServiceInstanceName; + private Layer destLayer; + + @Override + public int scope() { + return CILIUM_SERVICE_INSTANCE_RELATION; + } + + @Override + public void prepare() { + sourceServiceId = IDManager.ServiceID.buildId(sourceServiceName, sourceLayer.isNormal()); + sourceServiceInstanceId = IDManager.ServiceInstanceID.buildId(sourceServiceId, sourceServiceInstanceName); + destServiceId = IDManager.ServiceID.buildId(destServiceName, destLayer.isNormal()); + destServiceInstanceId = IDManager.ServiceInstanceID.buildId(destServiceId, destServiceInstanceName); + + entityId = IDManager.ServiceInstanceID.buildRelationId( + new IDManager.ServiceInstanceID.ServiceInstanceRelationDefine( + sourceServiceInstanceId, + destServiceInstanceId + ) + ); + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumServiceRelation.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumServiceRelation.java new file mode 100644 index 000000000000..a6d02b306955 --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/CiliumServiceRelation.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.source; + +import lombok.Data; +import org.apache.skywalking.oap.server.core.analysis.IDManager; +import org.apache.skywalking.oap.server.core.analysis.Layer; + +import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.CILIUM_SERVICE_RELATION; +import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.SERVICE_RELATION_CATALOG_NAME; + +@Data +@ScopeDeclaration(id = CILIUM_SERVICE_RELATION, name = "CiliumServiceRelation", catalog = SERVICE_RELATION_CATALOG_NAME) +@ScopeDefaultColumn.VirtualColumnDefinition(fieldName = "entityId", columnName = "entity_id", isID = true, type = String.class) +public class CiliumServiceRelation extends CiliumMetrics { + private volatile String entityId; + + private String sourceServiceId; + private String sourceServiceName; + private Layer sourceLayer; + + private DetectPoint detectPoint; + private int componentId; + + private String destServiceId; + private String destServiceName; + private Layer destLayer; + + @Override + public int scope() { + return CILIUM_SERVICE_RELATION; + } + + @Override + public void prepare() { + sourceServiceId = IDManager.ServiceID.buildId(sourceServiceName, sourceLayer.isNormal()); + destServiceId = IDManager.ServiceID.buildId(destServiceName, destLayer.isNormal()); + + entityId = IDManager.ServiceID.buildRelationId( + new IDManager.ServiceID.ServiceRelationDefine( + sourceServiceId, + destServiceId + ) + ); + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/DefaultScopeDefine.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/DefaultScopeDefine.java index 9529354ca615..b7ea73c6ee8e 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/DefaultScopeDefine.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/DefaultScopeDefine.java @@ -137,6 +137,13 @@ public class DefaultScopeDefine { public static final int K8S_ENDPOINT = 76; public static final int K8S_ENDPOINT_REALATION = 77; + public static final int CILIUM_SERVICE = 78; + public static final int CILIUM_SERVICE_INSTANCE = 79; + public static final int CILIUM_SERVICE_RELATION = 80; + public static final int CILIUM_SERVICE_INSTANCE_RELATION = 81; + public static final int CILIUM_ENDPOINT = 82; + public static final int CILIUM_ENDPOINT_REALATION = 83; + /** * Catalog of scope, the metrics processor could use this to group all generated metrics by oal rt. */ diff --git a/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/pom.xml b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/pom.xml new file mode 100644 index 000000000000..ed3d60cb9a21 --- /dev/null +++ b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/pom.xml @@ -0,0 +1,53 @@ + + + + + + org.apache.skywalking + server-fetcher-plugin + 10.1.0-SNAPSHOT + + 4.0.0 + + cilium-fetcher-plugin + jar + + + + org.apache.skywalking + fetcher-proto + ${project.version} + + + org.apache.skywalking + skywalking-sharing-server-plugin + ${project.version} + + + org.apache.skywalking + library-module + ${project.version} + + + + com.linecorp.armeria + armeria-grpc + + + \ No newline at end of file diff --git a/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/CiliumFetcherConfig.java b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/CiliumFetcherConfig.java new file mode 100644 index 000000000000..bce193600fbb --- /dev/null +++ b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/CiliumFetcherConfig.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.fetcher.cilium; + +import lombok.Getter; +import org.apache.skywalking.oap.server.library.module.ModuleConfig; + +@Getter +public class CiliumFetcherConfig extends ModuleConfig { + private String peerHost; + private int peerPort; + private int fetchFailureRetrySecond; + private boolean sslConnection; + private String sslPrivateKeyFile; + private String sslCertChainFile; + private String sslCaFile; + private boolean convertClientAsServerTraffic; +} diff --git a/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/CiliumFetcherModule.java b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/CiliumFetcherModule.java new file mode 100644 index 000000000000..fc20782468d1 --- /dev/null +++ b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/CiliumFetcherModule.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.fetcher.cilium; + +import org.apache.skywalking.oap.server.library.module.ModuleDefine; + +public class CiliumFetcherModule extends ModuleDefine { + public static final String NAME = "cilium-fetcher"; + + public CiliumFetcherModule() { + super(NAME); + } + + @Override + public Class[] services() { + return new Class[0]; + } +} diff --git a/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/CiliumFetcherProvider.java b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/CiliumFetcherProvider.java new file mode 100644 index 000000000000..98ef2f9e82a7 --- /dev/null +++ b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/CiliumFetcherProvider.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.fetcher.cilium; + +import lombok.extern.slf4j.Slf4j; +import org.apache.skywalking.oap.server.core.CoreModule; +import org.apache.skywalking.oap.server.core.cluster.ClusterModule; +import org.apache.skywalking.oap.server.core.oal.rt.OALEngineLoaderService; +import org.apache.skywalking.oap.server.fetcher.cilium.handler.CiliumFlowListener; +import org.apache.skywalking.oap.server.fetcher.cilium.handler.ServiceMetadata; +import org.apache.skywalking.oap.server.fetcher.cilium.nodes.CiliumNodeManager; +import org.apache.skywalking.oap.server.fetcher.cilium.nodes.GrpcStubBuilder; +import org.apache.skywalking.oap.server.library.module.ModuleDefine; +import org.apache.skywalking.oap.server.library.module.ModuleProvider; +import org.apache.skywalking.oap.server.library.module.ModuleStartException; +import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedException; +import org.apache.skywalking.oap.server.library.util.FieldsHelper; + +@Slf4j +public class CiliumFetcherProvider extends ModuleProvider { + private CiliumFetcherConfig config; + + protected String fieldMappingFile = "metadata-service-mapping.yaml"; + + @Override + public String name() { + return "default"; + } + + @Override + public Class module() { + return CiliumFetcherModule.class; + } + + @Override + public ConfigCreator newConfigCreator() { + return new ConfigCreator() { + @Override + public Class type() { + return CiliumFetcherConfig.class; + } + + @Override + public void onInitialized(CiliumFetcherConfig initialized) { + config = initialized; + } + }; + } + + @Override + public void prepare() throws ServiceNotProvidedException, ModuleStartException { + } + + @Override + public void start() throws ServiceNotProvidedException, ModuleStartException { + // load official analysis + getManager().find(CoreModule.NAME) + .provider() + .getService(OALEngineLoaderService.class) + .load(CiliumOALDefine.INSTANCE); + try { + FieldsHelper.forClass(ServiceMetadata.class).init(fieldMappingFile); + } catch (Exception e) { + throw new ModuleStartException(e.getMessage(), e); + } + + final CiliumNodeManager ciliumNodeManager = new CiliumNodeManager(getManager(), new GrpcStubBuilder(config), config); + ciliumNodeManager.addListener(new CiliumFlowListener(getManager(), config)); + ciliumNodeManager.start(); + } + + @Override + public void notifyAfterCompleted() throws ServiceNotProvidedException, ModuleStartException { + + } + + @Override + public String[] requiredModules() { + return new String[]{ + CoreModule.NAME, ClusterModule.NAME + }; + } +} diff --git a/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/CiliumOALDefine.java b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/CiliumOALDefine.java new file mode 100644 index 000000000000..1ccdec63f2c6 --- /dev/null +++ b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/CiliumOALDefine.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.fetcher.cilium; + +import org.apache.skywalking.oap.server.core.oal.rt.OALDefine; + +public class CiliumOALDefine extends OALDefine { + + public static final CiliumOALDefine INSTANCE = new CiliumOALDefine(); + + private CiliumOALDefine() { + super( + "oal/cilium.oal", + "org.apache.skywalking.oap.server.core.source" + ); + } +} diff --git a/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/handler/CiliumFlowListener.java b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/handler/CiliumFlowListener.java new file mode 100644 index 000000000000..c5d9b2f2b3cd --- /dev/null +++ b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/handler/CiliumFlowListener.java @@ -0,0 +1,474 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.fetcher.cilium.handler; + +import com.google.protobuf.util.Timestamps; +import io.cilium.api.flow.DNS; +import io.cilium.api.flow.Endpoint; +import io.cilium.api.flow.Flow; +import io.cilium.api.flow.HTTP; +import io.cilium.api.flow.Kafka; +import io.cilium.api.flow.L7FlowType; +import io.cilium.api.flow.TrafficDirection; +import io.cilium.api.flow.Verdict; +import io.cilium.api.observer.GetFlowsRequest; +import io.cilium.api.observer.GetFlowsResponse; +import io.cilium.api.observer.ObserverGrpc; +import lombok.extern.slf4j.Slf4j; +import org.apache.skywalking.oap.server.core.CoreModule; +import org.apache.skywalking.oap.server.core.analysis.Layer; +import org.apache.skywalking.oap.server.core.analysis.TimeBucket; +import org.apache.skywalking.oap.server.core.source.DetectPoint; +import org.apache.skywalking.oap.server.core.source.CiliumEndpointRelation; +import org.apache.skywalking.oap.server.core.source.CiliumEndpoint; +import org.apache.skywalking.oap.server.core.source.CiliumMetrics; +import org.apache.skywalking.oap.server.core.source.CiliumServiceInstanceRelation; +import org.apache.skywalking.oap.server.core.source.CiliumServiceInstance; +import org.apache.skywalking.oap.server.core.source.CiliumService; +import org.apache.skywalking.oap.server.core.source.CiliumServiceRelation; +import org.apache.skywalking.oap.server.core.source.SourceReceiver; +import org.apache.skywalking.oap.server.fetcher.cilium.CiliumFetcherConfig; +import org.apache.skywalking.oap.server.fetcher.cilium.nodes.CiliumNode; +import org.apache.skywalking.oap.server.fetcher.cilium.nodes.CiliumNodeUpdateListener; +import org.apache.skywalking.oap.server.library.module.ModuleManager; +import org.apache.skywalking.oap.server.library.util.RunnableWithExceptionProtection; +import org.apache.skywalking.oap.server.library.util.StringUtil; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +@Slf4j +public class CiliumFlowListener implements CiliumNodeUpdateListener { + private static final Executor EXECUTOR = Executors.newCachedThreadPool(); + private final SourceReceiver sourceReceiver; + private final Integer retrySecond; + private final boolean convertClientAsServerTraffic; + + public static final Layer SERVICE_LAYER = Layer.CILIUM_SERVICE; + + public CiliumFlowListener(ModuleManager moduleManager, CiliumFetcherConfig config) { + this.sourceReceiver = moduleManager.find(CoreModule.NAME).provider().getService(SourceReceiver.class); + this.retrySecond = config.getFetchFailureRetrySecond(); + this.convertClientAsServerTraffic = config.isConvertClientAsServerTraffic(); + } + + @Override + public void onNodeAdded(CiliumNode node) { + final String address = node.getAddress(); + EXECUTOR.execute(new RunnableWithExceptionProtection(() -> { + final ObserverGrpc.ObserverBlockingStub stub = node.getObserverStub(); + if (stub == null) { + return; + } + final Iterator flows = stub.getFlows( + GetFlowsRequest.newBuilder().setSince(Timestamps.now()).setFollow(true).build()); + final Thread thread = Thread.currentThread(); + node.addingCloseable(thread::interrupt); + flows.forEachRemaining(flow -> { + switch (flow.getResponseTypesCase()) { + case FLOW: + log.debug("Detect flow data: address: {}, flow: {}", address, flow.getFlow()); + handleFlow(node, flow.getFlow()); + break; + case LOST_EVENTS: + log.warn("Detected lost events, address: {}, events: {}", address, flow.getLostEvents()); + break; + case NODE_STATUS: + log.debug("Detected node status, address: {}, status: {}", address, flow.getNodeStatus()); + break; + } + }); + }, t -> { + if (t instanceof InterruptedException || (t.getCause() != null && t.getCause() instanceof InterruptedException)) { + log.debug("detected the node have been closed: {}, stopping to get flows", node.getAddress()); + return; + } + log.error("Failed to fetch flows from Cilium node: {}, will retry after {} seconds.", node.getAddress(), this.retrySecond, t); + try { + TimeUnit.SECONDS.sleep(this.retrySecond); + } catch (InterruptedException e) { + log.error("Failed to sleep for {} seconds.", this.retrySecond, e); + return; + } + + onNodeAdded(node); + })); + } + + @Override + public void onNodeDelete(CiliumNode node) { + } + + protected void handleFlow(CiliumNode node, Flow flow) { + // if no source or no destination, then ignore this flow + if (shouldIgnoreFlow(node, flow)) { + return; + } + + flow = convertTraffic(node, flow); + + final ServiceMetadata sourceMetadata = new ServiceMetadata(flow.getSource()); + final ServiceMetadata destMetadata = new ServiceMetadata(flow.getDestination()); + DetectPoint detectPoint = parseDetectPoint(flow); + if (convertClientAsServerTraffic) { + // if the client traffic is converted as server traffic, then the detect point should be only be server side + detectPoint = DetectPoint.SERVER; + } + log.debug("ready to building cilium traffic from {}{} -> {}{}, flow: {}, type: {}", + detectPoint.equals(DetectPoint.CLIENT) ? "*" : "", + sourceMetadata.getServiceName(), + detectPoint.equals(DetectPoint.SERVER) ? "*" : "", + destMetadata.getServiceName(), parseDirectionString(flow), + flow.getType()); + + switch (flow.getType()) { + case L3_L4: + buildL34Metrics(node, flow, sourceMetadata, destMetadata, detectPoint); + break; + case L7: + buildL7Metrics(node, flow, sourceMetadata, destMetadata, detectPoint); + break; + } + } + + protected Flow convertTraffic(CiliumNode node, Flow flow) { + final Flow.Builder builder = flow.toBuilder(); + // if the flow is reply traffic + if (flow.getIsReply().getValue()) { + // need to convert the traffic direction + // the reply flow traffic is opposite to the original flow + builder.setTrafficDirection(convertDirection(flow.getTrafficDirection())); + + // correct the source and destination + // when the flow is reply, the source and destination should be exchanged to the client -> server + final Endpoint source = flow.getSource(); + final Endpoint dest = flow.getDestination(); + builder.setSource(dest); + builder.setDestination(source); + } + + if (convertClientAsServerTraffic) { + // convert the traffic direction + builder.setTrafficDirection(convertDirection(builder.getTrafficDirection())); + } + + return builder.build(); + } + + protected TrafficDirection convertDirection(TrafficDirection direction) { + switch (direction) { + case INGRESS: + return TrafficDirection.EGRESS; + case EGRESS: + return TrafficDirection.INGRESS; + } + return direction; + } + + private void buildL34Metrics(CiliumNode node, Flow flow, ServiceMetadata sourceMetadata, ServiceMetadata destMetadata, DetectPoint detectPoint) { + ServiceMetadata currentService = detectPoint.equals(DetectPoint.CLIENT) ? sourceMetadata : destMetadata; + List metrics = Arrays.asList( + buildService(node, flow, currentService, detectPoint), buildServiceRelation(node, flow, sourceMetadata, destMetadata, detectPoint), + buildServiceInstance(node, flow, currentService, detectPoint), buildServiceInstanceRelation(node, flow, sourceMetadata, destMetadata, detectPoint)); + + metrics.forEach(metric -> { + setBasicInfo(metric, flow, CiliumMetrics.TYPE_TCP); + + sourceReceiver.receive(metric); + }); + } + + private void buildL7Metrics(CiliumNode node, Flow flow, ServiceMetadata sourceMetadata, ServiceMetadata destMetadata, DetectPoint detectPoint) { + switch (flow.getL7().getRecordCase()) { + case HTTP: + buildHttpMetrics(node, flow, sourceMetadata, destMetadata, detectPoint, flow.getL7().getHttp()); + break; + case DNS: + buildDnsMetrics(node, flow, sourceMetadata, destMetadata, detectPoint, flow.getL7().getDns()); + break; + case KAFKA: + buildKafkaMetrics(node, flow, sourceMetadata, destMetadata, detectPoint, flow.getL7().getKafka()); + break; + } + } + + private void buildKafkaMetrics(CiliumNode node, Flow flow, ServiceMetadata sourceMetadata, ServiceMetadata destMetadata, DetectPoint detectPoint, Kafka kafka) { + // only acknowledge the response flow + if (flow.getL7().getType() != L7FlowType.RESPONSE) { + return; + } + boolean success = kafka.getErrorCode() == 0; + String endpoint = "Kafka/" + kafka.getTopic() + "/" + kafka.getApiKey(); + List metrics = buildingL7Metrics(node, flow, sourceMetadata, destMetadata, detectPoint, endpoint); + + metrics.stream().filter(Objects::nonNull).forEach(metric -> { + setBasicInfo(metric, flow, CiliumMetrics.TYPE_KAFKA); + metric.setSuccess(success); + metric.setDuration(flow.getL7().getLatencyNs()); + + metric.setKafka(new CiliumMetrics.KafkaMetrics()); + metric.getKafka().setErrorCode(kafka.getErrorCode()); + metric.getKafka().setErrorCodeString(KafkaCodes.ERROR_CODES.getOrDefault(kafka.getErrorCode(), "UNKNOWN")); + metric.getKafka().setApiVersion(kafka.getApiVersion()); + metric.getKafka().setApiKey(kafka.getApiKey()); + metric.getKafka().setCorrelationId(kafka.getCorrelationId()); + metric.getKafka().setTopic(kafka.getTopic()); + + sourceReceiver.receive(metric); + }); + } + + private void buildDnsMetrics(CiliumNode node, Flow flow, ServiceMetadata sourceMetadata, ServiceMetadata destMetadata, DetectPoint detectPoint, DNS dns) { + // only acknowledge the response flow + if (flow.getL7().getType() != L7FlowType.RESPONSE) { + return; + } + boolean success = dns.getRcode() == 0; + String endpoint = "DNS/" + (dns.getQtypesCount() > 0 ? dns.getQtypesList().get(0) : "UNKNOWN"); + List metrics = buildingL7Metrics(node, flow, sourceMetadata, destMetadata, detectPoint, endpoint); + + metrics.stream().filter(Objects::nonNull).forEach(metric -> { + setBasicInfo(metric, flow, CiliumMetrics.TYPE_DNS); + metric.setSuccess(success); + metric.setDuration(flow.getL7().getLatencyNs()); + + metric.setDns(new CiliumMetrics.DNSMetrics()); + metric.getDns().setDomain(dns.getQuery()); + metric.getDns().setQueryType(dns.getQtypesCount() > 0 ? dns.getQtypesList().get(0) : "UNKNOWN"); + metric.getDns().setRcode(dns.getRcode()); + metric.getDns().setRcodeString(DNSCodes.RETURN_CODES.getOrDefault(dns.getRcode(), "UNKNOWN")); + metric.getDns().setTtl(dns.getTtl()); + metric.getDns().setIpCount(dns.getIpsCount()); + + sourceReceiver.receive(metric); + }); + } + + private void buildHttpMetrics(CiliumNode node, Flow flow, ServiceMetadata sourceMetadata, ServiceMetadata destMetadata, DetectPoint detectPoint, HTTP http) { + // if the http code is 0, then ignore this flow, it should be request + if (http.getCode() == 0) { + return; + } + final URL url; + try { + url = new URL(http.getUrl()); + } catch (MalformedURLException e) { + log.warn("Failed to parse the URL: {} from {} -> {}", http.getUrl(), + sourceMetadata.getServiceInstanceName(), destMetadata.getServiceInstanceName(), e); + return; + } + String endpointName = http.getMethod() + ":" + url.getPath(); + final boolean httpSuccess = parseHTTPSuccess(flow, http); + List metrics = buildingL7Metrics(node, flow, sourceMetadata, destMetadata, detectPoint, endpointName); + + metrics.stream().filter(Objects::nonNull).forEach(metric -> { + setBasicInfo(metric, flow, CiliumMetrics.TYPE_HTTP); + metric.setSuccess(httpSuccess); + metric.setDuration(flow.getL7().getLatencyNs()); + + metric.setHttp(new CiliumMetrics.HTTPMetrics()); + metric.getHttp().setUrl(http.getUrl()); + metric.getHttp().setCode(http.getCode()); + metric.getHttp().setProtocol(http.getProtocol()); + metric.getHttp().setMethod(http.getMethod()); + + sourceReceiver.receive(metric); + }); + } + + private List buildingL7Metrics(CiliumNode node, Flow flow, ServiceMetadata sourceMetadata, ServiceMetadata destMetadata, DetectPoint detectPoint, String endpointName) { + ServiceMetadata currentService = detectPoint.equals(DetectPoint.CLIENT) ? sourceMetadata : destMetadata; + return Arrays.asList( + buildService(node, flow, currentService, detectPoint), buildServiceRelation(node, flow, sourceMetadata, destMetadata, detectPoint), + buildServiceInstance(node, flow, currentService, detectPoint), buildServiceInstanceRelation(node, flow, sourceMetadata, destMetadata, detectPoint), + buildEndpoint(node, flow, currentService, endpointName, detectPoint), buildEndpointRelation(node, flow, sourceMetadata, destMetadata, detectPoint, endpointName) + ); + } + + private void setBasicInfo(CiliumMetrics metric, Flow flow, String type) { + metric.setVerdict(parseVerdictString(flow)); + metric.setType(type); + metric.setDirection(parseDirectionString(flow)); + metric.setTimeBucket(TimeBucket.getMinuteTimeBucket(flow.getTime().getSeconds() * 1000)); + if (Verdict.DROPPED.equals(flow.getVerdict())) { + metric.setDropReason(flow.getDropReasonDesc().toString()); + } + } + + protected boolean shouldIgnoreEndpoint(Endpoint endpoint) { + if (endpoint.getID() != 0) { + return false; + } + + return StringUtil.isEmpty(endpoint.getPodName()) || StringUtil.isEmpty(endpoint.getNamespace()); + } + + protected boolean shouldIgnoreFlow(CiliumNode node, Flow flow) { + // must have source and destination + if (!flow.hasSource() || !flow.hasDestination()) { + return true; + } + // if the source and destination or not set, then ignore this flow + if (shouldIgnoreEndpoint(flow.getSource()) || shouldIgnoreEndpoint(flow.getDestination())) { + return true; + } + // only acknowledge the flows is forwarded or dropped + switch (flow.getVerdict()) { + case FORWARDED: + case DROPPED: + break; + default: + return true; + } + // traffic direction must be set + if (flow.getTrafficDirection() == TrafficDirection.TRAFFIC_DIRECTION_UNKNOWN) { + return true; + } + // flow type is only support for L3, L4 and L7 + switch (flow.getType()) { + case L3_L4: + case L7: break; + default: return true; + } + // ignore the client traffic if we convert the client as server traffic + if (this.convertClientAsServerTraffic && DetectPoint.SERVER.equals(parseDetectPoint(flow))) { + return true; + } + return false; + } + + private String parseVerdictString(Flow flow) { + switch (flow.getVerdict()) { + case FORWARDED: + return CiliumMetrics.VERDICT_FORWARDED; + case DROPPED: + return CiliumMetrics.VERDICT_DROPPED; + } + return ""; + } + + private String parseDirectionString(Flow flow) { + switch (flow.getTrafficDirection()) { + case INGRESS: + return CiliumMetrics.DIRECTION_INGRESS; + case EGRESS: + return CiliumMetrics.DIRECTION_EGRESS; + } + return ""; + } + + protected CiliumMetrics buildService(CiliumNode node, Flow flow, ServiceMetadata metadata, DetectPoint detectPoint) { + final CiliumService service = new CiliumService(); + service.setServiceName(metadata.getServiceName()); + service.setLayer(SERVICE_LAYER); + service.setDetectPoint(detectPoint); + return service; + } + + protected CiliumMetrics buildServiceRelation(CiliumNode node, Flow flow, ServiceMetadata source, ServiceMetadata dest, DetectPoint detectPoint) { + final CiliumServiceRelation serviceRelation = new CiliumServiceRelation(); + serviceRelation.setSourceServiceName(source.getServiceName()); + serviceRelation.setSourceLayer(SERVICE_LAYER); + serviceRelation.setDestServiceName(dest.getServiceName()); + serviceRelation.setDestLayer(SERVICE_LAYER); + serviceRelation.setDetectPoint(detectPoint); + serviceRelation.setComponentId(parseComponentId(flow)); + return serviceRelation; + } + + protected CiliumMetrics buildServiceInstance(CiliumNode node, Flow flow, ServiceMetadata metadata, DetectPoint detectPoint) { + final CiliumServiceInstance serviceInstance = new CiliumServiceInstance(); + serviceInstance.setServiceName(metadata.getServiceName()); + serviceInstance.setServiceInstanceName(metadata.getServiceInstanceName()); + serviceInstance.setLayer(SERVICE_LAYER); + serviceInstance.setDetectPoint(detectPoint); + return serviceInstance; + } + + protected CiliumMetrics buildServiceInstanceRelation(CiliumNode node, Flow flow, ServiceMetadata source, ServiceMetadata dest, DetectPoint detectPoint) { + final CiliumServiceInstanceRelation serviceInstanceRelation = new CiliumServiceInstanceRelation(); + serviceInstanceRelation.setSourceServiceName(source.getServiceName()); + serviceInstanceRelation.setSourceServiceInstanceName(source.getServiceInstanceName()); + serviceInstanceRelation.setSourceLayer(SERVICE_LAYER); + serviceInstanceRelation.setDestServiceName(dest.getServiceName()); + serviceInstanceRelation.setDestServiceInstanceName(dest.getServiceInstanceName()); + serviceInstanceRelation.setDestLayer(SERVICE_LAYER); + serviceInstanceRelation.setDetectPoint(detectPoint); + serviceInstanceRelation.setComponentId(parseComponentId(flow)); + return serviceInstanceRelation; + } + + protected CiliumMetrics buildEndpoint(CiliumNode node, Flow flow, ServiceMetadata source, String endpointName, DetectPoint detectPoint) { + if (DetectPoint.CLIENT.equals(detectPoint)) { + return null; + } + final CiliumEndpoint endpoint = new CiliumEndpoint(); + endpoint.setServiceName(source.getServiceName()); + endpoint.setEndpointName(endpointName); + endpoint.setLayer(SERVICE_LAYER); + return endpoint; + } + + protected CiliumMetrics buildEndpointRelation(CiliumNode node, Flow flow, ServiceMetadata source, ServiceMetadata dest, + DetectPoint detectPoint, String endpointName) { + final CiliumEndpointRelation endpointRelation = new CiliumEndpointRelation(); + endpointRelation.setSourceServiceName(source.getServiceName()); + endpointRelation.setSourceEndpointName(endpointName); + endpointRelation.setSourceLayer(SERVICE_LAYER); + endpointRelation.setDestServiceName(dest.getServiceName()); + endpointRelation.setDestEndpointName(endpointName); + endpointRelation.setDestLayer(SERVICE_LAYER); + endpointRelation.setDetectPoint(detectPoint); + return endpointRelation; + } + + protected boolean parseHTTPSuccess(Flow flow, HTTP http) { + return http.getCode() < 500; + } + + private DetectPoint parseDetectPoint(Flow flow) { + boolean isReply = flow.getIsReply().getValue(); + if (!isReply) { + return flow.getSource().getID() != 0 ? DetectPoint.CLIENT : DetectPoint.SERVER; + } + return flow.getDestination().getID() != 0 ? DetectPoint.CLIENT : DetectPoint.SERVER; + } + + private int parseComponentId(Flow flow) { + switch (flow.getType()) { + case L3_L4: + return 110; // For the L3/L4 flow, just use the TCP component + case L7: + switch (flow.getL7().getRecordCase()) { + case HTTP: return 49; // HTTP + case DNS: return 159; // DNS + case KAFKA: return 27; // Kafka + } + } + return 0; + } + +} diff --git a/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/handler/DNSCodes.java b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/handler/DNSCodes.java new file mode 100644 index 000000000000..bf8a9955823e --- /dev/null +++ b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/handler/DNSCodes.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.fetcher.cilium.handler; + +import com.google.common.collect.ImmutableMap; + +import java.util.Map; + +public class DNSCodes { + + // Follow https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6 + public static final Map RETURN_CODES = ImmutableMap.builder() + .put(0, "NoError") + .put(1, "FormErr") + .put(2, "ServFail") + .put(3, "NXDomain") + .put(4, "NotImp") + .put(5, "Refused") + .put(6, "YXDomain") + .put(7, "YXRRSet") + .put(8, "NXRRSet") + .put(9, "NotAuth") + .put(10, "NotZone") + .put(11, "DSOTYPENI") + .put(16, "BADVERS|BADSIG") + .put(17, "BADKEY") + .put(18, "BADTIME") + .put(19, "BADMODE") + .put(20, "BADNAME") + .put(21, "BADALG") + .put(22, "BADTRUNC") + .put(23, "BADCOOKIE") + .build(); +} diff --git a/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/handler/KafkaCodes.java b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/handler/KafkaCodes.java new file mode 100644 index 000000000000..39e779b421bf --- /dev/null +++ b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/handler/KafkaCodes.java @@ -0,0 +1,151 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.fetcher.cilium.handler; + +import com.google.common.collect.ImmutableMap; + +import java.util.Map; + +public class KafkaCodes { + + // Follow https://kafka.apache.org/protocol#protocol_error_codes + public static final Map ERROR_CODES = ImmutableMap.builder() + .put(-1, "UNKNOWN_SERVER_ERROR") + .put(0, "NONE") + .put(1, "OFFSET_OUT_OF_RANGE") + .put(2, "CORRUPT_MESSAGE") + .put(3, "UNKNOWN_TOPIC_OR_PARTITION") + .put(4, "INVALID_FETCH_SIZE") + .put(5, "LEADER_NOT_AVAILABLE") + .put(6, "NOT_LEADER_OR_FOLLOWER") + .put(7, "REQUEST_TIMED_OUT") + .put(8, "BROKER_NOT_AVAILABLE") + .put(9, "REPLICA_NOT_AVAILABLE") + .put(10, "MESSAGE_TOO_LARGE") + .put(11, "STALE_CONTROLLER_EPOCH") + .put(12, "OFFSET_METADATA_TOO_LARGE") + .put(13, "NETWORK_EXCEPTION") + .put(14, "COORDINATOR_LOAD_IN_PROGRESS") + .put(15, "COORDINATOR_NOT_AVAILABLE") + .put(16, "NOT_COORDINATOR") + .put(17, "INVALID_TOPIC_EXCEPTION") + .put(18, "RECORD_LIST_TOO_LARGE") + .put(19, "NOT_ENOUGH_REPLICAS") + .put(20, "NOT_ENOUGH_REPLICAS_AFTER_APPEND") + .put(21, "INVALID_REQUIRED_ACKS") + .put(22, "ILLEGAL_GENERATION") + .put(23, "INCONSISTENT_GROUP_PROTOCOL") + .put(24, "INVALID_GROUP_ID") + .put(25, "UNKNOWN_MEMBER_ID") + .put(26, "INVALID_SESSION_TIMEOUT") + .put(27, "REBALANCE_IN_PROGRESS") + .put(28, "INVALID_COMMIT_OFFSET_SIZE") + .put(29, "TOPIC_AUTHORIZATION_FAILED") + .put(30, "GROUP_AUTHORIZATION_FAILED") + .put(31, "CLUSTER_AUTHORIZATION_FAILED") + .put(32, "INVALID_TIMESTAMP") + .put(33, "UNSUPPORTED_SASL_MECHANISM") + .put(34, "ILLEGAL_SASL_STATE") + .put(35, "UNSUPPORTED_VERSION") + .put(36, "TOPIC_ALREADY_EXISTS") + .put(37, "INVALID_PARTITIONS") + .put(38, "INVALID_REPLICATION_FACTOR") + .put(39, "INVALID_REPLICA_ASSIGNMENT") + .put(40, "INVALID_CONFIG") + .put(41, "NOT_CONTROLLER") + .put(42, "INVALID_REQUEST") + .put(43, "UNSUPPORTED_FOR_MESSAGE_FORMAT") + .put(44, "POLICY_VIOLATION") + .put(45, "OUT_OF_ORDER_SEQUENCE_NUMBER") + .put(46, "DUPLICATE_SEQUENCE_NUMBER") + .put(47, "INVALID_PRODUCER_EPOCH") + .put(48, "INVALID_TXN_STATE") + .put(49, "INVALID_PRODUCER_ID_MAPPING") + .put(50, "INVALID_TRANSACTION_TIMEOUT") + .put(51, "CONCURRENT_TRANSACTIONS") + .put(52, "TRANSACTION_COORDINATOR_FENCED") + .put(53, "TRANSACTIONAL_ID_AUTHORIZATION_FAILED") + .put(54, "SECURITY_DISABLED") + .put(55, "OPERATION_NOT_ATTEMPTED") + .put(56, "KAFKA_STORAGE_ERROR") + .put(57, "LOG_DIR_NOT_FOUND") + .put(58, "SASL_AUTHENTICATION_FAILED") + .put(59, "UNKNOWN_PRODUCER_ID") + .put(60, "REASSIGNMENT_IN_PROGRESS") + .put(61, "DELEGATION_TOKEN_AUTH_DISABLED") + .put(62, "DELEGATION_TOKEN_NOT_FOUND") + .put(63, "DELEGATION_TOKEN_OWNER_MISMATCH") + .put(64, "DELEGATION_TOKEN_REQUEST_NOT_ALLOWED") + .put(65, "DELEGATION_TOKEN_AUTHORIZATION_FAILED") + .put(66, "DELEGATION_TOKEN_EXPIRED") + .put(67, "INVALID_PRINCIPAL_TYPE") + .put(68, "NON_EMPTY_GROUP") + .put(69, "GROUP_ID_NOT_FOUND") + .put(70, "FETCH_SESSION_ID_NOT_FOUND") + .put(71, "INVALID_FETCH_SESSION_EPOCH") + .put(72, "LISTENER_NOT_FOUND") + .put(73, "TOPIC_DELETION_DISABLED") + .put(74, "FENCED_LEADER_EPOCH") + .put(75, "UNKNOWN_LEADER_EPOCH") + .put(76, "UNSUPPORTED_COMPRESSION_TYPE") + .put(77, "STALE_BROKER_EPOCH") + .put(78, "OFFSET_NOT_AVAILABLE") + .put(79, "MEMBER_ID_REQUIRED") + .put(80, "PREFERRED_LEADER_NOT_AVAILABLE") + .put(81, "GROUP_MAX_SIZE_REACHED") + .put(82, "FENCED_INSTANCE_ID") + .put(83, "ELIGIBLE_LEADERS_NOT_AVAILABLE") + .put(84, "ELECTION_NOT_NEEDED") + .put(85, "NO_REASSIGNMENT_IN_PROGRESS") + .put(86, "GROUP_SUBSCRIBED_TO_TOPIC") + .put(87, "INVALID_RECORD") + .put(88, "UNSTABLE_OFFSET_COMMIT") + .put(89, "THROTTLING_QUOTA_EXCEEDED") + .put(90, "PRODUCER_FENCED") + .put(91, "RESOURCE_NOT_FOUND") + .put(92, "DUPLICATE_RESOURCE") + .put(93, "UNACCEPTABLE_CREDENTIAL") + .put(94, "INCONSISTENT_VOTER_SET") + .put(95, "INVALID_UPDATE_VERSION") + .put(96, "FEATURE_UPDATE_FAILED") + .put(97, "PRINCIPAL_DESERIALIZATION_FAILURE") + .put(98, "SNAPSHOT_NOT_FOUND") + .put(99, "POSITION_OUT_OF_RANGE") + .put(100, "UNKNOWN_TOPIC_ID") + .put(101, "DUPLICATE_BROKER_REGISTRATION") + .put(102, "BROKER_ID_NOT_REGISTERED") + .put(103, "INCONSISTENT_TOPIC_ID") + .put(104, "INCONSISTENT_CLUSTER_ID") + .put(105, "TRANSACTIONAL_ID_NOT_FOUND") + .put(106, "FETCH_SESSION_TOPIC_ID_ERROR") + .put(107, "INELIGIBLE_REPLICA") + .put(108, "NEW_LEADER_ELECTED") + .put(109, "OFFSET_MOVED_TO_TIERED_STORAGE") + .put(110, "FENCED_MEMBER_EPOCH") + .put(111, "UNRELEASED_INSTANCE_ID") + .put(112, "UNSUPPORTED_ASSIGNOR") + .put(113, "STALE_MEMBER_EPOCH") + .put(114, "MISMATCHED_ENDPOINT_TYPE") + .put(115, "UNSUPPORTED_ENDPOINT_TYPE") + .put(116, "UNKNOWN_CONTROLLER_ID") + .put(117, "UNKNOWN_SUBSCRIPTION_ID") + .put(118, "TELEMETRY_TOO_LARGE") + .put(119, "INVALID_REGISTRATION") + .build(); +} diff --git a/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/handler/ServiceMetadata.java b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/handler/ServiceMetadata.java new file mode 100644 index 000000000000..d7548578488f --- /dev/null +++ b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/handler/ServiceMetadata.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.fetcher.cilium.handler; + +import com.google.protobuf.Struct; +import com.google.protobuf.Value; +import io.cilium.api.flow.Endpoint; +import io.vavr.Tuple; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import org.apache.skywalking.oap.server.library.util.FieldsHelper; + +@Getter +@Setter +@ToString +@NoArgsConstructor +@EqualsAndHashCode(onlyExplicitlyIncluded = true) +public class ServiceMetadata { + @EqualsAndHashCode.Include + private String serviceName; + @EqualsAndHashCode.Include + private String serviceInstanceName; + + public ServiceMetadata(Endpoint endpoint) { + FieldsHelper.forClass(this.getClass()).inflate(parseEndpointToStruct(endpoint), this); + } + + private Struct parseEndpointToStruct(Endpoint endpoint) { + final Struct.Builder builder = Struct.newBuilder(); + + // Convert Labels + final Struct.Builder labelsStruct = Struct.newBuilder(); + endpoint.getLabelsList().stream() + .map(label -> label.split("=", 2)) + .forEach(split -> { + if (split.length == 1) { + addingLabel(labelsStruct, split[0], ""); + return; + } + addingLabel(labelsStruct, split[0], split[1]); + }); + builder.putFields("LABELS", Value.newBuilder().setStructValue(labelsStruct.build()).build()); + + // Convert Workloads + final Struct.Builder workloadsStruct = Struct.newBuilder(); + endpoint.getWorkloadsList().stream() + .map(workload -> Tuple.of(workload.getKind(), workload.getName())) + .forEach(split -> { + workloadsStruct.putFields(split._1, Value.newBuilder().setStringValue(split._2).build()); + }); + builder.putFields("WORKLOADS", Value.newBuilder().setStructValue(workloadsStruct.build()).build()); + + // Adding other metadata + builder.putFields("NAMESPACE", Value.newBuilder().setStringValue(endpoint.getNamespace()).build()); + builder.putFields("NAME", Value.newBuilder().setStringValue(endpoint.getPodName()).build()); + + return builder.build(); + } + + private void addingLabel(Struct.Builder builder, String key, String value) { + final Value val = Value.newBuilder().setStringValue(value).build(); + builder.putFields(key, val); + // remove the prefix "k8s:" from the key + if (key.indexOf("k8s:") == 0) { + builder.putFields(key.substring(4), val); + } + } +} diff --git a/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/CiliumNode.java b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/CiliumNode.java new file mode 100644 index 000000000000..7a79f2e775cf --- /dev/null +++ b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/CiliumNode.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.fetcher.cilium.nodes; + +import io.cilium.api.observer.ObserverGrpc; +import io.vavr.Tuple2; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; + +import java.io.Closeable; +import java.util.Objects; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * CiliumNode represents a node in the Cilium cluster. + * Usually it's aware by the Cilium Peer Service. + */ +@RequiredArgsConstructor +@Getter +@Slf4j +@EqualsAndHashCode(of = { + "address" +}) +@ToString(of = { + "address", + "connected" +}) +public class CiliumNode { + private final String address; + private final ClientBuilder clientBuilder; + + private volatile ObserverGrpc.ObserverBlockingStub observerStub; + private volatile boolean closed; + private final CopyOnWriteArrayList closeables = new CopyOnWriteArrayList<>(); + + public ObserverGrpc.ObserverBlockingStub getObserverStub() { + if (closed) { + return null; + } + if (Objects.nonNull(observerStub)) { + return observerStub; + } + + synchronized (this) { + if (Objects.isNull(observerStub)) { + final Tuple2 addressTuple = parseAddress(); + observerStub = clientBuilder.buildClient(addressTuple._1, addressTuple._2, ObserverGrpc.ObserverBlockingStub.class); + } + } + return observerStub; + } + + public void addingCloseable(Closeable closeable) { + closeables.add(closeable); + } + + public void close() { + this.closed = true; + closeables.forEach(c -> { + try { + c.close(); + } catch (Exception e) { + log.warn("Failed to close the cilium node", e); + } + }); + } + + private Tuple2 parseAddress() { + String[] parts = address.split(":"); + if (parts.length != 2) { + return new Tuple2<>(address, 4244); + } + return new Tuple2<>(parts[0], Integer.parseInt(parts[1])); + } +} diff --git a/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/CiliumNodeManager.java b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/CiliumNodeManager.java new file mode 100644 index 000000000000..e5068fd2bbb2 --- /dev/null +++ b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/CiliumNodeManager.java @@ -0,0 +1,311 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.fetcher.cilium.nodes; + +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Sets; +import io.cilium.api.peer.NotifyRequest; +import io.cilium.api.peer.PeerGrpc; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.apache.log4j.helpers.LogLog; +import org.apache.skywalking.oap.server.core.cluster.ClusterCoordinator; +import org.apache.skywalking.oap.server.core.cluster.ClusterModule; +import org.apache.skywalking.oap.server.core.cluster.ClusterNodesQuery; +import org.apache.skywalking.oap.server.core.cluster.ClusterWatcher; +import org.apache.skywalking.oap.server.core.cluster.RemoteInstance; +import org.apache.skywalking.oap.server.fetcher.cilium.CiliumFetcherConfig; +import org.apache.skywalking.oap.server.library.module.ModuleManager; +import org.apache.skywalking.oap.server.library.util.CollectionUtils; +import org.apache.skywalking.oap.server.library.util.RunnableWithExceptionProtection; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +@Slf4j +public class CiliumNodeManager implements ClusterWatcher { + private static final Executor EXECUTOR = Executors.newCachedThreadPool(); + + private final PeerGrpc.PeerBlockingStub peerStub; + private final ClientBuilder clientBuilder; + private final ModuleManager moduleManager; + private final int retrySecond; + private volatile List remoteInstances; + private List listeners; + private ClusterNodesQuery clusterNodesQuery; + + // This is a list of all cilium nodes + private volatile List allNodes; + // This is a list of cilium nodes that are should be used in current OAP node + private volatile List usingNodes; + + public CiliumNodeManager(ModuleManager moduleManager, ClientBuilder clientBuilder, CiliumFetcherConfig config) { + this.moduleManager = moduleManager; + this.clientBuilder = clientBuilder; + this.peerStub = this.clientBuilder.buildClient(config.getPeerHost(), config.getPeerPort(), PeerGrpc.PeerBlockingStub.class); + this.allNodes = new ArrayList<>(); + this.usingNodes = new ArrayList<>(); + this.listeners = new ArrayList<>(); + this.retrySecond = config.getFetchFailureRetrySecond(); + } + + public void start() { + ClusterCoordinator coordinator = this.moduleManager + .find(ClusterModule.NAME) + .provider() + .getService(ClusterCoordinator.class); + coordinator.registerWatcher(this); + // init the remote instances + this.remoteInstances = ImmutableList.copyOf(coordinator.queryRemoteNodes()); + startWatchNodeUpdates(); + startRefreshRemoteNodes(); + } + + public void addListener(CiliumNodeUpdateListener listener) { + listeners.add(listener); + } + + private void listenNotified() { + peerStub.notify(NotifyRequest.newBuilder().build()) + .forEachRemaining(changeNotification -> { + log.debug("Receive cilium node change notification, name: {}, address: {}, type: {}", changeNotification.getName(), + changeNotification.getAddress(), changeNotification.getType()); + switch (changeNotification.getType()) { + case PEER_ADDED: + case PEER_UPDATED: + this.addOrUpdateNode(new CiliumNode(changeNotification.getAddress(), clientBuilder)); + break; + case PEER_DELETED: + this.removeNode(new CiliumNode(changeNotification.getAddress(), clientBuilder)); + break; + default: + log.error("Unknown cilium node change notification type: {}", changeNotification); + break; + } + }); + } + + private void startWatchNodeUpdates() { + EXECUTOR.execute(new RunnableWithExceptionProtection(this::listenNotified, t -> { + LogLog.error("Cilium node manager listen notified failure.", t); + try { + TimeUnit.SECONDS.sleep(this.retrySecond); + } catch (InterruptedException e) { + log.error("Failed to sleep for {} seconds.", this.retrySecond, e); + return; + } + + startWatchNodeUpdates(); + })); + } + + private void startRefreshRemoteNodes() { + Executors.newSingleThreadScheduledExecutor() + .scheduleWithFixedDelay(new RunnableWithExceptionProtection(this::refreshRemoteNodes, t -> log.error( + "Scheduled refresh Remote Clients failure.", t)), 1, 10, TimeUnit.SECONDS); + } + + private void refreshRemoteNodes() { + if (Objects.isNull(clusterNodesQuery)) { + this.clusterNodesQuery = moduleManager.find(ClusterModule.NAME) + .provider() + .getService(ClusterNodesQuery.class); + } + + this.onClusterNodesChanged(clusterNodesQuery.queryRemoteNodes()); + } + + private void addOrUpdateNode(CiliumNode node) { + if (allNodes.contains(node)) { + allNodes.remove(node); + } + allNodes.add(node); + this.refreshUsingNodes(); + } + + private void removeNode(CiliumNode node) { + allNodes.remove(node); + this.refreshUsingNodes(); + } + + void refreshUsingNodes() { + final List shouldUsingNodes = buildShouldUsingNodes(); + log.debug("Trying to rebuilding using cilium nodes, current using nodes count: {}, new using nodes count: {}", + usingNodes.size(), shouldUsingNodes.size()); + + if (log.isDebugEnabled()) { + shouldUsingNodes.forEach(node -> log.debug("Ready to using cilium node, wait notify: {}", node.getAddress())); + } + + if (!compare(shouldUsingNodes)) { + log.info("Rebuilding using cilium nodes, old using nodes count: {}, new using nodes count: {}", + usingNodes.size(), shouldUsingNodes.size()); + this.reBuildUsingNodes(shouldUsingNodes); + } else { + log.debug("No need to rebuild using cilium nodes, old using nodes count: {}, new using nodes count: {}", + usingNodes.size(), shouldUsingNodes.size()); + } + } + + private void reBuildUsingNodes(List shouldUsingNodes) { + final Map remoteClientCollection = + this.usingNodes.stream() + .collect(Collectors.toMap( + CiliumNode::getAddress, + node -> new NodeWithAction( + node, Action.Close) + )); + + final Map latestRemoteClients = + shouldUsingNodes.stream() + .collect(Collectors.toMap( + CiliumNode::getAddress, + remote -> new NodeWithAction( + remote, Action.Create) + )); + + final Set unChangeAddresses = Sets.intersection( + remoteClientCollection.keySet(), latestRemoteClients.keySet()); + + unChangeAddresses.stream() + .filter(remoteClientCollection::containsKey) + .forEach(unChangeAddress -> remoteClientCollection.get(unChangeAddress) + .setAction(Action.Unchanged)); + + // make the latestRemoteClients including the new clients only + unChangeAddresses.forEach(latestRemoteClients::remove); + remoteClientCollection.putAll(latestRemoteClients); + + final List newNodes = new LinkedList<>(); + remoteClientCollection.forEach((address, clientAction) -> { + switch (clientAction.getAction()) { + case Unchanged: + newNodes.add(clientAction.getNode()); + break; + case Create: + newNodes.add(clientAction.getNode()); + notifyListeners(clientAction.getNode(), Action.Create); + break; + case Close: + notifyListeners(clientAction.getNode(), Action.Close); + clientAction.getNode().close(); + break; + } + }); + + this.usingNodes = ImmutableList.copyOf(newNodes); + } + + private void notifyListeners(CiliumNode node, Action action) { + listeners.forEach(listener -> { + if (action == Action.Create) { + listener.onNodeAdded(node); + } else if (action == Action.Close) { + listener.onNodeDelete(node); + } + }); + } + + private void printUsingNodesList() { + if (!log.isDebugEnabled()) { + return; + } + final String addresses = Joiner.on(", ").join(usingNodes.stream().map(CiliumNode::getAddress).collect(Collectors.toList())); + log.debug("Current using cilium nodes: {}", addresses); + } + + private List buildShouldUsingNodes() { + if (CollectionUtils.isEmpty(allNodes) || CollectionUtils.isEmpty(remoteInstances)) { + log.debug("Found no cilium or backend nodes, skip all nodes, cilium nodes: {}, backend clients: {}", + allNodes, remoteInstances); + return ImmutableList.of(); + } + allNodes.sort(Comparator.comparing(CiliumNode::getAddress)); + final List totalBackendClients = remoteInstances + .stream().sorted(Comparator.comparing(RemoteInstance::getAddress)).collect(Collectors.toList()); + final int currentNodeIndex = totalBackendClients.indexOf(totalBackendClients.stream() + .filter(t -> t.getAddress().isSelf()).findFirst().get()); + // if the backend count bigger than cilium node count, we need to + if (totalBackendClients.size() > allNodes.size()) { + if (currentNodeIndex >= allNodes.size()) { + log.debug("Found no cilium nodes for current OAP node, skip all nodes, total cilium nodes: {}, total backend clients: {}, " + + "current node index: {}", allNodes.size(), totalBackendClients.size(), currentNodeIndex); + return ImmutableList.of(); + } + log.debug("Total cilium nodes: {}, total backend clients: {}, current node index: {}, using cilium node: {}", + allNodes.size(), totalBackendClients.size(), currentNodeIndex, allNodes.get(currentNodeIndex)); + return ImmutableList.of(allNodes.get(currentNodeIndex)); + } + + final int partNodesCount = allNodes.size() / totalBackendClients.size(); + if (partNodesCount == 0 && currentNodeIndex >= allNodes.size()) { + log.debug("Found no cilium nodes for current OAP node, skip all nodes, total cilium nodes: {}, total backend clients: {}, " + + "current node index: {}", allNodes.size(), totalBackendClients.size(), currentNodeIndex); + return ImmutableList.of(); + } + final int startIndex = currentNodeIndex * partNodesCount; + final int endIndex = currentNodeIndex == totalBackendClients.size() - 1 ? allNodes.size() : (currentNodeIndex + 1) * partNodesCount; + log.debug("Total cilium nodes: {}, part nodes count: {}, current node index: {}, using nodes part: {} - {}", + allNodes.size(), partNodesCount, currentNodeIndex, startIndex, endIndex); + return ImmutableList.copyOf(allNodes.subList(startIndex, endIndex)); + } + + private boolean compare(List remoteInstances) { + if (usingNodes.size() == remoteInstances.size()) { + for (int i = 0; i < usingNodes.size(); i++) { + if (!usingNodes.get(i).getAddress().equals(remoteInstances.get(i).getAddress())) { + return false; + } + } + return true; + } else { + return false; + } + } + + @Override + public void onClusterNodesChanged(List remoteInstances) { + this.remoteInstances = ImmutableList.copyOf(remoteInstances); + refreshUsingNodes(); + } + + enum Action { + Close, Unchanged, Create + } + + @AllArgsConstructor + @Getter + private static class NodeWithAction { + private final CiliumNode node; + @Setter + private Action action; + } +} diff --git a/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/CiliumNodeUpdateListener.java b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/CiliumNodeUpdateListener.java new file mode 100644 index 000000000000..64cd9f808d27 --- /dev/null +++ b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/CiliumNodeUpdateListener.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.fetcher.cilium.nodes; + +public interface CiliumNodeUpdateListener { + + /** + * Callback when a new node is added. + * + * @param node the new node + */ + void onNodeAdded(CiliumNode node); + + /** + * Callback when a node is deleted. + * + * @param node the deleted node + */ + void onNodeDelete(CiliumNode node); +} + diff --git a/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/ClientBuilder.java b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/ClientBuilder.java new file mode 100644 index 000000000000..fe88902a5359 --- /dev/null +++ b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/ClientBuilder.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.fetcher.cilium.nodes; + +public interface ClientBuilder { + /** + * Building client by address + */ + T buildClient(String host, int port, Class stubClass); +} diff --git a/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/GrpcStubBuilder.java b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/GrpcStubBuilder.java new file mode 100644 index 000000000000..dbdcbcbb53a3 --- /dev/null +++ b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/GrpcStubBuilder.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.fetcher.cilium.nodes; + +import com.linecorp.armeria.client.ClientBuilderParams; +import com.linecorp.armeria.client.ClientFactory; +import com.linecorp.armeria.client.ClientFactoryBuilder; +import com.linecorp.armeria.client.ClientOptions; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.skywalking.oap.server.fetcher.cilium.CiliumFetcherConfig; + +import java.io.File; +import java.net.URI; + +/** + * For Building all the gRPC stubs for the cilium fetcher. + */ +@Slf4j +public class GrpcStubBuilder implements ClientBuilder { + private final CiliumFetcherConfig config; + private final ClientFactory clientFactory; + + public GrpcStubBuilder(CiliumFetcherConfig config) { + final ClientFactoryBuilder builder = ClientFactory.builder(); + if (config.isSslConnection()) { + builder + .tlsNoVerify() // skip the verification of the server's certificate(for the host checker) + .useHttp2WithoutAlpn(true) // use HTTP/2 without ALPN(cilium not support for now) + .tlsCustomizer(ctx -> { + ctx.keyManager(new File(config.getSslCertChainFile()), new File(config.getSslPrivateKeyFile())); + ctx.trustManager(new File(config.getSslCaFile())); + }); + } + + this.config = config; + this.clientFactory = builder.build(); + } + + @Override + @SneakyThrows + public T buildClient(String host, int port, Class stubClass) { + String proto = "http"; + if (config.isSslConnection()) { + proto = "https"; + } + + final URI url = new URI("gproto+" + proto, null, host, port, "/", null, null); + return (T) clientFactory.newClient(ClientBuilderParams.of(url, stubClass, ClientOptions.of( + ClientOptions.RESPONSE_TIMEOUT_MILLIS.newValue(Long.MAX_VALUE), // For the cilium fetcher, we need to wait for the response(all the data from streaming) + ClientOptions.MAX_RESPONSE_LENGTH.newValue(0L) // For the cilium streaming fetcher, we should ignore the response length limit + ))); + } +} diff --git a/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleDefine b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleDefine new file mode 100644 index 000000000000..f67193309983 --- /dev/null +++ b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleDefine @@ -0,0 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# + +org.apache.skywalking.oap.server.fetcher.cilium.CiliumFetcherModule diff --git a/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider new file mode 100644 index 000000000000..04855b33418f --- /dev/null +++ b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider @@ -0,0 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# + +org.apache.skywalking.oap.server.fetcher.cilium.CiliumFetcherProvider diff --git a/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/test/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/CiliumNodeManagerTest.java b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/test/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/CiliumNodeManagerTest.java new file mode 100644 index 000000000000..acec03ff1aa2 --- /dev/null +++ b/oap-server/server-fetcher-plugin/cilium-fetcher-plugin/src/test/java/org/apache/skywalking/oap/server/fetcher/cilium/nodes/CiliumNodeManagerTest.java @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.fetcher.cilium.nodes; + +import lombok.Getter; +import org.apache.skywalking.oap.server.core.cluster.RemoteInstance; +import org.apache.skywalking.oap.server.core.remote.client.Address; +import org.apache.skywalking.oap.server.fetcher.cilium.CiliumFetcherConfig; +import org.apache.skywalking.oap.server.library.module.ModuleManager; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.powermock.reflect.Whitebox; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@ExtendWith(MockitoExtension.class) +public class CiliumNodeManagerTest { + + @Mock + private ModuleManager moduleManager; + private CiliumNodeManager ciliumNodeManager; + private NodeUpdateListener nodeUpdateListener; + + public static Collection data() { + return Arrays.asList(new Object[][] { + { + "none-node-cluster-with-cilium-nodes", + Collections.emptyList(), + Arrays.asList(ciliumNode("c1")), + Collections.emptyList(), + }, + { + "single-node-cluster-with-single-nodes", + Arrays.asList(oapInstance("a1", true)), + Arrays.asList(ciliumNode("c1")), + Arrays.asList(ciliumNode("c1")) + }, + { + "single-node-cluster-with-multiple-nodes", + Arrays.asList(oapInstance("a1", true)), + Arrays.asList(ciliumNode("c1"), ciliumNode("c2")), + Arrays.asList(ciliumNode("c1"), ciliumNode("c2")) + }, + { + "multiple-node-cluster-with-single-nodes", + Arrays.asList(oapInstance("a1", true), oapInstance("a2", false)), + Arrays.asList(ciliumNode("c1")), + Arrays.asList(ciliumNode("c1")) + }, + { + "multiple-node-cluster-with-single-nodes-2", + Arrays.asList(oapInstance("a1", false), oapInstance("a2", true)), + Arrays.asList(ciliumNode("c1")), + Collections.emptyList() + }, + { + "multiple-node-cluster-with-multiple-nodes", + Arrays.asList(oapInstance("a1", true), oapInstance("a2", false)), + Arrays.asList(ciliumNode("c1"), ciliumNode("c2")), + Arrays.asList(ciliumNode("c1")) + }, + { + "multiple-node-cluster-with-multiple-nodes-2", + Arrays.asList(oapInstance("a1", true), oapInstance("a2", false)), + Arrays.asList(ciliumNode("c1"), ciliumNode("c2"), ciliumNode("c3")), + Arrays.asList(ciliumNode("c1")) + }, + { + "multiple-node-cluster-with-multiple-nodes-3", + Arrays.asList(oapInstance("a1", false), oapInstance("a2", true)), + Arrays.asList(ciliumNode("c1"), ciliumNode("c2"), ciliumNode("c3")), + Arrays.asList(ciliumNode("c2"), ciliumNode("c3")) + }, + }); + } + + @BeforeEach + public void prepare() { + ciliumNodeManager = new CiliumNodeManager(moduleManager, new NoopClientBuilder(), new CiliumFetcherConfig()); + nodeUpdateListener = new NodeUpdateListener(); + ciliumNodeManager.addListener(nodeUpdateListener); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("data") + public void test(String name, + List allOAPInstances, + List allCiliumNodes, + List shouldMonitorNodeBySelf) { + Whitebox.setInternalState(ciliumNodeManager, "remoteInstances", allOAPInstances); + Whitebox.setInternalState(ciliumNodeManager, "allNodes", allCiliumNodes); + ciliumNodeManager.refreshUsingNodes(); + final List nodes = nodeUpdateListener.getNodes(); + nodes.sort(Comparator.comparing(CiliumNode::getAddress)); + assertThat(nodes).isEqualTo(shouldMonitorNodeBySelf); + } + + private static CiliumNode ciliumNode(String address) { + return new CiliumNode(address, null); + } + + private static RemoteInstance oapInstance(String address, boolean self) { + return new RemoteInstance(new Address(address, 0, self)); + } + + @Getter + private static class NodeUpdateListener implements CiliumNodeUpdateListener { + private List nodes; + + public NodeUpdateListener() { + this.nodes = new ArrayList<>(); + } + + @Override + public void onNodeAdded(CiliumNode node) { + this.nodes.add(node); + } + + @Override + public void onNodeDelete(CiliumNode node) { + this.nodes.remove(node); + } + } + + private static class NoopClientBuilder implements ClientBuilder { + + @Override + public T buildClient(String host, int port, Class stubClass) { + return null; + } + } +} diff --git a/oap-server/server-fetcher-plugin/fetcher-proto/pom.xml b/oap-server/server-fetcher-plugin/fetcher-proto/pom.xml new file mode 100644 index 000000000000..331b46099c54 --- /dev/null +++ b/oap-server/server-fetcher-plugin/fetcher-proto/pom.xml @@ -0,0 +1,164 @@ + + + + + + org.apache.skywalking + server-fetcher-plugin + 10.1.0-SNAPSHOT + + 4.0.0 + + fetcher-proto + jar + + + ${basedir}/src/main/fbs + ${project.build.directory}/generated-sources/fbs/java + ${project.build.directory}/bin/flatc + tar.gz + + + + + com.google.flatbuffers + flatbuffers-java + provided + + + io.grpc + grpc-api + 1.63.0 + compile + + + + + + windows + + + Windows + + + + zip + + + + + + + + kr.motd.maven + os-maven-plugin + ${os-maven-plugin.version} + + + + + kr.motd.maven + os-maven-plugin + ${os-maven-plugin.version} + + + initialize + + detect + + + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + ${protobuf-maven-plugin.version} + + + + com.google.protobuf:protoc:${com.google.protobuf.protoc.version}:exe:${os.detected.classifier} + + grpc-java + + io.grpc:protoc-gen-grpc-java:${protoc-gen-grpc-java.plugin.version}:exe:${os.detected.classifier} + + + + + + + compile + compile-custom + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + unpack + generate-sources + + unpack + + + + + com.github.davidmoten + flatbuffers-compiler + 1.12.0.1 + ${fbs.compiler.artifact.type} + distribution-${os.detected.name} + true + ${project.build.directory} + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + ${build-helper-maven-plugin.version} + + + add-source + generate-sources + + add-source + + + + ${fbs.generated.sources} + + + + + + + + \ No newline at end of file diff --git a/oap-server/server-fetcher-plugin/fetcher-proto/src/main/proto/cilium/hubble/flow/flow.proto b/oap-server/server-fetcher-plugin/fetcher-proto/src/main/proto/cilium/hubble/flow/flow.proto new file mode 100644 index 000000000000..6b9a5006fd6a --- /dev/null +++ b/oap-server/server-fetcher-plugin/fetcher-proto/src/main/proto/cilium/hubble/flow/flow.proto @@ -0,0 +1,869 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of Hubble + +syntax = "proto3"; + +import "google/protobuf/any.proto"; +import "google/protobuf/wrappers.proto"; +import "google/protobuf/timestamp.proto"; + +package flow; + +option go_package = "github.com/cilium/cilium/api/v1/flow"; + +option java_multiple_files = true; +option java_package = "io.cilium.api.flow"; + +message Flow { + google.protobuf.Timestamp time = 1; + + // uuid is a universally unique identifier for this flow. + string uuid = 34; + + Verdict verdict = 2; + // only applicable to Verdict = DROPPED. + // deprecated in favor of drop_reason_desc. + uint32 drop_reason = 3 [deprecated=true]; + + // auth_type is the authentication type specified for the flow in Cilium Network Policy. + // Only set on policy verdict events. + AuthType auth_type = 35; + + // l2 + Ethernet ethernet = 4; + // l3 + IP IP = 5; + // l4 + Layer4 l4 = 6; + + reserved 7; // removed, do not use + + Endpoint source = 8; + Endpoint destination = 9; + + FlowType Type = 10; + + // NodeName is the name of the node from which this Flow was captured. + string node_name = 11; + + reserved 12; // removed, do not use + + // all names the source IP can have. + repeated string source_names = 13; + // all names the destination IP can have. + repeated string destination_names = 14; + + // L7 information. This field is set if and only if FlowType is L7. + Layer7 l7 = 15; + + // Deprecated. This suffers from false negatives due to protobuf not being + // able to distinguish between the value being false or it being absent. + // Please use is_reply instead. + bool reply = 16 [deprecated=true]; + + reserved 17, 18; // removed, do not use + + // EventType of the originating Cilium event + CiliumEventType event_type = 19; + + // source_service contains the service name of the source + Service source_service = 20; + // destination_service contains the service name of the destination + Service destination_service = 21; + + // traffic_direction of the connection, e.g. ingress or egress + TrafficDirection traffic_direction = 22; + + // policy_match_type is only applicable to the cilium event type PolicyVerdict + // https://github.com/cilium/cilium/blob/e831859b5cc336c6d964a6d35bbd34d1840e21b9/pkg/monitor/datapath_policy.go#L50 + uint32 policy_match_type = 23; + + // Only applicable to cilium trace notifications, blank for other types. + TraceObservationPoint trace_observation_point = 24; + + // only applicable to Verdict = DROPPED. + DropReason drop_reason_desc = 25; + + // is_reply indicates that this was a packet (L4) or message (L7) in the + // reply direction. May be absent (in which case it is unknown whether it + // is a reply or not). + google.protobuf.BoolValue is_reply = 26; + + // Only applicable to cilium debug capture events, blank for other types + DebugCapturePoint debug_capture_point = 27; + + // interface is the network interface on which this flow was observed + NetworkInterface interface = 28; + + // proxy_port indicates the port of the proxy to which the flow was forwarded + uint32 proxy_port = 29; + + // trace_context contains information about a trace related to the flow, if + // any. + TraceContext trace_context = 30; + + // sock_xlate_point is the socket translation point. + // Only applicable to TraceSock notifications, blank for other types + SocketTranslationPoint sock_xlate_point = 31; + + // socket_cookie is the Linux kernel socket cookie for this flow. + // Only applicable to TraceSock notifications, zero for other types + uint64 socket_cookie = 32; + + // cgroup_id of the process which emitted this event. + // Only applicable to TraceSock notifications, zero for other types + uint64 cgroup_id = 33; + + // This is a temporary workaround to support summary field for pb.Flow without + // duplicating logic from the old parser. This field will be removed once we + // fully migrate to the new parser. + string Summary = 100000 [deprecated=true]; + + // extensions can be used to add arbitrary additional metadata to flows. + // This can be used to extend functionality for other Hubble compatible + // APIs, or experiment with new functionality without needing to change the public API. + google.protobuf.Any extensions = 150000; + + // The CiliumNetworkPolicies allowing the egress of the flow. + repeated Policy egress_allowed_by = 21001; + // The CiliumNetworkPolicies allowing the ingress of the flow. + repeated Policy ingress_allowed_by = 21002; + + // The CiliumNetworkPolicies denying the egress of the flow. + repeated Policy egress_denied_by = 21004; + // The CiliumNetworkPolicies denying the ingress of the flow. + repeated Policy ingress_denied_by = 21005; +} + +enum FlowType { + UNKNOWN_TYPE = 0; + L3_L4 = 1; // not sure about the underscore here, but `L34` also reads strange + L7 = 2; + SOCK = 3; +} + +// These types correspond to definitions in pkg/policy/l4.go. +enum AuthType { + DISABLED = 0; + SPIRE = 1; + TEST_ALWAYS_FAIL = 2; +} + +enum TraceObservationPoint { + // Cilium treats 0 as TO_LXC, but its's something we should work to remove. + // This is intentionally set as unknown, so proto API can guarantee the + // observation point is always going to be present on trace events. + UNKNOWN_POINT = 0; + + // TO_PROXY indicates network packets are transmitted towards the l7 proxy. + TO_PROXY = 1; + // TO_HOST indicates network packets are transmitted towards the host + // namespace. + TO_HOST = 2; + // TO_STACK indicates network packets are transmitted towards the Linux + // kernel network stack on host machine. + TO_STACK = 3; + // TO_OVERLAY indicates network packets are transmitted towards the tunnel + // device. + TO_OVERLAY = 4; + // TO_ENDPOINT indicates network packets are transmitted towards endpoints + // (containers). + TO_ENDPOINT = 101; + // FROM_ENDPOINT indicates network packets were received from endpoints + // (containers). + FROM_ENDPOINT = 5; + // FROM_PROXY indicates network packets were received from the l7 proxy. + FROM_PROXY = 6; + // FROM_HOST indicates network packets were received from the host + // namespace. + FROM_HOST = 7; + // FROM_STACK indicates network packets were received from the Linux kernel + // network stack on host machine. + FROM_STACK = 8; + // FROM_OVERLAY indicates network packets were received from the tunnel + // device. + FROM_OVERLAY = 9; + // FROM_NETWORK indicates network packets were received from native + // devices. + FROM_NETWORK = 10; + // TO_NETWORK indicates network packets are transmitted towards native + // devices. + TO_NETWORK = 11; +} + +message Layer4 { + oneof protocol { + TCP TCP = 1; + UDP UDP = 2; + // ICMP is technically not L4, but mutually exclusive with the above + ICMPv4 ICMPv4 = 3; + ICMPv6 ICMPv6 = 4; + SCTP SCTP = 5; + } +} + +// This enum corresponds to Cilium's L7 accesslog [FlowType](https://github.com/cilium/cilium/blob/728c79e427438ab6f8d9375b62fccd6fed4ace3a/pkg/proxy/accesslog/record.go#L26): +enum L7FlowType { + UNKNOWN_L7_TYPE = 0; + REQUEST = 1; + RESPONSE = 2; + SAMPLE = 3; +} + +// Message for L7 flow, which roughly corresponds to Cilium's accesslog [LogRecord](https://github.com/cilium/cilium/blob/728c79e427438ab6f8d9375b62fccd6fed4ace3a/pkg/proxy/accesslog/record.go#L141): +message Layer7 { + L7FlowType type = 1; + // Latency of the response + uint64 latency_ns = 2; + // L7 field. This field is set if and only if FlowType is L7. + oneof record { + DNS dns = 100; + HTTP http = 101; + Kafka kafka = 102; + } +} + +// TraceContext contains trace context propagation data, i.e. information about a +// distributed trace. +// For more information about trace context, check the [W3C Trace Context specification](https://www.w3.org/TR/trace-context/). +message TraceContext { + // parent identifies the incoming request in a tracing system. + TraceParent parent = 1; +} + +// TraceParent identifies the incoming request in a tracing system. +message TraceParent { + // trace_id is a unique value that identifies a trace. It is a byte array + // represented as a hex string. + string trace_id = 1; +} + +message Endpoint { + uint32 ID = 1; + uint32 identity = 2; + string namespace = 3; + // labels in `foo=bar` format. + repeated string labels = 4; + string pod_name = 5; + repeated Workload workloads = 6; +} + +message Workload { + string name = 1; + string kind = 2; +} + +message TCP { + uint32 source_port = 1; + uint32 destination_port = 2; + TCPFlags flags = 3; +} + +message IP { + string source = 1; + string destination = 2; + IPVersion ipVersion = 3; + // This field indicates whether the TraceReasonEncryptMask is set or not. + // https://github.com/cilium/cilium/blob/ba0ed147bd5bb342f67b1794c2ad13c6e99d5236/pkg/monitor/datapath_trace.go#L27 + bool encrypted = 4; +} + +message Ethernet { + string source = 1; + string destination = 2; +} + +message TCPFlags { + bool FIN = 1; + bool SYN = 2; + bool RST = 3; + bool PSH = 4; + bool ACK = 5; + bool URG = 6; + bool ECE = 7; + bool CWR = 8; + bool NS = 9; +} + +message UDP { + uint32 source_port = 1; + uint32 destination_port = 2; +} + +message SCTP { + uint32 source_port = 1; + uint32 destination_port = 2; +} + +message ICMPv4 { + uint32 type = 1; + uint32 code = 2; +} + +message ICMPv6 { + uint32 type = 1; + uint32 code = 2; +} + +enum IPVersion { + IP_NOT_USED = 0; + IPv4 = 1; + IPv6 = 2; +} + +enum Verdict { + // UNKNOWN is used if there is no verdict for this flow event + VERDICT_UNKNOWN = 0; + // FORWARDED is used for flow events where the trace point has forwarded + // this packet or connection to the next processing entity. + FORWARDED = 1; + // DROPPED is used for flow events where the connection or packet has + // been dropped (e.g. due to a malformed packet, it being rejected by a + // network policy etc). The exact drop reason may be found in drop_reason_desc. + DROPPED = 2; + // ERROR is used for flow events where an error occurred during processing + ERROR = 3; + // AUDIT is used on policy verdict events in policy audit mode, to + // denominate flows that would have been dropped by policy if audit mode + // was turned off + AUDIT = 4; + // REDIRECTED is used for flow events which have been redirected to the proxy + REDIRECTED = 5; + // TRACED is used for flow events which have been observed at a trace point, + // but no particular verdict has been reached yet + TRACED = 6; + // TRANSLATED is used for flow events where an address has been translated + TRANSLATED = 7; +} + +// These values are shared with pkg/monitor/api/drop.go and bpf/lib/common.h. +// Note that non-drop reasons (i.e. values less than api.DropMin) are not used +// here. +enum DropReason { + // non-drop reasons + DROP_REASON_UNKNOWN = 0; + // drop reasons + INVALID_SOURCE_MAC = 130 [deprecated = true]; + INVALID_DESTINATION_MAC = 131 [deprecated = true]; + INVALID_SOURCE_IP = 132; + POLICY_DENIED = 133; + INVALID_PACKET_DROPPED = 134; + CT_TRUNCATED_OR_INVALID_HEADER = 135; + CT_MISSING_TCP_ACK_FLAG = 136; + CT_UNKNOWN_L4_PROTOCOL = 137; + CT_CANNOT_CREATE_ENTRY_FROM_PACKET = 138 [deprecated = true]; + UNSUPPORTED_L3_PROTOCOL = 139; + MISSED_TAIL_CALL = 140; + ERROR_WRITING_TO_PACKET = 141; + UNKNOWN_L4_PROTOCOL = 142; + UNKNOWN_ICMPV4_CODE = 143; + UNKNOWN_ICMPV4_TYPE = 144; + UNKNOWN_ICMPV6_CODE = 145; + UNKNOWN_ICMPV6_TYPE = 146; + ERROR_RETRIEVING_TUNNEL_KEY = 147; + ERROR_RETRIEVING_TUNNEL_OPTIONS = 148 [deprecated = true]; + INVALID_GENEVE_OPTION = 149 [deprecated = true]; + UNKNOWN_L3_TARGET_ADDRESS = 150; + STALE_OR_UNROUTABLE_IP = 151; + NO_MATCHING_LOCAL_CONTAINER_FOUND = 152 [deprecated = true]; + ERROR_WHILE_CORRECTING_L3_CHECKSUM = 153; + ERROR_WHILE_CORRECTING_L4_CHECKSUM = 154; + CT_MAP_INSERTION_FAILED = 155; + INVALID_IPV6_EXTENSION_HEADER = 156; + IP_FRAGMENTATION_NOT_SUPPORTED = 157; + SERVICE_BACKEND_NOT_FOUND = 158; + NO_TUNNEL_OR_ENCAPSULATION_ENDPOINT = 160; + FAILED_TO_INSERT_INTO_PROXYMAP = 161; + REACHED_EDT_RATE_LIMITING_DROP_HORIZON = 162; + UNKNOWN_CONNECTION_TRACKING_STATE = 163; + LOCAL_HOST_IS_UNREACHABLE = 164; + NO_CONFIGURATION_AVAILABLE_TO_PERFORM_POLICY_DECISION = 165; + UNSUPPORTED_L2_PROTOCOL = 166; + NO_MAPPING_FOR_NAT_MASQUERADE = 167; + UNSUPPORTED_PROTOCOL_FOR_NAT_MASQUERADE = 168; + FIB_LOOKUP_FAILED = 169; + ENCAPSULATION_TRAFFIC_IS_PROHIBITED = 170; + INVALID_IDENTITY = 171; + UNKNOWN_SENDER = 172; + NAT_NOT_NEEDED = 173; + IS_A_CLUSTERIP = 174; + FIRST_LOGICAL_DATAGRAM_FRAGMENT_NOT_FOUND = 175; + FORBIDDEN_ICMPV6_MESSAGE = 176; + DENIED_BY_LB_SRC_RANGE_CHECK = 177; + SOCKET_LOOKUP_FAILED = 178; + SOCKET_ASSIGN_FAILED = 179; + PROXY_REDIRECTION_NOT_SUPPORTED_FOR_PROTOCOL = 180; + POLICY_DENY = 181; + VLAN_FILTERED = 182; + INVALID_VNI = 183; + INVALID_TC_BUFFER = 184; + NO_SID = 185; + MISSING_SRV6_STATE = 186; + NAT46 = 187; + NAT64 = 188; + AUTH_REQUIRED = 189; + CT_NO_MAP_FOUND = 190; + SNAT_NO_MAP_FOUND = 191; + INVALID_CLUSTER_ID = 192; + UNSUPPORTED_PROTOCOL_FOR_DSR_ENCAP = 193; + NO_EGRESS_GATEWAY = 194; + UNENCRYPTED_TRAFFIC = 195; + TTL_EXCEEDED = 196; + NO_NODE_ID = 197; + DROP_RATE_LIMITED = 198; + IGMP_HANDLED = 199; + IGMP_SUBSCRIBED = 200; + MULTICAST_HANDLED = 201; + // A BPF program wants to tail call into bpf_host, but the host datapath + // hasn't been loaded yet. + DROP_HOST_NOT_READY = 202; +} + +enum TrafficDirection { + TRAFFIC_DIRECTION_UNKNOWN = 0; + INGRESS = 1; + EGRESS = 2; +} + +// These values are shared with pkg/monitor/api/datapath_debug.go and bpf/lib/dbg.h. +enum DebugCapturePoint { + DBG_CAPTURE_POINT_UNKNOWN = 0; + reserved 1 to 3; + DBG_CAPTURE_DELIVERY = 4; + DBG_CAPTURE_FROM_LB = 5; + DBG_CAPTURE_AFTER_V46 = 6; + DBG_CAPTURE_AFTER_V64 = 7; + DBG_CAPTURE_PROXY_PRE = 8; + DBG_CAPTURE_PROXY_POST = 9; + DBG_CAPTURE_SNAT_PRE = 10; + DBG_CAPTURE_SNAT_POST = 11; +} + +message Policy { + string name = 1; + string namespace = 2; + repeated string labels = 3; + uint64 revision = 4; +} + +// EventTypeFilter is a filter describing a particular event type. +message EventTypeFilter { + // type is the primary flow type as defined by: + // github.com/cilium/cilium/pkg/monitor/api.MessageType* + int32 type = 1; + + // match_sub_type is set to true when matching on the sub_type should + // be done. This flag is required as 0 is a valid sub_type. + bool match_sub_type = 2; + + // sub_type is the secondary type, e.g. + // - github.com/cilium/cilium/pkg/monitor/api.Trace* + int32 sub_type = 3; +} + +// CiliumEventType from which the flow originated. +message CiliumEventType { + // type of event the flow originated from, i.e. + // github.com/cilium/cilium/pkg/monitor/api.MessageType* + int32 type = 1; + // sub_type may indicate more details depending on type, e.g. + // - github.com/cilium/cilium/pkg/monitor/api.Trace* + // - github.com/cilium/cilium/pkg/monitor/api.Drop* + // - github.com/cilium/cilium/pkg/monitor/api.DbgCapture* + int32 sub_type = 2; +} + +// FlowFilter represent an individual flow filter. All fields are optional. If +// multiple fields are set, then all fields must match for the filter to match. +message FlowFilter { + // uuid filters by a list of flow uuids. + repeated string uuid = 29; + // source_ip filters by a list of source ips. Each of the source ips can be + // specified as an exact match (e.g. "1.1.1.1") or as a CIDR range (e.g. + // "1.1.1.0/24"). + repeated string source_ip = 1; + // source_pod filters by a list of source pod name prefixes, optionally + // within a given namespace (e.g. "xwing", "kube-system/coredns-"). + // The pod name can be omitted to only filter by namespace + // (e.g. "kube-system/") or the namespace can be omitted to filter for + // pods in any namespace (e.g. "/xwing") + repeated string source_pod = 2; + // source_fqdn filters by a list of source fully qualified domain names + repeated string source_fqdn = 7; + // source_labels filters on a list of source label selectors. Selectors + // support the full Kubernetes label selector syntax. + repeated string source_label = 10; + // source_service filters on a list of source service names. This field + // supports the same syntax as the source_pod field. + repeated string source_service = 16; + // source_workload filters by a list of source workload. + repeated Workload source_workload = 26; + + // destination_ip filters by a list of destination ips. Each of the + // destination ips can be specified as an exact match (e.g. "1.1.1.1") or + // as a CIDR range (e.g. "1.1.1.0/24"). + repeated string destination_ip = 3; + // destination_pod filters by a list of destination pod names + repeated string destination_pod = 4; + // destination_fqdn filters by a list of destination fully qualified domain names + repeated string destination_fqdn = 8; + // destination_label filters on a list of destination label selectors + repeated string destination_label = 11; + // destination_service filters on a list of destination service names + repeated string destination_service = 17; + // destination_workload filters by a list of destination workload. + repeated Workload destination_workload = 27; + + // traffic_direction filters flow by direction of the connection, e.g. + // ingress or egress. + repeated TrafficDirection traffic_direction = 30; + + // only return Flows that were classified with a particular verdict. + repeated Verdict verdict = 5; + // event_type is the list of event types to filter on + repeated EventTypeFilter event_type = 6; + // http_status_code is a list of string prefixes (e.g. "4+", "404", "5+") + // to filter on the HTTP status code + repeated string http_status_code = 9; + + // protocol filters flows by L4 or L7 protocol, e.g. (e.g. "tcp", "http") + repeated string protocol = 12; + + // source_port filters flows by L4 source port + repeated string source_port = 13; + // destination_port filters flows by L4 destination port + repeated string destination_port = 14; + // reply filters flows based on the direction of the flow. + repeated bool reply = 15; + // dns_query filters L7 DNS flows by query patterns (RE2 regex), e.g. 'kube.*local'. + repeated string dns_query = 18; + // source_identity filters by the security identity of the source endpoint. + repeated uint32 source_identity = 19; + // destination_identity filters by the security identity of the destination endpoint. + repeated uint32 destination_identity = 20; + + // GET, POST, PUT, etc. methods. This type of field is well suited for an + // enum but every single existing place is using a string already. + repeated string http_method = 21; + // http_path is a list of regular expressions to filter on the HTTP path. + repeated string http_path = 22; + // http_url is a list of regular expressions to filter on the HTTP URL. + repeated string http_url = 31; + // http_header is a list of key:value pairs to filter on the HTTP headers. + repeated HTTPHeader http_header = 32; + + // tcp_flags filters flows based on TCP header flags + repeated TCPFlags tcp_flags = 23; + + // node_name is a list of patterns to filter on the node name, e.g. "k8s*", + // "test-cluster/*.domain.com", "cluster-name/" etc. + repeated string node_name = 24; + + // filter based on IP version (ipv4 or ipv6) + repeated IPVersion ip_version = 25; + + // trace_id filters flows by trace ID + repeated string trace_id = 28; + + // Experimental contains filters that are not stable yet. Support for + // experimental features is always optional and subject to change. + message Experimental { + // cel_expression takes a common expression language (CEL) expression + // returning a boolean to determine if the filter matched or not. + // You can use the `_flow` variable to access fields on the flow using + // the flow.Flow protobuf field names. + // See https://github.com/google/cel-spec/blob/v0.14.0/doc/intro.md#introduction + // for more details on CEL and accessing the protobuf fields in CEL. + // Using CEL has performance cost compared to other filters, so prefer + // using non-CEL filters when possible, and try to specify CEL filters + // last in the list of FlowFilters. + repeated string cel_expression = 33; + } + // experimental contains filters that are not stable yet. Support for + // experimental features is always optional and subject to change. + Experimental experimental = 999; +} + +// EventType are constants are based on the ones from . +enum EventType { + UNKNOWN = 0; + // EventSample is equivalent to PERF_RECORD_SAMPLE. + EventSample = 9; + // RecordLost is equivalent to PERF_RECORD_LOST. + RecordLost = 2; +} + +// DNS flow. This is basically directly mapped from Cilium's [LogRecordDNS](https://github.com/cilium/cilium/blob/04f3889d627774f79e56d14ddbc165b3169e2d01/pkg/proxy/accesslog/record.go#L264): +message DNS { + // DNS name that's being looked up: e.g. "isovalent.com." + string query = 1; + // List of IP addresses in the DNS response. + repeated string ips = 2; + // TTL in the DNS response. + uint32 ttl = 3; + // List of CNames in the DNS response. + repeated string cnames = 4; + // Corresponds to DNSDataSource defined in: + // https://github.com/cilium/cilium/blob/04f3889d627774f79e56d14ddbc165b3169e2d01/pkg/proxy/accesslog/record.go#L253 + string observation_source = 5; + // Return code of the DNS request defined in: + // https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6 + uint32 rcode = 6; + // String representation of qtypes defined in: + // https://tools.ietf.org/html/rfc1035#section-3.2.3 + repeated string qtypes = 7; + // String representation of rrtypes defined in: + // https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4 + repeated string rrtypes = 8; +} + +message HTTPHeader { + string key = 1; + string value = 2; +} + +// L7 information for HTTP flows. It corresponds to Cilium's [accesslog.LogRecordHTTP](https://github.com/cilium/cilium/blob/728c79e427438ab6f8d9375b62fccd6fed4ace3a/pkg/proxy/accesslog/record.go#L206) type. +message HTTP { + uint32 code = 1; + string method = 2; + string url = 3; + string protocol = 4; + repeated HTTPHeader headers = 5; +} + +// L7 information for Kafka flows. It corresponds to Cilium's [accesslog.LogRecordKafka](https://github.com/cilium/cilium/blob/728c79e427438ab6f8d9375b62fccd6fed4ace3a/pkg/proxy/accesslog/record.go#L229) type. +message Kafka { + int32 error_code = 1; + int32 api_version = 2; + string api_key = 3; + int32 correlation_id = 4; + string topic = 5; +} + +message Service { + string name = 1; + string namespace = 2; +} + +enum LostEventSource { + UNKNOWN_LOST_EVENT_SOURCE = 0; + // PERF_EVENT_RING_BUFFER indicates that events were dropped in the BPF + // perf event ring buffer, indicating that userspace agent did not keep up + // with the events produced by the datapath. + PERF_EVENT_RING_BUFFER = 1; + // OBSERVER_EVENTS_QUEUE indicates that events were dropped because the + // Hubble events queue was full, indicating that the Hubble observer did + // not keep up. + OBSERVER_EVENTS_QUEUE = 2; + + // HUBBLE_RING_BUFFER indicates that the event was dropped because it could + // not be read from Hubble's ring buffer in time before being overwritten. + HUBBLE_RING_BUFFER = 3; +} + +// LostEvent is a message which notifies consumers about a loss of events +// that happened before the events were captured by Hubble. +message LostEvent { + // source is the location where events got lost. + LostEventSource source = 1; + // num_events_lost is the number of events that haven been lost at source. + uint64 num_events_lost = 2; + // cpu on which the event was lost if the source of lost events is + // PERF_EVENT_RING_BUFFER. + google.protobuf.Int32Value cpu = 3; +} + +// AgentEventType is the type of agent event. These values are shared with type +// AgentNotification in pkg/monitor/api/types.go. +enum AgentEventType { + AGENT_EVENT_UNKNOWN = 0; + // used for AGENT_EVENT_GENERIC in monitor API, but there are currently no + // such events; + reserved 1; + AGENT_STARTED = 2; + POLICY_UPDATED = 3; + POLICY_DELETED = 4; + ENDPOINT_REGENERATE_SUCCESS = 5; + ENDPOINT_REGENERATE_FAILURE = 6; + ENDPOINT_CREATED = 7; + ENDPOINT_DELETED = 8; + IPCACHE_UPSERTED = 9; + IPCACHE_DELETED = 10; + SERVICE_UPSERTED = 11; + SERVICE_DELETED = 12; +} + +message AgentEvent { + AgentEventType type = 1; + oneof notification { + AgentEventUnknown unknown = 100; + TimeNotification agent_start = 101; + // used for POLICY_UPDATED and POLICY_DELETED + PolicyUpdateNotification policy_update = 102; + // used for ENDPOINT_REGENERATE_SUCCESS and ENDPOINT_REGENERATE_FAILURE + EndpointRegenNotification endpoint_regenerate = 103; + // used for ENDPOINT_CREATED and ENDPOINT_DELETED + EndpointUpdateNotification endpoint_update = 104; + // used for IPCACHE_UPSERTED and IPCACHE_DELETED + IPCacheNotification ipcache_update = 105; + ServiceUpsertNotification service_upsert = 106; + ServiceDeleteNotification service_delete = 107; + } +} + +message AgentEventUnknown { + string type = 1; + string notification = 2; +} + +message TimeNotification { + google.protobuf.Timestamp time = 1; +} + +message PolicyUpdateNotification { + repeated string labels = 1; + uint64 revision = 2; + int64 rule_count = 3; +} + +message EndpointRegenNotification { + uint64 id = 1; + repeated string labels = 2; + string error = 3; +} + +message EndpointUpdateNotification { + uint64 id = 1; + repeated string labels = 2; + string error = 3; + string pod_name = 4; + string namespace = 5; +} + +message IPCacheNotification { + string cidr = 1; + uint32 identity = 2; + google.protobuf.UInt32Value old_identity = 3; + string host_ip = 4; + string old_host_ip = 5; + uint32 encrypt_key = 6; + string namespace = 7; + string pod_name = 8; +} + +message ServiceUpsertNotificationAddr { + string ip = 1; + uint32 port = 2; +} + +message ServiceUpsertNotification { + uint32 id = 1; + ServiceUpsertNotificationAddr frontend_address = 2; + repeated ServiceUpsertNotificationAddr backend_addresses = 3; + string type = 4; + string traffic_policy = 5 [deprecated = true]; + string name = 6; + string namespace = 7; + string ext_traffic_policy = 8; + string int_traffic_policy = 9; +} + +message ServiceDeleteNotification { + uint32 id = 1; +} + +message NetworkInterface { + uint32 index = 1; + string name = 2; +} + +// This mirrors enum xlate_point in bpf/lib/trace_sock.h +enum SocketTranslationPoint { + SOCK_XLATE_POINT_UNKNOWN = 0; + SOCK_XLATE_POINT_PRE_DIRECTION_FWD = 1; // Pre service translation + SOCK_XLATE_POINT_POST_DIRECTION_FWD = 2; // Post service translation + SOCK_XLATE_POINT_PRE_DIRECTION_REV = 3; // Pre reverse service translation + SOCK_XLATE_POINT_POST_DIRECTION_REV = 4; // Post reverse service translation +} + +message DebugEvent { + DebugEventType type = 1; + Endpoint source = 2; + google.protobuf.UInt32Value hash = 3; + google.protobuf.UInt32Value arg1 = 4; + google.protobuf.UInt32Value arg2 = 5; + google.protobuf.UInt32Value arg3 = 6; + string message = 7; + google.protobuf.Int32Value cpu = 8; +} + +// These values are shared with pkg/monitor/api/datapath_debug.go and bpf/lib/dbg.h. +enum DebugEventType { + DBG_EVENT_UNKNOWN = 0; + DBG_GENERIC = 1; + DBG_LOCAL_DELIVERY = 2; + DBG_ENCAP = 3; + DBG_LXC_FOUND = 4; + DBG_POLICY_DENIED = 5; + DBG_CT_LOOKUP = 6; + DBG_CT_LOOKUP_REV = 7; + DBG_CT_MATCH = 8; + DBG_CT_CREATED = 9; + DBG_CT_CREATED2 = 10; + DBG_ICMP6_HANDLE = 11; + DBG_ICMP6_REQUEST = 12; + DBG_ICMP6_NS = 13; + DBG_ICMP6_TIME_EXCEEDED = 14; + DBG_CT_VERDICT = 15; + DBG_DECAP = 16; + DBG_PORT_MAP = 17; + DBG_ERROR_RET = 18; + DBG_TO_HOST = 19; + DBG_TO_STACK = 20; + DBG_PKT_HASH = 21; + DBG_LB6_LOOKUP_FRONTEND = 22; + DBG_LB6_LOOKUP_FRONTEND_FAIL = 23; + DBG_LB6_LOOKUP_BACKEND_SLOT = 24; + DBG_LB6_LOOKUP_BACKEND_SLOT_SUCCESS = 25; + DBG_LB6_LOOKUP_BACKEND_SLOT_V2_FAIL = 26; + DBG_LB6_LOOKUP_BACKEND_FAIL = 27; + DBG_LB6_REVERSE_NAT_LOOKUP = 28; + DBG_LB6_REVERSE_NAT = 29; + DBG_LB4_LOOKUP_FRONTEND = 30; + DBG_LB4_LOOKUP_FRONTEND_FAIL = 31; + DBG_LB4_LOOKUP_BACKEND_SLOT = 32; + DBG_LB4_LOOKUP_BACKEND_SLOT_SUCCESS = 33; + DBG_LB4_LOOKUP_BACKEND_SLOT_V2_FAIL = 34; + DBG_LB4_LOOKUP_BACKEND_FAIL = 35; + DBG_LB4_REVERSE_NAT_LOOKUP = 36; + DBG_LB4_REVERSE_NAT = 37; + DBG_LB4_LOOPBACK_SNAT = 38; + DBG_LB4_LOOPBACK_SNAT_REV = 39; + DBG_CT_LOOKUP4 = 40; + DBG_RR_BACKEND_SLOT_SEL = 41; + DBG_REV_PROXY_LOOKUP = 42; + DBG_REV_PROXY_FOUND = 43; + DBG_REV_PROXY_UPDATE = 44; + DBG_L4_POLICY = 45; + DBG_NETDEV_IN_CLUSTER = 46; + DBG_NETDEV_ENCAP4 = 47; + DBG_CT_LOOKUP4_1 = 48; + DBG_CT_LOOKUP4_2 = 49; + DBG_CT_CREATED4 = 50; + DBG_CT_LOOKUP6_1 = 51; + DBG_CT_LOOKUP6_2 = 52; + DBG_CT_CREATED6 = 53; + DBG_SKIP_PROXY = 54; + DBG_L4_CREATE = 55; + DBG_IP_ID_MAP_FAILED4 = 56; + DBG_IP_ID_MAP_FAILED6 = 57; + DBG_IP_ID_MAP_SUCCEED4 = 58; + DBG_IP_ID_MAP_SUCCEED6 = 59; + DBG_LB_STALE_CT = 60; + DBG_INHERIT_IDENTITY = 61; + DBG_SK_LOOKUP4 = 62; + DBG_SK_LOOKUP6 = 63; + DBG_SK_ASSIGN = 64; + DBG_L7_LB = 65; + DBG_SKIP_POLICY = 66; +} diff --git a/oap-server/server-fetcher-plugin/fetcher-proto/src/main/proto/cilium/hubble/observer/observer.proto b/oap-server/server-fetcher-plugin/fetcher-proto/src/main/proto/cilium/hubble/observer/observer.proto new file mode 100644 index 000000000000..116f10216652 --- /dev/null +++ b/oap-server/server-fetcher-plugin/fetcher-proto/src/main/proto/cilium/hubble/observer/observer.proto @@ -0,0 +1,310 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of Hubble + +syntax = "proto3"; + +import "google/protobuf/any.proto"; +import "google/protobuf/wrappers.proto"; +import "google/protobuf/timestamp.proto"; +import "google/protobuf/field_mask.proto"; +import public "cilium/hubble/flow/flow.proto"; +import "cilium/hubble/relay/relay.proto"; + +package observer; + +option go_package = "github.com/cilium/cilium/api/v1/observer"; + +option java_multiple_files = true; +option java_package = "io.cilium.api.observer"; + +// Observer returns a stream of Flows depending on which filter the user want +// to observe. +service Observer { + // GetFlows returning structured data, meant to eventually obsolete GetLastNFlows. + rpc GetFlows(GetFlowsRequest) returns (stream GetFlowsResponse) {} + + // GetAgentEvents returns Cilium agent events. + rpc GetAgentEvents(GetAgentEventsRequest) returns (stream GetAgentEventsResponse) {} + + // GetDebugEvents returns Cilium datapath debug events. + rpc GetDebugEvents(GetDebugEventsRequest) returns (stream GetDebugEventsResponse) {} + + // GetNodes returns information about nodes in a cluster. + rpc GetNodes(GetNodesRequest) returns (GetNodesResponse) {} + + // GetNamespaces returns information about namespaces in a cluster. + // The namespaces returned are namespaces which have had network flows in + // the last hour. The namespaces are returned sorted by cluster name and + // namespace in ascending order. + rpc GetNamespaces(GetNamespacesRequest) returns (GetNamespacesResponse) {} + + // ServerStatus returns some details about the running hubble server. + rpc ServerStatus(ServerStatusRequest) returns (ServerStatusResponse) {} +} + +message ServerStatusRequest {} + +message ServerStatusResponse { + // number of currently captured flows + // In a multi-node context, this is the cumulative count of all captured + // flows. + uint64 num_flows = 1; + + // maximum capacity of the ring buffer + // In a multi-node context, this is the aggregation of all ring buffers + // capacities. + uint64 max_flows = 2; + + // total amount of flows observed since the observer was started + // In a multi-node context, this is the aggregation of all flows that have + // been seen. + uint64 seen_flows = 3; + + // uptime of this observer instance in nanoseconds + // In a multi-node context, this field corresponds to the uptime of the + // longest living instance. + uint64 uptime_ns = 4; + + // number of nodes for which a connection is established + google.protobuf.UInt32Value num_connected_nodes = 5; + + // number of nodes for which a connection cannot be established + google.protobuf.UInt32Value num_unavailable_nodes = 6; + + // list of nodes that are unavailable + // This list may not be exhaustive. + repeated string unavailable_nodes = 7; + + // Version is the version of Cilium/Hubble. + string version = 8; + + // Approximate rate of flows seen by Hubble per second over the last minute. + // In a multi-node context, this is the sum of all flows rates. + double flows_rate = 9; +} + +message GetFlowsRequest { + // Number of flows that should be returned. Incompatible with `since/until`. + // Defaults to the most recent (last) `number` flows, unless `first` is + // true, then it will return the earliest `number` flows. + uint64 number = 1; + + // first specifies if we should look at the first `number` flows or the + // last `number` of flows. Incompatible with `follow`. + bool first = 9; + + reserved 2; // removed, do not use + + // follow sets when the server should continue to stream flows after + // printing the last N flows. + bool follow = 3; + + // blacklist defines a list of filters which have to match for a flow to be + // excluded from the result. + // If multiple blacklist filters are specified, only one of them has to + // match for a flow to be excluded. + repeated flow.FlowFilter blacklist = 5; + + // whitelist defines a list of filters which have to match for a flow to be + // included in the result. + // If multiple whitelist filters are specified, only one of them has to + // match for a flow to be included. + // The whitelist and blacklist can both be specified. In such cases, the + // set of the returned flows is the set difference `whitelist - blacklist`. + // In other words, the result will contain all flows matched by the + // whitelist that are not also simultaneously matched by the blacklist. + repeated flow.FlowFilter whitelist = 6; + + // Since this time for returned flows. Incompatible with `number`. + google.protobuf.Timestamp since = 7; + + // Until this time for returned flows. Incompatible with `number`. + google.protobuf.Timestamp until = 8; + + // FieldMask allows clients to limit flow's fields that will be returned. + // For example, {paths: ["source.id", "destination.id"]} will return flows + // with only these two fields set. + google.protobuf.FieldMask field_mask = 10; + + // Experimental contains fields that are not stable yet. Support for + // experimental features is always optional and subject to change. + message Experimental { + // FieldMask allows clients to limit flow's fields that will be returned. + // For example, {paths: ["source.id", "destination.id"]} will return flows + // with only these two fields set. + // Deprecated in favor of top-level field_mask. This field will be + // removed in v1.17. + google.protobuf.FieldMask field_mask = 1 [deprecated=true]; + } + Experimental experimental = 999; + + // extensions can be used to add arbitrary additional metadata to GetFlowsRequest. + // This can be used to extend functionality for other Hubble compatible + // APIs, or experiment with new functionality without needing to change the public API. + google.protobuf.Any extensions = 150000; +} + +// GetFlowsResponse contains either a flow or a protocol message. +message GetFlowsResponse { + oneof response_types{ + flow.Flow flow = 1; + // node_status informs clients about the state of the nodes + // participating in this particular GetFlows request. + relay.NodeStatusEvent node_status = 2; + // lost_events informs clients about events which got dropped due to + // a Hubble component being unavailable + flow.LostEvent lost_events = 3; + } + // Name of the node where this event was observed. + string node_name = 1000; + // Timestamp at which this event was observed. + google.protobuf.Timestamp time = 1001; +} + +message GetAgentEventsRequest { + // Number of flows that should be returned. Incompatible with `since/until`. + // Defaults to the most recent (last) `number` events, unless `first` is + // true, then it will return the earliest `number` events. + uint64 number = 1; + + // first specifies if we should look at the first `number` events or the + // last `number` of events. Incompatible with `follow`. + bool first = 9; + + // follow sets when the server should continue to stream agent events after + // printing the last N agent events. + bool follow = 2; + + // TODO: do we want to be able to specify blocklist/allowlist (previously + // known as blacklist/whitelist)? + + // Since this time for returned agent events. Incompatible with `number`. + google.protobuf.Timestamp since = 7; + + // Until this time for returned agent events. Incompatible with `number`. + google.protobuf.Timestamp until = 8; +} + +// GetAgentEventsResponse contains an event received from the Cilium agent. +message GetAgentEventsResponse { + flow.AgentEvent agent_event = 1; + // Name of the node where this event was observed. + string node_name = 1000; + // Timestamp at which this event was observed. + google.protobuf.Timestamp time = 1001; +} + +message GetDebugEventsRequest { + // Number of events that should be returned. Incompatible with `since/until`. + // Defaults to the most recent (last) `number` events, unless `first` is + // true, then it will return the earliest `number` events. + uint64 number = 1; + + // first specifies if we should look at the first `number` events or the + // last `number` of events. Incompatible with `follow`. + bool first = 9; + + // follow sets when the server should continue to stream debug events after + // printing the last N debug events. + bool follow = 2; + + // TODO: do we want to be able to specify blocklist/allowlist (previously + // known as blacklist/whitelist)? + + // Since this time for returned debug events. Incompatible with `number`. + google.protobuf.Timestamp since = 7; + + // Until this time for returned debug events. Incompatible with `number`. + google.protobuf.Timestamp until = 8; +} + +// GetDebugEventsResponse contains a Cilium datapath debug events. +message GetDebugEventsResponse { + flow.DebugEvent debug_event = 1; + // Name of the node where this event was observed. + string node_name = 1000; + // Timestamp at which this event was observed. + google.protobuf.Timestamp time = 1001; +} + +message GetNodesRequest {} + +// GetNodesResponse contains the list of nodes. +message GetNodesResponse { + // Nodes is an exhaustive list of nodes. + repeated Node nodes = 1; +} + +// Node represents a cluster node. +message Node { + // Name is the name of the node. + string name = 1; + // Version is the version of Cilium/Hubble as reported by the node. + string version = 2; + + // Address is the network address of the API endpoint. + string address = 3; + + // State represents the known state of the node. + relay.NodeState state = 4; + + // TLS reports TLS related information. + TLS tls = 5; + + // UptimeNS is the uptime of this instance in nanoseconds + uint64 uptime_ns = 6; + + // number of currently captured flows + uint64 num_flows = 7; + + // maximum capacity of the ring buffer + uint64 max_flows = 8; + + // total amount of flows observed since the observer was started + uint64 seen_flows = 9; +} + +// TLS represents TLS information. +message TLS { + // Enabled reports whether TLS is enabled or not. + bool enabled = 1; + // ServerName is the TLS server name that can be used as part of the TLS + // cert validation process. + string server_name = 2; +} + +message GetNamespacesRequest {} + +// GetNamespacesResponse contains the list of namespaces. +message GetNamespacesResponse { + // Namespaces is a list of namespaces with flows + repeated Namespace namespaces = 1; +} + +message Namespace { + string cluster = 1; + string namespace = 2; +} + +// ExportEvent contains an event to be exported. Not to be used outside of the +// exporter feature. +message ExportEvent { + oneof response_types{ + flow.Flow flow = 1; + // node_status informs clients about the state of the nodes + // participating in this particular GetFlows request. + relay.NodeStatusEvent node_status = 2; + // lost_events informs clients about events which got dropped due to + // a Hubble component being unavailable + flow.LostEvent lost_events = 3; + // agent_event informs clients about an event received from the Cilium + // agent. + flow.AgentEvent agent_event = 4; + // debug_event contains Cilium datapath debug events + flow.DebugEvent debug_event = 5; + } + // Name of the node where this event was observed. + string node_name = 1000; + // Timestamp at which this event was observed. + google.protobuf.Timestamp time = 1001; +} diff --git a/oap-server/server-fetcher-plugin/fetcher-proto/src/main/proto/cilium/hubble/peer/peer.proto b/oap-server/server-fetcher-plugin/fetcher-proto/src/main/proto/cilium/hubble/peer/peer.proto new file mode 100644 index 000000000000..3e8063fe17cf --- /dev/null +++ b/oap-server/server-fetcher-plugin/fetcher-proto/src/main/proto/cilium/hubble/peer/peer.proto @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of Hubble + +syntax = "proto3"; + +package peer; + +option go_package = "github.com/cilium/cilium/api/v1/peer"; + +option java_multiple_files = true; +option java_package = "io.cilium.api.peer"; + +// Peer lists hubble peers and notifies of changes. +service Peer { + // Notify sends information about hubble peers in the cluster. + // When Notify is called, it sends information about all the peers that are + // already part of the cluster (with the type as PEER_ADDED). It + // subsequently notifies of any change. + rpc Notify(NotifyRequest) returns (stream ChangeNotification) {} +} + +message NotifyRequest {} + +// ChangeNotification indicates a change regarding a hubble peer. +message ChangeNotification { + // Name is the name of the peer, typically the hostname. The name includes + // the cluster name if a value other than default has been specified. + // This value can be used to uniquely identify the host. + // When the cluster name is not the default, the cluster name is prepended + // to the peer name and a forward slash is added. + // + // Examples: + // - runtime1 + // - testcluster/runtime1 + string name = 1; + + // Address is the address of the peer's gRPC service. + string address = 2; + + // ChangeNotificationType indicates the type of change, ie whether the peer + // was added, deleted or updated. + ChangeNotificationType type = 3; + + // TLS provides information to connect to the Address with TLS enabled. + // If not set, TLS shall be assumed to be disabled. + TLS tls = 4; +} + +// ChangeNotificationType defines the peer change notification type. +enum ChangeNotificationType { + UNKNOWN = 0; + PEER_ADDED = 1; + PEER_DELETED = 2; + PEER_UPDATED = 3; +} + +// TLS provides information to establish a TLS connection to the peer. +message TLS { + // ServerName is used to verify the hostname on the returned certificate. + string server_name = 1; +} diff --git a/oap-server/server-fetcher-plugin/fetcher-proto/src/main/proto/cilium/hubble/relay/relay.proto b/oap-server/server-fetcher-plugin/fetcher-proto/src/main/proto/cilium/hubble/relay/relay.proto new file mode 100644 index 000000000000..ecc17c1afa6c --- /dev/null +++ b/oap-server/server-fetcher-plugin/fetcher-proto/src/main/proto/cilium/hubble/relay/relay.proto @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of Cilium + +syntax = "proto3"; + +package relay; + +option go_package = "github.com/cilium/cilium/api/v1/relay"; + +option java_multiple_files = true; +option java_package = "io.cilium.api.relay"; + +// NodeStatusEvent is a message sent by hubble-relay to inform clients about +// the state of a particular node. +message NodeStatusEvent { + // state_change contains the new node state + NodeState state_change = 1; + // node_names is the list of nodes for which the above state changes applies + repeated string node_names = 2; + // message is an optional message attached to the state change (e.g. an + // error message). The message applies to all nodes in node_names. + string message = 3; +} + +enum NodeState { + // UNKNOWN_NODE_STATE indicates that the state of this node is unknown. + UNKNOWN_NODE_STATE = 0; + // NODE_CONNECTED indicates that we have established a connection + // to this node. The client can expect to observe flows from this node. + NODE_CONNECTED = 1; + // NODE_UNAVAILABLE indicates that the connection to this + // node is currently unavailable. The client can expect to not see any + // flows from this node until either the connection is re-established or + // the node is gone. + NODE_UNAVAILABLE = 2; + // NODE_GONE indicates that a node has been removed from the + // cluster. No reconnection attempts will be made. + NODE_GONE = 3; + // NODE_ERROR indicates that a node has reported an error while processing + // the request. No reconnection attempts will be made. + NODE_ERROR = 4; +} diff --git a/oap-server/server-fetcher-plugin/pom.xml b/oap-server/server-fetcher-plugin/pom.xml index 7feda655d11e..4a8bb06ed000 100644 --- a/oap-server/server-fetcher-plugin/pom.xml +++ b/oap-server/server-fetcher-plugin/pom.xml @@ -29,7 +29,9 @@ pom + fetcher-proto kafka-fetcher-plugin + cilium-fetcher-plugin @@ -37,5 +39,25 @@ io.vavr vavr + + org.apache.skywalking + server-core + ${project.version} + + + org.apache.skywalking + apm-network + ${project.version} + + + org.apache.skywalking + library-module + ${project.version} + + + org.apache.skywalking + library-util + ${project.version} + diff --git a/oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/grpc/ssl/DynamicSslContext.java b/oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/grpc/ssl/DynamicSslContext.java index 4d9ff3c1023b..bdfd98a5ce70 100644 --- a/oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/grpc/ssl/DynamicSslContext.java +++ b/oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/grpc/ssl/DynamicSslContext.java @@ -74,7 +74,7 @@ protected void updateContext(final String privateKeyFile, final String certChain if (StringUtil.isNotEmpty(trustedCAsFile)) { builder.trustManager(Paths.get(trustedCAsFile).toFile()) - .clientAuth(ClientAuth.REQUIRE); + .clientAuth(ClientAuth.REQUIRE); } setCtx(builder.build()); diff --git a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/als/mx/FieldsHelper.java b/oap-server/server-library/library-util/src/main/java/org/apache/skywalking/oap/server/library/util/FieldsHelper.java similarity index 66% rename from oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/als/mx/FieldsHelper.java rename to oap-server/server-library/library-util/src/main/java/org/apache/skywalking/oap/server/library/util/FieldsHelper.java index 29b227ddacf3..9e3306ee7279 100644 --- a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/als/mx/FieldsHelper.java +++ b/oap-server/server-library/library-util/src/main/java/org/apache/skywalking/oap/server/library/util/FieldsHelper.java @@ -16,7 +16,17 @@ * */ -package org.apache.skywalking.oap.server.receiver.envoy.als.mx; +package org.apache.skywalking.oap.server.library.util; + +import com.google.common.base.Splitter; +import com.google.common.base.Strings; +import com.google.protobuf.Struct; +import com.google.protobuf.Value; +import lombok.RequiredArgsConstructor; +import lombok.experimental.Delegate; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.yaml.snakeyaml.Yaml; import java.io.InputStream; import java.lang.invoke.CallSite; @@ -28,51 +38,54 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiConsumer; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -import org.apache.commons.lang3.StringUtils; -import org.apache.skywalking.oap.server.library.module.ModuleStartException; -import org.apache.skywalking.oap.server.library.util.ResourceUtils; -import org.apache.skywalking.oap.server.receiver.envoy.als.ServiceMetaInfo; -import org.apache.skywalking.oap.server.receiver.envoy.als.ServiceMetaInfo.KeyValue; -import org.yaml.snakeyaml.Yaml; - -import com.google.common.base.Splitter; -import com.google.common.base.Strings; -import com.google.protobuf.Struct; -import com.google.protobuf.Value; +@Slf4j +public class FieldsHelper { -import lombok.RequiredArgsConstructor; -import lombok.experimental.Delegate; -import lombok.extern.slf4j.Slf4j; + /** + * The difference Class have different {@link FieldsHelper} instance for their own mappings. + */ + private static final Map, FieldsHelper> HELPER_MAP = new ConcurrentHashMap<>(); -@Slf4j -public enum FieldsHelper { - SINGLETON; + /** + * The target class to be inflated. + */ + private final Class targetClass; + /** + * Whether the {@link FieldsHelper} has been initialized. + */ private boolean initialized = false; /** - * The mappings from the field name of {@link ServiceMetaInfo} to the field name of {@code flatbuffers}. + * The mappings from the field name to the field name of {@code flatbuffers}. */ - private Map fieldNameMapping; + private Map fieldNameMapping; /** - * The mappings from the field name of {@link ServiceMetaInfo} to its {@code setter}. + * The mappings from the field name to its {@code setter}. */ - private Map> fieldSetterMapping; + private Map> fieldSetterMapping; - public void init(final String file, - final Class serviceInfoClass) throws Exception { - init(ResourceUtils.readToStream(file), serviceInfoClass); + public static FieldsHelper forClass(final Class targetClass) { + return HELPER_MAP.computeIfAbsent(targetClass, FieldsHelper::new); + } + + private FieldsHelper(Class targetClass) { + this.targetClass = targetClass; + } + + public void init(final String file) throws Exception { + init(ResourceUtils.readToStream(file)); } @SuppressWarnings("unchecked") - public void init(final InputStream inputStream, - final Class serviceInfoClass) throws ModuleStartException { + public void init(final InputStream inputStream) { if (initialized) { return; } @@ -103,13 +116,14 @@ public void init(final InputStream inputStream, tokenBuffer.append(token); } else if (tokenBuffer.length() > 0) { tokenBuffer.append(".").append(token); - if (token.endsWith("\"")) { - candidateFields.add(tokenBuffer.toString().replaceAll("\"", "")); - tokenBuffer.setLength(0); - } } else { candidateFields.add(token); } + + if (tokenBuffer.length() > 0 && token.endsWith("\"")) { + candidateFields.add(tokenBuffer.toString().replaceAll("\"", "")); + tokenBuffer.setLength(0); + } } return new Field(candidateFields); }).collect(Collectors.toList()); @@ -119,7 +133,7 @@ public void init(final InputStream inputStream, fieldNameMapping.put( serviceMetaInfoFieldName, - new ServiceNameFormat(serviceNamePattern.toString(), flatBuffersFieldNames) + new FieldFormat(serviceNamePattern.toString(), flatBuffersFieldNames) ); try { @@ -130,35 +144,35 @@ public void init(final InputStream inputStream, lookup, "accept", MethodType.methodType(BiConsumer.class), MethodType.methodType(void.class, Object.class, Object.class), - lookup.findVirtual(serviceInfoClass, setter, + lookup.findVirtual(targetClass, setter, MethodType.methodType(void.class, parameterType)), - MethodType.methodType(void.class, serviceInfoClass, parameterType)); + MethodType.methodType(void.class, targetClass, parameterType)); final MethodHandle factory = site.getTarget(); - final BiConsumer method = - (BiConsumer) factory.invoke(); + final BiConsumer method = + (BiConsumer) factory.invoke(); fieldSetterMapping.put(serviceMetaInfoFieldName, method); } catch (final Throwable e) { - throw new ModuleStartException("Initialize method error", e); + throw new IllegalStateException("Initialize method error", e); } } initialized = true; } /** - * Inflates the {@code serviceMetaInfo} with the given {@link Struct struct}. + * Inflates the {@code target} with the given {@link Struct struct}. * - * @param metadata the {@link Struct} metadata from where to retrieve and inflate the {@code serviceMetaInfo}. - * @param serviceMetaInfo the {@code serviceMetaInfo} to be inflated. + * @param metadata the {@link Struct} metadata from where to retrieve and inflate the {@code target}. + * @param target the {@code target} to be inflated. */ - public void inflate(final Struct metadata, final ServiceMetaInfo serviceMetaInfo) { + public void inflate(final Struct metadata, final Object target) { final Value empty = Value.newBuilder().setStringValue("-").build(); final Value root = Value.newBuilder().setStructValue(metadata).build(); - for (final Map.Entry entry : fieldNameMapping.entrySet()) { - final ServiceNameFormat serviceNameFormat = entry.getValue(); - final Object[] values = new String[serviceNameFormat.properties.size()]; - for (int i = 0; i < serviceNameFormat.properties.size(); i++) { + for (final Map.Entry entry : fieldNameMapping.entrySet()) { + final FieldFormat fieldFormat = entry.getValue(); + final Object[] values = new String[fieldFormat.properties.size()]; + for (int i = 0; i < fieldFormat.properties.size(); i++) { values[i] = "-"; // Give it a default value - final Property property = serviceNameFormat.properties.get(i); + final Property property = fieldFormat.properties.get(i); for (final Field field : property) { Value value = root; for (final String segment : field.dsvSegments) { @@ -171,26 +185,15 @@ public void inflate(final Struct metadata, final ServiceMetaInfo serviceMetaInfo break; } } - final String value = Strings.lenientFormat(serviceNameFormat.format, values); + final String value = Strings.lenientFormat(fieldFormat.format, values); if (!Strings.isNullOrEmpty(value)) { - fieldSetterMapping.get(entry.getKey()).accept(serviceMetaInfo, value); + fieldSetterMapping.get(entry.getKey()).accept(target, value); } } - final Map fieldsMap = metadata.getFieldsMap(); - final List tags = new ArrayList<>(); - if (fieldsMap.containsKey("NAME")) { - tags.add(new KeyValue("pod", fieldsMap.get("NAME").getStringValue())); - } - if (fieldsMap.containsKey("NAMESPACE")) { - tags.add(new KeyValue("namespace", fieldsMap.get("NAMESPACE").getStringValue())); - } - if (!tags.isEmpty()) { - serviceMetaInfo.setTags(tags); - } } @RequiredArgsConstructor - private static class ServiceNameFormat { + private static class FieldFormat { private final String format; private final List properties; diff --git a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/als/mx/FieldsHelperTest.java b/oap-server/server-library/library-util/src/test/java/org/apache/skywalking/oap/server/library/util/FieldsHelperTest.java similarity index 63% rename from oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/als/mx/FieldsHelperTest.java rename to oap-server/server-library/library-util/src/test/java/org/apache/skywalking/oap/server/library/util/FieldsHelperTest.java index 3ae6ac67e3dc..ed1e9d9efc9a 100644 --- a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/als/mx/FieldsHelperTest.java +++ b/oap-server/server-library/library-util/src/test/java/org/apache/skywalking/oap/server/library/util/FieldsHelperTest.java @@ -16,23 +16,21 @@ * */ -package org.apache.skywalking.oap.server.receiver.envoy.als.mx; +package org.apache.skywalking.oap.server.library.util; -import com.google.protobuf.util.JsonFormat; -import io.envoyproxy.envoy.service.accesslog.v3.StreamAccessLogsMessage; -import org.apache.skywalking.oap.server.receiver.envoy.als.ServiceMetaInfo; +import com.google.protobuf.Struct; +import com.google.protobuf.Value; +import lombok.Data; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.powermock.reflect.Whitebox; import java.io.ByteArrayInputStream; -import java.io.InputStreamReader; import java.util.Arrays; import java.util.Collection; -import static org.apache.skywalking.oap.server.receiver.envoy.als.k8s.K8SALSServiceMeshHTTPAnalysisTest.getResourceAsStream; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; public class FieldsHelperTest { public static Collection data() { @@ -77,22 +75,36 @@ public static Collection data() { @BeforeEach public void setUp() { - Whitebox.setInternalState(FieldsHelper.SINGLETON, "initialized", false); + Whitebox.setInternalState(FieldsHelper.forClass(ServiceInfo.class), "initialized", false); } @ParameterizedTest(name = "{0}") @MethodSource("data") public void testFormat(String mapping, String expectedServiceName, String expectedServiceInstanceName) throws Exception { - try (final InputStreamReader isr = new InputStreamReader(getResourceAsStream("field-helper.msg"))) { - final StreamAccessLogsMessage.Builder requestBuilder = StreamAccessLogsMessage.newBuilder(); - JsonFormat.parser().merge(isr, requestBuilder); - final ServiceMetaInfo info = new ServiceMetaInfo(); - FieldsHelper.SINGLETON.init(new ByteArrayInputStream(mapping.getBytes()), ServiceMetaInfo.class); - FieldsHelper.SINGLETON.inflate( - requestBuilder.getIdentifier().getNode().getMetadata(), - info - ); - assertThat(info.getServiceName()).isEqualTo(expectedServiceName); - } + final Struct.Builder builder = Struct.newBuilder(); + final Struct.Builder labelBuilder = Struct.newBuilder(); + labelBuilder.putFields("service.istio.io/canonical-name", Value.newBuilder().setStringValue("productpage").build()); + labelBuilder.putFields("version", Value.newBuilder().setStringValue("v1").build()); + labelBuilder.putFields("security.istio.io/tlsMode", Value.newBuilder().setStringValue("istio").build()); + labelBuilder.putFields("app", Value.newBuilder().setStringValue("whatever-differ-from-productpage").build()); + labelBuilder.putFields("service.istio.io/canonical-revision", Value.newBuilder().setStringValue("v1").build()); + labelBuilder.putFields("pod-template-hash", Value.newBuilder().setStringValue("65576bb7bf").build()); + labelBuilder.putFields("istio.io/rev", Value.newBuilder().setStringValue("default").build()); + builder.putFields("LABELS", Value.newBuilder().setStructValue(labelBuilder.build()).build()); + builder.putFields("CLUSTER_ID", Value.newBuilder().setStringValue("Kubernetes").build()); + + final ServiceInfo info = new ServiceInfo(); + FieldsHelper.forClass(ServiceInfo.class).init(new ByteArrayInputStream(mapping.getBytes())); + FieldsHelper.forClass(ServiceInfo.class).inflate( + builder.build(), + info + ); + assertThat(info.getServiceName()).isEqualTo(expectedServiceName); + } + + @Data + public static final class ServiceInfo { + private String serviceName; + private String serviceInstanceName; } } diff --git a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/EnvoyMetricReceiverProvider.java b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/EnvoyMetricReceiverProvider.java index 765b984315f9..f5ce2dc96cef 100644 --- a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/EnvoyMetricReceiverProvider.java +++ b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/EnvoyMetricReceiverProvider.java @@ -31,7 +31,7 @@ import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedException; import org.apache.skywalking.oap.server.library.server.ServerException; import org.apache.skywalking.oap.server.library.server.grpc.GRPCServer; -import org.apache.skywalking.oap.server.receiver.envoy.als.mx.FieldsHelper; +import org.apache.skywalking.oap.server.library.util.FieldsHelper; import org.apache.skywalking.oap.server.receiver.sharing.server.SharingServerModule; import org.apache.skywalking.oap.server.telemetry.TelemetryModule; @@ -72,7 +72,7 @@ public void onInitialized(final EnvoyMetricReceiverConfig initialized) { @Override public void prepare() throws ServiceNotProvidedException, ModuleStartException { try { - FieldsHelper.SINGLETON.init(fieldMappingFile, config.serviceMetaInfoFactory().clazz()); + FieldsHelper.forClass(config.serviceMetaInfoFactory().clazz()).init(fieldMappingFile); } catch (final Exception e) { throw new ModuleStartException("Failed to load metadata-service-mapping.yaml", e); } diff --git a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/als/mx/MetaExchangeALSHTTPAnalyzer.java b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/als/mx/MetaExchangeALSHTTPAnalyzer.java index 145e003b02df..c8b03e112e5d 100644 --- a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/als/mx/MetaExchangeALSHTTPAnalyzer.java +++ b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/als/mx/MetaExchangeALSHTTPAnalyzer.java @@ -26,6 +26,7 @@ import org.apache.skywalking.apm.network.servicemesh.v3.HTTPServiceMeshMetric; import org.apache.skywalking.oap.server.library.module.ModuleManager; import org.apache.skywalking.oap.server.library.module.ModuleStartException; +import org.apache.skywalking.oap.server.library.util.FieldsHelper; import org.apache.skywalking.oap.server.receiver.envoy.EnvoyMetricReceiverConfig; import org.apache.skywalking.oap.server.receiver.envoy.als.AbstractALSAnalyzer; import org.apache.skywalking.oap.server.receiver.envoy.als.Role; @@ -56,7 +57,7 @@ public String name() { public void init(ModuleManager manager, EnvoyMetricReceiverConfig config) throws ModuleStartException { this.config = config; try { - FieldsHelper.SINGLETON.init(fieldMappingFile, config.serviceMetaInfoFactory().clazz()); + FieldsHelper.forClass(config.serviceMetaInfoFactory().clazz()).init(fieldMappingFile); } catch (final Exception e) { throw new ModuleStartException("Failed to load metadata-service-mapping.yaml", e); } diff --git a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/als/mx/ServiceMetaInfoAdapter.java b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/als/mx/ServiceMetaInfoAdapter.java index 67da8a369d52..902b78a6ca17 100644 --- a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/als/mx/ServiceMetaInfoAdapter.java +++ b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/als/mx/ServiceMetaInfoAdapter.java @@ -26,8 +26,13 @@ import com.google.protobuf.Struct; import com.google.protobuf.Value; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.skywalking.oap.server.library.util.FieldsHelper; import org.apache.skywalking.oap.server.receiver.envoy.als.ServiceMetaInfo; import static com.google.common.base.Strings.nullToEmpty; @@ -60,7 +65,8 @@ public ServiceMetaInfoAdapter(final ByteString bv) throws Exception { } final Struct metadata = requireNonNull(extractStructFromNodeFlatBuffer(flatNode)); - FieldsHelper.SINGLETON.inflate(metadata, this); + FieldsHelper.forClass(this.getClass().getSuperclass()).inflate(metadata, this); + appendTags(metadata); } /** @@ -103,7 +109,22 @@ public static Struct extractStructFromNodeFlatBuffer(final FlatNode node) { * @param metadata the {@link Struct struct} to adapt from. */ public ServiceMetaInfoAdapter(final Struct metadata) { - FieldsHelper.SINGLETON.inflate(requireNonNull(metadata), this); + FieldsHelper.forClass(this.getClass().getSuperclass()).inflate(requireNonNull(metadata), this); + appendTags(requireNonNull(metadata)); + } + + private void appendTags(Struct metadata) { + final Map fieldsMap = metadata.getFieldsMap(); + final List tags = new ArrayList<>(); + if (fieldsMap.containsKey("NAME")) { + tags.add(new KeyValue("pod", fieldsMap.get("NAME").getStringValue())); + } + if (fieldsMap.containsKey("NAMESPACE")) { + tags.add(new KeyValue("namespace", fieldsMap.get("NAMESPACE").getStringValue())); + } + if (!tags.isEmpty()) { + this.setTags(tags); + } } } diff --git a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/als/tcp/mx/MetaExchangeTCPAccessLogAnalyzer.java b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/als/tcp/mx/MetaExchangeTCPAccessLogAnalyzer.java index 7f53439739c4..5d2e67835274 100644 --- a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/als/tcp/mx/MetaExchangeTCPAccessLogAnalyzer.java +++ b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/als/tcp/mx/MetaExchangeTCPAccessLogAnalyzer.java @@ -27,10 +27,10 @@ import org.apache.skywalking.apm.network.servicemesh.v3.TCPServiceMeshMetric; import org.apache.skywalking.oap.server.library.module.ModuleManager; import org.apache.skywalking.oap.server.library.module.ModuleStartException; +import org.apache.skywalking.oap.server.library.util.FieldsHelper; import org.apache.skywalking.oap.server.receiver.envoy.EnvoyMetricReceiverConfig; import org.apache.skywalking.oap.server.receiver.envoy.als.Role; import org.apache.skywalking.oap.server.receiver.envoy.als.ServiceMetaInfo; -import org.apache.skywalking.oap.server.receiver.envoy.als.mx.FieldsHelper; import org.apache.skywalking.oap.server.receiver.envoy.als.mx.ServiceMetaInfoAdapter; import org.apache.skywalking.oap.server.receiver.envoy.als.tcp.AbstractTCPAccessLogAnalyzer; @@ -57,7 +57,7 @@ public String name() { public void init(ModuleManager manager, EnvoyMetricReceiverConfig config) throws ModuleStartException { this.config = config; try { - FieldsHelper.SINGLETON.init(fieldMappingFile, config.serviceMetaInfoFactory().clazz()); + FieldsHelper.forClass(config.serviceMetaInfoFactory().clazz()).init(fieldMappingFile); } catch (final Exception e) { throw new ModuleStartException("Failed to load metadata-service-mapping.yaml", e); } diff --git a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/ClusterManagerMetricsAdapterTest.java b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/ClusterManagerMetricsAdapterTest.java index b79a141ba084..067721a0230a 100644 --- a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/ClusterManagerMetricsAdapterTest.java +++ b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/ClusterManagerMetricsAdapterTest.java @@ -20,7 +20,7 @@ import io.prometheus.client.Metrics; import lombok.SneakyThrows; -import org.apache.skywalking.oap.server.receiver.envoy.als.mx.FieldsHelper; +import org.apache.skywalking.oap.server.library.util.FieldsHelper; import org.apache.skywalking.oap.server.receiver.envoy.metrics.adapters.ClusterManagerMetricsAdapter; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -41,10 +41,10 @@ public class ClusterManagerMetricsAdapterTest { @SneakyThrows @BeforeEach public void setUp() { - Whitebox.setInternalState(FieldsHelper.SINGLETON, "initialized", false); + Whitebox.setInternalState(FieldsHelper.forClass(this.getClass()), "initialized", false); EnvoyMetricReceiverConfig config = new EnvoyMetricReceiverConfig(); clusterManagerMetricsAdapter = new ClusterManagerMetricsAdapter(config); - FieldsHelper.SINGLETON.init("metadata-service-mapping.yaml", config.serviceMetaInfoFactory().clazz()); + FieldsHelper.forClass(config.serviceMetaInfoFactory().clazz()).init("metadata-service-mapping.yaml"); } @Test diff --git a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/als/k8s/ServiceNameFormatterTest.java b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/als/k8s/FieldFormatterTest.java similarity index 99% rename from oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/als/k8s/ServiceNameFormatterTest.java rename to oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/als/k8s/FieldFormatterTest.java index 913048af147c..5bfab580afd5 100644 --- a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/als/k8s/ServiceNameFormatterTest.java +++ b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/als/k8s/FieldFormatterTest.java @@ -31,7 +31,7 @@ import static com.google.common.collect.ImmutableSortedMap.of; import static org.junit.jupiter.api.Assertions.assertEquals; -public class ServiceNameFormatterTest { +public class FieldFormatterTest { public static Case[] parameters() { return new Case[] { new Case( diff --git a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/resources/field-helper.msg b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/resources/field-helper.msg deleted file mode 100644 index d1901fb3c224..000000000000 --- a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/resources/field-helper.msg +++ /dev/null @@ -1,89 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -{ - "identifier": { - "node": { - "id": "sidecar~172.18.0.8~productpage-v1-65576bb7bf-4mzsp.default~default.svc.cluster.local", - "cluster": "productpage.default", - "metadata": { - "PROXY_CONFIG": { - "concurrency": 2.0, - "envoyAccessLogService": { - "address": "0.tcp.ngrok.io:13760" - }, - "statNameLength": 189.0, - "configPath": "./etc/istio/proxy", - "parentShutdownDuration": "60s", - "proxyAdminPort": 15000.0, - "controlPlaneAuthPolicy": "MUTUAL_TLS", - "drainDuration": "45s", - "proxyMetadata": { - "DNS_AGENT": "" - }, - "terminationDrainDuration": "5s", - "tracing": { - "zipkin": { - "address": "zipkin.istio-system:9411" - } - }, - "statusPort": 15020.0, - "serviceCluster": "productpage.default", - "envoyMetricsService": { - }, - "discoveryAddress": "istiod.istio-system.svc:15012", - "binaryPath": "/usr/local/bin/envoy" - }, - "PLATFORM_METADATA": { - "gcp_location": "us-central1-a", - "gcp_gce_instance_id": "2148869885222929334", - "gcp_gce_instance": "zhenxu-test", - "gcp_project_number": "191872121544", - "gcp_project": "skywalking-live-demo" - }, - "CLUSTER_ID": "Kubernetes", - "APP_CONTAINERS": "productpage", - "LABELS": { - "service.istio.io/canonical-name": "productpage", - "version": "v1", - "security.istio.io/tlsMode": "istio", - "app": "whatever-differ-from-productpage", - "service.istio.io/canonical-revision": "v1", - "pod-template-hash": "65576bb7bf", - "istio.io/rev": "default" - }, - "ISTIO_PROXY_SHA": "istio-proxy:262253d9d066f8ef7ed82fd175c28b8f95acbec0", - "NAME": "productpage-v1-65576bb7bf-4mzsp", - "NAMESPACE": "default", - "EXCHANGE_KEYS": "NAME,NAMESPACE,INSTANCE_IPS,LABELS,OWNER,PLATFORM_METADATA,WORKLOAD_NAME,MESH_ID,SERVICE_ACCOUNT,CLUSTER_ID", - "INSTANCE_IPS": "172.18.0.8", - "POD_PORTS": "[{\"containerPort\":9080,\"protocol\":\"TCP\"}]", - "INTERCEPTION_MODE": "REDIRECT", - "SERVICE_ACCOUNT": "bookinfo-productpage", - "MESH_ID": "cluster.local", - "SDS": "true", - "WORKLOAD_NAME": "productpage-v1", - "OWNER": "kubernetes://apis/apps/v1/namespaces/default/deployments/productpage-v1", - "ISTIO_VERSION": "1.7.1" - }, - "locality": { - "region": "us-central1", - "zone": "us-central1-a" - } - }, - "logName": "http_envoy_accesslog" - } -} diff --git a/oap-server/server-starter/pom.xml b/oap-server/server-starter/pom.xml index 62322988165c..7e07a73f4594 100644 --- a/oap-server/server-starter/pom.xml +++ b/oap-server/server-starter/pom.xml @@ -189,6 +189,11 @@ kafka-fetcher-plugin ${project.version} + + org.apache.skywalking + cilium-fetcher-plugin + ${project.version} + diff --git a/oap-server/server-starter/src/main/resources/application.yml b/oap-server/server-starter/src/main/resources/application.yml index c647418c462b..26eda39bbd8f 100644 --- a/oap-server/server-starter/src/main/resources/application.yml +++ b/oap-server/server-starter/src/main/resources/application.yml @@ -374,6 +374,18 @@ kafka-fetcher: kafkaHandlerThreadPoolSize: ${SW_KAFKA_HANDLER_THREAD_POOL_SIZE:-1} kafkaHandlerThreadPoolQueueSize: ${SW_KAFKA_HANDLER_THREAD_POOL_QUEUE_SIZE:-1} +cilium-fetcher: + selector: ${SW_CILIUM_FETCHER:-} + default: + peerHost: ${SW_CILIUM_FETCHER_PEER_HOST:hubble-peer.kube-system.svc.cluster.local} + peerPort: ${SW_CILIUM_FETCHER_PEER_PORT:80} + fetchFailureRetrySecond: ${SW_CILIUM_FETCHER_FETCH_FAILURE_RETRY_SECOND:10} + sslConnection: ${SW_CILIUM_FETCHER_SSL_CONNECTION:false} + sslPrivateKeyFile: ${SW_CILIUM_FETCHER_PRIVATE_KEY_FILE_PATH:} + sslCertChainFile: ${SW_CILIUM_FETCHER_CERT_CHAIN_FILE_PATH:} + sslCaFile: ${SW_CILIUM_FETCHER_CA_FILE_PATH:} + convertClientAsServerTraffic: ${SW_CILIUM_FETCHER_CONVERT_CLIENT_AS_SERVER_TRAFFIC:true} + receiver-meter: selector: ${SW_RECEIVER_METER:default} default: diff --git a/oap-server/server-starter/src/main/resources/component-libraries.yml b/oap-server/server-starter/src/main/resources/component-libraries.yml index 5234745e0875..25f44a98b969 100644 --- a/oap-server/server-starter/src/main/resources/component-libraries.yml +++ b/oap-server/server-starter/src/main/resources/component-libraries.yml @@ -526,6 +526,9 @@ OceanBase-jdbc-driver: SolonMVC: id: 158 languages: Java +DNS: + id: 159 + languages: ebpf # .NET/.NET Core components # [3000, 4000) for C#/.NET only diff --git a/oap-server/server-starter/src/main/resources/metadata-service-mapping.yaml b/oap-server/server-starter/src/main/resources/metadata-service-mapping.yaml index 2641a638e14b..cf9522b15041 100644 --- a/oap-server/server-starter/src/main/resources/metadata-service-mapping.yaml +++ b/oap-server/server-starter/src/main/resources/metadata-service-mapping.yaml @@ -13,5 +13,5 @@ # See the License for the specific language governing permissions and # limitations under the License. -serviceName: ${LABELS."service.istio.io/canonical-name",LABELS."app.kubernetes.io/name",LABELS.app}.${NAMESPACE} +serviceName: ${LABELS."service.istio.io/canonical-name",LABELS."app.kubernetes.io/name",LABELS.app,LABELS.k8s-app}.${NAMESPACE} serviceInstanceName: ${NAME} diff --git a/oap-server/server-starter/src/main/resources/oal/cilium.oal b/oap-server/server-starter/src/main/resources/oal/cilium.oal new file mode 100644 index 000000000000..b3c28ae853f2 --- /dev/null +++ b/oap-server/server-starter/src/main/resources/oal/cilium.oal @@ -0,0 +1,200 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Cilium Service +cilium_service_l4_read_pkg_cpm = from(CiliumService.*).filter(verdict == "forwarded").filter(type == "tcp").filter(direction == "ingress").cpm(); +cilium_service_l4_write_pkg_cpm = from(CiliumService.*).filter(verdict == "forwarded").filter(type == "tcp").filter(direction == "egress").cpm(); +cilium_service_l4_read_pkg_drop_cpm = from(CiliumService.*).filter(verdict == "dropped").filter(type == "tcp").filter(direction == "ingress").cpm(); +cilium_service_l4_write_pkg_drop_cpm = from(CiliumService.*).filter(verdict == "dropped").filter(type == "tcp").filter(direction == "egress").cpm(); +cilium_service_l4_drop_reason_count = from(CiliumService.*).filter(verdict == "dropped").filter(type == "tcp").labelCount(dropReason); +// Protocols of Service(Summary) +cilium_service_protocol_cpm = from(CiliumService.*).filter(verdict == "forwarded").filter(type != "tcp").filter(detectPoint == DetectPoint.SERVER).cpm(); +cilium_service_protocol_call_duration = from(CiliumService.duration).filter(verdict == "forwarded").filter(type != "tcp").filter(detectPoint == DetectPoint.SERVER).sum(); +cilium_service_protocol_call_success_count = from(CiliumService.*).filter(verdict == "forwarded").filter(type != "tcp").filter(detectPoint == DetectPoint.SERVER).filter(success == true).cpm(); +// Protocols of Service(HTTP) +cilium_service_protocol_http_call_cpm = from(CiliumService.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).cpm(); +cilium_service_protocol_http_call_duration = from(CiliumService.duration).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).sum(); +cilium_service_protocol_http_call_success_count = from(CiliumService.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(success == true).cpm(); +cilium_service_protocol_http_status_1xx_cpm = from(CiliumService.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(http.code >= 100).filter(http.code < 200).cpm(); +cilium_service_protocol_http_status_2xx_cpm = from(CiliumService.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(http.code >= 200).filter(http.code < 300).cpm(); +cilium_service_protocol_http_status_3xx_cpm = from(CiliumService.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(http.code >= 300).filter(http.code < 400).cpm(); +cilium_service_protocol_http_status_4xx_cpm = from(CiliumService.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(http.code >= 400).filter(http.code < 500).cpm(); +cilium_service_protocol_http_status_5xx_cpm = from(CiliumService.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(http.code >= 500).filter(http.code < 600).cpm(); +// Protocols of Service(DNS) +cilium_service_protocol_dns_call_cpm = from(CiliumService.*).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.SERVER).cpm(); +cilium_service_protocol_dns_call_duration = from(CiliumService.duration).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.SERVER).sum(); +cilium_service_protocol_dns_call_success_count = from(CiliumService.*).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.SERVER).filter(success == true).cpm(); +cilium_service_protocol_dns_error_count = from(CiliumService.*).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.SERVER).filter(success == false).labelCount(dns.rcodeString); +// Protocols of Service(Kafka) +cilium_service_protocol_kafka_call_cpm = from(CiliumService.*).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.SERVER).cpm(); +cilium_service_protocol_kafka_call_duration = from(CiliumService.duration).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.SERVER).sum(); +cilium_service_protocol_kafka_call_success_count = from(CiliumService.*).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.SERVER).filter(success == true).cpm(); +cilium_service_protocol_kafka_call_error_count = from(CiliumService.*).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.SERVER).filter(success == false).labelCount(kafka.errorCodeString); + +// Cilium Service Instance +cilium_service_instance_l4_read_pkg_cpm = from(CiliumServiceInstance.*).filter(verdict == "forwarded").filter(type == "tcp").filter(direction == "ingress").cpm(); +cilium_service_instance_l4_write_pkg_cpm = from(CiliumServiceInstance.*).filter(verdict == "forwarded").filter(type == "tcp").filter(direction == "egress").cpm(); +cilium_service_instance_l4_read_pkg_drop_cpm = from(CiliumServiceInstance.*).filter(verdict == "dropped").filter(type == "tcp").filter(direction == "ingress").cpm(); +cilium_service_instance_l4_write_pkg_drop_cpm = from(CiliumServiceInstance.*).filter(verdict == "dropped").filter(type == "tcp").filter(direction == "egress").cpm(); +cilium_service_instance_l4_drop_reason_count = from(CiliumServiceInstance.*).filter(verdict == "dropped").filter(type == "tcp").labelCount(dropReason); +// Protocols of Service Instance(Summary) +cilium_service_instance_protocol_cpm = from(CiliumServiceInstance.*).filter(verdict == "forwarded").filter(type != "tcp").filter(detectPoint == DetectPoint.SERVER).cpm(); +cilium_service_instance_protocol_call_duration = from(CiliumServiceInstance.duration).filter(verdict == "forwarded").filter(type != "tcp").filter(detectPoint == DetectPoint.SERVER).sum(); +cilium_service_instance_protocol_call_success_count = from(CiliumServiceInstance.*).filter(verdict == "forwarded").filter(type != "tcp").filter(detectPoint == DetectPoint.SERVER).filter(success == true).cpm(); +// Protocols of Service Instance(HTTP) +cilium_service_instance_protocol_http_call_cpm = from(CiliumServiceInstance.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).cpm(); +cilium_service_instance_protocol_http_call_duration = from(CiliumServiceInstance.duration).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).sum(); +cilium_service_instance_protocol_http_call_success_count = from(CiliumServiceInstance.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(success == true).cpm(); +cilium_service_instance_protocol_http_status_1xx_cpm = from(CiliumServiceInstance.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(http.code >= 100).filter(http.code < 200).cpm(); +cilium_service_instance_protocol_http_status_2xx_cpm = from(CiliumServiceInstance.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(http.code >= 200).filter(http.code < 300).cpm(); +cilium_service_instance_protocol_http_status_3xx_cpm = from(CiliumServiceInstance.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(http.code >= 300).filter(http.code < 400).cpm(); +cilium_service_instance_protocol_http_status_4xx_cpm = from(CiliumServiceInstance.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(http.code >= 400).filter(http.code < 500).cpm(); +cilium_service_instance_protocol_http_status_5xx_cpm = from(CiliumServiceInstance.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(http.code >= 500).filter(http.code < 600).cpm(); +// Protocols of Service Instance(DNS) +cilium_service_instance_protocol_dns_call_cpm = from(CiliumServiceInstance.*).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.SERVER).cpm(); +cilium_service_instance_protocol_dns_call_duration = from(CiliumServiceInstance.duration).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.SERVER).sum(); +cilium_service_instance_protocol_dns_call_success_count = from(CiliumServiceInstance.*).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.SERVER).filter(success == true).cpm(); +cilium_service_instance_protocol_dns_error_count = from(CiliumServiceInstance.*).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.SERVER).filter(success == false).labelCount(dns.rcodeString); +// Protocols of Service Instance(Kafka) +cilium_service_instance_protocol_kafka_call_cpm = from(CiliumServiceInstance.*).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.SERVER).cpm(); +cilium_service_instance_protocol_kafka_call_duration = from(CiliumServiceInstance.duration).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.SERVER).sum(); +cilium_service_instance_protocol_kafka_call_success_count = from(CiliumServiceInstance.*).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.SERVER).filter(success == true).cpm(); +cilium_service_instance_protocol_kafka_call_error_count = from(CiliumServiceInstance.*).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.SERVER).filter(success == false).labelCount(kafka.errorCodeString); + +// Cilium Endpoint +// Protocols of Endpoint(Summary) +cilium_endpoint_protocol_cpm = from(CiliumEndpoint.*).filter(verdict == "forwarded").filter(type != "tcp").cpm(); +cilium_endpoint_protocol_call_duration = from(CiliumEndpoint.duration).filter(verdict == "forwarded").filter(type != "tcp").sum(); +cilium_endpoint_protocol_call_success_count = from(CiliumEndpoint.*).filter(verdict == "forwarded").filter(type != "tcp").filter(success == true).cpm(); +// Protocols of Endpoint(HTTP) +cilium_endpoint_protocol_http_call_cpm = from(CiliumEndpoint.*).filter(verdict == "forwarded").filter(type == "http").cpm(); +cilium_endpoint_protocol_http_call_duration = from(CiliumEndpoint.duration).filter(verdict == "forwarded").filter(type == "http").sum(); +cilium_endpoint_protocol_http_call_success_count = from(CiliumEndpoint.*).filter(verdict == "forwarded").filter(type == "http").filter(success == true).cpm(); +cilium_endpoint_protocol_http_status_1xx_cpm = from(CiliumEndpoint.*).filter(verdict == "forwarded").filter(type == "http").filter(http.code >= 100).filter(http.code < 200).cpm(); +cilium_endpoint_protocol_http_status_2xx_cpm = from(CiliumEndpoint.*).filter(verdict == "forwarded").filter(type == "http").filter(http.code >= 200).filter(http.code < 300).cpm(); +cilium_endpoint_protocol_http_status_3xx_cpm = from(CiliumEndpoint.*).filter(verdict == "forwarded").filter(type == "http").filter(http.code >= 300).filter(http.code < 400).cpm(); +cilium_endpoint_protocol_http_status_4xx_cpm = from(CiliumEndpoint.*).filter(verdict == "forwarded").filter(type == "http").filter(http.code >= 400).filter(http.code < 500).cpm(); +cilium_endpoint_protocol_http_status_5xx_cpm = from(CiliumEndpoint.*).filter(verdict == "forwarded").filter(type == "http").filter(http.code >= 500).filter(http.code < 600).cpm(); +// Protocols of Endpoint(DNS) +cilium_endpoint_protocol_dns_call_cpm = from(CiliumEndpoint.*).filter(verdict == "forwarded").filter(type == "dns").cpm(); +cilium_endpoint_protocol_dns_call_duration = from(CiliumEndpoint.duration).filter(verdict == "forwarded").filter(type == "dns").sum(); +cilium_endpoint_protocol_dns_call_success_count = from(CiliumEndpoint.*).filter(verdict == "forwarded").filter(type == "dns").filter(success == true).cpm(); +cilium_endpoint_protocol_dns_error_count = from(CiliumEndpoint.*).filter(verdict == "forwarded").filter(type == "dns").filter(success == false).labelCount(dns.rcodeString); +// Protocols of Endpoint(Kafka) +cilium_endpoint_protocol_kafka_call_cpm = from(CiliumEndpoint.*).filter(verdict == "forwarded").filter(type == "kafka").cpm(); +cilium_endpoint_protocol_kafka_call_duration = from(CiliumEndpoint.duration).filter(verdict == "forwarded").filter(type == "kafka").sum(); +cilium_endpoint_protocol_kafka_call_success_count = from(CiliumEndpoint.*).filter(verdict == "forwarded").filter(type == "kafka").filter(success == true).cpm(); +cilium_endpoint_protocol_kafka_call_error_count = from(CiliumEndpoint.*).filter(verdict == "forwarded").filter(type == "kafka").filter(success == false).labelCount(kafka.errorCodeString); + +// Cilium Service Relation +cilium_service_relation_client_l4_read_pkg_cpm = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "tcp").filter(detectPoint == DetectPoint.CLIENT).filter(direction == "ingress").cpm(); +cilium_service_relation_client_l4_write_pkg_cpm = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "tcp").filter(detectPoint == DetectPoint.CLIENT).filter(direction == "egress").cpm(); +cilium_service_relation_client_l4_read_pkg_drop_cpm = from(CiliumServiceRelation.*).filter(verdict == "dropped").filter(type == "tcp").filter(detectPoint == DetectPoint.CLIENT).filter(direction == "ingress").cpm(); +cilium_service_relation_client_l4_write_pkg_drop_cpm = from(CiliumServiceRelation.*).filter(verdict == "dropped").filter(type == "tcp").filter(detectPoint == DetectPoint.CLIENT).filter(direction == "egress").cpm(); +cilium_service_relation_client_l4_drop_reason_count = from(CiliumServiceRelation.*).filter(verdict == "dropped").filter(type == "tcp").filter(detectPoint == DetectPoint.CLIENT).labelCount(dropReason); +cilium_service_relation_server_l4_read_pkg_cpm = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "tcp").filter(detectPoint == DetectPoint.SERVER).filter(direction == "ingress").cpm(); +cilium_service_relation_server_l4_write_pkg_cpm = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "tcp").filter(detectPoint == DetectPoint.SERVER).filter(direction == "egress").cpm(); +cilium_service_relation_server_l4_read_pkg_drop_cpm = from(CiliumServiceRelation.*).filter(verdict == "dropped").filter(type == "tcp").filter(detectPoint == DetectPoint.SERVER).filter(direction == "ingress").cpm(); +cilium_service_relation_server_l4_write_pkg_drop_cpm = from(CiliumServiceRelation.*).filter(verdict == "dropped").filter(type == "tcp").filter(detectPoint == DetectPoint.SERVER).filter(direction == "egress").cpm(); +cilium_service_relation_server_l4_drop_reason_count = from(CiliumServiceRelation.*).filter(verdict == "dropped").filter(type == "tcp").filter(detectPoint == DetectPoint.SERVER).labelCount(dropReason); +// Protocols of Service Relation(Summary) +cilium_service_relation_client_protocol_cpm = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type != "tcp").filter(detectPoint == DetectPoint.CLIENT).cpm(); +cilium_service_relation_client_protocol_call_duration = from(CiliumServiceRelation.duration).filter(verdict == "forwarded").filter(type != "tcp").filter(detectPoint == DetectPoint.CLIENT).sum(); +cilium_service_relation_client_protocol_call_success_count = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type != "tcp").filter(detectPoint == DetectPoint.CLIENT).filter(success == true).cpm(); +cilium_service_relation_server_protocol_cpm = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type != "tcp").filter(detectPoint == DetectPoint.SERVER).cpm(); +cilium_service_relation_server_protocol_call_duration = from(CiliumServiceRelation.duration).filter(verdict == "forwarded").filter(type != "tcp").filter(detectPoint == DetectPoint.SERVER).sum(); +cilium_service_relation_server_protocol_call_success_count = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type != "tcp").filter(detectPoint == DetectPoint.SERVER).filter(success == true).cpm(); +// Protocols of Service Relation(HTTP) +cilium_service_relation_client_protocol_http_call_cpm = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.CLIENT).cpm(); +cilium_service_relation_client_protocol_http_call_duration = from(CiliumServiceRelation.duration).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.CLIENT).sum(); +cilium_service_relation_client_protocol_http_call_success_count = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.CLIENT).filter(success == true).cpm(); +cilium_service_relation_server_protocol_http_call_cpm = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).cpm(); +cilium_service_relation_server_protocol_http_call_duration = from(CiliumServiceRelation.duration).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).sum(); +cilium_service_relation_server_protocol_http_call_success_count = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(success == true).cpm(); +cilium_service_relation_protocol_http_status_1xx_cpm = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(http.code >= 100).filter(http.code < 200).cpm(); +cilium_service_relation_protocol_http_status_2xx_cpm = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(http.code >= 200).filter(http.code < 300).cpm(); +cilium_service_relation_protocol_http_status_3xx_cpm = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(http.code >= 300).filter(http.code < 400).cpm(); +cilium_service_relation_protocol_http_status_4xx_cpm = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(http.code >= 400).filter(http.code < 500).cpm(); +cilium_service_relation_protocol_http_status_5xx_cpm = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(http.code >= 500).filter(http.code < 600).cpm(); +// Protocols of Service Relation(DNS) +cilium_service_relation_client_protocol_dns_call_cpm = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.CLIENT).cpm(); +cilium_service_relation_client_protocol_dns_call_duration = from(CiliumServiceRelation.duration).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.CLIENT).sum(); +cilium_service_relation_client_protocol_dns_call_success_count = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.CLIENT).filter(success == true).cpm(); +cilium_service_relation_client_protocol_dns_error_count = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.CLIENT).filter(success == false).labelCount(dns.rcodeString); +cilium_service_relation_server_protocol_dns_call_cpm = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.SERVER).cpm(); +cilium_service_relation_server_protocol_dns_call_duration = from(CiliumServiceRelation.duration).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.SERVER).sum(); +cilium_service_relation_server_protocol_dns_call_success_count = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.SERVER).filter(success == true).cpm(); +cilium_service_relation_server_protocol_dns_error_count = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.SERVER).filter(success == false).labelCount(dns.rcodeString); +// Protocols of Service Relation(Kafka) +cilium_service_relation_client_protocol_kafka_call_cpm = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.CLIENT).cpm(); +cilium_service_relation_client_protocol_kafka_call_duration = from(CiliumServiceRelation.duration).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.CLIENT).sum(); +cilium_service_relation_client_protocol_kafka_call_success_count = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.CLIENT).filter(success == true).cpm(); +cilium_service_relation_client_protocol_kafka_call_error_count = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.CLIENT).filter(success == false).labelCount(kafka.errorCodeString); +cilium_service_relation_server_protocol_kafka_call_cpm = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.SERVER).cpm(); +cilium_service_relation_server_protocol_kafka_call_duration = from(CiliumServiceRelation.duration).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.SERVER).sum(); +cilium_service_relation_server_protocol_kafka_call_success_count = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.SERVER).filter(success == true).cpm(); +cilium_service_relation_server_protocol_kafka_call_error_count = from(CiliumServiceRelation.*).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.SERVER).filter(success == false).labelCount(kafka.errorCodeString); + +// Cilium Service Instance Relation +cilium_service_instance_relation_client_l4_read_pkg_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "tcp").filter(detectPoint == DetectPoint.CLIENT).filter(direction == "ingress").cpm(); +cilium_service_instance_relation_client_l4_write_pkg_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "tcp").filter(detectPoint == DetectPoint.CLIENT).filter(direction == "egress").cpm(); +cilium_service_instance_relation_client_l4_read_pkg_drop_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "dropped").filter(type == "tcp").filter(detectPoint == DetectPoint.CLIENT).filter(direction == "ingress").cpm(); +cilium_service_instance_relation_client_l4_write_pkg_drop_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "dropped").filter(type == "tcp").filter(detectPoint == DetectPoint.CLIENT).filter(direction == "egress").cpm(); +cilium_service_instance_relation_client_l4_drop_reason_count = from(CiliumServiceInstanceRelation.*).filter(verdict == "dropped").filter(type == "tcp").filter(detectPoint == DetectPoint.CLIENT).labelCount(dropReason); +cilium_service_instance_relation_server_l4_read_pkg_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "tcp").filter(detectPoint == DetectPoint.SERVER).filter(direction == "ingress").cpm(); +cilium_service_instance_relation_server_l4_write_pkg_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "tcp").filter(detectPoint == DetectPoint.SERVER).filter(direction == "egress").cpm(); +cilium_service_instance_relation_server_l4_read_pkg_drop_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "dropped").filter(type == "tcp").filter(detectPoint == DetectPoint.SERVER).filter(direction == "ingress").cpm(); +cilium_service_instance_relation_server_l4_write_pkg_drop_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "dropped").filter(type == "tcp").filter(detectPoint == DetectPoint.SERVER).filter(direction == "egress").cpm(); +cilium_service_instance_relation_server_l4_drop_reason_count = from(CiliumServiceInstanceRelation.*).filter(verdict == "dropped").filter(type == "tcp").filter(detectPoint == DetectPoint.SERVER).labelCount(dropReason); +// Protocols of Service Instance Relation(Summary) +cilium_service_instance_relation_client_protocol_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type != "tcp").filter(detectPoint == DetectPoint.CLIENT).cpm(); +cilium_service_instance_relation_client_protocol_call_duration = from(CiliumServiceInstanceRelation.duration).filter(verdict == "forwarded").filter(type != "tcp").filter(detectPoint == DetectPoint.CLIENT).sum(); +cilium_service_instance_relation_client_protocol_call_success_count = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type != "tcp").filter(detectPoint == DetectPoint.CLIENT).filter(success == true).cpm(); +cilium_service_instance_relation_server_protocol_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type != "tcp").filter(detectPoint == DetectPoint.SERVER).cpm(); +cilium_service_instance_relation_server_protocol_call_duration = from(CiliumServiceInstanceRelation.duration).filter(verdict == "forwarded").filter(type != "tcp").filter(detectPoint == DetectPoint.SERVER).sum(); +cilium_service_instance_relation_server_protocol_call_success_count = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type != "tcp").filter(detectPoint == DetectPoint.SERVER).filter(success == true).cpm(); +// Protocols of Service Instance Relation(HTTP) +cilium_service_instance_relation_client_protocol_http_call_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.CLIENT).cpm(); +cilium_service_instance_relation_client_protocol_http_call_duration = from(CiliumServiceInstanceRelation.duration).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.CLIENT).sum(); +cilium_service_instance_relation_client_protocol_http_call_success_count = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.CLIENT).filter(success == true).cpm(); +cilium_service_instance_relation_server_protocol_http_call_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).cpm(); +cilium_service_instance_relation_server_protocol_http_call_duration = from(CiliumServiceInstanceRelation.duration).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).sum(); +cilium_service_instance_relation_server_protocol_http_call_success_count = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(success == true).cpm(); +cilium_service_instance_relation_protocol_http_status_1xx_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(http.code >= 100).filter(http.code < 200).cpm(); +cilium_service_instance_relation_protocol_http_status_2xx_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(http.code >= 200).filter(http.code < 300).cpm(); +cilium_service_instance_relation_protocol_http_status_3xx_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(http.code >= 300).filter(http.code < 400).cpm(); +cilium_service_instance_relation_protocol_http_status_4xx_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(http.code >= 400).filter(http.code < 500).cpm(); +cilium_service_instance_relation_protocol_http_status_5xx_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "http").filter(detectPoint == DetectPoint.SERVER).filter(http.code >= 500).filter(http.code < 600).cpm(); +// Protocols of Service Instance Relation(DNS) +cilium_service_instance_relation_client_protocol_dns_call_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.CLIENT).cpm(); +cilium_service_instance_relation_client_protocol_dns_call_duration = from(CiliumServiceInstanceRelation.duration).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.CLIENT).sum(); +cilium_service_instance_relation_client_protocol_dns_call_success_count = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.CLIENT).filter(success == true).cpm(); +cilium_service_instance_relation_client_protocol_dns_error_count = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.CLIENT).filter(success == false).labelCount(dns.rcodeString); +cilium_service_instance_relation_server_protocol_dns_call_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.SERVER).cpm(); +cilium_service_instance_relation_server_protocol_dns_call_duration = from(CiliumServiceInstanceRelation.duration).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.SERVER).sum(); +cilium_service_instance_relation_server_protocol_dns_call_success_count = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.SERVER).filter(success == true).cpm(); +cilium_service_instance_relation_server_protocol_dns_error_count = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "dns").filter(detectPoint == DetectPoint.SERVER).filter(success == false).labelCount(dns.rcodeString); +// Protocols of Service Instance Relation(Kafka) +cilium_service_instance_relation_client_protocol_kafka_call_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.CLIENT).cpm(); +cilium_service_instance_relation_client_protocol_kafka_call_duration = from(CiliumServiceInstanceRelation.duration).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.CLIENT).sum(); +cilium_service_instance_relation_client_protocol_kafka_call_success_count = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.CLIENT).filter(success == true).cpm(); +cilium_service_instance_relation_client_protocol_kafka_call_error_count = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.CLIENT).filter(success == false).labelCount(kafka.errorCodeString); +cilium_service_instance_relation_server_protocol_kafka_call_cpm = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.SERVER).cpm(); +cilium_service_instance_relation_server_protocol_kafka_call_duration = from(CiliumServiceInstanceRelation.duration).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.SERVER).sum(); +cilium_service_instance_relation_server_protocol_kafka_call_success_count = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.SERVER).filter(success == true).cpm(); +cilium_service_instance_relation_server_protocol_kafka_call_error_count = from(CiliumServiceInstanceRelation.*).filter(verdict == "forwarded").filter(type == "kafka").filter(detectPoint == DetectPoint.SERVER).filter(success == false).labelCount(kafka.errorCodeString); diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-endpoint.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-endpoint.json new file mode 100644 index 000000000000..fa20e1aa975e --- /dev/null +++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-endpoint.json @@ -0,0 +1,304 @@ +[ + { + "id": "71d6fd5c-d53d-49e8-8bef-d808ef3495f1", + "configuration": { + "children": [ + { + "x": 0, + "y": 0, + "w": 24, + "h": 48, + "i": "0", + "type": "Tab", + "children": [ + { + "name": "Overview", + "children": [ + { + "x": 0, + "y": 0, + "w": 6, + "h": 12, + "i": "4", + "type": "Widget", + "expressions": [ + "cilium_endpoint_protocol_http_call_cpm", + "cilium_endpoint_protocol_http_call_success_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "HTTP Load(Call per min)" + }, + "metricConfig": [ + { + "label": "Total Count" + }, + { + "label": "Success Count" + } + ] + }, + { + "x": 6, + "y": 0, + "w": 6, + "h": 12, + "i": "5", + "type": "Widget", + "expressions": [ + "cilium_endpoint_protocol_http_call_duration/cilium_endpoint_protocol_http_call_cpm/1000000" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "HTTP Duration(ms)" + }, + "metricConfig": [ + { + "label": "duration" + } + ] + }, + { + "x": 12, + "y": 0, + "w": 12, + "h": 12, + "i": "6", + "type": "Widget", + "expressions": [ + "cilium_endpoint_protocol_http_status_1xx_cpm", + "cilium_endpoint_protocol_http_status_2xx_cpm", + "cilium_endpoint_protocol_http_status_3xx_cpm", + "cilium_endpoint_protocol_http_status_4xx_cpm", + "cilium_endpoint_protocol_http_status_5xx_cpm" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "metricConfig": [ + { + "label": "1xx" + }, + { + "label": "2xx" + }, + { + "label": "3xx" + }, + { + "label": "4xx" + }, + { + "label": "5xx" + } + ], + "widget": { + "title": "HTTP Response Code(Count per min)" + } + }, + { + "x": 0, + "y": 12, + "w": 6, + "h": 12, + "i": "7", + "type": "Widget", + "expressions": [ + "cilium_endpoint_protocol_dns_call_cpm", + "cilium_endpoint_protocol_dns_call_success_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "DNS Load(Call per min)" + }, + "metricConfig": [ + { + "label": "Total Count" + }, + { + "label": "Success Count" + } + ] + }, + { + "x": 6, + "y": 12, + "w": 6, + "h": 12, + "i": "8", + "type": "Widget", + "expressions": [ + "cilium_endpoint_protocol_dns_call_duration/cilium_endpoint_protocol_dns_call_cpm/1000000" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "DNS Duration(ms)" + }, + "metricConfig": [ + { + "label": "duration" + } + ] + }, + { + "x": 12, + "y": 12, + "w": 12, + "h": 12, + "i": "9", + "type": "Widget", + "expressions": [ + "cilium_endpoint_protocol_dns_error_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "DNS Error(Count per min)" + } + }, + { + "x": 0, + "y": 24, + "w": 6, + "h": 12, + "i": "10", + "type": "Widget", + "expressions": [ + "cilium_endpoint_protocol_kafka_call_cpm", + "cilium_endpoint_protocol_kafka_call_success_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "Kafka Load(Operation per min)" + }, + "metricConfig": [ + { + "label": "Total Count" + }, + { + "label": "Success Count" + } + ] + }, + { + "x": 6, + "y": 24, + "w": 6, + "h": 12, + "i": "11", + "type": "Widget", + "expressions": [ + "cilium_endpoint_protocol_kafka_call_duration/cilium_endpoint_protocol_kafka_call_cpm/1000000" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "Kafka Operation Duration(ms)" + }, + "metricConfig": [ + { + "label": "duration" + } + ] + }, + { + "x": 12, + "y": 24, + "w": 12, + "h": 12, + "i": "12", + "type": "Widget", + "expressions": [ + "cilium_endpoint_protocol_kafka_call_error_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "Kafka Operation Error(Count per min)" + } + } + ] + }, + { + "name": "Topology", + "children": [ + { + "x": 0, + "y": 0, + "w": 24, + "h": 48, + "i": "0", + "type": "Topology", + "graph": { + "showDepth": true + } + } + ] + } + ] + } + ], + "layer": "CILIUM_SERVICE", + "entity": "Endpoint", + "name": "Cilium-Endpoint" + } + } +] \ No newline at end of file diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-root.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-root.json new file mode 100644 index 000000000000..489260fe8e38 --- /dev/null +++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-root.json @@ -0,0 +1,167 @@ +[ + { + "id": "Cilium-Root", + "configuration": { + "children": [ + { + "x": 0, + "y": 0, + "w": 24, + "h": 2, + "i": "100", + "type": "Text", + "graph": { + "fontColor": "theme", + "backgroundColor": "theme", + "content": "Observing services through flow data in hubble", + "fontSize": 14, + "textAlign": "left", + "url": "" + } + }, + { + "x": 0, + "y": 2, + "w": 24, + "h": 52, + "i": "1", + "type": "Tab", + "children": [ + { + "name": "Service", + "children": [ + { + "x": 0, + "y": 0, + "w": 24, + "h": 48, + "i": "0", + "type": "Widget", + "graph": { + "type": "ServiceList", + "dashboardName": "Cilium-Service", + "fontSize": 12, + "showXAxis": false, + "showYAxis": false, + "showGroup": true + }, + "metricConfig": [ + { + "label": "Load", + "unit": "calls / min", + "detailLabel": "load" + }, + { + "label": "Success Rate", + "unit": "%", + "detailLabel": "success_rate" + }, + { + "label": "Latency", + "unit": "ms", + "detailLabel": "latency" + } + ], + "expressions": [ + "avg(cilium_service_protocol_cpm)", + "avg(cilium_service_protocol_call_success_count/cilium_service_protocol_cpm)*100", + "avg(cilium_service_protocol_call_duration/cilium_service_protocol_cpm)/1000000" + ] + } + ] + }, + { + "name": "Topology", + "children": [ + { + "x": 0, + "y": 0, + "w": 24, + "h": 48, + "i": "0", + "type": "Topology", + "graph": { + "showDepth": true + }, + "linkDashboard": "Cilium-Service-Relation", + "nodeDashboard": [ + + ], + "linkServerExpressions": [ + "avg(cilium_service_relation_server_l4_read_pkg_cpm)", + "avg(cilium_service_relation_server_l4_write_pkg_cpm)", + "avg(cilium_service_relation_server_protocol_cpm)", + "avg(cilium_service_relation_server_protocol_call_duration/cilium_service_relation_server_protocol_cpm)/1000000" + ], + "linkClientExpressions": [ + ], + "nodeExpressions": [ + "avg(cilium_service_l4_read_pkg_cpm)", + "avg(cilium_service_l4_write_pkg_cpm)", + "avg(cilium_service_protocol_cpm)", + "avg(cilium_service_protocol_call_duration/cilium_service_protocol_cpm)/1000000", + "avg(cilium_service_protocol_call_success_count/cilium_service_protocol_cpm*100)" + ], + "legendMQE": { + "expression": "(avg(cilium_service_protocol_call_success_count / cilium_service_protocol_cpm*100) < 95) * (avg(cilium_service_protocol_cpm) > 1) == 1" + }, + "description": { + "healthy": "Healthy", + "unhealthy": "Success Rate < 95% and HTTP Traffic > 1 calls / min" + }, + "linkServerMetricConfig": [ + { + "unit": "Count / min", + "label": "Server Read Package" + }, + { + "unit": "Count / min", + "label": "Server Write Package" + }, + { + "unit": "calls / min", + "label": "Server Load" + }, + { + "label": "Server Latency", + "unit": "ms" + } + ], + "linkClientMetricConfig": [ + ], + "nodeMetricConfig": [ + { + "label": "Read", + "unit": "package / min" + }, + { + "unit": "package / min", + "label": "Write" + }, + { + "label": "Load", + "unit": "calls / min" + }, + { + "label": "Latency", + "unit": "ms" + }, + { + "label": "Success Rate", + "unit": "%" + } + ] + } + ] + } + ] + } + ], + "layer": "CILIUM_SERVICE", + "entity": "All", + "name": "Cilium-Root", + "isRoot": true, + "path": "/Cilium/Service" + } + } +] \ No newline at end of file diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-service-instance-relation.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-service-instance-relation.json new file mode 100644 index 000000000000..f37596df9575 --- /dev/null +++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-service-instance-relation.json @@ -0,0 +1,395 @@ +[ + { + "id": "0a792b86-23e7-4ccc-a0a8-2efb093479bc", + "configuration": { + "children": [ + { + "x": 0, + "y": 0, + "w": 24, + "h": 52, + "i": "0", + "type": "Tab", + "children": [ + { + "name": "Overview", + "children": [ + { + "x": 0, + "y": 0, + "w": 6, + "h": 12, + "i": "2", + "type": "Widget", + "expressions": [ + "cilium_service_instance_relation_server_l4_read_pkg_cpm" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "L4 Read Package Server Side(Count per min)" + }, + "metricConfig": [ + { + "label": "Read Package" + } + ] + }, + { + "x": 6, + "y": 0, + "w": 6, + "h": 12, + "i": "3", + "type": "Widget", + "expressions": [ + "cilium_service_instance_relation_server_l4_write_pkg_cpm" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "L4 Write Package Server Side(Count per min)" + }, + "metricConfig": [ + { + "label": "Write Package" + } + ] + }, + { + "x": 0, + "y": 12, + "w": 6, + "h": 12, + "i": "6", + "type": "Widget", + "expressions": [ + "cilium_service_instance_relation_server_protocol_http_call_cpm", + "cilium_service_instance_relation_server_protocol_http_call_success_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "HTTP Load Server Side(Count per min)" + }, + "metricConfig": [ + { + "label": "Total Count" + }, + { + "label": "Success Count" + } + ] + }, + { + "x": 6, + "y": 12, + "w": 6, + "h": 12, + "i": "7", + "type": "Widget", + "expressions": [ + "cilium_service_instance_relation_server_protocol_http_call_duration/cilium_service_instance_relation_server_protocol_http_call_cpm/1000000" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "HTTP Response Duration Server Side(ms)" + }, + "metricConfig": [ + { + "label": "duration" + } + ] + }, + { + "x": 0, + "y": 24, + "w": 6, + "h": 12, + "i": "10", + "type": "Widget", + "expressions": [ + "cilium_service_instance_relation_server_protocol_dns_call_cpm", + "cilium_service_instance_relation_server_protocol_dns_call_success_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "DNS Load Server Side(Count per min)" + }, + "metricConfig": [ + { + "label": "Total Count" + }, + { + "label": "Success Count" + } + ] + }, + { + "x": 6, + "y": 24, + "w": 6, + "h": 12, + "i": "11", + "type": "Widget", + "expressions": [ + "cilium_service_instance_relation_server_protocol_dns_call_duration/cilium_service_instance_relation_server_protocol_dns_call_cpm/1000000" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "DNS Response Duration Server Side(ms)" + }, + "metricConfig": [ + { + "label": "duration" + } + ] + }, + { + "x": 0, + "y": 36, + "w": 6, + "h": 12, + "i": "14", + "type": "Widget", + "expressions": [ + "cilium_service_instance_relation_server_protocol_kafka_call_cpm", + "cilium_service_instance_relation_server_protocol_kafka_call_success_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "Kakfa Load Server Side(Count per min)" + }, + "metricConfig": [ + { + "label": "Total Count" + }, + { + "label": "Success Count" + } + ] + }, + { + "x": 6, + "y": 36, + "w": 6, + "h": 12, + "i": "15", + "type": "Widget", + "expressions": [ + "cilium_service_instance_relation_server_protocol_kafka_call_duration/cilium_service_instance_relation_server_protocol_kafka_call_cpm/1000000" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "Kafka Response Duration Server Side(ms)" + }, + "metricConfig": [ + { + "label": "duration" + } + ] + }, + { + "x": 12, + "y": 0, + "w": 6, + "h": 12, + "i": "16", + "type": "Widget", + "expressions": [ + "cilium_service_instance_relation_server_l4_read_pkg_drop_cpm", + "cilium_service_instance_relation_server_l4_write_pkg_drop_cpm" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "TCP Drop Package Server Side(Count Per Min)" + }, + "metricConfig": [ + { + "label": "Drop Read Package Count" + }, + { + "label": "Drop Write Package Count" + } + ] + }, + { + "x": 18, + "y": 0, + "w": 6, + "h": 12, + "i": "17", + "type": "Widget", + "expressions": [ + "cilium_service_instance_relation_server_l4_drop_reason_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "Tcp Drop Package Reason Server Side(Count Per min)" + } + }, + { + "x": 12, + "y": 12, + "w": 12, + "h": 12, + "i": "18", + "type": "Widget", + "expressions": [ + "cilium_service_instance_relation_protocol_http_status_1xx_cpm", + "cilium_service_instance_relation_protocol_http_status_2xx_cpm", + "cilium_service_instance_relation_protocol_http_status_3xx_cpm", + "cilium_service_instance_relation_protocol_http_status_4xx_cpm", + "cilium_service_instance_relation_protocol_http_status_5xx_cpm" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "HTTP Response Status Server Side(Count Per Min)" + }, + "metricConfig": [ + { + "label": "1xx" + }, + { + "label": "2xx" + }, + { + "label": "3xx" + }, + { + "label": "4xx" + }, + { + "label": "5xx" + } + ] + }, + { + "x": 12, + "y": 24, + "w": 12, + "h": 12, + "i": "19", + "type": "Widget", + "expressions": [ + "cilium_service_instance_relation_server_protocol_dns_error_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "DNS Erro Server Side(Count Per Min)" + } + }, + { + "x": 12, + "y": 36, + "w": 12, + "h": 12, + "i": "20", + "type": "Widget", + "expressions": [ + "cilium_service_instance_relation_server_protocol_kafka_call_error_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "Kafka Error Server Side(Count Per Min)" + } + } + ] + } + ] + } + ], + "layer": "CILIUM_SERVICE", + "entity": "ServiceInstanceRelation", + "name": "Cilium-Service-Instance-Relation" + } + } +] \ No newline at end of file diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-service-instance.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-service-instance.json new file mode 100644 index 000000000000..40fc936210f4 --- /dev/null +++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-service-instance.json @@ -0,0 +1,481 @@ +[ + { + "id": "8a29b3a2-49d9-4fc8-848f-993229d03ac7", + "configuration": { + "children": [ + { + "x": 0, + "y": 0, + "w": 24, + "h": 48, + "i": "0", + "type": "Tab", + "children": [ + { + "name": "Overview", + "children": [ + { + "x": 0, + "y": 0, + "w": 6, + "h": 12, + "i": "0", + "type": "Widget", + "expressions": [ + "cilium_service_instance_l4_read_pkg_cpm" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "L4 Read(Package Count per min)" + }, + "metricConfig": [ + { + "label": "Read Package Count" + } + ] + }, + { + "x": 6, + "y": 0, + "w": 6, + "h": 12, + "i": "1", + "type": "Widget", + "expressions": [ + "cilium_service_instance_l4_write_pkg_cpm" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "L4 Write(Package Count per min)" + }, + "metricConfig": [ + { + "label": "Write Package Count" + } + ] + }, + { + "x": 12, + "y": 0, + "w": 6, + "h": 12, + "i": "2", + "type": "Widget", + "expressions": [ + "cilium_service_l4_read_pkg_drop_cpm", + "cilium_service_l4_write_pkg_drop_cpm" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "TCP Drop Package(Count Per Min)" + }, + "metricConfig": [ + { + "label": "Drop Read Package Count" + }, + { + "label": "Drop Write Package Count" + } + ] + }, + { + "x": 18, + "y": 0, + "w": 6, + "h": 12, + "i": "3", + "type": "Widget", + "expressions": [ + "cilium_service_l4_drop_reason_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "Tcp Drop Package Reason Server Side(Count Per min)" + } + }, + { + "x": 0, + "y": 12, + "w": 6, + "h": 12, + "i": "4", + "type": "Widget", + "expressions": [ + "cilium_service_instance_protocol_http_call_cpm", + "cilium_service_instance_protocol_http_call_success_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "HTTP Load(Call per min)" + }, + "metricConfig": [ + { + "label": "Total Count" + }, + { + "label": "Success Count" + } + ] + }, + { + "x": 6, + "y": 12, + "w": 6, + "h": 12, + "i": "5", + "type": "Widget", + "expressions": [ + "cilium_service_instance_protocol_http_call_duration/cilium_service_instance_protocol_http_call_duration/1000000" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "HTTP Duration(ms)" + }, + "metricConfig": [ + { + "label": "duration" + } + ] + }, + { + "x": 12, + "y": 12, + "w": 12, + "h": 12, + "i": "6", + "type": "Widget", + "expressions": [ + "cilium_service_instance_protocol_http_status_1xx_cpm", + "cilium_service_instance_protocol_http_status_2xx_cpm", + "cilium_service_instance_protocol_http_status_3xx_cpm", + "cilium_service_instance_protocol_http_status_4xx_cpm", + "cilium_service_instance_protocol_http_status_5xx_cpm" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "metricConfig": [ + { + "label": "1xx" + }, + { + "label": "2xx" + }, + { + "label": "3xx" + }, + { + "label": "4xx" + }, + { + "label": "5xx" + } + ], + "widget": { + "title": "HTTP Response Code(Count per min)" + } + }, + { + "x": 0, + "y": 24, + "w": 6, + "h": 12, + "i": "7", + "type": "Widget", + "expressions": [ + "cilium_service_instance_protocol_dns_call_cpm", + "cilium_service_instance_protocol_dns_call_success_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "DNS Load(Call per min)" + }, + "metricConfig": [ + { + "label": "Total Count" + }, + { + "label": "Success Count" + } + ] + }, + { + "x": 6, + "y": 24, + "w": 6, + "h": 12, + "i": "8", + "type": "Widget", + "expressions": [ + "cilium_service_instance_protocol_dns_call_duration/cilium_service_instance_protocol_dns_call_cpm" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "DNS Duration(ms)" + }, + "metricConfig": [ + { + "label": "duration" + } + ] + }, + { + "x": 12, + "y": 24, + "w": 12, + "h": 12, + "i": "9", + "type": "Widget", + "expressions": [ + "cilium_service_instance_protocol_dns_error_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "DNS Error(Count per min)" + } + }, + { + "x": 0, + "y": 36, + "w": 6, + "h": 12, + "i": "10", + "type": "Widget", + "expressions": [ + "cilium_service_instance_protocol_kafka_call_cpm", + "cilium_service_instance_protocol_kafka_call_success_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "Kafka Load(Operation per min)" + }, + "metricConfig": [ + { + "label": "Total Count" + }, + { + "label": "Success Count" + } + ] + }, + { + "x": 6, + "y": 36, + "w": 6, + "h": 12, + "i": "11", + "type": "Widget", + "expressions": [ + "cilium_service_instance_protocol_kafka_call_duration/cilium_service_instance_protocol_kafka_call_cpm/1000000" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "Kafka Operation Duration(ms)" + }, + "metricConfig": [ + { + "label": "duration" + } + ] + }, + { + "x": 12, + "y": 36, + "w": 12, + "h": 12, + "i": "12", + "type": "Widget", + "expressions": [ + "cilium_service_instance_protocol_kafka_call_error_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "Kafka Operation Error(Count per min)" + } + } + ] + }, + { + "name": "Topology", + "children": [ + { + "x": 0, + "y": 0, + "w": 24, + "h": 48, + "i": "0", + "type": "Topology", + "graph": { + "showDepth": true + }, + "linkDashboard": "", + "nodeDashboard": [ + + ], + "linkServerExpressions": [ + "avg(cilium_service_instance_relation_server_l4_read_pkg_cpm)", + "avg(cilium_service_instance_relation_server_l4_write_pkg_cpm)", + "avg(cilium_service_instance_relation_server_protocol_cpm)", + "avg(cilium_service_instance_relation_server_protocol_call_duration/cilium_service_relation_server_protocol_cpm)/1000000" + ], + "linkClientExpressions": [ + + ], + "nodeExpressions": [ + "avg(cilium_service_instance_l4_read_pkg_cpm)", + "avg(cilium_service_instance_l4_write_pkg_cpm)", + "avg(cilium_service_instance_protocol_cpm)", + "avg(cilium_service_instance_protocol_call_duration/cilium_service_instance_protocol_cpm)/1000000", + "avg(cilium_service_instance_protocol_call_success_count/cilium_service_instance_protocol_cpm)*100" + ], + "legendMQE": { + "expression": "(avg(cilium_service_instance_protocol_call_success_count / cilium_service_instance_protocol_cpm*100) < 95) * (avg(cilium_service_instance_protocol_cpm) > 1) == 1" + }, + "description": { + "healthy": "Healthy", + "unhealthy": "Success Rate < 95% and HTTP Traffic > 1 calls / min" + }, + "linkServerMetricConfig": [ + { + "unit": "Count / min", + "label": "Server Read Package" + }, + { + "unit": "Count / min", + "label": "Server Write Package" + }, + { + "unit": "calls / min", + "label": "Server Load" + }, + { + "label": "Server Latency", + "unit": "ms" + } + ], + "linkClientMetricConfig": [ + ], + "nodeMetricConfig": [ + { + "label": "Read", + "unit": "package / min" + }, + { + "unit": "package / min", + "label": "Write" + }, + { + "label": "Load", + "unit": "calls / min" + }, + { + "label": "Latency", + "unit": "ms" + }, + { + "label": "Success Rate", + "unit": "%" + } + ] + } + ] + } + ] + } + ], + "layer": "CILIUM_SERVICE", + "entity": "ServiceInstance", + "name": "Cilium-Service-Instance", + "isRoot": false + } + } +] \ No newline at end of file diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-service-relation.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-service-relation.json new file mode 100644 index 000000000000..485720c275a5 --- /dev/null +++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-service-relation.json @@ -0,0 +1,483 @@ +[ + { + "id": "4fd87f04-2a31-4c78-bb60-70473a4e3045", + "configuration": { + "children": [ + { + "x": 0, + "y": 0, + "w": 24, + "h": 52, + "i": "0", + "type": "Tab", + "children": [ + { + "name": "Overview", + "children": [ + { + "x": 0, + "y": 0, + "w": 6, + "h": 12, + "i": "2", + "type": "Widget", + "expressions": [ + "cilium_service_relation_server_l4_read_pkg_cpm" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "L4 Read Package Server Side(Count per min)" + }, + "metricConfig": [ + { + "label": "Read Package" + } + ] + }, + { + "x": 6, + "y": 0, + "w": 6, + "h": 12, + "i": "3", + "type": "Widget", + "expressions": [ + "cilium_service_relation_server_l4_write_pkg_cpm" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "L4 Write Package Server Side(Count per min)" + }, + "metricConfig": [ + { + "label": "Write Package" + } + ] + }, + { + "x": 0, + "y": 12, + "w": 6, + "h": 12, + "i": "6", + "type": "Widget", + "expressions": [ + "cilium_service_relation_server_protocol_http_call_cpm", + "cilium_service_relation_server_protocol_http_call_success_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "HTTP Load Server Side(Count per min)" + }, + "metricConfig": [ + { + "label": "Total Count" + }, + { + "label": "Success Count" + } + ] + }, + { + "x": 6, + "y": 12, + "w": 6, + "h": 12, + "i": "7", + "type": "Widget", + "expressions": [ + "cilium_service_relation_server_protocol_http_call_duration/cilium_service_relation_server_protocol_http_call_cpm/1000000" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "HTTP Response Duration Server Side(ms)" + }, + "metricConfig": [ + { + "label": "duration" + } + ] + }, + { + "x": 0, + "y": 24, + "w": 6, + "h": 12, + "i": "10", + "type": "Widget", + "expressions": [ + "cilium_service_relation_server_protocol_dns_call_cpm", + "cilium_service_relation_server_protocol_dns_call_success_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "DNS Load Server Side(Count per min)" + }, + "metricConfig": [ + { + "label": "Total Count" + }, + { + "label": "Success Count" + } + ] + }, + { + "x": 6, + "y": 24, + "w": 6, + "h": 12, + "i": "11", + "type": "Widget", + "expressions": [ + "cilium_service_relation_server_protocol_dns_call_duration/cilium_service_relation_server_protocol_dns_call_cpm/1000000" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "DNS Response Duration Server Side(ms)" + }, + "metricConfig": [ + { + "label": "duration" + } + ] + }, + { + "x": 0, + "y": 36, + "w": 6, + "h": 12, + "i": "14", + "type": "Widget", + "expressions": [ + "cilium_service_relation_server_protocol_kafka_call_cpm", + "cilium_service_relation_server_protocol_kafka_call_success_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "Kakfa Load Server Side(Count per min)" + }, + "metricConfig": [ + { + "label": "Total Count" + }, + { + "label": "Success Count" + } + ] + }, + { + "x": 6, + "y": 36, + "w": 6, + "h": 12, + "i": "15", + "type": "Widget", + "expressions": [ + "cilium_service_relation_server_protocol_kafka_call_duration/cilium_service_relation_server_protocol_kafka_call_cpm/1000000" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "Kafka Response Duration Server Side(ms)" + }, + "metricConfig": [ + { + "label": "duration" + } + ] + }, + { + "x": 12, + "y": 0, + "w": 6, + "h": 12, + "i": "16", + "type": "Widget", + "expressions": [ + "cilium_service_relation_server_l4_read_pkg_drop_cpm", + "cilium_service_relation_server_l4_write_pkg_drop_cpm" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "TCP Drop Package Server Side(Count Per Min)" + }, + "metricConfig": [ + { + "label": "Drop Read Package Count" + }, + { + "label": "Drop Write Package Count" + } + ] + }, + { + "x": 18, + "y": 0, + "w": 6, + "h": 12, + "i": "17", + "type": "Widget", + "expressions": [ + "cilium_service_relation_server_l4_drop_reason_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "Tcp Drop Package Reason Server Side(Count Per min)" + } + }, + { + "x": 12, + "y": 12, + "w": 12, + "h": 12, + "i": "18", + "type": "Widget", + "expressions": [ + "cilium_service_relation_protocol_http_status_1xx_cpm", + "cilium_service_relation_protocol_http_status_2xx_cpm", + "cilium_service_relation_protocol_http_status_3xx_cpm", + "cilium_service_relation_protocol_http_status_4xx_cpm", + "cilium_service_relation_protocol_http_status_5xx_cpm" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "HTTP Response Status Server Side(Count Per Min)" + }, + "metricConfig": [ + { + "label": "1xx" + }, + { + "label": "2xx" + }, + { + "label": "3xx" + }, + { + "label": "4xx" + }, + { + "label": "5xx" + } + ] + }, + { + "x": 12, + "y": 24, + "w": 12, + "h": 12, + "i": "19", + "type": "Widget", + "expressions": [ + "cilium_service_relation_server_protocol_dns_error_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "DNS Erro Server Side(Count Per Min)" + } + }, + { + "x": 12, + "y": 36, + "w": 12, + "h": 12, + "i": "20", + "type": "Widget", + "expressions": [ + "cilium_service_relation_server_protocol_kafka_call_error_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "Kafka Error Server Side(Count Per Min)" + } + } + ] + }, + { + "name": "Topology", + "children": [ + { + "x": 0, + "y": 0, + "w": 24, + "h": 48, + "i": "0", + "type": "Topology", + "graph": { + "showDepth": true + }, + "linkDashboard": "Cilium-Service-Instance-Relation", + "nodeDashboard": [ + + ], + "linkServerExpressions": [ + "avg(cilium_service_instance_relation_server_l4_read_pkg_cpm)", + "avg(cilium_service_instance_relation_server_l4_write_pkg_cpm)", + "avg(cilium_service_instance_relation_server_protocol_cpm)", + "avg(cilium_service_instance_relation_server_protocol_call_duration/cilium_service_relation_server_protocol_cpm)/1000000" + ], + "linkClientExpressions": [ + + ], + "nodeExpressions": [ + "avg(cilium_service_instance_l4_read_pkg_cpm)", + "avg(cilium_service_instance_l4_write_pkg_cpm)", + "avg(cilium_service_instance_protocol_cpm)", + "avg(cilium_service_instance_protocol_call_duration/cilium_service_instance_protocol_cpm)/1000000", + "avg(cilium_service_instance_protocol_call_success_count/cilium_service_instance_protocol_cpm)*100" + ], + "legendMQE": { + "expression": "(avg(cilium_service_instance_protocol_call_success_count / cilium_service_instance_protocol_cpm*100) < 95) * (avg(cilium_service_instance_protocol_cpm) > 1) == 1" + }, + "description": { + "healthy": "Healthy", + "unhealthy": "Success Rate < 95% and HTTP Traffic > 1 calls / min" + }, + "linkServerMetricConfig": [ + { + "unit": "Count / min", + "label": "Server Read Package" + }, + { + "unit": "Count / min", + "label": "Server Write Package" + }, + { + "unit": "calls / min", + "label": "Server Load" + }, + { + "label": "Server Latency", + "unit": "ms" + } + ], + "linkClientMetricConfig": [ + + ], + "nodeMetricConfig": [ + { + "label": "Read", + "unit": "package / min" + }, + { + "unit": "package / min", + "label": "Write" + }, + { + "label": "Load", + "unit": "calls / min" + }, + { + "label": "Latency", + "unit": "ms" + }, + { + "label": "Success Rate", + "unit": "%" + } + ] + } + ] + } + ] + } + ], + "name": "Cilium-Service-Relation", + "layer": "CILIUM_SERVICE", + "entity": "ServiceRelation", + "isRoot": false, + "isDefault": false + } + } +] \ No newline at end of file diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-service.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-service.json new file mode 100644 index 000000000000..7de44eced554 --- /dev/null +++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/cilium_service/cilium-service.json @@ -0,0 +1,564 @@ +[ + { + "id": "83af6733-15e4-495a-9802-0ea169f211f9", + "configuration": { + "children": [ + { + "x": 0, + "y": 0, + "w": 24, + "h": 48, + "i": "0", + "type": "Tab", + "children": [ + { + "name": "Overview", + "children": [ + { + "x": 0, + "y": 0, + "w": 6, + "h": 12, + "i": "0", + "type": "Widget", + "expressions": [ + "cilium_service_l4_read_pkg_cpm" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "L4 Read(Package Count per min)" + }, + "metricConfig": [ + { + "label": "Read Package Count" + } + ] + }, + { + "x": 6, + "y": 0, + "w": 6, + "h": 12, + "i": "1", + "type": "Widget", + "expressions": [ + "cilium_service_l4_write_pkg_cpm" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "L4 Write(Package Count per min)" + }, + "metricConfig": [ + { + "label": "Write Package Count" + } + ] + }, + { + "x": 12, + "y": 0, + "w": 6, + "h": 12, + "i": "2", + "type": "Widget", + "expressions": [ + "cilium_service_l4_read_pkg_drop_cpm", + "cilium_service_l4_write_pkg_drop_cpm" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "TCP Drop Package(Count Per Min)" + }, + "metricConfig": [ + { + "label": "Drop Read Package Count" + }, + { + "label": "Drop Write Package Count" + } + ] + }, + { + "x": 18, + "y": 0, + "w": 6, + "h": 12, + "i": "3", + "type": "Widget", + "expressions": [ + "cilium_service_l4_drop_reason_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "Tcp Drop Package Reason Server Side(Count Per min)" + } + }, + { + "x": 0, + "y": 12, + "w": 6, + "h": 12, + "i": "4", + "type": "Widget", + "expressions": [ + "cilium_service_protocol_http_call_cpm", + "cilium_service_protocol_http_call_success_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "HTTP Load(Call per min)" + }, + "metricConfig": [ + { + "label": "Total Count" + }, + { + "label": "Success Count" + } + ] + }, + { + "x": 6, + "y": 12, + "w": 6, + "h": 12, + "i": "5", + "type": "Widget", + "expressions": [ + "cilium_service_protocol_http_call_duration/cilium_service_protocol_http_call_cpm/1000000" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "HTTP Duration(ms)" + }, + "metricConfig": [ + { + "label": "duration" + } + ] + }, + { + "x": 12, + "y": 12, + "w": 12, + "h": 12, + "i": "6", + "type": "Widget", + "expressions": [ + "cilium_service_protocol_http_status_1xx_cpm", + "cilium_service_protocol_http_status_2xx_cpm", + "cilium_service_protocol_http_status_3xx_cpm", + "cilium_service_protocol_http_status_4xx_cpm", + "cilium_service_protocol_http_status_5xx_cpm" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "metricConfig": [ + { + "label": "1xx" + }, + { + "label": "2xx" + }, + { + "label": "3xx" + }, + { + "label": "4xx" + }, + { + "label": "5xx" + } + ], + "widget": { + "title": "HTTP Response Code(Count per min)" + } + }, + { + "x": 0, + "y": 24, + "w": 6, + "h": 12, + "i": "7", + "type": "Widget", + "expressions": [ + "cilium_service_protocol_dns_call_cpm", + "cilium_service_protocol_dns_call_success_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "DNS Load(Call per min)" + }, + "metricConfig": [ + { + "label": "Total Count" + }, + { + "label": "Success Count" + } + ] + }, + { + "x": 6, + "y": 24, + "w": 6, + "h": 12, + "i": "8", + "type": "Widget", + "expressions": [ + "cilium_service_protocol_dns_call_duration/cilium_service_protocol_dns_call_cpm/1000000" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "DNS Duration(ms)" + }, + "metricConfig": [ + { + "label": "duration" + } + ] + }, + { + "x": 12, + "y": 24, + "w": 12, + "h": 12, + "i": "9", + "type": "Widget", + "expressions": [ + "cilium_service_protocol_dns_error_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "DNS Error(Count per min)" + } + }, + { + "x": 0, + "y": 36, + "w": 6, + "h": 12, + "i": "10", + "type": "Widget", + "expressions": [ + "cilium_service_protocol_kafka_call_cpm", + "cilium_service_protocol_kafka_call_success_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "Kafka Load(Operation per min)" + }, + "metricConfig": [ + { + "label": "Total Count" + }, + { + "label": "Success Count" + } + ] + }, + { + "x": 6, + "y": 36, + "w": 6, + "h": 12, + "i": "11", + "type": "Widget", + "expressions": [ + "cilium_service_protocol_kafka_call_duration/cilium_service_protocol_kafka_call_cpm/1000000" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "Kafka Operation Duration(ms)" + }, + "metricConfig": [ + { + "label": "duration" + } + ] + }, + { + "x": 12, + "y": 36, + "w": 12, + "h": 12, + "i": "12", + "type": "Widget", + "expressions": [ + "cilium_service_protocol_kafka_call_error_count" + ], + "graph": { + "type": "Line", + "step": false, + "smooth": false, + "showSymbol": true, + "showXAxis": true, + "showYAxis": true + }, + "widget": { + "title": "Kafka Operation Error(Count per min)" + } + } + ] + }, + { + "name": "Instance", + "children": [ + { + "x": 0, + "y": 0, + "w": 24, + "h": 49, + "i": "0", + "type": "Widget", + "graph": { + "type": "InstanceList", + "dashboardName": "Cilium-Service-Instance", + "fontSize": 12 + }, + "metricConfig": [ + { + "label": "Load", + "detailLabel": "load", + "unit": "calls / min" + }, + { + "detailLabel": "success_rate", + "label": "Success Rate", + "unit": "%" + }, + { + "label": "Latency", + "detailLabel": "latency", + "unit": "ms" + } + ], + "expressions": [ + "avg(cilium_service_instance_protocol_cpm)", + "avg(cilium_service_instance_protocol_call_success_count/cilium_service_instance_protocol_cpm)*100", + "avg(cilium_service_instance_protocol_call_duration/cilium_service_instance_protocol_cpm)/1000000" + ] + } + ] + }, + { + "name": "Topology", + "children": [ + { + "x": 0, + "y": 0, + "w": 24, + "h": 48, + "i": "0", + "type": "Topology", + "graph": { + "showDepth": true + }, + "linkDashboard": "Cilium-Service-Relation", + "nodeDashboard": [ + + ], + "linkServerExpressions": [ + "avg(cilium_service_relation_server_l4_read_pkg_cpm)", + "avg(cilium_service_relation_server_l4_write_pkg_cpm)", + "avg(cilium_service_relation_server_protocol_cpm)", + "avg(cilium_service_relation_server_protocol_call_duration/cilium_service_relation_server_protocol_cpm)/1000000" + ], + "linkClientExpressions": [ + + ], + "nodeExpressions": [ + "avg(cilium_service_l4_read_pkg_cpm)", + "avg(cilium_service_l4_write_pkg_cpm)", + "avg(cilium_service_protocol_cpm)", + "avg(cilium_service_protocol_call_duration/cilium_service_protocol_cpm)/1000000", + "avg(cilium_service_protocol_call_success_count/cilium_service_protocol_cpm)*100" + ], + "legendMQE": { + "expression": "(avg(cilium_service_protocol_call_success_count / cilium_service_protocol_cpm*100) < 95) * (avg(cilium_service_protocol_cpm) > 1) == 1" + }, + "description": { + "healthy": "Healthy", + "unhealthy": "Success Rate < 95% and HTTP Traffic > 1 calls / min" + }, + "linkServerMetricConfig": [ + { + "unit": "Count / min", + "label": "Server Read Package" + }, + { + "unit": "Count / min", + "label": "Server Write Package" + }, + { + "unit": "calls / min", + "label": "Server Load" + }, + { + "label": "Server Latency", + "unit": "ms" + } + ], + "linkClientMetricConfig": [ + + ], + "nodeMetricConfig": [ + { + "label": "Read", + "unit": "package / min" + }, + { + "unit": "package / min", + "label": "Write" + }, + { + "label": "Load", + "unit": "calls / min" + }, + { + "label": "Latency", + "unit": "ms" + }, + { + "label": "Success Rate", + "unit": "%" + } + ] + } + ] + }, + { + "name": "Endpoint", + "children": [ + { + "x": 0, + "y": 0, + "w": 24, + "h": 49, + "i": "0", + "type": "Widget", + "widget": { + "title": "Title" + }, + "graph": { + "type": "EndpointList", + "fontSize": 12, + "showXAxis": false, + "showYAxis": false, + "dashboardName": "Cilium-Endpoint" + }, + "expressions": [ + "avg(cilium_endpoint_protocol_cpm)", + "avg(cilium_endpoint_protocol_call_duration/cilium_endpoint_protocol_cpm)/1000000", + "avg(cilium_endpoint_protocol_call_success_count/cilium_endpoint_protocol_cpm)*100" + ], + "metricConfig": [ + { + "label": "Load", + "unit": "calls / min" + }, + { + "label": "Avg Duration", + "unit": "ms" + }, + { + "unit": "%", + "label": "Success Rate" + } + ] + } + ] + } + ] + } + ], + "layer": "CILIUM_SERVICE", + "entity": "Service", + "name": "Cilium-Service", + "isRoot": false + } + } +] \ No newline at end of file diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/menu.yaml b/oap-server/server-starter/src/main/resources/ui-initialized-templates/menu.yaml index 36735b9c9fc9..6d0696d28387 100644 --- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/menu.yaml +++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/menu.yaml @@ -82,6 +82,15 @@ menus: description: Observe Service status and resources from Kubernetes. documentLink: https://skywalking.apache.org/docs/main/next/en/setup/backend/backend-k8s-monitoring/ i18nKey: kubernetes_service + - title: Cilium + icon: cilium + description: Cilium is a CNI plugin for Kubernetes that provides eBPF-based networking, security, and load balancing. + i18nKey: cilium + menus: + - title: Service + layer: CILIUM_SERVICE + description: Observe Service status and resources from Cilium Hubble. + i18nKey: cilium_service - title: Infrastructure icon: infrastructure description: Operation Systems act as the infrastructure of the whole IT system. Its observabilities provide the fundamentals for all distributed and modern complex systems running. diff --git a/skywalking-ui b/skywalking-ui index 065337c3446c..f664e786acea 160000 --- a/skywalking-ui +++ b/skywalking-ui @@ -1 +1 @@ -Subproject commit 065337c3446c4cccf9515da468feede939afd460 +Subproject commit f664e786acead0bb1884d12f91635b2a1cb0fc47