You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by ha...@apache.org on 2026/09/14 08:19:05 UTC
(skywalking-banyandb) branch main updated: fix(metadata): tolerate unreachable peers in DNS discovery ListNode so non-meta nodes no longer deadlock in PreRun (#1354)
This is an automated email from the ASF dual-hosted git repository.
hanahmily pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-banyandb.git
The following commit(s) were added to refs/heads/main by this push:
new 7f5e29fcf fix(metadata): tolerate unreachable peers in DNS discovery ListNode so non-meta nodes no longer deadlock in PreRun (#1354)
7f5e29fcf is described below
commit 7f5e29fcfa4c85003fa97e96479f8031c932a3c3
Author: mrproliu <74...@qq.com>
AuthorDate: Mon Sep 14 16:19:00 2026 +0800
fix(metadata): tolerate unreachable peers in DNS discovery ListNode so non-meta nodes no longer deadlock in PreRun (#1354)
---
.github/workflows/e2e.yml | 15 +-
.gitignore | 3 +
CHANGES.md | 1 +
banyand/metadata/discovery/dns/dns.go | 7 +-
banyand/metadata/discovery/dns/prerun_test.go | 172 ++++++++++
test/e2e-v2/cases/lifecycle/data-generator/gen.sh | 7 +
.../lifecycle/dns-discovery/banyandb-cluster.yaml | 380 +++++++++++++++++++++
test/e2e-v2/cases/lifecycle/dns-discovery/e2e.yaml | 137 ++++++++
.../{nodes.yaml => dns-discovery/kind.yaml.tpl} | 19 +-
.../lifecycle/dns-discovery/provider-consumer.yaml | 183 ++++++++++
.../lifecycle/dns-discovery/skywalking-values.yaml | 56 +++
test/e2e-v2/cases/lifecycle/e2e.yaml | 98 ------
.../cases/lifecycle/expected/traces-list.yml | 40 ++-
.../{ => file-discovery}/docker-compose.yml | 26 +-
.../e2e-v2/cases/lifecycle/file-discovery/e2e.yaml | 84 +++++
.../lifecycle/{ => file-discovery}/nodes.yaml | 0
test/e2e-v2/cases/lifecycle/lifecycle-cases.yaml | 46 +++
17 files changed, 1138 insertions(+), 136 deletions(-)
diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
index 9c54f071f..46cadf1f4 100644
--- a/.github/workflows/e2e.yml
+++ b/.github/workflows/e2e.yml
@@ -93,9 +93,10 @@ jobs:
- name: Rover eBPF - Istio mesh, Kind
config: test/e2e-v2/cases/rover/process/istio/banyandb/e2e-banyandb.yaml
runs-on: ubuntu-24.04
- # TODO: Enable Lifecycle test when it is ready
- # - name: Lifecycle
- # config: test/e2e-v2/cases/lifecycle/e2e.yaml
+ - name: Lifecycle File Discovery
+ config: test/e2e-v2/cases/lifecycle/file-discovery/e2e.yaml
+ - name: Lifecycle DNS Discovery
+ config: test/e2e-v2/cases/lifecycle/dns-discovery/e2e.yaml
engine:
- suffix: ""
- suffix: " Vec"
@@ -146,7 +147,7 @@ jobs:
;;
esac
- name: Generate data for lifecycle
- if: ${{ matrix.test.name == 'Lifecycle' }}
+ if: ${{ startsWith(matrix.test.name, 'Lifecycle') }}
run: |
bash test/e2e-v2/cases/lifecycle/data-generator/gen.sh
- name: ${{ matrix.test.name }}
@@ -154,7 +155,7 @@ jobs:
with:
e2e-file: $GITHUB_WORKSPACE/${{ matrix.test.config }}
- name: Fix directory permissions
- if: ${{ (failure() && matrix.test.name == 'Lifecycle') }}
+ if: ${{ (failure() && startsWith(matrix.test.name, 'Lifecycle')) }}
run: sudo chmod -R 777 test/e2e-v2/cases/lifecycle/data-generator/tmp
- if: ${{ failure() }}
run: |
@@ -168,10 +169,10 @@ jobs:
name: test-logs-${{ matrix.test.name }}
path: "${{ env.SW_INFRA_E2E_LOG_DIR }}"
- uses: actions/upload-artifact@v7
- if: ${{ (failure() && matrix.test.name == 'Lifecycle') }}
+ if: ${{ (failure() && startsWith(matrix.test.name, 'Lifecycle')) }}
name: Upload generated data
with:
- name: lifecycle-data
+ name: lifecycle-data-${{ matrix.test.name }}${{ matrix.engine.suffix }}
path: "test/e2e-v2/cases/lifecycle/data-generator/tmp"
Storage:
diff --git a/.gitignore b/.gitignore
index 20d0916a5..947d201bd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -112,3 +112,6 @@ progress.txt
verify-*.png
sw-tiered-*.png
handoff-login.png
+
+# rendered by test/e2e-v2/cases/lifecycle/data-generator/gen.sh
+test/e2e-v2/cases/lifecycle/dns-discovery/kind.yaml
diff --git a/CHANGES.md b/CHANGES.md
index 958c42600..f64d15a9b 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -20,6 +20,7 @@ Release Notes.
- Enforce trace query time ranges independently of the sort index, skipping row timestamp checks when the query fully covers a part.
- Retry property schema registry initialization indefinitely, logging an error every 10 attempts.
- Re-fetch file/DNS discovery nodes that are parked in the retry queue while discovery has not Start()-ed yet, so unbounded PreRun schema-registry retries can recover once peers become reachable without restarting liaison.
+- Keep DNS discovery `ListNode` successful when some SRV addresses refuse connections but at least one node was discovered, so non-meta nodes no longer deadlock in PreRun on their own not-yet-listening gRPC address.
### Document
diff --git a/banyand/metadata/discovery/dns/dns.go b/banyand/metadata/discovery/dns/dns.go
index 7dd906556..725ff8b64 100644
--- a/banyand/metadata/discovery/dns/dns.go
+++ b/banyand/metadata/discovery/dns/dns.go
@@ -573,10 +573,13 @@ func (s *Service) updateNodeCache(ctx context.Context, srvToAddresses map[string
s.metrics.totalNodesCount.Set(float64(s.GetCacheSize()))
}
- if len(addErrors) > 0 {
+ // Unreachable peers only fail the update when nothing was discovered at all.
+ // With at least one cached node the caller can proceed while the retry queue
+ // keeps chasing the rest. This matters during PreRun: the node's own address
+ // is already published but its gRPC port only opens after PreRun completes.
+ if len(addErrors) > 0 && s.GetCacheSize() == 0 {
return errors.Join(addErrors...)
}
-
return nil
}
diff --git a/banyand/metadata/discovery/dns/prerun_test.go b/banyand/metadata/discovery/dns/prerun_test.go
new file mode 100644
index 000000000..b8df4bc15
--- /dev/null
+++ b/banyand/metadata/discovery/dns/prerun_test.go
@@ -0,0 +1,172 @@
+// Licensed to 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. Apache Software Foundation (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 dns_test
+
+import (
+ "context"
+ "net"
+ "strconv"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "google.golang.org/grpc"
+
+ databasev1 "github.com/apache/skywalking-banyandb/api/proto/banyandb/database/v1"
+ "github.com/apache/skywalking-banyandb/banyand/metadata/discovery/dns"
+ "github.com/apache/skywalking-banyandb/banyand/metadata/schema/property"
+ "github.com/apache/skywalking-banyandb/banyand/metadata/schema/schemaserver"
+ "github.com/apache/skywalking-banyandb/banyand/observability"
+)
+
+// These specs cover the metadata PreRun phase: discovery has not been started,
+// so ListNode re-fetches unreachable peers on every call. A peer that can never
+// answer during PreRun (typically the node's own gRPC address published through
+// the headless service) must not hide the peers that did answer.
+var _ = Describe("ListNode before Start", func() {
+ var (
+ ctx context.Context
+ cancel context.CancelFunc
+ svc *dns.Service
+ mockResolver *mockDNSResolver
+ mockServer *mockNodeQueryServer
+ metaAddr string
+ refusedAddr string
+ stopServer func()
+ )
+
+ BeforeEach(func() {
+ ctx, cancel = context.WithCancel(context.Background())
+ mockResolver = newMockDNSResolver()
+
+ var listener net.Listener
+ var grpcServer *grpc.Server
+ listener, grpcServer, mockServer = setupMockGRPCServer()
+ metaAddr = listener.Addr().String()
+ mockServer.node = createTestNode("meta-node", metaAddr, databasev1.Role_ROLE_META)
+ stopServer = func() {
+ grpcServer.Stop()
+ _ = listener.Close()
+ }
+
+ refusedAddr = reserveRefusedAddr()
+ })
+
+ AfterEach(func() {
+ if svc != nil {
+ Expect(svc.Close()).To(Succeed())
+ svc = nil
+ }
+ stopServer()
+ cancel()
+ })
+
+ It("should return reachable nodes when another SRV address refuses connections", func() {
+ mockResolver.setResponse("_grpc._tcp.test.local", []*net.SRV{addrToSRV(refusedAddr), addrToSRV(metaAddr)})
+
+ var err error
+ svc, err = dns.NewServiceWithResolver(createDefaultConfig(), mockResolver)
+ Expect(err).NotTo(HaveOccurred())
+
+ nodes, listErr := svc.ListNode(ctx, databasev1.Role_ROLE_META)
+ Expect(listErr).NotTo(HaveOccurred())
+ Expect(nodes).To(HaveLen(1))
+ Expect(nodes[0].GetMetadata().GetName()).To(Equal("meta-node"))
+ Expect(svc.RetryManager.IsInRetry(refusedAddr)).To(BeTrue(), "unreachable address should be parked for retry")
+
+ // Every pre-Start ListNode re-dials the parked address; the repeated
+ // failure must keep being tolerated rather than poisoning the result.
+ nodes, listErr = svc.ListNode(ctx, databasev1.Role_ROLE_META)
+ Expect(listErr).NotTo(HaveOccurred())
+ Expect(nodes).To(HaveLen(1))
+ Expect(svc.RetryManager.IsInRetry(refusedAddr)).To(BeTrue())
+ })
+
+ It("should still report an error when no SRV address is reachable", func() {
+ mockResolver.setResponse("_grpc._tcp.test.local", []*net.SRV{addrToSRV(refusedAddr)})
+
+ var err error
+ svc, err = dns.NewServiceWithResolver(createDefaultConfig(), mockResolver)
+ Expect(err).NotTo(HaveOccurred())
+
+ nodes, listErr := svc.ListNode(ctx, databasev1.Role_ROLE_META)
+ Expect(listErr).To(HaveOccurred())
+ Expect(listErr.Error()).To(ContainSubstring(refusedAddr))
+ Expect(nodes).To(BeEmpty())
+ })
+
+ It("should bootstrap the property schema registry while the node's own address is unreachable", func() {
+ schemaAddr, stopSchema := startSchemaServer()
+ defer stopSchema()
+
+ // The meta node advertises the schema server; the refused address plays
+ // the role of the booting node itself, whose gRPC port only opens after
+ // PreRun completes.
+ mockServer.node.PropertySchemaGrpcAddress = schemaAddr
+ mockResolver.setResponse("_grpc._tcp.test.local", []*net.SRV{addrToSRV(refusedAddr), addrToSRV(metaAddr)})
+
+ var err error
+ svc, err = dns.NewServiceWithResolver(createDefaultConfig(), mockResolver)
+ Expect(err).NotTo(HaveOccurred())
+
+ reg, regErr := property.NewSchemaRegistryClient(&property.ClientConfig{
+ GRPCTimeout: 5 * time.Second,
+ InitWaitTime: 10 * time.Second,
+ NodeRegistry: svc,
+ })
+ Expect(regErr).NotTo(HaveOccurred())
+ Expect(reg.Close()).To(Succeed())
+ })
+})
+
+// reserveRefusedAddr returns a loopback address that nothing listens on, so
+// dialing it fails immediately with connection refused.
+func reserveRefusedAddr() string {
+ listener, err := net.Listen("tcp", "127.0.0.1:0")
+ Expect(err).NotTo(HaveOccurred())
+ addr := listener.Addr().String()
+ Expect(listener.Close()).To(Succeed())
+ return addr
+}
+
+func startSchemaServer() (string, func()) {
+ listener, err := net.Listen("tcp", "127.0.0.1:0")
+ Expect(err).NotTo(HaveOccurred())
+ port := listener.Addr().(*net.TCPAddr).Port
+ Expect(listener.Close()).To(Succeed())
+
+ srv := schemaserver.NewServer(observability.BypassRegistry)
+ Expect(srv.FlagSet().Parse([]string{
+ "--schema-server-root-path", GinkgoT().TempDir(),
+ "--schema-server-grpc-host", "127.0.0.1",
+ "--schema-server-grpc-port", strconv.Itoa(port),
+ })).To(Succeed())
+ Expect(srv.Validate()).To(Succeed())
+ Expect(srv.PreRun(context.Background())).To(Succeed())
+ srv.Serve()
+
+ addr := net.JoinHostPort("127.0.0.1", strconv.Itoa(port))
+ Eventually(func() error {
+ conn, dialErr := net.DialTimeout("tcp", addr, 100*time.Millisecond)
+ if dialErr != nil {
+ return dialErr
+ }
+ return conn.Close()
+ }, 5*time.Second, 50*time.Millisecond).Should(Succeed())
+ return addr, srv.GracefulStop
+}
diff --git a/test/e2e-v2/cases/lifecycle/data-generator/gen.sh b/test/e2e-v2/cases/lifecycle/data-generator/gen.sh
index fa8a4382d..5cdb1c533 100644
--- a/test/e2e-v2/cases/lifecycle/data-generator/gen.sh
+++ b/test/e2e-v2/cases/lifecycle/data-generator/gen.sh
@@ -54,3 +54,10 @@ else
fi
docker compose -f "$COMPOSE_FILE" down -v
+
+# Render the kind config for the dns-discovery variant. kind only accepts an
+# absolute hostPath and the e2e runner does not expand variables in kind.yaml,
+# so bake in the absolute path of the data generated above.
+KIND_DIR="$DIR/../dns-discovery"
+sed "s|__LIFECYCLE_DATA_DIR__|$DIR/tmp|" "$KIND_DIR/kind.yaml.tpl" > "$KIND_DIR/kind.yaml"
+echo "✅ rendered $KIND_DIR/kind.yaml"
diff --git a/test/e2e-v2/cases/lifecycle/dns-discovery/banyandb-cluster.yaml b/test/e2e-v2/cases/lifecycle/dns-discovery/banyandb-cluster.yaml
new file mode 100644
index 000000000..a9ce9ef7f
--- /dev/null
+++ b/test/e2e-v2/cases/lifecycle/dns-discovery/banyandb-cluster.yaml
@@ -0,0 +1,380 @@
+# 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.
+
+# BanyanDB hot/warm/cold cluster with DNS-based node discovery, the same
+# topology as ../file-discovery/docker-compose.yml. Every node lists the SRV
+# records of the four headless Services below and finds its peers from them,
+# mirroring the Helm chart: data nodes publish `grpc`, the liaison publishes
+# its data-facing `internal-grpc` port. publishNotReadyAddresses keeps a
+# booting pod in DNS before its readiness probe passes, exactly like production.
+#
+# Only hot keeps the meta role, so warm, cold and the liaison bootstrap their
+# schema registry by listing META nodes through discovery while their own
+# address is already published but not yet listening.
+#
+# The cold node is pre-loaded with the data produced by ../data-generator, which
+# kind.yaml mounts into the node at /lifecycle-data. Applied through envsubst so
+# ${BANYANDB_*_VECTORIZED_FLAGS} resolve; container args use $(POD_NAME), which
+# Kubernetes expands and envsubst leaves alone.
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: data-hot
+ labels:
+ app: banyandb-data
+ role: hot
+spec:
+ clusterIP: None
+ publishNotReadyAddresses: true
+ selector:
+ app: banyandb-data
+ role: hot
+ ports:
+ - name: grpc
+ port: 17912
+ targetPort: 17912
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: data-warm
+ labels:
+ app: banyandb-data
+ role: warm
+spec:
+ clusterIP: None
+ publishNotReadyAddresses: true
+ selector:
+ app: banyandb-data
+ role: warm
+ ports:
+ - name: grpc
+ port: 17912
+ targetPort: 17912
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: data-cold
+ labels:
+ app: banyandb-data
+ role: cold
+spec:
+ clusterIP: None
+ publishNotReadyAddresses: true
+ selector:
+ app: banyandb-data
+ role: cold
+ ports:
+ - name: grpc
+ port: 17912
+ targetPort: 17912
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: liaison-headless
+ labels:
+ app: banyandb-liaison
+spec:
+ clusterIP: None
+ publishNotReadyAddresses: true
+ selector:
+ app: banyandb-liaison
+ ports:
+ - name: internal-grpc
+ port: 18912
+ targetPort: 18912
+---
+# Client-facing liaison endpoint used by OAP (SW_STORAGE_BANYANDB_TARGETS).
+apiVersion: v1
+kind: Service
+metadata:
+ name: liaison
+ labels:
+ app: banyandb-liaison
+spec:
+ selector:
+ app: banyandb-liaison
+ ports:
+ - name: grpc
+ port: 17912
+ targetPort: 17912
+ - name: http
+ port: 17913
+ targetPort: 17913
+---
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: data-hot
+ labels:
+ app: banyandb-data
+ role: hot
+spec:
+ serviceName: data-hot
+ replicas: 1
+ selector:
+ matchLabels:
+ app: banyandb-data
+ role: hot
+ template:
+ metadata:
+ labels:
+ app: banyandb-data
+ role: hot
+ spec:
+ containers:
+ - name: data
+ image: apache/skywalking-banyandb:${TAG}-testing
+ imagePullPolicy: IfNotPresent
+ args:
+ - data
+ - --node-discovery-mode=dns
+ - --node-discovery-dns-srv-addresses=_internal-grpc._tcp.liaison-headless.default.svc.cluster.local,_grpc._tcp.data-hot.default.svc.cluster.local,_grpc._tcp.data-warm.default.svc.cluster.local,_grpc._tcp.data-cold.default.svc.cluster.local
+ - --node-host-provider=flag
+ - --node-host=$(POD_NAME).data-hot.default
+ - --node-labels=type=hot
+ - ${BANYANDB_MEASURE_VECTORIZED_FLAGS}
+ - ${BANYANDB_TRACE_VECTORIZED_FLAGS}
+ env:
+ - name: POD_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.name
+ ports:
+ - { name: grpc, containerPort: 17912 }
+ - { name: http, containerPort: 17913 }
+ - { name: metrics, containerPort: 2121 }
+ - { name: prop-schema, containerPort: 17916 }
+ - { name: prop-gossip, containerPort: 17932 }
+ readinessProbe:
+ # /api/healthz reports SERVING only after pre-run completes and the
+ # node serves gRPC on 17912, so OAP (deployed after) never starts
+ # against a not-yet-listening BanyanDB and crashloops.
+ httpGet:
+ path: /api/healthz
+ port: 17913
+ initialDelaySeconds: 5
+ periodSeconds: 5
+ failureThreshold: 60
+ volumeMounts:
+ - name: lifecycle-data
+ mountPath: /tmp/measure/data/sw_metadata
+ subPath: sw_metadata
+ resources:
+ limits:
+ memory: 1536Mi
+ cpu: "2"
+ requests:
+ memory: 256Mi
+ cpu: "250m"
+ volumes:
+ - name: lifecycle-data
+ hostPath:
+ path: /lifecycle-data
+ type: Directory
+---
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: data-warm
+ labels:
+ app: banyandb-data
+ role: warm
+spec:
+ serviceName: data-warm
+ replicas: 1
+ selector:
+ matchLabels:
+ app: banyandb-data
+ role: warm
+ template:
+ metadata:
+ labels:
+ app: banyandb-data
+ role: warm
+ spec:
+ containers:
+ - name: data
+ image: apache/skywalking-banyandb:${TAG}-testing
+ imagePullPolicy: IfNotPresent
+ args:
+ - data
+ - --node-discovery-mode=dns
+ - --node-discovery-dns-srv-addresses=_internal-grpc._tcp.liaison-headless.default.svc.cluster.local,_grpc._tcp.data-hot.default.svc.cluster.local,_grpc._tcp.data-warm.default.svc.cluster.local,_grpc._tcp.data-cold.default.svc.cluster.local
+ - --node-host-provider=flag
+ - --node-host=$(POD_NAME).data-warm.default
+ - --node-labels=type=warm
+ - --has-meta-role=false
+ - ${BANYANDB_MEASURE_VECTORIZED_FLAGS}
+ - ${BANYANDB_TRACE_VECTORIZED_FLAGS}
+ env:
+ - name: POD_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.name
+ ports:
+ - { name: grpc, containerPort: 17912 }
+ - { name: http, containerPort: 17913 }
+ - { name: metrics, containerPort: 2121 }
+ readinessProbe:
+ httpGet:
+ path: /api/healthz
+ port: 17913
+ initialDelaySeconds: 5
+ periodSeconds: 5
+ failureThreshold: 60
+ resources:
+ limits:
+ memory: 1536Mi
+ cpu: "2"
+ requests:
+ memory: 256Mi
+ cpu: "250m"
+---
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: data-cold
+ labels:
+ app: banyandb-data
+ role: cold
+spec:
+ serviceName: data-cold
+ replicas: 1
+ selector:
+ matchLabels:
+ app: banyandb-data
+ role: cold
+ template:
+ metadata:
+ labels:
+ app: banyandb-data
+ role: cold
+ spec:
+ containers:
+ - name: data
+ image: apache/skywalking-banyandb:${TAG}-testing
+ imagePullPolicy: IfNotPresent
+ args:
+ - data
+ - --node-discovery-mode=dns
+ - --node-discovery-dns-srv-addresses=_internal-grpc._tcp.liaison-headless.default.svc.cluster.local,_grpc._tcp.data-hot.default.svc.cluster.local,_grpc._tcp.data-warm.default.svc.cluster.local,_grpc._tcp.data-cold.default.svc.cluster.local
+ - --node-host-provider=flag
+ - --node-host=$(POD_NAME).data-cold.default
+ - --node-labels=type=cold
+ - --has-meta-role=false
+ - ${BANYANDB_MEASURE_VECTORIZED_FLAGS}
+ - ${BANYANDB_TRACE_VECTORIZED_FLAGS}
+ env:
+ - name: POD_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.name
+ ports:
+ - { name: grpc, containerPort: 17912 }
+ - { name: http, containerPort: 17913 }
+ - { name: metrics, containerPort: 2121 }
+ readinessProbe:
+ httpGet:
+ path: /api/healthz
+ port: 17913
+ initialDelaySeconds: 5
+ periodSeconds: 5
+ failureThreshold: 60
+ volumeMounts:
+ # Pre-generated cold data, the same directories the compose variant
+ # bind-mounts into data-cold1.
+ - name: lifecycle-data
+ mountPath: /tmp/measure
+ subPath: measure
+ - name: lifecycle-data
+ mountPath: /tmp/stream
+ subPath: stream
+ - name: lifecycle-data
+ mountPath: /tmp/property
+ subPath: property
+ - name: lifecycle-data
+ mountPath: /tmp/trace
+ subPath: trace
+ resources:
+ limits:
+ memory: 1536Mi
+ cpu: "2"
+ requests:
+ memory: 256Mi
+ cpu: "250m"
+ volumes:
+ - name: lifecycle-data
+ hostPath:
+ path: /lifecycle-data
+ type: Directory
+---
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: liaison
+ labels:
+ app: banyandb-liaison
+spec:
+ serviceName: liaison-headless
+ replicas: 1
+ selector:
+ matchLabels:
+ app: banyandb-liaison
+ template:
+ metadata:
+ labels:
+ app: banyandb-liaison
+ spec:
+ containers:
+ - name: liaison
+ image: apache/skywalking-banyandb:${TAG}-testing
+ imagePullPolicy: IfNotPresent
+ args:
+ - liaison
+ - --node-discovery-mode=dns
+ - --node-discovery-dns-srv-addresses=_internal-grpc._tcp.liaison-headless.default.svc.cluster.local,_grpc._tcp.data-hot.default.svc.cluster.local,_grpc._tcp.data-warm.default.svc.cluster.local,_grpc._tcp.data-cold.default.svc.cluster.local
+ - --node-host-provider=flag
+ - --node-host=$(POD_NAME).liaison-headless.default
+ - --data-node-selector=type=hot
+ - ${BANYANDB_MEASURE_VECTORIZED_FLAGS}
+ - ${BANYANDB_TRACE_VECTORIZED_FLAGS}
+ env:
+ - name: POD_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.name
+ ports:
+ - { name: grpc, containerPort: 17912 }
+ - { name: http, containerPort: 17913 }
+ - { name: internal-grpc, containerPort: 18912 }
+ - { name: metrics, containerPort: 2121 }
+ readinessProbe:
+ httpGet:
+ path: /api/healthz
+ port: 17913
+ initialDelaySeconds: 5
+ periodSeconds: 5
+ failureThreshold: 60
+ resources:
+ limits:
+ memory: 1Gi
+ cpu: "2"
+ requests:
+ memory: 256Mi
+ cpu: "250m"
diff --git a/test/e2e-v2/cases/lifecycle/dns-discovery/e2e.yaml b/test/e2e-v2/cases/lifecycle/dns-discovery/e2e.yaml
new file mode 100644
index 000000000..b37a66b9b
--- /dev/null
+++ b/test/e2e-v2/cases/lifecycle/dns-discovery/e2e.yaml
@@ -0,0 +1,137 @@
+# 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.
+
+# Lifecycle e2e on kind with DNS-based node discovery: every BanyanDB node
+# finds its peers through the SRV records of headless Services, the same way
+# the Helm chart wires a cluster. OAP is installed from the skywalking-helm
+# chart like the rover istio e2e. Run ../data-generator/gen.sh first: it
+# produces the cold data and renders kind.yaml with the absolute path that
+# mounts that data into the kind node.
+
+setup:
+ env: kind
+ file: kind.yaml
+ timeout: 25m
+ init-system-environment: ../../../script/env
+ kind:
+ import-images:
+ - apache/skywalking-banyandb:${TAG}-testing
+ expose-ports:
+ - namespace: default
+ resource: service/skywalking-oap
+ port: 12800
+ - namespace: default
+ resource: service/consumer
+ port: 9092
+ steps:
+ - name: set PATH
+ command: export PATH=/tmp/skywalking-infra-e2e/bin:$PATH
+ - name: install yq
+ command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh yq
+ - name: install swctl
+ command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh swctl
+ - name: install kubectl
+ command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh kubectl
+ - name: install helm
+ command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh helm
+ - name: default the vectorized engine flags
+ # The CI engine axis exports these to switch the engine; envsubst has no
+ # default syntax, so fill in the compose defaults when they are unset.
+ command: |
+ export BANYANDB_MEASURE_VECTORIZED_FLAGS=${BANYANDB_MEASURE_VECTORIZED_FLAGS:---measure-vectorized-enabled=false}
+ export BANYANDB_TRACE_VECTORIZED_FLAGS=${BANYANDB_TRACE_VECTORIZED_FLAGS:---trace-vectorized-enabled=false}
+ - name: Deploy BanyanDB hot/warm/cold cluster
+ command: envsubst < test/e2e-v2/cases/lifecycle/dns-discovery/banyandb-cluster.yaml | kubectl apply -f -
+ - name: Deploy SkyWalking OAP with helm
+ # Same chart and pin as the rover istio e2e; the chart's own BanyanDB is
+ # disabled in skywalking-values.yaml and OAP targets the liaison Service.
+ command: |
+ helm install skywalking \
+ oci://ghcr.io/apache/skywalking-helm/skywalking-helm \
+ --version "0.0.0-${SW_KUBERNETES_COMMIT_SHA}" \
+ --timeout 15m \
+ --set fullnameOverride=skywalking \
+ --set oap.image.repository=ghcr.io/apache/skywalking/oap \
+ --set oap.image.tag=${SW_OAP_COMMIT} \
+ --set ui.image.repository=ghcr.io/apache/skywalking/ui \
+ --set ui.image.tag=${SW_OAP_COMMIT} \
+ -f test/e2e-v2/cases/lifecycle/dns-discovery/skywalking-values.yaml
+ - name: Deploy provider and consumer demo apps
+ command: envsubst < test/e2e-v2/cases/lifecycle/dns-discovery/provider-consumer.yaml | kubectl apply -f -
+ - name: Wait for all workloads to be ready
+ # Block here so the kind expose-ports port-forward (set up right after the
+ # setup steps, before the wait: conditions) targets already-running pods.
+ command: |
+ kubectl rollout status statefulset/data-hot --timeout=300s
+ kubectl rollout status statefulset/data-warm --timeout=300s
+ kubectl rollout status statefulset/data-cold --timeout=300s
+ kubectl rollout status statefulset/liaison --timeout=300s
+ kubectl rollout status deployment/skywalking-oap --timeout=600s
+ kubectl rollout status deployment/provider --timeout=600s
+ kubectl rollout status deployment/consumer --timeout=600s
+ wait:
+ - namespace: default
+ resource: pod
+ label-selector: app=banyandb-data
+ for: condition=Ready
+ - namespace: default
+ resource: pod
+ label-selector: app=banyandb-liaison
+ for: condition=Ready
+ - namespace: default
+ resource: deployment/skywalking-oap
+ for: condition=available
+ - namespace: default
+ resource: deployment/provider
+ for: condition=available
+ - namespace: default
+ resource: deployment/consumer
+ for: condition=available
+
+trigger:
+ action: http
+ interval: 5s
+ times: -1
+ url: http://${service_consumer_host}:${service_consumer_9092}/users
+ method: POST
+ body: '{"id":"123","name":"skywalking"}'
+ headers:
+ "Content-Type": "application/json"
+
+verify:
+ # verify with retry strategy
+ retry:
+ # max retry count
+ count: 20
+ # the interval between two retries, in millisecond.
+ interval: 10s
+ cases:
+ - includes:
+ - ../lifecycle-cases.yaml
+
+cleanup:
+ on: always
+ collect:
+ on: failure
+ output-dir: $SW_INFRA_E2E_LOG_DIR/banyandb-data
+ items:
+ - namespace: default
+ label-selector: app=banyandb-data
+ paths:
+ - /tmp/trace/
+ - /tmp/stream/
+ - /tmp/measure/
+ - /tmp/property/
+ - /tmp/schema-property/
diff --git a/test/e2e-v2/cases/lifecycle/nodes.yaml b/test/e2e-v2/cases/lifecycle/dns-discovery/kind.yaml.tpl
similarity index 64%
copy from test/e2e-v2/cases/lifecycle/nodes.yaml
copy to test/e2e-v2/cases/lifecycle/dns-discovery/kind.yaml.tpl
index fcc72ce89..9d6a0275c 100644
--- a/test/e2e-v2/cases/lifecycle/nodes.yaml
+++ b/test/e2e-v2/cases/lifecycle/dns-discovery/kind.yaml.tpl
@@ -13,12 +13,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+# Template for kind.yaml. kind requires an absolute hostPath and the e2e
+# runner does not expand variables in this file, so ../data-generator/gen.sh
+# renders kind.yaml from it with the absolute path of the generated data.
+
+kind: Cluster
+apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- - name: data-hot1
- grpc_address: data-hot1:17912
- - name: data-warm1
- grpc_address: data-warm1:17912
- - name: data-cold1
- grpc_address: data-cold1:17912
- - name: liaison
- grpc_address: liaison:17912
+ - role: control-plane
+ image: kindest/node:v1.30.0
+ extraMounts:
+ - hostPath: __LIFECYCLE_DATA_DIR__
+ containerPath: /lifecycle-data
diff --git a/test/e2e-v2/cases/lifecycle/dns-discovery/provider-consumer.yaml b/test/e2e-v2/cases/lifecycle/dns-discovery/provider-consumer.yaml
new file mode 100644
index 000000000..72f450935
--- /dev/null
+++ b/test/e2e-v2/cases/lifecycle/dns-discovery/provider-consumer.yaml
@@ -0,0 +1,183 @@
+# 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.
+
+# SkyWalking e2e provider/consumer demo apps instrumented with the Java agent.
+# An initContainer copies the agent from the skywalking-java image into a shared
+# emptyDir, mirroring the docker-compose `agent` sidecar + sw_agent volume.
+# Consumer POSTs to provider; both report to the helm-deployed OAP
+# (Service `skywalking-oap`), generating writes into BanyanDB. Applied through
+# envsubst so the ${SW_AGENT_*_COMMIT} tags resolve from test/e2e-v2/script/env.
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: provider
+ labels:
+ app: provider
+spec:
+ selector:
+ app: provider
+ ports:
+ - name: http
+ port: 9090
+ targetPort: 9090
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: consumer
+ labels:
+ app: consumer
+spec:
+ selector:
+ app: consumer
+ ports:
+ - name: http
+ port: 9092
+ targetPort: 9092
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: provider
+ labels:
+ app: provider
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: provider
+ template:
+ metadata:
+ labels:
+ app: provider
+ spec:
+ initContainers:
+ - name: agent-init
+ image: ghcr.io/apache/skywalking-java/skywalking-java:${SW_AGENT_JAVA_COMMIT}-java8
+ command: ["sh", "-c", "cp -r /skywalking/agent /sw-java-agent/"]
+ volumeMounts:
+ - name: sw-agent
+ mountPath: /sw-java-agent
+ containers:
+ - name: provider
+ image: ghcr.io/apache/skywalking/e2e-service-provider:${SW_AGENT_E2E_SERVICE_PROVIDER_COMMIT}
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: JAVA_TOOL_OPTIONS
+ # Cap the heap explicitly: these demo images run Java 8u322, which
+ # predates cgroup-v2 support (8u372+), so on a cgroup-v2 host the JVM
+ # would size its heap off the host's RAM and get OOMKilled despite the
+ # container memory limit.
+ value: -javaagent:/sw-java-agent/agent/skywalking-agent.jar -Xmx512m -Xms128m
+ - name: SW_AGENT_COLLECTOR_BACKEND_SERVICES
+ value: skywalking-oap:11800
+ - name: SW_LOGGING_OUTPUT
+ value: CONSOLE
+ - name: SW_AGENT_NAME
+ value: e2e-service-provider
+ - name: SW_AGENT_INSTANCE_NAME
+ value: provider1
+ - name: SW_METER_ACTIVE
+ value: "false"
+ ports:
+ - { name: http, containerPort: 9090 }
+ volumeMounts:
+ - name: sw-agent
+ mountPath: /sw-java-agent
+ readinessProbe:
+ tcpSocket:
+ port: 9090
+ initialDelaySeconds: 20
+ periodSeconds: 5
+ failureThreshold: 60
+ resources:
+ limits:
+ memory: 1536Mi
+ cpu: "1"
+ requests:
+ memory: 512Mi
+ cpu: "250m"
+ volumes:
+ - name: sw-agent
+ emptyDir: {}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: consumer
+ labels:
+ app: consumer
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: consumer
+ template:
+ metadata:
+ labels:
+ app: consumer
+ spec:
+ initContainers:
+ - name: agent-init
+ image: ghcr.io/apache/skywalking-java/skywalking-java:${SW_AGENT_JAVA_COMMIT}-java8
+ command: ["sh", "-c", "cp -r /skywalking/agent /sw-java-agent/"]
+ volumeMounts:
+ - name: sw-agent
+ mountPath: /sw-java-agent
+ containers:
+ - name: consumer
+ image: ghcr.io/apache/skywalking/e2e-service-consumer:${SW_AGENT_E2E_SERVICE_PROVIDER_COMMIT}
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: JAVA_TOOL_OPTIONS
+ # Cap the heap explicitly: these demo images run Java 8u322, which
+ # predates cgroup-v2 support (8u372+), so on a cgroup-v2 host the JVM
+ # would size its heap off the host's RAM and get OOMKilled despite the
+ # container memory limit.
+ value: -javaagent:/sw-java-agent/agent/skywalking-agent.jar -Xmx512m -Xms128m
+ - name: SW_AGENT_COLLECTOR_BACKEND_SERVICES
+ value: skywalking-oap:11800
+ - name: SW_LOGGING_OUTPUT
+ value: CONSOLE
+ - name: PROVIDER_URL
+ value: http://provider:9090
+ - name: SW_AGENT_NAME
+ value: e2e-service-consumer
+ - name: SW_AGENT_INSTANCE_NAME
+ value: consumer1
+ - name: SW_METER_ACTIVE
+ value: "false"
+ ports:
+ - { name: http, containerPort: 9092 }
+ volumeMounts:
+ - name: sw-agent
+ mountPath: /sw-java-agent
+ readinessProbe:
+ tcpSocket:
+ port: 9092
+ initialDelaySeconds: 20
+ periodSeconds: 5
+ failureThreshold: 60
+ resources:
+ limits:
+ memory: 1536Mi
+ cpu: "1"
+ requests:
+ memory: 512Mi
+ cpu: "250m"
+ volumes:
+ - name: sw-agent
+ emptyDir: {}
diff --git a/test/e2e-v2/cases/lifecycle/dns-discovery/skywalking-values.yaml b/test/e2e-v2/cases/lifecycle/dns-discovery/skywalking-values.yaml
new file mode 100644
index 000000000..e38bf7936
--- /dev/null
+++ b/test/e2e-v2/cases/lifecycle/dns-discovery/skywalking-values.yaml
@@ -0,0 +1,56 @@
+# 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.
+
+# Values for the skywalking-helm chart (pinned by SW_KUBERNETES_COMMIT_SHA in
+# test/e2e-v2/script/env), the same way the rover istio e2e deploys OAP. The
+# chart's own BanyanDB stays disabled; OAP targets the hot/warm/cold cluster
+# from banyandb-cluster.yaml through the `liaison` Service. Image tags and the
+# release name are passed on the helm command line in e2e.yaml.
+eckOperator:
+ enabled: false
+elasticsearch:
+ enabled: false
+banyandb:
+ enabled: false
+ config:
+ grpcAddress: "liaison:17912"
+ httpAddress: "liaison:17913"
+oap:
+ storageType: banyandb
+ replicas: 1
+ # The chart defaults to -Xmx2g; keep the OAP heap within what a GitHub runner
+ # can spare next to four BanyanDB nodes and the two demo apps.
+ javaOpts: -Xmx1g -Xms512m
+ # Schema installation against a fresh cluster can exceed the chart's default
+ # 90s startup window, which would restart OAP mid-install.
+ startupProbe:
+ tcpSocket:
+ port: 12800
+ failureThreshold: 60
+ periodSeconds: 10
+ env:
+ SW_HEALTH_CHECKER: default
+ SW_STORAGE_BANYANDB_COMPATIBLE_SERVER_API_VERSIONS: "0.11"
+ # Same warm/cold stage switches as ../file-discovery/docker-compose.yml.
+ SW_STORAGE_BANYANDB_METRICS_MINUTE_ENABLE_WARM_STAGE: "true"
+ SW_STORAGE_BANYANDB_METRICS_MINUTE_ENABLE_COLD_STAGE: "true"
+ SW_STORAGE_BANYANDB_METRICS_HOUR_ENABLE_WARM_STAGE: "true"
+ SW_STORAGE_BANYANDB_METRICS_HOUR_ENABLE_COLD_STAGE: "true"
+ SW_STORAGE_BANYANDB_METRICS_DAY_ENABLE_WARM_STAGE: "true"
+ SW_STORAGE_BANYANDB_METRICS_DAY_ENABLE_COLD_STAGE: "true"
+ SW_STORAGE_BANYANDB_RECORDS_ENABLE_WARM_STAGE: "true"
+ SW_STORAGE_BANYANDB_RECORDS_ENABLE_COLD_STAGE: "true"
+ SW_STORAGE_BANYANDB_TRACE_ENABLE_WARM_STAGE: "true"
+ SW_STORAGE_BANYANDB_TRACE_ENABLE_COLD_STAGE: "true"
diff --git a/test/e2e-v2/cases/lifecycle/e2e.yaml b/test/e2e-v2/cases/lifecycle/e2e.yaml
deleted file mode 100644
index 92cd88966..000000000
--- a/test/e2e-v2/cases/lifecycle/e2e.yaml
+++ /dev/null
@@ -1,98 +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.
-
-# This file is used to show how to write configuration files and can be used to test.
-
-setup:
- env: compose
- file: docker-compose.yml
- timeout: 20m
- init-system-environment: ../../script/env
- steps:
- - name: set PATH
- command: export PATH=/tmp/skywalking-infra-e2e/bin:$PATH
- - name: install yq
- command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh yq
- - name: install swctl
- command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh swctl
-
-trigger:
- action: http
- interval: 5s
- times: -1
- url: http://${consumer_host}:${consumer_9092}/users
- method: POST
- body: '{"id":"123","name":"skywalking"}'
- headers:
- "Content-Type": "application/json"
-
-verify:
- # verify with retry strategy
- retry:
- # max retry count
- count: 20
- # the interval between two retries, in millisecond.
- interval: 10s
- cases:
- - includes:
- - ../storage/storage-cases.yaml
- - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression="top_n(service_resp_time,3,des,attr0='GENERAL',attr1!='Not_exist')/100"
- expected: ../storage/expected/topN-OP-service.yml
-
- # cold data test
- - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=service_resp_time --service-name=mock_a_service --start="-96h" --end="-48h" --cold=true --step=DAY
- expected: ../storage/expected/metrics-has-value.yml
- - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql dependency service --service-name=mock_a_service --start="-96h" --end="-48h" --cold=true --step=DAY
- expected: ./expected/dependency-services.yml
- - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql dependency instance --service-name=mock_a_service --dest-service-name=mock_b_service --start="-96h" --end="-48h" --cold=true --step=DAY
- expected: ./expected/dependency-instance.yml
- - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql dependency endpoint --service-name=mock_a_service --endpoint-name=/dubbox-case/case/dubbox-rest/404-test --start="-96h" --end="-48h" --cold=true --step=DAY
- expected: ./expected/dependency-endpoint.yml
- # trace list
- - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql tv2 ls --service-name=mock_a_service --endpoint-name=/dubbox-case/case/dubbox-rest/404-test --tags http.method=get --start="-96h" --end="-48h" --cold=true
- expected: ./expected/traces-list.yml
- ## topN
- - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression="top_n(service_resp_time,3,des,attr0='GENERAL')" --start="-96h" --end="-48h" --cold=true --step=DAY
- expected: ./expected/topN-OP-service.yml
- - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression="top_n(endpoint_resp_time,3,des)" --start="-96h" --end="-48h" --cold=true --step=DAY
- expected: ./expected/topN-OP-endpoint.yml
-
-cleanup:
- on: always
- collect:
- on: failure
- output-dir: $SW_INFRA_E2E_LOG_DIR/banyandb-data
- items:
- - service: data-hot1
- paths:
- - /tmp/trace/
- - /tmp/stream/
- - /tmp/measure/
- - /tmp/property/
- - /tmp/schema-property/
- - service: data-warm1
- paths:
- - /tmp/trace/
- - /tmp/stream/
- - /tmp/measure/
- - /tmp/property/
- - /tmp/schema-property/
- - service: data-cold1
- paths:
- - /tmp/trace/
- - /tmp/stream/
- - /tmp/measure/
- - /tmp/property/
- - /tmp/schema-property/
diff --git a/test/e2e-v2/cases/lifecycle/expected/traces-list.yml b/test/e2e-v2/cases/lifecycle/expected/traces-list.yml
index e2f0a6243..c17d15e16 100644
--- a/test/e2e-v2/cases/lifecycle/expected/traces-list.yml
+++ b/test/e2e-v2/cases/lifecycle/expected/traces-list.yml
@@ -13,15 +13,39 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+# Cold trace list for mock_a_service in the Trace V2 shape: every returned trace
+# must contain the Entry span of the queried endpoint carrying the queried tag.
debuggingtrace: null
+retrievedtimerange:
+ {{- with .retrievedtimerange }}
+ starttime: {{ gt .starttime 0 }}
+ endtime: {{ gt .endtime 0 }}
+ {{- end }}
traces:
{{- contains (.traces | noDuplicates) }}
-- segmentid: {{ notEmpty .segmentid }}
- endpointnames:
- - /dubbox-case/case/dubbox-rest/404-test
- duration: {{ ge .duration 0 }}
- start: "{{ notEmpty .start}}"
- iserror: false
- traceids:
- - {{ index .traceids 0 }}
+- spans:
+ {{- contains (.spans | noDuplicates) }}
+ - traceid: {{ notEmpty .traceid }}
+ segmentid: {{ notEmpty .segmentid }}
+ spanid: 0
+ parentspanid: -1
+ refs: []
+ servicecode: mock_a_service
+ serviceinstancename: mock_a_service_instance
+ starttime: {{ gt .starttime 0 }}
+ endtime: {{ gt .endtime 0 }}
+ endpointname: /dubbox-case/case/dubbox-rest/404-test
+ type: Entry
+ peer: ""
+ component: Tomcat
+ iserror: false
+ layer: Http
+ tags:
+ {{- contains .tags }}
+ - key: http.method
+ value: get
+ {{- end }}
+ logs: []
+ attachedevents: []
+ {{- end }}
{{- end }}
diff --git a/test/e2e-v2/cases/lifecycle/docker-compose.yml b/test/e2e-v2/cases/lifecycle/file-discovery/docker-compose.yml
similarity index 83%
rename from test/e2e-v2/cases/lifecycle/docker-compose.yml
rename to test/e2e-v2/cases/lifecycle/file-discovery/docker-compose.yml
index 2913c1d83..43b9f6298 100644
--- a/test/e2e-v2/cases/lifecycle/docker-compose.yml
+++ b/test/e2e-v2/cases/lifecycle/file-discovery/docker-compose.yml
@@ -16,19 +16,19 @@
services:
data-hot1:
extends:
- file: ../../script/docker-compose/base-compose.yml
+ file: ../../../script/docker-compose/base-compose.yml
service: data
hostname: data-hot1
command: data --node-discovery-mode=file --node-discovery-file-path=/etc/banyandb/nodes.yaml --node-labels type=hot ${BANYANDB_MEASURE_VECTORIZED_FLAGS:---measure-vectorized-enabled=false} ${BANYANDB_TRACE_VECTORIZED_FLAGS:---trace-vectorized-enabled=false}
volumes:
- - ./data-generator/tmp/metadata:/tmp/measure/data/sw_metadata
+ - ../data-generator/tmp/sw_metadata:/tmp/measure/data/sw_metadata
- ./nodes.yaml:/etc/banyandb/nodes.yaml
networks:
- e2e
data-warm1:
extends:
- file: ../../script/docker-compose/base-compose.yml
+ file: ../../../script/docker-compose/base-compose.yml
service: data
hostname: data-warm1
command: data --node-discovery-mode=file --node-discovery-file-path=/etc/banyandb/nodes.yaml --node-labels type=warm ${BANYANDB_MEASURE_VECTORIZED_FLAGS:---measure-vectorized-enabled=false} ${BANYANDB_TRACE_VECTORIZED_FLAGS:---trace-vectorized-enabled=false}
@@ -39,22 +39,22 @@ services:
data-cold1:
extends:
- file: ../../script/docker-compose/base-compose.yml
+ file: ../../../script/docker-compose/base-compose.yml
service: data
hostname: data-cold1
command: data --node-discovery-mode=file --node-discovery-file-path=/etc/banyandb/nodes.yaml --node-labels type=cold ${BANYANDB_MEASURE_VECTORIZED_FLAGS:---measure-vectorized-enabled=false} ${BANYANDB_TRACE_VECTORIZED_FLAGS:---trace-vectorized-enabled=false}
volumes:
- - ./data-generator/tmp/measure:/tmp/measure
- - ./data-generator/tmp/stream:/tmp/stream
- - ./data-generator/tmp/property:/tmp/property
- - ./data-generator/tmp/trace:/tmp/trace
+ - ../data-generator/tmp/measure:/tmp/measure
+ - ../data-generator/tmp/stream:/tmp/stream
+ - ../data-generator/tmp/property:/tmp/property
+ - ../data-generator/tmp/trace:/tmp/trace
- ./nodes.yaml:/etc/banyandb/nodes.yaml
networks:
- e2e
liaison:
extends:
- file: ../../script/docker-compose/base-compose.yml
+ file: ../../../script/docker-compose/base-compose.yml
service: liaison
command: liaison --node-discovery-mode=file --node-discovery-file-path=/etc/banyandb/nodes.yaml --data-node-selector type=hot ${BANYANDB_MEASURE_VECTORIZED_FLAGS:---measure-vectorized-enabled=false} ${BANYANDB_TRACE_VECTORIZED_FLAGS:---trace-vectorized-enabled=false}
volumes:
@@ -64,7 +64,7 @@ services:
oap:
extends:
- file: ../../script/docker-compose/base-compose.yml
+ file: ../../../script/docker-compose/base-compose.yml
service: oap
environment:
SW_STORAGE: banyandb
@@ -88,14 +88,14 @@ services:
agent:
extends:
- file: ../../script/docker-compose/base-compose.yml
+ file: ../../../script/docker-compose/base-compose.yml
service: agent
networks:
- e2e
provider:
extends:
- file: ../../script/docker-compose/base-compose.yml
+ file: ../../../script/docker-compose/base-compose.yml
service: provider
ports:
- 9090
@@ -109,7 +109,7 @@ services:
consumer:
extends:
- file: ../../script/docker-compose/base-compose.yml
+ file: ../../../script/docker-compose/base-compose.yml
service: consumer
ports:
- 9092
diff --git a/test/e2e-v2/cases/lifecycle/file-discovery/e2e.yaml b/test/e2e-v2/cases/lifecycle/file-discovery/e2e.yaml
new file mode 100644
index 000000000..9100638ac
--- /dev/null
+++ b/test/e2e-v2/cases/lifecycle/file-discovery/e2e.yaml
@@ -0,0 +1,84 @@
+# 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.
+
+# Lifecycle e2e on docker-compose with file-based node discovery (nodes.yaml).
+# Run ../data-generator/gen.sh first: it produces the cold data mounted below.
+
+setup:
+ env: compose
+ file: docker-compose.yml
+ timeout: 20m
+ init-system-environment: ../../../script/env
+ steps:
+ - name: set PATH
+ command: export PATH=/tmp/skywalking-infra-e2e/bin:$PATH
+ - name: install yq
+ command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh yq
+ - name: install swctl
+ command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh swctl
+ - name: alias OAP address to the kind-style names used by ../lifecycle-cases.yaml
+ command: |
+ export service_skywalking_oap_host=${oap_host}
+ export service_skywalking_oap_12800=${oap_12800}
+
+trigger:
+ action: http
+ interval: 5s
+ times: -1
+ url: http://${consumer_host}:${consumer_9092}/users
+ method: POST
+ body: '{"id":"123","name":"skywalking"}'
+ headers:
+ "Content-Type": "application/json"
+
+verify:
+ # verify with retry strategy
+ retry:
+ # max retry count
+ count: 20
+ # the interval between two retries, in millisecond.
+ interval: 10s
+ cases:
+ - includes:
+ - ../../storage/storage-cases.yaml
+ - ../lifecycle-cases.yaml
+
+cleanup:
+ on: always
+ collect:
+ on: failure
+ output-dir: $SW_INFRA_E2E_LOG_DIR/banyandb-data
+ items:
+ - service: data-hot1
+ paths:
+ - /tmp/trace/
+ - /tmp/stream/
+ - /tmp/measure/
+ - /tmp/property/
+ - /tmp/schema-property/
+ - service: data-warm1
+ paths:
+ - /tmp/trace/
+ - /tmp/stream/
+ - /tmp/measure/
+ - /tmp/property/
+ - /tmp/schema-property/
+ - service: data-cold1
+ paths:
+ - /tmp/trace/
+ - /tmp/stream/
+ - /tmp/measure/
+ - /tmp/property/
+ - /tmp/schema-property/
diff --git a/test/e2e-v2/cases/lifecycle/nodes.yaml b/test/e2e-v2/cases/lifecycle/file-discovery/nodes.yaml
similarity index 100%
rename from test/e2e-v2/cases/lifecycle/nodes.yaml
rename to test/e2e-v2/cases/lifecycle/file-discovery/nodes.yaml
diff --git a/test/e2e-v2/cases/lifecycle/lifecycle-cases.yaml b/test/e2e-v2/cases/lifecycle/lifecycle-cases.yaml
new file mode 100644
index 000000000..ec57505cd
--- /dev/null
+++ b/test/e2e-v2/cases/lifecycle/lifecycle-cases.yaml
@@ -0,0 +1,46 @@
+# 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.
+
+# Verify cases shared by the file-discovery (docker-compose) and dns-discovery
+# (kind) lifecycle e2e. Both variants pre-load the same generated cold data, so
+# the queries and expected files are identical; only the cluster bootstrap differs.
+#
+# The OAP address uses the kind-style variables ${service_skywalking_oap_host}
+# and ${service_skywalking_oap_12800}, which the kind runner exports for the
+# helm-deployed `service/skywalking-oap`. The compose runner exports
+# ${oap_host}/${oap_12800} instead, so file-discovery/e2e.yaml aliases them to
+# these names in a setup step.
+
+cases:
+ - query: swctl --display yaml --base-url=http://${service_skywalking_oap_host}:${service_skywalking_oap_12800}/graphql metrics exec --expression="top_n(service_resp_time,3,des,attr0='GENERAL',attr1!='Not_exist')/100"
+ expected: ../storage/expected/topN-OP-service.yml
+
+ # cold data test
+ - query: swctl --display yaml --base-url=http://${service_skywalking_oap_host}:${service_skywalking_oap_12800}/graphql metrics exec --expression=service_resp_time --service-name=mock_a_service --start="-96h" --end="-48h" --cold=true --step=DAY
+ expected: ../storage/expected/metrics-has-value.yml
+ - query: swctl --display yaml --base-url=http://${service_skywalking_oap_host}:${service_skywalking_oap_12800}/graphql dependency service --service-name=mock_a_service --start="-96h" --end="-48h" --cold=true --step=DAY
+ expected: ./expected/dependency-services.yml
+ - query: swctl --display yaml --base-url=http://${service_skywalking_oap_host}:${service_skywalking_oap_12800}/graphql dependency instance --service-name=mock_a_service --dest-service-name=mock_b_service --start="-96h" --end="-48h" --cold=true --step=DAY
+ expected: ./expected/dependency-instance.yml
+ - query: swctl --display yaml --base-url=http://${service_skywalking_oap_host}:${service_skywalking_oap_12800}/graphql dependency endpoint --service-name=mock_a_service --endpoint-name=/dubbox-case/case/dubbox-rest/404-test --start="-96h" --end="-48h" --cold=true --step=DAY
+ expected: ./expected/dependency-endpoint.yml
+ # trace list
+ - query: swctl --display yaml --base-url=http://${service_skywalking_oap_host}:${service_skywalking_oap_12800}/graphql tv2 ls --service-name=mock_a_service --endpoint-name=/dubbox-case/case/dubbox-rest/404-test --tags http.method=get --start="-96h" --end="-48h" --cold=true
+ expected: ./expected/traces-list.yml
+ ## topN
+ - query: swctl --display yaml --base-url=http://${service_skywalking_oap_host}:${service_skywalking_oap_12800}/graphql metrics exec --expression="top_n(service_resp_time,3,des,attr0='GENERAL')" --start="-96h" --end="-48h" --cold=true --step=DAY
+ expected: ./expected/topN-OP-service.yml
+ - query: swctl --display yaml --base-url=http://${service_skywalking_oap_host}:${service_skywalking_oap_12800}/graphql metrics exec --expression="top_n(endpoint_resp_time,3,des)" --start="-96h" --end="-48h" --cold=true --step=DAY
+ expected: ./expected/topN-OP-endpoint.yml