This is an automated email from the ASF dual-hosted git repository.
zhongxjian pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/dubbo-kubernetes.git
The following commit(s) were added to refs/heads/master by this push:
new b3266156 [discovery] fix inject and xds push (#804)
b3266156 is described below
commit b32661561c172e69f831d8e4f780b53cb0fa71c9
Author: Jian Zhong <[email protected]>
AuthorDate: Tue Oct 28 10:08:13 2025 +0800
[discovery] fix inject and xds push (#804)
---
go.mod | 45 +---
go.sum | 85 +-----
pkg/kube/inject/app_probe.go | 14 +
pkg/kube/inject/inject.go | 45 ++++
pkg/kube/inject/validate.go | 23 ++
pkg/kube/inject/webhook.go | 72 ++++-
pkg/model/proxy.go | 5 +
pkg/model/xds.go | 1 +
pkg/util/protomarshal/protomarshal.go | 46 ++--
pkg/util/sets/set.go | 8 +
pkg/version/version.go | 6 +-
pkg/xds/server.go | 1 -
sail/pkg/model/context.go | 139 +++++++++-
sail/pkg/model/push_context.go | 5 +
sail/pkg/model/service.go | 15 +-
sail/pkg/serviceregistry/aggregate/controller.go | 42 ++-
.../serviceregistry/kube/controller/controller.go | 13 +
sail/pkg/xds/ads.go | 144 +++++++++-
sail/pkg/xds/auth.go | 7 +
sail/pkg/xds/delta.go | 299 +++++++++++++++++++--
sail/pkg/xds/v3/model.go | 1 +
sail/pkg/xds/xdsgen.go | 40 ++-
22 files changed, 852 insertions(+), 204 deletions(-)
diff --git a/go.mod b/go.mod
index f323b7b0..ea16e464 100644
--- a/go.mod
+++ b/go.mod
@@ -33,7 +33,7 @@ require (
github.com/docker/docker v27.5.1+incompatible
github.com/docker/docker-credential-helpers v0.9.3
github.com/docker/go-connections v0.5.0
- github.com/envoyproxy/go-control-plane/envoy
v1.32.5-0.20250921184633-9a6a6e1d1741
+ github.com/envoyproxy/go-control-plane/envoy
v1.32.5-0.20250627145903-197b96a9c7f8
github.com/evanphx/json-patch/v5 v5.9.11
github.com/fatih/color v1.18.0
github.com/fsnotify/fsnotify v1.9.0
@@ -44,6 +44,7 @@ require (
github.com/golang/protobuf v1.5.4
github.com/google/go-cmp v0.7.0
github.com/google/go-containerregistry v0.20.6
+ github.com/google/uuid v1.6.0
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
@@ -78,6 +79,7 @@ require (
k8s.io/klog/v2 v2.130.1
k8s.io/kubectl v0.33.3
k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d
+ sigs.k8s.io/mcs-api v0.2.0
sigs.k8s.io/yaml v1.6.0
)
@@ -102,7 +104,6 @@ require (
github.com/ProtonMail/go-crypto v1.1.3 // indirect
github.com/VividCortex/ewma v1.2.0 // indirect
github.com/agext/levenshtein v1.2.3 // indirect
- github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
github.com/apex/log v1.9.0 // indirect
github.com/aws/aws-sdk-go-v2 v1.26.1 // indirect
github.com/aws/aws-sdk-go-v2/config v1.27.12 // indirect
@@ -133,7 +134,6 @@ require (
github.com/containerd/typeurl v1.0.2 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc //
indirect
- github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
github.com/dgraph-io/ristretto v0.0.1 // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
github.com/dlclark/regexp2 v1.11.0 // indirect
@@ -142,7 +142,6 @@ require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
- github.com/envoyproxy/go-control-plane/contrib
v1.32.5-0.20250627145903-197b96a9c7f8 // indirect
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/gdamore/encoding v1.0.0 // indirect
@@ -150,25 +149,19 @@ require (
github.com/go-errors/errors v1.5.1 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-logr/logr v1.4.3 // indirect
- github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.21.2 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/swag v0.23.1 // indirect
github.com/gobwas/glob v0.2.3 // indirect
- github.com/goccy/go-json v0.10.5 // indirect
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da //
indirect
github.com/google/btree v1.1.3 // indirect
- github.com/google/cel-go v0.26.0 // indirect
github.com/google/gnostic-models v0.7.0 // indirect
+ github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
- github.com/google/uuid v1.6.0 // indirect
github.com/goph/emperror v0.17.2 // indirect
- github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 //
indirect
- github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 //
indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
- github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
@@ -180,12 +173,6 @@ require (
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
- github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect
- github.com/lestrrat-go/blackmagic v1.0.3 // indirect
- github.com/lestrrat-go/httpcc v1.0.1 // indirect
- github.com/lestrrat-go/iter v1.0.2 // indirect
- github.com/lestrrat-go/jwx v1.2.31 // indirect
- github.com/lestrrat-go/option v1.0.1 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/magiconair/properties v1.8.9 // indirect
github.com/mailru/easyjson v0.9.0 // indirect
@@ -193,7 +180,6 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
- github.com/miekg/dns v1.1.68 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e //
indirect
@@ -201,7 +187,6 @@ require (
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/buildkit v0.23.2 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect
- github.com/moby/spdystream v0.5.0 // indirect
github.com/moby/sys/capability v0.4.0 // indirect
github.com/moby/sys/mountinfo v0.7.2 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
@@ -212,8 +197,9 @@ require (
github.com/monochromegane/go-gitignore
v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 //
indirect
- github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f //
indirect
github.com/nikolalohinski/gonja v1.5.3 // indirect
+ github.com/onsi/ginkgo/v2 v2.25.3 // indirect
+ github.com/onsi/gomega v1.38.2 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/opencontainers/runc v1.1.7 // indirect
@@ -229,7 +215,6 @@ require (
github.com/prometheus/client_golang v1.23.2 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.66.1 // indirect
- github.com/prometheus/otlptranslator v0.0.0-20250717125610-8549f4ab4f8f
// indirect
github.com/prometheus/procfs v0.17.0 // indirect
github.com/rivo/tview v0.0.0-20220307222120-9994674d60a8 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
@@ -243,7 +228,6 @@ require (
github.com/spf13/afero v1.14.0 // indirect
github.com/spf13/cast v1.8.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
- github.com/stoewer/go-strcase v1.3.1 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/ulikunitz/xz v0.5.12 // indirect
github.com/vbatts/tar-split v0.12.1 // indirect
@@ -251,41 +235,26 @@ require (
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
github.com/yargevad/filepathx v1.0.0 // indirect
- go.opentelemetry.io/auto/sdk v1.1.0 // indirect
- go.opentelemetry.io/otel v1.37.0 // indirect
- go.opentelemetry.io/otel/exporters/prometheus v0.59.1 // indirect
- go.opentelemetry.io/otel/metric v1.37.0 // indirect
- go.opentelemetry.io/otel/sdk v1.37.0 // indirect
- go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect
- go.opentelemetry.io/otel/trace v1.37.0 // indirect
- go.opentelemetry.io/proto/otlp v1.7.1 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0
// indirect
go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 // indirect
- go.uber.org/multierr v1.11.0 // indirect
- go.uber.org/zap v1.27.0 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/mod v0.27.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/text v0.28.0 // indirect
- golang.org/x/tools v0.36.0 // indirect
google.golang.org/genproto/googleapis/api
v0.0.0-20250811230008-5f3141c8851a // indirect
google.golang.org/genproto/googleapis/rpc
v0.0.0-20250826171959-ef028d996bc1 // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
- gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
- k8s.io/apiserver v0.34.1 // indirect
k8s.io/cli-runtime v0.33.3 // indirect
k8s.io/kube-openapi v0.0.0-20250814151709-d7b6acb124c3 // indirect
- sigs.k8s.io/gateway-api v1.3.1-0.20250924180216-ab6b5a251c59 // indirect
- sigs.k8s.io/gateway-api-inference-extension
v0.0.0-20250917095812-173ad587b675 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/kustomize/api v0.19.0 // indirect
sigs.k8s.io/kustomize/kyaml v0.19.0 // indirect
- sigs.k8s.io/mcs-api v0.2.0 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
)
diff --git a/go.sum b/go.sum
index 0070e356..3f4542cc 100644
--- a/go.sum
+++ b/go.sum
@@ -22,8 +22,8 @@ cloud.google.com/go/vertexai v0.12.0
h1:zTadEo/CtsoyRXNx3uGCncoWAP1H2HakGqwznt+i
cloud.google.com/go/vertexai v0.12.0/go.mod
h1:8u+d0TsvBfAAd2x5R6GMgbYhsLgo3J7lmP4bR8g2ig8=
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
-github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6
h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
-github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod
h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24
h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod
h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/AlecAivazis/survey/v2 v2.3.7
h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ=
github.com/AlecAivazis/survey/v2 v2.3.7/go.mod
h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo=
github.com/AssemblyAI/assemblyai-go-sdk v1.3.0
h1:AtOVgGxUycvK4P4ypP+1ZupecvFgnfH+Jsum0o5ILoU=
@@ -89,8 +89,6 @@ github.com/andybalholm/cascadia v1.3.2
h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsVi
github.com/andybalholm/cascadia v1.3.2/go.mod
h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod
h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
-github.com/antlr4-go/antlr/v4 v4.13.1
h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
-github.com/antlr4-go/antlr/v4 v4.13.1/go.mod
h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0=
github.com/apex/log v1.9.0/go.mod
h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA=
github.com/apex/logs v1.0.0/go.mod
h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo=
@@ -167,8 +165,6 @@ github.com/cenkalti/backoff v2.2.1+incompatible
h1:tNowT99t7UNflLxfYYSlKYsBpXdEe
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod
h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cenkalti/backoff/v4 v4.3.0
h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod
h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
-github.com/cenkalti/backoff/v5 v5.0.2
h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
-github.com/cenkalti/backoff/v5 v5.0.2/go.mod
h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod
h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/certifi/gocertifi v0.0.0-20190105021004-abcd57078448/go.mod
h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
github.com/cespare/xxhash v1.1.0
h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
@@ -219,8 +215,6 @@ github.com/davecgh/go-spew v1.1.0/go.mod
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0
h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod
h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
github.com/dgraph-io/ristretto v0.0.1
h1:cJwdnj42uV8Jg4+KLrYovLiCgIfz9wtWm6E6KA+1tLs=
github.com/dgraph-io/ristretto v0.0.1/go.mod
h1:T40EBc7CJke8TkpiYfGGKAeFjSaxuFXhuXRyumBd6RE=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2
h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
@@ -257,10 +251,8 @@ github.com/emirpasic/gods v1.18.1/go.mod
h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FM
github.com/envoyproxy/go-control-plane v0.9.0/go.mod
h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane
v0.9.1-0.20191026205805-5f8ba28d4473/go.mod
h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod
h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
-github.com/envoyproxy/go-control-plane/contrib
v1.32.5-0.20250627145903-197b96a9c7f8
h1:KXgXPtBofHkRHr+8dO058dGZnLHapW7m0yJEgSYdAFA=
-github.com/envoyproxy/go-control-plane/contrib
v1.32.5-0.20250627145903-197b96a9c7f8/go.mod
h1:Nx/YcyEeIcgjT13QwKHdcPmS060urxZ835MeO8cLOrg=
-github.com/envoyproxy/go-control-plane/envoy
v1.32.5-0.20250921184633-9a6a6e1d1741
h1:cihocN3Y1vol5fNBh5Zxbk0s72PWbDL9WuKIVpCCkTI=
-github.com/envoyproxy/go-control-plane/envoy
v1.32.5-0.20250921184633-9a6a6e1d1741/go.mod
h1:2LcmvJoXsDSrsGZIxGM0Gah9ykiwTn/kgjyQdnNH8Jc=
+github.com/envoyproxy/go-control-plane/envoy
v1.32.5-0.20250627145903-197b96a9c7f8
h1:/F9jLyfDeNr4iZxyibtKlZxCDqCFEhoYiLdc9VOZT2E=
+github.com/envoyproxy/go-control-plane/envoy
v1.32.5-0.20250627145903-197b96a9c7f8/go.mod
h1:09qwbGVuSWWAyN5t/b3iyVfz5+z8QWGrzkoqm/8SbEs=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod
h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v1.2.1
h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod
h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
@@ -309,7 +301,6 @@ github.com/go-kit/log v0.1.0/go.mod
h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb
github.com/go-logfmt/logfmt v0.4.0/go.mod
h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod
h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v0.1.0/go.mod
h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
-github.com/go-logr/logr v1.2.2/go.mod
h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod
h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
@@ -327,8 +318,6 @@ github.com/go-task/slim-sprig/v3 v3.0.0
h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod
h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod
h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
-github.com/goccy/go-json v0.10.5
h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
-github.com/goccy/go-json v0.10.5/go.mod
h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod
h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod
h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@@ -357,8 +346,6 @@ github.com/golang/protobuf v1.5.4
h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
github.com/golang/protobuf v1.5.4/go.mod
h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod
h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
-github.com/google/cel-go v0.26.0
h1:DPGjXackMpJWH680oGY4lZhYjIameYmR+/6RBdDGmaI=
-github.com/google/cel-go v0.26.0/go.mod
h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM=
github.com/google/generative-ai-go v0.15.1
h1:n8aQUpvhPOlGVuM2DRkJ2jvx04zpp42B778AROJa+pQ=
github.com/google/generative-ai-go v0.15.1/go.mod
h1:AAucpWZjXsDKhQYWvCYuP6d0yB1kX998pJlOW1rAesw=
github.com/google/gnostic-models v0.7.0
h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
@@ -377,8 +364,6 @@ github.com/google/go-containerregistry v0.20.2/go.mod
h1:z38EKdKh4h7IP2gSfUUqEva
github.com/google/go-querystring v1.1.0
h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod
h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod
h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
-github.com/google/gofuzz v1.2.0/go.mod
h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a
h1://KbezygeMJZCSHH+HgUZiTeSoiuFspbMg1ge+eFj18=
github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a/go.mod
h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
@@ -399,10 +384,6 @@ github.com/gorilla/css v1.0.0
h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod
h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod
h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
-github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674
h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
-github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod
h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
-github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc
h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248=
-github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod
h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79
h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod
h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
@@ -411,16 +392,11 @@ github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2
h1:sGm2vDRFUrQJO/Veii4h4z
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2/go.mod
h1:wd1YpapPLivG6nQgbf7ZkG1hhSOXDhhn4MLTknx2aAc=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod
h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0
h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1
h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod
h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90=
github.com/hashicorp/errwrap v1.0.0/go.mod
h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0
h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod
h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1
h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod
h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
-github.com/hashicorp/golang-lru/v2 v2.0.7
h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
-github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod
h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod
h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/heroku/color v0.0.6 h1:UTFFMrmMLFcL3OweqP1lAdp8i1y/9oHqkeHjQ/b/Ny0=
@@ -466,23 +442,8 @@ github.com/kr/pty v1.1.1/go.mod
h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod
h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod
h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/kylelemons/godebug v1.1.0
h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
-github.com/kylelemons/godebug v1.1.0/go.mod
h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80
h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod
h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
-github.com/lestrrat-go/backoff/v2 v2.0.8
h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A=
-github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod
h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y=
-github.com/lestrrat-go/blackmagic v1.0.3
h1:94HXkVLxkZO9vJI/w2u1T0DAoprShFd13xtnSINtDWs=
-github.com/lestrrat-go/blackmagic v1.0.3/go.mod
h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw=
-github.com/lestrrat-go/httpcc v1.0.1
h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
-github.com/lestrrat-go/httpcc v1.0.1/go.mod
h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
-github.com/lestrrat-go/iter v1.0.2
h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
-github.com/lestrrat-go/iter v1.0.2/go.mod
h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
-github.com/lestrrat-go/jwx v1.2.31
h1:/OM9oNl/fzyldpv5HKZ9m7bTywa7COUfg8gujd9nJ54=
-github.com/lestrrat-go/jwx v1.2.31/go.mod
h1:eQJKoRwWcLg4PfD5CFA5gIZGxhPgoPYq9pZISdxLf0c=
-github.com/lestrrat-go/option v1.0.0/go.mod
h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
-github.com/lestrrat-go/option v1.0.1
h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
-github.com/lestrrat-go/option v1.0.1/go.mod
h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/lucasb-eyer/go-colorful v1.2.0
h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod
h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/magiconair/properties v1.8.1/go.mod
h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -506,8 +467,6 @@ github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b
h1:j7+1HpAFS1zy5+Q4qx1f
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod
h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/microcosm-cc/bluemonday v1.0.26
h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
github.com/microcosm-cc/bluemonday v1.0.26/go.mod
h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
-github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA=
-github.com/miekg/dns v1.1.68/go.mod
h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
github.com/mitchellh/copystructure v1.2.0
h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod
h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/go-homedir v1.1.0
h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
@@ -523,8 +482,6 @@ github.com/moby/buildkit v0.10.6
h1:DJlEuLIgnu34HQKF4n9Eg6q2YqQVC0eOpMb4p2eRS2w=
github.com/moby/buildkit v0.10.6/go.mod
h1:tQuuyTWtOb9D+RE425cwOCUkX0/oZ+5iBZ+uWpWQ9bU=
github.com/moby/patternmatcher v0.6.0
h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
github.com/moby/patternmatcher v0.6.0/go.mod
h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
-github.com/moby/spdystream v0.5.0
h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
-github.com/moby/spdystream v0.5.0/go.mod
h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
github.com/moby/sys/capability v0.4.0
h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCndZoHk=
github.com/moby/sys/capability v0.4.0/go.mod
h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I=
github.com/moby/sys/mountinfo v0.7.2
h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
@@ -549,13 +506,10 @@ github.com/morikuni/aec v1.0.0
h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod
h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod
h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
-github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f
h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
-github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod
h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/nikolalohinski/gonja v1.5.3
h1:GsA+EEaZDZPGJ8JtpeGN78jidhOlxeJROpqMT9fTj9c=
github.com/nikolalohinski/gonja v1.5.3/go.mod
h1:RmjwxNiXAEqcq1HeK5SSMmqFJvKOfTfXhkJv6YBtPa4=
github.com/onsi/ginkgo v1.6.0/go.mod
h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0/go.mod
h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo/v2 v2.25.3
h1:Ty8+Yi/ayDAGtk4XxmmfUy4GabvM+MegeB4cDLRi6nw=
github.com/onsi/ginkgo/v2 v2.25.3/go.mod
h1:43uiyQC4Ed2tkOzLsEYm7hnrb7UJTWHYNsuy3bG/snE=
github.com/onsi/gomega v1.5.0/go.mod
h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@@ -601,8 +555,6 @@ github.com/prometheus/client_model v0.6.2
h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNw
github.com/prometheus/client_model v0.6.2/go.mod
h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.66.1
h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
github.com/prometheus/common v0.66.1/go.mod
h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
-github.com/prometheus/otlptranslator v0.0.0-20250717125610-8549f4ab4f8f
h1:QQB6SuvGZjK8kdc2YaLJpYhV8fxauOsjE6jgcL6YJ8Q=
-github.com/prometheus/otlptranslator v0.0.0-20250717125610-8549f4ab4f8f/go.mod
h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI=
github.com/prometheus/procfs v0.17.0
h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
github.com/prometheus/procfs v0.17.0/go.mod
h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
github.com/rivo/tview v0.0.0-20220307222120-9994674d60a8
h1:xe+mmCnDN82KhC010l3NfYlA8ZbOuzbXAzSYBa6wbMc=
@@ -660,8 +612,6 @@ github.com/spf13/pflag v1.0.3/go.mod
h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
github.com/spf13/pflag v1.0.6/go.mod
h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M=
github.com/spf13/pflag v1.0.7/go.mod
h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/stoewer/go-strcase v1.3.1
h1:iS0MdW+kVTxgMoE1LAZyMiYJFKlOzLooE4MxjirtkAs=
-github.com/stoewer/go-strcase v1.3.1/go.mod
h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
github.com/stretchr/objx v0.1.0/go.mod
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod
h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
@@ -675,7 +625,6 @@ github.com/stretchr/testify v1.6.1/go.mod
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod
h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1/go.mod
h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod
h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.11.1
h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod
h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
@@ -728,12 +677,6 @@
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6h
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod
h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
go.opentelemetry.io/otel v1.37.0
h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/otel v1.37.0/go.mod
h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0
h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod
h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0
h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod
h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI=
-go.opentelemetry.io/otel/exporters/prometheus v0.59.1
h1:HcpSkTkJbggT8bjYP+BjyqPWlD17BH9C5CYNKeDzmcA=
-go.opentelemetry.io/otel/exporters/prometheus v0.59.1/go.mod
h1:0FJL+gjuUoM07xzik3KPBaN+nz/CoB15kV6WLMiXZag=
go.opentelemetry.io/otel/metric v1.37.0
h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
go.opentelemetry.io/otel/metric v1.37.0/go.mod
h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/sdk v1.37.0
h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
@@ -742,8 +685,6 @@ go.opentelemetry.io/otel/sdk/metric v1.37.0
h1:90lI228XrB9jCMuSdA0673aubgRobVZFh
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod
h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
go.opentelemetry.io/otel/trace v1.37.0
h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0/go.mod
h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
-go.opentelemetry.io/proto/otlp v1.7.1
h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
-go.opentelemetry.io/proto/otlp v1.7.1/go.mod
h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
go.starlark.net v0.0.0-20230302034142-4b1e35fe2254
h1:Ss6D3hLXTM0KobyBYEAygXzFfGcjnmfEJOBgSbemCtg=
go.starlark.net v0.0.0-20230302034142-4b1e35fe2254/go.mod
h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
go.uber.org/atomic v1.7.0/go.mod
h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
@@ -755,11 +696,7 @@ go.uber.org/goleak v1.1.10/go.mod
h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod
h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.6.0/go.mod
h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
-go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
-go.uber.org/multierr v1.11.0/go.mod
h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
-go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
-go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod
h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
@@ -927,8 +864,6 @@ gopkg.in/inf.v0 v0.9.1/go.mod
h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/natefinch/lumberjack.v2 v2.2.1
h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
-gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod
h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod
h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod
h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
@@ -953,22 +888,16 @@ istio.io/api v1.27.1-0.20250820125923-f5a5d3a605a9
h1:gVTxnhYGJ1pY+iqcz/mrbPSpdk
istio.io/api v1.27.1-0.20250820125923-f5a5d3a605a9/go.mod
h1:DTVGH6CLXj5W8FF9JUD3Tis78iRgT1WeuAnxfTz21Wg=
istio.io/client-go v1.27.1 h1:VWEtOzmv9gi4x3OPjN5wMFOBV1i95UIGcbYXoP4VVuA=
istio.io/client-go v1.27.1/go.mod
h1:otQns/CCDd4EoyEFWp8w+ksTP0T05baYTIx5FxqS8eM=
-istio.io/istio v0.0.0-20251004003413-450b9f38614f
h1:Kdl3XP0a/zFHU8//DLlj+LjGFWg/+XHzG1Z7iUMMjwc=
-istio.io/istio v0.0.0-20251004003413-450b9f38614f/go.mod
h1:rkwXkzAe+prvZU+JxLOJboEX44gr1ycbEPyl9k24CE8=
k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM=
k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk=
k8s.io/apiextensions-apiserver v0.34.1
h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI=
k8s.io/apiextensions-apiserver v0.34.1/go.mod
h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc=
k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4=
k8s.io/apimachinery v0.34.1/go.mod
h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
-k8s.io/apiserver v0.34.1 h1:U3JBGdgANK3dfFcyknWde1G6X1F4bg7PXuvlqt8lITA=
-k8s.io/apiserver v0.34.1/go.mod h1:eOOc9nrVqlBI1AFCvVzsob0OxtPZUCPiUJL45JOTBG0=
k8s.io/cli-runtime v0.33.3 h1:Dgy4vPjNIu8LMJBSvs8W0LcdV0PX/8aGG1DA1W8lklA=
k8s.io/cli-runtime v0.33.3/go.mod
h1:yklhLklD4vLS8HNGgC9wGiuHWze4g7x6XQZ+8edsKEo=
k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY=
k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8=
-k8s.io/component-base v0.34.1 h1:v7xFgG+ONhytZNFpIz5/kecwD+sUhVE6HU7qQUiRM4A=
-k8s.io/component-base v0.34.1/go.mod
h1:mknCpLlTSKHzAQJJnnHVKqjxR7gBeHRv0rPXA7gdtQ0=
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
@@ -981,12 +910,6 @@ k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d
h1:wAhiDyZ4Tdtt7e46e9M5ZSAJ/MnPG
k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d/go.mod
h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
nhooyr.io/websocket v1.8.7/go.mod
h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
-sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.32.1
h1:Cf+ed5N8038zbsaXFO7mKQDi/+VcSRafb0jM84KX5so=
-sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.32.1/go.mod
h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
-sigs.k8s.io/gateway-api v1.3.1-0.20250924180216-ab6b5a251c59
h1:oemARIB7UxADVkfGavZazg/PLWSKmzbZhr7l4P0kCho=
-sigs.k8s.io/gateway-api v1.3.1-0.20250924180216-ab6b5a251c59/go.mod
h1:eEPQfoYoowXAJ+/1RFugqZSanFd705bAPrIjB8Z8LdQ=
-sigs.k8s.io/gateway-api-inference-extension v0.0.0-20250917095812-173ad587b675
h1:CW+VWxazW54YzQnlHkyCE/WmAvF0YK7HOl+OK8IO3Ug=
-sigs.k8s.io/gateway-api-inference-extension
v0.0.0-20250917095812-173ad587b675/go.mod
h1:Tqmt4U654MNQkzC1lFYVa43wbUW7K8r8Lv6Sq2I3HCc=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730
h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod
h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/kustomize/api v0.19.0
h1:F+2HB2mU1MSiR9Hp1NEgoU2q9ItNOaBJl0I4Dlus5SQ=
diff --git a/pkg/kube/inject/app_probe.go b/pkg/kube/inject/app_probe.go
new file mode 100644
index 00000000..1a317e55
--- /dev/null
+++ b/pkg/kube/inject/app_probe.go
@@ -0,0 +1,14 @@
+package inject
+
+import corev1 "k8s.io/api/core/v1"
+
+func FindProxy(pod *corev1.Pod) *corev1.Container {
+ return FindContainerFromPod(ProxyContainerName, pod)
+}
+
+func FindContainerFromPod(name string, pod *corev1.Pod) *corev1.Container {
+ if c := FindContainer(name, pod.Spec.Containers); c != nil {
+ return c
+ }
+ return FindContainer(name, pod.Spec.InitContainers)
+}
diff --git a/pkg/kube/inject/inject.go b/pkg/kube/inject/inject.go
index 0989dae8..9a4bac68 100644
--- a/pkg/kube/inject/inject.go
+++ b/pkg/kube/inject/inject.go
@@ -15,10 +15,18 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/klog/v2"
"sigs.k8s.io/yaml"
+ "sort"
"strings"
"text/template"
)
+const (
+ ProxyContainerName = "dubbo-proxy"
+ ValidationContainerName = "dubbo-validation"
+ InitContainerName = "dubbo-init"
+ EnableCoreDumpName = "enable-core-dump"
+)
+
type (
Template *corev1.Pod
RawTemplates map[string]string
@@ -93,8 +101,14 @@ func potentialPodName(metadata metav1.ObjectMeta) string {
}
func RunTemplate(params InjectionParameters) (mergedPod *corev1.Pod,
templatePod *corev1.Pod, err error) {
+ metadata := ¶ms.pod.ObjectMeta
meshConfig := params.meshConfig
+ if err := validateAnnotations(metadata.GetAnnotations()); err != nil {
+ klog.Errorf("Injection failed due to invalid annotations: %v",
err)
+ return nil, nil, err
+ }
+
strippedPod, err := reinsertOverrides(stripPod(params))
if err != nil {
return nil, nil, err
@@ -139,6 +153,37 @@ func RunTemplate(params InjectionParameters) (mergedPod
*corev1.Pod, templatePod
return mergedPod, templatePod, nil
}
+func overwriteClusterInfo(pod *corev1.Pod, params InjectionParameters) {
+ c := FindProxy(pod)
+ if c == nil {
+ return
+ }
+ if len(params.proxyEnvs) > 0 {
+ updateClusterEnvs(c, params.proxyEnvs)
+ }
+}
+
+func updateClusterEnvs(container *corev1.Container, newKVs map[string]string) {
+ envVars := make([]corev1.EnvVar, 0)
+
+ for _, env := range container.Env {
+ if _, found := newKVs[env.Name]; !found {
+ envVars = append(envVars, env)
+ }
+ }
+
+ keys := make([]string, 0, len(newKVs))
+ for key := range newKVs {
+ keys = append(keys, key)
+ }
+ sort.Strings(keys)
+ for _, key := range keys {
+ val := newKVs[key]
+ envVars = append(envVars, corev1.EnvVar{Name: key, Value: val,
ValueFrom: nil})
+ }
+ container.Env = envVars
+}
+
func knownTemplates(t Templates) []string {
keys := make([]string, 0, len(t))
for k := range t {
diff --git a/pkg/kube/inject/validate.go b/pkg/kube/inject/validate.go
new file mode 100644
index 00000000..3a2230e2
--- /dev/null
+++ b/pkg/kube/inject/validate.go
@@ -0,0 +1,23 @@
+package inject
+
+import (
+ "fmt"
+ "github.com/hashicorp/go-multierror"
+)
+
+type annotationValidationFunc func(value string) error
+
+var (
+ AnnotationValidation = map[string]annotationValidationFunc{}
+)
+
+func validateAnnotations(annotations map[string]string) (err error) {
+ for name, value := range annotations {
+ if v, ok := AnnotationValidation[name]; ok {
+ if e := v(value); e != nil {
+ err = multierror.Append(err,
fmt.Errorf("invalid value '%s' for annotation '%s': %v", value, name, e))
+ }
+ }
+ }
+ return
+}
diff --git a/pkg/kube/inject/webhook.go b/pkg/kube/inject/webhook.go
index 6f24befc..f36e9cca 100644
--- a/pkg/kube/inject/webhook.go
+++ b/pkg/kube/inject/webhook.go
@@ -5,10 +5,12 @@ import (
"errors"
"fmt"
opconfig "github.com/apache/dubbo-kubernetes/operator/pkg/apis"
+ "github.com/apache/dubbo-kubernetes/pkg/config/mesh"
"github.com/apache/dubbo-kubernetes/pkg/kube"
"github.com/apache/dubbo-kubernetes/pkg/util/protomarshal"
"github.com/apache/dubbo-kubernetes/sail/pkg/model"
"gomodules.xyz/jsonpatch/v2"
+ "istio.io/api/annotation"
meshconfig "istio.io/api/mesh/v1alpha1"
admissionv1 "k8s.io/api/admission/v1"
kubeApiAdmissionv1beta1 "k8s.io/api/admission/v1beta1"
@@ -170,7 +172,6 @@ func (wh *Webhook) serveInject(w http.ResponseWriter, r
*http.Request) {
return
}
- // verify the content type is accurate
contentType := r.Header.Get("Content-Type")
if contentType != "application/json" {
http.Error(w, "invalid Content-Type, want `application/json`",
http.StatusUnsupportedMediaType)
@@ -239,13 +240,11 @@ type InjectionParameters struct {
}
func injectPod(req InjectionParameters) ([]byte, error) {
- // The patch will be built relative to the initial pod, capture its
current state
originalPodSpec, err := json.Marshal(req.pod)
if err != nil {
return nil, err
}
- // Run the injection template, giving us a partial pod spec
mergedPod, injectedPodData, err := RunTemplate(req)
if err != nil {
return nil, fmt.Errorf("failed to run injection template: %v",
err)
@@ -256,6 +255,10 @@ func injectPod(req InjectionParameters) ([]byte, error) {
return nil, fmt.Errorf("failed to re apply container: %v", err)
}
+ if err := postProcessPod(mergedPod, *injectedPodData, req); err != nil {
+ return nil, fmt.Errorf("failed to process pod: %v", err)
+ }
+
patch, err := createPatch(mergedPod, originalPodSpec)
if err != nil {
return nil, fmt.Errorf("failed to create patch: %v", err)
@@ -264,6 +267,69 @@ func injectPod(req InjectionParameters) ([]byte, error) {
return patch, nil
}
+func postProcessPod(pod *corev1.Pod, injectedPod corev1.Pod, req
InjectionParameters) error {
+ if pod.Annotations == nil {
+ pod.Annotations = map[string]string{}
+ }
+ if pod.Labels == nil {
+ pod.Labels = map[string]string{}
+ }
+
+ overwriteClusterInfo(pod, req)
+
+ if err := reorderPod(pod, req); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func reorderPod(pod *corev1.Pod, req InjectionParameters) error {
+ var merr error
+ mc := req.meshConfig
+ // Get copy of pod proxyconfig, to determine container ordering
+ if pca, f :=
req.pod.ObjectMeta.GetAnnotations()[annotation.ProxyConfig.Name]; f {
+ mc, merr = mesh.ApplyProxyConfig(pca, req.meshConfig)
+ if merr != nil {
+ return merr
+ }
+ }
+
+ // nolint: staticcheck
+ holdPod :=
mc.GetDefaultConfig().GetHoldApplicationUntilProxyStarts().GetValue()
+
+ proxyLocation := MoveLast
+ // If HoldApplicationUntilProxyStarts is set, reorder the proxy location
+ if holdPod {
+ proxyLocation = MoveFirst
+ }
+
+ // Proxy container should be last, unless
HoldApplicationUntilProxyStarts is set
+ // This is to ensure `kubectl exec` and similar commands continue to
default to the user's container
+ pod.Spec.Containers = modifyContainers(pod.Spec.Containers,
ProxyContainerName, proxyLocation)
+ if hasContainer(pod.Spec.InitContainers, ProxyContainerName) {
+ pod.Spec.InitContainers =
modifyContainers(pod.Spec.InitContainers, EnableCoreDumpName, MoveFirst)
+ pod.Spec.InitContainers =
modifyContainers(pod.Spec.InitContainers, ProxyContainerName, MoveFirst)
+ pod.Spec.InitContainers =
modifyContainers(pod.Spec.InitContainers, ValidationContainerName, MoveFirst)
+ pod.Spec.InitContainers =
modifyContainers(pod.Spec.InitContainers, InitContainerName, MoveFirst)
+ } else {
+ pod.Spec.InitContainers =
modifyContainers(pod.Spec.InitContainers, ValidationContainerName, MoveFirst)
+ pod.Spec.InitContainers =
modifyContainers(pod.Spec.InitContainers, InitContainerName, MoveLast)
+ pod.Spec.InitContainers =
modifyContainers(pod.Spec.InitContainers, EnableCoreDumpName, MoveLast)
+ }
+
+ return nil
+}
+
+func hasContainer(cl []corev1.Container, name string) bool {
+ for _, c := range cl {
+ if c.Name == name {
+ return true
+ }
+ }
+ return false
+}
+
func reapplyOverwrittenContainers(finalPod *corev1.Pod, originalPod
*corev1.Pod, templatePod *corev1.Pod,
proxyConfig *meshconfig.ProxyConfig,
) (*corev1.Pod, error) {
diff --git a/pkg/model/proxy.go b/pkg/model/proxy.go
index e9924c6d..ea270a0c 100644
--- a/pkg/model/proxy.go
+++ b/pkg/model/proxy.go
@@ -5,4 +5,9 @@ import "github.com/apache/dubbo-kubernetes/pkg/cluster"
type NodeMetadata struct {
Generator string `json:"GENERATOR,omitempty"`
ClusterID cluster.ID `json:"CLUSTER_ID,omitempty"`
+ Namespace string `json:"NAMESPACE,omitempty"`
+}
+
+type BootstrapNodeMetadata struct {
+ NodeMetadata
}
diff --git a/pkg/model/xds.go b/pkg/model/xds.go
index 72d334d3..130c49a6 100644
--- a/pkg/model/xds.go
+++ b/pkg/model/xds.go
@@ -8,6 +8,7 @@ const (
RouteType = APITypePrefix +
"envoy.config.route.v3.RouteConfiguration"
SecretType = APITypePrefix +
"envoy.extensions.transport_sockets.tls.v3.Secret"
ExtensionConfigurationType = APITypePrefix +
"envoy.config.core.v3.TypedExtensionConfig"
+ AddressType = APITypePrefix + "dubbo.workload.Address"
HealthInfoType = APITypePrefix + "dubbo.v1.HealthInformation"
DebugType = "dubbo.io/debug"
diff --git a/pkg/util/protomarshal/protomarshal.go
b/pkg/util/protomarshal/protomarshal.go
index 8dfbd950..564aace8 100644
--- a/pkg/util/protomarshal/protomarshal.go
+++ b/pkg/util/protomarshal/protomarshal.go
@@ -40,16 +40,10 @@ func Unmarshal(b []byte, m proto.Message) error {
return strictUnmarshaler.Unmarshal(bytes.NewReader(b),
legacyproto.MessageV1(m))
}
-func UnmarshalAllowUnknown(b []byte, m proto.Message) error {
- return unmarshaler.Unmarshal(bytes.NewReader(b),
legacyproto.MessageV1(m))
-}
-
-// ToJSON marshals a proto to canonical JSON
func ToJSON(msg proto.Message) (string, error) {
return ToJSONWithIndent(msg, "")
}
-// Marshal marshals a proto to canonical JSON
func Marshal(msg proto.Message) ([]byte, error) {
res, err := ToJSONWithIndent(msg, "")
if err != nil {
@@ -58,7 +52,6 @@ func Marshal(msg proto.Message) ([]byte, error) {
return []byte(res), err
}
-// MarshalIndent marshals a proto to canonical JSON with indentation
func MarshalIndent(msg proto.Message, indent string) ([]byte, error) {
res, err := ToJSONWithIndent(msg, indent)
if err != nil {
@@ -67,13 +60,10 @@ func MarshalIndent(msg proto.Message, indent string)
([]byte, error) {
return []byte(res), err
}
-// ToJSONWithIndent marshals a proto to canonical JSON with pretty printed
string
func ToJSONWithIndent(msg proto.Message, indent string) (string, error) {
return ToJSONWithOptions(msg, indent, false)
}
-// ToJSONWithOptions marshals a proto to canonical JSON with options to indent
and
-// print enums' int values
func ToJSONWithOptions(msg proto.Message, indent string, enumsAsInts bool)
(string, error) {
if msg == nil {
return "", errors.New("unexpected nil message")
@@ -84,19 +74,6 @@ func ToJSONWithOptions(msg proto.Message, indent string,
enumsAsInts bool) (stri
return m.MarshalToString(legacyproto.MessageV1(msg))
}
-func ToJSONWithAnyResolver(msg proto.Message, indent string, anyResolver
jsonpb.AnyResolver) (string, error) {
- if msg == nil {
- return "", errors.New("unexpected nil message")
- }
-
- m := jsonpb.Marshaler{
- Indent: indent,
- AnyResolver: anyResolver,
- }
- return m.MarshalToString(legacyproto.MessageV1(msg))
-}
-
-// ToYAML marshals a proto to canonical YAML
func ToYAML(msg proto.Message) (string, error) {
js, err := ToJSON(msg)
if err != nil {
@@ -106,7 +83,6 @@ func ToYAML(msg proto.Message) (string, error) {
return string(yml), err
}
-// ApplyJSON unmarshals a JSON string into a proto message.
func ApplyJSON(js string, pb proto.Message) error {
reader := strings.NewReader(js)
m := jsonpb.Unmarshaler{}
@@ -119,15 +95,12 @@ func ApplyJSON(js string, pb proto.Message) error {
return nil
}
-// ApplyJSONStrict unmarshals a JSON string into a proto message.
func ApplyJSONStrict(js string, pb proto.Message) error {
reader := strings.NewReader(js)
m := jsonpb.Unmarshaler{}
return m.Unmarshal(reader, legacyproto.MessageV1(pb))
}
-// ApplyYAML unmarshals a YAML string into a proto message.
-// Unknown fields are allowed.
func ApplyYAML(yml string, pb proto.Message) error {
js, err := yaml.YAMLToJSON([]byte(yml))
if err != nil {
@@ -141,14 +114,10 @@ type ComparableMessage interface {
proto.Message
}
-// Clone is a small wrapper that handles the upstream function not returning a
typed message
func Clone[T proto.Message](obj T) T {
return proto.Clone(obj).(T)
}
-// MessageToStructSlow encodes a protobuf Message into a Struct.
-// It roundtrips trough JSON so it is slow.
-// Copied from
https://github.com/envoyproxy/go-control-plane/blob/d77bd2ea68bdbb72afd65a7ddf6fe8969e556c45/pkg/conversion/struct.go#L29
func MessageToStructSlow(msg proto.Message) (*structpb.Struct, error) {
if msg == nil {
return nil, errors.New("nil message")
@@ -166,3 +135,18 @@ func MessageToStructSlow(msg proto.Message)
(*structpb.Struct, error) {
return pbs, nil
}
+
+func MarshalProtoNames(msg proto.Message) ([]byte, error) {
+ if msg == nil {
+ return nil, errors.New("unexpected nil message")
+ }
+
+ // Marshal from proto to json bytes
+ m := jsonpb.Marshaler{OrigName: true}
+ buf := &bytes.Buffer{}
+ err := m.Marshal(buf, legacyproto.MessageV1(msg))
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
diff --git a/pkg/util/sets/set.go b/pkg/util/sets/set.go
index d9b0ddd5..6638b569 100644
--- a/pkg/util/sets/set.go
+++ b/pkg/util/sets/set.go
@@ -292,3 +292,11 @@ func DeleteCleanupLast[K comparable, T comparable](m
map[K]Set[T], k K, v T) {
delete(m, k)
}
}
+
+func (s Set[T]) DeleteContains(item T) bool {
+ if !s.Contains(item) {
+ return false
+ }
+ delete(s, item)
+ return true
+}
diff --git a/pkg/version/version.go b/pkg/version/version.go
index 8ae9ffed..1a6d8d17 100644
--- a/pkg/version/version.go
+++ b/pkg/version/version.go
@@ -54,7 +54,11 @@ var (
gitTag = "unknown"
gitCommit = "unknown"
buildDate = "unknown"
- Envoy = "unknown"
+)
+
+var (
+ // Info exports the build version information.
+ Info BuildInfo
)
type BuildInfo struct {
diff --git a/pkg/xds/server.go b/pkg/xds/server.go
index 1527bf97..a8230e14 100644
--- a/pkg/xds/server.go
+++ b/pkg/xds/server.go
@@ -64,7 +64,6 @@ type Watcher interface {
GetWatchedResource(url string) *WatchedResource
NewWatchedResource(url string, names []string)
UpdateWatchedResource(string, func(*WatchedResource) *WatchedResource)
- // GetID identifies an xDS client. This is different from a connection
ID.
GetID() string
}
diff --git a/sail/pkg/model/context.go b/sail/pkg/model/context.go
index f86b60a3..99f35526 100644
--- a/sail/pkg/model/context.go
+++ b/sail/pkg/model/context.go
@@ -18,24 +18,49 @@
package model
import (
+ "encoding/json"
"fmt"
"github.com/apache/dubbo-kubernetes/pkg/config/constants"
"github.com/apache/dubbo-kubernetes/pkg/config/host"
"github.com/apache/dubbo-kubernetes/pkg/config/mesh"
"github.com/apache/dubbo-kubernetes/pkg/config/mesh/meshwatcher"
+ "github.com/apache/dubbo-kubernetes/pkg/config/schema/kind"
+ "github.com/apache/dubbo-kubernetes/pkg/maps"
pm "github.com/apache/dubbo-kubernetes/pkg/model"
+ "github.com/apache/dubbo-kubernetes/pkg/util/protomarshal"
"github.com/apache/dubbo-kubernetes/pkg/util/sets"
"github.com/apache/dubbo-kubernetes/pkg/xds"
+ core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
discovery
"github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
+ "google.golang.org/protobuf/types/known/structpb"
meshconfig "istio.io/api/mesh/v1alpha1"
"net"
+ "sort"
"strconv"
+ "strings"
"sync"
"time"
)
+const (
+ serviceNodeSeparator = "~"
+)
+
+type XdsResourceGenerator interface {
+ // Generate generates the Sotw resources for Xds.
+ Generate(proxy *Proxy, w *WatchedResource, req *PushRequest)
(Resources, XdsLogDetails, error)
+}
+
+// XdsDeltaResourceGenerator generates Sotw and delta resources.
+type XdsDeltaResourceGenerator interface {
+ XdsResourceGenerator
+ // GenerateDeltas returns the changed and removed resources, along with
whether or not delta was actually used.
+ GenerateDeltas(proxy *Proxy, req *PushRequest, w *WatchedResource)
(Resources, DeletedResources, XdsLogDetails, bool, error)
+}
+
type (
- NodeMetadata = pm.NodeMetadata
+ NodeMetadata = pm.NodeMetadata
+ BootstrapNodeMetadata = pm.BootstrapNodeMetadata
)
type Watcher = meshwatcher.WatcherCollection
@@ -145,8 +170,12 @@ type Proxy struct {
LastPushTime time.Time
WatchedResources map[string]*WatchedResource
ID string
+ DNSDomain string
Metadata *NodeMetadata
IPAddresses []string
+ XdsNode *core.Node
+ ConfigNamespace string
+ ServiceTargets []ServiceTarget
}
func (node *Proxy) GetWatchedResource(typeURL string) *WatchedResource {
@@ -193,6 +222,43 @@ func (node *Proxy) IsProxylessGrpc() bool {
return node.Metadata != nil && node.Metadata.Generator == "grpc"
}
+func (node *Proxy) ShouldUpdateServiceTargets(updates sets.Set[ConfigKey])
bool {
+ // we only care for services which can actually select this proxy
+ for config := range updates {
+ if config.Kind == kind.ServiceEntry || config.Namespace ==
node.Metadata.Namespace {
+ return true
+ }
+ }
+
+ return false
+}
+
+func (node *Proxy) SetServiceTargets(serviceDiscovery ServiceDiscovery) {
+ instances := serviceDiscovery.GetProxyServiceTargets(node)
+
+ // Keep service instances in order of creation/hostname.
+ sort.SliceStable(instances, func(i, j int) bool {
+ if instances[i].Service != nil && instances[j].Service != nil {
+ if
!instances[i].Service.CreationTime.Equal(instances[j].Service.CreationTime) {
+ return
instances[i].Service.CreationTime.Before(instances[j].Service.CreationTime)
+ }
+ // Additionally, sort by hostname just in case services
created automatically at the same second.
+ return instances[i].Service.Hostname <
instances[j].Service.Hostname
+ }
+ return true
+ })
+
+ node.ServiceTargets = instances
+}
+
+func (node *Proxy) ShallowCloneWatchedResources() map[string]*WatchedResource {
+ node.RLock()
+ defer node.RUnlock()
+ return maps.Clone(node.WatchedResources)
+}
+
+type DeletedResources = []string
+
type XdsLogDetails struct {
Incremental bool
AdditionalInfo string
@@ -200,7 +266,72 @@ type XdsLogDetails struct {
type Resources = []*discovery.Resource
-type XdsResourceGenerator interface {
- // Generate generates the Sotw resources for Xds.
- Generate(proxy *Proxy, w *WatchedResource, req *PushRequest)
(Resources, XdsLogDetails, error)
+func ParseMetadata(metadata *structpb.Struct) (*NodeMetadata, error) {
+ if metadata == nil {
+ return &NodeMetadata{}, nil
+ }
+
+ bootstrapNodeMeta, err := ParseBootstrapNodeMetadata(metadata)
+ if err != nil {
+ return nil, err
+ }
+ return &bootstrapNodeMeta.NodeMetadata, nil
+}
+
+func ParseBootstrapNodeMetadata(metadata *structpb.Struct)
(*BootstrapNodeMetadata, error) {
+ if metadata == nil {
+ return &BootstrapNodeMetadata{}, nil
+ }
+
+ b, err := protomarshal.MarshalProtoNames(metadata)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read node metadata %v: %v",
metadata, err)
+ }
+ meta := &BootstrapNodeMetadata{}
+ if err := json.Unmarshal(b, meta); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal node metadata (%v):
%v", string(b), err)
+ }
+ return meta, nil
+}
+
+func ParseServiceNodeWithMetadata(nodeID string, metadata *NodeMetadata)
(*Proxy, error) {
+ parts := strings.Split(nodeID, serviceNodeSeparator)
+ out := &Proxy{
+ Metadata: metadata,
+ }
+
+ if len(parts) != 4 {
+ return out, fmt.Errorf("missing parts in the service node %q",
nodeID)
+ }
+ // TODO ?
+
+ // Does query from ingress or router have to carry valid IP address?
+ if len(out.IPAddresses) == 0 {
+ return out, fmt.Errorf("no valid IP address in the service node
id or metadata")
+ }
+
+ out.ID = parts[2]
+ out.DNSDomain = parts[3]
+ return out, nil
+}
+
+func GetProxyConfigNamespace(proxy *Proxy) string {
+ if proxy == nil {
+ return ""
+ }
+
+ // First look for ISTIO_META_CONFIG_NAMESPACE
+ // All newer proxies (from Istio 1.1 onwards) are supposed to supply
this
+ if len(proxy.Metadata.Namespace) > 0 {
+ return proxy.Metadata.Namespace
+ }
+
+ // if not found, for backward compatibility, extract the namespace from
+ // the proxy domain. this is a k8s specific hack and should be enabled
+ parts := strings.Split(proxy.DNSDomain, ".")
+ if len(parts) > 1 { // k8s will have namespace.<domain>
+ return parts[0]
+ }
+
+ return ""
}
diff --git a/sail/pkg/model/push_context.go b/sail/pkg/model/push_context.go
index eb147798..a51ae06d 100644
--- a/sail/pkg/model/push_context.go
+++ b/sail/pkg/model/push_context.go
@@ -52,6 +52,7 @@ const (
HeadlessEndpointUpdate TriggerReason = "headlessendpoint"
EndpointUpdate TriggerReason = "endpoint"
ProxyUpdate TriggerReason = "proxy"
+ DependentResource TriggerReason = "depdendentresource"
)
type ProxyPushStatus struct {
@@ -149,6 +150,10 @@ func (pr *PushRequest) CopyMerge(other *PushRequest)
*PushRequest {
return merged
}
+func (pr *PushRequest) IsProxyUpdate() bool {
+ return pr.Reason.Has(ProxyUpdate)
+}
+
type XDSUpdater interface {
ConfigUpdate(req *PushRequest)
ServiceUpdate(shard ShardKey, hostname string, namespace string, event
Event)
diff --git a/sail/pkg/model/service.go b/sail/pkg/model/service.go
index 95985f8b..dd47b061 100644
--- a/sail/pkg/model/service.go
+++ b/sail/pkg/model/service.go
@@ -279,6 +279,19 @@ func (s *Service) Key() string {
return s.Attributes.Namespace + "/" + string(s.Hostname)
}
+type (
+ ServicePort = *Port
+ ServiceInstancePort struct {
+ ServicePort
+ TargetPort uint32
+ }
+)
+
+type ServiceTarget struct {
+ Service *Service
+ Port ServiceInstancePort
+}
+
type Port struct {
Name string `json:"name,omitempty"`
Port int `json:"port"`
@@ -306,6 +319,7 @@ func (ports PortList) Equals(other PortList) bool {
type ServiceDiscovery interface {
Services() []*Service
GetService(hostname host.Name) *Service
+ GetProxyServiceTargets(*Proxy) []ServiceTarget
}
func (s *ServiceAttributes) DeepCopy() ServiceAttributes {
@@ -331,7 +345,6 @@ func (s *ServiceAttributes) DeepCopy() ServiceAttributes {
out.Aliases = slices.Clone(s.Aliases)
out.PassthroughTargetPorts = maps.Clone(out.PassthroughTargetPorts)
- // AddressMap contains a mutex, which is safe to return a copy in this
case.
// nolint: govet
return out
}
diff --git a/sail/pkg/serviceregistry/aggregate/controller.go
b/sail/pkg/serviceregistry/aggregate/controller.go
index 528de8e7..4a6feaf8 100644
--- a/sail/pkg/serviceregistry/aggregate/controller.go
+++ b/sail/pkg/serviceregistry/aggregate/controller.go
@@ -27,7 +27,6 @@ type Controller struct {
type registryEntry struct {
serviceregistry.Instance
- // stop if not nil is the per-registry stop chan. If null, the server
stop chan should be used to Run the registry.
stop <-chan struct{}
}
@@ -45,11 +44,9 @@ func NewController(opt Options) *Controller {
}
}
-// Run starts all the controllers
func (c *Controller) Run(stop <-chan struct{}) {
c.storeLock.Lock()
for _, r := range c.registries {
- // prefer the per-registry stop channel
registryStop := stop
if s := r.stop; s != nil {
registryStop = s
@@ -186,3 +183,42 @@ func mergeService(dst, src *model.Service, srcRegistry
serviceregistry.Instance)
dst.ClusterVIPs.SetAddressesFor(clusterID, newAddresses)
}
}
+
+func (c *Controller) GetProxyServiceTargets(node *model.Proxy)
[]model.ServiceTarget {
+ out := make([]model.ServiceTarget, 0)
+ nodeClusterID := nodeClusterID(node)
+ for _, r := range c.GetRegistries() {
+ if skipSearchingRegistryForProxy(nodeClusterID, r) {
+ klog.Infof("GetProxyServiceTargets(): not searching
registry %v: proxy %v CLUSTER_ID is %v",
+ r.Cluster(), node.ID, nodeClusterID)
+ continue
+ }
+
+ instances := r.GetProxyServiceTargets(node)
+ if len(instances) > 0 {
+ out = append(out, instances...)
+ }
+ }
+
+ if len(out) == 0 {
+ klog.Infof("GetProxyServiceTargets(): no service targets found
for proxy %s with clusterID %s",
+ node.ID, nodeClusterID.String())
+ }
+
+ return out
+}
+
+func nodeClusterID(node *model.Proxy) cluster.ID {
+ if node.Metadata == nil || node.Metadata.ClusterID == "" {
+ return ""
+ }
+ return node.Metadata.ClusterID
+}
+
+func skipSearchingRegistryForProxy(nodeClusterID cluster.ID, r
serviceregistry.Instance) bool {
+ if r.Provider() != provider.Kubernetes || nodeClusterID == "" {
+ return false
+ }
+
+ return !r.Cluster().Equals(nodeClusterID)
+}
diff --git a/sail/pkg/serviceregistry/kube/controller/controller.go
b/sail/pkg/serviceregistry/kube/controller/controller.go
index 558cfcb3..e0ed972d 100644
--- a/sail/pkg/serviceregistry/kube/controller/controller.go
+++ b/sail/pkg/serviceregistry/kube/controller/controller.go
@@ -187,6 +187,19 @@ func (c *Controller) Services() []*model.Service {
return out
}
+func (c *Controller) isControllerForProxy(proxy *model.Proxy) bool {
+ return proxy.Metadata.ClusterID == "" || proxy.Metadata.ClusterID ==
c.Cluster()
+}
+
+func (c *Controller) GetProxyServiceTargets(proxy *model.Proxy)
[]model.ServiceTarget {
+ if !c.isControllerForProxy(proxy) {
+ klog.Errorf("proxy is in cluster %v, but controller is for
cluster %v", proxy.Metadata.ClusterID, c.Cluster())
+ return nil
+ }
+ // TODO
+ return nil
+}
+
// GetService implements a service catalog operation by hostname specified.
func (c *Controller) GetService(hostname host.Name) *model.Service {
c.RLock()
diff --git a/sail/pkg/xds/ads.go b/sail/pkg/xds/ads.go
index f5bbd7d1..e74bba98 100644
--- a/sail/pkg/xds/ads.go
+++ b/sail/pkg/xds/ads.go
@@ -30,10 +30,14 @@ import (
"google.golang.org/grpc/peer"
"google.golang.org/grpc/status"
"k8s.io/klog/v2"
+ "strconv"
"strings"
+ "sync/atomic"
"time"
)
+var connectionNumber = int64(0)
+
type (
DiscoveryStream = xds.DiscoveryStream
DeltaDiscoveryStream =
discovery.AggregatedDiscoveryService_DeltaAggregatedResourcesServer
@@ -91,7 +95,6 @@ func (s *DiscoveryServer) AdsPushAll(req *model.PushRequest) {
totalService := len(req.Push.GetAllServices())
klog.Infof("XDS: Pushing Services:%d ConnectedEndpoints:%d",
totalService, s.adsClientCount())
- // Make sure the ConfigsUpdated map exists
if req.ConfigsUpdated == nil {
req.ConfigsUpdated = make(sets.Set[model.ConfigKey])
}
@@ -105,7 +108,67 @@ func (s *DiscoveryServer) adsClientCount() int {
return len(s.adsClients)
}
+func (s *DiscoveryServer) computeProxyState(proxy *model.Proxy, request
*model.PushRequest) {
+ proxy.Lock()
+ defer proxy.Unlock()
+ // 1. If request == nil(initiation phase) or request.ConfigsUpdated ==
nil(global push), set proxy serviceTargets.
+ // 2. otherwise only set when svc update, this is for the case that a
service may select the proxy
+ if request == nil || request.Forced ||
+ proxy.ShouldUpdateServiceTargets(request.ConfigsUpdated) {
+ proxy.SetServiceTargets(s.Env.ServiceDiscovery)
+ }
+
+ recomputeLabels := request == nil || request.IsProxyUpdate()
+ if recomputeLabels {
+ }
+
+ push := proxy.LastPushContext
+ if request == nil {
+ } else {
+ push = request.Push
+ if request.Forced {
+ }
+ for conf := range request.ConfigsUpdated {
+ switch conf.Kind {
+ }
+ }
+ }
+ proxy.LastPushContext = push
+ if request != nil {
+ proxy.LastPushTime = request.Start
+ }
+}
+
+func connectionID(node string) string {
+ id := atomic.AddInt64(&connectionNumber, 1)
+ return node + "-" + strconv.FormatInt(id, 10)
+}
+
func (s *DiscoveryServer) initConnection(node *core.Node, con *Connection,
identities []string) error {
+ proxy, err := s.initProxyMetadata(node)
+ if err != nil {
+ return err
+ }
+
+ if alias, exists := s.ClusterAliases[proxy.Metadata.ClusterID]; exists {
+ proxy.Metadata.ClusterID = alias
+ }
+
+ proxy.LastPushContext = s.globalPushContext()
+ con.SetID(connectionID(proxy.ID))
+ con.node = node
+ con.proxy = proxy
+
+ if err := s.authorize(con, identities); err != nil {
+ return err
+ }
+ s.addCon(con.ID(), con)
+
+ defer con.MarkInitialized()
+ if err := s.initializeProxy(con); err != nil {
+ s.closeConnection(con)
+ return err
+ }
return nil
}
@@ -114,6 +177,51 @@ func (s *DiscoveryServer) closeConnection(con *Connection)
{
if con.ID() == "" {
return
}
+ s.removeCon(con.ID())
+}
+
+func (s *DiscoveryServer) initializeProxy(con *Connection) error {
+ proxy := con.proxy
+ s.computeProxyState(proxy, nil)
+ proxy.WatchedResources = map[string]*model.WatchedResource{}
+ // Based on node metadata and version, we can associate a different
generator.
+ if proxy.Metadata.Generator != "" {
+ proxy.XdsResourceGenerator =
s.Generators[proxy.Metadata.Generator]
+ }
+
+ return nil
+}
+
+func (s *DiscoveryServer) initProxyMetadata(node *core.Node) (*model.Proxy,
error) {
+ meta, err := model.ParseMetadata(node.Metadata)
+ if err != nil {
+ return nil, status.New(codes.InvalidArgument, err.Error()).Err()
+ }
+ proxy, err := model.ParseServiceNodeWithMetadata(node.Id, meta)
+ if err != nil {
+ return nil, status.New(codes.InvalidArgument, err.Error()).Err()
+ }
+ // Update the config namespace associated with this proxy
+ proxy.ConfigNamespace = model.GetProxyConfigNamespace(proxy)
+ proxy.XdsNode = node
+ return proxy, nil
+}
+
+func (s *DiscoveryServer) addCon(conID string, con *Connection) {
+ s.adsClientsMutex.Lock()
+ defer s.adsClientsMutex.Unlock()
+ s.adsClients[conID] = con
+}
+
+func (s *DiscoveryServer) removeCon(conID string) {
+ s.adsClientsMutex.Lock()
+ defer s.adsClientsMutex.Unlock()
+
+ if _, exist := s.adsClients[conID]; !exist {
+ klog.Errorf("ADS: Removing connection for non-existing
node:%v.", conID)
+ } else {
+ delete(s.adsClients, conID)
+ }
}
func (s *DiscoveryServer) Stream(stream DiscoveryStream) error {
@@ -153,11 +261,8 @@ func (s *DiscoveryServer) Stream(stream DiscoveryStream)
error {
func (s *DiscoveryServer) WaitForRequestLimit(ctx context.Context) error {
if s.RequestRateLimit.Limit() == 0 {
- // Allow opt out when rate limiting is set to 0qps
return nil
}
- // Give a bit of time for queue to clear out, but if not fail fast.
Client will connect to another
- // instance in best case, or retry with backoff.
wait, cancel := context.WithTimeout(ctx, time.Second)
defer cancel()
return s.RequestRateLimit.Wait(wait)
@@ -169,8 +274,32 @@ func newConnection(peerAddr string, stream
DiscoveryStream) *Connection {
}
}
+var PushOrder = []string{
+ v3.ClusterType,
+ v3.EndpointType,
+ v3.ListenerType,
+ v3.RouteType,
+ v3.AddressType,
+}
+
+var KnownOrderedTypeUrls = sets.New(PushOrder...)
+
func (conn *Connection) watchedResourcesByOrder() []*model.WatchedResource {
- return nil
+ allWatched := conn.proxy.ShallowCloneWatchedResources()
+ ordered := make([]*model.WatchedResource, 0, len(allWatched))
+ // first add all known types, in order
+ for _, tp := range PushOrder {
+ if allWatched[tp] != nil {
+ ordered = append(ordered, allWatched[tp])
+ }
+ }
+ // Then add any undeclared types
+ for tp, res := range allWatched {
+ if !KnownOrderedTypeUrls.Contains(tp) {
+ ordered = append(ordered, res)
+ }
+ }
+ return ordered
}
func (conn *Connection) Initialize(node *core.Node) error {
@@ -214,7 +343,6 @@ func (s *DiscoveryServer) processRequest(req
*discovery.DiscoveryRequest, con *C
return nil
}
- // For now, don't let xDS piggyback debug requests start watchers.
if strings.HasPrefix(req.TypeUrl, v3.DebugType) {
return s.pushXds(con,
&model.WatchedResource{TypeUrl: req.TypeUrl,
ResourceNames: sets.New(req.ResourceNames...)},
@@ -230,10 +358,6 @@ func (s *DiscoveryServer) processRequest(req
*discovery.DiscoveryRequest, con *C
Full: true,
Push: con.proxy.LastPushContext,
Reason: model.NewReasonStats(model.ProxyRequest),
-
- // The usage of LastPushTime (rather than time.Now()), is
critical here for correctness; This time
- // is used by the XDS cache to determine if a entry is stale.
If we use Now() with an old push context,
- // we may end up overriding active cache entries with stale
ones.
Start: con.proxy.LastPushTime,
Delta: delta,
Forced: true,
diff --git a/sail/pkg/xds/auth.go b/sail/pkg/xds/auth.go
index 02780d17..1b5b0569 100644
--- a/sail/pkg/xds/auth.go
+++ b/sail/pkg/xds/auth.go
@@ -7,3 +7,10 @@ import (
func (s *DiscoveryServer) authenticate(ctx context.Context) ([]string, error) {
return nil, nil
}
+
+func (s *DiscoveryServer) authorize(con *Connection, identities []string)
error {
+ if con == nil || con.proxy == nil {
+ return nil
+ }
+ return nil
+}
diff --git a/sail/pkg/xds/delta.go b/sail/pkg/xds/delta.go
index 71b36305..1f8f7184 100644
--- a/sail/pkg/xds/delta.go
+++ b/sail/pkg/xds/delta.go
@@ -2,17 +2,78 @@ package xds
import (
"errors"
+ "github.com/apache/dubbo-kubernetes/pkg/util/sets"
"github.com/apache/dubbo-kubernetes/pkg/xds"
dubbogrpc "github.com/apache/dubbo-kubernetes/sail/pkg/grpc"
"github.com/apache/dubbo-kubernetes/sail/pkg/model"
v3 "github.com/apache/dubbo-kubernetes/sail/pkg/xds/v3"
discovery
"github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
+ "github.com/google/uuid"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/peer"
"google.golang.org/grpc/status"
"k8s.io/klog/v2"
+ "strings"
+ "time"
)
+func (s *DiscoveryServer) processDeltaRequest(req
*discovery.DeltaDiscoveryRequest, con *Connection) error {
+ stype := v3.GetShortType(req.TypeUrl)
+ klog.Infof("ADS:%s: REQ %s resources sub:%d unsub:%d nonce:%s", stype,
+ con.ID(), len(req.ResourceNamesSubscribe),
len(req.ResourceNamesUnsubscribe), req.ResponseNonce)
+
+ if req.TypeUrl == v3.HealthInfoType {
+ return nil
+ }
+ if strings.HasPrefix(req.TypeUrl, v3.DebugType) {
+ return s.pushDeltaXds(con,
+ &model.WatchedResource{TypeUrl: req.TypeUrl,
ResourceNames: sets.New(req.ResourceNamesSubscribe...)},
+ &model.PushRequest{Full: true, Push:
con.proxy.LastPushContext, Forced: true})
+ }
+
+ shouldRespond := shouldRespondDelta(con, req)
+ if !shouldRespond {
+ return nil
+ }
+
+ subs, _, _ := deltaWatchedResources(nil, req)
+ request := &model.PushRequest{
+ Full: true,
+ Push: con.proxy.LastPushContext,
+ Reason: model.NewReasonStats(model.ProxyRequest),
+ Start: con.proxy.LastPushTime,
+ Delta: model.ResourceDelta{
+ Subscribed: subs,
+ Unsubscribed:
sets.New(req.ResourceNamesUnsubscribe...).Delete("*"),
+ },
+ Forced: true,
+ }
+
+ err := s.pushDeltaXds(con, con.proxy.GetWatchedResource(req.TypeUrl),
request)
+ if err != nil {
+ return err
+ }
+ if req.TypeUrl != v3.ClusterType {
+ return nil
+ }
+ return s.forceEDSPush(con)
+}
+
+func (s *DiscoveryServer) forceEDSPush(con *Connection) error {
+ if dwr := con.proxy.GetWatchedResource(v3.EndpointType); dwr != nil {
+ request := &model.PushRequest{
+ Full: true,
+ Push: con.proxy.LastPushContext,
+ Reason: model.NewReasonStats(model.DependentResource),
+ Start: con.proxy.LastPushTime,
+ Forced: true,
+ }
+ klog.Infof("ADS:%s: FORCE %s PUSH for warming.",
v3.GetShortType(v3.EndpointType), con.ID())
+ return s.pushDeltaXds(con, dwr, request)
+ }
+ return nil
+}
+
func (s *DiscoveryServer) StreamDeltas(stream DeltaDiscoveryStream) error {
if !s.IsServerReady() {
return errors.New("server is not ready to serve discovery
information")
@@ -39,30 +100,14 @@ func (s *DiscoveryServer) StreamDeltas(stream
DeltaDiscoveryStream) error {
klog.V(2).Infof("Unauthenticated XDS: %v", peerAddr)
}
- // InitContext returns immediately if the context was already
initialized.
s.globalPushContext().InitContext(s.Env, nil, nil)
con := newDeltaConnection(peerAddr, stream)
- // Do not call: defer close(con.pushChannel). The push channel will be
garbage collected
- // when the connection is no longer used. Closing the channel can cause
subtle race conditions
- // with push. According to the spec: "It's only necessary to close a
channel when it is important
- // to tell the receiving goroutines that all data have been sent."
-
- // Block until either a request is received or a push is triggered.
- // We need 2 go routines because 'read' blocks in Recv().
go s.receiveDelta(con, ids)
- // Wait for the proxy to be fully initialized before we start serving
traffic. Because
- // initialization doesn't have dependencies that will block, there is
no need to add any timeout
- // here. Prior to this explicit wait, we were implicitly waiting by
receive() not sending to
- // reqChannel and the connection not being enqueued for pushes to
pushChannel until the
- // initialization is complete.
<-con.InitializedCh()
for {
- // Go select{} statements are not ordered; the same channel can
be chosen many times.
- // For requests, these are higher priority (client may be
blocked on startup until these are done)
- // and often very cheap to handle (simple ACK), so we check it
first.
select {
case req, ok := <-con.deltaReqChan:
if ok {
@@ -77,10 +122,6 @@ func (s *DiscoveryServer) StreamDeltas(stream
DeltaDiscoveryStream) error {
return nil
default:
}
- // If there wasn't already a request, poll for requests and
pushes. Note: if we have a huge
- // amount of incoming requests, we may still send some pushes,
as we do not `continue` above;
- // however, requests will be handled ~2x as much as pushes.
This ensures a wave of requests
- // cannot completely starve pushes. However, this scenario is
unlikely.
select {
case req, ok := <-con.deltaReqChan:
if ok {
@@ -88,7 +129,6 @@ func (s *DiscoveryServer) StreamDeltas(stream
DeltaDiscoveryStream) error {
return err
}
} else {
- // Remote side closed connection or error
processing the request.
return <-con.ErrorCh()
}
case ev := <-con.PushCh():
@@ -108,7 +148,6 @@ func (s *DiscoveryServer) receiveDelta(con *Connection,
identities []string) {
defer func() {
close(con.deltaReqChan)
close(con.ErrorCh())
- // Close the initialized channel, if its not already closed, to
prevent blocking the stream
select {
case <-con.InitializedCh():
default:
@@ -127,7 +166,6 @@ func (s *DiscoveryServer) receiveDelta(con *Connection,
identities []string) {
klog.Errorf("ADS: %q %s terminated with error: %v",
con.Peer(), con.ID(), err)
return
}
- // This should be only set for the first request. The node id
may not be set - for example malicious clients.
if firstRequest {
// probe happens before envoy sends first xDS request
if req.TypeUrl == v3.HealthInfoType {
@@ -182,16 +220,190 @@ func (s *DiscoveryServer) pushConnectionDelta(con
*Connection, pushEv *Event) er
return nil
}
-func (s *DiscoveryServer) processDeltaRequest(req
*discovery.DeltaDiscoveryRequest, con *Connection) error {
+func (s *DiscoveryServer) pushDeltaXds(con *Connection, w
*model.WatchedResource, req *model.PushRequest) error {
+ if w == nil {
+ return nil
+ }
+ gen := s.findGenerator(w.TypeUrl, con)
+ if gen == nil {
+ return nil
+ }
+
+ var logFiltered string
+ var res model.Resources
+ var deletedRes model.DeletedResources
+ var logdata model.XdsLogDetails
+ var usedDelta bool
+ var err error
+ switch g := gen.(type) {
+ case model.XdsDeltaResourceGenerator:
+ res, deletedRes, logdata, usedDelta, err =
g.GenerateDeltas(con.proxy, req, w)
+ case model.XdsResourceGenerator:
+ res, logdata, err = g.Generate(con.proxy, w, req)
+ }
+ if err != nil || (res == nil && deletedRes == nil) {
+ return err
+ }
+ defer func() {}()
+ resp := &discovery.DeltaDiscoveryResponse{
+ ControlPlane: ControlPlane(w.TypeUrl),
+ TypeUrl: w.TypeUrl,
+ // TODO: send different version for incremental eds
+ SystemVersionInfo: req.Push.PushVersion,
+ Nonce: nonce(req.Push.PushVersion),
+ Resources: res,
+ }
+ if usedDelta {
+ resp.RemovedResources = deletedRes
+ } else if req.Full {
+ // similar to sotw
+ removed := w.ResourceNames.Copy()
+ for _, r := range res {
+ removed.Delete(r.Name)
+ }
+ resp.RemovedResources = sets.SortedList(removed)
+ }
+ var newResourceNames sets.String
+ if len(resp.RemovedResources) > 0 {
+ klog.Infof("ADS:%v REMOVE for node:%s %v",
v3.GetShortType(w.TypeUrl), con.ID(), resp.RemovedResources)
+ }
+
+ ptype := "PUSH"
+ info := ""
+ if logdata.Incremental {
+ ptype = "PUSH INC"
+ }
+ if len(logdata.AdditionalInfo) > 0 {
+ info = " " + logdata.AdditionalInfo
+ }
+ if len(logFiltered) > 0 {
+ info += logFiltered
+ }
+
+ if err := con.sendDelta(resp, newResourceNames); err != nil {
+ return err
+ }
+
+ switch {
+ case !req.Full:
+ default:
+ klog.Infof("%s: %s%s for node:%s resources:%d removed:%d
size:%v%s%s",
+ v3.GetShortType(w.TypeUrl), ptype, req.PushReason(),
con.proxy.ID, len(res), len(resp.RemovedResources))
+ }
+
return nil
}
-func (s *DiscoveryServer) computeProxyState(proxy *model.Proxy, request
*model.PushRequest) {
- return
+func deltaWatchedResources(existing sets.String, request
*discovery.DeltaDiscoveryRequest) (sets.String, bool, bool) {
+ res := existing
+ if res == nil {
+ res = sets.New[string]()
+ }
+ changed := false
+ for _, r := range request.ResourceNamesSubscribe {
+ if !res.InsertContains(r) {
+ changed = true
+ }
+ }
+ for r := range request.InitialResourceVersions {
+ if !res.InsertContains(r) {
+ changed = true
+ }
+ }
+ for _, r := range request.ResourceNamesUnsubscribe {
+ if res.DeleteContains(r) {
+ changed = true
+ }
+ }
+ wildcard := false
+ if res.Contains("*") {
+ wildcard = true
+ res.Delete("*")
+ }
+ if len(request.ResourceNamesSubscribe) == 0 {
+ wildcard = true
+ }
+ return res, wildcard, changed
}
-func (s *DiscoveryServer) pushDeltaXds(con *Connection, w
*model.WatchedResource, req *model.PushRequest) error {
- return nil
+func shouldRespondDelta(con *Connection, request
*discovery.DeltaDiscoveryRequest) bool {
+ stype := v3.GetShortType(request.TypeUrl)
+
+ if request.ErrorDetail != nil {
+ errCode := codes.Code(request.ErrorDetail.Code)
+ klog.Warningf("ADS:%s: ACK ERROR %s %s:%s", stype, con.ID(),
errCode.String(), request.ErrorDetail.GetMessage())
+ con.proxy.UpdateWatchedResource(request.TypeUrl, func(wr
*model.WatchedResource) *model.WatchedResource {
+ wr.LastError = request.ErrorDetail.GetMessage()
+ return wr
+ })
+ return false
+ }
+
+ klog.Infof("ADS:%s REQUEST %v: sub:%v unsub:%v initial:%v", stype,
con.ID(),
+ request.ResourceNamesSubscribe,
request.ResourceNamesUnsubscribe, request.InitialResourceVersions)
+ previousInfo := con.proxy.GetWatchedResource(request.TypeUrl)
+
+ if previousInfo == nil {
+ con.proxy.Lock()
+ defer con.proxy.Unlock()
+
+ if len(request.InitialResourceVersions) > 0 {
+ klog.Infof("ADS:%s: RECONNECT %s %s resources:%v",
stype, con.ID(), request.ResponseNonce, len(request.InitialResourceVersions))
+ } else {
+ klog.Infof("ADS:%s: INIT %s %s", stype, con.ID(),
request.ResponseNonce)
+ }
+
+ res, wildcard, _ := deltaWatchedResources(nil, request)
+ skip := request.TypeUrl == v3.AddressType && wildcard
+ if skip {
+ res = nil
+ }
+ con.proxy.WatchedResources[request.TypeUrl] =
&model.WatchedResource{
+ TypeUrl: request.TypeUrl,
+ ResourceNames: res,
+ Wildcard: wildcard,
+ }
+ return true
+ }
+
+ if request.ResponseNonce != "" && request.ResponseNonce !=
previousInfo.NonceSent {
+ klog.Infof("ADS:%s: REQ %s Expired nonce received %s, sent %s",
stype,
+ con.ID(), request.ResponseNonce, previousInfo.NonceSent)
+ return false
+ }
+
+ spontaneousReq := request.ResponseNonce == ""
+
+ var alwaysRespond bool
+ var subChanged bool
+
+ con.proxy.UpdateWatchedResource(request.TypeUrl, func(wr
*model.WatchedResource) *model.WatchedResource {
+ wr.ResourceNames, _, subChanged =
deltaWatchedResources(wr.ResourceNames, request)
+ if !spontaneousReq {
+ wr.LastError = ""
+ wr.NonceAcked = request.ResponseNonce
+ }
+ alwaysRespond = wr.AlwaysRespond
+ wr.AlwaysRespond = false
+ return wr
+ })
+
+ if spontaneousReq && !subChanged || !spontaneousReq && subChanged {
+ klog.Infof("ADS:%s: Subscribed resources check mismatch: %v vs
%v", stype, spontaneousReq, subChanged)
+ }
+
+ if !subChanged {
+ if alwaysRespond {
+ klog.Infof("ADS:%s: FORCE RESPONSE %s for warming.",
stype, con.ID())
+ return true
+ }
+
+ klog.Infof("ADS:%s: ACK %s %s", stype, con.ID(),
request.ResponseNonce)
+ return false
+ }
+ klog.Infof("ADS:%s: RESOURCE CHANGE %s %s", stype, con.ID(),
request.ResponseNonce)
+
+ return true
}
func newDeltaConnection(peerAddr string, stream DeltaDiscoveryStream)
*Connection {
@@ -201,3 +413,34 @@ func newDeltaConnection(peerAddr string, stream
DeltaDiscoveryStream) *Connectio
deltaReqChan: make(chan *discovery.DeltaDiscoveryRequest, 1),
}
}
+
+func nonce(noncePrefix string) string {
+ return noncePrefix + uuid.New().String()
+}
+
+func (conn *Connection) sendDelta(res *discovery.DeltaDiscoveryResponse,
newResourceNames sets.String) error {
+ sendResonse := func() error {
+ defer func() {}()
+ return conn.deltaStream.Send(res)
+ }
+ err := sendResonse()
+ if err == nil {
+ if !strings.HasPrefix(res.TypeUrl, v3.DebugType) {
+ conn.proxy.UpdateWatchedResource(res.TypeUrl, func(wr
*model.WatchedResource) *model.WatchedResource {
+ if wr == nil {
+ wr = &model.WatchedResource{TypeUrl:
res.TypeUrl}
+ }
+ // some resources dynamically update
ResourceNames. Most don't though
+ if newResourceNames != nil {
+ wr.ResourceNames = newResourceNames
+ }
+ wr.NonceSent = res.Nonce
+ wr.LastSendTime = time.Now()
+ return wr
+ })
+ }
+ } else if status.Convert(err).Code() == codes.DeadlineExceeded {
+ klog.Infof("Timeout writing %s: %v", conn.ID(),
v3.GetShortType(res.TypeUrl))
+ }
+ return err
+}
diff --git a/sail/pkg/xds/v3/model.go b/sail/pkg/xds/v3/model.go
index 38aad5fb..bc589282 100644
--- a/sail/pkg/xds/v3/model.go
+++ b/sail/pkg/xds/v3/model.go
@@ -9,6 +9,7 @@ const (
RouteType = model.RouteType
DebugType = model.DebugType
HealthInfoType = model.HealthInfoType
+ AddressType = model.AddressType
)
func GetShortType(typeURL string) string {
diff --git a/sail/pkg/xds/xdsgen.go b/sail/pkg/xds/xdsgen.go
index cc2a0598..8de5422b 100644
--- a/sail/pkg/xds/xdsgen.go
+++ b/sail/pkg/xds/xdsgen.go
@@ -1,14 +1,48 @@
package xds
import (
+ "encoding/json"
+ "github.com/apache/dubbo-kubernetes/pkg/env"
+ "github.com/apache/dubbo-kubernetes/pkg/lazy"
+ dubboversion "github.com/apache/dubbo-kubernetes/pkg/version"
+ "github.com/apache/dubbo-kubernetes/pkg/xds"
"github.com/apache/dubbo-kubernetes/sail/pkg/model"
+ core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
discovery
"github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
- "strings"
-
- "github.com/apache/dubbo-kubernetes/pkg/xds"
+ "k8s.io/klog/v2"
"strconv"
+ "strings"
)
+type IstioControlPlaneInstance struct {
+ // The Istio component type (e.g. "istiod")
+ Component string
+ // The ID of the component instance
+ ID string
+ // The Istio version
+ Info dubboversion.BuildInfo
+}
+
+var controlPlane = lazy.New(func() (*core.ControlPlane, error) {
+ // The Pod Name (instance identity) is in PilotArgs, but not reachable
globally nor from DiscoveryServer
+ podName := env.Register("POD_NAME", "", "").Get()
+ byVersion, err := json.Marshal(IstioControlPlaneInstance{
+ Component: "dubbod",
+ ID: podName,
+ Info: dubboversion.Info,
+ })
+ if err != nil {
+ klog.Warningf("XDS: Could not serialize control plane id: %v",
err)
+ }
+ return &core.ControlPlane{Identifier: string(byVersion)}, nil
+})
+
+func ControlPlane(typ string) *core.ControlPlane {
+ // Error will never happen because the getter of lazy does not return
error.
+ cp, _ := controlPlane.Get()
+ return cp
+}
+
func (s *DiscoveryServer) pushXds(con *Connection, w *model.WatchedResource,
req *model.PushRequest) error {
if w == nil {
return nil