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 bf01489b Update makefile and client-go (#842)
bf01489b is described below
commit bf01489b62850055110b7fb5e2a9e0d0051d3f26
Author: mfordjody <[email protected]>
AuthorDate: Tue Jan 6 03:40:19 2026 +0800
Update makefile and client-go (#842)
---
Makefile | 49 +-
Makefile.common.mk | 13 +
Makefile.core.mk | 85 +++
Makefile.overrides.mk | 1 +
api/networking/v1alpha3/destination_rule.pb.go | 16 +
api/networking/v1alpha3/destination_rule.proto | 15 +
api/networking/v1alpha3/virtual_service.pb.go | 16 +
api/networking/v1alpha3/virtual_service.proto | 15 +
client-go/pkg/apis/networking/v1alpha3/doc.go | 23 +
client-go/pkg/apis/networking/v1alpha3/register.go | 53 ++
client-go/pkg/apis/networking/v1alpha3/types.go | 119 ++++
.../pkg/applyconfiguration/internal/internal.go | 62 ++
.../pkg/applyconfiguration/meta/v1/objectmeta.go | 172 +++++
.../applyconfiguration/meta/v1/ownerreference.go | 88 +++
.../pkg/applyconfiguration/meta/v1/typemeta.go | 48 ++
client-go/pkg/applyconfiguration/utils.go | 41 ++
client-go/pkg/clientset/versioned/clientset.go | 19 +
.../versioned/fake/clientset_generated.go | 19 +
client-go/pkg/clientset/versioned/fake/doc.go | 20 +
client-go/pkg/clientset/versioned/fake/register.go | 19 +
client-go/pkg/clientset/versioned/scheme/doc.go | 20 +
.../pkg/clientset/versioned/scheme/register.go | 19 +
.../versioned/typed/networking/v1alpha3/doc.go | 20 +
.../typed/networking/v1alpha3/fake/doc.go | 20 +
.../v1alpha3/fake/fake_networking_client.go | 19 +
.../networking/v1alpha3/generated_expansion.go | 19 +
.../typed/networking/v1alpha3/networking_client.go | 19 +
go.mod | 9 +-
go.sum | 5 +
header.go.txt | 16 +
kubetype-gen | Bin 11522162 -> 0 bytes
tests/grpc-app/.dockerignore | 21 -
tests/grpc-app/.gitignore | 2 -
tests/grpc-app/README.md | 12 -
tests/grpc-app/consumer/main.go | 739 ---------------------
tests/grpc-app/docker/dockerfile.consumer | 53 --
tests/grpc-app/docker/dockerfile.provider | 50 --
tests/grpc-app/generate-proto.sh | 27 -
tests/grpc-app/go.mod | 44 --
tests/grpc-app/go.sum | 76 ---
tests/grpc-app/proto/echo.proto | 62 --
tests/grpc-app/proto/gen.sh | 7 -
tests/grpc-app/provider/main.go | 404 -----------
tests/loadtest/go.mod | 29 -
tests/loadtest/go.sum | 85 ---
tools/scripts/run.sh | 43 ++
tools/scripts/setup_env.sh | 145 ++++
47 files changed, 1243 insertions(+), 1615 deletions(-)
diff --git a/Makefile b/Makefile
index 39b62ecf..ecb80294 100644
--- a/Makefile
+++ b/Makefile
@@ -22,4 +22,51 @@ build-dubboctl:
.PHONY: clone-sample
clone-sample:
mkdir -p bin
- cp -r samples bin/samples
\ No newline at end of file
+ cp -r samples bin/samples
+
+# allow optional per-repo overrides
+-include Makefile.overrides.mk
+
+# Set the environment variable BUILD_WITH_CONTAINER to use a container
+# to build the repo. The only dependencies in this mode are to have make and
+# docker. If you'd rather build with a local tool chain instead, you'll need to
+# figure out all the tools you need in your environment to make that work.
+export BUILD_WITH_CONTAINER ?= 0
+
+ifeq ($(BUILD_WITH_CONTAINER),1)
+
+# An export free of arguments in a Makefile places all variables in the
Makefile into the
+# environment. This is needed to allow overrides from Makefile.overrides.mk.
+export
+
+RUN = ./tools/scripts/run.sh
+
+MAKE_DOCKER = $(RUN) make --no-print-directory -e -f Makefile.core.mk
+
+%:
+ @$(MAKE_DOCKER) $@
+
+default:
+ @$(MAKE_DOCKER)
+
+shell:
+ @$(RUN) /bin/bash
+
+.PHONY: default shell
+
+else
+
+# If we are not in build container, we need a workaround to get environment
properly set
+# Write to file, then include
+$(shell mkdir -p out)
+$(shell $(shell pwd)/tools/scripts/setup_env.sh envfile > out/.env)
+include out/.env
+# An export free of arguments in a Makefile places all variables in the
Makefile into the
+# environment. This behavior may be surprising to many that use shell often,
which simply
+# displays the existing environment
+export
+
+export GOBIN ?= $(GOPATH)/bin
+include Makefile.core.mk
+
+endif
\ No newline at end of file
diff --git a/Makefile.common.mk b/Makefile.common.mk
new file mode 100644
index 00000000..d4f4d53b
--- /dev/null
+++ b/Makefile.common.mk
@@ -0,0 +1,13 @@
+tidy-go:
+ @find -name go.mod -execdir go mod tidy \;
+
+mod-download-go:
+ @-GOFLAGS="-mod=readonly" find -name go.mod -execdir go mod download \;
+# go mod tidy is needed with Golang 1.16+ as go mod download affects go.sum
+# https://github.com/golang/go/issues/43994
+ @find -name go.mod -execdir go mod tidy \;
+
+format-go: tidy-go
+ @${FINDFILES} -name '*.go' \( ! \( -name '*.gen.go' -o -name '*.pb.go'
\) \) -print0 | ${XARGS} common/scripts/format_go.sh
+
+.PHONY: format-go tidy-go mod-download-go
diff --git a/Makefile.core.mk b/Makefile.core.mk
new file mode 100644
index 00000000..49c252b6
--- /dev/null
+++ b/Makefile.core.mk
@@ -0,0 +1,85 @@
+gen: generate-k8s-client tidy-go
+
+clean: clean-k8s-client
+
+applyconfiguration_gen = applyconfiguration-gen
+kubetype_gen = kubetype-gen
+deepcopy_gen = deepcopy-gen
+client_gen = client-gen
+lister_gen = lister-gen
+informer_gen = informer-gen
+
+empty:=
+space := $(empty) $(empty)
+comma := ,
+
+kube_dubbo_source_packages = $(subst $(space),$(empty), \
+ ./api/networking/v1alpha3 \
+ )
+
+kube_base_output_package = client-go/pkg
+kube_api_base_package = $(kube_base_output_package)/apis
+kube_api_packages = $(subst $(space),$(empty), \
+ $(kube_api_base_package)/networking/v1alpha3 \
+ )
+
+kube_api_applyconfiguration_packages =
$(kube_api_packages),k8s.io/apimachinery/pkg/apis/meta/v1
+kube_clientset_package = $(kube_base_output_package)/clientset
+kube_clientset_name = versioned
+kube_listers_package = $(kube_base_output_package)/listers
+kube_informers_package = $(kube_base_output_package)/informers
+kube_applyconfiguration_package =
$(kube_base_output_package)/applyconfiguration
+
+kube_go_header_text = header.go.txt
+
+ifeq ($(IN_BUILD_CONTAINER),1)
+ # k8s code generators rely on GOPATH, using $GOPATH/src as the base
package
+ # directory. Using --output-base . does not work, as that ends up
generating
+ # code into ./<package>, e.g. ./client-go/pkg/apis/... To work
+ # around this, we'll just let k8s generate the code where it wants and
copy
+ # back to where it should have been generated.
+ move_generated=([ -d $(GOPATH)/src/$(kube_base_output_package)/ ] && cp
-r $(GOPATH)/src/$(kube_base_output_package)/ client-go/ && rm -rf
$(GOPATH)/src/$(kube_base_output_package)/) || true
+else
+ # nothing special for local builds
+ move_generated=
+endif
+
+rename_generated_files=\
+ for dir in $(subst client-go/, $(empty), $(subst $(comma), $(space),
$(kube_api_packages)) $(kube_clientset_package) $(kube_listers_package)
$(kube_informers_package)); do \
+ if [ -d "$$dir" ]; then \
+ find "$$dir" -name '*.go' -and -not -name 'doc.go' -and
-not -name '*.gen.go' -type f -exec sh -c 'mv "$$1" "$${1%.go}".gen.go' - '{}'
\; ; \
+ fi \
+ done
+
+
+# Kubernetes deepcopy gen directly sets values of our types. Our types are
protos; it is illegal to do this for protos.
+# However, we don't even need this anyways -- each individual field is
explicitly copied already.
+# Remove the line doing this illegal operation.
+fixup_generated_files=\
+ find . -name "*.deepcopy.gen.go" -type f -exec sed -i '' -e '/\*out =
\*in/d' {} +
+
+.PHONY: generate-k8s-client
+generate-k8s-client:
+ # generate kube api type wrappers for dubbo types
+ @GODEBUG=gotypesalias=0 $(kubetype_gen) --input-dirs
$(kube_dubbo_source_packages) --output-package $(kube_api_base_package) -h
$(kube_go_header_text)
+ @$(move_generated)
+ # generate deepcopy for kube api types
+ @$(deepcopy_gen) --input-dirs $(kube_api_packages) -O
zz_generated.deepcopy -h $(kube_go_header_text)
+ # generate ssa for kube api types
+ @$(applyconfiguration_gen) --input-dirs
$(kube_api_applyconfiguration_packages) --output-package
$(kube_applyconfiguration_package) -h $(kube_go_header_text)
+ # generate clientsets for kube api types
+ @$(client_gen) --clientset-name $(kube_clientset_name) --input-base ""
--input $(kube_api_packages) --output-package $(kube_clientset_package) -h
$(kube_go_header_text) --apply-configuration-package
$(kube_applyconfiguration_package)
+ # generate listers for kube api types
+ @$(lister_gen) --input-dirs $(kube_api_packages) --output-package
$(kube_listers_package) -h $(kube_go_header_text)
+ # generate informers for kube api types
+ @$(informer_gen) --input-dirs $(kube_api_packages)
--versioned-clientset-package $(kube_clientset_package)/$(kube_clientset_name)
--listers-package $(kube_listers_package) --output-package
$(kube_informers_package) -h $(kube_go_header_text)
+ @$(move_generated)
+ @$(rename_generated_files)
+ @$(fixup_generated_files)
+
+.PHONY: clean-k8s-client
+clean-k8s-client:
+ # remove generated code
+ @rm -rf client-go/pkg
+
+include Makefile.common.mk
diff --git a/Makefile.overrides.mk b/Makefile.overrides.mk
new file mode 100644
index 00000000..de678eac
--- /dev/null
+++ b/Makefile.overrides.mk
@@ -0,0 +1 @@
+BUILD_WITH_CONTAINER ?= 1
diff --git a/api/networking/v1alpha3/destination_rule.pb.go
b/api/networking/v1alpha3/destination_rule.pb.go
index 587bbd24..bb1802ca 100644
--- a/api/networking/v1alpha3/destination_rule.pb.go
+++ b/api/networking/v1alpha3/destination_rule.pb.go
@@ -93,6 +93,22 @@ func (ClientTLSSettings_TLSmode) EnumDescriptor() ([]byte,
[]int) {
return file_networking_v1alpha3_destination_rule_proto_rawDescGZIP(),
[]int{3, 0}
}
+// <!-- crd generation tags
+// +cue-gen:DestinationRule:groupName:networking.dubbo.apache.org
+// +cue-gen:DestinationRule:versions:v1alpha3
+// +cue-gen:DestinationRule:annotations:helm.sh/resource-policy=keep
+//
+cue-gen:DestinationRule:labels:app=dubbo-planet,chart=dubbo,heritage=Tiller,release=dubbo
+// +cue-gen:DestinationRule:subresource:status
+// +cue-gen:DestinationRule:scope:Namespaced
+// +cue-gen:DestinationRule:resource:categories=dubbo,networking,shortNames=dr
+//
+cue-gen:DestinationRule:printerColumn:name=Host,type=string,JSONPath=.spec.host,description="The
name of a service from the service registry"
+//
+cue-gen:DestinationRule:printerColumn:name=Age,type=date,JSONPath=.metadata.creationTimestamp,description="CreationTimestamp
is a timestamp
+// representing the server time when this object was created. It is not
guaranteed to be set in happens-before order across separate operations.
+// Clients may not set this value. It is represented in RFC3339 form and is in
UTC.
+// Populated by the system. Read-only. Null for lists. For more information,
see [Kubernetes API
Conventions](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#metadata)"
+// +cue-gen:DestinationRule:preserveUnknownFields:false
+// -->
+//
// <!-- go code generation tags
// +kubetype-gen
// +kubetype-gen:groupVersion=networking.dubbo.apache.org/v1alpha3
diff --git a/api/networking/v1alpha3/destination_rule.proto
b/api/networking/v1alpha3/destination_rule.proto
index 154044c3..0e90d87b 100644
--- a/api/networking/v1alpha3/destination_rule.proto
+++ b/api/networking/v1alpha3/destination_rule.proto
@@ -28,6 +28,21 @@ import "networking/v1alpha3/virtual_service.proto";
option go_package = "/api/networking/v1alpha3";
+// <!-- crd generation tags
+// +cue-gen:DestinationRule:groupName:networking.dubbo.apache.org
+// +cue-gen:DestinationRule:versions:v1alpha3
+// +cue-gen:DestinationRule:annotations:helm.sh/resource-policy=keep
+//
+cue-gen:DestinationRule:labels:app=dubbo-planet,chart=dubbo,heritage=Tiller,release=dubbo
+// +cue-gen:DestinationRule:subresource:status
+// +cue-gen:DestinationRule:scope:Namespaced
+// +cue-gen:DestinationRule:resource:categories=dubbo,networking,shortNames=dr
+//
+cue-gen:DestinationRule:printerColumn:name=Host,type=string,JSONPath=.spec.host,description="The
name of a service from the service registry"
+//
+cue-gen:DestinationRule:printerColumn:name=Age,type=date,JSONPath=.metadata.creationTimestamp,description="CreationTimestamp
is a timestamp
+// representing the server time when this object was created. It is not
guaranteed to be set in happens-before order across separate operations.
+// Clients may not set this value. It is represented in RFC3339 form and is in
UTC.
+// Populated by the system. Read-only. Null for lists. For more information,
see [Kubernetes API
Conventions](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#metadata)"
+// +cue-gen:DestinationRule:preserveUnknownFields:false
+// -->
//
// <!-- go code generation tags
// +kubetype-gen
diff --git a/api/networking/v1alpha3/virtual_service.pb.go
b/api/networking/v1alpha3/virtual_service.pb.go
index 5f92d8a1..762719c9 100644
--- a/api/networking/v1alpha3/virtual_service.pb.go
+++ b/api/networking/v1alpha3/virtual_service.pb.go
@@ -40,6 +40,22 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
+// <!-- crd generation tags
+// +cue-gen:VirtualService:groupName:networking.dubbo.apache.org
+// +cue-gen:VirtualService:versions:v1alpha3
+// +cue-gen:VirtualService:annotations:helm.sh/resource-policy=keep
+//
+cue-gen:VirtualService:labels:app=dubbo-planet,chart=dubbo,heritage=Tiller,release=dubbo
+// +cue-gen:VirtualService:subresource:status
+// +cue-gen:VirtualService:scope:Namespaced
+// +cue-gen:VirtualService:resource:categories=dubbo,networking,shortNames=vs
+//
+cue-gen:VirtualService:printerColumn:name=Hosts,type=string,JSONPath=.spec.hosts,description="The
destination hosts to which traffic is being sent"
+//
+cue-gen:VirtualService:printerColumn:name=Age,type=date,JSONPath=.metadata.creationTimestamp,description="CreationTimestamp
is a timestamp
+// representing the server time when this object was created. It is not
guaranteed to be set in happens-before order across separate operations.
+// Clients may not set this value. It is represented in RFC3339 form and is in
UTC.
+// Populated by the system. Read-only. Null for lists. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata"
+// +cue-gen:VirtualService:preserveUnknownFields:false
+// -->
+//
// <!-- go code generation tags
// +kubetype-gen
// +kubetype-gen:groupVersion=networking.dubbo.apache.org/v1alpha3
diff --git a/api/networking/v1alpha3/virtual_service.proto
b/api/networking/v1alpha3/virtual_service.proto
index a9c01ecd..67a00101 100644
--- a/api/networking/v1alpha3/virtual_service.proto
+++ b/api/networking/v1alpha3/virtual_service.proto
@@ -24,6 +24,21 @@ import "google/protobuf/wrappers.proto";
option go_package = "/api/networking/v1alpha3";
+// <!-- crd generation tags
+// +cue-gen:VirtualService:groupName:networking.dubbo.apache.org
+// +cue-gen:VirtualService:versions:v1alpha3
+// +cue-gen:VirtualService:annotations:helm.sh/resource-policy=keep
+//
+cue-gen:VirtualService:labels:app=dubbo-planet,chart=dubbo,heritage=Tiller,release=dubbo
+// +cue-gen:VirtualService:subresource:status
+// +cue-gen:VirtualService:scope:Namespaced
+// +cue-gen:VirtualService:resource:categories=dubbo,networking,shortNames=vs
+//
+cue-gen:VirtualService:printerColumn:name=Hosts,type=string,JSONPath=.spec.hosts,description="The
destination hosts to which traffic is being sent"
+//
+cue-gen:VirtualService:printerColumn:name=Age,type=date,JSONPath=.metadata.creationTimestamp,description="CreationTimestamp
is a timestamp
+// representing the server time when this object was created. It is not
guaranteed to be set in happens-before order across separate operations.
+// Clients may not set this value. It is represented in RFC3339 form and is in
UTC.
+// Populated by the system. Read-only. Null for lists. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata"
+// +cue-gen:VirtualService:preserveUnknownFields:false
+// -->
//
// <!-- go code generation tags
// +kubetype-gen
diff --git a/client-go/pkg/apis/networking/v1alpha3/doc.go
b/client-go/pkg/apis/networking/v1alpha3/doc.go
new file mode 100644
index 00000000..27561001
--- /dev/null
+++ b/client-go/pkg/apis/networking/v1alpha3/doc.go
@@ -0,0 +1,23 @@
+//
+// 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.
+
+// Code generated by kubetype-gen. DO NOT EDIT.
+
+// Package has auto-generated kube type wrappers for raw types.
+// +k8s:openapi-gen=true
+// +k8s:deepcopy-gen=package
+// +groupName=networking.dubbo.apache.org
+package v1alpha3
diff --git a/client-go/pkg/apis/networking/v1alpha3/register.go
b/client-go/pkg/apis/networking/v1alpha3/register.go
new file mode 100644
index 00000000..146157b2
--- /dev/null
+++ b/client-go/pkg/apis/networking/v1alpha3/register.go
@@ -0,0 +1,53 @@
+//
+// 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.
+
+// Code generated by kubetype-gen. DO NOT EDIT.
+
+package v1alpha3
+
+import (
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ runtime "k8s.io/apimachinery/pkg/runtime"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+var (
+ // Package-wide variables from generator "register".
+ SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version:
"v1alpha3"}
+ SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
+ localSchemeBuilder = &SchemeBuilder
+ AddToScheme = localSchemeBuilder.AddToScheme
+)
+
+const (
+ // Package-wide consts from generator "register".
+ GroupName = "networking.dubbo.apache.org"
+)
+
+func Resource(resource string) schema.GroupResource {
+ return SchemeGroupVersion.WithResource(resource).GroupResource()
+}
+
+func addKnownTypes(scheme *runtime.Scheme) error {
+ scheme.AddKnownTypes(SchemeGroupVersion,
+ &DestinationRule{},
+ &DestinationRuleList{},
+ &VirtualService{},
+ &VirtualServiceList{},
+ )
+ v1.AddToGroupVersion(scheme, SchemeGroupVersion)
+ return nil
+}
diff --git a/client-go/pkg/apis/networking/v1alpha3/types.go
b/client-go/pkg/apis/networking/v1alpha3/types.go
new file mode 100644
index 00000000..bc5cb2df
--- /dev/null
+++ b/client-go/pkg/apis/networking/v1alpha3/types.go
@@ -0,0 +1,119 @@
+//
+// 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.
+
+// Code generated by kubetype-gen. DO NOT EDIT.
+
+package v1alpha3
+
+import (
+ networkingv1alpha3 "./api/networking/v1alpha3"
+ v1alpha1 "github.com/apache/dubbo-kubernetes/api/meta/v1alpha1"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+//
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// <!-- crd generation tags
+// +cue-gen:DestinationRule:groupName:networking.dubbo.apache.org
+// +cue-gen:DestinationRule:versions:v1alpha3
+// +cue-gen:DestinationRule:annotations:helm.sh/resource-policy=keep
+//
+cue-gen:DestinationRule:labels:app=dubbo-planet,chart=dubbo,heritage=Tiller,release=dubbo
+// +cue-gen:DestinationRule:subresource:status
+// +cue-gen:DestinationRule:scope:Namespaced
+// +cue-gen:DestinationRule:resource:categories=dubbo,networking,shortNames=dr
+//
+cue-gen:DestinationRule:printerColumn:name=Host,type=string,JSONPath=.spec.host,description="The
name of a service from the service registry"
+//
+cue-gen:DestinationRule:printerColumn:name=Age,type=date,JSONPath=.metadata.creationTimestamp,description="CreationTimestamp
is a timestamp
+// representing the server time when this object was created. It is not
guaranteed to be set in happens-before order across separate operations.
+// Clients may not set this value. It is represented in RFC3339 form and is in
UTC.
+// Populated by the system. Read-only. Null for lists. For more information,
see [Kubernetes API
Conventions](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#metadata)"
+// +cue-gen:DestinationRule:preserveUnknownFields:false
+// -->
+//
+// <!-- go code generation tags
+// +kubetype-gen
+// +kubetype-gen:groupVersion=networking.dubbo.apache.org/v1alpha3
+// +genclient
+// +k8s:deepcopy-gen=true
+// -->
+type DestinationRule struct {
+ v1.TypeMeta `json:",inline"`
+ // +optional
+ v1.ObjectMeta `json:"metadata,omitempty"
protobuf:"bytes,1,opt,name=metadata"`
+
+ // Spec defines the implementation of this definition.
+ // +optional
+ Spec networkingv1alpha3.DestinationRule `json:"spec,omitempty"
protobuf:"bytes,2,opt,name=spec"`
+
+ Status v1alpha1.DubboStatus `json:"status,omitempty"`
+}
+
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// DestinationRuleList is a collection of DestinationRules.
+type DestinationRuleList struct {
+ v1.TypeMeta `json:",inline"`
+ // +optional
+ v1.ListMeta `json:"metadata,omitempty"
protobuf:"bytes,1,opt,name=metadata"`
+ Items []*DestinationRule `json:"items"
protobuf:"bytes,2,rep,name=items"`
+}
+
+//
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// <!-- crd generation tags
+// +cue-gen:VirtualService:groupName:networking.dubbo.apache.org
+// +cue-gen:VirtualService:versions:v1alpha3
+// +cue-gen:VirtualService:annotations:helm.sh/resource-policy=keep
+//
+cue-gen:VirtualService:labels:app=dubbo-planet,chart=dubbo,heritage=Tiller,release=dubbo
+// +cue-gen:VirtualService:subresource:status
+// +cue-gen:VirtualService:scope:Namespaced
+// +cue-gen:VirtualService:resource:categories=dubbo,networking,shortNames=vs
+//
+cue-gen:VirtualService:printerColumn:name=Hosts,type=string,JSONPath=.spec.hosts,description="The
destination hosts to which traffic is being sent"
+//
+cue-gen:VirtualService:printerColumn:name=Age,type=date,JSONPath=.metadata.creationTimestamp,description="CreationTimestamp
is a timestamp
+// representing the server time when this object was created. It is not
guaranteed to be set in happens-before order across separate operations.
+// Clients may not set this value. It is represented in RFC3339 form and is in
UTC.
+// Populated by the system. Read-only. Null for lists. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata"
+// +cue-gen:VirtualService:preserveUnknownFields:false
+// -->
+//
+// <!-- go code generation tags
+// +kubetype-gen
+// +kubetype-gen:groupVersion=networking.dubbo.apache.org/v1alpha3
+// +genclient
+// +k8s:deepcopy-gen=true
+// -->
+type VirtualService struct {
+ v1.TypeMeta `json:",inline"`
+ // +optional
+ v1.ObjectMeta `json:"metadata,omitempty"
protobuf:"bytes,1,opt,name=metadata"`
+
+ // Spec defines the implementation of this definition.
+ // +optional
+ Spec networkingv1alpha3.VirtualService `json:"spec,omitempty"
protobuf:"bytes,2,opt,name=spec"`
+
+ Status v1alpha1.DubboStatus `json:"status,omitempty"`
+}
+
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// VirtualServiceList is a collection of VirtualServices.
+type VirtualServiceList struct {
+ v1.TypeMeta `json:",inline"`
+ // +optional
+ v1.ListMeta `json:"metadata,omitempty"
protobuf:"bytes,1,opt,name=metadata"`
+ Items []*VirtualService `json:"items"
protobuf:"bytes,2,rep,name=items"`
+}
diff --git a/client-go/pkg/applyconfiguration/internal/internal.go
b/client-go/pkg/applyconfiguration/internal/internal.go
new file mode 100644
index 00000000..97948bcd
--- /dev/null
+++ b/client-go/pkg/applyconfiguration/internal/internal.go
@@ -0,0 +1,62 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by applyconfiguration-gen. DO NOT EDIT.
+
+package internal
+
+import (
+ "fmt"
+ "sync"
+
+ typed "sigs.k8s.io/structured-merge-diff/v4/typed"
+)
+
+func Parser() *typed.Parser {
+ parserOnce.Do(func() {
+ var err error
+ parser, err = typed.NewParser(schemaYAML)
+ if err != nil {
+ panic(fmt.Sprintf("Failed to parse schema: %v", err))
+ }
+ })
+ return parser
+}
+
+var parserOnce sync.Once
+var parser *typed.Parser
+var schemaYAML = typed.YAMLObject(`types:
+- name: __untyped_atomic_
+ scalar: untyped
+ list:
+ elementType:
+ namedType: __untyped_atomic_
+ elementRelationship: atomic
+ map:
+ elementType:
+ namedType: __untyped_atomic_
+ elementRelationship: atomic
+- name: __untyped_deduced_
+ scalar: untyped
+ list:
+ elementType:
+ namedType: __untyped_atomic_
+ elementRelationship: atomic
+ map:
+ elementType:
+ namedType: __untyped_deduced_
+ elementRelationship: separable
+`)
diff --git a/client-go/pkg/applyconfiguration/meta/v1/objectmeta.go
b/client-go/pkg/applyconfiguration/meta/v1/objectmeta.go
new file mode 100644
index 00000000..a8e58a80
--- /dev/null
+++ b/client-go/pkg/applyconfiguration/meta/v1/objectmeta.go
@@ -0,0 +1,172 @@
+//
+// 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.
+
+// Code generated by applyconfiguration-gen. DO NOT EDIT.
+
+package v1
+
+import (
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ types "k8s.io/apimachinery/pkg/types"
+ metav1 "k8s.io/client-go/applyconfigurations/meta/v1"
+)
+
+// ObjectMetaApplyConfiguration represents an declarative configuration of the
ObjectMeta type for use
+// with apply.
+type ObjectMetaApplyConfiguration struct {
+ Name *string
`json:"name,omitempty"`
+ GenerateName *string
`json:"generateName,omitempty"`
+ Namespace *string
`json:"namespace,omitempty"`
+ UID *types.UID
`json:"uid,omitempty"`
+ ResourceVersion *string
`json:"resourceVersion,omitempty"`
+ Generation *int64
`json:"generation,omitempty"`
+ CreationTimestamp *v1.Time
`json:"creationTimestamp,omitempty"`
+ DeletionTimestamp *v1.Time
`json:"deletionTimestamp,omitempty"`
+ DeletionGracePeriodSeconds *int64
`json:"deletionGracePeriodSeconds,omitempty"`
+ Labels map[string]string
`json:"labels,omitempty"`
+ Annotations map[string]string
`json:"annotations,omitempty"`
+ OwnerReferences []metav1.OwnerReferenceApplyConfiguration
`json:"ownerReferences,omitempty"`
+ Finalizers []string
`json:"finalizers,omitempty"`
+}
+
+// ObjectMetaApplyConfiguration constructs an declarative configuration of the
ObjectMeta type for use with
+// apply.
+func ObjectMeta() *ObjectMetaApplyConfiguration {
+ return &ObjectMetaApplyConfiguration{}
+}
+
+// WithName sets the Name field in the declarative configuration to the given
value
+// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
+// If called multiple times, the Name field is set to the value of the last
call.
+func (b *ObjectMetaApplyConfiguration) WithName(value string)
*ObjectMetaApplyConfiguration {
+ b.Name = &value
+ return b
+}
+
+// WithGenerateName sets the GenerateName field in the declarative
configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
+// If called multiple times, the GenerateName field is set to the value of the
last call.
+func (b *ObjectMetaApplyConfiguration) WithGenerateName(value string)
*ObjectMetaApplyConfiguration {
+ b.GenerateName = &value
+ return b
+}
+
+// WithNamespace sets the Namespace field in the declarative configuration to
the given value
+// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
+// If called multiple times, the Namespace field is set to the value of the
last call.
+func (b *ObjectMetaApplyConfiguration) WithNamespace(value string)
*ObjectMetaApplyConfiguration {
+ b.Namespace = &value
+ return b
+}
+
+// WithUID sets the UID field in the declarative configuration to the given
value
+// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
+// If called multiple times, the UID field is set to the value of the last
call.
+func (b *ObjectMetaApplyConfiguration) WithUID(value types.UID)
*ObjectMetaApplyConfiguration {
+ b.UID = &value
+ return b
+}
+
+// WithResourceVersion sets the ResourceVersion field in the declarative
configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
+// If called multiple times, the ResourceVersion field is set to the value of
the last call.
+func (b *ObjectMetaApplyConfiguration) WithResourceVersion(value string)
*ObjectMetaApplyConfiguration {
+ b.ResourceVersion = &value
+ return b
+}
+
+// WithGeneration sets the Generation field in the declarative configuration
to the given value
+// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
+// If called multiple times, the Generation field is set to the value of the
last call.
+func (b *ObjectMetaApplyConfiguration) WithGeneration(value int64)
*ObjectMetaApplyConfiguration {
+ b.Generation = &value
+ return b
+}
+
+// WithCreationTimestamp sets the CreationTimestamp field in the declarative
configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
+// If called multiple times, the CreationTimestamp field is set to the value
of the last call.
+func (b *ObjectMetaApplyConfiguration) WithCreationTimestamp(value v1.Time)
*ObjectMetaApplyConfiguration {
+ b.CreationTimestamp = &value
+ return b
+}
+
+// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative
configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
+// If called multiple times, the DeletionTimestamp field is set to the value
of the last call.
+func (b *ObjectMetaApplyConfiguration) WithDeletionTimestamp(value v1.Time)
*ObjectMetaApplyConfiguration {
+ b.DeletionTimestamp = &value
+ return b
+}
+
+// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in
the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
+// If called multiple times, the DeletionGracePeriodSeconds field is set to
the value of the last call.
+func (b *ObjectMetaApplyConfiguration) WithDeletionGracePeriodSeconds(value
int64) *ObjectMetaApplyConfiguration {
+ b.DeletionGracePeriodSeconds = &value
+ return b
+}
+
+// WithLabels puts the entries into the Labels field in the declarative
configuration
+// and returns the receiver, so that objects can be build by chaining "With"
function invocations.
+// If called multiple times, the entries provided by each call will be put on
the Labels field,
+// overwriting an existing map entries in Labels field with the same key.
+func (b *ObjectMetaApplyConfiguration) WithLabels(entries map[string]string)
*ObjectMetaApplyConfiguration {
+ if b.Labels == nil && len(entries) > 0 {
+ b.Labels = make(map[string]string, len(entries))
+ }
+ for k, v := range entries {
+ b.Labels[k] = v
+ }
+ return b
+}
+
+// WithAnnotations puts the entries into the Annotations field in the
declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With"
function invocations.
+// If called multiple times, the entries provided by each call will be put on
the Annotations field,
+// overwriting an existing map entries in Annotations field with the same key.
+func (b *ObjectMetaApplyConfiguration) WithAnnotations(entries
map[string]string) *ObjectMetaApplyConfiguration {
+ if b.Annotations == nil && len(entries) > 0 {
+ b.Annotations = make(map[string]string, len(entries))
+ }
+ for k, v := range entries {
+ b.Annotations[k] = v
+ }
+ return b
+}
+
+// WithOwnerReferences adds the given value to the OwnerReferences field in
the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With"
function invocations.
+// If called multiple times, values provided by each call will be appended to
the OwnerReferences field.
+func (b *ObjectMetaApplyConfiguration) WithOwnerReferences(values
...*metav1.OwnerReferenceApplyConfiguration) *ObjectMetaApplyConfiguration {
+ for i := range values {
+ if values[i] == nil {
+ panic("nil value passed to WithOwnerReferences")
+ }
+ b.OwnerReferences = append(b.OwnerReferences, *values[i])
+ }
+ return b
+}
+
+// WithFinalizers adds the given value to the Finalizers field in the
declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With"
function invocations.
+// If called multiple times, values provided by each call will be appended to
the Finalizers field.
+func (b *ObjectMetaApplyConfiguration) WithFinalizers(values ...string)
*ObjectMetaApplyConfiguration {
+ for i := range values {
+ b.Finalizers = append(b.Finalizers, values[i])
+ }
+ return b
+}
diff --git a/client-go/pkg/applyconfiguration/meta/v1/ownerreference.go
b/client-go/pkg/applyconfiguration/meta/v1/ownerreference.go
new file mode 100644
index 00000000..45ea2c86
--- /dev/null
+++ b/client-go/pkg/applyconfiguration/meta/v1/ownerreference.go
@@ -0,0 +1,88 @@
+//
+// 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.
+
+// Code generated by applyconfiguration-gen. DO NOT EDIT.
+
+package v1
+
+import (
+ types "k8s.io/apimachinery/pkg/types"
+)
+
+// OwnerReferenceApplyConfiguration represents an declarative configuration of
the OwnerReference type for use
+// with apply.
+type OwnerReferenceApplyConfiguration struct {
+ APIVersion *string `json:"apiVersion,omitempty"`
+ Kind *string `json:"kind,omitempty"`
+ Name *string `json:"name,omitempty"`
+ UID *types.UID `json:"uid,omitempty"`
+ Controller *bool `json:"controller,omitempty"`
+ BlockOwnerDeletion *bool `json:"blockOwnerDeletion,omitempty"`
+}
+
+// OwnerReferenceApplyConfiguration constructs an declarative configuration of
the OwnerReference type for use with
+// apply.
+func OwnerReference() *OwnerReferenceApplyConfiguration {
+ return &OwnerReferenceApplyConfiguration{}
+}
+
+// WithAPIVersion sets the APIVersion field in the declarative configuration
to the given value
+// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
+// If called multiple times, the APIVersion field is set to the value of the
last call.
+func (b *OwnerReferenceApplyConfiguration) WithAPIVersion(value string)
*OwnerReferenceApplyConfiguration {
+ b.APIVersion = &value
+ return b
+}
+
+// WithKind sets the Kind field in the declarative configuration to the given
value
+// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
+// If called multiple times, the Kind field is set to the value of the last
call.
+func (b *OwnerReferenceApplyConfiguration) WithKind(value string)
*OwnerReferenceApplyConfiguration {
+ b.Kind = &value
+ return b
+}
+
+// WithName sets the Name field in the declarative configuration to the given
value
+// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
+// If called multiple times, the Name field is set to the value of the last
call.
+func (b *OwnerReferenceApplyConfiguration) WithName(value string)
*OwnerReferenceApplyConfiguration {
+ b.Name = &value
+ return b
+}
+
+// WithUID sets the UID field in the declarative configuration to the given
value
+// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
+// If called multiple times, the UID field is set to the value of the last
call.
+func (b *OwnerReferenceApplyConfiguration) WithUID(value types.UID)
*OwnerReferenceApplyConfiguration {
+ b.UID = &value
+ return b
+}
+
+// WithController sets the Controller field in the declarative configuration
to the given value
+// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
+// If called multiple times, the Controller field is set to the value of the
last call.
+func (b *OwnerReferenceApplyConfiguration) WithController(value bool)
*OwnerReferenceApplyConfiguration {
+ b.Controller = &value
+ return b
+}
+
+// WithBlockOwnerDeletion sets the BlockOwnerDeletion field in the declarative
configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
+// If called multiple times, the BlockOwnerDeletion field is set to the value
of the last call.
+func (b *OwnerReferenceApplyConfiguration) WithBlockOwnerDeletion(value bool)
*OwnerReferenceApplyConfiguration {
+ b.BlockOwnerDeletion = &value
+ return b
+}
diff --git a/client-go/pkg/applyconfiguration/meta/v1/typemeta.go
b/client-go/pkg/applyconfiguration/meta/v1/typemeta.go
new file mode 100644
index 00000000..b7e00bf7
--- /dev/null
+++ b/client-go/pkg/applyconfiguration/meta/v1/typemeta.go
@@ -0,0 +1,48 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by applyconfiguration-gen. DO NOT EDIT.
+
+package v1
+
+// TypeMetaApplyConfiguration represents an declarative configuration of the
TypeMeta type for use
+// with apply.
+type TypeMetaApplyConfiguration struct {
+ Kind *string `json:"kind,omitempty"`
+ APIVersion *string `json:"apiVersion,omitempty"`
+}
+
+// TypeMetaApplyConfiguration constructs an declarative configuration of the
TypeMeta type for use with
+// apply.
+func TypeMeta() *TypeMetaApplyConfiguration {
+ return &TypeMetaApplyConfiguration{}
+}
+
+// WithKind sets the Kind field in the declarative configuration to the given
value
+// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
+// If called multiple times, the Kind field is set to the value of the last
call.
+func (b *TypeMetaApplyConfiguration) WithKind(value string)
*TypeMetaApplyConfiguration {
+ b.Kind = &value
+ return b
+}
+
+// WithAPIVersion sets the APIVersion field in the declarative configuration
to the given value
+// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
+// If called multiple times, the APIVersion field is set to the value of the
last call.
+func (b *TypeMetaApplyConfiguration) WithAPIVersion(value string)
*TypeMetaApplyConfiguration {
+ b.APIVersion = &value
+ return b
+}
diff --git a/client-go/pkg/applyconfiguration/utils.go
b/client-go/pkg/applyconfiguration/utils.go
new file mode 100644
index 00000000..8a3650f7
--- /dev/null
+++ b/client-go/pkg/applyconfiguration/utils.go
@@ -0,0 +1,41 @@
+//
+// 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.
+
+// Code generated by applyconfiguration-gen. DO NOT EDIT.
+
+package applyconfiguration
+
+import (
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
+ metav1 "k8s.io/client-go/applyconfigurations/meta/v1"
+)
+
+// ForKind returns an apply configuration type for the given GroupVersionKind,
or nil if no
+// apply configuration type exists for the given GroupVersionKind.
+func ForKind(kind schema.GroupVersionKind) interface{} {
+ switch kind {
+ // Group=meta.k8s.io, Version=v1
+ case v1.SchemeGroupVersion.WithKind("ObjectMeta"):
+ return &metav1.ObjectMetaApplyConfiguration{}
+ case v1.SchemeGroupVersion.WithKind("OwnerReference"):
+ return &metav1.OwnerReferenceApplyConfiguration{}
+ case v1.SchemeGroupVersion.WithKind("TypeMeta"):
+ return &metav1.TypeMetaApplyConfiguration{}
+
+ }
+ return nil
+}
diff --git a/client-go/pkg/clientset/versioned/clientset.go
b/client-go/pkg/clientset/versioned/clientset.go
new file mode 100644
index 00000000..4c2c0bca
--- /dev/null
+++ b/client-go/pkg/clientset/versioned/clientset.go
@@ -0,0 +1,19 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package versioned
diff --git a/client-go/pkg/clientset/versioned/fake/clientset_generated.go
b/client-go/pkg/clientset/versioned/fake/clientset_generated.go
new file mode 100644
index 00000000..4f3f17a1
--- /dev/null
+++ b/client-go/pkg/clientset/versioned/fake/clientset_generated.go
@@ -0,0 +1,19 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package fake
diff --git a/client-go/pkg/clientset/versioned/fake/doc.go
b/client-go/pkg/clientset/versioned/fake/doc.go
new file mode 100644
index 00000000..6f3e45fb
--- /dev/null
+++ b/client-go/pkg/clientset/versioned/fake/doc.go
@@ -0,0 +1,20 @@
+//
+// 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.
+
+// Code generated by client-gen. DO NOT EDIT.
+
+// This package has the automatically generated fake clientset.
+package fake
diff --git a/client-go/pkg/clientset/versioned/fake/register.go
b/client-go/pkg/clientset/versioned/fake/register.go
new file mode 100644
index 00000000..4f3f17a1
--- /dev/null
+++ b/client-go/pkg/clientset/versioned/fake/register.go
@@ -0,0 +1,19 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package fake
diff --git a/client-go/pkg/clientset/versioned/scheme/doc.go
b/client-go/pkg/clientset/versioned/scheme/doc.go
new file mode 100644
index 00000000..8931dc53
--- /dev/null
+++ b/client-go/pkg/clientset/versioned/scheme/doc.go
@@ -0,0 +1,20 @@
+//
+// 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.
+
+// Code generated by client-gen. DO NOT EDIT.
+
+// This package contains the scheme of the automatically generated clientset.
+package scheme
diff --git a/client-go/pkg/clientset/versioned/scheme/register.go
b/client-go/pkg/clientset/versioned/scheme/register.go
new file mode 100644
index 00000000..a9569ec0
--- /dev/null
+++ b/client-go/pkg/clientset/versioned/scheme/register.go
@@ -0,0 +1,19 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package scheme
diff --git a/client-go/pkg/clientset/versioned/typed/networking/v1alpha3/doc.go
b/client-go/pkg/clientset/versioned/typed/networking/v1alpha3/doc.go
new file mode 100644
index 00000000..1697aa54
--- /dev/null
+++ b/client-go/pkg/clientset/versioned/typed/networking/v1alpha3/doc.go
@@ -0,0 +1,20 @@
+//
+// 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.
+
+// Code generated by client-gen. DO NOT EDIT.
+
+// This package has the automatically generated typed clients.
+package v1alpha3
diff --git
a/client-go/pkg/clientset/versioned/typed/networking/v1alpha3/fake/doc.go
b/client-go/pkg/clientset/versioned/typed/networking/v1alpha3/fake/doc.go
new file mode 100644
index 00000000..cccb459f
--- /dev/null
+++ b/client-go/pkg/clientset/versioned/typed/networking/v1alpha3/fake/doc.go
@@ -0,0 +1,20 @@
+//
+// 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.
+
+// Code generated by client-gen. DO NOT EDIT.
+
+// Package fake has the automatically generated clients.
+package fake
diff --git
a/client-go/pkg/clientset/versioned/typed/networking/v1alpha3/fake/fake_networking_client.go
b/client-go/pkg/clientset/versioned/typed/networking/v1alpha3/fake/fake_networking_client.go
new file mode 100644
index 00000000..4f3f17a1
--- /dev/null
+++
b/client-go/pkg/clientset/versioned/typed/networking/v1alpha3/fake/fake_networking_client.go
@@ -0,0 +1,19 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package fake
diff --git
a/client-go/pkg/clientset/versioned/typed/networking/v1alpha3/generated_expansion.go
b/client-go/pkg/clientset/versioned/typed/networking/v1alpha3/generated_expansion.go
new file mode 100644
index 00000000..1ce7eb7a
--- /dev/null
+++
b/client-go/pkg/clientset/versioned/typed/networking/v1alpha3/generated_expansion.go
@@ -0,0 +1,19 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package v1alpha3
diff --git
a/client-go/pkg/clientset/versioned/typed/networking/v1alpha3/networking_client.go
b/client-go/pkg/clientset/versioned/typed/networking/v1alpha3/networking_client.go
new file mode 100644
index 00000000..1ce7eb7a
--- /dev/null
+++
b/client-go/pkg/clientset/versioned/typed/networking/v1alpha3/networking_client.go
@@ -0,0 +1,19 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package v1alpha3
diff --git a/go.mod b/go.mod
index 6efb735a..53ae3e92 100644
--- a/go.mod
+++ b/go.mod
@@ -17,6 +17,12 @@ module github.com/apache/dubbo-kubernetes
go 1.24.0
+require (
+ k8s.io/apimachinery v0.34.1
+ k8s.io/client-go v0.34.1
+ sigs.k8s.io/structured-merge-diff/v4 v4.6.0
+)
+
require (
github.com/AlecAivazis/survey/v2 v2.3.7
github.com/Masterminds/sprig/v3 v3.3.0
@@ -79,8 +85,6 @@ require (
istio.io/client-go v1.27.1
k8s.io/api v0.34.1
k8s.io/apiextensions-apiserver v0.34.1
- k8s.io/apimachinery v0.34.1
- k8s.io/client-go v0.34.1
k8s.io/gengo v0.0.0-20251215205346-5ee0d033ba5b
k8s.io/klog/v2 v2.130.1
k8s.io/kubectl v0.33.3
@@ -273,5 +277,4 @@ replace (
github.com/google/go-containerregistry =>
github.com/google/go-containerregistry v0.20.2
github.com/moby/buildkit => github.com/moby/buildkit v0.10.6
github.com/moby/dockerfile => github.com/moby/dockerfile v1.4.1
-
)
diff --git a/go.sum b/go.sum
index 581e42ff..53b06856 100644
--- a/go.sum
+++ b/go.sum
@@ -361,6 +361,7 @@ github.com/google/go-cmp v0.4.0/go.mod
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.0/go.mod
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8/go.mod
h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.5.9/go.mod
h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod
h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-containerregistry v0.20.2
h1:B1wPJ1SN/S7pB+ZAimcciVD+r+yV/l/DSArMxlbwseo=
@@ -932,10 +933,14 @@ sigs.k8s.io/kustomize/kyaml v0.19.0
h1:RFge5qsO1uHhwJsu3ipV7RNolC7Uozc0jUBC/61XS
sigs.k8s.io/kustomize/kyaml v0.19.0/go.mod
h1:FeKD5jEOH+FbZPpqUghBP8mrLjJ3+zD3/rf9NNu1cwY=
sigs.k8s.io/mcs-api v0.2.0 h1:F8o/nIpQmog494Qwe94srDWjS3ltEu4y5IL9i3dB938=
sigs.k8s.io/mcs-api v0.2.0/go.mod
h1:zZ5CK8uS6HaLkxY4HqsmcBHfzHuNMrY2uJy8T7jffK4=
+sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod
h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
sigs.k8s.io/randfill v1.0.0/go.mod
h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
+sigs.k8s.io/structured-merge-diff/v4 v4.6.0
h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc=
+sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod
h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
sigs.k8s.io/structured-merge-diff/v6 v6.3.0
h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco=
sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod
h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
+sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
diff --git a/header.go.txt b/header.go.txt
new file mode 100644
index 00000000..bf64d9fa
--- /dev/null
+++ b/header.go.txt
@@ -0,0 +1,16 @@
+//
+// 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.
+
diff --git a/kubetype-gen b/kubetype-gen
deleted file mode 100755
index 3ec817ea..00000000
Binary files a/kubetype-gen and /dev/null differ
diff --git a/tests/grpc-app/.dockerignore b/tests/grpc-app/.dockerignore
deleted file mode 100644
index e29c0862..00000000
--- a/tests/grpc-app/.dockerignore
+++ /dev/null
@@ -1,21 +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.
-
-*.md
-bin/
-*.pb.go
-.git/
-.gitignore
-README.md
\ No newline at end of file
diff --git a/tests/grpc-app/.gitignore b/tests/grpc-app/.gitignore
deleted file mode 100644
index db441f49..00000000
--- a/tests/grpc-app/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-bin/
-*.pb.go
diff --git a/tests/grpc-app/README.md b/tests/grpc-app/README.md
deleted file mode 100644
index a88ecf5f..00000000
--- a/tests/grpc-app/README.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# gRPC Application
-
-This is a test example for gRPC proxyless service mesh based on [Istio's blog
post](https://istio.io/latest/blog/2021/proxyless-grpc/).
-
-## Architecture
-
-- **Provider**: gRPC server with xDS support (port 17070). This service is
deployed with multiple versions (v1/v2) to demonstrate gray
release/traffic-splitting scenarios and exposes gRPC reflection so `grpcurl`
can query it directly.
-- **Consumer**: gRPC client with xDS support + test server (port 17171). This
component drives load toward the provider service for automated tests.
-
-Both services use `dubbo-proxy` sidecar as an xDS proxy to connect to the
control plane. The sidecar runs an xDS proxy server that listens on a Unix
Domain Socket (UDS) at `/etc/dubbo/proxy/XDS`. The gRPC applications connect to
this xDS proxy via the UDS socket using the `GRPC_XDS_BOOTSTRAP` environment
variable.
-
-**Note**: This is "proxyless" in the sense that the applications use native
gRPC xDS clients instead of Envoy proxy for traffic routing. However, a
lightweight sidecar (`dubbo-proxy`) is still used to proxy xDS API calls
between the gRPC clients and the control plane.
diff --git a/tests/grpc-app/consumer/main.go b/tests/grpc-app/consumer/main.go
deleted file mode 100644
index c5dad251..00000000
--- a/tests/grpc-app/consumer/main.go
+++ /dev/null
@@ -1,739 +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.
-
-package main
-
-import (
- "context"
- "encoding/json"
- "flag"
- "fmt"
- "log"
- "net"
- "os"
- "os/signal"
- "regexp"
- "strings"
- "sync"
- "syscall"
- "time"
-
- "google.golang.org/grpc"
- "google.golang.org/grpc/connectivity"
- "google.golang.org/grpc/credentials/insecure"
- xdscreds "google.golang.org/grpc/credentials/xds"
- "google.golang.org/grpc/grpclog"
- "google.golang.org/grpc/reflection"
- "google.golang.org/grpc/status"
- _ "google.golang.org/grpc/xds"
-
- pb "github.com/apache/dubbo-kubernetes/tests/grpc-app/proto"
-)
-
-var (
- port = flag.Int("port", 17171, "gRPC server port for ForwardEcho
testing")
- testServer *grpc.Server
-)
-
-// grpcLogger filters out xDS informational logs that are incorrectly marked
as ERROR
-type grpcLogger struct {
- logger *log.Logger
-}
-
-var (
- // Regex to match gRPC formatting errors like %!p(...)
- formatErrorRegex = regexp.MustCompile(`%!p\([^)]+\)`)
-)
-
-// cleanMessage removes formatting errors from gRPC logs
-// Fixes issues like:
"\u003c%!p(networktype.keyType=grpc.internal.transport.networktype)\u003e":
"unix"
-func cleanMessage(msg string) string {
- // Replace %!p(...) patterns with a cleaner representation
- msg = formatErrorRegex.ReplaceAllStringFunc(msg, func(match string)
string {
- // Extract the key from %!p(networktype.keyType=...)
- if strings.Contains(match, "networktype.keyType") {
- return `"networktype"`
- }
- // For other cases, just remove the error pattern
- return ""
- })
- // Also clean up Unicode escape sequences that appear with formatting
errors
- // Replace \u003c (which is <) and \u003e (which is >) when they appear
with formatting errors
- msg = strings.ReplaceAll(msg, `\u003c`, "<")
- msg = strings.ReplaceAll(msg, `\u003e`, ">")
- // Clean up patterns like <...>: "unix" to just show the value
- msg = regexp.MustCompile(`<[^>]*>:\s*"unix"`).ReplaceAllString(msg,
`"networktype": "unix"`)
- return msg
-}
-
-func (l *grpcLogger) Info(args ...interface{}) {
- msg := fmt.Sprint(args...)
- if strings.Contains(msg, "entering mode") && strings.Contains(msg,
"SERVING") {
- return
- }
- msg = cleanMessage(msg)
- l.logger.Print("INFO: ", msg)
-}
-
-func (l *grpcLogger) Infoln(args ...interface{}) {
- msg := fmt.Sprintln(args...)
- if strings.Contains(msg, "entering mode") && strings.Contains(msg,
"SERVING") {
- return
- }
- msg = cleanMessage(msg)
- l.logger.Print("INFO: ", msg)
-}
-
-func (l *grpcLogger) Infof(format string, args ...interface{}) {
- msg := fmt.Sprintf(format, args...)
- if strings.Contains(msg, "entering mode") && strings.Contains(msg,
"SERVING") {
- return
- }
- msg = cleanMessage(msg)
- l.logger.Printf("INFO: %s", msg)
-}
-
-func (l *grpcLogger) Warning(args ...interface{}) {
- msg := cleanMessage(fmt.Sprint(args...))
- l.logger.Print("WARNING: ", msg)
-}
-
-func (l *grpcLogger) Warningln(args ...interface{}) {
- msg := cleanMessage(fmt.Sprintln(args...))
- l.logger.Print("WARNING: ", msg)
-}
-
-func (l *grpcLogger) Warningf(format string, args ...interface{}) {
- msg := cleanMessage(fmt.Sprintf(format, args...))
- l.logger.Printf("WARNING: %s", msg)
-}
-
-func (l *grpcLogger) Error(args ...interface{}) {
- msg := fmt.Sprint(args...)
- if strings.Contains(msg, "entering mode") && strings.Contains(msg,
"SERVING") {
- return
- }
- msg = cleanMessage(msg)
- l.logger.Print("ERROR: ", msg)
-}
-
-func (l *grpcLogger) Errorln(args ...interface{}) {
- msg := fmt.Sprintln(args...)
- if strings.Contains(msg, "entering mode") && strings.Contains(msg,
"SERVING") {
- return
- }
- msg = cleanMessage(msg)
- l.logger.Print("ERROR: ", msg)
-}
-
-func (l *grpcLogger) Errorf(format string, args ...interface{}) {
- msg := fmt.Sprintf(format, args...)
- if strings.Contains(msg, "entering mode") && strings.Contains(msg,
"SERVING") {
- return
- }
- msg = cleanMessage(msg)
- l.logger.Printf("ERROR: %s", msg)
-}
-
-func (l *grpcLogger) Fatal(args ...interface{}) {
- l.logger.Fatal(args...)
-}
-
-func (l *grpcLogger) Fatalln(args ...interface{}) {
- l.logger.Fatal(args...)
-}
-
-func (l *grpcLogger) Fatalf(format string, args ...interface{}) {
- l.logger.Fatalf(format, args...)
-}
-
-func (l *grpcLogger) V(level int) bool {
- return level <= 0
-}
-
-func main() {
- flag.Parse()
-
- // Set custom gRPC logger to filter out xDS informational logs
- // The "ERROR: [xds] Listener entering mode: SERVING" is actually an
informational log
- grpclog.SetLoggerV2(&grpcLogger{
- logger: log.New(os.Stderr, "", log.LstdFlags),
- })
-
- go startTestServer(*port)
-
- log.Printf("Consumer running. Test server listening on port %d for
ForwardEcho", *port)
-
- sigChan := make(chan os.Signal, 1)
- signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
- <-sigChan
- log.Println("Shutting down...")
-
- if testServer != nil {
- log.Println("Stopping test server...")
- testServer.GracefulStop()
- }
-}
-
-func startTestServer(port int) {
- lis, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", port))
- if err != nil {
- log.Printf("Failed to listen on port %d: %v", port, err)
- return
- }
-
- testServer = grpc.NewServer()
- pb.RegisterEchoTestServiceServer(testServer, &testServerImpl{
- connCache: make(map[string]*cachedConnection),
- })
- reflection.Register(testServer)
-
- log.Printf("Test server listening on port %d for ForwardEcho
(reflection enabled)", port)
- if err := testServer.Serve(lis); err != nil {
- log.Printf("Test server error: %v", err)
- }
-}
-
-type cachedConnection struct {
- conn *grpc.ClientConn
- createdAt time.Time
-}
-
-type testServerImpl struct {
- pb.UnimplementedEchoTestServiceServer
- // Connection cache: map from URL to cached connection
- connCache map[string]*cachedConnection
- connMutex sync.RWMutex
-}
-
-// formatGRPCError formats gRPC errors similar to grpcurl output
-func formatGRPCError(err error, index int32, total int32) string {
- if err == nil {
- return ""
- }
-
- // Extract gRPC status code and message using status package
- code := "Unknown"
- message := err.Error()
-
- // Try to extract gRPC status
- if st, ok := status.FromError(err); ok {
- code = st.Code().String()
- message = st.Message()
- } else {
- // Fallback: try to extract from error string
- if strings.Contains(message, "code = ") {
- // Extract code like "code = Unavailable"
- codeMatch := regexp.MustCompile(`code =
(\w+)`).FindStringSubmatch(message)
- if len(codeMatch) > 1 {
- code = codeMatch[1]
- }
- // Extract message after "desc = "
- descMatch := regexp.MustCompile(`desc =
"?([^"]+)"?`).FindStringSubmatch(message)
- if len(descMatch) > 1 {
- message = descMatch[1]
- } else {
- // If no desc, try to extract message after code
- parts := strings.SplitN(message, "desc = ", 2)
- if len(parts) > 1 {
- message = strings.Trim(parts[1], `"`)
- }
- }
- }
- }
-
- // Format similar to grpcurl (single line format)
- if total == 1 {
- return fmt.Sprintf("ERROR:\nCode: %s\nMessage: %s", code,
message)
- }
- return fmt.Sprintf("[%d] Error: rpc error: code = %s desc = %s", index,
code, message)
-}
-
-func (s *testServerImpl) ForwardEcho(ctx context.Context, req
*pb.ForwardEchoRequest) (*pb.ForwardEchoResponse, error) {
- if req == nil {
- return nil, fmt.Errorf("request is nil")
- }
-
- if req.Url == "" {
- return nil, fmt.Errorf("url is required")
- }
-
- count := req.Count
- if count < 0 {
- count = 0
- }
- if count > 100 {
- count = 100
- }
-
- log.Printf("ForwardEcho: url=%s, count=%d", req.Url, count)
-
- // Check bootstrap configuration
- bootstrapPath := os.Getenv("GRPC_XDS_BOOTSTRAP")
- if bootstrapPath == "" {
- return nil, fmt.Errorf("GRPC_XDS_BOOTSTRAP environment variable
is not set")
- }
-
- // Verify bootstrap file exists
- if _, err := os.Stat(bootstrapPath); os.IsNotExist(err) {
- return nil, fmt.Errorf("bootstrap file does not exist: %s",
bootstrapPath)
- }
-
- // Read bootstrap file to verify UDS socket
- bootstrapData, err := os.ReadFile(bootstrapPath)
- if err != nil {
- return nil, fmt.Errorf("failed to read bootstrap file: %v", err)
- }
-
- var bootstrapJSON map[string]interface{}
- if err := json.Unmarshal(bootstrapData, &bootstrapJSON); err != nil {
- return nil, fmt.Errorf("failed to parse bootstrap file: %v",
err)
- }
-
- // Extract UDS socket path
- var udsPath string
- if xdsServers, ok := bootstrapJSON["xds_servers"].([]interface{}); ok
&& len(xdsServers) > 0 {
- if server, ok := xdsServers[0].(map[string]interface{}); ok {
- if serverURI, ok := server["server_uri"].(string); ok {
- if strings.HasPrefix(serverURI, "unix://") {
- udsPath = strings.TrimPrefix(serverURI,
"unix://")
- if _, err := os.Stat(udsPath);
os.IsNotExist(err) {
- return nil, fmt.Errorf("UDS
socket does not exist: %s", udsPath)
- }
- }
- }
- }
- }
-
- // Reuse connections to avoid creating new xDS connections for each RPC
call
- // This prevents the RDS request loop issue and ensures stable
connection state
- s.connMutex.RLock()
- cached, exists := s.connCache[req.Url]
- var conn *grpc.ClientConn
- if exists && cached != nil {
- conn = cached.conn
- }
- s.connMutex.RUnlock()
-
- // Check if cached connection is still valid and not too old.
- // When xDS config changes (e.g., TLS is added/removed), gRPC xDS
client should update connections,
- // but if the connection was established before xDS config was
received, it may use old configuration.
- // To ensure we use the latest xDS config, we clear connections older
than 10 seconds.
- // rebuilt quickly to use the new configuration.
- const maxConnectionAge = 10 * time.Second
- if exists && conn != nil {
- state := conn.GetState()
- if state == connectivity.Shutdown {
- // Connection is closed, remove from cache
- log.Printf("ForwardEcho: cached connection for %s is
SHUTDOWN, removing from cache", req.Url)
- s.connMutex.Lock()
- delete(s.connCache, req.Url)
- conn = nil
- exists = false
- s.connMutex.Unlock()
- } else if time.Since(cached.createdAt) > maxConnectionAge {
- // Connection is too old, may be using stale xDS config
(e.g., plaintext when TLS is required)
- // Clear cache to force reconnection with latest xDS
config
- log.Printf("ForwardEcho: cached connection for %s is
too old (%v), clearing cache to use latest xDS config", req.Url,
time.Since(cached.createdAt))
- s.connMutex.Lock()
- if cachedConn, stillExists := s.connCache[req.Url];
stillExists && cachedConn != nil && cachedConn.conn != nil {
- cachedConn.conn.Close()
- }
- delete(s.connCache, req.Url)
- conn = nil
- exists = false
- s.connMutex.Unlock()
- }
- }
-
- if !exists || conn == nil {
- // Create new connection
- s.connMutex.Lock()
- // Double-check after acquiring write lock
- if cached, exists = s.connCache[req.Url]; !exists || cached ==
nil || cached.conn == nil {
- conn = nil
- // When TLS is configured (DestinationRule
ISTIO_MUTUAL), gRPC xDS client needs
- // to fetch certificates from CertificateProvider. The
CertificateProvider uses file_watcher
- // to read certificate files. If the files are not
ready or CertificateProvider is not
- // initialized, certificate fetching will timeout.
- // We wait a short time to ensure CertificateProvider
is ready and certificate files are accessible.
- // This is especially important when DestinationRule is
just created and TLS is enabled.
- // The CertificateProvider may need time to initialize,
especially on first connection.
- // We wait 3 seconds to give CertificateProvider enough
time to initialize (reduced from 5s for faster startup).
- log.Printf("ForwardEcho: waiting 3 seconds to ensure
CertificateProvider is ready...")
- time.Sleep(3 * time.Second)
-
- // Create xDS client credentials
- // NOTE: FallbackCreds is REQUIRED by gRPC xDS library
for initial connection
- // before xDS configuration is available. However, once
xDS configures TLS,
- // the client will use TLS and will NOT fallback to
plaintext if TLS fails.
- // FallbackCreds is only used when xDS has not yet
provided TLS configuration.
- creds, err :=
xdscreds.NewClientCredentials(xdscreds.ClientOptions{
- FallbackCreds: insecure.NewCredentials(),
- })
- if err != nil {
- s.connMutex.Unlock()
- return nil, fmt.Errorf("failed to create xDS
client credentials: %v", err)
- }
-
- // Dial with xDS URL - use background context, not the
request context
- // The request context might timeout before xDS
configuration is received
- // When TLS is configured (DestinationRule
ISTIO_MUTUAL), gRPC xDS client needs
- // to fetch certificates from CertificateProvider. This
may take time, especially on
- // first connection. We use a longer timeout context to
allow certificate fetching.
- log.Printf("ForwardEcho: creating new connection for
%s...", req.Url)
- dialCtx, dialCancel :=
context.WithTimeout(context.Background(), 60*time.Second)
- conn, err = grpc.DialContext(dialCtx, req.Url,
grpc.WithTransportCredentials(creds))
- dialCancel()
- if err != nil {
- s.connMutex.Unlock()
- return nil, fmt.Errorf("failed to dial %s: %v",
req.Url, err)
- }
- s.connCache[req.Url] = &cachedConnection{
- conn: conn,
- createdAt: time.Now(),
- }
- log.Printf("ForwardEcho: cached connection for %s",
req.Url)
- }
- s.connMutex.Unlock()
- } else {
- log.Printf("ForwardEcho: reusing cached connection for %s
(state: %v)", req.Url, conn.GetState())
- // NOTE: We reuse the cached connection. If xDS config changes
(e.g., TLS is added/removed),
- // gRPC xDS client should automatically update the connection.
However, if the connection
- // was established before xDS config was received, it may still
be using old configuration.
- // We rely on the TLS mismatch detection logic in the RPC error
handling to handle this case.
- }
-
- initialState := conn.GetState()
- log.Printf("ForwardEcho: initial connection state: %v", initialState)
-
- // Even if connection is READY, we need to verify it's still valid
- // because xDS configuration may have changed (e.g., from plaintext to
TLS)
- // and the cached connection might be using old configuration.
- // gRPC xDS client should automatically update connections, but if the
connection
- // was established before xDS config was received, it might be using
FallbackCreds (plaintext).
- // We'll proceed with RPC calls, but if they fail with TLS/plaintext
mismatch errors,
- // we'll clear the cache and retry.
- // When TLS is configured (DestinationRule ISTIO_MUTUAL), gRPC xDS
client needs
- // to fetch certificates from CertificateProvider during TLS handshake.
The TLS handshake
- // happens when the connection state transitions to READY. If
CertificateProvider is not ready,
- // the TLS handshake will timeout. We need to wait for the connection
to be READY, which
- // indicates that TLS handshake has completed successfully.
- if initialState == connectivity.Ready {
- log.Printf("ForwardEcho: connection is already READY,
proceeding with RPC calls (will retry with new connection if TLS/plaintext
mismatch detected)")
- } else {
- // Only wait for new connections or connections that are not
READY
- // For gRPC xDS proxyless, we need to wait for the client to
receive and process LDS/CDS/EDS
- // The connection state may transition: IDLE -> CONNECTING ->
READY (or TRANSIENT_FAILURE -> CONNECTING -> READY)
- // When TLS is configured, the TLS handshake happens during
this state transition.
- // If CertificateProvider is not ready, the TLS handshake will
timeout and connection will fail.
- // We use a longer timeout (60 seconds) to allow
CertificateProvider to fetch certificates.
- log.Printf("ForwardEcho: waiting for xDS configuration to be
processed and connection to be ready (60 seconds)...")
-
- // Wait for state changes with multiple attempts
- maxWait := 60 * time.Second
-
- // Wait for state changes, allowing multiple state transitions
- // Don't exit on TRANSIENT_FAILURE - it may recover to READY
- stateChanged := false
- currentState := initialState
- startTime := time.Now()
- lastStateChangeTime := startTime
-
- for time.Since(startTime) < maxWait {
- if currentState == connectivity.Ready {
- log.Printf("ForwardEcho: connection is READY
after %v", time.Since(startTime))
- stateChanged = true
- break
- }
-
- // Only exit on Shutdown, not on TransientFailure (it
may recover)
- if currentState == connectivity.Shutdown {
- log.Printf("ForwardEcho: connection in %v state
after %v, cannot recover", currentState, time.Since(startTime))
- break
- }
-
- // Wait for state change with remaining timeout
- remaining := maxWait - time.Since(startTime)
- if remaining <= 0 {
- break
- }
-
- // Use shorter timeout for each WaitForStateChange call
to allow periodic checks
- waitTimeout := remaining
- if waitTimeout > 5*time.Second {
- waitTimeout = 5 * time.Second
- }
-
- stateCtx, stateCancel :=
context.WithTimeout(context.Background(), waitTimeout)
- if conn.WaitForStateChange(stateCtx, currentState) {
- newState := conn.GetState()
- elapsed := time.Since(startTime)
- log.Printf("ForwardEcho: connection state
changed from %v to %v after %v", currentState, newState, elapsed)
- stateChanged = true
- currentState = newState
- lastStateChangeTime = time.Now()
-
- // If READY, we're done
- if newState == connectivity.Ready {
- stateCancel()
- break
- }
-
- // If we're in TRANSIENT_FAILURE, continue
waiting - it may recover
- // gRPC xDS client will retry connection when
endpoints become available
- if newState == connectivity.TransientFailure {
- log.Printf("ForwardEcho: connection in
TRANSIENT_FAILURE, continuing to wait for recovery (remaining: %v)",
maxWait-elapsed)
- }
- } else {
- // Timeout waiting for state change - check if
we should continue
- elapsed := time.Since(startTime)
- if currentState ==
connectivity.TransientFailure {
- // If we've been in TRANSIENT_FAILURE
for a while, continue waiting
- // The connection may recover when
endpoints become available
- if time.Since(lastStateChangeTime) <
10*time.Second {
- log.Printf("ForwardEcho: still
in TRANSIENT_FAILURE after %v, continuing to wait (remaining: %v)", elapsed,
maxWait-elapsed)
- } else {
- log.Printf("ForwardEcho: no
state change after %v, current state: %v (remaining: %v)", elapsed,
currentState, maxWait-elapsed)
- }
- } else {
- log.Printf("ForwardEcho: no state
change after %v, current state: %v (remaining: %v)", elapsed, currentState,
maxWait-elapsed)
- }
- }
- stateCancel()
- }
-
- finalState := conn.GetState()
- log.Printf("ForwardEcho: final connection state: %v
(stateChanged=%v, waited=%v)", finalState, stateChanged, time.Since(startTime))
-
- // If connection is not READY, log a warning but proceed anyway
- // The first RPC call may trigger connection establishment
- if finalState != connectivity.Ready {
- log.Printf("ForwardEcho: WARNING - connection is not
READY (state=%v), but proceeding with RPC calls", finalState)
- }
- }
-
- // Create client and make RPC calls
- client := pb.NewEchoServiceClient(conn)
- output := make([]string, 0, count)
-
- log.Printf("ForwardEcho: sending %d requests...", count)
- errorCount := 0
- firstError := ""
- for i := int32(0); i < count; i++ {
- echoReq := &pb.EchoRequest{
- Message: fmt.Sprintf("Request %d", i+1),
- }
-
- currentState := conn.GetState()
- log.Printf("ForwardEcho: sending request %d (connection state:
%v)...", i+1, currentState)
-
- // Use longer timeout for requests to allow TLS handshake
completion
- // When mTLS is configured, certificate fetching and TLS
handshake may take time
- // Use 30 seconds for all requests to ensure TLS handshake has
enough time
- timeout := 30 * time.Second
-
- reqCtx, reqCancel := context.WithTimeout(context.Background(),
timeout)
- reqStartTime := time.Now()
- resp, err := client.Echo(reqCtx, echoReq)
- duration := time.Since(reqStartTime)
- reqCancel()
-
- // Check connection state after RPC call
- stateAfterRPC := conn.GetState()
- log.Printf("ForwardEcho: request %d completed in %v, connection
state: %v (was %v)", i+1, duration, stateAfterRPC, currentState)
-
- if err != nil {
- log.Printf("ForwardEcho: request %d failed: %v", i+1,
err)
- errorCount++
- if firstError == "" {
- firstError = err.Error()
- }
-
- // Format error similar to grpcurl output
- errMsg := formatGRPCError(err, i, count)
- output = append(output, errMsg)
-
- // Only clear cache if we detect specific TLS/plaintext
mismatch errors.
- // TRANSIENT_FAILURE can occur for many reasons (e.g.,
xDS config updates, endpoint changes),
- // so we should NOT clear cache on every
TRANSIENT_FAILURE.
- // Only clear cache when we detect explicit TLS-related
errors that indicate a mismatch.
- errStr := err.Error()
- isTLSMismatch := false
-
- // Check for specific TLS/plaintext mismatch indicators:
- // - "tls: first record does not look like a TLS
handshake" - client uses TLS but server is plaintext
- // - "authentication handshake failed" with TLS context
- TLS handshake failed
- // - "context deadline exceeded" during authentication
handshake - may indicate TLS handshake timeout
- // (e.g., client using plaintext but server requiring
TLS, or vice versa)
- // - "fetching trusted roots from CertificateProvider
failed" - CertificateProvider not ready yet
- // This is a temporary error that should be retried
after waiting for CertificateProvider to be ready
- // These errors indicate that client and server TLS
configuration are mismatched, or CertificateProvider is not ready
- if strings.Contains(errStr, "tls: first record does not
look like a TLS handshake") ||
- (strings.Contains(errStr, "authentication
handshake failed") && strings.Contains(errStr, "tls:")) ||
- (strings.Contains(errStr, "authentication
handshake failed") && strings.Contains(errStr, "context deadline exceeded")) ||
- strings.Contains(errStr, "fetching trusted
roots from CertificateProvider failed") {
- isTLSMismatch = true
- log.Printf("ForwardEcho: detected TLS/plaintext
mismatch or CertificateProvider not ready error: %v", err)
- }
-
- // When TLS mismatch is detected, immediately clear
cache and force reconnection.
- // This ensures that:
- // 1. If client config changed (plaintext -> TLS), new
connection uses TLS
- // 2. If server config changed (TLS -> plaintext), new
connection uses plaintext
- // 3. Connection behavior is consistent with current
xDS configuration
- // - When only client TLS (DestinationRule
ISTIO_MUTUAL) but server plaintext: connection SHOULD FAIL
- // - When client TLS + server mTLS (PeerAuthentication
STRICT): connection SHOULD SUCCEED
- // - When both plaintext: connection SHOULD SUCCEED
- // By clearing cache and reconnecting, we ensure
connection uses current xDS config.
- if isTLSMismatch {
- // Check if this is a CertificateProvider not
ready error (temporary) vs configuration mismatch (persistent)
- isCertProviderNotReady :=
strings.Contains(errStr, "fetching trusted roots from CertificateProvider
failed")
-
- // Clear cache and force reconnection on every
TLS mismatch detection
- // This ensures we always try to use the latest
xDS configuration
- if isCertProviderNotReady {
- log.Printf("ForwardEcho: WARNING -
CertificateProvider not ready yet: %v", err)
- log.Printf("ForwardEcho: NOTE - This is
a temporary error. CertificateProvider needs time to initialize.")
- log.Printf("ForwardEcho: Clearing
connection cache and waiting for CertificateProvider to be ready...")
- } else {
- log.Printf("ForwardEcho: WARNING -
detected TLS/plaintext mismatch error: %v", err)
- log.Printf("ForwardEcho: NOTE - This
error indicates that client and server TLS configuration are mismatched")
- log.Printf("ForwardEcho: This usually
happens when:")
- log.Printf("ForwardEcho: 1.
DestinationRule with ISTIO_MUTUAL exists but PeerAuthentication with STRICT
does not (client TLS, server plaintext)")
- log.Printf("ForwardEcho: 2.
DestinationRule was deleted but cached connection still uses TLS")
- log.Printf("ForwardEcho: Clearing
connection cache to force reconnection with updated xDS config...")
- }
-
- s.connMutex.Lock()
- if cachedConn, stillExists :=
s.connCache[req.Url]; stillExists && cachedConn != nil && cachedConn.conn !=
nil {
- cachedConn.conn.Close()
- }
- delete(s.connCache, req.Url)
- conn = nil
- s.connMutex.Unlock()
-
- // Wait for xDS config to propagate and be
processed by gRPC xDS client.
- // When CDS/LDS config changes, it takes time
for:
- // 1. Control plane to push new config to gRPC
xDS client
- // 2. gRPC xDS client to process and apply new
config
- // 3. CertificateProvider to be ready and
certificate files to be accessible
- // 4. New connections to use updated config
- // For CertificateProvider not ready errors, we
wait shorter time (3 seconds) as it's usually faster.
- // For configuration mismatch, we wait longer
(10 seconds) to ensure config has propagated.
- // Reduced wait times for faster recovery while
still ensuring reliability.
- if isCertProviderNotReady {
- log.Printf("ForwardEcho: waiting 3
seconds for CertificateProvider to be ready...")
- time.Sleep(3 * time.Second)
- } else {
- log.Printf("ForwardEcho: waiting 10
seconds for xDS config to propagate and CertificateProvider to be ready...")
- time.Sleep(10 * time.Second)
- }
-
- // Recreate connection - this will use current
xDS config
- // When TLS is configured, gRPC xDS client
needs to fetch certificates
- // from CertificateProvider. Use a longer
timeout to allow certificate fetching.
- log.Printf("ForwardEcho: recreating connection
with current xDS config...")
- creds, credErr :=
xdscreds.NewClientCredentials(xdscreds.ClientOptions{
- FallbackCreds:
insecure.NewCredentials(),
- })
- if credErr != nil {
- log.Printf("ForwardEcho: failed to
create xDS client credentials: %v", credErr)
- // Continue to record error
- } else {
- // Wait additional time before dialing
to ensure CertificateProvider is ready
- // Reduced from 3s to 2s for faster
recovery
- log.Printf("ForwardEcho: waiting 2
seconds before dialing to ensure CertificateProvider is ready...")
- time.Sleep(2 * time.Second)
-
- dialCtx, dialCancel :=
context.WithTimeout(context.Background(), 60*time.Second)
- newConn, dialErr :=
grpc.DialContext(dialCtx, req.Url, grpc.WithTransportCredentials(creds))
- dialCancel()
- if dialErr != nil {
- log.Printf("ForwardEcho: failed
to dial %s: %v", req.Url, dialErr)
- // Continue to record error
- } else {
- s.connMutex.Lock()
- s.connCache[req.Url] =
&cachedConnection{
- conn: newConn,
- createdAt: time.Now(),
- }
- conn = newConn
- client =
pb.NewEchoServiceClient(conn)
- s.connMutex.Unlock()
- log.Printf("ForwardEcho:
connection recreated, retrying request %d", i+1)
- // Retry this request with new
connection
- continue
- }
- }
- }
- if i < count-1 {
- waitTime := 2 * time.Second
- log.Printf("ForwardEcho: waiting %v before next
request...", waitTime)
- time.Sleep(waitTime)
- }
- continue
- }
-
- if resp == nil {
- log.Printf("ForwardEcho: request %d failed: response is
nil", i+1)
- output = append(output, fmt.Sprintf("[%d] Error:
response is nil", i))
- continue
- }
-
- log.Printf("ForwardEcho: request %d succeeded: Hostname=%s
ServiceVersion=%s Namespace=%s IP=%s",
- i+1, resp.Hostname, resp.ServiceVersion,
resp.Namespace, resp.Ip)
-
- lineParts := []string{
- fmt.Sprintf("[%d body] Hostname=%s", i, resp.Hostname),
- }
- if resp.ServiceVersion != "" {
- lineParts = append(lineParts,
fmt.Sprintf("ServiceVersion=%s", resp.ServiceVersion))
- }
- if resp.Namespace != "" {
- lineParts = append(lineParts,
fmt.Sprintf("Namespace=%s", resp.Namespace))
- }
- if resp.Ip != "" {
- lineParts = append(lineParts, fmt.Sprintf("IP=%s",
resp.Ip))
- }
- if resp.Cluster != "" {
- lineParts = append(lineParts, fmt.Sprintf("Cluster=%s",
resp.Cluster))
- }
- if resp.ServicePort > 0 {
- lineParts = append(lineParts,
fmt.Sprintf("ServicePort=%d", resp.ServicePort))
- }
-
- output = append(output, strings.Join(lineParts, " "))
-
- // Small delay between successful requests to avoid
overwhelming the server
- if i < count-1 {
- time.Sleep(100 * time.Millisecond)
- }
- }
-
- log.Printf("ForwardEcho: completed %d requests", count)
-
- // If all requests failed, add summary similar to grpcurl
- if errorCount > 0 && errorCount == int(count) && firstError != "" {
- summary := fmt.Sprintf("ERROR:\nCode: Unknown\nMessage: %d/%d
requests had errors; first error: %s", errorCount, count, firstError)
- // Prepend summary to output
- output = append([]string{summary}, output...)
- }
-
- return &pb.ForwardEchoResponse{
- Output: output,
- }, nil
-}
diff --git a/tests/grpc-app/docker/dockerfile.consumer
b/tests/grpc-app/docker/dockerfile.consumer
deleted file mode 100644
index 8c4def20..00000000
--- a/tests/grpc-app/docker/dockerfile.consumer
+++ /dev/null
@@ -1,53 +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.
-
-FROM golang:1.24-alpine AS builder
-
-WORKDIR /build
-
-RUN apk add --no-cache protobuf
-
-COPY go.mod go.sum ./
-RUN go mod download
-
-RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@latest && \
- go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
-
-ENV PATH=$PATH:/go/bin:/root/go/bin
-
-COPY proto/echo.proto ./proto/
-RUN protoc --go_out=. --go_opt=paths=source_relative \
- --go-grpc_out=. --go-grpc_opt=paths=source_relative \
- proto/echo.proto
-
-COPY consumer/ ./consumer/
-
-ARG GOOS=linux
-ARG GOARCH=amd64
-RUN GOOS=${GOOS} GOARCH=${GOARCH} CGO_ENABLED=0 go build -a -ldflags
'-extldflags "-static"' -o /build/grpc-consumer ./consumer/
-
-FROM alpine:latest
-RUN apk update && \
- apk --no-cache add ca-certificates tzdata || \
- (sleep 2 && apk update && apk --no-cache add ca-certificates tzdata)
-WORKDIR /app
-
-COPY --from=builder /build/grpc-consumer /usr/local/bin/grpc-consumer
-RUN chmod +x /usr/local/bin/grpc-consumer
-
-COPY ./grpcurl /usr/local/bin/grpcurl
-RUN chmod +x /usr/local/bin/grpcurl
-
-ENTRYPOINT ["/usr/local/bin/grpc-consumer"]
diff --git a/tests/grpc-app/docker/dockerfile.provider
b/tests/grpc-app/docker/dockerfile.provider
deleted file mode 100644
index 58945080..00000000
--- a/tests/grpc-app/docker/dockerfile.provider
+++ /dev/null
@@ -1,50 +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.
-
-FROM golang:1.24-alpine AS builder
-
-WORKDIR /build
-
-RUN apk add --no-cache protobuf
-
-COPY go.mod go.sum ./
-RUN go mod download
-
-RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@latest && \
- go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
-
-ENV PATH=$PATH:/go/bin:/root/go/bin
-
-COPY proto/echo.proto ./proto/
-RUN protoc --go_out=. --go_opt=paths=source_relative \
- --go-grpc_out=. --go-grpc_opt=paths=source_relative \
- proto/echo.proto
-
-COPY provider/ ./provider/
-
-ARG GOOS=linux
-ARG GOARCH=amd64
-RUN GOOS=${GOOS} GOARCH=${GOARCH} CGO_ENABLED=0 go build -a -ldflags
'-extldflags "-static"' -o /build/grpc-provider ./provider/
-
-FROM alpine:latest
-RUN apk update && \
- apk --no-cache add ca-certificates tzdata || \
- (sleep 2 && apk update && apk --no-cache add ca-certificates tzdata)
-WORKDIR /app
-
-COPY --from=builder /build/grpc-provider /usr/local/bin/grpc-provider
-RUN chmod +x /usr/local/bin/grpc-provider
-
-ENTRYPOINT ["/usr/local/bin/grpc-provider"]
diff --git a/tests/grpc-app/generate-proto.sh b/tests/grpc-app/generate-proto.sh
deleted file mode 100755
index 1657f6da..00000000
--- a/tests/grpc-app/generate-proto.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/bash
-# 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.
-
-set -e
-cd "$(dirname "$0")"
-
-# This script will be used when protoc is fixed
-# For now, proto files are generated in Dockerfile
-echo "Proto files are generated in Dockerfile during build"
-echo "To generate locally, fix protoc first:"
-echo " brew reinstall protobuf abseil"
-echo ""
-echo "Then run:"
-echo " protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=.
--go-grpc_opt=paths=source_relative proto/echo.proto"
diff --git a/tests/grpc-app/go.mod b/tests/grpc-app/go.mod
deleted file mode 100644
index b14c730f..00000000
--- a/tests/grpc-app/go.mod
+++ /dev/null
@@ -1,44 +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.
-
-module github.com/apache/dubbo-kubernetes/tests/grpc-app
-
-go 1.24.0
-
-require (
- google.golang.org/grpc v1.76.0
- google.golang.org/protobuf v1.36.10
-)
-
-require (
- cel.dev/expr v0.24.0 // indirect
- cloud.google.com/go/compute/metadata v0.7.0 // indirect
- github.com/cespare/xxhash/v2 v2.3.0 // indirect
- github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect
- github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
- github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
- github.com/go-jose/go-jose/v4 v4.1.2 // indirect
- github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10
// indirect
- github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect
- github.com/zeebo/errs v1.4.0 // indirect
- golang.org/x/crypto v0.43.0 // indirect
- golang.org/x/net v0.46.0 // indirect
- golang.org/x/oauth2 v0.30.0 // indirect
- golang.org/x/sync v0.17.0 // indirect
- golang.org/x/sys v0.37.0 // indirect
- golang.org/x/text v0.30.0 // indirect
- google.golang.org/genproto/googleapis/api
v0.0.0-20250804133106-a7a43d27e69b // indirect
- google.golang.org/genproto/googleapis/rpc
v0.0.0-20251103181224-f26f9409b101 // indirect
-)
diff --git a/tests/grpc-app/go.sum b/tests/grpc-app/go.sum
deleted file mode 100644
index a0ddf76c..00000000
--- a/tests/grpc-app/go.sum
+++ /dev/null
@@ -1,76 +0,0 @@
-cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
-cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
-cloud.google.com/go/compute/metadata v0.7.0
h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
-cloud.google.com/go/compute/metadata v0.7.0/go.mod
h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
-github.com/cespare/xxhash/v2 v2.3.0
h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
-github.com/cespare/xxhash/v2 v2.3.0/go.mod
h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443
h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls=
-github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod
h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
-github.com/davecgh/go-spew v1.1.1
h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/envoyproxy/go-control-plane v0.13.4
h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M=
-github.com/envoyproxy/go-control-plane v0.13.4/go.mod
h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA=
-github.com/envoyproxy/go-control-plane/envoy v1.32.4
h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A=
-github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod
h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw=
-github.com/envoyproxy/go-control-plane/ratelimit v0.1.0
h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI=
-github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod
h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=
-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=
-github.com/go-jose/go-jose/v4 v4.1.2
h1:TK/7NqRQZfgAh+Td8AlsrvtPoUyiHh0LqVvokh+1vHI=
-github.com/go-jose/go-jose/v4 v4.1.2/go.mod
h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo=
-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=
-github.com/go-logr/stdr v1.2.2/go.mod
h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
-github.com/golang/protobuf v1.5.4
h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
-github.com/golang/protobuf v1.5.4/go.mod
h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
-github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
-github.com/google/go-cmp v0.7.0/go.mod
h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
-github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
-github.com/google/uuid v1.6.0/go.mod
h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10
h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
-github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod
h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
-github.com/pmezard/go-difflib v1.0.0
h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/spiffe/go-spiffe/v2 v2.5.0
h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE=
-github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod
h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g=
-github.com/stretchr/testify v1.10.0
h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
-github.com/stretchr/testify v1.10.0/go.mod
h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM=
-github.com/zeebo/errs v1.4.0/go.mod
h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
-go.opentelemetry.io/auto/sdk v1.1.0
h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
-go.opentelemetry.io/auto/sdk v1.1.0/go.mod
h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
-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/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=
-go.opentelemetry.io/otel/sdk v1.37.0/go.mod
h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
-go.opentelemetry.io/otel/sdk/metric v1.37.0
h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
-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=
-golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
-golang.org/x/crypto v0.43.0/go.mod
h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
-golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
-golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
-golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
-golang.org/x/oauth2 v0.30.0/go.mod
h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
-golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
-golang.org/x/sync v0.17.0/go.mod
h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
-golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
-golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
-golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
-golang.org/x/text v0.30.0/go.mod
h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
-gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
-gonum.org/v1/gonum v0.16.0/go.mod
h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
-google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b
h1:ULiyYQ0FdsJhwwZUwbaXpZF5yUE3h+RA+gxvBu37ucc=
-google.golang.org/genproto/googleapis/api
v0.0.0-20250804133106-a7a43d27e69b/go.mod
h1:oDOGiMSXHL4sDTJvFvIB9nRQCGdLP1o/iVaqQK8zB+M=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101
h1:tRPGkdGHuewF4UisLzzHHr1spKw92qLM98nIzxbC0wY=
-google.golang.org/genproto/googleapis/rpc
v0.0.0-20251103181224-f26f9409b101/go.mod
h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
-google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
-google.golang.org/grpc v1.76.0/go.mod
h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
-google.golang.org/protobuf v1.36.10
h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
-google.golang.org/protobuf v1.36.10/go.mod
h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/tests/grpc-app/proto/echo.proto b/tests/grpc-app/proto/echo.proto
deleted file mode 100644
index 1d7c32e6..00000000
--- a/tests/grpc-app/proto/echo.proto
+++ /dev/null
@@ -1,62 +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.
-
-syntax = "proto3";
-
-package echo;
-
-option go_package = "github.com/apache/dubbo-kubernetes/tests/grpc-app/proto";
-
-// Echo service for testing gRPC proxyless
-service EchoService {
- // Echo returns the same message sent
- rpc Echo(EchoRequest) returns (EchoResponse);
-
- // StreamEcho streams back the same message
- rpc StreamEcho(EchoRequest) returns (stream EchoResponse);
-}
-
-// EchoTestService for grpcurl testing (similar to Istio's echo service)
-service EchoTestService {
- // ForwardEcho forwards a request to another service and returns the response
- rpc ForwardEcho(ForwardEchoRequest) returns (ForwardEchoResponse);
-}
-
-message EchoRequest {
- string message = 1;
-}
-
-message EchoResponse {
- string message = 1;
- string hostname = 2;
- string service_version = 3;
- string namespace = 4;
- string ip = 5;
- string cluster = 6;
- int32 service_port = 7;
-}
-
-message ForwardEchoRequest {
- string url = 1; // Target URL (e.g.,
"xds:///consumer.grpc-app.svc.cluster.local:7070")
- int32 count = 2; // Number of requests to send
- map<string, string> headers = 3;
- int32 timeout = 4; // Timeout in seconds
- bool h2 = 5; // Use HTTP/2
- bool insecure = 6; // Use insecure connection
-}
-
-message ForwardEchoResponse {
- repeated string output = 1; // Output lines from the requests
-}
diff --git a/tests/grpc-app/proto/gen.sh b/tests/grpc-app/proto/gen.sh
deleted file mode 100755
index fc0bea40..00000000
--- a/tests/grpc-app/proto/gen.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-set -e
-cd "$(dirname "$0")/.."
-export PATH=$PATH:$(go env GOPATH)/bin
-protoc --go_out=. --go_opt=paths=source_relative \
- --go-grpc_out=. --go-grpc_opt=paths=source_relative \
- proto/echo.proto
diff --git a/tests/grpc-app/provider/main.go b/tests/grpc-app/provider/main.go
deleted file mode 100644
index c3d222b8..00000000
--- a/tests/grpc-app/provider/main.go
+++ /dev/null
@@ -1,404 +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.
-
-package main
-
-import (
- "context"
- "flag"
- "fmt"
- "log"
- "net"
- "os"
- "os/signal"
- "regexp"
- "strconv"
- "strings"
- "syscall"
- "time"
-
- "google.golang.org/grpc"
- "google.golang.org/grpc/credentials/insecure"
- xdscreds "google.golang.org/grpc/credentials/xds"
- "google.golang.org/grpc/grpclog"
- "google.golang.org/grpc/reflection"
- "google.golang.org/grpc/xds"
-
- pb "github.com/apache/dubbo-kubernetes/tests/grpc-app/proto"
-)
-
-var (
- port = flag.Int("port", 17070, "gRPC server port")
-)
-
-type echoServer struct {
- pb.UnimplementedEchoServiceServer
- pb.UnimplementedEchoTestServiceServer
- hostname string
- serviceVersion string
- namespace string
- instanceIP string
- cluster string
- servicePort int
-}
-
-func (s *echoServer) Echo(ctx context.Context, req *pb.EchoRequest)
(*pb.EchoResponse, error) {
- if req == nil {
- return nil, fmt.Errorf("request is nil")
- }
- log.Printf("Received: %v", req.Message)
- return &pb.EchoResponse{
- Message: req.Message,
- Hostname: s.hostname,
- ServiceVersion: s.serviceVersion,
- Namespace: s.namespace,
- Ip: s.instanceIP,
- Cluster: s.cluster,
- ServicePort: int32(s.servicePort),
- }, nil
-}
-
-func (s *echoServer) StreamEcho(req *pb.EchoRequest, stream
pb.EchoService_StreamEchoServer) error {
- if req == nil {
- return fmt.Errorf("request is nil")
- }
- if stream == nil {
- return fmt.Errorf("stream is nil")
- }
- log.Printf("StreamEcho received: %v", req.Message)
- for i := 0; i < 3; i++ {
- if err := stream.Send(&pb.EchoResponse{
- Message: fmt.Sprintf("%s [%d]", req.Message, i),
- Hostname: s.hostname,
- }); err != nil {
- log.Printf("StreamEcho send error: %v", err)
- return err
- }
- }
- return nil
-}
-
-func (s *echoServer) ForwardEcho(ctx context.Context, req
*pb.ForwardEchoRequest) (*pb.ForwardEchoResponse, error) {
- if req == nil {
- return nil, fmt.Errorf("request is nil")
- }
-
- count := req.Count
- if count < 0 {
- count = 0
- }
- if count > 100 {
- count = 100
- }
-
- log.Printf("ForwardEcho called: url=%s, count=%d", req.Url, count)
-
- output := make([]string, 0, count)
- for i := int32(0); i < count; i++ {
- line := fmt.Sprintf("[%d body] Hostname=%s ServiceVersion=%s
ServicePort=%d Namespace=%s",
- i, s.hostname, s.serviceVersion, s.servicePort,
s.namespace)
- if s.instanceIP != "" {
- line += fmt.Sprintf(" IP=%s", s.instanceIP)
- }
- if s.cluster != "" {
- line += fmt.Sprintf(" Cluster=%s", s.cluster)
- }
- output = append(output, line)
- }
-
- return &pb.ForwardEchoResponse{
- Output: output,
- }, nil
-}
-
-// grpcLogger filters out xDS informational logs that are incorrectly marked
as ERROR
-type grpcLogger struct {
- logger *log.Logger
-}
-
-var (
- // Regex to match gRPC formatting errors like %!p(...)
- formatErrorRegex = regexp.MustCompile(`%!p\([^)]+\)`)
-)
-
-// cleanMessage removes formatting errors from gRPC logs
-// Fixes issues like:
"\u003c%!p(networktype.keyType=grpc.internal.transport.networktype)\u003e":
"unix"
-func cleanMessage(msg string) string {
- // Replace %!p(...) patterns with a cleaner representation
- msg = formatErrorRegex.ReplaceAllStringFunc(msg, func(match string)
string {
- // Extract the key from %!p(networktype.keyType=...)
- if strings.Contains(match, "networktype.keyType") {
- return `"networktype"`
- }
- // For other cases, just remove the error pattern
- return ""
- })
- // Also clean up Unicode escape sequences that appear with formatting
errors
- // Replace \u003c (which is <) and \u003e (which is >) when they appear
with formatting errors
- msg = strings.ReplaceAll(msg, `\u003c`, "<")
- msg = strings.ReplaceAll(msg, `\u003e`, ">")
- // Clean up patterns like <...>: "unix" to just show the value
- msg = regexp.MustCompile(`<[^>]*>:\s*"unix"`).ReplaceAllString(msg,
`"networktype": "unix"`)
- return msg
-}
-
-func (l *grpcLogger) Info(args ...interface{}) {
- msg := fmt.Sprint(args...)
- // Filter out xDS "entering mode: SERVING" logs
- if strings.Contains(msg, "entering mode") && strings.Contains(msg,
"SERVING") {
- return
- }
- msg = cleanMessage(msg)
- l.logger.Print("INFO: ", msg)
-}
-
-func (l *grpcLogger) Infoln(args ...interface{}) {
- msg := fmt.Sprintln(args...)
- if strings.Contains(msg, "entering mode") && strings.Contains(msg,
"SERVING") {
- return
- }
- msg = cleanMessage(msg)
- l.logger.Print("INFO: ", msg)
-}
-
-func (l *grpcLogger) Infof(format string, args ...interface{}) {
- msg := fmt.Sprintf(format, args...)
- if strings.Contains(msg, "entering mode") && strings.Contains(msg,
"SERVING") {
- return
- }
- msg = cleanMessage(msg)
- l.logger.Printf("INFO: %s", msg)
-}
-
-func (l *grpcLogger) Warning(args ...interface{}) {
- msg := cleanMessage(fmt.Sprint(args...))
- l.logger.Print("WARNING: ", msg)
-}
-
-func (l *grpcLogger) Warningln(args ...interface{}) {
- msg := cleanMessage(fmt.Sprintln(args...))
- l.logger.Print("WARNING: ", msg)
-}
-
-func (l *grpcLogger) Warningf(format string, args ...interface{}) {
- msg := cleanMessage(fmt.Sprintf(format, args...))
- l.logger.Printf("WARNING: %s", msg)
-}
-
-func (l *grpcLogger) Error(args ...interface{}) {
- msg := fmt.Sprint(args...)
- // Filter out xDS "entering mode: SERVING" logs that are incorrectly
marked as ERROR
- if strings.Contains(msg, "entering mode") && strings.Contains(msg,
"SERVING") {
- return
- }
- // Filter out common connection reset errors - these are normal network
behavior
- // when clients disconnect before completing the HTTP/2 handshake
- if strings.Contains(msg, "connection reset by peer") ||
- strings.Contains(msg, "failed to receive the preface from
client") ||
- strings.Contains(msg, "connection error") {
- // These are normal network events, log at DEBUG level instead
of ERROR
- return
- }
- msg = cleanMessage(msg)
- l.logger.Print("ERROR: ", msg)
-}
-
-func (l *grpcLogger) Errorln(args ...interface{}) {
- msg := fmt.Sprintln(args...)
- if strings.Contains(msg, "entering mode") && strings.Contains(msg,
"SERVING") {
- return
- }
- // Filter out common connection reset errors - these are normal network
behavior
- if strings.Contains(msg, "connection reset by peer") ||
- strings.Contains(msg, "failed to receive the preface from
client") ||
- strings.Contains(msg, "connection error") {
- return
- }
- msg = cleanMessage(msg)
- l.logger.Print("ERROR: ", msg)
-}
-
-func (l *grpcLogger) Errorf(format string, args ...interface{}) {
- msg := fmt.Sprintf(format, args...)
- if strings.Contains(msg, "entering mode") && strings.Contains(msg,
"SERVING") {
- return
- }
- // Filter out common connection reset errors - these are normal network
behavior
- if strings.Contains(msg, "connection reset by peer") ||
- strings.Contains(msg, "failed to receive the preface from
client") ||
- strings.Contains(msg, "connection error") {
- return
- }
- msg = cleanMessage(msg)
- l.logger.Printf("ERROR: %s", msg)
-}
-
-func (l *grpcLogger) Fatal(args ...interface{}) {
- l.logger.Fatal(args...)
-}
-
-func (l *grpcLogger) Fatalln(args ...interface{}) {
- l.logger.Fatal(args...)
-}
-
-func (l *grpcLogger) Fatalf(format string, args ...interface{}) {
- l.logger.Fatalf(format, args...)
-}
-
-func (l *grpcLogger) V(level int) bool {
- return level <= 0
-}
-
-// waitForBootstrapFile waits for the grpc-bootstrap.json file to exist
-// This is necessary because the dubbo-proxy sidecar needs time to generate
the file
-func waitForBootstrapFile(bootstrapPath string, maxWait time.Duration) error {
- log.Printf("Waiting for bootstrap file to exist: %s (max wait: %v)",
bootstrapPath, maxWait)
-
- ctx, cancel := context.WithTimeout(context.Background(), maxWait)
- defer cancel()
-
- ticker := time.NewTicker(500 * time.Millisecond)
- defer ticker.Stop()
-
- startTime := time.Now()
- for {
- // Check if file exists and is not empty
- if info, err := os.Stat(bootstrapPath); err == nil &&
info.Size() > 0 {
- log.Printf("Bootstrap file found after %v: %s",
time.Since(startTime), bootstrapPath)
- return nil
- }
-
- // Check for timeout
- select {
- case <-ctx.Done():
- return fmt.Errorf("timeout waiting for bootstrap file:
%s (waited %v)", bootstrapPath, time.Since(startTime))
- case <-ticker.C:
- // Continue waiting
- }
- }
-}
-
-func firstNonEmpty(values ...string) string {
- for _, v := range values {
- if strings.TrimSpace(v) != "" {
- return v
- }
- }
- return ""
-}
-
-func main() {
- flag.Parse()
-
- // Set custom gRPC logger to filter out xDS informational logs
- // The "ERROR: [xds] Listener entering mode: SERVING" is actually an
informational log
- grpclog.SetLoggerV2(&grpcLogger{
- logger: log.New(os.Stderr, "", log.LstdFlags),
- })
-
- hostname, _ := os.Hostname()
- if hostname == "" {
- hostname = "unknown"
- }
-
- namespace := firstNonEmpty(os.Getenv("SERVICE_NAMESPACE"),
os.Getenv("POD_NAMESPACE"), "default")
- serviceVersion := firstNonEmpty(
- os.Getenv("SERVICE_VERSION"),
- os.Getenv("POD_VERSION"),
- os.Getenv("VERSION"),
- )
- if serviceVersion == "" {
- serviceVersion = "unknown"
- }
- cluster := os.Getenv("SERVICE_CLUSTER")
- instanceIP := os.Getenv("INSTANCE_IP")
- servicePort := *port
- if sp := os.Getenv("SERVICE_PORT"); sp != "" {
- if parsed, err := strconv.Atoi(sp); err == nil {
- servicePort = parsed
- }
- }
-
- // Get bootstrap file path from environment variable or use default
- bootstrapPath := os.Getenv("GRPC_XDS_BOOTSTRAP")
- if bootstrapPath == "" {
- bootstrapPath = "/etc/dubbo/proxy/grpc-bootstrap.json"
- log.Printf("GRPC_XDS_BOOTSTRAP not set, using default: %s",
bootstrapPath)
- }
-
- // Wait for bootstrap file to exist before creating xDS server
- // The dubbo-proxy sidecar needs time to generate this file
- if err := waitForBootstrapFile(bootstrapPath, 60*time.Second); err !=
nil {
- log.Fatalf("Failed to wait for bootstrap file: %v", err)
- }
-
- // Create xDS-enabled gRPC server
- // For proxyless gRPC, we use xds.NewGRPCServer() instead of
grpc.NewServer()
- // NOTE: FallbackCreds is REQUIRED by gRPC xDS library for initial
connection
- // before xDS configuration is available. However, once xDS configures
TLS,
- // the server will use TLS and will NOT fallback to plaintext if TLS
fails.
- // FallbackCreds is only used when xDS has not yet provided TLS
configuration.
- creds, err := xdscreds.NewServerCredentials(xdscreds.ServerOptions{
- FallbackCreds: insecure.NewCredentials(),
- })
- if err != nil {
- log.Fatalf("Failed to create xDS server credentials: %v", err)
- }
-
- server, err := xds.NewGRPCServer(grpc.Creds(creds))
- if err != nil {
- log.Fatalf("Failed to create xDS gRPC server: %v", err)
- }
-
- es := &echoServer{
- hostname: hostname,
- serviceVersion: serviceVersion,
- namespace: namespace,
- instanceIP: instanceIP,
- cluster: cluster,
- servicePort: servicePort,
- }
- pb.RegisterEchoServiceServer(server, es)
- pb.RegisterEchoTestServiceServer(server, es)
- // Enable reflection API for grpcurl to discover services
- reflection.Register(server)
-
- lis, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", *port))
- if err != nil {
- log.Fatalf("Failed to listen: %v", err)
- }
-
- log.Printf("Starting gRPC proxyless server on port %d (hostname: %s)",
*port, hostname)
-
- go func() {
- sigChan := make(chan os.Signal, 1)
- signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
- <-sigChan
- log.Println("Shutting down server...")
- server.GracefulStop()
- }()
-
- // Serve the gRPC server
- // Note: server.Serve returns when the listener is closed, which is
normal during shutdown
- // Connection reset errors are handled by the gRPC library and logged
separately
- if err := server.Serve(lis); err != nil {
- // Only log as fatal if it's not a normal shutdown (listener
closed)
- if !strings.Contains(err.Error(), "use of closed network
connection") {
- log.Fatalf("Failed to serve: %v", err)
- }
- log.Printf("Server stopped: %v", err)
- }
-}
diff --git a/tests/loadtest/go.mod b/tests/loadtest/go.mod
index a57dda58..281b7481 100644
--- a/tests/loadtest/go.mod
+++ b/tests/loadtest/go.mod
@@ -16,32 +16,3 @@
module github.com/apache/dubbo-kubernetes/test/loadtest
go 1.24.0
-
-require (
- github.com/fatih/color v1.16.0
- google.golang.org/grpc v1.76.0
- google.golang.org/protobuf v1.36.10
-)
-
-require (
- cel.dev/expr v0.24.0 // indirect
- cloud.google.com/go/compute/metadata v0.7.0 // indirect
- github.com/cespare/xxhash/v2 v2.3.0 // indirect
- github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect
- github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
- github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
- github.com/go-jose/go-jose/v4 v4.1.2 // indirect
- github.com/mattn/go-colorable v0.1.13 // indirect
- github.com/mattn/go-isatty v0.0.20 // indirect
- github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10
// indirect
- github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect
- github.com/zeebo/errs v1.4.0 // indirect
- golang.org/x/crypto v0.43.0 // indirect
- golang.org/x/net v0.46.0 // indirect
- golang.org/x/oauth2 v0.30.0 // indirect
- golang.org/x/sync v0.17.0 // indirect
- golang.org/x/sys v0.37.0 // indirect
- golang.org/x/text v0.30.0 // indirect
- google.golang.org/genproto/googleapis/api
v0.0.0-20250804133106-a7a43d27e69b // indirect
- google.golang.org/genproto/googleapis/rpc
v0.0.0-20251103181224-f26f9409b101 // indirect
-)
diff --git a/tests/loadtest/go.sum b/tests/loadtest/go.sum
index 47c916ae..e69de29b 100644
--- a/tests/loadtest/go.sum
+++ b/tests/loadtest/go.sum
@@ -1,85 +0,0 @@
-cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
-cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
-cloud.google.com/go/compute/metadata v0.7.0
h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
-cloud.google.com/go/compute/metadata v0.7.0/go.mod
h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
-github.com/cespare/xxhash/v2 v2.3.0
h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
-github.com/cespare/xxhash/v2 v2.3.0/go.mod
h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443
h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls=
-github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod
h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
-github.com/davecgh/go-spew v1.1.1
h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/envoyproxy/go-control-plane v0.13.4
h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M=
-github.com/envoyproxy/go-control-plane v0.13.4/go.mod
h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA=
-github.com/envoyproxy/go-control-plane/envoy v1.32.4
h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A=
-github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod
h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw=
-github.com/envoyproxy/go-control-plane/ratelimit v0.1.0
h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI=
-github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod
h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=
-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=
-github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
-github.com/fatih/color v1.16.0/go.mod
h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
-github.com/go-jose/go-jose/v4 v4.1.2
h1:TK/7NqRQZfgAh+Td8AlsrvtPoUyiHh0LqVvokh+1vHI=
-github.com/go-jose/go-jose/v4 v4.1.2/go.mod
h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo=
-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=
-github.com/go-logr/stdr v1.2.2/go.mod
h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
-github.com/golang/protobuf v1.5.4
h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
-github.com/golang/protobuf v1.5.4/go.mod
h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
-github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
-github.com/google/go-cmp v0.7.0/go.mod
h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
-github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
-github.com/google/uuid v1.6.0/go.mod
h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/mattn/go-colorable v0.1.13
h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
-github.com/mattn/go-colorable v0.1.13/go.mod
h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
-github.com/mattn/go-isatty v0.0.16/go.mod
h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-isatty v0.0.20
h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
-github.com/mattn/go-isatty v0.0.20/go.mod
h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10
h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
-github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod
h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
-github.com/pmezard/go-difflib v1.0.0
h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/spiffe/go-spiffe/v2 v2.5.0
h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE=
-github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod
h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g=
-github.com/stretchr/testify v1.10.0
h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
-github.com/stretchr/testify v1.10.0/go.mod
h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM=
-github.com/zeebo/errs v1.4.0/go.mod
h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
-go.opentelemetry.io/auto/sdk v1.1.0
h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
-go.opentelemetry.io/auto/sdk v1.1.0/go.mod
h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
-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/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=
-go.opentelemetry.io/otel/sdk v1.37.0/go.mod
h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
-go.opentelemetry.io/otel/sdk/metric v1.37.0
h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
-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=
-golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
-golang.org/x/crypto v0.43.0/go.mod
h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
-golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
-golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
-golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
-golang.org/x/oauth2 v0.30.0/go.mod
h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
-golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
-golang.org/x/sync v0.17.0/go.mod
h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
-golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
-golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
-golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
-golang.org/x/text v0.30.0/go.mod
h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
-gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
-gonum.org/v1/gonum v0.16.0/go.mod
h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
-google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b
h1:ULiyYQ0FdsJhwwZUwbaXpZF5yUE3h+RA+gxvBu37ucc=
-google.golang.org/genproto/googleapis/api
v0.0.0-20250804133106-a7a43d27e69b/go.mod
h1:oDOGiMSXHL4sDTJvFvIB9nRQCGdLP1o/iVaqQK8zB+M=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101
h1:tRPGkdGHuewF4UisLzzHHr1spKw92qLM98nIzxbC0wY=
-google.golang.org/genproto/googleapis/rpc
v0.0.0-20251103181224-f26f9409b101/go.mod
h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
-google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
-google.golang.org/grpc v1.76.0/go.mod
h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
-google.golang.org/protobuf v1.36.10
h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
-google.golang.org/protobuf v1.36.10/go.mod
h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/tools/scripts/run.sh b/tools/scripts/run.sh
new file mode 100755
index 00000000..e6c6d9ab
--- /dev/null
+++ b/tools/scripts/run.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+
+set -e
+
+WD=$(dirname "$0")
+WD=$(cd "$WD"; pwd)
+
+export FOR_BUILD_CONTAINER=1
+# shellcheck disable=SC1090,SC1091
+source "${WD}/setup_env.sh"
+
+
+MOUNT_SOURCE="${MOUNT_SOURCE:-${PWD}}"
+MOUNT_DEST="${MOUNT_DEST:-/work}"
+
+read -ra DOCKER_RUN_OPTIONS <<< "${DOCKER_RUN_OPTIONS:-}"
+
+[[ -t 0 ]] && DOCKER_RUN_OPTIONS+=("-it")
+[[ ${UID} -ne 0 ]] && DOCKER_RUN_OPTIONS+=(-u "${UID}:${DOCKER_GID}")
+
+# $CONTAINER_OPTIONS becomes an empty arg when quoted, so SC2086 is disabled
for the
+# following command only
+# shellcheck disable=SC2086
+"${CONTAINER_CLI}" run \
+ --rm \
+ "${DOCKER_RUN_OPTIONS[@]}" \
+ --init \
+ --sig-proxy=true \
+ --cap-add=SYS_ADMIN \
+ ${DOCKER_SOCKET_MOUNT:--v /var/run/docker.sock:/var/run/docker.sock} \
+ -e DOCKER_HOST=${DOCKER_SOCKET_HOST:-unix:///var/run/docker.sock} \
+ $CONTAINER_OPTIONS \
+ --env-file <(env | grep -v "${ENV_BLOCKLIST:-^$}") \
+ -e IN_BUILD_CONTAINER=1 \
+ -e TZ="${TIMEZONE:-$TZ}" \
+ --mount "type=bind,source=${MOUNT_SOURCE},destination=/work" \
+ --mount "type=volume,source=go,destination=/go" \
+ --mount "type=volume,source=gocache,destination=/gocache" \
+ --mount "type=volume,source=cache,destination=/home/.cache" \
+ --mount "type=volume,source=crates,destination=/home/.cargo/registry" \
+ --mount "type=volume,source=git-crates,destination=/home/.cargo/git" \
+ ${CONDITIONAL_HOST_MOUNTS} \
+ -w "${MOUNT_DEST}" "${IMG}" "$@"
diff --git a/tools/scripts/setup_env.sh b/tools/scripts/setup_env.sh
new file mode 100755
index 00000000..370b4c29
--- /dev/null
+++ b/tools/scripts/setup_env.sh
@@ -0,0 +1,145 @@
+#!/usr/bin/env bash
+# shellcheck disable=SC2034
+
+set -e
+
+#
https://stackoverflow.com/questions/59895/how-can-i-get-the-source-directory-of-a-bash-script-from-within-the-script-itsel
+# Note: the normal way we use in other scripts in Istio do not work when
`source`d, which is why we use this approach
+SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+REPO_ROOT="$(dirname "$(dirname "${SCRIPT_DIR}")")"
+
+LOCAL_ARCH=$(uname -m)
+
+# Pass environment set target architecture to build system
+if [[ ${TARGET_ARCH} ]]; then
+ # Target explicitly set
+ :
+elif [[ ${LOCAL_ARCH} == x86_64 ]]; then
+ TARGET_ARCH=amd64
+elif [[ ${LOCAL_ARCH} == armv8* ]]; then
+ TARGET_ARCH=arm64
+elif [[ ${LOCAL_ARCH} == arm64* ]]; then
+ TARGET_ARCH=arm64
+elif [[ ${LOCAL_ARCH} == aarch64* ]]; then
+ TARGET_ARCH=arm64
+else
+ echo "This system's architecture, ${LOCAL_ARCH}, isn't supported"
+ exit 1
+fi
+
+LOCAL_OS=$(uname)
+
+# Pass environment set target operating-system to build system
+if [[ ${TARGET_OS} ]]; then
+ # Target explicitly set
+ :
+elif [[ $LOCAL_OS == Linux ]]; then
+ TARGET_OS=linux
+ readlink_flags="-f"
+elif [[ $LOCAL_OS == Darwin ]]; then
+ TARGET_OS=darwin
+ readlink_flags=""
+else
+ echo "This system's OS, $LOCAL_OS, isn't supported"
+ exit 1
+fi
+
+TIMEZONE=$(readlink "$readlink_flags" /etc/localtime | sed -e
's/^.*zoneinfo\///')
+
+ENV_BLOCKLIST="${ENV_BLOCKLIST:-^_\|^PATH=\|^GOPATH=\|^GOROOT=\|^SHELL=\|^EDITOR=\|^TMUX=\|^USER=\|^HOME=\|^PWD=\|^TERM=\|^RUBY_\|^GEM_\|^rvm_\|^SSH=\|^TMPDIR=\|^CC=\|^CXX=\|^MAKEFILE_LIST=}"
+
+# Build image to use
+TOOLS_REGISTRY_PROVIDER=${TOOLS_REGISTRY_PROVIDER:-docker.io}
+PROJECT_ID=${PROJECT_ID:-mfordjody}
+if [[ "${IMAGE_VERSION:-}" == "" ]]; then
+ IMAGE_VERSION=master
+fi
+if [[ "${IMAGE_NAME:-}" == "" ]]; then
+ IMAGE_NAME=build-tools
+fi
+
+#TOOLS_REGISTRY_PROVIDER=${TOOLS_REGISTRY_PROVIDER:-gcr.io}
+#PROJECT_ID=${PROJECT_ID:-istio-testing}
+#if [[ "${IMAGE_VERSION:-}" == "" ]]; then
+# IMAGE_VERSION=master-dd350f492cf194be812d6f79d13e450f10b62e94
+#fi
+#if [[ "${IMAGE_NAME:-}" == "" ]]; then
+# IMAGE_NAME=build-tools
+#fi
+
+CONTAINER_CLI="${CONTAINER_CLI:-docker}"
+
+# Try to use the latest cached image we have. Use at your own risk, may have
incompatibly-old versions
+if [[ "${LATEST_CACHED_IMAGE:-}" != "" ]]; then
+ prefix="$(<<<"$IMAGE_VERSION" cut -d- -f1)"
+ query="${TOOLS_REGISTRY_PROVIDER}/${PROJECT_ID}/${IMAGE_NAME}:${prefix}-*"
+ latest="$("${CONTAINER_CLI}" images --filter=reference="${query}" --format
"{{.CreatedAt|json}}~{{.Repository}}:{{.Tag}}~{{.CreatedSince}}" | sort -n -r |
head -n1)"
+ IMG="$(<<<"$latest" cut -d~ -f2)"
+ if [[ "${IMG}" == "" ]]; then
+ echo "Attempted to use LATEST_CACHED_IMAGE, but found no images matching
${query}" >&2
+ exit 1
+ fi
+ echo "Using cached image $IMG, created $(<<<"$latest" cut -d~ -f3)" >&2
+fi
+
+IMG="${IMG:-${TOOLS_REGISTRY_PROVIDER}/${PROJECT_ID}/${IMAGE_NAME}:${IMAGE_VERSION}}"
+
+TARGET_OUT="${TARGET_OUT:-$(pwd)/out/${TARGET_OS}_${TARGET_ARCH}}"
+TARGET_OUT_LINUX="${TARGET_OUT_LINUX:-$(pwd)/out/linux_${TARGET_ARCH}}"
+
+CONTAINER_TARGET_OUT="${CONTAINER_TARGET_OUT:-/work/out/${TARGET_OS}_${TARGET_ARCH}}"
+CONTAINER_TARGET_OUT_LINUX="${CONTAINER_TARGET_OUT_LINUX:-/work/out/linux_${TARGET_ARCH}}"
+
+BUILD_WITH_CONTAINER=0
+
+# LOCAL_OUT should point to architecture where we are currently running versus
the desired.
+# This is used when we need to run a build artifact during tests or later as
part of another
+# target.
+if [[ "${FOR_BUILD_CONTAINER:-0}" -eq "1" ]]; then
+ # Override variables with container specific
+ TARGET_OUT=${CONTAINER_TARGET_OUT}
+ TARGET_OUT_LINUX=${CONTAINER_TARGET_OUT_LINUX}
+ REPO_ROOT=/work
+ LOCAL_OUT="${TARGET_OUT_LINUX}"
+else
+ LOCAL_OUT="${TARGET_OUT}"
+fi
+
+go_os_arch=${LOCAL_OUT##*/}
+# Golang OS/Arch format
+LOCAL_GO_OS=${go_os_arch%_*}
+LOCAL_GO_ARCH=${go_os_arch##*_}
+
+VARS=(
+ CONTAINER_TARGET_OUT
+ CONTAINER_TARGET_OUT_LINUX
+ TARGET_OUT
+ TARGET_OUT_LINUX
+ LOCAL_GO_OS
+ LOCAL_GO_ARCH
+ LOCAL_OUT
+ LOCAL_OS
+ TARGET_OS
+ LOCAL_ARCH
+ TARGET_ARCH
+ TIMEZONE
+ CONTAINER_CLI
+ IMG
+ IMAGE_NAME
+ IMAGE_VERSION
+ REPO_ROOT
+ BUILD_WITH_CONTAINER
+)
+
+# For non container build, we need to write env to file
+if [[ "${1}" == "envfile" ]]; then
+ # ! does a variable-variable https://stackoverflow.com/a/10757531/374797
+ for var in "${VARS[@]}"; do
+ echo "${var}"="${!var}"
+ done
+else
+ for var in "${VARS[@]}"; do
+ # shellcheck disable=SC2163
+ export "${var}"
+ done
+fi