mirror of
https://github.com/alibaba/higress.git
synced 2026-02-26 21:50:53 +08:00
Compare commits
49 Commits
v1.3.1
...
v1.3.4-rc.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d1e09c146 | ||
|
|
87c39d393f | ||
|
|
c97260c4a9 | ||
|
|
5e509e7032 | ||
|
|
c9c7df78a9 | ||
|
|
1e018770e5 | ||
|
|
53ff28c58b | ||
|
|
66f2d8980d | ||
|
|
b1e4cf9492 | ||
|
|
c250e850d5 | ||
|
|
1f7e98cef5 | ||
|
|
4273bf573a | ||
|
|
13f36856cc | ||
|
|
e84f9980a1 | ||
|
|
a2fecd59a1 | ||
|
|
89c72777e1 | ||
|
|
85df257f4e | ||
|
|
659a982496 | ||
|
|
0ae376b320 | ||
|
|
c647ab3a08 | ||
|
|
688247f4f9 | ||
|
|
10f5267b3f | ||
|
|
cec99686a0 | ||
|
|
2d5d9c095b | ||
|
|
4bd4433248 | ||
|
|
4ea85e9a35 | ||
|
|
a140f780d2 | ||
|
|
2548815667 | ||
|
|
e760b4d0ab | ||
|
|
3cc1c7877f | ||
|
|
8039b82699 | ||
|
|
f9a015e45a | ||
|
|
5fbfbe0e4a | ||
|
|
a3339a9b1c | ||
|
|
aa94412af2 | ||
|
|
817925ef39 | ||
|
|
c55a5b9bd9 | ||
|
|
518d8dfa3d | ||
|
|
d2ee6065a0 | ||
|
|
4426f18a84 | ||
|
|
17794cef2a | ||
|
|
a554ee1ceb | ||
|
|
1dbb130539 | ||
|
|
9c1684c941 | ||
|
|
bd4109e1a4 | ||
|
|
967fa3f3d1 | ||
|
|
d57ffce1dc | ||
|
|
a2d97ae98f | ||
|
|
324e0bcf91 |
70
.github/workflows/build-and-test-plugin.yaml
vendored
Normal file
70
.github/workflows/build-and-test-plugin.yaml
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
name: "Build and Test Plugins"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- 'plugins/**'
|
||||
- 'test/**'
|
||||
pull_request:
|
||||
branches: ["*"]
|
||||
paths:
|
||||
- 'plugins/**'
|
||||
- 'test/**'
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.19
|
||||
# There are too many lint errors in current code bases
|
||||
# uncomment when we decide what lint should be addressed or ignored.
|
||||
# - run: make lint
|
||||
|
||||
higress-wasmplugin-test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
# TODO(Xunzhuo): Enable C WASM Filters in CI
|
||||
wasmPluginType: [ GO ]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: "Setup Go"
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.19
|
||||
|
||||
- name: Setup Golang Caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |-
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go
|
||||
|
||||
- name: Setup Submodule Caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |-
|
||||
envoy
|
||||
istio
|
||||
.git/modules
|
||||
key: ${{ runner.os }}-submodules-new-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-submodules-new
|
||||
|
||||
- run: git stash # restore patch
|
||||
|
||||
- name: "Run Ingress WasmPlugins Tests"
|
||||
run: GOPROXY="https://proxy.golang.org,direct" PLUGIN_TYPE=${{ matrix.wasmPluginType }} make higress-wasmplugin-test
|
||||
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [higress-wasmplugin-test]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
42
.github/workflows/build-and-test.yaml
vendored
42
.github/workflows/build-and-test.yaml
vendored
@@ -141,48 +141,8 @@ jobs:
|
||||
- name: "Run Higress E2E Conformance Tests"
|
||||
run: GOPROXY="https://proxy.golang.org,direct" make higress-conformance-test
|
||||
|
||||
higress-wasmplugin-test:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build]
|
||||
strategy:
|
||||
matrix:
|
||||
# TODO(Xunzhuo): Enable C WASM Filters in CI
|
||||
wasmPluginType: [ GO ]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: "Setup Go"
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.19
|
||||
|
||||
- name: Setup Golang Caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |-
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go
|
||||
|
||||
- name: Setup Submodule Caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |-
|
||||
envoy
|
||||
istio
|
||||
.git/modules
|
||||
key: ${{ runner.os }}-submodules-new-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-submodules-new
|
||||
|
||||
- run: git stash # restore patch
|
||||
|
||||
- name: "Run Ingress WasmPlugins Tests"
|
||||
run: GOPROXY="https://proxy.golang.org,direct" PLUGIN_TYPE=${{ matrix.wasmPluginType }} make higress-wasmplugin-test
|
||||
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [higress-conformance-test,gateway-conformance-test,higress-wasmplugin-test]
|
||||
needs: [higress-conformance-test,gateway-conformance-test]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
4
.github/workflows/latest-release.yaml
vendored
4
.github/workflows/latest-release.yaml
vendored
@@ -18,6 +18,8 @@ jobs:
|
||||
tar -zcvf hgctl_latest_linux_arm64.tar.gz out/linux_arm64/
|
||||
tar -zcvf hgctl_latest_darwin_amd64.tar.gz out/darwin_amd64/
|
||||
tar -zcvf hgctl_latest_darwin_arm64.tar.gz out/darwin_arm64/
|
||||
zip -q -r hgctl_latest_windows_amd64.zip out/windows_amd64/
|
||||
zip -q -r hgctl_latest_windows_arm64.zip out/windows_arm64/
|
||||
|
||||
# Ignore the error when we delete the latest release, it might not exist.
|
||||
|
||||
@@ -54,6 +56,8 @@ jobs:
|
||||
hgctl_latest_linux_arm64.tar.gz
|
||||
hgctl_latest_darwin_amd64.tar.gz
|
||||
hgctl_latest_darwin_arm64.tar.gz
|
||||
hgctl_latest_windows_amd64.zip
|
||||
hgctl_latest_windows_arm64.zip
|
||||
body: |
|
||||
This is the "latest" release of **Higress**, which contains the most recent commits from the main branch.
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ header:
|
||||
- 'VERSION'
|
||||
- 'tools/'
|
||||
- 'test/README.md'
|
||||
- 'pkg/cmd/hgctl/testdata/config'
|
||||
- 'cmd/hgctl/config/testdata/config'
|
||||
- 'pkg/cmd/hgctl/manifests'
|
||||
|
||||
comment: on-failure
|
||||
|
||||
14
CODEOWNERS
14
CODEOWNERS
@@ -1,10 +1,10 @@
|
||||
/api @johnlanni
|
||||
/envoy @gengleilei @johnlanni @Lynskylate
|
||||
/api @johnlanni @CH3CHO
|
||||
/envoy @gengleilei @johnlanni
|
||||
/istio @SpecialYang @johnlanni
|
||||
/pkg @SpecialYang @johnlanni @Charlie17Li @Xunzhuo
|
||||
/plugins @johnlanni
|
||||
/registry @NameHaibinZhang @johnlanni
|
||||
/test @Xunzhuo
|
||||
/tools @johnlanni @Xunzhuo
|
||||
/pkg @SpecialYang @johnlanni @CH3CHO @Xunzhuo
|
||||
/plugins @johnlanni @WeixinX
|
||||
/registry @NameHaibinZhang @2456868764 @johnlanni
|
||||
/test @Xunzhuo @2456868764 @CH3CHO
|
||||
/tools @johnlanni @Xunzhuo @2456868764
|
||||
|
||||
|
||||
|
||||
@@ -92,7 +92,8 @@ build-hgctl-multiarch: prebuild $(OUT)
|
||||
GOPROXY=$(GOPROXY) GOOS=linux GOARCH=arm64 LDFLAGS=$(RELEASE_LDFLAGS) tools/hack/gobuild.sh ./out/linux_arm64/ $(HGCTL_BINARIES)
|
||||
GOPROXY=$(GOPROXY) GOOS=darwin GOARCH=amd64 LDFLAGS=$(RELEASE_LDFLAGS) tools/hack/gobuild.sh ./out/darwin_amd64/ $(HGCTL_BINARIES)
|
||||
GOPROXY=$(GOPROXY) GOOS=darwin GOARCH=arm64 LDFLAGS=$(RELEASE_LDFLAGS) tools/hack/gobuild.sh ./out/darwin_arm64/ $(HGCTL_BINARIES)
|
||||
|
||||
GOPROXY=$(GOPROXY) GOOS=windows GOARCH=amd64 LDFLAGS=$(RELEASE_LDFLAGS) tools/hack/gobuild.sh ./out/windows_amd64/ $(HGCTL_BINARIES)
|
||||
GOPROXY=$(GOPROXY) GOOS=windows GOARCH=arm64 LDFLAGS=$(RELEASE_LDFLAGS) tools/hack/gobuild.sh ./out/windows_arm64/ $(HGCTL_BINARIES)
|
||||
# Create targets for OUT_LINUX/binary
|
||||
# There are two use cases here:
|
||||
# * Building all docker images (generally in CI). In this case we want to build everything at once, so they share work
|
||||
@@ -137,11 +138,11 @@ export ENVOY_TAR_PATH:=/home/package/envoy.tar.gz
|
||||
|
||||
external/package/envoy-amd64.tar.gz:
|
||||
# cd external/proxy; BUILD_WITH_CONTAINER=1 make test_release
|
||||
cd external/package; wget "https://github.com/alibaba/higress/releases/download/v1.2.0/envoy-amd64.tar.gz"
|
||||
cd external/package; wget -O envoy-amd64.tar.gz "https://github.com/alibaba/higress/releases/download/v1.3.3/envoy-symbol-amd64.tar.gz"
|
||||
|
||||
external/package/envoy-arm64.tar.gz:
|
||||
# cd external/proxy; BUILD_WITH_CONTAINER=1 make test_release
|
||||
cd external/package; wget "https://github.com/alibaba/higress/releases/download/v1.2.0/envoy-arm64.tar.gz"
|
||||
cd external/package; wget -O envoy-arm64.tar.gz "https://github.com/alibaba/higress/releases/download/v1.3.3/envoy-symbol-arm64.tar.gz"
|
||||
|
||||
build-pilot:
|
||||
cd external/istio; rm -rf out/linux_amd64; GOOS_LOCAL=linux TARGET_OS=linux TARGET_ARCH=amd64 BUILD_WITH_CONTAINER=1 make build-linux
|
||||
@@ -176,8 +177,8 @@ install: pre-install
|
||||
cd helm/higress; helm dependency build
|
||||
helm install higress helm/higress -n higress-system --create-namespace --set 'global.local=true'
|
||||
|
||||
ENVOY_LATEST_IMAGE_TAG ?= sha-34054f8
|
||||
ISTIO_LATEST_IMAGE_TAG ?= sha-34054f8
|
||||
ENVOY_LATEST_IMAGE_TAG ?= sha-87c39d3
|
||||
ISTIO_LATEST_IMAGE_TAG ?= sha-87c39d3
|
||||
|
||||
install-dev: pre-install
|
||||
helm install higress helm/core -n higress-system --create-namespace --set 'controller.tag=$(TAG)' --set 'gateway.replicas=1' --set 'pilot.tag=$(ISTIO_LATEST_IMAGE_TAG)' --set 'gateway.tag=$(ENVOY_LATEST_IMAGE_TAG)' --set 'global.local=true'
|
||||
@@ -257,13 +258,13 @@ delete-cluster: $(tools/kind) ## Delete kind cluster.
|
||||
.PHONY: kube-load-image
|
||||
kube-load-image: $(tools/kind) ## Install the Higress image to a kind cluster using the provided $IMAGE and $TAG.
|
||||
tools/hack/kind-load-image.sh higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/higress $(TAG)
|
||||
tools/hack/docker-pull-image.sh docker.io/alihigress/dubbo-provider-demo 0.0.1
|
||||
tools/hack/docker-pull-image.sh higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/dubbo-provider-demo 0.0.3-x86
|
||||
tools/hack/docker-pull-image.sh docker.io/alihigress/nacos-standlone-rc3 1.0.0-RC3
|
||||
tools/hack/docker-pull-image.sh docker.io/hashicorp/consul 1.16.0
|
||||
tools/hack/docker-pull-image.sh docker.io/charlie1380/eureka-registry-provider v0.3.0
|
||||
tools/hack/docker-pull-image.sh docker.io/bitinit/eureka latest
|
||||
tools/hack/docker-pull-image.sh docker.io/alihigress/httpbin 1.0.2
|
||||
tools/hack/kind-load-image.sh docker.io/alihigress/dubbo-provider-demo 0.0.1
|
||||
tools/hack/kind-load-image.sh higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/dubbo-provider-demo 0.0.3-x86
|
||||
tools/hack/kind-load-image.sh docker.io/alihigress/nacos-standlone-rc3 1.0.0-RC3
|
||||
tools/hack/kind-load-image.sh docker.io/hashicorp/consul 1.16.0
|
||||
tools/hack/kind-load-image.sh docker.io/alihigress/httpbin 1.0.2
|
||||
|
||||
@@ -121,13 +121,7 @@ Higress 是基于阿里内部两年多的 Envoy Gateway 实践沉淀,以开源
|
||||
|
||||
### 联系我们
|
||||
|
||||
- Mailing list: higress@googlegroups.com
|
||||
|
||||
社区交流群:
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
开发者群:
|
||||
|
||||

|
||||
|
||||
@@ -154,6 +154,11 @@ spec:
|
||||
type: array
|
||||
httpPath:
|
||||
type: string
|
||||
paramFromEntireBody:
|
||||
properties:
|
||||
paramType:
|
||||
type: string
|
||||
type: object
|
||||
params:
|
||||
items:
|
||||
properties:
|
||||
|
||||
@@ -200,14 +200,15 @@ func (m *DubboService) GetMethods() []*Method {
|
||||
}
|
||||
|
||||
type Method struct {
|
||||
ServiceMethod string `protobuf:"bytes,1,opt,name=service_method,json=serviceMethod,proto3" json:"service_method,omitempty"`
|
||||
HeadersAttach string `protobuf:"bytes,2,opt,name=headers_attach,json=headersAttach,proto3" json:"headers_attach,omitempty"`
|
||||
HttpPath string `protobuf:"bytes,3,opt,name=http_path,json=httpPath,proto3" json:"http_path,omitempty"`
|
||||
HttpMethods []string `protobuf:"bytes,4,rep,name=http_methods,json=httpMethods,proto3" json:"http_methods,omitempty"`
|
||||
Params []*Param `protobuf:"bytes,5,rep,name=params,proto3" json:"params,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
ServiceMethod string `protobuf:"bytes,1,opt,name=service_method,json=serviceMethod,proto3" json:"service_method,omitempty"`
|
||||
HeadersAttach string `protobuf:"bytes,2,opt,name=headers_attach,json=headersAttach,proto3" json:"headers_attach,omitempty"`
|
||||
HttpPath string `protobuf:"bytes,3,opt,name=http_path,json=httpPath,proto3" json:"http_path,omitempty"`
|
||||
HttpMethods []string `protobuf:"bytes,4,rep,name=http_methods,json=httpMethods,proto3" json:"http_methods,omitempty"`
|
||||
Params []*Param `protobuf:"bytes,5,rep,name=params,proto3" json:"params,omitempty"`
|
||||
ParamFromEntireBody *ParamFromEntireBody `protobuf:"bytes,6,opt,name=paramFromEntireBody,proto3" json:"paramFromEntireBody,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Method) Reset() { *m = Method{} }
|
||||
@@ -278,6 +279,13 @@ func (m *Method) GetParams() []*Param {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Method) GetParamFromEntireBody() *ParamFromEntireBody {
|
||||
if m != nil {
|
||||
return m.ParamFromEntireBody
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Param struct {
|
||||
ParamSource string `protobuf:"bytes,1,opt,name=param_source,json=paramSource,proto3" json:"param_source,omitempty"`
|
||||
ParamKey string `protobuf:"bytes,2,opt,name=param_key,json=paramKey,proto3" json:"param_key,omitempty"`
|
||||
@@ -341,6 +349,53 @@ func (m *Param) GetParamType() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type ParamFromEntireBody struct {
|
||||
ParamType string `protobuf:"bytes,1,opt,name=param_type,json=paramType,proto3" json:"param_type,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ParamFromEntireBody) Reset() { *m = ParamFromEntireBody{} }
|
||||
func (m *ParamFromEntireBody) String() string { return proto.CompactTextString(m) }
|
||||
func (*ParamFromEntireBody) ProtoMessage() {}
|
||||
func (*ParamFromEntireBody) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_dc706c3b890c1c84, []int{4}
|
||||
}
|
||||
func (m *ParamFromEntireBody) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *ParamFromEntireBody) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_ParamFromEntireBody.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *ParamFromEntireBody) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ParamFromEntireBody.Merge(m, src)
|
||||
}
|
||||
func (m *ParamFromEntireBody) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *ParamFromEntireBody) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ParamFromEntireBody.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ParamFromEntireBody proto.InternalMessageInfo
|
||||
|
||||
func (m *ParamFromEntireBody) GetParamType() string {
|
||||
if m != nil {
|
||||
return m.ParamType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type GrpcService struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
@@ -351,7 +406,7 @@ func (m *GrpcService) Reset() { *m = GrpcService{} }
|
||||
func (m *GrpcService) String() string { return proto.CompactTextString(m) }
|
||||
func (*GrpcService) ProtoMessage() {}
|
||||
func (*GrpcService) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_dc706c3b890c1c84, []int{4}
|
||||
return fileDescriptor_dc706c3b890c1c84, []int{5}
|
||||
}
|
||||
func (m *GrpcService) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -385,42 +440,46 @@ func init() {
|
||||
proto.RegisterType((*DubboService)(nil), "higress.networking.v1.DubboService")
|
||||
proto.RegisterType((*Method)(nil), "higress.networking.v1.Method")
|
||||
proto.RegisterType((*Param)(nil), "higress.networking.v1.Param")
|
||||
proto.RegisterType((*ParamFromEntireBody)(nil), "higress.networking.v1.ParamFromEntireBody")
|
||||
proto.RegisterType((*GrpcService)(nil), "higress.networking.v1.GrpcService")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("networking/v1/http_2_rpc.proto", fileDescriptor_dc706c3b890c1c84) }
|
||||
|
||||
var fileDescriptor_dc706c3b890c1c84 = []byte{
|
||||
// 463 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x53, 0xcf, 0x8a, 0xd3, 0x40,
|
||||
0x18, 0x77, 0xba, 0x6d, 0xb7, 0xfb, 0x65, 0xeb, 0x61, 0x40, 0x08, 0x8b, 0xc6, 0x35, 0x7b, 0x70,
|
||||
0x41, 0x49, 0xd8, 0xea, 0x41, 0x14, 0x0f, 0x5b, 0x04, 0x17, 0x44, 0x58, 0xb2, 0x9e, 0xbc, 0x84,
|
||||
0x49, 0x32, 0x66, 0x86, 0x6d, 0x33, 0xc3, 0xcc, 0x34, 0xda, 0xb7, 0xf0, 0x35, 0x7c, 0x13, 0x8f,
|
||||
0x3e, 0x82, 0x14, 0x1f, 0x44, 0x32, 0x93, 0x6e, 0x13, 0xb1, 0xb7, 0xf0, 0xfb, 0x33, 0xdf, 0xef,
|
||||
0xc7, 0xf7, 0x05, 0x82, 0x8a, 0x9a, 0xaf, 0x42, 0xdd, 0xf2, 0xaa, 0x8c, 0xeb, 0x8b, 0x98, 0x19,
|
||||
0x23, 0xd3, 0x59, 0xaa, 0x64, 0x1e, 0x49, 0x25, 0x8c, 0xc0, 0x0f, 0x18, 0x2f, 0x15, 0xd5, 0x3a,
|
||||
0xda, 0xe9, 0xa2, 0xfa, 0xe2, 0xe4, 0x71, 0x29, 0x44, 0xb9, 0xa0, 0x31, 0x91, 0x3c, 0xfe, 0xc2,
|
||||
0xe9, 0xa2, 0x48, 0x33, 0xca, 0x48, 0xcd, 0x85, 0x72, 0xbe, 0xf0, 0x3b, 0x82, 0xc9, 0x95, 0x31,
|
||||
0x72, 0x96, 0xc8, 0x1c, 0xbf, 0x81, 0x51, 0xb1, 0xca, 0x32, 0xe1, 0xa3, 0x53, 0x74, 0xee, 0xcd,
|
||||
0xce, 0xa2, 0xff, 0x3e, 0x1a, 0xbd, 0x6b, 0x34, 0x37, 0x54, 0xd5, 0x3c, 0xa7, 0x57, 0xf7, 0x12,
|
||||
0xe7, 0xc1, 0xaf, 0x60, 0x58, 0x2a, 0x99, 0xfb, 0x03, 0xeb, 0x0d, 0xf7, 0x78, 0xdf, 0x2b, 0x99,
|
||||
0xef, 0xac, 0xd6, 0x31, 0x9f, 0x82, 0x57, 0x50, 0x6d, 0x78, 0x45, 0x0c, 0x17, 0x55, 0xf8, 0x03,
|
||||
0xc1, 0x71, 0x77, 0x04, 0x0e, 0xe0, 0x50, 0xbb, 0x4f, 0x1b, 0xec, 0x68, 0x3e, 0xdc, 0x5c, 0xa2,
|
||||
0x41, 0xb2, 0x05, 0x1b, 0xbe, 0xa6, 0x4a, 0x73, 0x51, 0xd9, 0xe1, 0x77, 0x7c, 0x0b, 0xe2, 0x13,
|
||||
0x18, 0x95, 0x4a, 0xac, 0xa4, 0x7f, 0x70, 0xc7, 0xa2, 0xc4, 0x41, 0xf8, 0x2d, 0x1c, 0x2e, 0xa9,
|
||||
0x61, 0xa2, 0xd0, 0xfe, 0xf0, 0xf4, 0xe0, 0xdc, 0x9b, 0x3d, 0xda, 0x13, 0xfc, 0xa3, 0x55, 0x6d,
|
||||
0x9f, 0x6e, 0x3d, 0xe1, 0x1f, 0x04, 0x63, 0xc7, 0xe0, 0x67, 0x70, 0xbf, 0x0d, 0x94, 0x3a, 0xb6,
|
||||
0x17, 0x76, 0xda, 0x72, 0x3b, 0x31, 0xa3, 0xa4, 0xa0, 0x4a, 0xa7, 0xc4, 0x18, 0x92, 0xb3, 0x4e,
|
||||
0x72, 0x94, 0x4c, 0x5b, 0xee, 0xd2, 0x52, 0xf8, 0x09, 0x1c, 0xd9, 0x7d, 0x4b, 0x62, 0x58, 0xa7,
|
||||
0xc3, 0x20, 0x99, 0x34, 0xf0, 0x35, 0x31, 0x0c, 0x3f, 0x85, 0x63, 0x2b, 0xe9, 0x76, 0xd9, 0xaa,
|
||||
0xbc, 0x86, 0x71, 0x73, 0x35, 0x7e, 0x09, 0x63, 0x49, 0x14, 0x59, 0x6a, 0x7f, 0x64, 0xeb, 0x3e,
|
||||
0xdc, 0x53, 0xf7, 0xba, 0x11, 0x25, 0xad, 0x36, 0xfc, 0x06, 0x23, 0x0b, 0x34, 0x73, 0x2c, 0x94,
|
||||
0x6a, 0xb1, 0x52, 0xff, 0xec, 0xc3, 0xb3, 0xcc, 0x8d, 0x25, 0x9a, 0xcc, 0x4e, 0x78, 0x4b, 0xd7,
|
||||
0xbd, 0xad, 0x4c, 0x2c, 0xfc, 0x81, 0xae, 0xf1, 0x19, 0x80, 0x93, 0x98, 0xb5, 0xa4, 0xbd, 0x5e,
|
||||
0xce, 0xfa, 0x69, 0x2d, 0x69, 0x38, 0x05, 0xaf, 0x73, 0x32, 0xf3, 0xd7, 0x3f, 0x37, 0x01, 0xfa,
|
||||
0xb5, 0x09, 0xd0, 0xef, 0x4d, 0x80, 0x3e, 0x3f, 0x2f, 0xb9, 0x61, 0xab, 0x2c, 0xca, 0xc5, 0x32,
|
||||
0x26, 0x0b, 0x9e, 0x91, 0x8c, 0xc4, 0x6d, 0x1d, 0x7b, 0xf1, 0xbd, 0x7f, 0x26, 0x1b, 0xdb, 0x8b,
|
||||
0x7f, 0xf1, 0x37, 0x00, 0x00, 0xff, 0xff, 0x75, 0x5c, 0x9e, 0x28, 0x4b, 0x03, 0x00, 0x00,
|
||||
// 506 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x93, 0xdf, 0x6e, 0xd3, 0x30,
|
||||
0x14, 0xc6, 0x71, 0xd7, 0x76, 0xdd, 0xc9, 0xca, 0x85, 0x27, 0xa4, 0x68, 0x82, 0x32, 0xb2, 0x0b,
|
||||
0x26, 0x40, 0x89, 0x56, 0xb8, 0x40, 0x43, 0x5c, 0xac, 0xe2, 0xcf, 0x24, 0x84, 0x34, 0x65, 0x5c,
|
||||
0x71, 0x13, 0x39, 0x89, 0x49, 0xac, 0xb5, 0xb1, 0x65, 0xbb, 0x85, 0xbc, 0x05, 0xaf, 0xc1, 0x9b,
|
||||
0xec, 0x92, 0x47, 0x40, 0x7d, 0x12, 0x14, 0x3b, 0x5d, 0x93, 0xa9, 0xdd, 0x5d, 0x74, 0xbe, 0xef,
|
||||
0x77, 0x7c, 0x3e, 0x9f, 0x18, 0x46, 0x05, 0xd5, 0x3f, 0xb9, 0xbc, 0x66, 0x45, 0x16, 0x2c, 0x4e,
|
||||
0x83, 0x5c, 0x6b, 0x11, 0x8d, 0x23, 0x29, 0x12, 0x5f, 0x48, 0xae, 0x39, 0x7e, 0x94, 0xb3, 0x4c,
|
||||
0x52, 0xa5, 0xfc, 0xb5, 0xcf, 0x5f, 0x9c, 0x1e, 0x3e, 0xcd, 0x38, 0xcf, 0xa6, 0x34, 0x20, 0x82,
|
||||
0x05, 0x3f, 0x18, 0x9d, 0xa6, 0x51, 0x4c, 0x73, 0xb2, 0x60, 0x5c, 0x5a, 0xce, 0xfb, 0x8d, 0x60,
|
||||
0x70, 0xa1, 0xb5, 0x18, 0x87, 0x22, 0xc1, 0xef, 0xa0, 0x97, 0xce, 0xe3, 0x98, 0xbb, 0xe8, 0x08,
|
||||
0x9d, 0x38, 0xe3, 0x63, 0x7f, 0x63, 0x53, 0xff, 0x43, 0xe5, 0xb9, 0xa2, 0x72, 0xc1, 0x12, 0x7a,
|
||||
0xf1, 0x20, 0xb4, 0x0c, 0x7e, 0x0b, 0xdd, 0x4c, 0x8a, 0xc4, 0xed, 0x18, 0xd6, 0xdb, 0xc2, 0x7e,
|
||||
0x96, 0x22, 0x59, 0xa3, 0x86, 0x98, 0x0c, 0xc1, 0x49, 0xa9, 0xd2, 0xac, 0x20, 0x9a, 0xf1, 0xc2,
|
||||
0xfb, 0x83, 0x60, 0xbf, 0x79, 0x04, 0x1e, 0xc1, 0xae, 0xb2, 0x9f, 0x66, 0xb0, 0xbd, 0x49, 0x77,
|
||||
0x79, 0x8e, 0x3a, 0xe1, 0xaa, 0x58, 0xe9, 0x0b, 0x2a, 0x15, 0xe3, 0x85, 0x39, 0xfc, 0x56, 0xaf,
|
||||
0x8b, 0xf8, 0x10, 0x7a, 0x99, 0xe4, 0x73, 0xe1, 0xee, 0xdc, 0xaa, 0x28, 0xb4, 0x25, 0xfc, 0x1e,
|
||||
0x76, 0x67, 0x54, 0xe7, 0x3c, 0x55, 0x6e, 0xf7, 0x68, 0xe7, 0xc4, 0x19, 0x3f, 0xd9, 0x32, 0xf8,
|
||||
0x57, 0xe3, 0x5a, 0xb5, 0xae, 0x19, 0xef, 0xa6, 0x03, 0x7d, 0xab, 0xe0, 0x97, 0xf0, 0xb0, 0x1e,
|
||||
0x28, 0xb2, 0x6a, 0x6b, 0xd8, 0x61, 0xad, 0xad, 0xcd, 0x39, 0x25, 0x29, 0x95, 0x2a, 0x22, 0x5a,
|
||||
0x93, 0x24, 0x6f, 0x4c, 0x8e, 0xc2, 0x61, 0xad, 0x9d, 0x1b, 0x09, 0x3f, 0x83, 0x3d, 0xb3, 0x6f,
|
||||
0x41, 0x74, 0xde, 0xc8, 0xd0, 0x09, 0x07, 0x55, 0xf9, 0x92, 0xe8, 0x1c, 0x3f, 0x87, 0x7d, 0x63,
|
||||
0x69, 0x66, 0x59, 0xb9, 0x9c, 0x4a, 0xb1, 0xe7, 0x2a, 0xfc, 0x06, 0xfa, 0x82, 0x48, 0x32, 0x53,
|
||||
0x6e, 0xcf, 0xc4, 0x7d, 0xbc, 0x25, 0xee, 0x65, 0x65, 0x0a, 0x6b, 0x2f, 0x8e, 0xe1, 0xc0, 0x7c,
|
||||
0x7d, 0x92, 0x7c, 0xf6, 0xb1, 0xd0, 0x4c, 0xd2, 0x09, 0x4f, 0x4b, 0xb7, 0x6f, 0x56, 0xfd, 0xe2,
|
||||
0xbe, 0x16, 0x6d, 0xa2, 0xce, 0xb7, 0xa9, 0x99, 0xf7, 0x0b, 0x7a, 0x86, 0xa8, 0xb2, 0x18, 0x3d,
|
||||
0x52, 0x7c, 0x2e, 0xef, 0xec, 0xdc, 0x31, 0xca, 0x95, 0x11, 0xaa, 0x7b, 0xb1, 0xc6, 0x6b, 0x5a,
|
||||
0xb6, 0x36, 0x3f, 0x30, 0xe5, 0x2f, 0xb4, 0xc4, 0xc7, 0x00, 0xd6, 0xa2, 0x4b, 0x41, 0x5b, 0x77,
|
||||
0x67, 0xd1, 0x6f, 0xa5, 0xa0, 0xde, 0x19, 0x1c, 0x6c, 0x98, 0xf5, 0x0e, 0x8b, 0x36, 0xb3, 0x43,
|
||||
0x70, 0x1a, 0xbf, 0xf4, 0xe4, 0xec, 0x66, 0x39, 0x42, 0x7f, 0x97, 0x23, 0xf4, 0x6f, 0x39, 0x42,
|
||||
0xdf, 0x5f, 0x65, 0x4c, 0xe7, 0xf3, 0xd8, 0x4f, 0xf8, 0x2c, 0x20, 0x53, 0x16, 0x93, 0x98, 0x04,
|
||||
0xf5, 0x5d, 0x99, 0x17, 0xd9, 0x7a, 0xd3, 0x71, 0xdf, 0xbc, 0xc8, 0xd7, 0xff, 0x03, 0x00, 0x00,
|
||||
0xff, 0xff, 0x30, 0xef, 0x3d, 0xa9, 0xeb, 0x03, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *Http2Rpc) Marshal() (dAtA []byte, err error) {
|
||||
@@ -587,6 +646,18 @@ func (m *Method) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i -= len(m.XXX_unrecognized)
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
if m.ParamFromEntireBody != nil {
|
||||
{
|
||||
size, err := m.ParamFromEntireBody.MarshalToSizedBuffer(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintHttp_2Rpc(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x32
|
||||
}
|
||||
if len(m.Params) > 0 {
|
||||
for iNdEx := len(m.Params) - 1; iNdEx >= 0; iNdEx-- {
|
||||
{
|
||||
@@ -682,6 +753,40 @@ func (m *Param) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *ParamFromEntireBody) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *ParamFromEntireBody) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *ParamFromEntireBody) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.XXX_unrecognized != nil {
|
||||
i -= len(m.XXX_unrecognized)
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
if len(m.ParamType) > 0 {
|
||||
i -= len(m.ParamType)
|
||||
copy(dAtA[i:], m.ParamType)
|
||||
i = encodeVarintHttp_2Rpc(dAtA, i, uint64(len(m.ParamType)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *GrpcService) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
@@ -819,6 +924,10 @@ func (m *Method) Size() (n int) {
|
||||
n += 1 + l + sovHttp_2Rpc(uint64(l))
|
||||
}
|
||||
}
|
||||
if m.ParamFromEntireBody != nil {
|
||||
l = m.ParamFromEntireBody.Size()
|
||||
n += 1 + l + sovHttp_2Rpc(uint64(l))
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
@@ -849,6 +958,22 @@ func (m *Param) Size() (n int) {
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *ParamFromEntireBody) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.ParamType)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovHttp_2Rpc(uint64(l))
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *GrpcService) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
@@ -1360,6 +1485,42 @@ func (m *Method) Unmarshal(dAtA []byte) error {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 6:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ParamFromEntireBody", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHttp_2Rpc
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthHttp_2Rpc
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthHttp_2Rpc
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if m.ParamFromEntireBody == nil {
|
||||
m.ParamFromEntireBody = &ParamFromEntireBody{}
|
||||
}
|
||||
if err := m.ParamFromEntireBody.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipHttp_2Rpc(dAtA[iNdEx:])
|
||||
@@ -1529,6 +1690,89 @@ func (m *Param) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *ParamFromEntireBody) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHttp_2Rpc
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: ParamFromEntireBody: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: ParamFromEntireBody: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ParamType", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHttp_2Rpc
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthHttp_2Rpc
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthHttp_2Rpc
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.ParamType = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipHttp_2Rpc(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthHttp_2Rpc
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *GrpcService) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
|
||||
@@ -62,6 +62,7 @@ message Method {
|
||||
string http_path = 3 [(google.api.field_behavior) = REQUIRED];
|
||||
repeated string http_methods = 4 [(google.api.field_behavior) = REQUIRED];
|
||||
repeated Param params = 5;
|
||||
ParamFromEntireBody paramFromEntireBody = 6 [(google.api.field_behavior) = OPTIONAL];
|
||||
}
|
||||
|
||||
message Param {
|
||||
@@ -70,5 +71,9 @@ message Param {
|
||||
string param_type = 3 [(google.api.field_behavior) = REQUIRED];
|
||||
}
|
||||
|
||||
message ParamFromEntireBody {
|
||||
string param_type = 1 [(google.api.field_behavior) = REQUIRED];
|
||||
}
|
||||
|
||||
message GrpcService {
|
||||
}
|
||||
|
||||
@@ -99,6 +99,27 @@ func (in *Param) DeepCopyInterface() interface{} {
|
||||
return in.DeepCopy()
|
||||
}
|
||||
|
||||
// DeepCopyInto supports using ParamFromEntireBody within kubernetes types, where deepcopy-gen is used.
|
||||
func (in *ParamFromEntireBody) DeepCopyInto(out *ParamFromEntireBody) {
|
||||
p := proto.Clone(in).(*ParamFromEntireBody)
|
||||
*out = *p
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParamFromEntireBody. Required by controller-gen.
|
||||
func (in *ParamFromEntireBody) DeepCopy() *ParamFromEntireBody {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ParamFromEntireBody)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new ParamFromEntireBody. Required by controller-gen.
|
||||
func (in *ParamFromEntireBody) DeepCopyInterface() interface{} {
|
||||
return in.DeepCopy()
|
||||
}
|
||||
|
||||
// DeepCopyInto supports using GrpcService within kubernetes types, where deepcopy-gen is used.
|
||||
func (in *GrpcService) DeepCopyInto(out *GrpcService) {
|
||||
p := proto.Clone(in).(*GrpcService)
|
||||
|
||||
@@ -61,6 +61,17 @@ func (this *Param) UnmarshalJSON(b []byte) error {
|
||||
return Http_2RpcUnmarshaler.Unmarshal(bytes.NewReader(b), this)
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshaler for ParamFromEntireBody
|
||||
func (this *ParamFromEntireBody) MarshalJSON() ([]byte, error) {
|
||||
str, err := Http_2RpcMarshaler.MarshalToString(this)
|
||||
return []byte(str), err
|
||||
}
|
||||
|
||||
// UnmarshalJSON is a custom unmarshaler for ParamFromEntireBody
|
||||
func (this *ParamFromEntireBody) UnmarshalJSON(b []byte) error {
|
||||
return Http_2RpcUnmarshaler.Unmarshal(bytes.NewReader(b), this)
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshaler for GrpcService
|
||||
func (this *GrpcService) MarshalJSON() ([]byte, error) {
|
||||
str, err := Http_2RpcMarshaler.MarshalToString(this)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package hgctl
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -27,26 +27,61 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
output string
|
||||
podName string
|
||||
podNamespace string
|
||||
BootstrapEnvoyConfigType EnvoyConfigType = "bootstrap"
|
||||
ClusterEnvoyConfigType EnvoyConfigType = "cluster"
|
||||
EndpointEnvoyConfigType EnvoyConfigType = "endpoint"
|
||||
ListenerEnvoyConfigType EnvoyConfigType = "listener"
|
||||
RouteEnvoyConfigType EnvoyConfigType = "route"
|
||||
AllEnvoyConfigType EnvoyConfigType = "all"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultProxyAdminPort = 15000
|
||||
containerName = "envoy"
|
||||
)
|
||||
|
||||
func retrieveConfigDump(args []string, includeEds bool) ([]byte, error) {
|
||||
if len(args) != 0 {
|
||||
podName = args[0]
|
||||
}
|
||||
type EnvoyConfigType string
|
||||
|
||||
type GetEnvoyConfigOptions struct {
|
||||
IncludeEds bool
|
||||
PodName string
|
||||
PodNamespace string
|
||||
BindAddress string
|
||||
Output string
|
||||
EnvoyConfigType EnvoyConfigType
|
||||
}
|
||||
|
||||
func NewDefaultGetEnvoyConfigOptions() *GetEnvoyConfigOptions {
|
||||
return &GetEnvoyConfigOptions{
|
||||
IncludeEds: true,
|
||||
PodName: "",
|
||||
PodNamespace: "higress-system",
|
||||
BindAddress: "localhost",
|
||||
Output: "json",
|
||||
EnvoyConfigType: AllEnvoyConfigType,
|
||||
}
|
||||
}
|
||||
|
||||
func GetEnvoyConfig(config *GetEnvoyConfigOptions) ([]byte, error) {
|
||||
configDump, err := retrieveConfigDump(config.PodName, config.PodNamespace, config.BindAddress, config.IncludeEds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if config.EnvoyConfigType == AllEnvoyConfigType {
|
||||
return configDump, nil
|
||||
}
|
||||
resource, err := getXDSResource(config.EnvoyConfigType, configDump)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return formatGatewayConfig(resource, config.Output)
|
||||
}
|
||||
|
||||
func retrieveConfigDump(podName, podNamespace, bindAddress string, includeEds bool) ([]byte, error) {
|
||||
if podNamespace == "" {
|
||||
return nil, fmt.Errorf("pod namespace is required")
|
||||
}
|
||||
|
||||
if podName == "" || len(args) == 0 {
|
||||
if podName == "" {
|
||||
c, err := kubernetes.NewCLIClient(options.DefaultConfigFlags.ToRawKubeConfigLoader())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build kubernetes client: %w", err)
|
||||
@@ -65,7 +100,7 @@ func retrieveConfigDump(args []string, includeEds bool) ([]byte, error) {
|
||||
fw, err := portForwarder(types.NamespacedName{
|
||||
Namespace: podNamespace,
|
||||
Name: podName,
|
||||
})
|
||||
}, bindAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -82,7 +117,7 @@ func retrieveConfigDump(args []string, includeEds bool) ([]byte, error) {
|
||||
return configDump, nil
|
||||
}
|
||||
|
||||
func portForwarder(nn types.NamespacedName) (kubernetes.PortForwarder, error) {
|
||||
func portForwarder(nn types.NamespacedName, bindAddress string) (kubernetes.PortForwarder, error) {
|
||||
c, err := kubernetes.NewCLIClient(options.DefaultConfigFlags.ToRawKubeConfigLoader())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("build CLI client fail: %w", err)
|
||||
@@ -96,7 +131,7 @@ func portForwarder(nn types.NamespacedName) (kubernetes.PortForwarder, error) {
|
||||
return nil, fmt.Errorf("pod %s is not running", nn)
|
||||
}
|
||||
|
||||
fw, err := kubernetes.NewLocalPortForwarder(c, nn, 0, defaultProxyAdminPort)
|
||||
fw, err := kubernetes.NewLocalPortForwarder(c, nn, 0, defaultProxyAdminPort, bindAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -149,3 +184,53 @@ func configDumpRequest(address string, includeEds bool) ([]byte, error) {
|
||||
|
||||
return io.ReadAll(resp.Body)
|
||||
}
|
||||
|
||||
func getXDSResource(resourceType EnvoyConfigType, configDump []byte) (any, error) {
|
||||
cd := map[string]any{}
|
||||
if err := json.Unmarshal(configDump, &cd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resourceType == AllEnvoyConfigType {
|
||||
return cd, nil
|
||||
}
|
||||
configs := cd["configs"]
|
||||
globalConfigs := configs.([]any)
|
||||
|
||||
switch resourceType {
|
||||
case BootstrapEnvoyConfigType:
|
||||
for _, config := range globalConfigs {
|
||||
if config.(map[string]interface{})["@type"] == "type.googleapis.com/envoy.admin.v3.BootstrapConfigDump" {
|
||||
return config, nil
|
||||
}
|
||||
}
|
||||
case EndpointEnvoyConfigType:
|
||||
for _, config := range globalConfigs {
|
||||
if config.(map[string]interface{})["@type"] == "type.googleapis.com/envoy.admin.v3.EndpointsConfigDump" {
|
||||
return config, nil
|
||||
}
|
||||
}
|
||||
|
||||
case ClusterEnvoyConfigType:
|
||||
for _, config := range globalConfigs {
|
||||
if config.(map[string]interface{})["@type"] == "type.googleapis.com/envoy.admin.v3.ClustersConfigDump" {
|
||||
return config, nil
|
||||
}
|
||||
}
|
||||
case ListenerEnvoyConfigType:
|
||||
for _, config := range globalConfigs {
|
||||
if config.(map[string]interface{})["@type"] == "type.googleapis.com/envoy.admin.v3.ListenersConfigDump" {
|
||||
return config, nil
|
||||
}
|
||||
}
|
||||
case RouteEnvoyConfigType:
|
||||
for _, config := range globalConfigs {
|
||||
if config.(map[string]interface{})["@type"] == "type.googleapis.com/envoy.admin.v3.RoutesConfigDump" {
|
||||
return config, nil
|
||||
}
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown resourceType %s", resourceType)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unknown resourceType %s", resourceType)
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package hgctl
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -38,7 +38,7 @@ type fakePortForwarder struct {
|
||||
}
|
||||
|
||||
func newFakePortForwarder(b []byte) (kubernetes.PortForwarder, error) {
|
||||
p, err := kubernetes.LocalAvailablePort()
|
||||
p, err := kubernetes.LocalAvailablePort("localhost")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -109,7 +109,7 @@ func TestExtractAllConfigDump(t *testing.T) {
|
||||
t.Run(tc.output, func(t *testing.T) {
|
||||
configDump, err := fetchGatewayConfig(fw, true)
|
||||
assert.NoError(t, err)
|
||||
data, err := GetXDSResource(AllEnvoyConfigType, configDump)
|
||||
data, err := getXDSResource(AllEnvoyConfigType, configDump)
|
||||
assert.NoError(t, err)
|
||||
got, err := formatGatewayConfig(data, tc.output)
|
||||
assert.NoError(t, err)
|
||||
@@ -137,7 +137,7 @@ func TestExtractSubResourcesConfigDump(t *testing.T) {
|
||||
cases := []struct {
|
||||
output string
|
||||
expected string
|
||||
resourceType envoyConfigType
|
||||
resourceType EnvoyConfigType
|
||||
}{
|
||||
{
|
||||
output: "json",
|
||||
@@ -192,7 +192,7 @@ func TestExtractSubResourcesConfigDump(t *testing.T) {
|
||||
t.Run(tc.output, func(t *testing.T) {
|
||||
configDump, err := fetchGatewayConfig(fw, false)
|
||||
assert.NoError(t, err)
|
||||
resource, err := GetXDSResource(tc.resourceType, configDump)
|
||||
resource, err := getXDSResource(tc.resourceType, configDump)
|
||||
assert.NoError(t, err)
|
||||
got, err := formatGatewayConfig(resource, tc.output)
|
||||
assert.NoError(t, err)
|
||||
315
envoy/1.20/patches/envoy/20231124-rds-optimize.patch
Normal file
315
envoy/1.20/patches/envoy/20231124-rds-optimize.patch
Normal file
@@ -0,0 +1,315 @@
|
||||
diff -Naur envoy/envoy/router/rds.h envoy-new/envoy/router/rds.h
|
||||
--- envoy/envoy/router/rds.h 2023-11-24 10:52:39.914235488 +0800
|
||||
+++ envoy-new/envoy/router/rds.h 2023-11-24 10:47:36.293873127 +0800
|
||||
@@ -51,12 +51,6 @@
|
||||
virtual void onConfigUpdate() PURE;
|
||||
|
||||
/**
|
||||
- * Validate if the route configuration can be applied to the context of the route config provider.
|
||||
- */
|
||||
- virtual void
|
||||
- validateConfig(const envoy::config::route::v3::RouteConfiguration& config) const PURE;
|
||||
-
|
||||
- /**
|
||||
* Callback used to request an update to the route configuration from the management server.
|
||||
* @param for_domain supplies the domain name that virtual hosts must match on
|
||||
* @param thread_local_dispatcher thread-local dispatcher
|
||||
diff -Naur envoy/envoy/router/route_config_update_receiver.h envoy-new/envoy/router/route_config_update_receiver.h
|
||||
--- envoy/envoy/router/route_config_update_receiver.h 2023-11-24 10:52:39.918235651 +0800
|
||||
+++ envoy-new/envoy/router/route_config_update_receiver.h 2023-11-24 10:47:36.293873127 +0800
|
||||
@@ -27,6 +27,7 @@
|
||||
* @param rc supplies the RouteConfiguration.
|
||||
* @param version_info supplies RouteConfiguration version.
|
||||
* @return bool whether RouteConfiguration has been updated.
|
||||
+ * @throw EnvoyException if the new config can't be applied.
|
||||
*/
|
||||
virtual bool onRdsUpdate(const envoy::config::route::v3::RouteConfiguration& rc,
|
||||
const std::string& version_info) PURE;
|
||||
diff -Naur envoy/source/common/router/rds_impl.cc envoy-new/source/common/router/rds_impl.cc
|
||||
--- envoy/source/common/router/rds_impl.cc 2023-11-24 10:52:40.194246888 +0800
|
||||
+++ envoy-new/source/common/router/rds_impl.cc 2023-11-24 10:47:36.293873127 +0800
|
||||
@@ -122,9 +122,6 @@
|
||||
throw EnvoyException(fmt::format("Unexpected RDS configuration (expecting {}): {}",
|
||||
route_config_name_, route_config.name()));
|
||||
}
|
||||
- if (route_config_provider_opt_.has_value()) {
|
||||
- route_config_provider_opt_.value()->validateConfig(route_config);
|
||||
- }
|
||||
std::unique_ptr<Init::ManagerImpl> noop_init_manager;
|
||||
std::unique_ptr<Cleanup> resume_rds;
|
||||
if (config_update_info_->onRdsUpdate(route_config, version_info)) {
|
||||
@@ -292,12 +289,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
-void RdsRouteConfigProviderImpl::validateConfig(
|
||||
- const envoy::config::route::v3::RouteConfiguration& config) const {
|
||||
- // TODO(lizan): consider cache the config here until onConfigUpdate.
|
||||
- ConfigImpl validation_config(config, optional_http_filters_, factory_context_, validator_, false);
|
||||
-}
|
||||
-
|
||||
// Schedules a VHDS request on the main thread and queues up the callback to use when the VHDS
|
||||
// response has been propagated to the worker thread that was the request origin.
|
||||
void RdsRouteConfigProviderImpl::requestVirtualHostsUpdate(
|
||||
diff -Naur envoy/source/common/router/rds_impl.h envoy-new/source/common/router/rds_impl.h
|
||||
--- envoy/source/common/router/rds_impl.h 2023-11-24 10:52:40.194246888 +0800
|
||||
+++ envoy-new/source/common/router/rds_impl.h 2023-11-24 10:47:36.293873127 +0800
|
||||
@@ -81,7 +81,6 @@
|
||||
}
|
||||
SystemTime lastUpdated() const override { return last_updated_; }
|
||||
void onConfigUpdate() override {}
|
||||
- void validateConfig(const envoy::config::route::v3::RouteConfiguration&) const override {}
|
||||
void requestVirtualHostsUpdate(const std::string&, Event::Dispatcher&,
|
||||
std::weak_ptr<Http::RouteConfigUpdatedCallback>) override {
|
||||
NOT_IMPLEMENTED_GCOVR_EXCL_LINE;
|
||||
@@ -209,7 +208,6 @@
|
||||
void requestVirtualHostsUpdate(
|
||||
const std::string& for_domain, Event::Dispatcher& thread_local_dispatcher,
|
||||
std::weak_ptr<Http::RouteConfigUpdatedCallback> route_config_updated_cb) override;
|
||||
- void validateConfig(const envoy::config::route::v3::RouteConfiguration& config) const override;
|
||||
|
||||
private:
|
||||
struct ThreadLocalConfig : public ThreadLocal::ThreadLocalObject {
|
||||
diff -Naur envoy/source/common/router/route_config_update_receiver_impl.cc envoy-new/source/common/router/route_config_update_receiver_impl.cc
|
||||
--- envoy/source/common/router/route_config_update_receiver_impl.cc 2023-11-24 10:52:40.194246888 +0800
|
||||
+++ envoy-new/source/common/router/route_config_update_receiver_impl.cc 2023-11-24 10:47:36.297873290 +0800
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "source/common/router/route_config_update_receiver_impl.h"
|
||||
|
||||
#include <string>
|
||||
+#include <utility>
|
||||
|
||||
#include "envoy/config/route/v3/route.pb.h"
|
||||
#include "envoy/service/discovery/v3/discovery.pb.h"
|
||||
@@ -14,23 +15,49 @@
|
||||
namespace Envoy {
|
||||
namespace Router {
|
||||
|
||||
+namespace {
|
||||
+
|
||||
+// Resets 'route_config::virtual_hosts' by merging VirtualHost contained in
|
||||
+// 'rds_vhosts' and 'vhds_vhosts'.
|
||||
+void rebuildRouteConfigVirtualHosts(
|
||||
+ const std::map<std::string, envoy::config::route::v3::VirtualHost>& rds_vhosts,
|
||||
+ const std::map<std::string, envoy::config::route::v3::VirtualHost>& vhds_vhosts,
|
||||
+ envoy::config::route::v3::RouteConfiguration& route_config) {
|
||||
+ route_config.clear_virtual_hosts();
|
||||
+ for (const auto& vhost : rds_vhosts) {
|
||||
+ route_config.mutable_virtual_hosts()->Add()->CopyFrom(vhost.second);
|
||||
+ }
|
||||
+ for (const auto& vhost : vhds_vhosts) {
|
||||
+ route_config.mutable_virtual_hosts()->Add()->CopyFrom(vhost.second);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+} // namespace
|
||||
+
|
||||
bool RouteConfigUpdateReceiverImpl::onRdsUpdate(
|
||||
const envoy::config::route::v3::RouteConfiguration& rc, const std::string& version_info) {
|
||||
const uint64_t new_hash = MessageUtil::hash(rc);
|
||||
if (new_hash == last_config_hash_) {
|
||||
return false;
|
||||
}
|
||||
- route_config_proto_ = std::make_unique<envoy::config::route::v3::RouteConfiguration>(rc);
|
||||
- last_config_hash_ = new_hash;
|
||||
const uint64_t new_vhds_config_hash = rc.has_vhds() ? MessageUtil::hash(rc.vhds()) : 0ul;
|
||||
+ std::map<std::string, envoy::config::route::v3::VirtualHost> rds_virtual_hosts;
|
||||
+ for (const auto& vhost : rc.virtual_hosts()) {
|
||||
+ rds_virtual_hosts.emplace(vhost.name(), vhost);
|
||||
+ }
|
||||
+ envoy::config::route::v3::RouteConfiguration new_route_config = rc;
|
||||
+ rebuildRouteConfigVirtualHosts(rds_virtual_hosts, *vhds_virtual_hosts_, new_route_config);
|
||||
+ auto new_config = std::make_shared<ConfigImpl>(
|
||||
+ new_route_config, optional_http_filters_, factory_context_,
|
||||
+ factory_context_.messageValidationContext().dynamicValidationVisitor(), false);
|
||||
+ // If the above validation/validation doesn't raise exception, update the
|
||||
+ // other cached config entries.
|
||||
+ config_ = new_config;
|
||||
+ rds_virtual_hosts_ = std::move(rds_virtual_hosts);
|
||||
+ last_config_hash_ = new_hash;
|
||||
+ *route_config_proto_ = std::move(new_route_config);
|
||||
vhds_configuration_changed_ = new_vhds_config_hash != last_vhds_config_hash_;
|
||||
last_vhds_config_hash_ = new_vhds_config_hash;
|
||||
- initializeRdsVhosts(*route_config_proto_);
|
||||
-
|
||||
- rebuildRouteConfig(rds_virtual_hosts_, *vhds_virtual_hosts_, *route_config_proto_);
|
||||
- config_ = std::make_shared<ConfigImpl>(
|
||||
- *route_config_proto_, optional_http_filters_, factory_context_,
|
||||
- factory_context_.messageValidationContext().dynamicValidationVisitor(), false);
|
||||
|
||||
onUpdateCommon(version_info);
|
||||
return true;
|
||||
@@ -50,8 +77,8 @@
|
||||
auto route_config_after_this_update =
|
||||
std::make_unique<envoy::config::route::v3::RouteConfiguration>();
|
||||
route_config_after_this_update->CopyFrom(*route_config_proto_);
|
||||
- rebuildRouteConfig(rds_virtual_hosts_, *vhosts_after_this_update,
|
||||
- *route_config_after_this_update);
|
||||
+ rebuildRouteConfigVirtualHosts(rds_virtual_hosts_, *vhosts_after_this_update,
|
||||
+ *route_config_after_this_update);
|
||||
|
||||
auto new_config = std::make_shared<ConfigImpl>(
|
||||
*route_config_after_this_update, optional_http_filters_, factory_context_,
|
||||
@@ -73,14 +100,6 @@
|
||||
config_info_.emplace(RouteConfigProvider::ConfigInfo{*route_config_proto_, last_config_version_});
|
||||
}
|
||||
|
||||
-void RouteConfigUpdateReceiverImpl::initializeRdsVhosts(
|
||||
- const envoy::config::route::v3::RouteConfiguration& route_configuration) {
|
||||
- rds_virtual_hosts_.clear();
|
||||
- for (const auto& vhost : route_configuration.virtual_hosts()) {
|
||||
- rds_virtual_hosts_.emplace(vhost.name(), vhost);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
bool RouteConfigUpdateReceiverImpl::removeVhosts(
|
||||
std::map<std::string, envoy::config::route::v3::VirtualHost>& vhosts,
|
||||
const Protobuf::RepeatedPtrField<std::string>& removed_vhost_names) {
|
||||
@@ -110,18 +129,5 @@
|
||||
return vhosts_added;
|
||||
}
|
||||
|
||||
-void RouteConfigUpdateReceiverImpl::rebuildRouteConfig(
|
||||
- const std::map<std::string, envoy::config::route::v3::VirtualHost>& rds_vhosts,
|
||||
- const std::map<std::string, envoy::config::route::v3::VirtualHost>& vhds_vhosts,
|
||||
- envoy::config::route::v3::RouteConfiguration& route_config) {
|
||||
- route_config.clear_virtual_hosts();
|
||||
- for (const auto& vhost : rds_vhosts) {
|
||||
- route_config.mutable_virtual_hosts()->Add()->CopyFrom(vhost.second);
|
||||
- }
|
||||
- for (const auto& vhost : vhds_vhosts) {
|
||||
- route_config.mutable_virtual_hosts()->Add()->CopyFrom(vhost.second);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
} // namespace Router
|
||||
} // namespace Envoy
|
||||
diff -Naur envoy/source/common/router/route_config_update_receiver_impl.h envoy-new/source/common/router/route_config_update_receiver_impl.h
|
||||
--- envoy/source/common/router/route_config_update_receiver_impl.h 2023-11-24 10:52:40.194246888 +0800
|
||||
+++ envoy-new/source/common/router/route_config_update_receiver_impl.h 2023-11-24 10:47:36.297873290 +0800
|
||||
@@ -27,15 +27,10 @@
|
||||
std::make_unique<std::map<std::string, envoy::config::route::v3::VirtualHost>>()),
|
||||
vhds_configuration_changed_(true), optional_http_filters_(optional_http_filters) {}
|
||||
|
||||
- void initializeRdsVhosts(const envoy::config::route::v3::RouteConfiguration& route_configuration);
|
||||
bool removeVhosts(std::map<std::string, envoy::config::route::v3::VirtualHost>& vhosts,
|
||||
const Protobuf::RepeatedPtrField<std::string>& removed_vhost_names);
|
||||
bool updateVhosts(std::map<std::string, envoy::config::route::v3::VirtualHost>& vhosts,
|
||||
const VirtualHostRefVector& added_vhosts);
|
||||
- void rebuildRouteConfig(
|
||||
- const std::map<std::string, envoy::config::route::v3::VirtualHost>& rds_vhosts,
|
||||
- const std::map<std::string, envoy::config::route::v3::VirtualHost>& vhds_vhosts,
|
||||
- envoy::config::route::v3::RouteConfiguration& route_config);
|
||||
bool onDemandFetchFailed(const envoy::service::discovery::v3::Resource& resource) const;
|
||||
void onUpdateCommon(const std::string& version_info);
|
||||
|
||||
diff -Naur envoy/source/server/admin/admin.h envoy-new/source/server/admin/admin.h
|
||||
--- envoy/source/server/admin/admin.h 2023-11-24 10:52:41.358294284 +0800
|
||||
+++ envoy-new/source/server/admin/admin.h 2023-11-24 10:47:36.297873290 +0800
|
||||
@@ -234,7 +234,6 @@
|
||||
absl::optional<ConfigInfo> configInfo() const override { return {}; }
|
||||
SystemTime lastUpdated() const override { return time_source_.systemTime(); }
|
||||
void onConfigUpdate() override {}
|
||||
- void validateConfig(const envoy::config::route::v3::RouteConfiguration&) const override {}
|
||||
void requestVirtualHostsUpdate(const std::string&, Event::Dispatcher&,
|
||||
std::weak_ptr<Http::RouteConfigUpdatedCallback>) override {
|
||||
NOT_IMPLEMENTED_GCOVR_EXCL_LINE;
|
||||
diff -Naur envoy/test/common/router/rds_impl_test.cc envoy-new/test/common/router/rds_impl_test.cc
|
||||
--- envoy/test/common/router/rds_impl_test.cc 2023-11-24 10:52:40.714268062 +0800
|
||||
+++ envoy-new/test/common/router/rds_impl_test.cc 2023-11-24 10:47:36.297873290 +0800
|
||||
@@ -528,34 +528,66 @@
|
||||
rds_callbacks_->onConfigUpdate(decoded_resources.refvec_, response1.version_info());
|
||||
}
|
||||
|
||||
-// Validate behavior when the config is delivered but it fails PGV validation.
|
||||
+// Validates behavior when the config is delivered but it fails PGV validation.
|
||||
+// The invalid config won't affect existing valid config.
|
||||
TEST_F(RdsImplTest, FailureInvalidConfig) {
|
||||
InSequence s;
|
||||
|
||||
setup();
|
||||
+ EXPECT_CALL(init_watcher_, ready());
|
||||
|
||||
- const std::string response1_json = R"EOF(
|
||||
+ const std::string valid_json = R"EOF(
|
||||
{
|
||||
"version_info": "1",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
|
||||
- "name": "INVALID_NAME_FOR_route_config",
|
||||
+ "name": "foo_route_config",
|
||||
"virtual_hosts": null
|
||||
}
|
||||
]
|
||||
}
|
||||
)EOF";
|
||||
+
|
||||
auto response1 =
|
||||
- TestUtility::parseYaml<envoy::service::discovery::v3::DiscoveryResponse>(response1_json);
|
||||
+ TestUtility::parseYaml<envoy::service::discovery::v3::DiscoveryResponse>(valid_json);
|
||||
const auto decoded_resources =
|
||||
TestUtility::decodeResources<envoy::config::route::v3::RouteConfiguration>(response1);
|
||||
+ EXPECT_NO_THROW(
|
||||
+ rds_callbacks_->onConfigUpdate(decoded_resources.refvec_, response1.version_info()));
|
||||
+ // Sadly the RdsRouteConfigSubscription privately inherited from
|
||||
+ // SubscriptionCallbacks, so we has to use reinterpret_cast here.
|
||||
+ RdsRouteConfigSubscription* rds_subscription =
|
||||
+ reinterpret_cast<RdsRouteConfigSubscription*>(rds_callbacks_);
|
||||
+ auto config_impl_pointer = rds_subscription->routeConfigProvider().value()->config();
|
||||
+ // Now send an invalid config update.
|
||||
+ const std::string invalid_json =
|
||||
+ R"EOF(
|
||||
+{
|
||||
+ "version_info": "1",
|
||||
+ "resources": [
|
||||
+ {
|
||||
+ "@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
|
||||
+ "name": "INVALID_NAME_FOR_route_config",
|
||||
+ "virtual_hosts": null
|
||||
+ }
|
||||
+ ]
|
||||
+}
|
||||
+)EOF";
|
||||
+
|
||||
+ auto response2 =
|
||||
+ TestUtility::parseYaml<envoy::service::discovery::v3::DiscoveryResponse>(invalid_json);
|
||||
+ const auto decoded_resources_2 =
|
||||
+ TestUtility::decodeResources<envoy::config::route::v3::RouteConfiguration>(response2);
|
||||
|
||||
- EXPECT_CALL(init_watcher_, ready());
|
||||
EXPECT_THROW_WITH_MESSAGE(
|
||||
- rds_callbacks_->onConfigUpdate(decoded_resources.refvec_, response1.version_info()),
|
||||
+ rds_callbacks_->onConfigUpdate(decoded_resources_2.refvec_, response2.version_info()),
|
||||
EnvoyException,
|
||||
- "Unexpected RDS configuration (expecting foo_route_config): INVALID_NAME_FOR_route_config");
|
||||
+ "Unexpected RDS configuration (expecting foo_route_config): "
|
||||
+ "INVALID_NAME_FOR_route_config");
|
||||
+
|
||||
+ // Verify that the config is still the old value.
|
||||
+ ASSERT_EQ(config_impl_pointer, rds_subscription->routeConfigProvider().value()->config());
|
||||
}
|
||||
|
||||
// rds and vhds configurations change together
|
||||
diff -Naur envoy/test/mocks/router/mocks.h envoy-new/test/mocks/router/mocks.h
|
||||
--- envoy/test/mocks/router/mocks.h 2023-11-24 10:52:41.370294773 +0800
|
||||
+++ envoy-new/test/mocks/router/mocks.h 2023-11-24 10:47:36.301873453 +0800
|
||||
@@ -538,7 +538,6 @@
|
||||
MOCK_METHOD(absl::optional<ConfigInfo>, configInfo, (), (const));
|
||||
MOCK_METHOD(SystemTime, lastUpdated, (), (const));
|
||||
MOCK_METHOD(void, onConfigUpdate, ());
|
||||
- MOCK_METHOD(void, validateConfig, (const envoy::config::route::v3::RouteConfiguration&), (const));
|
||||
MOCK_METHOD(void, requestVirtualHostsUpdate,
|
||||
(const std::string&, Event::Dispatcher&,
|
||||
std::weak_ptr<Http::RouteConfigUpdatedCallback> route_config_updated_cb));
|
||||
diff -Naur envoy/tools/spelling/spelling_dictionary.txt envoy-new/tools/spelling/spelling_dictionary.txt
|
||||
--- envoy/tools/spelling/spelling_dictionary.txt 2023-11-24 10:52:41.370294773 +0800
|
||||
+++ envoy-new/tools/spelling/spelling_dictionary.txt 2023-11-24 10:48:54.969076506 +0800
|
||||
@@ -1303,6 +1303,7 @@
|
||||
ep
|
||||
suri
|
||||
transid
|
||||
+vhosts
|
||||
WAF
|
||||
TRI
|
||||
tmd
|
||||
1502
envoy/1.20/patches/envoy/20231218-dubbo-optimize.patch
Normal file
1502
envoy/1.20/patches/envoy/20231218-dubbo-optimize.patch
Normal file
File diff suppressed because one or more lines are too long
483
envoy/1.20/patches/envoy/20240104-enhance-srds.patch
Normal file
483
envoy/1.20/patches/envoy/20240104-enhance-srds.patch
Normal file
@@ -0,0 +1,483 @@
|
||||
diff -Naur envoy/api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto envoy-new/api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto
|
||||
--- envoy/api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto 2024-01-04 21:07:40.000000000 +0800
|
||||
+++ envoy-new/api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto 2024-01-04 21:09:13.000000000 +0800
|
||||
@@ -888,11 +888,31 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ message HostValueExtractor {
|
||||
+ option (udpa.annotations.versioning).previous_message_type =
|
||||
+ "envoy.config.filter.network.http_connection_manager.v2.ScopedRoutes.ScopeKeyBuilder."
|
||||
+ "FragmentBuilder.HostValueExtractor";
|
||||
+
|
||||
+ // The maximum number of host superset recomputes. If not specified, defaults to 100.
|
||||
+ google.protobuf.UInt32Value max_recompute_num = 1;
|
||||
+ }
|
||||
+
|
||||
+ message LocalPortValueExtractor {
|
||||
+ option (udpa.annotations.versioning).previous_message_type =
|
||||
+ "envoy.config.filter.network.http_connection_manager.v2.ScopedRoutes.ScopeKeyBuilder."
|
||||
+ "FragmentBuilder.LocalPortValueExtractor";
|
||||
+ }
|
||||
+
|
||||
+
|
||||
oneof type {
|
||||
option (validate.required) = true;
|
||||
|
||||
// Specifies how a header field's value should be extracted.
|
||||
HeaderValueExtractor header_value_extractor = 1;
|
||||
+
|
||||
+ HostValueExtractor host_value_extractor = 101;
|
||||
+
|
||||
+ LocalPortValueExtractor local_port_value_extractor = 102;
|
||||
}
|
||||
}
|
||||
|
||||
diff -Naur envoy/envoy/router/scopes.h envoy-new/envoy/router/scopes.h
|
||||
--- envoy/envoy/router/scopes.h 2024-01-04 21:07:38.000000000 +0800
|
||||
+++ envoy-new/envoy/router/scopes.h 2024-01-04 21:09:13.000000000 +0800
|
||||
@@ -92,7 +92,12 @@
|
||||
* @param headers the request headers to match the scoped routing configuration against.
|
||||
* @return ConfigConstSharedPtr the router's Config matching the request headers.
|
||||
*/
|
||||
+#if defined ALIMESH
|
||||
+ virtual ConfigConstSharedPtr getRouteConfig(const Http::HeaderMap& headers,
|
||||
+ const StreamInfo::StreamInfo& info) const PURE;
|
||||
+#else
|
||||
virtual ConfigConstSharedPtr getRouteConfig(const Http::HeaderMap& headers) const PURE;
|
||||
+#endif
|
||||
|
||||
/**
|
||||
* Based on the incoming HTTP request headers, returns the hash value of its scope key.
|
||||
@@ -100,6 +105,12 @@
|
||||
* @return unique_ptr of the scope key computed from header.
|
||||
*/
|
||||
virtual ScopeKeyPtr computeScopeKey(const Http::HeaderMap&) const { return {}; }
|
||||
+
|
||||
+#if defined(ALIMESH)
|
||||
+ virtual ScopeKeyPtr computeScopeKey(const Http::HeaderMap&, const StreamInfo::StreamInfo&) const {
|
||||
+ return {};
|
||||
+ };
|
||||
+#endif
|
||||
};
|
||||
|
||||
using ScopedConfigConstSharedPtr = std::shared_ptr<const ScopedConfig>;
|
||||
diff -Naur envoy/source/common/http/conn_manager_impl.cc envoy-new/source/common/http/conn_manager_impl.cc
|
||||
--- envoy/source/common/http/conn_manager_impl.cc 2024-01-04 21:07:41.000000000 +0800
|
||||
+++ envoy-new/source/common/http/conn_manager_impl.cc 2024-01-04 21:09:13.000000000 +0800
|
||||
@@ -577,8 +577,13 @@
|
||||
requestVhdsUpdate(host_header, thread_local_dispatcher, std::move(route_config_updated_cb));
|
||||
return;
|
||||
} else if (parent_.snapped_scoped_routes_config_ != nullptr) {
|
||||
+#if defined(ALIMESH)
|
||||
+ Router::ScopeKeyPtr scope_key = parent_.snapped_scoped_routes_config_->computeScopeKey(
|
||||
+ *parent_.request_headers_, parent_.connection()->streamInfo());
|
||||
+#else
|
||||
Router::ScopeKeyPtr scope_key =
|
||||
parent_.snapped_scoped_routes_config_->computeScopeKey(*parent_.request_headers_);
|
||||
+#endif
|
||||
// If scope_key is not null, the scope exists but RouteConfiguration is not initialized.
|
||||
if (scope_key != nullptr) {
|
||||
requestSrdsUpdate(std::move(scope_key), thread_local_dispatcher,
|
||||
@@ -1197,7 +1202,13 @@
|
||||
void ConnectionManagerImpl::ActiveStream::snapScopedRouteConfig() {
|
||||
// NOTE: if a RDS subscription hasn't got a RouteConfiguration back, a Router::NullConfigImpl is
|
||||
// returned, in that case we let it pass.
|
||||
+#if defined(ALIMESH)
|
||||
+ snapped_route_config_ =
|
||||
+ snapped_scoped_routes_config_->getRouteConfig(*request_headers_, connection()->streamInfo());
|
||||
+#else
|
||||
snapped_route_config_ = snapped_scoped_routes_config_->getRouteConfig(*request_headers_);
|
||||
+
|
||||
+#endif
|
||||
if (snapped_route_config_ == nullptr) {
|
||||
ENVOY_STREAM_LOG(trace, "can't find SRDS scope.", *this);
|
||||
// TODO(stevenzzzz): Consider to pass an error message to router filter, so that it can
|
||||
diff -Naur envoy/source/common/router/scoped_config_impl.cc envoy-new/source/common/router/scoped_config_impl.cc
|
||||
--- envoy/source/common/router/scoped_config_impl.cc 2024-01-04 21:07:36.000000000 +0800
|
||||
+++ envoy-new/source/common/router/scoped_config_impl.cc 2024-01-04 21:09:13.000000000 +0800
|
||||
@@ -6,6 +6,160 @@
|
||||
namespace Envoy {
|
||||
namespace Router {
|
||||
|
||||
+#if defined(ALIMESH)
|
||||
+namespace {
|
||||
+
|
||||
+std::string maskFirstDNSLabel(absl::string_view host) {
|
||||
+ if (host == "*") {
|
||||
+ return std::string(host);
|
||||
+ }
|
||||
+ if (host.size() < 2) {
|
||||
+ return "*";
|
||||
+ }
|
||||
+ size_t start_pos = (host[0] == '*' && host[1] == '.') ? 2 : 0;
|
||||
+ size_t dot_pos = host.find('.', start_pos);
|
||||
+ if (dot_pos != absl::string_view::npos) {
|
||||
+ return absl::StrCat("*", absl::string_view(host.data() + dot_pos, host.size() - dot_pos));
|
||||
+ }
|
||||
+ return "*";
|
||||
+}
|
||||
+
|
||||
+} // namespace
|
||||
+
|
||||
+LocalPortValueExtractorImpl::LocalPortValueExtractorImpl(
|
||||
+ ScopedRoutes::ScopeKeyBuilder::FragmentBuilder&& config)
|
||||
+ : FragmentBuilderBase(std::move(config)) {
|
||||
+ ASSERT(config_.type_case() ==
|
||||
+ ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::kLocalPortValueExtractor,
|
||||
+ "local_port_value_extractor is not set.");
|
||||
+}
|
||||
+
|
||||
+std::unique_ptr<ScopeKeyFragmentBase> LocalPortValueExtractorImpl::computeFragment(
|
||||
+ const Http::HeaderMap&, const StreamInfo::StreamInfo& info, ReComputeCbPtr&) const {
|
||||
+ auto port = info.downstreamAddressProvider().localAddress()->ip()->port();
|
||||
+ return std::make_unique<StringKeyFragment>(std::to_string(long(port)));
|
||||
+}
|
||||
+
|
||||
+HostValueExtractorImpl::HostValueExtractorImpl(
|
||||
+ ScopedRoutes::ScopeKeyBuilder::FragmentBuilder&& config)
|
||||
+ : FragmentBuilderBase(std::move(config)),
|
||||
+ host_value_extractor_config_(config_.host_value_extractor()),
|
||||
+ max_recompute_num_(PROTOBUF_GET_WRAPPED_OR_DEFAULT(
|
||||
+ host_value_extractor_config_, max_recompute_num, DefaultMaxRecomputeNum)) {
|
||||
+ ASSERT(config_.type_case() == ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::kHostValueExtractor,
|
||||
+ "host_value_extractor is not set.");
|
||||
+}
|
||||
+
|
||||
+std::unique_ptr<ScopeKeyFragmentBase>
|
||||
+HostValueExtractorImpl::reComputeHelper(const std::string& host, ReComputeCbPtr& next_recompute,
|
||||
+ uint32_t recompute_seq) const {
|
||||
+ if (recompute_seq == max_recompute_num_) {
|
||||
+ ENVOY_LOG_MISC(warn,
|
||||
+ "recompute host fragment failed, maximum number of recalculations exceeded");
|
||||
+ return nullptr;
|
||||
+ }
|
||||
+ if (host == "*") {
|
||||
+ *next_recompute = nullptr;
|
||||
+ return nullptr;
|
||||
+ }
|
||||
+ auto masked_host = maskFirstDNSLabel(host);
|
||||
+ *next_recompute = [this, masked_host, recompute_seq,
|
||||
+ next_recompute]() mutable -> std::unique_ptr<ScopeKeyFragmentBase> {
|
||||
+ return reComputeHelper(masked_host, next_recompute, recompute_seq + 1);
|
||||
+ };
|
||||
+ return std::make_unique<StringKeyFragment>(masked_host);
|
||||
+}
|
||||
+
|
||||
+std::unique_ptr<ScopeKeyFragmentBase>
|
||||
+HostValueExtractorImpl::computeFragment(const Http::HeaderMap& headers,
|
||||
+ const StreamInfo::StreamInfo&,
|
||||
+ ReComputeCbPtr& recompute) const {
|
||||
+ auto fragment = computeFragment(headers);
|
||||
+ auto host = static_cast<const Http::RequestHeaderMap&>(headers).getHostValue();
|
||||
+ *recompute = [this, host, recompute]() mutable -> std::unique_ptr<ScopeKeyFragmentBase> {
|
||||
+ return reComputeHelper(std::string(host), recompute, 0);
|
||||
+ };
|
||||
+ return fragment;
|
||||
+}
|
||||
+
|
||||
+std::unique_ptr<ScopeKeyFragmentBase>
|
||||
+HostValueExtractorImpl::computeFragment(const Http::HeaderMap& headers) const {
|
||||
+ return std::make_unique<StringKeyFragment>(
|
||||
+ static_cast<const Http::RequestHeaderMap&>(headers).getHostValue());
|
||||
+}
|
||||
+
|
||||
+std::unique_ptr<ScopeKeyFragmentBase>
|
||||
+HeaderValueExtractorImpl::computeFragment(const Http::HeaderMap& headers,
|
||||
+ const StreamInfo::StreamInfo&, ReComputeCbPtr&) const {
|
||||
+ return computeFragment(headers);
|
||||
+}
|
||||
+
|
||||
+ScopeKeyPtr ScopeKeyBuilderImpl::computeScopeKey(const Http::HeaderMap& headers,
|
||||
+ const StreamInfo::StreamInfo& info,
|
||||
+ std::function<ScopeKeyPtr()>& recompute) const {
|
||||
+ ScopeKey key;
|
||||
+ bool recomputeable = false;
|
||||
+ auto recompute_cbs = std::make_shared<std::vector<ReComputeCbPtr>>();
|
||||
+ for (const auto& builder : fragment_builders_) {
|
||||
+ // returns nullopt if a null fragment is found.
|
||||
+ ReComputeCbPtr recompute_fragment_cb = std::make_shared<ReComputeCb>();
|
||||
+ std::unique_ptr<ScopeKeyFragmentBase> fragment =
|
||||
+ builder->computeFragment(headers, info, recompute_fragment_cb);
|
||||
+ if (fragment == nullptr) {
|
||||
+ return nullptr;
|
||||
+ }
|
||||
+ if (*recompute_fragment_cb == nullptr) {
|
||||
+ auto key_fragment = static_cast<StringKeyFragment*>(fragment.get());
|
||||
+ auto copied_fragment = std::make_shared<StringKeyFragment>(*key_fragment);
|
||||
+ auto recompute_cb =
|
||||
+ std::make_shared<ReComputeCb>([copied_fragment]() -> std::unique_ptr<StringKeyFragment> {
|
||||
+ return std::make_unique<StringKeyFragment>(*copied_fragment);
|
||||
+ });
|
||||
+ recompute_cbs->push_back(recompute_cb);
|
||||
+ } else {
|
||||
+ recomputeable = true;
|
||||
+ recompute_cbs->push_back(recompute_fragment_cb);
|
||||
+ }
|
||||
+ key.addFragment(std::move(fragment));
|
||||
+ }
|
||||
+ if (recomputeable) {
|
||||
+ recompute = [&recompute, recompute_cbs]() mutable -> ScopeKeyPtr {
|
||||
+ ScopeKey new_key;
|
||||
+ for (auto& cb : *recompute_cbs) {
|
||||
+ auto new_fragment = (*cb)();
|
||||
+ if (new_fragment == nullptr) {
|
||||
+ return nullptr;
|
||||
+ }
|
||||
+ if (*cb == nullptr) {
|
||||
+ recompute = nullptr;
|
||||
+ }
|
||||
+ new_key.addFragment(std::move(new_fragment));
|
||||
+ }
|
||||
+ return std::make_unique<ScopeKey>(std::move(new_key));
|
||||
+ };
|
||||
+ }
|
||||
+ return std::make_unique<ScopeKey>(std::move(key));
|
||||
+}
|
||||
+
|
||||
+ScopeKeyPtr ScopedConfigImpl::computeScopeKey(const Http::HeaderMap& headers,
|
||||
+ const StreamInfo::StreamInfo& info) const {
|
||||
+ std::function<Router::ScopeKeyPtr()> recompute;
|
||||
+ ScopeKeyPtr scope_key = scope_key_builder_.computeScopeKey(headers, info, recompute);
|
||||
+ if (scope_key == nullptr) {
|
||||
+ return nullptr;
|
||||
+ }
|
||||
+ decltype(scoped_route_info_by_key_.begin()) iter;
|
||||
+ do {
|
||||
+ iter = scoped_route_info_by_key_.find(scope_key->hash());
|
||||
+ if (iter != scoped_route_info_by_key_.end()) {
|
||||
+ return scope_key;
|
||||
+ }
|
||||
+ } while (recompute != nullptr && (scope_key = recompute()));
|
||||
+ return nullptr;
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
+
|
||||
bool ScopeKey::operator!=(const ScopeKey& other) const { return !(*this == other); }
|
||||
|
||||
bool ScopeKey::operator==(const ScopeKey& other) const {
|
||||
@@ -95,6 +249,16 @@
|
||||
: ScopeKeyBuilderBase(std::move(config)) {
|
||||
for (const auto& fragment_builder : config_.fragments()) {
|
||||
switch (fragment_builder.type_case()) {
|
||||
+#if defined(ALIMESH)
|
||||
+ case ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::kHostValueExtractor:
|
||||
+ fragment_builders_.emplace_back(std::make_unique<HostValueExtractorImpl>(
|
||||
+ ScopedRoutes::ScopeKeyBuilder::FragmentBuilder(fragment_builder)));
|
||||
+ break;
|
||||
+ case ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::kLocalPortValueExtractor:
|
||||
+ fragment_builders_.emplace_back(std::make_unique<LocalPortValueExtractorImpl>(
|
||||
+ ScopedRoutes::ScopeKeyBuilder::FragmentBuilder(fragment_builder)));
|
||||
+ break;
|
||||
+#endif
|
||||
case ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::kHeaderValueExtractor:
|
||||
fragment_builders_.emplace_back(std::make_unique<HeaderValueExtractorImpl>(
|
||||
ScopedRoutes::ScopeKeyBuilder::FragmentBuilder(fragment_builder)));
|
||||
@@ -143,6 +307,22 @@
|
||||
}
|
||||
|
||||
Router::ConfigConstSharedPtr
|
||||
+#if defined(ALIMESH)
|
||||
+ScopedConfigImpl::getRouteConfig(const Http::HeaderMap& headers,
|
||||
+ const StreamInfo::StreamInfo& info) const {
|
||||
+ std::function<ScopeKeyPtr()> recompute;
|
||||
+ ScopeKeyPtr scope_key = scope_key_builder_.computeScopeKey(headers, info, recompute);
|
||||
+ if (scope_key == nullptr) {
|
||||
+ return nullptr;
|
||||
+ }
|
||||
+ decltype(scoped_route_info_by_key_.begin()) iter;
|
||||
+ do {
|
||||
+ iter = scoped_route_info_by_key_.find(scope_key->hash());
|
||||
+ if (iter != scoped_route_info_by_key_.end()) {
|
||||
+ return iter->second->routeConfig();
|
||||
+ }
|
||||
+ } while (recompute != nullptr && (scope_key = recompute()));
|
||||
+#else
|
||||
ScopedConfigImpl::getRouteConfig(const Http::HeaderMap& headers) const {
|
||||
ScopeKeyPtr scope_key = scope_key_builder_.computeScopeKey(headers);
|
||||
if (scope_key == nullptr) {
|
||||
@@ -152,6 +332,7 @@
|
||||
if (iter != scoped_route_info_by_key_.end()) {
|
||||
return iter->second->routeConfig();
|
||||
}
|
||||
+#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
diff -Naur envoy/source/common/router/scoped_config_impl.h envoy-new/source/common/router/scoped_config_impl.h
|
||||
--- envoy/source/common/router/scoped_config_impl.h 2024-01-04 21:07:36.000000000 +0800
|
||||
+++ envoy-new/source/common/router/scoped_config_impl.h 2024-01-04 21:09:13.000000000 +0800
|
||||
@@ -22,6 +22,11 @@
|
||||
|
||||
using envoy::extensions::filters::network::http_connection_manager::v3::ScopedRoutes;
|
||||
|
||||
+#if defined(ALIMESH)
|
||||
+using ReComputeCb = std::function<std::unique_ptr<ScopeKeyFragmentBase>()>;
|
||||
+using ReComputeCbPtr = std::shared_ptr<ReComputeCb>;
|
||||
+#endif
|
||||
+
|
||||
/**
|
||||
* Base class for fragment builders.
|
||||
*/
|
||||
@@ -36,6 +41,12 @@
|
||||
virtual std::unique_ptr<ScopeKeyFragmentBase>
|
||||
computeFragment(const Http::HeaderMap& headers) const PURE;
|
||||
|
||||
+#if defined(ALIMESH)
|
||||
+ virtual std::unique_ptr<ScopeKeyFragmentBase>
|
||||
+ computeFragment(const Http::HeaderMap& headers, const StreamInfo::StreamInfo& info,
|
||||
+ ReComputeCbPtr& recompute) const PURE;
|
||||
+#endif
|
||||
+
|
||||
protected:
|
||||
const ScopedRoutes::ScopeKeyBuilder::FragmentBuilder config_;
|
||||
};
|
||||
@@ -47,11 +58,54 @@
|
||||
std::unique_ptr<ScopeKeyFragmentBase>
|
||||
computeFragment(const Http::HeaderMap& headers) const override;
|
||||
|
||||
+#if defined(ALIMESH)
|
||||
+ std::unique_ptr<ScopeKeyFragmentBase> computeFragment(const Http::HeaderMap& headers,
|
||||
+ const StreamInfo::StreamInfo& info,
|
||||
+ ReComputeCbPtr& recompute) const override;
|
||||
+#endif
|
||||
+
|
||||
private:
|
||||
const ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::HeaderValueExtractor&
|
||||
header_value_extractor_config_;
|
||||
};
|
||||
|
||||
+#if defined(ALIMESH)
|
||||
+class HostValueExtractorImpl : public FragmentBuilderBase {
|
||||
+public:
|
||||
+ explicit HostValueExtractorImpl(ScopedRoutes::ScopeKeyBuilder::FragmentBuilder&& config);
|
||||
+
|
||||
+ std::unique_ptr<ScopeKeyFragmentBase>
|
||||
+ computeFragment(const Http::HeaderMap& headers) const override;
|
||||
+
|
||||
+ std::unique_ptr<ScopeKeyFragmentBase> computeFragment(const Http::HeaderMap& headers,
|
||||
+ const StreamInfo::StreamInfo& info,
|
||||
+ ReComputeCbPtr& recompute) const override;
|
||||
+
|
||||
+private:
|
||||
+ std::unique_ptr<ScopeKeyFragmentBase> reComputeHelper(const std::string& host,
|
||||
+ ReComputeCbPtr& next_recompute,
|
||||
+ uint32_t recompute_seq) const;
|
||||
+
|
||||
+ static constexpr uint32_t DefaultMaxRecomputeNum = 100;
|
||||
+
|
||||
+ const ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::HostValueExtractor&
|
||||
+ host_value_extractor_config_;
|
||||
+ const uint32_t max_recompute_num_;
|
||||
+};
|
||||
+
|
||||
+class LocalPortValueExtractorImpl : public FragmentBuilderBase {
|
||||
+public:
|
||||
+ explicit LocalPortValueExtractorImpl(ScopedRoutes::ScopeKeyBuilder::FragmentBuilder&& config);
|
||||
+
|
||||
+ std::unique_ptr<ScopeKeyFragmentBase> computeFragment(const Http::HeaderMap&) const override {
|
||||
+ return nullptr;
|
||||
+ };
|
||||
+
|
||||
+ std::unique_ptr<ScopeKeyFragmentBase> computeFragment(const Http::HeaderMap& headers,
|
||||
+ const StreamInfo::StreamInfo& info,
|
||||
+ ReComputeCbPtr& recompute) const override;
|
||||
+};
|
||||
+#endif
|
||||
/**
|
||||
* Base class for ScopeKeyBuilder implementations.
|
||||
*/
|
||||
@@ -64,6 +118,12 @@
|
||||
// Computes scope key for given headers, returns nullptr if a key can't be computed.
|
||||
virtual ScopeKeyPtr computeScopeKey(const Http::HeaderMap& headers) const PURE;
|
||||
|
||||
+#if defined(ALIMESH)
|
||||
+ virtual ScopeKeyPtr computeScopeKey(const Http::HeaderMap& headers,
|
||||
+ const StreamInfo::StreamInfo& info,
|
||||
+ std::function<ScopeKeyPtr()>& recompute) const PURE;
|
||||
+#endif
|
||||
+
|
||||
protected:
|
||||
const ScopedRoutes::ScopeKeyBuilder config_;
|
||||
};
|
||||
@@ -74,6 +134,11 @@
|
||||
|
||||
ScopeKeyPtr computeScopeKey(const Http::HeaderMap& headers) const override;
|
||||
|
||||
+#if defined(ALIMESH)
|
||||
+ ScopeKeyPtr computeScopeKey(const Http::HeaderMap& headers, const StreamInfo::StreamInfo& info,
|
||||
+ std::function<ScopeKeyPtr()>& recompute) const override;
|
||||
+#endif
|
||||
+
|
||||
private:
|
||||
std::vector<std::unique_ptr<FragmentBuilderBase>> fragment_builders_;
|
||||
};
|
||||
@@ -118,10 +183,20 @@
|
||||
void removeRoutingScopes(const std::vector<std::string>& scope_names);
|
||||
|
||||
// Envoy::Router::ScopedConfig
|
||||
+#if defined(ALIMESH)
|
||||
+ Router::ConfigConstSharedPtr getRouteConfig(const Http::HeaderMap& headers,
|
||||
+ const StreamInfo::StreamInfo& info) const override;
|
||||
+#else
|
||||
Router::ConfigConstSharedPtr getRouteConfig(const Http::HeaderMap& headers) const override;
|
||||
+#endif
|
||||
// The return value is not null only if the scope corresponding to the header exists.
|
||||
ScopeKeyPtr computeScopeKey(const Http::HeaderMap& headers) const override;
|
||||
|
||||
+#if defined(ALIMESH)
|
||||
+ ScopeKeyPtr computeScopeKey(const Http::HeaderMap& headers,
|
||||
+ const StreamInfo::StreamInfo& info) const override;
|
||||
+#endif
|
||||
+
|
||||
private:
|
||||
ScopeKeyBuilderImpl scope_key_builder_;
|
||||
// From scope name to cached ScopedRouteInfo.
|
||||
@@ -135,9 +210,16 @@
|
||||
*/
|
||||
class NullScopedConfigImpl : public ScopedConfig {
|
||||
public:
|
||||
+#if defined(ALIMESH)
|
||||
+ Router::ConfigConstSharedPtr getRouteConfig(const Http::HeaderMap&,
|
||||
+ const StreamInfo::StreamInfo&) const override {
|
||||
+ return std::make_shared<const NullConfigImpl>();
|
||||
+ }
|
||||
+#else
|
||||
Router::ConfigConstSharedPtr getRouteConfig(const Http::HeaderMap&) const override {
|
||||
return std::make_shared<const NullConfigImpl>();
|
||||
}
|
||||
+#endif
|
||||
};
|
||||
|
||||
} // namespace Router
|
||||
diff -Naur envoy/source/extensions/filters/http/on_demand/on_demand_update.cc envoy-new/source/extensions/filters/http/on_demand/on_demand_update.cc
|
||||
--- envoy/source/extensions/filters/http/on_demand/on_demand_update.cc 2024-01-04 21:07:33.000000000 +0800
|
||||
+++ envoy-new/source/extensions/filters/http/on_demand/on_demand_update.cc 2024-01-04 21:09:13.000000000 +0800
|
||||
@@ -50,7 +50,11 @@
|
||||
// This is the callback which is called when an update requested in requestRouteConfigUpdate()
|
||||
// has been propagated to workers, at which point the request processing is restarted from the
|
||||
// beginning.
|
||||
+#if defined(ALIMESH)
|
||||
+void OnDemandRouteUpdate::onRouteConfigUpdateCompletion(bool) {
|
||||
+#else
|
||||
void OnDemandRouteUpdate::onRouteConfigUpdateCompletion(bool route_exists) {
|
||||
+#endif
|
||||
filter_iteration_state_ = Http::FilterHeadersStatus::Continue;
|
||||
|
||||
// Don't call continueDecoding in the middle of decodeHeaders()
|
||||
@@ -58,12 +62,14 @@
|
||||
return;
|
||||
}
|
||||
|
||||
+#if !defined(ALIMESH)
|
||||
if (route_exists && // route can be resolved after an on-demand
|
||||
// VHDS update
|
||||
!callbacks_->decodingBuffer() && // Redirects with body not yet supported.
|
||||
callbacks_->recreateStream(/*headers=*/nullptr)) {
|
||||
return;
|
||||
}
|
||||
+#endif
|
||||
|
||||
// route cannot be resolved after an on-demand VHDS update or
|
||||
// recreating stream failed, continue the filter-chain
|
||||
49
envoy/1.20/patches/envoy/20240110-fix-srds.patch
Normal file
49
envoy/1.20/patches/envoy/20240110-fix-srds.patch
Normal file
@@ -0,0 +1,49 @@
|
||||
diff -Naur envoy/source/common/router/BUILD envoy-new/source/common/router/BUILD
|
||||
--- envoy/source/common/router/BUILD 2024-01-10 20:10:14.505600746 +0800
|
||||
+++ envoy-new/source/common/router/BUILD 2024-01-10 20:07:25.960379955 +0800
|
||||
@@ -212,6 +212,7 @@
|
||||
"//envoy/router:rds_interface",
|
||||
"//envoy/router:scopes_interface",
|
||||
"//envoy/thread_local:thread_local_interface",
|
||||
+ "//source/common/http:header_utility_lib",
|
||||
"@envoy_api//envoy/config/route/v3:pkg_cc_proto",
|
||||
"@envoy_api//envoy/extensions/filters/network/http_connection_manager/v3:pkg_cc_proto",
|
||||
],
|
||||
diff -Naur envoy/source/common/router/scoped_config_impl.cc envoy-new/source/common/router/scoped_config_impl.cc
|
||||
--- envoy/source/common/router/scoped_config_impl.cc 2024-01-10 20:10:14.529600924 +0800
|
||||
+++ envoy-new/source/common/router/scoped_config_impl.cc 2024-01-10 20:09:50.161422411 +0800
|
||||
@@ -3,6 +3,8 @@
|
||||
#include "envoy/config/route/v3/scoped_route.pb.h"
|
||||
#include "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.h"
|
||||
|
||||
+#include "source/common/http/header_utility.h"
|
||||
+
|
||||
namespace Envoy {
|
||||
namespace Router {
|
||||
|
||||
@@ -74,18 +76,20 @@
|
||||
HostValueExtractorImpl::computeFragment(const Http::HeaderMap& headers,
|
||||
const StreamInfo::StreamInfo&,
|
||||
ReComputeCbPtr& recompute) const {
|
||||
- auto fragment = computeFragment(headers);
|
||||
auto host = static_cast<const Http::RequestHeaderMap&>(headers).getHostValue();
|
||||
+ auto port_start = Http::HeaderUtility::getPortStart(host);
|
||||
+ if (port_start != absl::string_view::npos) {
|
||||
+ host = host.substr(0, port_start);
|
||||
+ }
|
||||
*recompute = [this, host, recompute]() mutable -> std::unique_ptr<ScopeKeyFragmentBase> {
|
||||
return reComputeHelper(std::string(host), recompute, 0);
|
||||
};
|
||||
- return fragment;
|
||||
+ return std::make_unique<StringKeyFragment>(host);
|
||||
}
|
||||
|
||||
std::unique_ptr<ScopeKeyFragmentBase>
|
||||
-HostValueExtractorImpl::computeFragment(const Http::HeaderMap& headers) const {
|
||||
- return std::make_unique<StringKeyFragment>(
|
||||
- static_cast<const Http::RequestHeaderMap&>(headers).getHostValue());
|
||||
+HostValueExtractorImpl::computeFragment(const Http::HeaderMap&) const {
|
||||
+ return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<ScopeKeyFragmentBase>
|
||||
65
envoy/1.20/patches/envoy/20240111-fix-srds-compute.patch
Normal file
65
envoy/1.20/patches/envoy/20240111-fix-srds-compute.patch
Normal file
@@ -0,0 +1,65 @@
|
||||
diff -Naur envoy/source/common/router/scoped_config_impl.cc envoy-new/source/common/router/scoped_config_impl.cc
|
||||
--- envoy/source/common/router/scoped_config_impl.cc 2024-01-11 16:23:55.407881263 +0800
|
||||
+++ envoy-new/source/common/router/scoped_config_impl.cc 2024-01-11 16:23:42.311786814 +0800
|
||||
@@ -53,21 +53,26 @@
|
||||
}
|
||||
|
||||
std::unique_ptr<ScopeKeyFragmentBase>
|
||||
-HostValueExtractorImpl::reComputeHelper(const std::string& host, ReComputeCbPtr& next_recompute,
|
||||
+HostValueExtractorImpl::reComputeHelper(const std::string& host,
|
||||
+ ReComputeCbWeakPtr& weak_next_recompute,
|
||||
uint32_t recompute_seq) const {
|
||||
if (recompute_seq == max_recompute_num_) {
|
||||
ENVOY_LOG_MISC(warn,
|
||||
"recompute host fragment failed, maximum number of recalculations exceeded");
|
||||
return nullptr;
|
||||
}
|
||||
+ auto next_recompute = weak_next_recompute.lock();
|
||||
+ if (!next_recompute) {
|
||||
+ return nullptr;
|
||||
+ }
|
||||
if (host == "*") {
|
||||
*next_recompute = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
auto masked_host = maskFirstDNSLabel(host);
|
||||
*next_recompute = [this, masked_host, recompute_seq,
|
||||
- next_recompute]() mutable -> std::unique_ptr<ScopeKeyFragmentBase> {
|
||||
- return reComputeHelper(masked_host, next_recompute, recompute_seq + 1);
|
||||
+ weak_next_recompute]() mutable -> std::unique_ptr<ScopeKeyFragmentBase> {
|
||||
+ return reComputeHelper(masked_host, weak_next_recompute, recompute_seq + 1);
|
||||
};
|
||||
return std::make_unique<StringKeyFragment>(masked_host);
|
||||
}
|
||||
@@ -81,8 +86,9 @@
|
||||
if (port_start != absl::string_view::npos) {
|
||||
host = host.substr(0, port_start);
|
||||
}
|
||||
- *recompute = [this, host, recompute]() mutable -> std::unique_ptr<ScopeKeyFragmentBase> {
|
||||
- return reComputeHelper(std::string(host), recompute, 0);
|
||||
+ *recompute = [this, host, weak_recompute = ReComputeCbWeakPtr(recompute)]() mutable
|
||||
+ -> std::unique_ptr<ScopeKeyFragmentBase> {
|
||||
+ return reComputeHelper(std::string(host), weak_recompute, 0);
|
||||
};
|
||||
return std::make_unique<StringKeyFragment>(host);
|
||||
}
|
||||
diff -Naur envoy/source/common/router/scoped_config_impl.h envoy-new/source/common/router/scoped_config_impl.h
|
||||
--- envoy/source/common/router/scoped_config_impl.h 2024-01-11 16:23:55.407881263 +0800
|
||||
+++ envoy-new/source/common/router/scoped_config_impl.h 2024-01-11 16:23:42.311786814 +0800
|
||||
@@ -25,6 +25,7 @@
|
||||
#if defined(ALIMESH)
|
||||
using ReComputeCb = std::function<std::unique_ptr<ScopeKeyFragmentBase>()>;
|
||||
using ReComputeCbPtr = std::shared_ptr<ReComputeCb>;
|
||||
+using ReComputeCbWeakPtr = std::weak_ptr<ReComputeCb>;
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -83,7 +84,7 @@
|
||||
|
||||
private:
|
||||
std::unique_ptr<ScopeKeyFragmentBase> reComputeHelper(const std::string& host,
|
||||
- ReComputeCbPtr& next_recompute,
|
||||
+ ReComputeCbWeakPtr& weak_next_recompute,
|
||||
uint32_t recompute_seq) const;
|
||||
|
||||
static constexpr uint32_t DefaultMaxRecomputeNum = 100;
|
||||
931
envoy/1.20/patches/go-control-plane/20240104-enhance-srds.patch
Normal file
931
envoy/1.20/patches/go-control-plane/20240104-enhance-srds.patch
Normal file
@@ -0,0 +1,931 @@
|
||||
diff -Naur go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.go go-control-plane-new/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.go
|
||||
--- go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.go 2024-01-04 21:07:22.000000000 +0800
|
||||
+++ go-control-plane-new/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.go 2024-01-04 21:02:10.000000000 +0800
|
||||
@@ -2286,6 +2286,8 @@
|
||||
|
||||
// Types that are assignable to Type:
|
||||
// *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_
|
||||
+ // *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor_
|
||||
+ // *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor_
|
||||
Type isScopedRoutes_ScopeKeyBuilder_FragmentBuilder_Type `protobuf_oneof:"type"`
|
||||
}
|
||||
|
||||
@@ -2335,6 +2337,20 @@
|
||||
return nil
|
||||
}
|
||||
|
||||
+func (x *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder) GetHostValueExtractor() *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor {
|
||||
+ if x, ok := x.GetType().(*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor_); ok {
|
||||
+ return x.HostValueExtractor
|
||||
+ }
|
||||
+ return nil
|
||||
+}
|
||||
+
|
||||
+func (x *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder) GetLocalPortValueExtractor() *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor {
|
||||
+ if x, ok := x.GetType().(*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor_); ok {
|
||||
+ return x.LocalPortValueExtractor
|
||||
+ }
|
||||
+ return nil
|
||||
+}
|
||||
+
|
||||
type isScopedRoutes_ScopeKeyBuilder_FragmentBuilder_Type interface {
|
||||
isScopedRoutes_ScopeKeyBuilder_FragmentBuilder_Type()
|
||||
}
|
||||
@@ -2344,9 +2360,23 @@
|
||||
HeaderValueExtractor *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor `protobuf:"bytes,1,opt,name=header_value_extractor,json=headerValueExtractor,proto3,oneof"`
|
||||
}
|
||||
|
||||
+type ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor_ struct {
|
||||
+ HostValueExtractor *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor `protobuf:"bytes,101,opt,name=host_value_extractor,json=hostValueExtractor,proto3,oneof"`
|
||||
+}
|
||||
+
|
||||
+type ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor_ struct {
|
||||
+ LocalPortValueExtractor *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor `protobuf:"bytes,102,opt,name=local_port_value_extractor,json=localPortValueExtractor,proto3,oneof"`
|
||||
+}
|
||||
+
|
||||
func (*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_) isScopedRoutes_ScopeKeyBuilder_FragmentBuilder_Type() {
|
||||
}
|
||||
|
||||
+func (*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor_) isScopedRoutes_ScopeKeyBuilder_FragmentBuilder_Type() {
|
||||
+}
|
||||
+
|
||||
+func (*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor_) isScopedRoutes_ScopeKeyBuilder_FragmentBuilder_Type() {
|
||||
+}
|
||||
+
|
||||
// Specifies how the value of a header should be extracted.
|
||||
// The following example maps the structure of a header to the fields in this message.
|
||||
//
|
||||
@@ -2475,6 +2505,92 @@
|
||||
func (*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_Element) isScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_ExtractType() {
|
||||
}
|
||||
|
||||
+type ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor struct {
|
||||
+ state protoimpl.MessageState
|
||||
+ sizeCache protoimpl.SizeCache
|
||||
+ unknownFields protoimpl.UnknownFields
|
||||
+
|
||||
+ // The maximum number of host superset recomputes. If not specified, defaults to 100.
|
||||
+ MaxRecomputeNum *wrappers.UInt32Value `protobuf:"bytes,1,opt,name=max_recompute_num,json=maxRecomputeNum,proto3" json:"max_recompute_num,omitempty"`
|
||||
+}
|
||||
+
|
||||
+func (x *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor) Reset() {
|
||||
+ *x = ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor{}
|
||||
+ if protoimpl.UnsafeEnabled {
|
||||
+ mi := &file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_msgTypes[18]
|
||||
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
+ ms.StoreMessageInfo(mi)
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+func (x *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor) String() string {
|
||||
+ return protoimpl.X.MessageStringOf(x)
|
||||
+}
|
||||
+
|
||||
+func (*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor) ProtoMessage() {}
|
||||
+
|
||||
+func (x *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor) ProtoReflect() protoreflect.Message {
|
||||
+ mi := &file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_msgTypes[18]
|
||||
+ if protoimpl.UnsafeEnabled && x != nil {
|
||||
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
+ if ms.LoadMessageInfo() == nil {
|
||||
+ ms.StoreMessageInfo(mi)
|
||||
+ }
|
||||
+ return ms
|
||||
+ }
|
||||
+ return mi.MessageOf(x)
|
||||
+}
|
||||
+
|
||||
+// Deprecated: Use ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor.ProtoReflect.Descriptor instead.
|
||||
+func (*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor) Descriptor() ([]byte, []int) {
|
||||
+ return file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_rawDescGZIP(), []int{5, 0, 0, 1}
|
||||
+}
|
||||
+
|
||||
+func (x *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor) GetMaxRecomputeNum() *wrappers.UInt32Value {
|
||||
+ if x != nil {
|
||||
+ return x.MaxRecomputeNum
|
||||
+ }
|
||||
+ return nil
|
||||
+}
|
||||
+
|
||||
+type ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor struct {
|
||||
+ state protoimpl.MessageState
|
||||
+ sizeCache protoimpl.SizeCache
|
||||
+ unknownFields protoimpl.UnknownFields
|
||||
+}
|
||||
+
|
||||
+func (x *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor) Reset() {
|
||||
+ *x = ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor{}
|
||||
+ if protoimpl.UnsafeEnabled {
|
||||
+ mi := &file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_msgTypes[19]
|
||||
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
+ ms.StoreMessageInfo(mi)
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+func (x *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor) String() string {
|
||||
+ return protoimpl.X.MessageStringOf(x)
|
||||
+}
|
||||
+
|
||||
+func (*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor) ProtoMessage() {}
|
||||
+
|
||||
+func (x *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor) ProtoReflect() protoreflect.Message {
|
||||
+ mi := &file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_msgTypes[19]
|
||||
+ if protoimpl.UnsafeEnabled && x != nil {
|
||||
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
+ if ms.LoadMessageInfo() == nil {
|
||||
+ ms.StoreMessageInfo(mi)
|
||||
+ }
|
||||
+ return ms
|
||||
+ }
|
||||
+ return mi.MessageOf(x)
|
||||
+}
|
||||
+
|
||||
+// Deprecated: Use ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor.ProtoReflect.Descriptor instead.
|
||||
+func (*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor) Descriptor() ([]byte, []int) {
|
||||
+ return file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_rawDescGZIP(), []int{5, 0, 0, 2}
|
||||
+}
|
||||
+
|
||||
// Specifies a header field's key value pair to match on.
|
||||
type ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement struct {
|
||||
state protoimpl.MessageState
|
||||
@@ -2494,7 +2610,7 @@
|
||||
func (x *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement) Reset() {
|
||||
*x = ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
- mi := &file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_msgTypes[18]
|
||||
+ mi := &file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_msgTypes[20]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2507,7 +2623,7 @@
|
||||
func (*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement) ProtoMessage() {}
|
||||
|
||||
func (x *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement) ProtoReflect() protoreflect.Message {
|
||||
- mi := &file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_msgTypes[18]
|
||||
+ mi := &file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_msgTypes[20]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -3079,7 +3195,7 @@
|
||||
0x74, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61,
|
||||
0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x52,
|
||||
0x6f, 0x75, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
|
||||
- 0x6e, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x22, 0xe9, 0x0e, 0x0a, 0x0c, 0x53, 0x63, 0x6f, 0x70, 0x65,
|
||||
+ 0x6e, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x22, 0xe1, 0x14, 0x0a, 0x0c, 0x53, 0x63, 0x6f, 0x70, 0x65,
|
||||
0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x12, 0x8f, 0x01, 0x0a, 0x11, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x6b,
|
||||
@@ -3114,7 +3230,7 @@
|
||||
0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
|
||||
0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65,
|
||||
0x64, 0x52, 0x64, 0x73, 0x48, 0x00, 0x52, 0x09, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x52, 0x64,
|
||||
- 0x73, 0x1a, 0xd9, 0x09, 0x0a, 0x0f, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x4b, 0x65, 0x79, 0x42, 0x75,
|
||||
+ 0x73, 0x1a, 0xd1, 0x0f, 0x0a, 0x0f, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x4b, 0x65, 0x79, 0x42, 0x75,
|
||||
0x69, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x91, 0x01, 0x0a, 0x09, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65,
|
||||
0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x69, 0x2e, 0x65, 0x6e, 0x76, 0x6f,
|
||||
0x79, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66, 0x69, 0x6c,
|
||||
@@ -3124,7 +3240,7 @@
|
||||
0x75, 0x74, 0x65, 0x73, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x4b, 0x65, 0x79, 0x42, 0x75, 0x69,
|
||||
0x6c, 0x64, 0x65, 0x72, 0x2e, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x75, 0x69,
|
||||
0x6c, 0x64, 0x65, 0x72, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, 0x08, 0x01, 0x52, 0x09,
|
||||
- 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0xd5, 0x07, 0x0a, 0x0f, 0x46, 0x72,
|
||||
+ 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0xcd, 0x0d, 0x0a, 0x0f, 0x46, 0x72,
|
||||
0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x12, 0xb6, 0x01,
|
||||
0x0a, 0x16, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x65,
|
||||
0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x7e,
|
||||
@@ -3137,131 +3253,178 @@
|
||||
0x6e, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72,
|
||||
0x56, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x48, 0x00,
|
||||
0x52, 0x14, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x78, 0x74,
|
||||
- 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x1a, 0x8f, 0x05, 0x0a, 0x14, 0x48, 0x65, 0x61, 0x64, 0x65,
|
||||
- 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x12,
|
||||
- 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa,
|
||||
- 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x11,
|
||||
- 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f,
|
||||
- 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74,
|
||||
- 0x53, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x16, 0x0a, 0x05, 0x69, 0x6e, 0x64,
|
||||
- 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65,
|
||||
- 0x78, 0x12, 0xa5, 0x01, 0x0a, 0x07, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20,
|
||||
- 0x01, 0x28, 0x0b, 0x32, 0x88, 0x01, 0x2e, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x65, 0x78, 0x74,
|
||||
- 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x2e,
|
||||
+ 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x12, 0xb0, 0x01, 0x0a, 0x14, 0x68, 0x6f, 0x73, 0x74, 0x5f,
|
||||
+ 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x18,
|
||||
+ 0x65, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x7c, 0x2e, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x65, 0x78,
|
||||
+ 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73,
|
||||
+ 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f,
|
||||
+ 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72,
|
||||
+ 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73,
|
||||
+ 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x4b, 0x65, 0x79, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72,
|
||||
+ 0x2e, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72,
|
||||
+ 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63,
|
||||
+ 0x74, 0x6f, 0x72, 0x48, 0x00, 0x52, 0x12, 0x68, 0x6f, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65,
|
||||
+ 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x12, 0xc1, 0x01, 0x0a, 0x1a, 0x6c, 0x6f,
|
||||
+ 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x65,
|
||||
+ 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x66, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x81,
|
||||
+ 0x01, 0x2e, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,
|
||||
+ 0x6e, 0x73, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f,
|
||||
+ 0x72, 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69,
|
||||
+ 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x63,
|
||||
+ 0x6f, 0x70, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65,
|
||||
+ 0x4b, 0x65, 0x79, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x2e, 0x46, 0x72, 0x61, 0x67, 0x6d,
|
||||
+ 0x65, 0x6e, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c,
|
||||
+ 0x50, 0x6f, 0x72, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74,
|
||||
+ 0x6f, 0x72, 0x48, 0x00, 0x52, 0x17, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x56,
|
||||
+ 0x61, 0x6c, 0x75, 0x65, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x1a, 0x8f, 0x05,
|
||||
+ 0x0a, 0x14, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x78, 0x74,
|
||||
+ 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
|
||||
+ 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6e,
|
||||
+ 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73,
|
||||
+ 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10,
|
||||
+ 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72,
|
||||
+ 0x12, 0x16, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x48,
|
||||
+ 0x00, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0xa5, 0x01, 0x0a, 0x07, 0x65, 0x6c, 0x65,
|
||||
+ 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x88, 0x01, 0x2e, 0x65, 0x6e,
|
||||
+ 0x76, 0x6f, 0x79, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66,
|
||||
+ 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x68,
|
||||
+ 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d,
|
||||
+ 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x64,
|
||||
+ 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x4b, 0x65, 0x79, 0x42,
|
||||
+ 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x2e, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x42,
|
||||
+ 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x56, 0x61, 0x6c,
|
||||
+ 0x75, 0x65, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x4b, 0x76, 0x45, 0x6c,
|
||||
+ 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x07, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74,
|
||||
+ 0x1a, 0xdb, 0x01, 0x0a, 0x09, 0x4b, 0x76, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x25,
|
||||
+ 0x0a, 0x09, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
+ 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x73, 0x65, 0x70, 0x61,
|
||||
+ 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x19, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01,
|
||||
+ 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x03, 0x6b, 0x65, 0x79,
|
||||
+ 0x3a, 0x8b, 0x01, 0x9a, 0xc5, 0x88, 0x1e, 0x85, 0x01, 0x0a, 0x82, 0x01, 0x65, 0x6e, 0x76, 0x6f,
|
||||
+ 0x79, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x2e,
|
||||
0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x6e,
|
||||
0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e,
|
||||
- 0x76, 0x33, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2e,
|
||||
+ 0x76, 0x32, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2e,
|
||||
0x53, 0x63, 0x6f, 0x70, 0x65, 0x4b, 0x65, 0x79, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x2e,
|
||||
0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x2e,
|
||||
0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x78, 0x74, 0x72, 0x61,
|
||||
- 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x4b, 0x76, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x00,
|
||||
- 0x52, 0x07, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x1a, 0xdb, 0x01, 0x0a, 0x09, 0x4b, 0x76,
|
||||
- 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x09, 0x73, 0x65, 0x70, 0x61, 0x72,
|
||||
- 0x61, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72,
|
||||
- 0x02, 0x10, 0x01, 0x52, 0x09, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x19,
|
||||
- 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04,
|
||||
- 0x72, 0x02, 0x10, 0x01, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x3a, 0x8b, 0x01, 0x9a, 0xc5, 0x88, 0x1e,
|
||||
- 0x85, 0x01, 0x0a, 0x82, 0x01, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69,
|
||||
+ 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x4b, 0x76, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x3a, 0x7f,
|
||||
+ 0x9a, 0xc5, 0x88, 0x1e, 0x7a, 0x0a, 0x78, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x63, 0x6f, 0x6e,
|
||||
+ 0x66, 0x69, 0x67, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f,
|
||||
+ 0x72, 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69,
|
||||
+ 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x63,
|
||||
+ 0x6f, 0x70, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65,
|
||||
+ 0x4b, 0x65, 0x79, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x2e, 0x46, 0x72, 0x61, 0x67, 0x6d,
|
||||
+ 0x65, 0x6e, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65,
|
||||
+ 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x42,
|
||||
+ 0x0e, 0x0a, 0x0c, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x1a,
|
||||
+ 0xdd, 0x01, 0x0a, 0x12, 0x48, 0x6f, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x78, 0x74,
|
||||
+ 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x48, 0x0a, 0x11, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x65,
|
||||
+ 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
+ 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
+ 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52,
|
||||
+ 0x0f, 0x6d, 0x61, 0x78, 0x52, 0x65, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x4e, 0x75, 0x6d,
|
||||
+ 0x3a, 0x7d, 0x9a, 0xc5, 0x88, 0x1e, 0x78, 0x0a, 0x76, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x63,
|
||||
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x2e, 0x6e, 0x65, 0x74,
|
||||
+ 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
||||
+ 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e,
|
||||
+ 0x53, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x53, 0x63, 0x6f,
|
||||
+ 0x70, 0x65, 0x4b, 0x65, 0x79, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x2e, 0x46, 0x72, 0x61,
|
||||
+ 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x2e, 0x48, 0x6f, 0x73,
|
||||
+ 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x1a,
|
||||
+ 0x9e, 0x01, 0x0a, 0x17, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x56, 0x61, 0x6c,
|
||||
+ 0x75, 0x65, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x3a, 0x82, 0x01, 0x9a, 0xc5,
|
||||
+ 0x88, 0x1e, 0x7d, 0x0a, 0x7b, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69,
|
||||
0x67, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
|
||||
0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x63, 0x6f, 0x70,
|
||||
0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x4b, 0x65,
|
||||
0x79, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x2e, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e,
|
||||
- 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x56,
|
||||
- 0x61, 0x6c, 0x75, 0x65, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x4b, 0x76,
|
||||
- 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x3a, 0x7f, 0x9a, 0xc5, 0x88, 0x1e, 0x7a, 0x0a, 0x78,
|
||||
- 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x66, 0x69, 0x6c,
|
||||
- 0x74, 0x65, 0x72, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70,
|
||||
- 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61,
|
||||
- 0x67, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x52, 0x6f, 0x75,
|
||||
- 0x74, 0x65, 0x73, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x4b, 0x65, 0x79, 0x42, 0x75, 0x69, 0x6c,
|
||||
- 0x64, 0x65, 0x72, 0x2e, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x75, 0x69, 0x6c,
|
||||
- 0x64, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x45,
|
||||
- 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x42, 0x0e, 0x0a, 0x0c, 0x65, 0x78, 0x74, 0x72,
|
||||
- 0x61, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x6a, 0x9a, 0xc5, 0x88, 0x1e, 0x65, 0x0a,
|
||||
- 0x63, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x66, 0x69,
|
||||
- 0x6c, 0x74, 0x65, 0x72, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x68, 0x74, 0x74,
|
||||
- 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x6e,
|
||||
- 0x61, 0x67, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x52, 0x6f,
|
||||
- 0x75, 0x74, 0x65, 0x73, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x4b, 0x65, 0x79, 0x42, 0x75, 0x69,
|
||||
- 0x6c, 0x64, 0x65, 0x72, 0x2e, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x75, 0x69,
|
||||
- 0x6c, 0x64, 0x65, 0x72, 0x42, 0x0b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x03, 0xf8, 0x42,
|
||||
- 0x01, 0x3a, 0x5a, 0x9a, 0xc5, 0x88, 0x1e, 0x55, 0x0a, 0x53, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e,
|
||||
- 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x2e, 0x6e, 0x65,
|
||||
- 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
|
||||
- 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x76, 0x32,
|
||||
- 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x53, 0x63,
|
||||
- 0x6f, 0x70, 0x65, 0x4b, 0x65, 0x79, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x3a, 0x4a, 0x9a,
|
||||
- 0xc5, 0x88, 0x1e, 0x45, 0x0a, 0x43, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x63, 0x6f, 0x6e, 0x66,
|
||||
- 0x69, 0x67, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72,
|
||||
- 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f,
|
||||
- 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x63, 0x6f,
|
||||
- 0x70, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x42, 0x17, 0x0a, 0x10, 0x63, 0x6f, 0x6e,
|
||||
- 0x66, 0x69, 0x67, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x03, 0xf8,
|
||||
- 0x42, 0x01, 0x22, 0xf1, 0x01, 0x0a, 0x09, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x52, 0x64, 0x73,
|
||||
- 0x12, 0x65, 0x0a, 0x18, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x5f, 0x72, 0x64, 0x73, 0x5f, 0x63,
|
||||
- 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01,
|
||||
- 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69,
|
||||
- 0x67, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
- 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01,
|
||||
- 0x52, 0x15, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x52, 0x64, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||
- 0x67, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x16, 0x73, 0x72, 0x64, 0x73, 0x5f,
|
||||
- 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f,
|
||||
- 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x73, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73,
|
||||
- 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x3a, 0x47, 0x9a,
|
||||
- 0xc5, 0x88, 0x1e, 0x42, 0x0a, 0x40, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x63, 0x6f, 0x6e, 0x66,
|
||||
- 0x69, 0x67, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72,
|
||||
- 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f,
|
||||
- 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x63, 0x6f,
|
||||
- 0x70, 0x65, 0x64, 0x52, 0x64, 0x73, 0x22, 0xcc, 0x02, 0x0a, 0x0a, 0x48, 0x74, 0x74, 0x70, 0x46,
|
||||
- 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
|
||||
- 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6e, 0x61,
|
||||
- 0x6d, 0x65, 0x12, 0x39, 0x0a, 0x0c, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66,
|
||||
- 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||
- 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x48, 0x00,
|
||||
- 0x52, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x58, 0x0a,
|
||||
- 0x10, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72,
|
||||
- 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e,
|
||||
- 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x33, 0x2e, 0x45,
|
||||
- 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x6f,
|
||||
- 0x75, 0x72, 0x63, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69,
|
||||
- 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x73, 0x5f, 0x6f, 0x70,
|
||||
- 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73,
|
||||
- 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x3a, 0x48, 0x9a, 0xc5, 0x88, 0x1e, 0x43, 0x0a,
|
||||
- 0x41, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x66, 0x69,
|
||||
- 0x6c, 0x74, 0x65, 0x72, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x68, 0x74, 0x74,
|
||||
- 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x6e,
|
||||
- 0x61, 0x67, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x46, 0x69, 0x6c, 0x74,
|
||||
- 0x65, 0x72, 0x42, 0x0d, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x74, 0x79, 0x70,
|
||||
- 0x65, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x52, 0x06, 0x63,
|
||||
- 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x9f, 0x01, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
- 0x74, 0x49, 0x44, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x37, 0x0a, 0x0c,
|
||||
- 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01,
|
||||
- 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
- 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x64, 0x43,
|
||||
- 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x3a, 0x50, 0x9a, 0xc5, 0x88, 0x1e, 0x4b, 0x0a, 0x49, 0x65, 0x6e,
|
||||
+ 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f,
|
||||
+ 0x72, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72,
|
||||
+ 0x3a, 0x6a, 0x9a, 0xc5, 0x88, 0x1e, 0x65, 0x0a, 0x63, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x63,
|
||||
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x2e, 0x6e, 0x65, 0x74,
|
||||
+ 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
||||
+ 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e,
|
||||
+ 0x53, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x53, 0x63, 0x6f,
|
||||
+ 0x70, 0x65, 0x4b, 0x65, 0x79, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x2e, 0x46, 0x72, 0x61,
|
||||
+ 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x42, 0x0b, 0x0a, 0x04,
|
||||
+ 0x74, 0x79, 0x70, 0x65, 0x12, 0x03, 0xf8, 0x42, 0x01, 0x3a, 0x5a, 0x9a, 0xc5, 0x88, 0x1e, 0x55,
|
||||
+ 0x0a, 0x53, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x66,
|
||||
+ 0x69, 0x6c, 0x74, 0x65, 0x72, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x68, 0x74,
|
||||
+ 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61,
|
||||
+ 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x52,
|
||||
+ 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x4b, 0x65, 0x79, 0x42, 0x75,
|
||||
+ 0x69, 0x6c, 0x64, 0x65, 0x72, 0x3a, 0x4a, 0x9a, 0xc5, 0x88, 0x1e, 0x45, 0x0a, 0x43, 0x65, 0x6e,
|
||||
0x76, 0x6f, 0x79, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65,
|
||||
0x72, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63,
|
||||
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65,
|
||||
- 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x44, 0x45, 0x78,
|
||||
- 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x8e, 0x01, 0x0a, 0x20, 0x45, 0x6e, 0x76, 0x6f,
|
||||
- 0x79, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x48, 0x74, 0x74, 0x70, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
|
||||
- 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x6a, 0x0a, 0x06,
|
||||
- 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x52, 0x2e, 0x65,
|
||||
- 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
|
||||
- 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e,
|
||||
- 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
|
||||
- 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x76, 0x33, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x43,
|
||||
- 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72,
|
||||
- 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x71, 0x0a, 0x49, 0x69, 0x6f, 0x2e, 0x65,
|
||||
- 0x6e, 0x76, 0x6f, 0x79, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e,
|
||||
- 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65,
|
||||
- 0x72, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f,
|
||||
- 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67,
|
||||
- 0x65, 0x72, 0x2e, 0x76, 0x33, 0x42, 0x1a, 0x48, 0x74, 0x74, 0x70, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
|
||||
- 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x74,
|
||||
- 0x6f, 0x50, 0x01, 0xba, 0x80, 0xc8, 0xd1, 0x06, 0x02, 0x10, 0x02, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
||||
- 0x74, 0x6f, 0x33,
|
||||
+ 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65,
|
||||
+ 0x73, 0x42, 0x17, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x70, 0x65, 0x63,
|
||||
+ 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x03, 0xf8, 0x42, 0x01, 0x22, 0xf1, 0x01, 0x0a, 0x09, 0x53,
|
||||
+ 0x63, 0x6f, 0x70, 0x65, 0x64, 0x52, 0x64, 0x73, 0x12, 0x65, 0x0a, 0x18, 0x73, 0x63, 0x6f, 0x70,
|
||||
+ 0x65, 0x64, 0x5f, 0x72, 0x64, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x6f,
|
||||
+ 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x65, 0x6e, 0x76,
|
||||
+ 0x6f, 0x79, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76,
|
||||
+ 0x33, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x42, 0x08,
|
||||
+ 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x15, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x64,
|
||||
+ 0x52, 0x64, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12,
|
||||
+ 0x34, 0x0a, 0x16, 0x73, 0x72, 0x64, 0x73, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
|
||||
+ 0x73, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
+ 0x14, 0x73, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4c, 0x6f,
|
||||
+ 0x63, 0x61, 0x74, 0x6f, 0x72, 0x3a, 0x47, 0x9a, 0xc5, 0x88, 0x1e, 0x42, 0x0a, 0x40, 0x65, 0x6e,
|
||||
+ 0x76, 0x6f, 0x79, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65,
|
||||
+ 0x72, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63,
|
||||
+ 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65,
|
||||
+ 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x52, 0x64, 0x73, 0x22, 0xcc,
|
||||
+ 0x02, 0x0a, 0x0a, 0x48, 0x74, 0x74, 0x70, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1b, 0x0a,
|
||||
+ 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04,
|
||||
+ 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x39, 0x0a, 0x0c, 0x74, 0x79,
|
||||
+ 0x70, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
|
||||
+ 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
+ 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x48, 0x00, 0x52, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x64, 0x43,
|
||||
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x58, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f,
|
||||
+ 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
+ 0x2b, 0x2e, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x63,
|
||||
+ 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
|
||||
+ 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x00, 0x52, 0x0f,
|
||||
+ 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x12,
|
||||
+ 0x1f, 0x0a, 0x0b, 0x69, 0x73, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x18, 0x06,
|
||||
+ 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c,
|
||||
+ 0x3a, 0x48, 0x9a, 0xc5, 0x88, 0x1e, 0x43, 0x0a, 0x41, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x63,
|
||||
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x2e, 0x6e, 0x65, 0x74,
|
||||
+ 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
||||
+ 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e,
|
||||
+ 0x48, 0x74, 0x74, 0x70, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x0d, 0x0a, 0x0b, 0x63, 0x6f,
|
||||
+ 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a,
|
||||
+ 0x04, 0x08, 0x02, 0x10, 0x03, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x9f, 0x01,
|
||||
+ 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x44, 0x45, 0x78, 0x74, 0x65, 0x6e,
|
||||
+ 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x37, 0x0a, 0x0c, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x63, 0x6f,
|
||||
+ 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f,
|
||||
+ 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79,
|
||||
+ 0x52, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x3a, 0x50, 0x9a,
|
||||
+ 0xc5, 0x88, 0x1e, 0x4b, 0x0a, 0x49, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x63, 0x6f, 0x6e, 0x66,
|
||||
+ 0x69, 0x67, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72,
|
||||
+ 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f,
|
||||
+ 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71,
|
||||
+ 0x75, 0x65, 0x73, 0x74, 0x49, 0x44, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x22,
|
||||
+ 0x8e, 0x01, 0x0a, 0x20, 0x45, 0x6e, 0x76, 0x6f, 0x79, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x48,
|
||||
+ 0x74, 0x74, 0x70, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x6e,
|
||||
+ 0x61, 0x67, 0x65, 0x72, 0x12, 0x6a, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01,
|
||||
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x52, 0x2e, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x65, 0x78, 0x74,
|
||||
+ 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x2e,
|
||||
+ 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x6e,
|
||||
+ 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e,
|
||||
+ 0x76, 0x33, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f,
|
||||
+ 0x6e, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
+ 0x42, 0x71, 0x0a, 0x49, 0x69, 0x6f, 0x2e, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x70, 0x72, 0x6f, 0x78,
|
||||
+ 0x79, 0x2e, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,
|
||||
+ 0x6e, 0x73, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f,
|
||||
+ 0x72, 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69,
|
||||
+ 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x76, 0x33, 0x42, 0x1a, 0x48,
|
||||
+ 0x74, 0x74, 0x70, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x6e,
|
||||
+ 0x61, 0x67, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0xba, 0x80, 0xc8, 0xd1, 0x06,
|
||||
+ 0x02, 0x10, 0x02, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -3277,7 +3440,7 @@
|
||||
}
|
||||
|
||||
var file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_enumTypes = make([]protoimpl.EnumInfo, 5)
|
||||
-var file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_msgTypes = make([]protoimpl.MessageInfo, 19)
|
||||
+var file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_msgTypes = make([]protoimpl.MessageInfo, 21)
|
||||
var file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_goTypes = []interface{}{
|
||||
(HttpConnectionManager_CodecType)(0), // 0: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.CodecType
|
||||
(HttpConnectionManager_ServerHeaderTransformation)(0), // 1: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.ServerHeaderTransformation
|
||||
@@ -3302,102 +3465,107 @@
|
||||
(*ScopedRoutes_ScopeKeyBuilder)(nil), // 20: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder
|
||||
(*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder)(nil), // 21: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder.FragmentBuilder
|
||||
(*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor)(nil), // 22: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder.FragmentBuilder.HeaderValueExtractor
|
||||
- (*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement)(nil), // 23: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder.FragmentBuilder.HeaderValueExtractor.KvElement
|
||||
- (*v32.RouteConfiguration)(nil), // 24: envoy.config.route.v3.RouteConfiguration
|
||||
- (*wrappers.BoolValue)(nil), // 25: google.protobuf.BoolValue
|
||||
- (*v3.HttpProtocolOptions)(nil), // 26: envoy.config.core.v3.HttpProtocolOptions
|
||||
- (*v3.Http1ProtocolOptions)(nil), // 27: envoy.config.core.v3.Http1ProtocolOptions
|
||||
- (*v3.Http2ProtocolOptions)(nil), // 28: envoy.config.core.v3.Http2ProtocolOptions
|
||||
- (*v3.Http3ProtocolOptions)(nil), // 29: envoy.config.core.v3.Http3ProtocolOptions
|
||||
- (*v3.SchemeHeaderTransformation)(nil), // 30: envoy.config.core.v3.SchemeHeaderTransformation
|
||||
- (*wrappers.UInt32Value)(nil), // 31: google.protobuf.UInt32Value
|
||||
- (*duration.Duration)(nil), // 32: google.protobuf.Duration
|
||||
- (*v31.AccessLog)(nil), // 33: envoy.config.accesslog.v3.AccessLog
|
||||
- (*v3.TypedExtensionConfig)(nil), // 34: envoy.config.core.v3.TypedExtensionConfig
|
||||
- (*v3.SubstitutionFormatString)(nil), // 35: envoy.config.core.v3.SubstitutionFormatString
|
||||
- (*v31.AccessLogFilter)(nil), // 36: envoy.config.accesslog.v3.AccessLogFilter
|
||||
- (*v3.DataSource)(nil), // 37: envoy.config.core.v3.DataSource
|
||||
- (*v3.HeaderValueOption)(nil), // 38: envoy.config.core.v3.HeaderValueOption
|
||||
- (*v3.ConfigSource)(nil), // 39: envoy.config.core.v3.ConfigSource
|
||||
- (*v32.ScopedRouteConfiguration)(nil), // 40: envoy.config.route.v3.ScopedRouteConfiguration
|
||||
- (*any.Any)(nil), // 41: google.protobuf.Any
|
||||
- (*v3.ExtensionConfigSource)(nil), // 42: envoy.config.core.v3.ExtensionConfigSource
|
||||
- (*v33.Percent)(nil), // 43: envoy.type.v3.Percent
|
||||
- (*v34.CustomTag)(nil), // 44: envoy.type.tracing.v3.CustomTag
|
||||
- (*v35.Tracing_Http)(nil), // 45: envoy.config.trace.v3.Tracing.Http
|
||||
- (*v36.PathTransformation)(nil), // 46: envoy.type.http.v3.PathTransformation
|
||||
+ (*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor)(nil), // 23: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder.FragmentBuilder.HostValueExtractor
|
||||
+ (*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor)(nil), // 24: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder.FragmentBuilder.LocalPortValueExtractor
|
||||
+ (*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement)(nil), // 25: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder.FragmentBuilder.HeaderValueExtractor.KvElement
|
||||
+ (*v32.RouteConfiguration)(nil), // 26: envoy.config.route.v3.RouteConfiguration
|
||||
+ (*wrappers.BoolValue)(nil), // 27: google.protobuf.BoolValue
|
||||
+ (*v3.HttpProtocolOptions)(nil), // 28: envoy.config.core.v3.HttpProtocolOptions
|
||||
+ (*v3.Http1ProtocolOptions)(nil), // 29: envoy.config.core.v3.Http1ProtocolOptions
|
||||
+ (*v3.Http2ProtocolOptions)(nil), // 30: envoy.config.core.v3.Http2ProtocolOptions
|
||||
+ (*v3.Http3ProtocolOptions)(nil), // 31: envoy.config.core.v3.Http3ProtocolOptions
|
||||
+ (*v3.SchemeHeaderTransformation)(nil), // 32: envoy.config.core.v3.SchemeHeaderTransformation
|
||||
+ (*wrappers.UInt32Value)(nil), // 33: google.protobuf.UInt32Value
|
||||
+ (*duration.Duration)(nil), // 34: google.protobuf.Duration
|
||||
+ (*v31.AccessLog)(nil), // 35: envoy.config.accesslog.v3.AccessLog
|
||||
+ (*v3.TypedExtensionConfig)(nil), // 36: envoy.config.core.v3.TypedExtensionConfig
|
||||
+ (*v3.SubstitutionFormatString)(nil), // 37: envoy.config.core.v3.SubstitutionFormatString
|
||||
+ (*v31.AccessLogFilter)(nil), // 38: envoy.config.accesslog.v3.AccessLogFilter
|
||||
+ (*v3.DataSource)(nil), // 39: envoy.config.core.v3.DataSource
|
||||
+ (*v3.HeaderValueOption)(nil), // 40: envoy.config.core.v3.HeaderValueOption
|
||||
+ (*v3.ConfigSource)(nil), // 41: envoy.config.core.v3.ConfigSource
|
||||
+ (*v32.ScopedRouteConfiguration)(nil), // 42: envoy.config.route.v3.ScopedRouteConfiguration
|
||||
+ (*any.Any)(nil), // 43: google.protobuf.Any
|
||||
+ (*v3.ExtensionConfigSource)(nil), // 44: envoy.config.core.v3.ExtensionConfigSource
|
||||
+ (*v33.Percent)(nil), // 45: envoy.type.v3.Percent
|
||||
+ (*v34.CustomTag)(nil), // 46: envoy.type.tracing.v3.CustomTag
|
||||
+ (*v35.Tracing_Http)(nil), // 47: envoy.config.trace.v3.Tracing.Http
|
||||
+ (*v36.PathTransformation)(nil), // 48: envoy.type.http.v3.PathTransformation
|
||||
}
|
||||
var file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_depIdxs = []int32{
|
||||
0, // 0: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.codec_type:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.CodecType
|
||||
8, // 1: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.rds:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.Rds
|
||||
- 24, // 2: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.route_config:type_name -> envoy.config.route.v3.RouteConfiguration
|
||||
+ 26, // 2: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.route_config:type_name -> envoy.config.route.v3.RouteConfiguration
|
||||
10, // 3: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.scoped_routes:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes
|
||||
12, // 4: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.http_filters:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.HttpFilter
|
||||
- 25, // 5: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.add_user_agent:type_name -> google.protobuf.BoolValue
|
||||
+ 27, // 5: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.add_user_agent:type_name -> google.protobuf.BoolValue
|
||||
15, // 6: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.tracing:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.Tracing
|
||||
- 26, // 7: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.common_http_protocol_options:type_name -> envoy.config.core.v3.HttpProtocolOptions
|
||||
- 27, // 8: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.http_protocol_options:type_name -> envoy.config.core.v3.Http1ProtocolOptions
|
||||
- 28, // 9: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.http2_protocol_options:type_name -> envoy.config.core.v3.Http2ProtocolOptions
|
||||
- 29, // 10: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.http3_protocol_options:type_name -> envoy.config.core.v3.Http3ProtocolOptions
|
||||
+ 28, // 7: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.common_http_protocol_options:type_name -> envoy.config.core.v3.HttpProtocolOptions
|
||||
+ 29, // 8: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.http_protocol_options:type_name -> envoy.config.core.v3.Http1ProtocolOptions
|
||||
+ 30, // 9: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.http2_protocol_options:type_name -> envoy.config.core.v3.Http2ProtocolOptions
|
||||
+ 31, // 10: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.http3_protocol_options:type_name -> envoy.config.core.v3.Http3ProtocolOptions
|
||||
1, // 11: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.server_header_transformation:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.ServerHeaderTransformation
|
||||
- 30, // 12: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.scheme_header_transformation:type_name -> envoy.config.core.v3.SchemeHeaderTransformation
|
||||
- 31, // 13: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.max_request_headers_kb:type_name -> google.protobuf.UInt32Value
|
||||
- 32, // 14: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.stream_idle_timeout:type_name -> google.protobuf.Duration
|
||||
- 32, // 15: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.request_timeout:type_name -> google.protobuf.Duration
|
||||
- 32, // 16: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.request_headers_timeout:type_name -> google.protobuf.Duration
|
||||
- 32, // 17: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.drain_timeout:type_name -> google.protobuf.Duration
|
||||
- 32, // 18: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.delayed_close_timeout:type_name -> google.protobuf.Duration
|
||||
- 33, // 19: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.access_log:type_name -> envoy.config.accesslog.v3.AccessLog
|
||||
- 25, // 20: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.use_remote_address:type_name -> google.protobuf.BoolValue
|
||||
- 34, // 21: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.original_ip_detection_extensions:type_name -> envoy.config.core.v3.TypedExtensionConfig
|
||||
+ 32, // 12: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.scheme_header_transformation:type_name -> envoy.config.core.v3.SchemeHeaderTransformation
|
||||
+ 33, // 13: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.max_request_headers_kb:type_name -> google.protobuf.UInt32Value
|
||||
+ 34, // 14: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.stream_idle_timeout:type_name -> google.protobuf.Duration
|
||||
+ 34, // 15: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.request_timeout:type_name -> google.protobuf.Duration
|
||||
+ 34, // 16: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.request_headers_timeout:type_name -> google.protobuf.Duration
|
||||
+ 34, // 17: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.drain_timeout:type_name -> google.protobuf.Duration
|
||||
+ 34, // 18: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.delayed_close_timeout:type_name -> google.protobuf.Duration
|
||||
+ 35, // 19: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.access_log:type_name -> envoy.config.accesslog.v3.AccessLog
|
||||
+ 27, // 20: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.use_remote_address:type_name -> google.protobuf.BoolValue
|
||||
+ 36, // 21: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.original_ip_detection_extensions:type_name -> envoy.config.core.v3.TypedExtensionConfig
|
||||
16, // 22: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.internal_address_config:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.InternalAddressConfig
|
||||
- 25, // 23: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.generate_request_id:type_name -> google.protobuf.BoolValue
|
||||
+ 27, // 23: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.generate_request_id:type_name -> google.protobuf.BoolValue
|
||||
2, // 24: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.forward_client_cert_details:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.ForwardClientCertDetails
|
||||
17, // 25: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.set_current_client_cert_details:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.SetCurrentClientCertDetails
|
||||
18, // 26: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.upgrade_configs:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.UpgradeConfig
|
||||
- 25, // 27: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.normalize_path:type_name -> google.protobuf.BoolValue
|
||||
+ 27, // 27: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.normalize_path:type_name -> google.protobuf.BoolValue
|
||||
3, // 28: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.path_with_escaped_slashes_action:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.PathWithEscapedSlashesAction
|
||||
13, // 29: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.request_id_extension:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.RequestIDExtension
|
||||
6, // 30: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.local_reply_config:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.LocalReplyConfig
|
||||
- 25, // 31: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.stream_error_on_invalid_http_message:type_name -> google.protobuf.BoolValue
|
||||
+ 27, // 31: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.stream_error_on_invalid_http_message:type_name -> google.protobuf.BoolValue
|
||||
19, // 32: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.path_normalization_options:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.PathNormalizationOptions
|
||||
7, // 33: envoy.extensions.filters.network.http_connection_manager.v3.LocalReplyConfig.mappers:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.ResponseMapper
|
||||
- 35, // 34: envoy.extensions.filters.network.http_connection_manager.v3.LocalReplyConfig.body_format:type_name -> envoy.config.core.v3.SubstitutionFormatString
|
||||
- 36, // 35: envoy.extensions.filters.network.http_connection_manager.v3.ResponseMapper.filter:type_name -> envoy.config.accesslog.v3.AccessLogFilter
|
||||
- 31, // 36: envoy.extensions.filters.network.http_connection_manager.v3.ResponseMapper.status_code:type_name -> google.protobuf.UInt32Value
|
||||
- 37, // 37: envoy.extensions.filters.network.http_connection_manager.v3.ResponseMapper.body:type_name -> envoy.config.core.v3.DataSource
|
||||
- 35, // 38: envoy.extensions.filters.network.http_connection_manager.v3.ResponseMapper.body_format_override:type_name -> envoy.config.core.v3.SubstitutionFormatString
|
||||
- 38, // 39: envoy.extensions.filters.network.http_connection_manager.v3.ResponseMapper.headers_to_add:type_name -> envoy.config.core.v3.HeaderValueOption
|
||||
- 39, // 40: envoy.extensions.filters.network.http_connection_manager.v3.Rds.config_source:type_name -> envoy.config.core.v3.ConfigSource
|
||||
- 40, // 41: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRouteConfigurationsList.scoped_route_configurations:type_name -> envoy.config.route.v3.ScopedRouteConfiguration
|
||||
+ 37, // 34: envoy.extensions.filters.network.http_connection_manager.v3.LocalReplyConfig.body_format:type_name -> envoy.config.core.v3.SubstitutionFormatString
|
||||
+ 38, // 35: envoy.extensions.filters.network.http_connection_manager.v3.ResponseMapper.filter:type_name -> envoy.config.accesslog.v3.AccessLogFilter
|
||||
+ 33, // 36: envoy.extensions.filters.network.http_connection_manager.v3.ResponseMapper.status_code:type_name -> google.protobuf.UInt32Value
|
||||
+ 39, // 37: envoy.extensions.filters.network.http_connection_manager.v3.ResponseMapper.body:type_name -> envoy.config.core.v3.DataSource
|
||||
+ 37, // 38: envoy.extensions.filters.network.http_connection_manager.v3.ResponseMapper.body_format_override:type_name -> envoy.config.core.v3.SubstitutionFormatString
|
||||
+ 40, // 39: envoy.extensions.filters.network.http_connection_manager.v3.ResponseMapper.headers_to_add:type_name -> envoy.config.core.v3.HeaderValueOption
|
||||
+ 41, // 40: envoy.extensions.filters.network.http_connection_manager.v3.Rds.config_source:type_name -> envoy.config.core.v3.ConfigSource
|
||||
+ 42, // 41: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRouteConfigurationsList.scoped_route_configurations:type_name -> envoy.config.route.v3.ScopedRouteConfiguration
|
||||
20, // 42: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.scope_key_builder:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder
|
||||
- 39, // 43: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.rds_config_source:type_name -> envoy.config.core.v3.ConfigSource
|
||||
+ 41, // 43: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.rds_config_source:type_name -> envoy.config.core.v3.ConfigSource
|
||||
9, // 44: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.scoped_route_configurations_list:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.ScopedRouteConfigurationsList
|
||||
11, // 45: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.scoped_rds:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.ScopedRds
|
||||
- 39, // 46: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRds.scoped_rds_config_source:type_name -> envoy.config.core.v3.ConfigSource
|
||||
- 41, // 47: envoy.extensions.filters.network.http_connection_manager.v3.HttpFilter.typed_config:type_name -> google.protobuf.Any
|
||||
- 42, // 48: envoy.extensions.filters.network.http_connection_manager.v3.HttpFilter.config_discovery:type_name -> envoy.config.core.v3.ExtensionConfigSource
|
||||
- 41, // 49: envoy.extensions.filters.network.http_connection_manager.v3.RequestIDExtension.typed_config:type_name -> google.protobuf.Any
|
||||
+ 41, // 46: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRds.scoped_rds_config_source:type_name -> envoy.config.core.v3.ConfigSource
|
||||
+ 43, // 47: envoy.extensions.filters.network.http_connection_manager.v3.HttpFilter.typed_config:type_name -> google.protobuf.Any
|
||||
+ 44, // 48: envoy.extensions.filters.network.http_connection_manager.v3.HttpFilter.config_discovery:type_name -> envoy.config.core.v3.ExtensionConfigSource
|
||||
+ 43, // 49: envoy.extensions.filters.network.http_connection_manager.v3.RequestIDExtension.typed_config:type_name -> google.protobuf.Any
|
||||
5, // 50: envoy.extensions.filters.network.http_connection_manager.v3.EnvoyMobileHttpConnectionManager.config:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
|
||||
- 43, // 51: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.Tracing.client_sampling:type_name -> envoy.type.v3.Percent
|
||||
- 43, // 52: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.Tracing.random_sampling:type_name -> envoy.type.v3.Percent
|
||||
- 43, // 53: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.Tracing.overall_sampling:type_name -> envoy.type.v3.Percent
|
||||
- 31, // 54: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.Tracing.max_path_tag_length:type_name -> google.protobuf.UInt32Value
|
||||
- 44, // 55: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.Tracing.custom_tags:type_name -> envoy.type.tracing.v3.CustomTag
|
||||
- 45, // 56: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.Tracing.provider:type_name -> envoy.config.trace.v3.Tracing.Http
|
||||
- 25, // 57: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.SetCurrentClientCertDetails.subject:type_name -> google.protobuf.BoolValue
|
||||
+ 45, // 51: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.Tracing.client_sampling:type_name -> envoy.type.v3.Percent
|
||||
+ 45, // 52: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.Tracing.random_sampling:type_name -> envoy.type.v3.Percent
|
||||
+ 45, // 53: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.Tracing.overall_sampling:type_name -> envoy.type.v3.Percent
|
||||
+ 33, // 54: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.Tracing.max_path_tag_length:type_name -> google.protobuf.UInt32Value
|
||||
+ 46, // 55: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.Tracing.custom_tags:type_name -> envoy.type.tracing.v3.CustomTag
|
||||
+ 47, // 56: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.Tracing.provider:type_name -> envoy.config.trace.v3.Tracing.Http
|
||||
+ 27, // 57: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.SetCurrentClientCertDetails.subject:type_name -> google.protobuf.BoolValue
|
||||
12, // 58: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.UpgradeConfig.filters:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.HttpFilter
|
||||
- 25, // 59: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.UpgradeConfig.enabled:type_name -> google.protobuf.BoolValue
|
||||
- 46, // 60: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.PathNormalizationOptions.forwarding_transformation:type_name -> envoy.type.http.v3.PathTransformation
|
||||
- 46, // 61: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.PathNormalizationOptions.http_filter_transformation:type_name -> envoy.type.http.v3.PathTransformation
|
||||
+ 27, // 59: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.UpgradeConfig.enabled:type_name -> google.protobuf.BoolValue
|
||||
+ 48, // 60: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.PathNormalizationOptions.forwarding_transformation:type_name -> envoy.type.http.v3.PathTransformation
|
||||
+ 48, // 61: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.PathNormalizationOptions.http_filter_transformation:type_name -> envoy.type.http.v3.PathTransformation
|
||||
21, // 62: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder.fragments:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder.FragmentBuilder
|
||||
22, // 63: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder.FragmentBuilder.header_value_extractor:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder.FragmentBuilder.HeaderValueExtractor
|
||||
- 23, // 64: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder.FragmentBuilder.HeaderValueExtractor.element:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder.FragmentBuilder.HeaderValueExtractor.KvElement
|
||||
- 65, // [65:65] is the sub-list for method output_type
|
||||
- 65, // [65:65] is the sub-list for method input_type
|
||||
- 65, // [65:65] is the sub-list for extension type_name
|
||||
- 65, // [65:65] is the sub-list for extension extendee
|
||||
- 0, // [0:65] is the sub-list for field type_name
|
||||
+ 23, // 64: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder.FragmentBuilder.host_value_extractor:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder.FragmentBuilder.HostValueExtractor
|
||||
+ 24, // 65: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder.FragmentBuilder.local_port_value_extractor:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder.FragmentBuilder.LocalPortValueExtractor
|
||||
+ 25, // 66: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder.FragmentBuilder.HeaderValueExtractor.element:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder.FragmentBuilder.HeaderValueExtractor.KvElement
|
||||
+ 33, // 67: envoy.extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder.FragmentBuilder.HostValueExtractor.max_recompute_num:type_name -> google.protobuf.UInt32Value
|
||||
+ 68, // [68:68] is the sub-list for method output_type
|
||||
+ 68, // [68:68] is the sub-list for method input_type
|
||||
+ 68, // [68:68] is the sub-list for extension type_name
|
||||
+ 68, // [68:68] is the sub-list for extension extendee
|
||||
+ 0, // [0:68] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -3625,6 +3793,30 @@
|
||||
}
|
||||
}
|
||||
file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
|
||||
+ switch v := v.(*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor); i {
|
||||
+ case 0:
|
||||
+ return &v.state
|
||||
+ case 1:
|
||||
+ return &v.sizeCache
|
||||
+ case 2:
|
||||
+ return &v.unknownFields
|
||||
+ default:
|
||||
+ return nil
|
||||
+ }
|
||||
+ }
|
||||
+ file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
|
||||
+ switch v := v.(*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor); i {
|
||||
+ case 0:
|
||||
+ return &v.state
|
||||
+ case 1:
|
||||
+ return &v.sizeCache
|
||||
+ case 2:
|
||||
+ return &v.unknownFields
|
||||
+ default:
|
||||
+ return nil
|
||||
+ }
|
||||
+ }
|
||||
+ file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
@@ -3653,6 +3845,8 @@
|
||||
}
|
||||
file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_msgTypes[16].OneofWrappers = []interface{}{
|
||||
(*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_)(nil),
|
||||
+ (*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor_)(nil),
|
||||
+ (*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor_)(nil),
|
||||
}
|
||||
file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_msgTypes[17].OneofWrappers = []interface{}{
|
||||
(*ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_Index)(nil),
|
||||
@@ -3664,7 +3858,7 @@
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_envoy_extensions_filters_network_http_connection_manager_v3_http_connection_manager_proto_rawDesc,
|
||||
NumEnums: 5,
|
||||
- NumMessages: 19,
|
||||
+ NumMessages: 21,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
diff -Naur go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.validate.go go-control-plane-new/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.validate.go
|
||||
--- go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.validate.go 2024-01-04 21:07:22.000000000 +0800
|
||||
+++ go-control-plane-new/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.validate.go 2024-01-04 21:02:10.000000000 +0800
|
||||
@@ -1986,6 +1986,30 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ case *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor_:
|
||||
+
|
||||
+ if v, ok := interface{}(m.GetHostValueExtractor()).(interface{ Validate() error }); ok {
|
||||
+ if err := v.Validate(); err != nil {
|
||||
+ return ScopedRoutes_ScopeKeyBuilder_FragmentBuilderValidationError{
|
||||
+ field: "HostValueExtractor",
|
||||
+ reason: "embedded message failed validation",
|
||||
+ cause: err,
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ case *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor_:
|
||||
+
|
||||
+ if v, ok := interface{}(m.GetLocalPortValueExtractor()).(interface{ Validate() error }); ok {
|
||||
+ if err := v.Validate(); err != nil {
|
||||
+ return ScopedRoutes_ScopeKeyBuilder_FragmentBuilderValidationError{
|
||||
+ field: "LocalPortValueExtractor",
|
||||
+ reason: "embedded message failed validation",
|
||||
+ cause: err,
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
default:
|
||||
return ScopedRoutes_ScopeKeyBuilder_FragmentBuilderValidationError{
|
||||
field: "Type",
|
||||
@@ -2162,6 +2186,172 @@
|
||||
} = ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractorValidationError{}
|
||||
|
||||
// Validate checks the field values on
|
||||
+// ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor with the
|
||||
+// rules defined in the proto definition for this message. If any rules are
|
||||
+// violated, an error is returned.
|
||||
+func (m *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor) Validate() error {
|
||||
+ if m == nil {
|
||||
+ return nil
|
||||
+ }
|
||||
+
|
||||
+ if v, ok := interface{}(m.GetMaxRecomputeNum()).(interface{ Validate() error }); ok {
|
||||
+ if err := v.Validate(); err != nil {
|
||||
+ return ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractorValidationError{
|
||||
+ field: "MaxRecomputeNum",
|
||||
+ reason: "embedded message failed validation",
|
||||
+ cause: err,
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return nil
|
||||
+}
|
||||
+
|
||||
+// ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractorValidationError
|
||||
+// is the validation error returned by
|
||||
+// ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor.Validate if
|
||||
+// the designated constraints aren't met.
|
||||
+type ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractorValidationError struct {
|
||||
+ field string
|
||||
+ reason string
|
||||
+ cause error
|
||||
+ key bool
|
||||
+}
|
||||
+
|
||||
+// Field function returns field value.
|
||||
+func (e ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractorValidationError) Field() string {
|
||||
+ return e.field
|
||||
+}
|
||||
+
|
||||
+// Reason function returns reason value.
|
||||
+func (e ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractorValidationError) Reason() string {
|
||||
+ return e.reason
|
||||
+}
|
||||
+
|
||||
+// Cause function returns cause value.
|
||||
+func (e ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractorValidationError) Cause() error {
|
||||
+ return e.cause
|
||||
+}
|
||||
+
|
||||
+// Key function returns key value.
|
||||
+func (e ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractorValidationError) Key() bool {
|
||||
+ return e.key
|
||||
+}
|
||||
+
|
||||
+// ErrorName returns error name.
|
||||
+func (e ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractorValidationError) ErrorName() string {
|
||||
+ return "ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractorValidationError"
|
||||
+}
|
||||
+
|
||||
+// Error satisfies the builtin error interface
|
||||
+func (e ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractorValidationError) Error() string {
|
||||
+ cause := ""
|
||||
+ if e.cause != nil {
|
||||
+ cause = fmt.Sprintf(" | caused by: %v", e.cause)
|
||||
+ }
|
||||
+
|
||||
+ key := ""
|
||||
+ if e.key {
|
||||
+ key = "key for "
|
||||
+ }
|
||||
+
|
||||
+ return fmt.Sprintf(
|
||||
+ "invalid %sScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor.%s: %s%s",
|
||||
+ key,
|
||||
+ e.field,
|
||||
+ e.reason,
|
||||
+ cause)
|
||||
+}
|
||||
+
|
||||
+var _ error = ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractorValidationError{}
|
||||
+
|
||||
+var _ interface {
|
||||
+ Field() string
|
||||
+ Reason() string
|
||||
+ Key() bool
|
||||
+ Cause() error
|
||||
+ ErrorName() string
|
||||
+} = ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractorValidationError{}
|
||||
+
|
||||
+// Validate checks the field values on
|
||||
+// ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor with
|
||||
+// the rules defined in the proto definition for this message. If any rules
|
||||
+// are violated, an error is returned.
|
||||
+func (m *ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor) Validate() error {
|
||||
+ if m == nil {
|
||||
+ return nil
|
||||
+ }
|
||||
+
|
||||
+ return nil
|
||||
+}
|
||||
+
|
||||
+// ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractorValidationError
|
||||
+// is the validation error returned by
|
||||
+// ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor.Validate
|
||||
+// if the designated constraints aren't met.
|
||||
+type ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractorValidationError struct {
|
||||
+ field string
|
||||
+ reason string
|
||||
+ cause error
|
||||
+ key bool
|
||||
+}
|
||||
+
|
||||
+// Field function returns field value.
|
||||
+func (e ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractorValidationError) Field() string {
|
||||
+ return e.field
|
||||
+}
|
||||
+
|
||||
+// Reason function returns reason value.
|
||||
+func (e ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractorValidationError) Reason() string {
|
||||
+ return e.reason
|
||||
+}
|
||||
+
|
||||
+// Cause function returns cause value.
|
||||
+func (e ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractorValidationError) Cause() error {
|
||||
+ return e.cause
|
||||
+}
|
||||
+
|
||||
+// Key function returns key value.
|
||||
+func (e ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractorValidationError) Key() bool {
|
||||
+ return e.key
|
||||
+}
|
||||
+
|
||||
+// ErrorName returns error name.
|
||||
+func (e ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractorValidationError) ErrorName() string {
|
||||
+ return "ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractorValidationError"
|
||||
+}
|
||||
+
|
||||
+// Error satisfies the builtin error interface
|
||||
+func (e ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractorValidationError) Error() string {
|
||||
+ cause := ""
|
||||
+ if e.cause != nil {
|
||||
+ cause = fmt.Sprintf(" | caused by: %v", e.cause)
|
||||
+ }
|
||||
+
|
||||
+ key := ""
|
||||
+ if e.key {
|
||||
+ key = "key for "
|
||||
+ }
|
||||
+
|
||||
+ return fmt.Sprintf(
|
||||
+ "invalid %sScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor.%s: %s%s",
|
||||
+ key,
|
||||
+ e.field,
|
||||
+ e.reason,
|
||||
+ cause)
|
||||
+}
|
||||
+
|
||||
+var _ error = ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractorValidationError{}
|
||||
+
|
||||
+var _ interface {
|
||||
+ Field() string
|
||||
+ Reason() string
|
||||
+ Key() bool
|
||||
+ Cause() error
|
||||
+ ErrorName() string
|
||||
+} = ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractorValidationError{}
|
||||
+
|
||||
+// Validate checks the field values on
|
||||
// ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement
|
||||
// with the rules defined in the proto definition for this message. If any
|
||||
// rules are violated, an error is returned.
|
||||
3
go.mod
3
go.mod
@@ -238,6 +238,8 @@ require (
|
||||
github.com/spf13/cast v1.3.1 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/theupdateframework/notary v0.7.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/tonistiigi/fsutil v0.0.0-20220930225714-4638ad635be5 // indirect
|
||||
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
|
||||
github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3 // indirect
|
||||
@@ -302,6 +304,7 @@ require (
|
||||
github.com/evanphx/json-patch/v5 v5.6.0
|
||||
github.com/google/yamlfmt v0.10.0
|
||||
github.com/kylelemons/godebug v1.1.0
|
||||
github.com/tidwall/gjson v1.17.0
|
||||
helm.sh/helm/v3 v3.7.1
|
||||
k8s.io/apiextensions-apiserver v0.25.4
|
||||
knative.dev/networking v0.0.0-20220302134042-e8b2eb995165
|
||||
|
||||
6
go.sum
6
go.sum
@@ -1582,6 +1582,12 @@ github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIU
|
||||
github.com/theupdateframework/notary v0.6.1/go.mod h1:MOfgIfmox8s7/7fduvB2xyPPMJCrjRLRizA8OFwpnKY=
|
||||
github.com/theupdateframework/notary v0.7.0 h1:QyagRZ7wlSpjT5N2qQAh/pN+DVqgekv4DzbAiAiEL3c=
|
||||
github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnHqbFDGRSlXPO0AhYWw=
|
||||
github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
|
||||
github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
apiVersion: v2
|
||||
appVersion: 1.3.1
|
||||
appVersion: 1.3.4-rc.1
|
||||
description: Helm chart for deploying higress gateways
|
||||
icon: https://higress.io/img/higress_logo_small.png
|
||||
home: http://higress.io/
|
||||
@@ -10,4 +10,4 @@ name: higress-core
|
||||
sources:
|
||||
- http://github.com/alibaba/higress
|
||||
type: application
|
||||
version: 1.3.1
|
||||
version: 1.3.4-rc.1
|
||||
|
||||
@@ -31,11 +31,7 @@ spec:
|
||||
containers:
|
||||
{{- if not .Values.global.enableHigressIstio }}
|
||||
- name: discovery
|
||||
{{- if contains "/" .Values.pilot.image }}
|
||||
image: "{{ .Values.pilot.image }}"
|
||||
{{- else }}
|
||||
image: "{{ .Values.pilot.hub | default .Values.global.hub }}/{{ .Values.pilot.image | default "pilot" }}:{{ .Values.pilot.tag | default .Chart.AppVersion }}"
|
||||
{{- end }}
|
||||
{{- if .Values.global.imagePullPolicy }}
|
||||
imagePullPolicy: {{ .Values.global.imagePullPolicy }}
|
||||
{{- end }}
|
||||
@@ -74,6 +70,12 @@ spec:
|
||||
periodSeconds: 3
|
||||
timeoutSeconds: 5
|
||||
env:
|
||||
- name: ENBALE_SCOPED_RDS
|
||||
value: "{{ .Values.global.enableSRDS }}"
|
||||
- name: ON_DEMAND_RDS
|
||||
value: "{{ .Values.global.onDemandRDS }}"
|
||||
- name: HOST_RDS_MERGE_SUBSET
|
||||
value: "{{ .Values.global.hostRDSMergeSubset }}"
|
||||
- name: PILOT_FILTER_GATEWAY_CLUSTER_CONFIG
|
||||
value: "{{ .Values.global.onlyPushRouteCluster }}"
|
||||
- name: HIGRESS_CONTROLLER_SVC
|
||||
@@ -184,7 +186,7 @@ spec:
|
||||
- name: {{ .Chart.Name }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.controller.securityContext | nindent 12 }}
|
||||
image: "{{ .Values.hub }}/{{ .Values.controller.image }}:{{ .Values.controller.tag | default .Chart.AppVersion }}"
|
||||
image: "{{ .Values.controller.hub | default .Values.global.hub }}/{{ .Values.controller.image | default "higress" }}:{{ .Values.controller.tag | default .Chart.AppVersion }}"
|
||||
args:
|
||||
- "serve"
|
||||
- --gatewaySelectorKey=higress
|
||||
|
||||
@@ -68,7 +68,7 @@ spec:
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: higress-gateway
|
||||
image: "{{ .Values.hub }}/{{ .Values.gateway.image }}:{{ .Values.gateway.tag | default .Chart.AppVersion }}"
|
||||
image: "{{ .Values.gateway.hub | default .Values.global.hub }}/{{ .Values.gateway.image | default "gateway" }}:{{ .Values.gateway.tag | default .Chart.AppVersion }}"
|
||||
args:
|
||||
- proxy
|
||||
- router
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
revision: ""
|
||||
global:
|
||||
enableSRDS: false
|
||||
onDemandRDS: true
|
||||
hostRDSMergeSubset: true
|
||||
onlyPushRouteCluster: true
|
||||
# IngressClass filters which ingress resources the higress controller watches.
|
||||
# The default ingress class is higress.
|
||||
@@ -369,6 +372,8 @@ gateway:
|
||||
name: "higress-gateway"
|
||||
replicas: 2
|
||||
image: gateway
|
||||
|
||||
hub: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress
|
||||
tag: ""
|
||||
# revision declares which revision this gateway is a part of
|
||||
revision: ""
|
||||
@@ -457,6 +462,8 @@ controller:
|
||||
name: "higress-controller"
|
||||
replicas: 1
|
||||
image: higress
|
||||
|
||||
hub: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress
|
||||
tag: ""
|
||||
env: {}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
dependencies:
|
||||
- name: higress-core
|
||||
repository: file://../core
|
||||
version: 1.3.1
|
||||
version: 1.3.4-rc.1
|
||||
- name: higress-console
|
||||
repository: https://higress.io/helm-charts/
|
||||
version: 1.3.1
|
||||
digest: sha256:980abd3f62b107970555051be7e57dd8d8b69821fe163daa9f3c84521881a05b
|
||||
generated: "2023-11-16T11:09:23.463473+08:00"
|
||||
digest: sha256:cdd2b6e7023f505c5a7d4851d2a7bdb999e11f19508661f07e1f862918c5e793
|
||||
generated: "2024-01-11T17:40:17.045364+08:00"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
apiVersion: v2
|
||||
appVersion: 1.3.1
|
||||
appVersion: 1.3.4-rc.1
|
||||
description: Helm chart for deploying Higress gateways
|
||||
icon: https://higress.io/img/higress_logo_small.png
|
||||
home: http://higress.io/
|
||||
@@ -12,9 +12,9 @@ sources:
|
||||
dependencies:
|
||||
- name: higress-core
|
||||
repository: "file://../core"
|
||||
version: 1.3.1
|
||||
version: 1.3.4-rc.1
|
||||
- name: higress-console
|
||||
repository: "https://higress.io/helm-charts/"
|
||||
version: 1.3.1
|
||||
type: application
|
||||
version: 1.3.1
|
||||
version: 1.3.4-rc.1
|
||||
|
||||
633
istio/1.12/patches/istio/20240104-enhance-srds.patch
Normal file
633
istio/1.12/patches/istio/20240104-enhance-srds.patch
Normal file
@@ -0,0 +1,633 @@
|
||||
diff -Naur istio/pilot/pkg/features/pilot.go istio-new/pilot/pkg/features/pilot.go
|
||||
--- istio/pilot/pkg/features/pilot.go 2024-01-05 17:58:08.000000000 +0800
|
||||
+++ istio-new/pilot/pkg/features/pilot.go 2024-01-04 21:20:00.000000000 +0800
|
||||
@@ -569,6 +569,12 @@
|
||||
// Added by ingress
|
||||
CustomCACertConfigMapName = env.RegisterStringVar("CUSTOM_CA_CERT_NAME", "",
|
||||
"Defines the configmap's name of istio's root ca certificate").Get()
|
||||
+ HostRDSMergeSubset = env.RegisterBoolVar("HOST_RDS_MERGE_SUBSET", true,
|
||||
+ "If enabled, if host A is a subset of B, then we merge B's routes into A's hostRDS").Get()
|
||||
+ EnableScopedRDS = env.RegisterBoolVar("ENBALE_SCOPED_RDS", true,
|
||||
+ "If enabled, each host in virtualservice will have an independent RDS, which is used with SRDS").Get()
|
||||
+ OnDemandRDS = env.RegisterBoolVar("ON_DEMAND_RDS", false,
|
||||
+ "If enabled, the on demand filter will be added to the HCM filters").Get()
|
||||
// End added by ingress
|
||||
)
|
||||
|
||||
diff -Naur istio/pilot/pkg/networking/core/configgen.go istio-new/pilot/pkg/networking/core/configgen.go
|
||||
--- istio/pilot/pkg/networking/core/configgen.go 2024-01-05 17:58:02.000000000 +0800
|
||||
+++ istio-new/pilot/pkg/networking/core/configgen.go 2024-01-04 21:20:00.000000000 +0800
|
||||
@@ -17,6 +17,7 @@
|
||||
import (
|
||||
core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
|
||||
listener "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
|
||||
+ route "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
||||
discovery "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
|
||||
|
||||
meshconfig "istio.io/api/mesh/v1alpha1"
|
||||
@@ -44,6 +45,10 @@
|
||||
// BuildHTTPRoutes returns the list of HTTP routes for the given proxy. This is the RDS output
|
||||
BuildHTTPRoutes(node *model.Proxy, req *model.PushRequest, routeNames []string) ([]*discovery.Resource, model.XdsLogDetails)
|
||||
|
||||
+ // Added by ingress
|
||||
+ BuildScopedRoutes(node *model.Proxy, push *model.PushContext) []*route.ScopedRouteConfiguration
|
||||
+ // End added by ingress
|
||||
+
|
||||
// BuildNameTable returns list of hostnames and the associated IPs
|
||||
BuildNameTable(node *model.Proxy, push *model.PushContext) *dnsProto.NameTable
|
||||
|
||||
diff -Naur istio/pilot/pkg/networking/core/v1alpha3/gateway.go istio-new/pilot/pkg/networking/core/v1alpha3/gateway.go
|
||||
--- istio/pilot/pkg/networking/core/v1alpha3/gateway.go 2024-01-05 17:58:07.000000000 +0800
|
||||
+++ istio-new/pilot/pkg/networking/core/v1alpha3/gateway.go 2024-01-05 11:19:54.000000000 +0800
|
||||
@@ -41,7 +41,9 @@
|
||||
"istio.io/istio/pilot/pkg/networking/plugin"
|
||||
"istio.io/istio/pilot/pkg/networking/util"
|
||||
authn_model "istio.io/istio/pilot/pkg/security/model"
|
||||
+ "istio.io/istio/pilot/pkg/util/sets"
|
||||
"istio.io/istio/pkg/config"
|
||||
+ "istio.io/istio/pkg/config/constants"
|
||||
"istio.io/istio/pkg/config/gateway"
|
||||
"istio.io/istio/pkg/config/host"
|
||||
"istio.io/istio/pkg/config/protocol"
|
||||
@@ -104,10 +106,15 @@
|
||||
// We can also have QUIC on a given port along with HTTPS/TLS on a given port. It does not
|
||||
// cause port-conflict as they use different transport protocols
|
||||
opts := &buildListenerOpts{
|
||||
- push: builder.push,
|
||||
- proxy: builder.node,
|
||||
- bind: bind,
|
||||
- port: &model.Port{Port: int(port.Number)},
|
||||
+ push: builder.push,
|
||||
+ proxy: builder.node,
|
||||
+ bind: bind,
|
||||
+ port: &model.Port{
|
||||
+ Port: int(port.Number),
|
||||
+ // Added by ingress
|
||||
+ Protocol: protocol.Parse(port.Protocol),
|
||||
+ // End added by ingress
|
||||
+ },
|
||||
bindToPort: true,
|
||||
class: istionetworking.ListenerClassGateway,
|
||||
transport: transport,
|
||||
@@ -340,6 +347,269 @@
|
||||
return nameToServiceMap
|
||||
}
|
||||
|
||||
+// Added by ingress
|
||||
+func (configgen *ConfigGeneratorImpl) BuildScopedRoutes(node *model.Proxy, push *model.PushContext) []*route.ScopedRouteConfiguration {
|
||||
+ if node.MergedGateway == nil {
|
||||
+ log.Warnf("buildScopedRoutes: no gateways for router %v", node.ID)
|
||||
+ return nil
|
||||
+ }
|
||||
+ merged := node.MergedGateway
|
||||
+ var out []*route.ScopedRouteConfiguration
|
||||
+ gatewayVirtualServices := make(map[string][]config.Config)
|
||||
+ serverIterator := func(listenerPort int, mergedServers map[model.ServerPort]*model.MergedServers) sets.Set {
|
||||
+ hostSet := sets.NewSet()
|
||||
+ for port, servers := range mergedServers {
|
||||
+ if port.Number != uint32(listenerPort) {
|
||||
+ continue
|
||||
+ }
|
||||
+ for _, server := range servers.Servers {
|
||||
+ gatewayName := merged.GatewayNameForServer[server]
|
||||
+
|
||||
+ var virtualServices []config.Config
|
||||
+ var exists bool
|
||||
+
|
||||
+ if virtualServices, exists = gatewayVirtualServices[gatewayName]; !exists {
|
||||
+ virtualServices = push.VirtualServicesForGateway(node, gatewayName)
|
||||
+ gatewayVirtualServices[gatewayName] = virtualServices
|
||||
+ }
|
||||
+ for _, virtualService := range virtualServices {
|
||||
+ for _, host := range virtualService.Spec.(*networking.VirtualService).Hosts {
|
||||
+ hostSet.Insert(host)
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return hostSet
|
||||
+ }
|
||||
+ buildPortHostScopedRoute := func(listenerPort model.ServerPort) {
|
||||
+ p := protocol.Parse(listenerPort.Protocol)
|
||||
+ if !p.IsHTTP() && p != protocol.HTTPS {
|
||||
+ return
|
||||
+ }
|
||||
+ port := strconv.Itoa(int(listenerPort.Number))
|
||||
+ hostSet := serverIterator(int(listenerPort.Number), merged.MergedServers).
|
||||
+ Union(serverIterator(int(listenerPort.Number), merged.MergedQUICTransportServers))
|
||||
+ for host, _ := range hostSet {
|
||||
+ portKey := &route.ScopedRouteConfiguration_Key_Fragment{
|
||||
+ Type: &route.ScopedRouteConfiguration_Key_Fragment_StringKey{
|
||||
+ StringKey: port,
|
||||
+ },
|
||||
+ }
|
||||
+ hostKey := &route.ScopedRouteConfiguration_Key_Fragment{
|
||||
+ Type: &route.ScopedRouteConfiguration_Key_Fragment_StringKey{
|
||||
+ StringKey: host,
|
||||
+ },
|
||||
+ }
|
||||
+ name := strings.Join([]string{port, host}, ".")
|
||||
+ out = append(out, &route.ScopedRouteConfiguration{
|
||||
+ OnDemand: features.OnDemandRDS,
|
||||
+ Name: name,
|
||||
+ RouteConfigurationName: constants.HigressHostRDSNamePrefix + name,
|
||||
+ Key: &route.ScopedRouteConfiguration_Key{
|
||||
+ Fragments: []*route.ScopedRouteConfiguration_Key_Fragment{portKey, hostKey},
|
||||
+ },
|
||||
+ })
|
||||
+ }
|
||||
+ }
|
||||
+ for _, port := range merged.ServerPorts {
|
||||
+ buildPortHostScopedRoute(port)
|
||||
+ }
|
||||
+ return out
|
||||
+}
|
||||
+
|
||||
+type virtualServiceContext struct {
|
||||
+ virtualService config.Config
|
||||
+ server *networking.Server
|
||||
+ gatewayName string
|
||||
+}
|
||||
+
|
||||
+func (configgen *ConfigGeneratorImpl) buildHostRDSConfig(node *model.Proxy, push *model.PushContext,
|
||||
+ routeName string) *route.RouteConfiguration {
|
||||
+ var (
|
||||
+ hostRDSPort string
|
||||
+ hostRDSHost string
|
||||
+ )
|
||||
+ portAndHost := strings.SplitN(strings.TrimPrefix(routeName, constants.HigressHostRDSNamePrefix), ".", 2)
|
||||
+ if len(portAndHost) != 2 {
|
||||
+ log.Errorf("Invalid route %s when using Higress hostRDS", routeName)
|
||||
+ return nil
|
||||
+ }
|
||||
+ hostRDSPort = portAndHost[0]
|
||||
+ hostRDSHost = portAndHost[1]
|
||||
+ merged := node.MergedGateway
|
||||
+ log.Debugf("buildGatewayRoutes: gateways after merging: %v", merged)
|
||||
+ rdsPort, err := strconv.Atoi(hostRDSPort)
|
||||
+ if err != nil {
|
||||
+ log.Errorf("Invalid port %s of route %s when using Higress hostRDS", hostRDSPort, routeName)
|
||||
+ return nil
|
||||
+ }
|
||||
+ listenerPort := uint32(rdsPort)
|
||||
+ globalHTTPFilters := mseingress.ExtractGlobalHTTPFilters(node, push)
|
||||
+
|
||||
+ isH3DiscoveryNeeded := false
|
||||
+
|
||||
+ // When this is true, we add alt-svc header to the response to tell the client
|
||||
+ // that HTTP/3 over QUIC is available on the same port for this host. This is
|
||||
+ // very important for discovering HTTP/3 services
|
||||
+ for port, servers := range merged.MergedQUICTransportServers {
|
||||
+ if port.Number == listenerPort && len(servers.Servers) > 0 {
|
||||
+ isH3DiscoveryNeeded = true
|
||||
+ break
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ gatewayRoutes := make(map[string]map[string][]*route.Route)
|
||||
+ gatewayVirtualServices := make(map[string][]config.Config)
|
||||
+ var selectedVirtualServices []virtualServiceContext
|
||||
+ var vHost *route.VirtualHost
|
||||
+ serverIterator := func(mergedServers map[model.ServerPort]*model.MergedServers) {
|
||||
+ for port, servers := range mergedServers {
|
||||
+ if port.Number != listenerPort {
|
||||
+ continue
|
||||
+ }
|
||||
+ for _, server := range servers.Servers {
|
||||
+ gatewayName := merged.GatewayNameForServer[server]
|
||||
+
|
||||
+ var virtualServices []config.Config
|
||||
+ var exists bool
|
||||
+
|
||||
+ if virtualServices, exists = gatewayVirtualServices[gatewayName]; !exists {
|
||||
+ virtualServices = push.VirtualServicesForGateway(node, gatewayName)
|
||||
+ gatewayVirtualServices[gatewayName] = virtualServices
|
||||
+ }
|
||||
+ for _, virtualService := range virtualServices {
|
||||
+ hostMatch := false
|
||||
+ var selectHost string
|
||||
+ virtualServiceHosts := host.NewNames(virtualService.Spec.(*networking.VirtualService).Hosts)
|
||||
+ for _, hostname := range virtualServiceHosts {
|
||||
+ // exact match
|
||||
+ if hostname == host.Name(hostRDSHost) {
|
||||
+ hostMatch = true
|
||||
+ selectHost = hostRDSHost
|
||||
+ break
|
||||
+ }
|
||||
+ if features.HostRDSMergeSubset {
|
||||
+ // subset match
|
||||
+ if host.Name(hostRDSHost).SubsetOf(hostname) {
|
||||
+ hostMatch = true
|
||||
+ selectHost = string(hostname)
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ if !hostMatch {
|
||||
+ continue
|
||||
+ }
|
||||
+ copiedVS := virtualService.DeepCopy()
|
||||
+ copiedVS.Spec.(*networking.VirtualService).Hosts = []string{selectHost}
|
||||
+ selectedVirtualServices = append(selectedVirtualServices, virtualServiceContext{
|
||||
+ virtualService: copiedVS,
|
||||
+ server: server,
|
||||
+ gatewayName: gatewayName,
|
||||
+ })
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ serverIterator(merged.MergedServers)
|
||||
+ serverIterator(merged.MergedQUICTransportServers)
|
||||
+ // Sort by subset
|
||||
+ // before: ["*.abc.com", "*.com", "www.abc.com"]
|
||||
+ // after: ["www.abc.com", "*.abc.com", "*.com"]
|
||||
+ sort.SliceStable(selectedVirtualServices, func(i, j int) bool {
|
||||
+ return host.Name(selectedVirtualServices[i].virtualService.Spec.(*networking.VirtualService).Hosts[0]).SubsetOf(
|
||||
+ host.Name(selectedVirtualServices[j].virtualService.Spec.(*networking.VirtualService).Hosts[0]))
|
||||
+ })
|
||||
+ port := int(listenerPort)
|
||||
+ for _, ctx := range selectedVirtualServices {
|
||||
+ virtualService := ctx.virtualService
|
||||
+ server := ctx.server
|
||||
+ gatewayName := ctx.gatewayName
|
||||
+ // Make sure we can obtain services which are visible to this virtualService as much as possible.
|
||||
+ nameToServiceMap := buildNameToServiceMapForHTTPRoutes(node, push, virtualService)
|
||||
+
|
||||
+ var routes []*route.Route
|
||||
+ var exists bool
|
||||
+ var err error
|
||||
+ if _, exists = gatewayRoutes[gatewayName]; !exists {
|
||||
+ gatewayRoutes[gatewayName] = make(map[string][]*route.Route)
|
||||
+ }
|
||||
+
|
||||
+ vskey := virtualService.Name + "/" + virtualService.Namespace
|
||||
+
|
||||
+ if routes, exists = gatewayRoutes[gatewayName][vskey]; !exists {
|
||||
+ hashByDestination := istio_route.GetConsistentHashForVirtualService(push, node, virtualService, nameToServiceMap)
|
||||
+ routes, err = istio_route.BuildHTTPRoutesForVirtualServiceWithHTTPFilters(node, virtualService, nameToServiceMap,
|
||||
+ hashByDestination, port, map[string]bool{gatewayName: true}, isH3DiscoveryNeeded, push.Mesh, globalHTTPFilters)
|
||||
+ if err != nil {
|
||||
+ log.Debugf("%s omitting routes for virtual service %v/%v due to error: %v", node.ID, virtualService.Namespace, virtualService.Name, err)
|
||||
+ continue
|
||||
+ }
|
||||
+ gatewayRoutes[gatewayName][vskey] = routes
|
||||
+ }
|
||||
+
|
||||
+ if vHost != nil {
|
||||
+ vHost.Routes = append(vHost.Routes, routes...)
|
||||
+ if server.Tls != nil && server.Tls.HttpsRedirect {
|
||||
+ vHost.RequireTls = route.VirtualHost_ALL
|
||||
+ }
|
||||
+ } else {
|
||||
+ vHost = &route.VirtualHost{
|
||||
+ Name: util.DomainName(hostRDSHost, port),
|
||||
+ Domains: buildGatewayVirtualHostDomains(hostRDSHost, port),
|
||||
+ Routes: routes,
|
||||
+ IncludeRequestAttemptCount: true,
|
||||
+ TypedPerFilterConfig: mseingress.ConstructTypedPerFilterConfigForVHost(globalHTTPFilters, virtualService),
|
||||
+ }
|
||||
+ if server.Tls != nil && server.Tls.HttpsRedirect {
|
||||
+ vHost.RequireTls = route.VirtualHost_ALL
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // check all hostname if is not exist with HttpsRedirect set to true
|
||||
+ // create VirtualHost to redirect
|
||||
+ for _, hostname := range server.Hosts {
|
||||
+ if !server.GetTls().GetHttpsRedirect() {
|
||||
+ continue
|
||||
+ }
|
||||
+ if vHost != nil && host.Name(hostname) == host.Name(hostRDSHost) {
|
||||
+ vHost.RequireTls = route.VirtualHost_ALL
|
||||
+ continue
|
||||
+ }
|
||||
+ vHost = &route.VirtualHost{
|
||||
+ Name: util.DomainName(hostname, port),
|
||||
+ Domains: buildGatewayVirtualHostDomains(hostname, port),
|
||||
+ IncludeRequestAttemptCount: true,
|
||||
+ RequireTls: route.VirtualHost_ALL,
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ }
|
||||
+ var virtualHosts []*route.VirtualHost
|
||||
+ if vHost == nil {
|
||||
+ log.Warnf("constructed http route config for route %s on port %d with no vhosts; Setting up a default 404 vhost", routeName, port)
|
||||
+ virtualHosts = []*route.VirtualHost{{
|
||||
+ Name: util.DomainName("blackhole", port),
|
||||
+ Domains: []string{"*"},
|
||||
+ // Empty route list will cause Envoy to 404 NR any requests
|
||||
+ Routes: []*route.Route{},
|
||||
+ }}
|
||||
+ } else {
|
||||
+ vHost.Routes = istio_route.CombineVHostRoutes(vHost.Routes)
|
||||
+ virtualHosts = append(virtualHosts, vHost)
|
||||
+ }
|
||||
+
|
||||
+ routeCfg := &route.RouteConfiguration{
|
||||
+ // Retain the routeName as its used by EnvoyFilter patching logic
|
||||
+ Name: routeName,
|
||||
+ VirtualHosts: virtualHosts,
|
||||
+ ValidateClusters: proto.BoolFalse,
|
||||
+ }
|
||||
+
|
||||
+ return routeCfg
|
||||
+}
|
||||
+
|
||||
+// End added by ingress
|
||||
+
|
||||
func (configgen *ConfigGeneratorImpl) buildGatewayHTTPRouteConfig(node *model.Proxy, push *model.PushContext,
|
||||
routeName string) *route.RouteConfiguration {
|
||||
if node.MergedGateway == nil {
|
||||
@@ -351,6 +621,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ // Added by ingress
|
||||
+ if strings.HasPrefix(routeName, constants.HigressHostRDSNamePrefix) {
|
||||
+ return configgen.buildHostRDSConfig(node, push, routeName)
|
||||
+ }
|
||||
+ // End added by ingress
|
||||
+
|
||||
merged := node.MergedGateway
|
||||
log.Debugf("buildGatewayRoutes: gateways after merging: %v", merged)
|
||||
|
||||
@@ -670,7 +946,9 @@
|
||||
// TLS mode | Mesh-wide SDS | Ingress SDS | Resulting Configuration
|
||||
// SIMPLE/MUTUAL | ENABLED | ENABLED | support SDS at ingress gateway to terminate SSL communication outside the mesh
|
||||
// ISTIO_MUTUAL | ENABLED | DISABLED | support SDS at gateway to terminate workload mTLS, with internal workloads
|
||||
-// | for egress or with another trusted cluster for ingress)
|
||||
+//
|
||||
+// | for egress or with another trusted cluster for ingress)
|
||||
+//
|
||||
// ISTIO_MUTUAL | DISABLED | DISABLED | use file-mounted secret paths to terminate workload mTLS from gateway
|
||||
//
|
||||
// Note that ISTIO_MUTUAL TLS mode and ingressSds should not be used simultaneously on the same ingress gateway.
|
||||
diff -Naur istio/pilot/pkg/networking/core/v1alpha3/listener.go istio-new/pilot/pkg/networking/core/v1alpha3/listener.go
|
||||
--- istio/pilot/pkg/networking/core/v1alpha3/listener.go 2024-01-05 17:58:07.000000000 +0800
|
||||
+++ istio-new/pilot/pkg/networking/core/v1alpha3/listener.go 2024-01-05 17:31:10.000000000 +0800
|
||||
@@ -1279,8 +1279,48 @@
|
||||
|
||||
notimeout := durationpb.New(0 * time.Second)
|
||||
connectionManager.StreamIdleTimeout = notimeout
|
||||
-
|
||||
- if httpOpts.rds != "" {
|
||||
+ // Added by ingress
|
||||
+ enableSRDS := false
|
||||
+ if features.EnableScopedRDS &&
|
||||
+ (listenerOpts.port.Protocol.IsHTTP() || (listenerOpts.port.Protocol == protocol.HTTPS)) {
|
||||
+ enableSRDS = true
|
||||
+ portFragment := &hcm.ScopedRoutes_ScopeKeyBuilder_FragmentBuilder{
|
||||
+ Type: &hcm.ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor_{
|
||||
+ LocalPortValueExtractor: &hcm.ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_LocalPortValueExtractor{},
|
||||
+ }}
|
||||
+ hostFragment := &hcm.ScopedRoutes_ScopeKeyBuilder_FragmentBuilder{
|
||||
+ Type: &hcm.ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor_{
|
||||
+ HostValueExtractor: &hcm.ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HostValueExtractor{},
|
||||
+ }}
|
||||
+ scopedRoutes := &hcm.HttpConnectionManager_ScopedRoutes{
|
||||
+ ScopedRoutes: &hcm.ScopedRoutes{
|
||||
+ Name: constants.DefaultScopedRouteName,
|
||||
+ ScopeKeyBuilder: &hcm.ScopedRoutes_ScopeKeyBuilder{
|
||||
+ Fragments: []*hcm.ScopedRoutes_ScopeKeyBuilder_FragmentBuilder{portFragment, hostFragment},
|
||||
+ },
|
||||
+ RdsConfigSource: &core.ConfigSource{
|
||||
+ ConfigSourceSpecifier: &core.ConfigSource_Ads{
|
||||
+ Ads: &core.AggregatedConfigSource{},
|
||||
+ },
|
||||
+ InitialFetchTimeout: durationpb.New(0),
|
||||
+ ResourceApiVersion: core.ApiVersion_V3,
|
||||
+ },
|
||||
+ ConfigSpecifier: &hcm.ScopedRoutes_ScopedRds{
|
||||
+ ScopedRds: &hcm.ScopedRds{
|
||||
+ ScopedRdsConfigSource: &core.ConfigSource{
|
||||
+ ConfigSourceSpecifier: &core.ConfigSource_Ads{
|
||||
+ Ads: &core.AggregatedConfigSource{},
|
||||
+ },
|
||||
+ InitialFetchTimeout: durationpb.New(0),
|
||||
+ ResourceApiVersion: core.ApiVersion_V3,
|
||||
+ },
|
||||
+ },
|
||||
+ },
|
||||
+ },
|
||||
+ }
|
||||
+ connectionManager.RouteSpecifier = scopedRoutes
|
||||
+ } else if httpOpts.rds != "" {
|
||||
+ // End added by ingress
|
||||
rds := &hcm.HttpConnectionManager_Rds{
|
||||
Rds: &hcm.Rds{
|
||||
ConfigSource: &core.ConfigSource{
|
||||
@@ -1304,8 +1344,15 @@
|
||||
|
||||
filters := make([]*hcm.HttpFilter, len(httpFilters))
|
||||
copy(filters, httpFilters)
|
||||
- // Make sure cors filter always in the first.
|
||||
- filters = append([]*hcm.HttpFilter{xdsfilters.Cors}, filters...)
|
||||
+ // Added by ingress
|
||||
+ // Now only support onDemandRDS when enable SRDS
|
||||
+ if features.OnDemandRDS && enableSRDS {
|
||||
+ filters = append([]*hcm.HttpFilter{xdsfilters.OnDemand, xdsfilters.Cors}, filters...)
|
||||
+ } else {
|
||||
+ // End added by ingress
|
||||
+ // Make sure cors filter always in the first.
|
||||
+ filters = append([]*hcm.HttpFilter{xdsfilters.Cors}, filters...)
|
||||
+ }
|
||||
|
||||
if features.MetadataExchange {
|
||||
filters = append(filters, xdsfilters.HTTPMx)
|
||||
diff -Naur istio/pilot/pkg/xds/ads.go istio-new/pilot/pkg/xds/ads.go
|
||||
--- istio/pilot/pkg/xds/ads.go 2024-01-05 17:58:08.000000000 +0800
|
||||
+++ istio-new/pilot/pkg/xds/ads.go 2024-01-05 17:31:44.000000000 +0800
|
||||
@@ -797,15 +797,18 @@
|
||||
|
||||
// PushOrder defines the order that updates will be pushed in. Any types not listed here will be pushed in random
|
||||
// order after the types listed here
|
||||
-var PushOrder = []string{v3.ClusterType, v3.EndpointType, v3.ListenerType, v3.RouteType, v3.SecretType}
|
||||
+var PushOrder = []string{v3.ClusterType, v3.EndpointType, v3.ListenerType, v3.ScopedRouteType, v3.RouteType, v3.SecretType}
|
||||
|
||||
// KnownOrderedTypeUrls has typeUrls for which we know the order of push.
|
||||
var KnownOrderedTypeUrls = map[string]struct{}{
|
||||
v3.ClusterType: {},
|
||||
v3.EndpointType: {},
|
||||
v3.ListenerType: {},
|
||||
- v3.RouteType: {},
|
||||
- v3.SecretType: {},
|
||||
+ // Added by ingress
|
||||
+ v3.ScopedRouteType: {},
|
||||
+ // End added by ingress
|
||||
+ v3.RouteType: {},
|
||||
+ v3.SecretType: {},
|
||||
}
|
||||
|
||||
// orderWatchedResources orders the resources in accordance with known push order.
|
||||
diff -Naur istio/pilot/pkg/xds/discovery.go istio-new/pilot/pkg/xds/discovery.go
|
||||
--- istio/pilot/pkg/xds/discovery.go 2024-01-05 17:58:07.000000000 +0800
|
||||
+++ istio-new/pilot/pkg/xds/discovery.go 2024-01-04 21:20:00.000000000 +0800
|
||||
@@ -589,6 +589,9 @@
|
||||
s.Generators[v3.ClusterType] = &CdsGenerator{Server: s}
|
||||
s.Generators[v3.ListenerType] = &LdsGenerator{Server: s}
|
||||
s.Generators[v3.RouteType] = &RdsGenerator{Server: s}
|
||||
+ // Added by ingress
|
||||
+ s.Generators[v3.ScopedRouteType] = &SrdsGenerator{Server: s}
|
||||
+ // End added by ingress
|
||||
s.Generators[v3.EndpointType] = edsGen
|
||||
s.Generators[v3.NameTableType] = &NdsGenerator{Server: s}
|
||||
s.Generators[v3.ExtensionConfigurationType] = &EcdsGenerator{Server: s}
|
||||
diff -Naur istio/pilot/pkg/xds/filters/filters.go istio-new/pilot/pkg/xds/filters/filters.go
|
||||
--- istio/pilot/pkg/xds/filters/filters.go 2024-01-05 17:58:03.000000000 +0800
|
||||
+++ istio-new/pilot/pkg/xds/filters/filters.go 2024-01-04 21:20:00.000000000 +0800
|
||||
@@ -21,6 +21,7 @@
|
||||
fault "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/fault/v3"
|
||||
grpcstats "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/grpc_stats/v3"
|
||||
grpcweb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/grpc_web/v3"
|
||||
+ ondemand "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/on_demand/v3"
|
||||
router "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/router/v3"
|
||||
httpwasm "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/wasm/v3"
|
||||
httpinspector "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/listener/http_inspector/v3"
|
||||
@@ -54,6 +55,14 @@
|
||||
// Define static filters to be reused across the codebase. This avoids duplicate marshaling/unmarshaling
|
||||
// This should not be used for filters that will be mutated
|
||||
var (
|
||||
+ // Added by ingress
|
||||
+ OnDemand = &hcm.HttpFilter{
|
||||
+ Name: "envoy.filters.http.on_demand.v3.OnDemand",
|
||||
+ ConfigType: &hcm.HttpFilter_TypedConfig{
|
||||
+ TypedConfig: util.MessageToAny(&ondemand.OnDemand{}),
|
||||
+ },
|
||||
+ }
|
||||
+ // End added by ingress
|
||||
Cors = &hcm.HttpFilter{
|
||||
Name: wellknown.CORS,
|
||||
ConfigType: &hcm.HttpFilter_TypedConfig{
|
||||
diff -Naur istio/pilot/pkg/xds/srds.go istio-new/pilot/pkg/xds/srds.go
|
||||
--- istio/pilot/pkg/xds/srds.go 1970-01-01 08:00:00.000000000 +0800
|
||||
+++ istio-new/pilot/pkg/xds/srds.go 2024-01-05 13:45:49.000000000 +0800
|
||||
@@ -0,0 +1,79 @@
|
||||
+// Copyright Istio Authors
|
||||
+//
|
||||
+// Licensed 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 xds
|
||||
+
|
||||
+import (
|
||||
+ discovery "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
|
||||
+ "istio.io/istio/pilot/pkg/features"
|
||||
+ "istio.io/istio/pilot/pkg/model"
|
||||
+ "istio.io/istio/pilot/pkg/networking/util"
|
||||
+ "istio.io/istio/pkg/config"
|
||||
+ "istio.io/istio/pkg/config/schema/gvk"
|
||||
+)
|
||||
+
|
||||
+type SrdsGenerator struct {
|
||||
+ Server *DiscoveryServer
|
||||
+}
|
||||
+
|
||||
+var _ model.XdsResourceGenerator = &SrdsGenerator{}
|
||||
+
|
||||
+// Map of all configs that do not impact SRDS
|
||||
+var skippedSrdsConfigs = map[config.GroupVersionKind]struct{}{
|
||||
+ gvk.WorkloadEntry: {},
|
||||
+ gvk.WorkloadGroup: {},
|
||||
+ gvk.RequestAuthentication: {},
|
||||
+ gvk.PeerAuthentication: {},
|
||||
+ gvk.Secret: {},
|
||||
+}
|
||||
+
|
||||
+func srdsNeedsPush(req *model.PushRequest) bool {
|
||||
+ if !features.EnableScopedRDS {
|
||||
+ return false
|
||||
+ }
|
||||
+ if req == nil {
|
||||
+ return true
|
||||
+ }
|
||||
+ if !req.Full {
|
||||
+ // SRDS only handles full push
|
||||
+ return false
|
||||
+ }
|
||||
+ // If none set, we will always push
|
||||
+ if len(req.ConfigsUpdated) == 0 {
|
||||
+ return true
|
||||
+ }
|
||||
+ for config := range req.ConfigsUpdated {
|
||||
+ if _, f := skippedSrdsConfigs[config.Kind]; !f {
|
||||
+ return true
|
||||
+ }
|
||||
+ }
|
||||
+ return false
|
||||
+}
|
||||
+
|
||||
+func (s SrdsGenerator) Generate(proxy *model.Proxy, push *model.PushContext, w *model.WatchedResource,
|
||||
+ req *model.PushRequest) (model.Resources, model.XdsLogDetails, error) {
|
||||
+ if !srdsNeedsPush(req) {
|
||||
+ return nil, model.DefaultXdsLogDetails, nil
|
||||
+ }
|
||||
+
|
||||
+ scopedRoutes := s.Server.ConfigGenerator.BuildScopedRoutes(proxy, push)
|
||||
+ resources := model.Resources{}
|
||||
+ for _, sr := range scopedRoutes {
|
||||
+ resources = append(resources, &discovery.Resource{
|
||||
+ Name: sr.Name,
|
||||
+ Resource: util.MessageToAny(sr),
|
||||
+ })
|
||||
+ }
|
||||
+ return resources, model.DefaultXdsLogDetails, nil
|
||||
+}
|
||||
diff -Naur istio/pilot/pkg/xds/v3/model.go istio-new/pilot/pkg/xds/v3/model.go
|
||||
--- istio/pilot/pkg/xds/v3/model.go 2024-01-05 17:58:03.000000000 +0800
|
||||
+++ istio-new/pilot/pkg/xds/v3/model.go 2024-01-05 16:55:49.000000000 +0800
|
||||
@@ -31,6 +31,10 @@
|
||||
SecretType = resource.SecretType
|
||||
ExtensionConfigurationType = resource.ExtensionConfigType
|
||||
|
||||
+ // Added by ingress
|
||||
+ ScopedRouteType = apiTypePrefix + "envoy.config.route.v3.ScopedRouteConfiguration"
|
||||
+ // End added by ingress
|
||||
+
|
||||
NameTableType = apiTypePrefix + "istio.networking.nds.v1.NameTable"
|
||||
HealthInfoType = apiTypePrefix + "istio.v1.HealthInformation"
|
||||
ProxyConfigType = apiTypePrefix + "istio.mesh.v1alpha1.ProxyConfig"
|
||||
@@ -61,6 +65,10 @@
|
||||
return "PCDS"
|
||||
case ExtensionConfigurationType:
|
||||
return "ECDS"
|
||||
+ // Added by ingress
|
||||
+ case ScopedRouteType:
|
||||
+ return "SRDS"
|
||||
+ // End added by ingress
|
||||
default:
|
||||
return typeURL
|
||||
}
|
||||
@@ -87,6 +95,10 @@
|
||||
return "ecds"
|
||||
case BootstrapType:
|
||||
return "bds"
|
||||
+ // Added by ingress
|
||||
+ case ScopedRouteType:
|
||||
+ return "srds"
|
||||
+ // End added by ingress
|
||||
default:
|
||||
return typeURL
|
||||
}
|
||||
diff -Naur istio/pkg/config/constants/constants.go istio-new/pkg/config/constants/constants.go
|
||||
--- istio/pkg/config/constants/constants.go 2024-01-05 17:58:08.000000000 +0800
|
||||
+++ istio-new/pkg/config/constants/constants.go 2024-01-04 21:20:00.000000000 +0800
|
||||
@@ -143,4 +143,9 @@
|
||||
// CertProviderNone does not create any certificates for the control plane. It is assumed that some external
|
||||
// load balancer, such as an Istio Gateway, is terminating the TLS.
|
||||
CertProviderNone = "none"
|
||||
+
|
||||
+ // Added by ingress
|
||||
+ HigressHostRDSNamePrefix = "higress-rds-"
|
||||
+ DefaultScopedRouteName = "scoped-route"
|
||||
+ // End added by ingress
|
||||
)
|
||||
338
pkg/cmd/hgctl/code_debug.go
Normal file
338
pkg/cmd/hgctl/code_debug.go
Normal file
@@ -0,0 +1,338 @@
|
||||
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
//
|
||||
// Licensed 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 hgctl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/helm"
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultIp = "127.0.0.1"
|
||||
DefaultPort = ":15051"
|
||||
)
|
||||
|
||||
func newCodeDebugCmd() *cobra.Command {
|
||||
codeDebugCmd := &cobra.Command{
|
||||
Use: "code-debug",
|
||||
Short: "Start or stop code debug",
|
||||
}
|
||||
|
||||
codeDebugCmd.AddCommand(getStartCodeDebugCmd())
|
||||
codeDebugCmd.AddCommand(getStopCodeDebugCmd())
|
||||
|
||||
return codeDebugCmd
|
||||
}
|
||||
|
||||
func getStartCodeDebugCmd() *cobra.Command {
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
fmt.Printf("fail to get user home dir: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
kubeConfigDir := homeDir + "/.kube/config"
|
||||
|
||||
startCodeDebugCmd := &cobra.Command{
|
||||
Use: "start",
|
||||
Aliases: []string{"start"},
|
||||
Short: "Start code debug",
|
||||
Example: "hgctl code-debug start",
|
||||
RunE: func(c *cobra.Command, args []string) error {
|
||||
writer := c.OutOrStdout()
|
||||
|
||||
// wait for user to confirm
|
||||
if !promptCodeDebug(writer, "local grpc address") {
|
||||
return nil
|
||||
}
|
||||
|
||||
// check profile type is local or not
|
||||
fmt.Fprintf(writer, "Checking profile type...\n")
|
||||
profiles, err := getAllProfiles()
|
||||
if err != nil {
|
||||
return fmt.Errorf("fail to get all profiles: %v", err)
|
||||
}
|
||||
if len(profiles) == 0 {
|
||||
fmt.Fprintf(writer, "Higress hasn't been installed yet!\n")
|
||||
return nil
|
||||
}
|
||||
for _, profile := range profiles {
|
||||
if profile.Install != helm.InstallLocalK8s {
|
||||
fmt.Fprintf(writer, "\nHigress needs to be installed locally!\n")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// get kubernetes clientSet
|
||||
fmt.Fprintf(writer, "Getting kubernetes clientset...\n")
|
||||
config, err := clientcmd.BuildConfigFromFlags("", kubeConfigDir)
|
||||
if err != nil {
|
||||
fmt.Fprintf(writer, "fail to build config from kubeconfig: %v", err)
|
||||
return nil
|
||||
}
|
||||
clientSet, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
fmt.Fprintf(writer, "fail to create kubernetes clientset: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// get non-loopback IPv4 address
|
||||
fmt.Fprintf(writer, "Getting non-loopback IPv4 address...\n")
|
||||
ip, err := getNonLoopbackIPv4()
|
||||
if err != nil {
|
||||
fmt.Fprintf(writer, "fail to get non-loopback IPv4 address: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// update the xds address in higress-config ConfigMap
|
||||
// and trigger rollout for higress-controller and higress-gateway deployments
|
||||
fmt.Fprintf(writer, "Updating xds address in higress-config ConfigMap "+
|
||||
"and triggering rollout for higress-controller and higress-gateway deployments...\n")
|
||||
err = updateXdsIpAndRollout(clientSet, ip, DefaultPort)
|
||||
if err != nil {
|
||||
fmt.Fprintf(writer, "fail to update xds address in higress-config ConfigMap: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Fprintf(writer, "Code debug started!\n")
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
startCodeDebugCmd.PersistentFlags().StringVar(&kubeConfigDir, "kubeconfig", kubeConfigDir,
|
||||
"Use a Kubernetes configuration file instead of in-cluster configuration")
|
||||
|
||||
return startCodeDebugCmd
|
||||
}
|
||||
|
||||
func getStopCodeDebugCmd() *cobra.Command {
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
fmt.Printf("fail to get user home dir: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
kubeConfigDir := homeDir + "/.kube/config"
|
||||
|
||||
stopCodeDebugCmd := &cobra.Command{
|
||||
Use: "stop",
|
||||
Aliases: []string{"stop"},
|
||||
Short: "Stop code debug",
|
||||
Example: "hgctl code-debug stop",
|
||||
RunE: func(c *cobra.Command, args []string) error {
|
||||
// wait for user to confirm
|
||||
writer := c.OutOrStdout()
|
||||
if !promptCodeDebug(writer, "default grpc address") {
|
||||
return nil
|
||||
}
|
||||
|
||||
// check profile type is local or not
|
||||
fmt.Fprintf(writer, "Checking profile type...\n")
|
||||
profiles, err := getAllProfiles()
|
||||
if err != nil {
|
||||
return fmt.Errorf("fail to get all profiles: %v", err)
|
||||
}
|
||||
if len(profiles) == 0 {
|
||||
fmt.Fprintf(writer, "Higress hasn't been installed yet!\n")
|
||||
return nil
|
||||
}
|
||||
for _, profile := range profiles {
|
||||
if profile.Install != helm.InstallLocalK8s {
|
||||
fmt.Fprintf(writer, "\nHigress needs to be installed locally!\n")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// get kubernetes clientSet
|
||||
fmt.Fprintf(writer, "Getting kubernetes clientset...\n")
|
||||
config, err := clientcmd.BuildConfigFromFlags("", kubeConfigDir)
|
||||
if err != nil {
|
||||
fmt.Fprintf(writer, "fail to build config from kubeconfig: %v", err)
|
||||
return nil
|
||||
}
|
||||
clientSet, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
fmt.Fprintf(writer, "fail to create kubernetes clientset: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// recover the xds address in higress-config ConfigMap
|
||||
// and trigger rollout for higress-controller and higress-gateway deployments
|
||||
fmt.Fprintf(writer, "Recovering xds address in higress-config ConfigMap "+
|
||||
"and triggering rollout for higress-controller and higress-gateway deployments...\n")
|
||||
err = updateXdsIpAndRollout(clientSet, DefaultIp, DefaultPort)
|
||||
if err != nil {
|
||||
fmt.Fprintf(writer, "fail to recover xds address in higress-config ConfigMap: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Fprintf(writer, "Code debug stopped!\n")
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
stopCodeDebugCmd.PersistentFlags().StringVar(&kubeConfigDir, "kubeconfig", kubeConfigDir,
|
||||
"Use a Kubernetes configuration file instead of in-cluster configuration")
|
||||
|
||||
return stopCodeDebugCmd
|
||||
}
|
||||
|
||||
// getNonLoopbackIPv4 returns the first non-loopback IPv4 address of the host.
|
||||
func getNonLoopbackIPv4() (string, error) {
|
||||
// get all network interfaces
|
||||
interfaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// traverse all network interfaces
|
||||
for _, i := range interfaces {
|
||||
// exclude loopback interface and virtual interface
|
||||
if i.Flags&net.FlagLoopback == 0 && i.Flags&net.FlagUp != 0 {
|
||||
// get all addresses of the interface
|
||||
addrs, err := i.Addrs()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// traverse all addresses of the interface
|
||||
for _, addr := range addrs {
|
||||
// check the type of the address is IP address
|
||||
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
||||
// check the IP address is IPv4 address
|
||||
if ipnet.IP.To4() != nil {
|
||||
return ipnet.IP.String(), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("Non-loopback IPv4 address not found")
|
||||
}
|
||||
|
||||
// updateXdsIpAndRollout updates the xds address in higress-config ConfigMap
|
||||
// and triggers rollout for higress-controller and higress-gateway deployments
|
||||
// also can recover the xds address in higress-config ConfigMap
|
||||
func updateXdsIpAndRollout(c *kubernetes.Clientset, ip string, port string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// Get higress-config ConfigMap
|
||||
cm, err := c.CoreV1().ConfigMaps("higress-system").Get(ctx, "higress-config", metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Update mesh field in higress-config ConfigMap
|
||||
if _, ok := cm.Data["mesh"]; !ok {
|
||||
return fmt.Errorf("mesh not found in configmap higress-config")
|
||||
}
|
||||
mesh := cm.Data["mesh"]
|
||||
newMesh, err := replaceXDSAddress(mesh, ip, port)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cm.Data["mesh"] = newMesh
|
||||
|
||||
// Update higress-config ConfigMap
|
||||
_, err = c.CoreV1().ConfigMaps("higress-system").Update(ctx, cm, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Trigger rollout for higress-controller deployment
|
||||
err = triggerRollout(c, "higress-controller")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Trigger rollout for higress-gateway deployment
|
||||
err = triggerRollout(c, "higress-gateway")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// triggerRollout triggers rollout for the specified deployment
|
||||
func triggerRollout(clientset *kubernetes.Clientset, deploymentName string) error {
|
||||
deploymentsClient := clientset.AppsV1().Deployments("higress-system")
|
||||
|
||||
// Get the deployment
|
||||
deployment, err := deploymentsClient.Get(context.TODO(), deploymentName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Increment the deployment's revision to trigger a rollout
|
||||
deployment.Spec.Template.ObjectMeta.Labels["version"] = time.Now().Format("20060102150405")
|
||||
|
||||
// Update the deployment
|
||||
_, err = deploymentsClient.Update(context.TODO(), deployment, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// replaceXDSAddress replaces the xds address in the config string with new IP and Port
|
||||
func replaceXDSAddress(configString, newIP, newPort string) (string, error) {
|
||||
// define the regular expression to match xds address
|
||||
xdsRegex := regexp.MustCompile(`xds://[0-9.:]+`)
|
||||
|
||||
// find the first match
|
||||
match := xdsRegex.FindString(configString)
|
||||
if match == "" {
|
||||
// if no match, return error
|
||||
return "", fmt.Errorf("no xds address found in config string")
|
||||
}
|
||||
|
||||
// replace xds address with new IP and Port
|
||||
newXDSAddress := fmt.Sprintf("xds://%s%s", newIP, newPort)
|
||||
result := xdsRegex.ReplaceAllString(configString, newXDSAddress)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// promptCodeDebug prompts user to confirm code debug
|
||||
func promptCodeDebug(writer io.Writer, t string) bool {
|
||||
answer := ""
|
||||
for {
|
||||
fmt.Fprintf(writer, "This will start set xds address to %s in higress-config ConfigMap "+
|
||||
"and trigger rollout for higress-controller and higress-gateway deployments. \nProceed? (y/N)", t)
|
||||
fmt.Scanln(&answer)
|
||||
if answer == "y" {
|
||||
return true
|
||||
}
|
||||
if answer == "N" {
|
||||
fmt.Fprintf(writer, "Cancelled.\n")
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
232
pkg/cmd/hgctl/completion.go
Normal file
232
pkg/cmd/hgctl/completion.go
Normal file
@@ -0,0 +1,232 @@
|
||||
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
//
|
||||
// Licensed 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 hgctl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const completionDesc = `
|
||||
Generate autocompletion scripts for hgctl for the specified shell.
|
||||
`
|
||||
|
||||
const bashCompDesc = `
|
||||
Generate the autocompletion script for the bash shell.
|
||||
|
||||
This script depends on the 'bash-completion' package.
|
||||
If it is not installed already, you can install it via your OS's package manager.
|
||||
|
||||
To load completions in your current shell session:
|
||||
|
||||
source <(hgctl completion bash)
|
||||
|
||||
To load completions for every new session, execute once:
|
||||
|
||||
#### Linux:
|
||||
|
||||
hgctl completion bash > /etc/bash_completion.d/hgctl
|
||||
|
||||
#### macOS:
|
||||
|
||||
hgctl completion bash > $(brew --prefix)/etc/bash_completion.d/hgctl
|
||||
|
||||
You will need to start a new shell for this setup to take effect.
|
||||
`
|
||||
|
||||
const zshCompDesc = `
|
||||
Generate the autocompletion script for the zsh shell.
|
||||
|
||||
If shell completion is not already enabled in your environment you will need
|
||||
to enable it. You can execute the following once:
|
||||
|
||||
echo "autoload -U compinit; compinit" >> ~/.zshrc
|
||||
|
||||
To load completions in your current shell session:
|
||||
|
||||
source <(hgctl completion zsh); compdef _hgctl hgctl
|
||||
|
||||
To load completions for every new session, execute once:
|
||||
|
||||
#### Linux:
|
||||
|
||||
hgctl completion zsh > "${fpath[1]}/_hgctl"
|
||||
|
||||
#### macOS:
|
||||
|
||||
hgctl completion zsh > $(brew --prefix)/share/zsh/site-functions/_hgctl
|
||||
|
||||
You will need to start a new shell for this setup to take effect.
|
||||
`
|
||||
|
||||
const fishCompDesc = `
|
||||
Generate the autocompletion script for the fish shell.
|
||||
|
||||
To load completions in your current shell session:
|
||||
|
||||
hgctl completion fish | source
|
||||
|
||||
To load completions for every new session, execute once:
|
||||
|
||||
hgctl completion fish > ~/.config/fish/completions/hgctl.fish
|
||||
|
||||
You will need to start a new shell for this setup to take effect.
|
||||
`
|
||||
|
||||
const powershellCompDesc = `
|
||||
Generate the autocompletion script for powershell.
|
||||
|
||||
To load completions in your current shell session:
|
||||
|
||||
hgctl completion powershell | Out-String | Invoke-Expression
|
||||
|
||||
To load completions for every new session, add the output of the above command
|
||||
to your powershell profile.
|
||||
`
|
||||
|
||||
const (
|
||||
noDescFlagName = "no-descriptions"
|
||||
noDescFlagText = "disable completion descriptions"
|
||||
)
|
||||
|
||||
var disableCompDescriptions bool
|
||||
|
||||
// newCompletionCmd creates a new completion command for hgctl
|
||||
func newCompletionCmd(out io.Writer) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "completion",
|
||||
Short: "generate autocompletion scripts for the specified shell",
|
||||
Long: completionDesc,
|
||||
Args: cobra.NoArgs,
|
||||
}
|
||||
|
||||
bash := &cobra.Command{
|
||||
Use: "bash",
|
||||
Short: "generate autocompletion script for bash",
|
||||
Long: bashCompDesc,
|
||||
Args: cobra.NoArgs,
|
||||
ValidArgsFunction: noCompletions,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return runCompletionBash(out, cmd)
|
||||
},
|
||||
}
|
||||
bash.Flags().BoolVar(&disableCompDescriptions, noDescFlagName, false, noDescFlagText)
|
||||
|
||||
zsh := &cobra.Command{
|
||||
Use: "zsh",
|
||||
Short: "generate autocompletion script for zsh",
|
||||
Long: zshCompDesc,
|
||||
Args: cobra.NoArgs,
|
||||
ValidArgsFunction: noCompletions,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return runCompletionZsh(out, cmd)
|
||||
},
|
||||
}
|
||||
zsh.Flags().BoolVar(&disableCompDescriptions, noDescFlagName, false, noDescFlagText)
|
||||
|
||||
fish := &cobra.Command{
|
||||
Use: "fish",
|
||||
Short: "generate autocompletion script for fish",
|
||||
Long: fishCompDesc,
|
||||
Args: cobra.NoArgs,
|
||||
ValidArgsFunction: noCompletions,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return runCompletionFish(out, cmd)
|
||||
},
|
||||
}
|
||||
fish.Flags().BoolVar(&disableCompDescriptions, noDescFlagName, false, noDescFlagText)
|
||||
|
||||
powershell := &cobra.Command{
|
||||
Use: "powershell",
|
||||
Short: "generate autocompletion script for powershell",
|
||||
Long: powershellCompDesc,
|
||||
Args: cobra.NoArgs,
|
||||
ValidArgsFunction: noCompletions,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return runCompletionPowershell(out, cmd)
|
||||
},
|
||||
}
|
||||
powershell.Flags().BoolVar(&disableCompDescriptions, noDescFlagName, false, noDescFlagText)
|
||||
|
||||
cmd.AddCommand(bash, zsh, fish, powershell)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runCompletionBash(out io.Writer, cmd *cobra.Command) error {
|
||||
err := cmd.Root().GenBashCompletionV2(out, !disableCompDescriptions)
|
||||
|
||||
// In case the user renamed the hgctl binary, we hook the new binary name to the completion function
|
||||
if binary := filepath.Base(os.Args[0]); binary != "hgctl" {
|
||||
renamedBinaryHook := `
|
||||
# Hook the command used to generate the completion script
|
||||
# to the hgctl completion function to handle the case where
|
||||
# the user renamed the hgctl binary
|
||||
if [[ $(type -t compopt) = "builtin" ]]; then
|
||||
complete -o default -F __start_hgctl %[1]s
|
||||
else
|
||||
complete -o default -o nospace -F __start_hgctl %[1]s
|
||||
fi
|
||||
`
|
||||
fmt.Fprintf(out, renamedBinaryHook, binary)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func runCompletionZsh(out io.Writer, cmd *cobra.Command) error {
|
||||
var err error
|
||||
if disableCompDescriptions {
|
||||
err = cmd.Root().GenZshCompletionNoDesc(out)
|
||||
} else {
|
||||
err = cmd.Root().GenZshCompletion(out)
|
||||
}
|
||||
|
||||
// In case the user renamed the hgctl binary, we hook the new binary name to the completion function
|
||||
if binary := filepath.Base(os.Args[0]); binary != "hgctl" {
|
||||
renamedBinaryHook := `
|
||||
# Hook the command used to generate the completion script
|
||||
# to the hgctl completion function to handle the case where
|
||||
# the user renamed the hgctl binary
|
||||
compdef _hgctl %[1]s
|
||||
`
|
||||
fmt.Fprintf(out, renamedBinaryHook, binary)
|
||||
}
|
||||
|
||||
// Cobra doesn't source zsh completion file, explicitly doing it here
|
||||
fmt.Fprintf(out, "compdef _hgctl hgctl")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func runCompletionFish(out io.Writer, cmd *cobra.Command) error {
|
||||
return cmd.Root().GenFishCompletion(out, !disableCompDescriptions)
|
||||
}
|
||||
|
||||
func runCompletionPowershell(out io.Writer, cmd *cobra.Command) error {
|
||||
if disableCompDescriptions {
|
||||
return cmd.Root().GenPowerShellCompletion(out)
|
||||
}
|
||||
return cmd.Root().GenPowerShellCompletionWithDesc(out)
|
||||
}
|
||||
|
||||
// Function to disable file completion
|
||||
func noCompletions(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
@@ -17,6 +17,7 @@ package hgctl
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/alibaba/higress/cmd/hgctl/config"
|
||||
"github.com/spf13/cobra"
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
)
|
||||
@@ -45,21 +46,20 @@ func bootstrapConfigCmd() *cobra.Command {
|
||||
}
|
||||
|
||||
func runBootstrapConfig(c *cobra.Command, args []string) error {
|
||||
configDump, err := retrieveConfigDump(args, false)
|
||||
if len(args) != 0 {
|
||||
podName = args[0]
|
||||
}
|
||||
envoyConfig, err := config.GetEnvoyConfig(&config.GetEnvoyConfigOptions{
|
||||
PodName: podName,
|
||||
PodNamespace: podNamespace,
|
||||
BindAddress: bindAddress,
|
||||
Output: output,
|
||||
EnvoyConfigType: config.BootstrapEnvoyConfigType,
|
||||
IncludeEds: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bootstrap, err := GetXDSResource(BootstrapEnvoyConfigType, configDump)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out, err := formatGatewayConfig(bootstrap, output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = fmt.Fprintln(c.OutOrStdout(), string(out))
|
||||
_, err = fmt.Fprintln(c.OutOrStdout(), string(envoyConfig))
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -11,11 +11,13 @@
|
||||
// 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 hgctl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/alibaba/higress/cmd/hgctl/config"
|
||||
"github.com/spf13/cobra"
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
)
|
||||
@@ -44,21 +46,20 @@ func clusterConfigCmd() *cobra.Command {
|
||||
}
|
||||
|
||||
func runClusterConfig(c *cobra.Command, args []string) error {
|
||||
configDump, err := retrieveConfigDump(args, false)
|
||||
if len(args) != 0 {
|
||||
podName = args[0]
|
||||
}
|
||||
envoyConfig, err := config.GetEnvoyConfig(&config.GetEnvoyConfigOptions{
|
||||
PodName: podName,
|
||||
PodNamespace: podNamespace,
|
||||
BindAddress: bindAddress,
|
||||
Output: output,
|
||||
EnvoyConfigType: config.ClusterEnvoyConfigType,
|
||||
IncludeEds: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cluster, err := GetXDSResource(ClusterEnvoyConfigType, configDump)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out, err := formatGatewayConfig(cluster, output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = fmt.Fprintln(c.OutOrStdout(), string(out))
|
||||
_, err = fmt.Fprintln(c.OutOrStdout(), string(envoyConfig))
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -17,11 +17,23 @@ package hgctl
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/alibaba/higress/cmd/hgctl/config"
|
||||
"github.com/alibaba/higress/pkg/cmd/options"
|
||||
"github.com/spf13/cobra"
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
)
|
||||
|
||||
var (
|
||||
output string
|
||||
podName string
|
||||
podNamespace string
|
||||
)
|
||||
|
||||
const (
|
||||
defaultProxyAdminPort = 15000
|
||||
containerName = "envoy"
|
||||
)
|
||||
|
||||
func newConfigCommand() *cobra.Command {
|
||||
cfgCommand := &cobra.Command{
|
||||
Use: "gateway-config",
|
||||
@@ -69,11 +81,20 @@ func allConfigCmd() *cobra.Command {
|
||||
}
|
||||
|
||||
func runAllConfig(c *cobra.Command, args []string) error {
|
||||
configDump, err := retrieveConfigDump(args, true)
|
||||
if len(args) != 0 {
|
||||
podName = args[0]
|
||||
}
|
||||
envoyConfig, err := config.GetEnvoyConfig(&config.GetEnvoyConfigOptions{
|
||||
PodName: podName,
|
||||
PodNamespace: podNamespace,
|
||||
BindAddress: bindAddress,
|
||||
Output: output,
|
||||
EnvoyConfigType: config.AllEnvoyConfigType,
|
||||
IncludeEds: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = fmt.Fprintln(c.OutOrStdout(), string(configDump))
|
||||
_, err = fmt.Fprintln(c.OutOrStdout(), string(envoyConfig))
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package hgctl
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/alibaba/higress/cmd/hgctl/config"
|
||||
"github.com/spf13/cobra"
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
)
|
||||
@@ -45,21 +46,20 @@ func endpointConfigCmd() *cobra.Command {
|
||||
}
|
||||
|
||||
func runEndpointConfig(c *cobra.Command, args []string) error {
|
||||
configDump, err := retrieveConfigDump(args, true)
|
||||
if len(args) != 0 {
|
||||
podName = args[0]
|
||||
}
|
||||
envoyConfig, err := config.GetEnvoyConfig(&config.GetEnvoyConfigOptions{
|
||||
PodName: podName,
|
||||
PodNamespace: podNamespace,
|
||||
BindAddress: bindAddress,
|
||||
Output: output,
|
||||
EnvoyConfigType: config.EndpointEnvoyConfigType,
|
||||
IncludeEds: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
endpoint, err := GetXDSResource(EndpointEnvoyConfigType, configDump)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out, err := formatGatewayConfig(endpoint, output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = fmt.Fprintln(c.OutOrStdout(), string(out))
|
||||
_, err = fmt.Fprintln(c.OutOrStdout(), string(envoyConfig))
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package hgctl
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/alibaba/higress/cmd/hgctl/config"
|
||||
"github.com/spf13/cobra"
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
)
|
||||
@@ -45,21 +46,20 @@ func listenerConfigCmd() *cobra.Command {
|
||||
}
|
||||
|
||||
func runListenerConfig(c *cobra.Command, args []string) error {
|
||||
configDump, err := retrieveConfigDump(args, false)
|
||||
if len(args) != 0 {
|
||||
podName = args[0]
|
||||
}
|
||||
envoyConfig, err := config.GetEnvoyConfig(&config.GetEnvoyConfigOptions{
|
||||
PodName: podName,
|
||||
PodNamespace: podNamespace,
|
||||
BindAddress: bindAddress,
|
||||
Output: output,
|
||||
EnvoyConfigType: config.ListenerEnvoyConfigType,
|
||||
IncludeEds: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
listener, err := GetXDSResource(ListenerEnvoyConfigType, configDump)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out, err := formatGatewayConfig(listener, output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = fmt.Fprintln(c.OutOrStdout(), string(out))
|
||||
_, err = fmt.Fprintln(c.OutOrStdout(), string(envoyConfig))
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package hgctl
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/alibaba/higress/cmd/hgctl/config"
|
||||
"github.com/spf13/cobra"
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
)
|
||||
@@ -45,21 +46,20 @@ func routeConfigCmd() *cobra.Command {
|
||||
}
|
||||
|
||||
func runRouteConfig(c *cobra.Command, args []string) error {
|
||||
configDump, err := retrieveConfigDump(args, false)
|
||||
if len(args) != 0 {
|
||||
podName = args[0]
|
||||
}
|
||||
envoyConfig, err := config.GetEnvoyConfig(&config.GetEnvoyConfigOptions{
|
||||
PodName: podName,
|
||||
PodNamespace: podNamespace,
|
||||
BindAddress: bindAddress,
|
||||
Output: output,
|
||||
EnvoyConfigType: config.RouteEnvoyConfigType,
|
||||
IncludeEds: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
route, err := GetXDSResource(RouteEnvoyConfigType, configDump)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out, err := formatGatewayConfig(route, output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = fmt.Fprintln(c.OutOrStdout(), string(out))
|
||||
_, err = fmt.Fprintln(c.OutOrStdout(), string(envoyConfig))
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -15,15 +15,20 @@
|
||||
package hgctl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/kubernetes"
|
||||
"github.com/alibaba/higress/pkg/cmd/options"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/flags"
|
||||
types2 "github.com/docker/docker/api/types"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
@@ -49,6 +54,8 @@ var (
|
||||
envoyDashNs = ""
|
||||
|
||||
proxyAdminPort int
|
||||
|
||||
docker = false
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -81,6 +88,7 @@ func newDashboardCmd() *cobra.Command {
|
||||
"Default is true which means hgctl dashboard will always open a browser to view the dashboard.")
|
||||
dashboardCmd.PersistentFlags().StringVarP(&addonNamespace, "namespace", "n", "higress-system",
|
||||
"Namespace where the addon is running, if not specified, higress-system would be used")
|
||||
dashboardCmd.PersistentFlags().StringVarP(&bindAddress, "listen", "l", "localhost", "The address to bind to")
|
||||
|
||||
prom := promDashCmd()
|
||||
prom.PersistentFlags().IntVar(&promPort, "ui-port", defaultPrometheusPort, "The component dashboard UI port.")
|
||||
@@ -91,7 +99,7 @@ func newDashboardCmd() *cobra.Command {
|
||||
dashboardCmd.AddCommand(graf)
|
||||
|
||||
envoy := envoyDashCmd()
|
||||
envoy.PersistentFlags().StringVarP(&labelSelector, "selector", "l", "app=higress-gateway", "Label selector")
|
||||
envoy.PersistentFlags().StringVarP(&labelSelector, "selector", "s", "app=higress-gateway", "Label selector")
|
||||
envoy.PersistentFlags().StringVarP(&envoyDashNs, "namespace", "n", "",
|
||||
"Namespace where the addon is running, if not specified, higress-system would be used")
|
||||
envoy.PersistentFlags().IntVar(&proxyAdminPort, "ui-port", defaultProxyAdminPort, "The component dashboard UI port.")
|
||||
@@ -99,6 +107,7 @@ func newDashboardCmd() *cobra.Command {
|
||||
|
||||
consoleCmd := consoleDashCmd()
|
||||
consoleCmd.PersistentFlags().IntVar(&consolePort, "ui-port", defaultConsolePort, "The component dashboard UI port.")
|
||||
consoleCmd.PersistentFlags().BoolVar(&docker, "docker", false, "Search higress console from docker")
|
||||
dashboardCmd.AddCommand(consoleCmd)
|
||||
|
||||
controllerDebugCmd := controllerDebugCmd()
|
||||
@@ -156,18 +165,23 @@ func consoleDashCmd() *cobra.Command {
|
||||
hgctl dash console
|
||||
hgctl d console`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if docker {
|
||||
return accessDocker(cmd)
|
||||
}
|
||||
client, err := kubernetes.NewCLIClient(options.DefaultConfigFlags.ToRawKubeConfigLoader())
|
||||
if err != nil {
|
||||
return fmt.Errorf("build CLI client fail: %w", err)
|
||||
fmt.Printf("build kubernetes CLI client fail: %v\ntry to access docker container\n", err)
|
||||
return accessDocker(cmd)
|
||||
}
|
||||
|
||||
pl, err := client.PodsForSelector(addonNamespace, "app.kubernetes.io/name=higress-console")
|
||||
if err != nil {
|
||||
return fmt.Errorf("not able to locate console pod: %v", err)
|
||||
fmt.Printf("build kubernetes CLI client fail: %v\ntry to access docker container\n", err)
|
||||
return accessDocker(cmd)
|
||||
}
|
||||
|
||||
if len(pl.Items) < 1 {
|
||||
return errors.New("no higress console pods found")
|
||||
fmt.Printf("no higress console pods found\ntry to access docker container\n")
|
||||
return accessDocker(cmd)
|
||||
}
|
||||
|
||||
// only use the first pod in the list
|
||||
@@ -179,6 +193,32 @@ func consoleDashCmd() *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
// accessDocker access docker container
|
||||
func accessDocker(cmd *cobra.Command) error {
|
||||
dockerCli, err := command.NewDockerCli(command.WithCombinedStreams(os.Stdout))
|
||||
if err != nil {
|
||||
return fmt.Errorf("build docker CLI client fail: %w", err)
|
||||
}
|
||||
err = dockerCli.Initialize(flags.NewClientOptions())
|
||||
if err != nil {
|
||||
return fmt.Errorf("docker client initialize fail: %w", err)
|
||||
}
|
||||
apiClient := dockerCli.Client()
|
||||
list, err := apiClient.ContainerList(context.Background(), types2.ContainerListOptions{})
|
||||
for _, container := range list {
|
||||
for i, name := range container.Names {
|
||||
if strings.Contains(name, "higress-console") {
|
||||
port := container.Ports[i].PublicPort
|
||||
// not support define ip address
|
||||
url := fmt.Sprintf("http://localhost:%d", port)
|
||||
openBrowser(url, cmd.OutOrStdout(), browser)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors.New("no higress console container found")
|
||||
}
|
||||
|
||||
// port-forward to Higress System Grafana; open browser
|
||||
func grafanaDashCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
@@ -324,7 +364,7 @@ func portForward(podName, namespace, flavor, urlFormat, localAddress string, rem
|
||||
var err error
|
||||
for _, localPort := range portPrefs {
|
||||
var fw kubernetes.PortForwarder
|
||||
fw, err = kubernetes.NewLocalPortForwarder(client, types.NamespacedName{Namespace: namespace, Name: podName}, localPort, remotePort)
|
||||
fw, err = kubernetes.NewLocalPortForwarder(client, types.NamespacedName{Namespace: namespace, Name: podName}, localPort, remotePort, bindAddress)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not build port forwarder for %s: %v", flavor, err)
|
||||
}
|
||||
@@ -361,8 +401,6 @@ func ClosePortForwarderOnInterrupt(fw kubernetes.PortForwarder) {
|
||||
}
|
||||
|
||||
func openBrowser(url string, writer io.Writer, browser bool) {
|
||||
var err error
|
||||
|
||||
fmt.Fprintf(writer, "%s\n", url)
|
||||
|
||||
if !browser {
|
||||
@@ -372,16 +410,30 @@ func openBrowser(url string, writer io.Writer, browser bool) {
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
err = exec.Command("xdg-open", url).Start()
|
||||
openCommand(writer, "xdg-open", url)
|
||||
case "windows":
|
||||
err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
|
||||
openCommand(writer, "rundll32", "url.dll,FileProtocolHandler", url)
|
||||
case "darwin":
|
||||
err = exec.Command("open", url).Start()
|
||||
openCommand(writer, "open", url)
|
||||
default:
|
||||
fmt.Fprintf(writer, "Unsupported platform %q; open %s in your browser.\n", runtime.GOOS, url)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func openCommand(writer io.Writer, command string, args ...string) {
|
||||
_, err := exec.LookPath(command)
|
||||
if err != nil {
|
||||
fmt.Fprintf(writer, "Failed to open browser; open %s in your browser.\nError: %s\n", url, err.Error())
|
||||
if errors.Is(err, exec.ErrNotFound) {
|
||||
fmt.Fprintf(writer, "Could not open your browser. Please open it maually.\n")
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(writer, "Failed to open browser; open %s in your browser.\nError: %s\n", args[0], err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
err = exec.Command(command, args...).Start()
|
||||
if err != nil {
|
||||
fmt.Fprintf(writer, "Failed to open browser; open %s in your browser.\nError: %s\n", args[0], err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,7 +318,45 @@ func GenProfile(profileOrPath, fileOverlayYAML string, setFlags []string) (strin
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
finalProfile.InstallPackagePath = installPackagePath
|
||||
if len(installPackagePath) > 0 {
|
||||
finalProfile.InstallPackagePath = installPackagePath
|
||||
}
|
||||
|
||||
if finalProfile.Profile == "" {
|
||||
finalProfile.Profile = DefaultProfileName
|
||||
}
|
||||
return util.ToYAML(finalProfile), finalProfile, nil
|
||||
}
|
||||
|
||||
func GenProfileFromProfileContent(profileContent, fileOverlayYAML string, setFlags []string) (string, *Profile, error) {
|
||||
installPackagePath, err := getInstallPackagePath(fileOverlayYAML)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if sfp := GetValueForSetFlag(setFlags, "installPackagePath"); sfp != "" {
|
||||
// set flag installPackagePath has the highest precedence, if set.
|
||||
installPackagePath = sfp
|
||||
}
|
||||
|
||||
// Combine file and --set overlays and translate any K8s settings in values to Profile format
|
||||
overlayYAML, err := overlaySetFlagValues(fileOverlayYAML, setFlags)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
// Merge user file and --set flags.
|
||||
outYAML, err := util.OverlayYAML(profileContent, overlayYAML)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("could not overlay user config over base: %s", err)
|
||||
}
|
||||
|
||||
finalProfile, err := UnmarshalProfile(outYAML)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if len(installPackagePath) > 0 {
|
||||
finalProfile.InstallPackagePath = installPackagePath
|
||||
}
|
||||
|
||||
if finalProfile.Profile == "" {
|
||||
finalProfile.Profile = DefaultProfileName
|
||||
|
||||
@@ -35,6 +35,7 @@ const (
|
||||
type Profile struct {
|
||||
Profile string `json:"profile,omitempty"`
|
||||
InstallPackagePath string `json:"installPackagePath,omitempty"`
|
||||
HigressVersion string `json:"higressVersion,omitempty"`
|
||||
Global ProfileGlobal `json:"global,omitempty"`
|
||||
Console ProfileConsole `json:"console,omitempty"`
|
||||
Gateway ProfileGateway `json:"gateway,omitempty"`
|
||||
|
||||
@@ -17,6 +17,7 @@ package hgctl
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/helm"
|
||||
@@ -134,7 +135,7 @@ func install(writer io.Writer, iArgs *InstallArgs) error {
|
||||
return fmt.Errorf("generate config: %v", err)
|
||||
}
|
||||
|
||||
fmt.Fprintf(writer, "🧐 Validating Profile: \"%s\" \n", profileName)
|
||||
fmt.Fprintf(writer, "\n🧐 Validating Profile: \"%s\" \n", profileName)
|
||||
err = profile.Validate()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -144,6 +145,12 @@ func install(writer io.Writer, iArgs *InstallArgs) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to install manifests: %v", err)
|
||||
}
|
||||
|
||||
// Remove "~/.hgctl/profiles/install.yaml"
|
||||
if oldProfileName, isExisted := installer.GetInstalledYamlPath(); isExisted {
|
||||
_ = os.Remove(oldProfileName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ func (h *HigressComponent) Run() error {
|
||||
if err := h.renderer.Init(); err != nil {
|
||||
return err
|
||||
}
|
||||
h.profile.HigressVersion = h.opts.Version
|
||||
h.started = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -17,17 +17,17 @@ package installer
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/helm"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/util"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/helm"
|
||||
)
|
||||
|
||||
type DockerInstaller struct {
|
||||
started bool
|
||||
standalone *StandaloneComponent
|
||||
profile *helm.Profile
|
||||
writer io.Writer
|
||||
started bool
|
||||
standalone *StandaloneComponent
|
||||
profile *helm.Profile
|
||||
writer io.Writer
|
||||
profileStore ProfileStore
|
||||
}
|
||||
|
||||
func (d *DockerInstaller) Install() error {
|
||||
@@ -37,11 +37,11 @@ func (d *DockerInstaller) Install() error {
|
||||
return err
|
||||
}
|
||||
|
||||
profileName, _ := GetInstalledYamlPath()
|
||||
fmt.Fprintf(d.writer, "\n✔️ Wrote Profile: \"%s\" \n", profileName)
|
||||
if err := util.WriteFileString(profileName, util.ToYAML(d.profile), 0o644); err != nil {
|
||||
return err
|
||||
profileName, err1 := d.profileStore.Save(d.profile)
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
fmt.Fprintf(d.writer, "\n✔️ Wrote Profile: \"%s\" \n", profileName)
|
||||
|
||||
fmt.Fprintf(d.writer, "\n🎊 Install All Resources Complete!\n")
|
||||
return nil
|
||||
@@ -55,9 +55,11 @@ func (d *DockerInstaller) UnInstall() error {
|
||||
return err
|
||||
}
|
||||
|
||||
profileName, _ := GetInstalledYamlPath()
|
||||
profileName, err1 := d.profileStore.Delete(d.profile)
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
fmt.Fprintf(d.writer, "\n✔️ Removed Profile: \"%s\" \n", profileName)
|
||||
os.Remove(profileName)
|
||||
|
||||
fmt.Fprintf(d.writer, "\n🎊 Uninstall All Resources Complete!\n")
|
||||
return nil
|
||||
@@ -92,10 +94,19 @@ func NewDockerInstaller(profile *helm.Profile, writer io.Writer, quiet bool) (*D
|
||||
return nil, fmt.Errorf("NewStandaloneComponent failed, err: %s", err)
|
||||
}
|
||||
|
||||
profileInstalledPath, err1 := GetProfileInstalledPath()
|
||||
if err1 != nil {
|
||||
return nil, err1
|
||||
}
|
||||
profileStore, err2 := NewFileDirProfileStore(profileInstalledPath)
|
||||
if err2 != nil {
|
||||
return nil, err2
|
||||
}
|
||||
op := &DockerInstaller{
|
||||
profile: profile,
|
||||
standalone: standaloneComponent,
|
||||
writer: writer,
|
||||
profile: profile,
|
||||
standalone: standaloneComponent,
|
||||
writer: writer,
|
||||
profileStore: profileStore,
|
||||
}
|
||||
return op, nil
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/helm"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/helm/object"
|
||||
@@ -28,11 +29,12 @@ import (
|
||||
)
|
||||
|
||||
type K8sInstaller struct {
|
||||
started bool
|
||||
components map[ComponentName]Component
|
||||
kubeCli kubernetes.CLIClient
|
||||
profile *helm.Profile
|
||||
writer io.Writer
|
||||
started bool
|
||||
components map[ComponentName]Component
|
||||
kubeCli kubernetes.CLIClient
|
||||
profile *helm.Profile
|
||||
writer io.Writer
|
||||
profileStore ProfileStore
|
||||
}
|
||||
|
||||
func (o *K8sInstaller) Install() error {
|
||||
@@ -44,10 +46,6 @@ func (o *K8sInstaller) Install() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err := GetProfileInstalledPath(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := o.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -62,11 +60,16 @@ func (o *K8sInstaller) Install() error {
|
||||
return err
|
||||
}
|
||||
|
||||
profileName, _ := GetInstalledYamlPath()
|
||||
fmt.Fprintf(o.writer, "\n✔️ Wrote Profile: \"%s\" \n", profileName)
|
||||
if err := util.WriteFileString(profileName, util.ToYAML(o.profile), 0o644); err != nil {
|
||||
return err
|
||||
profileName, err1 := o.profileStore.Save(o.profile)
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
fmt.Fprintf(o.writer, "\n✔️ Wrote Profile in kubernetes configmap: \"%s\" \n", profileName)
|
||||
fmt.Fprintf(o.writer, "\n Use bellow kubectl command to edit profile for upgrade. \n")
|
||||
fmt.Fprintf(o.writer, " ================================================================================== \n")
|
||||
names := strings.Split(profileName, "/")
|
||||
fmt.Fprintf(o.writer, " kubectl edit configmap %s -n %s \n", names[1], names[0])
|
||||
fmt.Fprintf(o.writer, " ================================================================================== \n")
|
||||
|
||||
fmt.Fprintf(o.writer, "\n🎊 Install All Resources Complete!\n")
|
||||
|
||||
@@ -92,9 +95,11 @@ func (o *K8sInstaller) UnInstall() error {
|
||||
return err
|
||||
}
|
||||
|
||||
profileName, _ := GetInstalledYamlPath()
|
||||
profileName, err1 := o.profileStore.Delete(o.profile)
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
fmt.Fprintf(o.writer, "\n✔️ Removed Profile: \"%s\" \n", profileName)
|
||||
os.Remove(profileName)
|
||||
|
||||
fmt.Fprintf(o.writer, "\n🎊 Uninstall All Resources Complete!\n")
|
||||
|
||||
@@ -322,11 +327,17 @@ func NewK8sInstaller(profile *helm.Profile, cli kubernetes.CLIClient, writer io.
|
||||
components[GatewayAPI] = gatewayAPIComponent
|
||||
}
|
||||
|
||||
profileStore, err := NewConfigmapProfileStore(cli)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
op := &K8sInstaller{
|
||||
profile: profile,
|
||||
components: components,
|
||||
kubeCli: cli,
|
||||
writer: writer,
|
||||
profile: profile,
|
||||
components: components,
|
||||
kubeCli: cli,
|
||||
writer: writer,
|
||||
profileStore: profileStore,
|
||||
}
|
||||
return op, nil
|
||||
}
|
||||
|
||||
247
pkg/cmd/hgctl/installer/profile_store.go
Normal file
247
pkg/cmd/hgctl/installer/profile_store.go
Normal file
@@ -0,0 +1,247 @@
|
||||
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
//
|
||||
// Licensed 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 installer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/helm"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/kubernetes"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/util"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
ProfileConfigmapKey = "profile"
|
||||
ProfileConfigmapName = "higress-profile"
|
||||
ProfileConfigmapAnnotation = "higress.io/install"
|
||||
ProfileFilePrefix = "install"
|
||||
)
|
||||
|
||||
type ProfileContext struct {
|
||||
Profile *helm.Profile
|
||||
SourceType string
|
||||
Namespace string
|
||||
PathOrName string
|
||||
Install helm.InstallMode
|
||||
HigressVersion string
|
||||
}
|
||||
|
||||
type ProfileStore interface {
|
||||
Save(profile *helm.Profile) (string, error)
|
||||
List() ([]*ProfileContext, error)
|
||||
Delete(profile *helm.Profile) (string, error)
|
||||
}
|
||||
|
||||
type FileDirProfileStore struct {
|
||||
profilesPath string
|
||||
}
|
||||
|
||||
func (f *FileDirProfileStore) Save(profile *helm.Profile) (string, error) {
|
||||
namespace := profile.Global.Namespace
|
||||
install := profile.Global.Install
|
||||
var profileName = ""
|
||||
if install == helm.InstallK8s || install == helm.InstallLocalK8s {
|
||||
profileName = filepath.Join(f.profilesPath, fmt.Sprintf("%s-%s.yaml", ProfileFilePrefix, namespace))
|
||||
} else {
|
||||
profileName = filepath.Join(f.profilesPath, fmt.Sprintf("%s-%s.yaml", ProfileFilePrefix, install))
|
||||
}
|
||||
if err := util.WriteFileString(profileName, util.ToYAML(profile), 0o644); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return profileName, nil
|
||||
}
|
||||
|
||||
func (f *FileDirProfileStore) List() ([]*ProfileContext, error) {
|
||||
profileContexts := make([]*ProfileContext, 0)
|
||||
dir, err := os.ReadDir(f.profilesPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, file := range dir {
|
||||
if !strings.HasSuffix(file.Name(), ".yaml") {
|
||||
continue
|
||||
}
|
||||
if file.IsDir() {
|
||||
continue
|
||||
}
|
||||
fileName := filepath.Join(f.profilesPath, file.Name())
|
||||
content, err2 := os.ReadFile(fileName)
|
||||
if err2 != nil {
|
||||
continue
|
||||
}
|
||||
profile, err3 := helm.UnmarshalProfile(string(content))
|
||||
if err3 != nil {
|
||||
continue
|
||||
}
|
||||
profileContext := &ProfileContext{
|
||||
Profile: profile,
|
||||
Namespace: profile.Global.Namespace,
|
||||
Install: profile.Global.Install,
|
||||
HigressVersion: profile.HigressVersion,
|
||||
SourceType: "file",
|
||||
PathOrName: fileName,
|
||||
}
|
||||
profileContexts = append(profileContexts, profileContext)
|
||||
}
|
||||
return profileContexts, nil
|
||||
}
|
||||
|
||||
func (f *FileDirProfileStore) Delete(profile *helm.Profile) (string, error) {
|
||||
namespace := profile.Global.Namespace
|
||||
install := profile.Global.Install
|
||||
var profileName = ""
|
||||
if install == helm.InstallK8s || install == helm.InstallLocalK8s {
|
||||
profileName = filepath.Join(f.profilesPath, fmt.Sprintf("%s-%s.yaml", ProfileFilePrefix, namespace))
|
||||
} else {
|
||||
profileName = filepath.Join(f.profilesPath, fmt.Sprintf("%s-%s.yaml", ProfileFilePrefix, install))
|
||||
}
|
||||
if err := os.Remove(profileName); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return profileName, nil
|
||||
}
|
||||
|
||||
func NewFileDirProfileStore(profilesPath string) (ProfileStore, error) {
|
||||
if _, err := os.Stat(profilesPath); os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(profilesPath, os.ModePerm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
profileStore := &FileDirProfileStore{
|
||||
profilesPath: profilesPath,
|
||||
}
|
||||
return profileStore, nil
|
||||
}
|
||||
|
||||
type ConfigmapProfileStore struct {
|
||||
kubeCli kubernetes.CLIClient
|
||||
}
|
||||
|
||||
func (c *ConfigmapProfileStore) Save(profile *helm.Profile) (string, error) {
|
||||
bytes, err := json.Marshal(profile)
|
||||
jsonProfile := ""
|
||||
if err == nil {
|
||||
jsonProfile = string(bytes)
|
||||
}
|
||||
annotation := make(map[string]string, 0)
|
||||
annotation[ProfileConfigmapAnnotation] = jsonProfile
|
||||
configmap := &corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: profile.Global.Namespace,
|
||||
Name: ProfileConfigmapName,
|
||||
Annotations: annotation,
|
||||
},
|
||||
}
|
||||
configmap.Data = make(map[string]string, 0)
|
||||
configmap.Data[ProfileConfigmapKey] = util.ToYAML(profile)
|
||||
name := fmt.Sprintf("%s/%s", profile.Global.Namespace, ProfileConfigmapName)
|
||||
if err := c.applyConfigmap(configmap); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func (c *ConfigmapProfileStore) List() ([]*ProfileContext, error) {
|
||||
profileContexts := make([]*ProfileContext, 0)
|
||||
configmapList, err := c.listConfigmaps(ProfileConfigmapName, "", 100)
|
||||
if err != nil {
|
||||
return profileContexts, err
|
||||
}
|
||||
for _, configmap := range configmapList.Items {
|
||||
if data, ok := configmap.Data[ProfileConfigmapKey]; ok {
|
||||
profile, err := helm.UnmarshalProfile(data)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
profileContext := &ProfileContext{
|
||||
Profile: profile,
|
||||
Namespace: profile.Global.Namespace,
|
||||
Install: profile.Global.Install,
|
||||
HigressVersion: profile.HigressVersion,
|
||||
SourceType: "configmap",
|
||||
PathOrName: fmt.Sprintf("%s/%s", profile.Global.Namespace, configmap.Name),
|
||||
}
|
||||
profileContexts = append(profileContexts, profileContext)
|
||||
}
|
||||
}
|
||||
return profileContexts, nil
|
||||
}
|
||||
|
||||
func (c *ConfigmapProfileStore) Delete(profile *helm.Profile) (string, error) {
|
||||
configmap := &corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: profile.Global.Namespace,
|
||||
Name: ProfileConfigmapName,
|
||||
},
|
||||
}
|
||||
name := fmt.Sprintf("%s/%s", profile.Global.Namespace, ProfileConfigmapName)
|
||||
if err := c.deleteConfigmap(configmap); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func (c *ConfigmapProfileStore) listConfigmaps(name string, namespace string, size int64) (*corev1.ConfigMapList, error) {
|
||||
var result *corev1.ConfigMapList
|
||||
var err error
|
||||
if len(namespace) == 0 {
|
||||
result, err = c.kubeCli.KubernetesInterface().CoreV1().ConfigMaps("").List(context.Background(), metav1.ListOptions{Limit: size, FieldSelector: fmt.Sprintf("metadata.name=%s", name)})
|
||||
} else {
|
||||
result, err = c.kubeCli.KubernetesInterface().CoreV1().ConfigMaps(namespace).List(context.Background(), metav1.ListOptions{Limit: size, FieldSelector: fmt.Sprintf("metadata.name=%s", name)})
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *ConfigmapProfileStore) applyConfigmap(configmap *corev1.ConfigMap) error {
|
||||
_, err := c.kubeCli.KubernetesInterface().CoreV1().ConfigMaps(configmap.Namespace).Get(context.Background(), configmap.Name, metav1.GetOptions{})
|
||||
if err != nil && errors.IsNotFound(err) {
|
||||
_, err = c.kubeCli.KubernetesInterface().CoreV1().ConfigMaps(configmap.Namespace).Create(context.Background(), configmap, metav1.CreateOptions{})
|
||||
return err
|
||||
} else if err != nil {
|
||||
return err
|
||||
} else {
|
||||
_, err = c.kubeCli.KubernetesInterface().CoreV1().ConfigMaps(configmap.Namespace).Update(context.Background(), configmap, metav1.UpdateOptions{})
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ConfigmapProfileStore) deleteConfigmap(configmap *corev1.ConfigMap) error {
|
||||
err := c.kubeCli.KubernetesInterface().CoreV1().ConfigMaps(configmap.Namespace).Delete(context.Background(), configmap.Name, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
if !errors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewConfigmapProfileStore(kubeCli kubernetes.CLIClient) (ProfileStore, error) {
|
||||
profileStore := &ConfigmapProfileStore{
|
||||
kubeCli: kubeCli,
|
||||
}
|
||||
return profileStore, nil
|
||||
}
|
||||
@@ -58,7 +58,10 @@ func (s *StandaloneComponent) Install() error {
|
||||
if err := s.agent.Install(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set Higress version
|
||||
if version, err := s.agent.Version(); err == nil {
|
||||
s.profile.HigressVersion = version
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -86,7 +89,10 @@ func (s *StandaloneComponent) Upgrade() error {
|
||||
if err := s.agent.Upgrade(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set Higress version
|
||||
if version, err := s.agent.Version(); err != nil {
|
||||
s.profile.HigressVersion = version
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -112,10 +118,6 @@ func NewStandaloneComponent(profile *helm.Profile, writer io.Writer, opts ...Com
|
||||
}
|
||||
|
||||
func prepareProfile(profile *helm.Profile) error {
|
||||
if _, err := GetProfileInstalledPath(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(profile.InstallPackagePath) == 0 {
|
||||
dir, err := GetDefaultInstallPackagePath()
|
||||
if err != nil {
|
||||
|
||||
@@ -253,4 +253,5 @@ func (c *client) CreateNamespace(namespace string) error {
|
||||
// KubernetesInterface get kubernetes interface
|
||||
func (c *client) KubernetesInterface() kubernetes.Interface {
|
||||
return c.kube
|
||||
|
||||
}
|
||||
|
||||
@@ -28,12 +28,8 @@ import (
|
||||
"k8s.io/client-go/transport/spdy"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultLocalAddress = "localhost"
|
||||
)
|
||||
|
||||
func LocalAvailablePort() (int, error) {
|
||||
l, err := net.Listen("tcp", fmt.Sprintf("%s:0", DefaultLocalAddress))
|
||||
func LocalAvailablePort(localAddress string) (int, error) {
|
||||
l, err := net.Listen("tcp", fmt.Sprintf("%s:0", localAddress))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -59,23 +55,25 @@ type localForwarder struct {
|
||||
types.NamespacedName
|
||||
CLIClient
|
||||
|
||||
localPort int
|
||||
podPort int
|
||||
localPort int
|
||||
podPort int
|
||||
localAddress string
|
||||
|
||||
stopCh chan struct{}
|
||||
}
|
||||
|
||||
func NewLocalPortForwarder(client CLIClient, namespacedName types.NamespacedName, localPort, podPort int) (PortForwarder, error) {
|
||||
func NewLocalPortForwarder(client CLIClient, namespacedName types.NamespacedName, localPort, podPort int, bindAddress string) (PortForwarder, error) {
|
||||
f := &localForwarder{
|
||||
stopCh: make(chan struct{}),
|
||||
CLIClient: client,
|
||||
NamespacedName: namespacedName,
|
||||
localPort: localPort,
|
||||
podPort: podPort,
|
||||
localAddress: bindAddress,
|
||||
}
|
||||
if f.localPort == 0 {
|
||||
// get a random port
|
||||
p, err := LocalAvailablePort()
|
||||
p, err := LocalAvailablePort(bindAddress)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get a local available port")
|
||||
}
|
||||
@@ -136,7 +134,7 @@ func (f *localForwarder) buildKubernetesPortForwarder(readyCh chan struct{}) (*p
|
||||
|
||||
dialer := spdy.NewDialer(upgrader, &http.Client{Transport: roundTripper}, http.MethodPost, serverURL)
|
||||
fw, err := portforward.NewOnAddresses(dialer,
|
||||
[]string{DefaultLocalAddress},
|
||||
[]string{f.localAddress},
|
||||
[]string{fmt.Sprintf("%d:%d", f.localPort, f.podPort)},
|
||||
f.stopCh,
|
||||
readyCh,
|
||||
@@ -154,7 +152,7 @@ func (f *localForwarder) Stop() {
|
||||
}
|
||||
|
||||
func (f *localForwarder) Address() string {
|
||||
return fmt.Sprintf("%s:%d", DefaultLocalAddress, f.localPort)
|
||||
return fmt.Sprintf("%s:%d", f.localAddress, f.localPort)
|
||||
}
|
||||
|
||||
func (f *localForwarder) WaitForStop() {
|
||||
|
||||
@@ -20,10 +20,8 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"os/user"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/plugin/option"
|
||||
ptypes "github.com/alibaba/higress/pkg/cmd/hgctl/plugin/types"
|
||||
@@ -633,11 +631,7 @@ func (b *Builder) config(f ConfigFunc) (err error) {
|
||||
b.w = os.Stdout
|
||||
}
|
||||
|
||||
b.sig = make(chan os.Signal, 1)
|
||||
b.stop = make(chan struct{}, 1)
|
||||
b.done = make(chan struct{}, 1)
|
||||
signal.Notify(b.sig, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM,
|
||||
syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGQUIT, syscall.SIGTSTP)
|
||||
signalNotify(b)
|
||||
|
||||
if b.Debugger == nil {
|
||||
b.Debugger = utils.NewDefaultDebugger(b.Debug, b.w)
|
||||
|
||||
31
pkg/cmd/hgctl/plugin/build/signal.go
Normal file
31
pkg/cmd/hgctl/plugin/build/signal.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
//
|
||||
// Licensed 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.
|
||||
|
||||
//go:build linux || darwin || bsd
|
||||
|
||||
package build
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func signalNotify(b *Builder) {
|
||||
b.sig = make(chan os.Signal, 1)
|
||||
b.stop = make(chan struct{}, 1)
|
||||
b.done = make(chan struct{}, 1)
|
||||
signal.Notify(b.sig, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM,
|
||||
syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGQUIT, syscall.SIGTSTP)
|
||||
}
|
||||
31
pkg/cmd/hgctl/plugin/build/signal_windows.go
Normal file
31
pkg/cmd/hgctl/plugin/build/signal_windows.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
//
|
||||
// Licensed 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.
|
||||
|
||||
//go:build windows
|
||||
|
||||
package build
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func signalNotify(b *Builder) {
|
||||
b.sig = make(chan os.Signal, 1)
|
||||
b.stop = make(chan struct{}, 1)
|
||||
b.done = make(chan struct{}, 1)
|
||||
signal.Notify(b.sig, syscall.SIGHUP, syscall.SIGINT,
|
||||
syscall.SIGTERM, syscall.SIGQUIT)
|
||||
}
|
||||
@@ -17,6 +17,7 @@ package hgctl
|
||||
import (
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/plugin"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
)
|
||||
|
||||
// GetRootCommand returns the root cobra command to be executed
|
||||
@@ -38,6 +39,8 @@ func GetRootCommand() *cobra.Command {
|
||||
rootCmd.AddCommand(newDashboardCmd())
|
||||
rootCmd.AddCommand(newManifestCmd())
|
||||
rootCmd.AddCommand(plugin.NewCommand())
|
||||
rootCmd.AddCommand(newCompletionCmd(os.Stdout))
|
||||
rootCmd.AddCommand(newCodeDebugCmd())
|
||||
|
||||
return rootCmd
|
||||
}
|
||||
|
||||
@@ -17,10 +17,12 @@ package hgctl
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/helm"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/installer"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/util"
|
||||
"github.com/alibaba/higress/pkg/cmd/options"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -60,18 +62,22 @@ func newUninstallCmd() *cobra.Command {
|
||||
|
||||
// uninstall uninstalls control plane by either pruning by target revision or deleting specified manifests.
|
||||
func uninstall(writer io.Writer, uiArgs *uninstallArgs) error {
|
||||
profileName, ok := installer.GetInstalledYamlPath()
|
||||
if !ok {
|
||||
fmt.Fprintf(writer, "⌛️ Checking higress installed profiles...\n")
|
||||
profileContexts, _ := getAllProfiles()
|
||||
if len(profileContexts) == 0 {
|
||||
fmt.Fprintf(writer, "\nHigress hasn't been installed yet!\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
setFlags := make([]string, 0)
|
||||
_, profile, err := helm.GenProfile(profileName, "", setFlags)
|
||||
|
||||
profileContext := promptProfileContexts(writer, profileContexts)
|
||||
_, profile, err := helm.GenProfileFromProfileContent(util.ToYAML(profileContext.Profile), "", setFlags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintf(writer, "🧐 Validating Profile: \"%s\" \n", profileName)
|
||||
fmt.Fprintf(writer, "\n🧐 Validating Profile: \"%s\" \n", profileContext.PathOrName)
|
||||
err = profile.Validate()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -95,6 +101,11 @@ func uninstall(writer io.Writer, uiArgs *uninstallArgs) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove "~/.hgctl/profiles/install.yaml"
|
||||
if oldProfileName, isExisted := installer.GetInstalledYamlPath(); isExisted {
|
||||
_ = os.Remove(oldProfileName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -17,10 +17,14 @@ package hgctl
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/helm"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/installer"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/kubernetes"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/util"
|
||||
"github.com/alibaba/higress/pkg/cmd/options"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -58,8 +62,9 @@ func newUpgradeCmd() *cobra.Command {
|
||||
// upgrade upgrade higress resources from the cluster.
|
||||
func upgrade(writer io.Writer, iArgs *InstallArgs) error {
|
||||
setFlags := applyFlagAliases(iArgs.Set, iArgs.ManifestsPath)
|
||||
profileName, ok := installer.GetInstalledYamlPath()
|
||||
if !ok {
|
||||
fmt.Fprintf(writer, "⌛️ Checking higress installed profiles...\n")
|
||||
profileContexts, _ := getAllProfiles()
|
||||
if len(profileContexts) == 0 {
|
||||
fmt.Fprintf(writer, "\nHigress hasn't been installed yet!\n")
|
||||
return nil
|
||||
}
|
||||
@@ -69,12 +74,14 @@ func upgrade(writer io.Writer, iArgs *InstallArgs) error {
|
||||
return err
|
||||
}
|
||||
|
||||
_, profile, err := helm.GenProfile(profileName, valuesOverlay, setFlags)
|
||||
profileContext := promptProfileContexts(writer, profileContexts)
|
||||
|
||||
_, profile, err := helm.GenProfileFromProfileContent(util.ToYAML(profileContext.Profile), valuesOverlay, setFlags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintf(writer, "🧐 Validating Profile: \"%s\" \n", profileName)
|
||||
fmt.Fprintf(writer, "\n🧐 Validating Profile: \"%s\" \n", profileContext.PathOrName)
|
||||
err = profile.Validate()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -89,6 +96,11 @@ func upgrade(writer io.Writer, iArgs *InstallArgs) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove "~/.hgctl/profiles/install.yaml"
|
||||
if oldProfileName, isExisted := installer.GetInstalledYamlPath(); isExisted {
|
||||
_ = os.Remove(oldProfileName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -121,3 +133,71 @@ func upgradeManifests(profile *helm.Profile, writer io.Writer) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getAllProfiles() ([]*installer.ProfileContext, error) {
|
||||
profileContexts := make([]*installer.ProfileContext, 0)
|
||||
profileInstalledPath, err := installer.GetProfileInstalledPath()
|
||||
if err != nil {
|
||||
return profileContexts, nil
|
||||
}
|
||||
fileProfileStore, err := installer.NewFileDirProfileStore(profileInstalledPath)
|
||||
if err != nil {
|
||||
return profileContexts, nil
|
||||
}
|
||||
fileProfileContexts, err := fileProfileStore.List()
|
||||
if err == nil {
|
||||
profileContexts = append(profileContexts, fileProfileContexts...)
|
||||
}
|
||||
|
||||
cliClient, err := kubernetes.NewCLIClient(options.DefaultConfigFlags.ToRawKubeConfigLoader())
|
||||
if err != nil {
|
||||
return profileContexts, nil
|
||||
}
|
||||
configmapProfileStore, err := installer.NewConfigmapProfileStore(cliClient)
|
||||
if err != nil {
|
||||
return profileContexts, nil
|
||||
}
|
||||
|
||||
configmapProfileContexts, err := configmapProfileStore.List()
|
||||
if err == nil {
|
||||
profileContexts = append(profileContexts, configmapProfileContexts...)
|
||||
}
|
||||
return profileContexts, nil
|
||||
}
|
||||
|
||||
func promptProfileContexts(writer io.Writer, profileContexts []*installer.ProfileContext) *installer.ProfileContext {
|
||||
if len(profileContexts) == 1 {
|
||||
fmt.Fprintf(writer, "\nFound a profile:: ")
|
||||
} else {
|
||||
fmt.Fprintf(writer, "\nPlease select higress installed configration profiles:\n")
|
||||
}
|
||||
index := 1
|
||||
for _, profileContext := range profileContexts {
|
||||
if len(profileContexts) > 1 {
|
||||
fmt.Fprintf(writer, "\n%d: ", index)
|
||||
}
|
||||
fmt.Fprintf(writer, "install mode: %s, profile location: %s", profileContext.Install, profileContext.PathOrName)
|
||||
if len(profileContext.Namespace) > 0 {
|
||||
fmt.Fprintf(writer, ", namespace: %s", profileContext.Namespace)
|
||||
}
|
||||
if len(profileContext.HigressVersion) > 0 {
|
||||
fmt.Fprintf(writer, ", version: %s", profileContext.HigressVersion)
|
||||
}
|
||||
fmt.Fprintf(writer, "\n")
|
||||
index++
|
||||
}
|
||||
|
||||
if len(profileContexts) == 1 {
|
||||
return profileContexts[0]
|
||||
}
|
||||
|
||||
answer := ""
|
||||
for {
|
||||
fmt.Fprintf(writer, "\nPlease input 1 to %d select, input your selection:", len(profileContexts))
|
||||
fmt.Scanln(&answer)
|
||||
index, err := strconv.Atoi(answer)
|
||||
if err == nil && index >= 1 && index <= len(profileContexts) {
|
||||
return profileContexts[index-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ func getServerCommand() *cobra.Command {
|
||||
}
|
||||
|
||||
serveCmd.PersistentFlags().StringVar(&serverArgs.GatewaySelectorKey, "gatewaySelectorKey", "higress", "gateway resource selector label key")
|
||||
serveCmd.PersistentFlags().StringVar(&serverArgs.GatewaySelectorValue, "gatewaySelectorValue", "higress-gateway", "gateway resource selector label value")
|
||||
serveCmd.PersistentFlags().StringVar(&serverArgs.GatewaySelectorValue, "gatewaySelectorValue", "higress-system-higress-gateway", "gateway resource selector label value")
|
||||
serveCmd.PersistentFlags().BoolVar(&serverArgs.EnableStatus, "enableStatus", true, "enable the ingress status syncer which use to update the ip in ingress's status")
|
||||
serveCmd.PersistentFlags().StringVar(&serverArgs.IngressClass, "ingressClass", innerconstants.DefaultIngressClass, "if not empty, only watch the ingresses have the specified class, otherwise watch all ingresses")
|
||||
serveCmd.PersistentFlags().StringVar(&serverArgs.WatchNamespace, "watchNamespace", "", "if not empty, only wath the ingresses in the specified namespace, otherwise watch in all namespacees")
|
||||
|
||||
@@ -140,8 +140,6 @@ type IngressConfig struct {
|
||||
|
||||
annotationHandler annotations.AnnotationHandler
|
||||
|
||||
globalGatewayName string
|
||||
|
||||
namespace string
|
||||
|
||||
clusterId string
|
||||
@@ -157,13 +155,11 @@ func NewIngressConfig(localKubeClient kube.Client, XDSUpdater model.XDSUpdater,
|
||||
XDSUpdater: XDSUpdater,
|
||||
annotationHandler: annotations.NewAnnotationHandlerManager(),
|
||||
clusterId: clusterId,
|
||||
globalGatewayName: namespace + "/" +
|
||||
common.CreateConvertedName(clusterId, "global"),
|
||||
watchedSecretSet: sets.NewSet(),
|
||||
namespace: namespace,
|
||||
mcpbridgeReconciled: atomic.NewBool(false),
|
||||
wasmPlugins: make(map[string]*extensions.WasmPlugin),
|
||||
http2rpcs: make(map[string]*higressv1.Http2Rpc),
|
||||
watchedSecretSet: sets.NewSet(),
|
||||
namespace: namespace,
|
||||
mcpbridgeReconciled: atomic.NewBool(false),
|
||||
wasmPlugins: make(map[string]*extensions.WasmPlugin),
|
||||
http2rpcs: make(map[string]*higressv1.Http2Rpc),
|
||||
}
|
||||
mcpbridgeController := mcpbridge.NewController(localKubeClient, clusterId)
|
||||
mcpbridgeController.AddEventHandler(config.AddOrUpdateMcpBridge, config.DeleteMcpBridge)
|
||||
@@ -479,7 +475,7 @@ func (m *IngressConfig) convertVirtualService(configs []common.WrapperConfig) []
|
||||
common.CreateConvertedName(m.clusterId, cleanHost),
|
||||
common.CreateConvertedName(constants.IstioIngressGatewayName, cleanHost)}
|
||||
if host != "*" {
|
||||
gateways = append(gateways, m.globalGatewayName)
|
||||
gateways = append(gateways, m.namespace+"/"+common.CreateConvertedName(m.clusterId, common.CleanHost("*")))
|
||||
}
|
||||
|
||||
wrapperVS, exist := convertOptions.VirtualServices[host]
|
||||
@@ -530,7 +526,7 @@ func (m *IngressConfig) convertEnvoyFilter(convertOptions *common.ConvertOptions
|
||||
IngressLog.Infof("Found http2rpc for name %s", http2rpc.Name)
|
||||
envoyFilter, err := m.constructHttp2RpcEnvoyFilter(http2rpc, route, m.namespace)
|
||||
if err != nil {
|
||||
IngressLog.Errorf("Construct http2rpc EnvoyFilter error %v", err)
|
||||
IngressLog.Infof("Construct http2rpc EnvoyFilter error %v", err)
|
||||
} else {
|
||||
IngressLog.Infof("Append http2rpc EnvoyFilter for name %s", http2rpc.Name)
|
||||
envoyFilters = append(envoyFilters, *envoyFilter)
|
||||
@@ -573,6 +569,7 @@ func (m *IngressConfig) convertEnvoyFilter(convertOptions *common.ConvertOptions
|
||||
|
||||
// TODO Support other envoy filters
|
||||
|
||||
IngressLog.Infof("Found %d number of envoyFilters", len(envoyFilters))
|
||||
m.mutex.Lock()
|
||||
m.cachedEnvoyFilters = envoyFilters
|
||||
m.mutex.Unlock()
|
||||
@@ -1003,9 +1000,23 @@ func (m *IngressConfig) AddOrUpdateHttp2Rpc(clusterNamespacedName util.ClusterNa
|
||||
m.http2rpcs[clusterNamespacedName.Name] = &http2rpc.Spec
|
||||
m.mutex.Unlock()
|
||||
IngressLog.Infof("AddOrUpdateHttp2Rpc http2rpc ingress name %s", clusterNamespacedName.Name)
|
||||
push := func(kind config.GroupVersionKind) {
|
||||
m.XDSUpdater.ConfigUpdate(&model.PushRequest{
|
||||
Full: true,
|
||||
ConfigsUpdated: map[model.ConfigKey]struct{}{{
|
||||
Kind: kind,
|
||||
Name: clusterNamespacedName.Name,
|
||||
Namespace: clusterNamespacedName.Namespace,
|
||||
}: {}},
|
||||
Reason: []model.TriggerReason{"Http2Rpc-AddOrUpdate"},
|
||||
})
|
||||
}
|
||||
push(gvk.VirtualService)
|
||||
push(gvk.EnvoyFilter)
|
||||
}
|
||||
|
||||
func (m *IngressConfig) DeleteHttp2Rpc(clusterNamespacedName util.ClusterNamespacedName) {
|
||||
IngressLog.Infof("Http2Rpc triggerd deleted event %s", clusterNamespacedName.Name)
|
||||
if clusterNamespacedName.Namespace != m.namespace {
|
||||
return
|
||||
}
|
||||
@@ -1017,7 +1028,20 @@ func (m *IngressConfig) DeleteHttp2Rpc(clusterNamespacedName util.ClusterNamespa
|
||||
}
|
||||
m.mutex.Unlock()
|
||||
if hit {
|
||||
IngressLog.Debugf("Http2Rpc triggerd deleted %s", clusterNamespacedName.Name)
|
||||
IngressLog.Infof("Http2Rpc triggerd deleted event executed %s", clusterNamespacedName.Name)
|
||||
push := func(kind config.GroupVersionKind) {
|
||||
m.XDSUpdater.ConfigUpdate(&model.PushRequest{
|
||||
Full: true,
|
||||
ConfigsUpdated: map[model.ConfigKey]struct{}{{
|
||||
Kind: kind,
|
||||
Name: clusterNamespacedName.Name,
|
||||
Namespace: clusterNamespacedName.Namespace,
|
||||
}: {}},
|
||||
Reason: []model.TriggerReason{"Http2Rpc-Deleted"},
|
||||
})
|
||||
}
|
||||
push(gvk.VirtualService)
|
||||
push(gvk.EnvoyFilter)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1241,12 +1265,21 @@ func (m *IngressConfig) constructHttp2RpcMethods(dubbo *higressv1.DubboService)
|
||||
var method = make(map[string]interface{})
|
||||
method["name"] = serviceMethod.GetServiceMethod()
|
||||
var params []interface{}
|
||||
for _, methodParam := range serviceMethod.GetParams() {
|
||||
// paramFromEntireBody is for methods with single parameter. So when paramFromEntireBody exists, we just ignore parmas.
|
||||
var paramFromEntireBody = serviceMethod.GetParamFromEntireBody()
|
||||
if paramFromEntireBody != nil {
|
||||
var param = make(map[string]interface{})
|
||||
param["extract_key"] = methodParam.GetParamKey()
|
||||
param["extract_key_spec"] = Http2RpcParamSourceMap()[methodParam.GetParamSource()]
|
||||
param["mapping_type"] = methodParam.GetParamType()
|
||||
param["extract_key_spec"] = Http2RpcParamSourceMap()["BODY"]
|
||||
param["mapping_type"] = paramFromEntireBody.GetParamType()
|
||||
params = append(params, param)
|
||||
} else {
|
||||
for _, methodParam := range serviceMethod.GetParams() {
|
||||
var param = make(map[string]interface{})
|
||||
param["extract_key"] = methodParam.GetParamKey()
|
||||
param["extract_key_spec"] = Http2RpcParamSourceMap()[methodParam.GetParamSource()]
|
||||
param["mapping_type"] = methodParam.GetParamType()
|
||||
params = append(params, param)
|
||||
}
|
||||
}
|
||||
method["parameter_mapping"] = params
|
||||
var path_matcher = make(map[string]interface{})
|
||||
|
||||
@@ -257,7 +257,7 @@ func TestConvertGatewaysForIngress(t *testing.T) {
|
||||
"foo.com": {
|
||||
Meta: config.Meta{
|
||||
GroupVersionKind: gvk.Gateway,
|
||||
Name: "istio-autogenerated-k8s-ingress-foo-com",
|
||||
Name: "istio-autogenerated-k8s-ingress-" + common.CleanHost("foo.com"),
|
||||
Namespace: "wakanda",
|
||||
Annotations: map[string]string{
|
||||
common.ClusterIdAnnotation: "ingress-v1beta1",
|
||||
@@ -270,7 +270,7 @@ func TestConvertGatewaysForIngress(t *testing.T) {
|
||||
Port: &networking.Port{
|
||||
Number: 80,
|
||||
Protocol: "HTTP",
|
||||
Name: "http-80-ingress-ingress-v1beta1-wakanda-test-1-foo-com",
|
||||
Name: "http-80-ingress-ingress-v1beta1",
|
||||
},
|
||||
Hosts: []string{"foo.com"},
|
||||
},
|
||||
@@ -278,7 +278,7 @@ func TestConvertGatewaysForIngress(t *testing.T) {
|
||||
Port: &networking.Port{
|
||||
Number: 443,
|
||||
Protocol: "HTTPS",
|
||||
Name: "https-443-ingress-ingress-v1beta1-wakanda-test-2-foo-com",
|
||||
Name: "https-443-ingress-ingress-v1beta1",
|
||||
},
|
||||
Hosts: []string{"foo.com"},
|
||||
Tls: &networking.ServerTLSSettings{
|
||||
@@ -293,7 +293,7 @@ func TestConvertGatewaysForIngress(t *testing.T) {
|
||||
"test.com": {
|
||||
Meta: config.Meta{
|
||||
GroupVersionKind: gvk.Gateway,
|
||||
Name: "istio-autogenerated-k8s-ingress-test-com",
|
||||
Name: "istio-autogenerated-k8s-ingress-" + common.CleanHost("test.com"),
|
||||
Namespace: "wakanda",
|
||||
Annotations: map[string]string{
|
||||
common.ClusterIdAnnotation: "ingress-v1beta1",
|
||||
@@ -306,7 +306,7 @@ func TestConvertGatewaysForIngress(t *testing.T) {
|
||||
Port: &networking.Port{
|
||||
Number: 80,
|
||||
Protocol: "HTTP",
|
||||
Name: "http-80-ingress-ingress-v1beta1-wakanda-test-1-test-com",
|
||||
Name: "http-80-ingress-ingress-v1beta1",
|
||||
},
|
||||
Hosts: []string{"test.com"},
|
||||
},
|
||||
@@ -314,7 +314,7 @@ func TestConvertGatewaysForIngress(t *testing.T) {
|
||||
Port: &networking.Port{
|
||||
Number: 443,
|
||||
Protocol: "HTTPS",
|
||||
Name: "https-443-ingress-ingress-v1beta1-wakanda-test-1-test-com",
|
||||
Name: "https-443-ingress-ingress-v1beta1",
|
||||
},
|
||||
Hosts: []string{"test.com"},
|
||||
Tls: &networking.ServerTLSSettings{
|
||||
@@ -329,7 +329,7 @@ func TestConvertGatewaysForIngress(t *testing.T) {
|
||||
"bar.com": {
|
||||
Meta: config.Meta{
|
||||
GroupVersionKind: gvk.Gateway,
|
||||
Name: "istio-autogenerated-k8s-ingress-bar-com",
|
||||
Name: "istio-autogenerated-k8s-ingress-" + common.CleanHost("bar.com"),
|
||||
Namespace: "wakanda",
|
||||
Annotations: map[string]string{
|
||||
common.ClusterIdAnnotation: "ingress-v1beta1",
|
||||
@@ -342,7 +342,7 @@ func TestConvertGatewaysForIngress(t *testing.T) {
|
||||
Port: &networking.Port{
|
||||
Number: 80,
|
||||
Protocol: "HTTP",
|
||||
Name: "http-80-ingress-ingress-v1beta1-wakanda-test-2-bar-com",
|
||||
Name: "http-80-ingress-ingress-v1beta1",
|
||||
},
|
||||
Hosts: []string{"bar.com"},
|
||||
},
|
||||
@@ -471,7 +471,7 @@ func TestConvertGatewaysForIngress(t *testing.T) {
|
||||
"foo.com": {
|
||||
Meta: config.Meta{
|
||||
GroupVersionKind: gvk.Gateway,
|
||||
Name: "istio-autogenerated-k8s-ingress-foo-com",
|
||||
Name: "istio-autogenerated-k8s-ingress-" + common.CleanHost("foo.com"),
|
||||
Namespace: "wakanda",
|
||||
Annotations: map[string]string{
|
||||
common.ClusterIdAnnotation: "ingress-v1",
|
||||
@@ -484,7 +484,7 @@ func TestConvertGatewaysForIngress(t *testing.T) {
|
||||
Port: &networking.Port{
|
||||
Number: 80,
|
||||
Protocol: "HTTP",
|
||||
Name: "http-80-ingress-ingress-v1-wakanda-test-1-foo-com",
|
||||
Name: "http-80-ingress-ingress-v1",
|
||||
},
|
||||
Hosts: []string{"foo.com"},
|
||||
},
|
||||
@@ -492,7 +492,7 @@ func TestConvertGatewaysForIngress(t *testing.T) {
|
||||
Port: &networking.Port{
|
||||
Number: 443,
|
||||
Protocol: "HTTPS",
|
||||
Name: "https-443-ingress-ingress-v1-wakanda-test-2-foo-com",
|
||||
Name: "https-443-ingress-ingress-v1",
|
||||
},
|
||||
Hosts: []string{"foo.com"},
|
||||
Tls: &networking.ServerTLSSettings{
|
||||
@@ -507,7 +507,7 @@ func TestConvertGatewaysForIngress(t *testing.T) {
|
||||
"test.com": {
|
||||
Meta: config.Meta{
|
||||
GroupVersionKind: gvk.Gateway,
|
||||
Name: "istio-autogenerated-k8s-ingress-test-com",
|
||||
Name: "istio-autogenerated-k8s-ingress-" + common.CleanHost("test.com"),
|
||||
Namespace: "wakanda",
|
||||
Annotations: map[string]string{
|
||||
common.ClusterIdAnnotation: "ingress-v1",
|
||||
@@ -520,7 +520,7 @@ func TestConvertGatewaysForIngress(t *testing.T) {
|
||||
Port: &networking.Port{
|
||||
Number: 80,
|
||||
Protocol: "HTTP",
|
||||
Name: "http-80-ingress-ingress-v1-wakanda-test-1-test-com",
|
||||
Name: "http-80-ingress-ingress-v1",
|
||||
},
|
||||
Hosts: []string{"test.com"},
|
||||
},
|
||||
@@ -528,7 +528,7 @@ func TestConvertGatewaysForIngress(t *testing.T) {
|
||||
Port: &networking.Port{
|
||||
Number: 443,
|
||||
Protocol: "HTTPS",
|
||||
Name: "https-443-ingress-ingress-v1-wakanda-test-1-test-com",
|
||||
Name: "https-443-ingress-ingress-v1",
|
||||
},
|
||||
Hosts: []string{"test.com"},
|
||||
Tls: &networking.ServerTLSSettings{
|
||||
@@ -543,7 +543,7 @@ func TestConvertGatewaysForIngress(t *testing.T) {
|
||||
"bar.com": {
|
||||
Meta: config.Meta{
|
||||
GroupVersionKind: gvk.Gateway,
|
||||
Name: "istio-autogenerated-k8s-ingress-bar-com",
|
||||
Name: "istio-autogenerated-k8s-ingress-" + common.CleanHost("bar.com"),
|
||||
Namespace: "wakanda",
|
||||
Annotations: map[string]string{
|
||||
common.ClusterIdAnnotation: "ingress-v1",
|
||||
@@ -556,7 +556,7 @@ func TestConvertGatewaysForIngress(t *testing.T) {
|
||||
Port: &networking.Port{
|
||||
Number: 80,
|
||||
Protocol: "HTTP",
|
||||
Name: "http-80-ingress-ingress-v1-wakanda-test-2-bar-com",
|
||||
Name: "http-80-ingress-ingress-v1",
|
||||
},
|
||||
Hosts: []string{"bar.com"},
|
||||
},
|
||||
|
||||
@@ -66,8 +66,6 @@ type KIngressConfig struct {
|
||||
|
||||
annotationHandler annotations.AnnotationHandler
|
||||
|
||||
globalGatewayName string
|
||||
|
||||
namespace string
|
||||
|
||||
clusterId string
|
||||
@@ -86,10 +84,8 @@ func NewKIngressConfig(localKubeClient kube.Client, XDSUpdater model.XDSUpdater,
|
||||
XDSUpdater: XDSUpdater,
|
||||
annotationHandler: annotations.NewAnnotationHandlerManager(),
|
||||
clusterId: clusterId,
|
||||
globalGatewayName: namespace + "/" +
|
||||
common.CreateConvertedName(clusterId, "global"),
|
||||
watchedSecretSet: sets.NewSet(),
|
||||
namespace: namespace,
|
||||
watchedSecretSet: sets.NewSet(),
|
||||
namespace: namespace,
|
||||
}
|
||||
|
||||
return config
|
||||
@@ -319,7 +315,7 @@ func (m *KIngressConfig) convertVirtualService(configs []common.WrapperConfig) [
|
||||
common.CreateConvertedName(m.clusterId, cleanHost),
|
||||
common.CreateConvertedName(constants.IstioIngressGatewayName, cleanHost)}
|
||||
if host != "*" {
|
||||
gateways = append(gateways, m.globalGatewayName)
|
||||
gateways = append(gateways, m.namespace+"/"+common.CreateConvertedName(m.clusterId, common.CleanHost("*")))
|
||||
}
|
||||
|
||||
wrapperVS, exist := convertOptions.VirtualServices[host]
|
||||
|
||||
@@ -363,7 +363,7 @@ func TestConvertGatewaysForKIngress(t *testing.T) {
|
||||
"foo.com": {
|
||||
Meta: config.Meta{
|
||||
GroupVersionKind: gvk.Gateway,
|
||||
Name: "istio-autogenerated-k8s-ingress-foo-com",
|
||||
Name: "istio-autogenerated-k8s-ingress-" + common.CleanHost("foo.com"),
|
||||
Namespace: "wakanda",
|
||||
Annotations: map[string]string{
|
||||
common.ClusterIdAnnotation: "kingress",
|
||||
@@ -376,7 +376,7 @@ func TestConvertGatewaysForKIngress(t *testing.T) {
|
||||
Port: &networking.Port{
|
||||
Number: 80,
|
||||
Protocol: "HTTP",
|
||||
Name: "http-80-ingress-kingress-wakanda-test-1-foo-com",
|
||||
Name: "http-80-ingress-kingress",
|
||||
},
|
||||
Hosts: []string{"foo.com"},
|
||||
//Tls: &networking.ServerTLSSettings{
|
||||
@@ -387,7 +387,7 @@ func TestConvertGatewaysForKIngress(t *testing.T) {
|
||||
Port: &networking.Port{
|
||||
Number: 443,
|
||||
Protocol: "HTTPS",
|
||||
Name: "https-443-ingress-kingress-wakanda-test-2-foo-com",
|
||||
Name: "https-443-ingress-kingress",
|
||||
},
|
||||
Hosts: []string{"foo.com"},
|
||||
Tls: &networking.ServerTLSSettings{
|
||||
@@ -402,7 +402,7 @@ func TestConvertGatewaysForKIngress(t *testing.T) {
|
||||
"test.com": {
|
||||
Meta: config.Meta{
|
||||
GroupVersionKind: gvk.Gateway,
|
||||
Name: "istio-autogenerated-k8s-ingress-test-com",
|
||||
Name: "istio-autogenerated-k8s-ingress-" + common.CleanHost("test.com"),
|
||||
Namespace: "wakanda",
|
||||
Annotations: map[string]string{
|
||||
common.ClusterIdAnnotation: "kingress",
|
||||
@@ -415,7 +415,7 @@ func TestConvertGatewaysForKIngress(t *testing.T) {
|
||||
Port: &networking.Port{
|
||||
Number: 80,
|
||||
Protocol: "HTTP",
|
||||
Name: "http-80-ingress-kingress-wakanda-test-1-test-com",
|
||||
Name: "http-80-ingress-kingress",
|
||||
},
|
||||
Hosts: []string{"test.com"},
|
||||
//Tls: &networking.ServerTLSSettings{
|
||||
@@ -426,7 +426,7 @@ func TestConvertGatewaysForKIngress(t *testing.T) {
|
||||
Port: &networking.Port{
|
||||
Number: 443,
|
||||
Protocol: "HTTPS",
|
||||
Name: "https-443-ingress-kingress-wakanda-test-1-test-com",
|
||||
Name: "https-443-ingress-kingress",
|
||||
},
|
||||
Hosts: []string{"test.com"},
|
||||
Tls: &networking.ServerTLSSettings{
|
||||
@@ -441,7 +441,7 @@ func TestConvertGatewaysForKIngress(t *testing.T) {
|
||||
"bar.com": {
|
||||
Meta: config.Meta{
|
||||
GroupVersionKind: gvk.Gateway,
|
||||
Name: "istio-autogenerated-k8s-ingress-bar-com",
|
||||
Name: "istio-autogenerated-k8s-ingress-" + common.CleanHost("bar.com"),
|
||||
Namespace: "wakanda",
|
||||
Annotations: map[string]string{
|
||||
common.ClusterIdAnnotation: "kingress",
|
||||
@@ -454,7 +454,7 @@ func TestConvertGatewaysForKIngress(t *testing.T) {
|
||||
Port: &networking.Port{
|
||||
Number: 80,
|
||||
Protocol: "HTTP",
|
||||
Name: "http-80-ingress-kingress-wakanda-test-2-bar-com",
|
||||
Name: "http-80-ingress-kingress",
|
||||
},
|
||||
Hosts: []string{"bar.com"},
|
||||
},
|
||||
|
||||
@@ -154,7 +154,7 @@ func ApplyByHeader(canary, route *networking.HTTPRoute, canaryIngress *Ingress)
|
||||
match.Headers = map[string]*networking.StringMatch{
|
||||
canaryConfig.Header: {
|
||||
MatchType: &networking.StringMatch_Regex{
|
||||
Regex: canaryConfig.HeaderPattern,
|
||||
Regex: ".*" + canaryConfig.HeaderPattern + ".*",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -140,17 +140,19 @@ func GetHost(annotations map[string]string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Istio requires that the name of the gateway must conform to the DNS label.
|
||||
// For details, you can view: https://github.com/istio/istio/blob/2d5c40ad5e9cceebe64106005aa38381097da2ba/pkg/config/validation/validation.go#L478
|
||||
func convertToDNSLabelValid(input string) string {
|
||||
hasher := md5.New()
|
||||
hasher.Write([]byte(input))
|
||||
hash := hasher.Sum(nil)
|
||||
|
||||
return hex.EncodeToString(hash)
|
||||
}
|
||||
|
||||
// CleanHost follow the format of mse-ops for host.
|
||||
func CleanHost(host string) string {
|
||||
if host == "*" {
|
||||
return "global"
|
||||
}
|
||||
|
||||
if strings.HasPrefix(host, "*") {
|
||||
host = strings.ReplaceAll(host, "*", "global-")
|
||||
}
|
||||
|
||||
return strings.ReplaceAll(host, ".", "-")
|
||||
return convertToDNSLabelValid(host)
|
||||
}
|
||||
|
||||
func CreateConvertedName(items ...string) string {
|
||||
|
||||
@@ -34,12 +34,21 @@ const (
|
||||
type ItemEventHandler = func(name string)
|
||||
|
||||
type HigressConfig struct {
|
||||
Tracing *Tracing `json:"tracing,omitempty"`
|
||||
Tracing *Tracing `json:"tracing,omitempty"`
|
||||
Gzip *Gzip `json:"gzip,omitempty"`
|
||||
Downstream *Downstream `json:"downstream,omitempty"`
|
||||
DisableXEnvoyHeaders bool `json:"disableXEnvoyHeaders,omitempty"`
|
||||
AddXRealIpHeader bool `json:"addXRealIpHeader,omitempty"`
|
||||
}
|
||||
|
||||
func NewDefaultHigressConfig() *HigressConfig {
|
||||
globalOption := NewDefaultGlobalOption()
|
||||
higressConfig := &HigressConfig{
|
||||
Tracing: NewDefaultTracing(),
|
||||
Tracing: NewDefaultTracing(),
|
||||
Gzip: NewDefaultGzip(),
|
||||
Downstream: globalOption.Downstream,
|
||||
DisableXEnvoyHeaders: globalOption.DisableXEnvoyHeaders,
|
||||
AddXRealIpHeader: globalOption.AddXRealIpHeader,
|
||||
}
|
||||
return higressConfig
|
||||
}
|
||||
|
||||
@@ -74,6 +74,13 @@ func NewConfigmapMgr(XDSUpdater model.XDSUpdater, namespace string, higressConfi
|
||||
|
||||
tracingController := NewTracingController(namespace)
|
||||
configmapMgr.AddItemControllers(tracingController)
|
||||
|
||||
gzipController := NewGzipController(namespace)
|
||||
configmapMgr.AddItemControllers(gzipController)
|
||||
|
||||
globalOptionController := NewGlobalOptionController(namespace)
|
||||
configmapMgr.AddItemControllers(globalOptionController)
|
||||
|
||||
configmapMgr.initEventHandlers()
|
||||
|
||||
return configmapMgr
|
||||
|
||||
502
pkg/ingress/kube/configmap/global.go
Normal file
502
pkg/ingress/kube/configmap/global.go
Normal file
@@ -0,0 +1,502 @@
|
||||
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
//
|
||||
// Licensed 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 configmap
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/alibaba/higress/pkg/ingress/kube/util"
|
||||
. "github.com/alibaba/higress/pkg/ingress/log"
|
||||
networking "istio.io/api/networking/v1alpha3"
|
||||
"istio.io/istio/pkg/config"
|
||||
"istio.io/istio/pkg/config/schema/gvk"
|
||||
)
|
||||
|
||||
const (
|
||||
higressGlobalEnvoyFilterName = "global-option"
|
||||
|
||||
maxMaxRequestHeadersKb = 8192
|
||||
minMaxConcurrentStreams = 1
|
||||
maxMaxConcurrentStreams = 2147483647
|
||||
minInitialStreamWindowSize = 65535
|
||||
maxInitialStreamWindowSize = 2147483647
|
||||
minInitialConnectionWindowSize = 65535
|
||||
maxInitialConnectionWindowSize = 2147483647
|
||||
|
||||
defaultIdleTimeout = 180
|
||||
defaultMaxRequestHeadersKb = 60
|
||||
defaultConnectionBufferLimits = 32768
|
||||
defaultMaxConcurrentStreams = 100
|
||||
defaultInitialStreamWindowSize = 65535
|
||||
defaultInitialConnectionWindowSize = 1048576
|
||||
defaultAddXRealIpHeader = false
|
||||
defaultDisableXEnvoyHeaders = false
|
||||
)
|
||||
|
||||
// Global configures the behavior of the downstream connection, x-real-ip header and x-envoy headers.
|
||||
type Global struct {
|
||||
Downstream *Downstream `json:"downstream,omitempty"`
|
||||
AddXRealIpHeader bool `json:"addXRealIpHeader,omitempty"`
|
||||
DisableXEnvoyHeaders bool `json:"disableXEnvoyHeaders,omitempty"`
|
||||
}
|
||||
|
||||
// Downstream configures the behavior of the downstream connection.
|
||||
type Downstream struct {
|
||||
// IdleTimeout limits the time that a connection may be idle and stream idle.
|
||||
IdleTimeout uint32 `json:"idleTimeout,omitempty"`
|
||||
// MaxRequestHeadersKb limits the size of request headers allowed.
|
||||
MaxRequestHeadersKb uint32 `json:"maxRequestHeadersKb,omitempty"`
|
||||
// ConnectionBufferLimits configures the buffer size limits for connections.
|
||||
ConnectionBufferLimits uint32 `json:"connectionBufferLimits,omitempty"`
|
||||
// Http2 configures HTTP/2 specific options.
|
||||
Http2 *Http2 `json:"http2,omitempty"`
|
||||
}
|
||||
|
||||
// Http2 configures HTTP/2 specific options.
|
||||
type Http2 struct {
|
||||
// MaxConcurrentStreams limits the number of concurrent streams allowed.
|
||||
MaxConcurrentStreams uint32 `json:"maxConcurrentStreams,omitempty"`
|
||||
// InitialStreamWindowSize limits the initial window size of stream.
|
||||
InitialStreamWindowSize uint32 `json:"initialStreamWindowSize,omitempty"`
|
||||
// InitialConnectionWindowSize limits the initial window size of connection.
|
||||
InitialConnectionWindowSize uint32 `json:"initialConnectionWindowSize,omitempty"`
|
||||
}
|
||||
|
||||
// validGlobal validates the global config.
|
||||
func validGlobal(global *Global) error {
|
||||
if global == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if global.Downstream == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
downStream := global.Downstream
|
||||
|
||||
// check maxRequestHeadersKb
|
||||
if downStream.MaxRequestHeadersKb > maxMaxRequestHeadersKb {
|
||||
return fmt.Errorf("maxRequestHeadersKb must be less than or equal to 8192")
|
||||
}
|
||||
// check http2
|
||||
if downStream.Http2 != nil {
|
||||
// check maxConcurrentStreams
|
||||
if downStream.Http2.MaxConcurrentStreams < minMaxConcurrentStreams ||
|
||||
downStream.Http2.MaxConcurrentStreams > maxMaxConcurrentStreams {
|
||||
return fmt.Errorf("http2.maxConcurrentStreams must be between 1 and 2147483647")
|
||||
}
|
||||
// check initialStreamWindowSize
|
||||
if downStream.Http2.InitialStreamWindowSize < minInitialStreamWindowSize ||
|
||||
downStream.Http2.InitialStreamWindowSize > maxInitialStreamWindowSize {
|
||||
return fmt.Errorf("http2.initialStreamWindowSize must be between 65535 and 2147483647")
|
||||
}
|
||||
// check initialConnectionWindowSize
|
||||
if downStream.Http2.InitialConnectionWindowSize < minInitialConnectionWindowSize ||
|
||||
downStream.Http2.InitialConnectionWindowSize > maxInitialConnectionWindowSize {
|
||||
return fmt.Errorf("http2.initialConnectionWindowSize must be between 65535 and 2147483647")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// compareGlobal compares the old and new global option.
|
||||
func compareGlobal(old *Global, new *Global) (Result, error) {
|
||||
if old == nil && new == nil {
|
||||
return ResultNothing, nil
|
||||
}
|
||||
|
||||
if new == nil {
|
||||
return ResultDelete, nil
|
||||
}
|
||||
|
||||
if new.Downstream == nil && !new.AddXRealIpHeader && !new.DisableXEnvoyHeaders {
|
||||
return ResultDelete, nil
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(old, new) {
|
||||
return ResultReplace, nil
|
||||
}
|
||||
|
||||
return ResultNothing, nil
|
||||
}
|
||||
|
||||
// deepCopyGlobal deep copies the global option.
|
||||
func deepCopyGlobal(global *Global) (*Global, error) {
|
||||
newGlobal := NewDefaultGlobalOption()
|
||||
bytes, err := json.Marshal(global)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = json.Unmarshal(bytes, newGlobal)
|
||||
return newGlobal, err
|
||||
}
|
||||
|
||||
// NewDefaultGlobalOption returns a default global config.
|
||||
func NewDefaultGlobalOption() *Global {
|
||||
return &Global{
|
||||
Downstream: NewDefaultDownstream(),
|
||||
AddXRealIpHeader: defaultAddXRealIpHeader,
|
||||
DisableXEnvoyHeaders: defaultDisableXEnvoyHeaders,
|
||||
}
|
||||
}
|
||||
|
||||
// NewDefaultDownstream returns a default downstream config.
|
||||
func NewDefaultDownstream() *Downstream {
|
||||
return &Downstream{
|
||||
IdleTimeout: defaultIdleTimeout,
|
||||
MaxRequestHeadersKb: defaultMaxRequestHeadersKb,
|
||||
ConnectionBufferLimits: defaultConnectionBufferLimits,
|
||||
Http2: NewDefaultHttp2(),
|
||||
}
|
||||
}
|
||||
|
||||
// NewDefaultHttp2 returns a default http2 config.
|
||||
func NewDefaultHttp2() *Http2 {
|
||||
return &Http2{
|
||||
MaxConcurrentStreams: defaultMaxConcurrentStreams,
|
||||
InitialStreamWindowSize: defaultInitialStreamWindowSize,
|
||||
InitialConnectionWindowSize: defaultInitialConnectionWindowSize,
|
||||
}
|
||||
}
|
||||
|
||||
// GlobalOptionController is the controller of downstream config.
|
||||
type GlobalOptionController struct {
|
||||
Namespace string
|
||||
global atomic.Value
|
||||
Name string
|
||||
eventHandler ItemEventHandler
|
||||
}
|
||||
|
||||
// NewGlobalOptionController returns a GlobalOptionController.
|
||||
func NewGlobalOptionController(namespace string) *GlobalOptionController {
|
||||
globalOptionController := &GlobalOptionController{
|
||||
Namespace: namespace,
|
||||
global: atomic.Value{},
|
||||
Name: "global-option",
|
||||
}
|
||||
globalOptionController.SetGlobal(NewDefaultGlobalOption())
|
||||
return globalOptionController
|
||||
}
|
||||
|
||||
func (g *GlobalOptionController) SetGlobal(global *Global) {
|
||||
g.global.Store(global)
|
||||
}
|
||||
|
||||
func (g *GlobalOptionController) GetGlobal() *Global {
|
||||
value := g.global.Load()
|
||||
if value != nil {
|
||||
if global, ok := value.(*Global); ok {
|
||||
return global
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *GlobalOptionController) GetName() string {
|
||||
return g.Name
|
||||
}
|
||||
|
||||
func (g *GlobalOptionController) AddOrUpdateHigressConfig(name util.ClusterNamespacedName, old *HigressConfig, new *HigressConfig) error {
|
||||
newGlobal := &Global{
|
||||
Downstream: new.Downstream,
|
||||
AddXRealIpHeader: new.AddXRealIpHeader,
|
||||
DisableXEnvoyHeaders: new.DisableXEnvoyHeaders,
|
||||
}
|
||||
|
||||
oldGlobal := &Global{
|
||||
Downstream: old.Downstream,
|
||||
AddXRealIpHeader: old.AddXRealIpHeader,
|
||||
DisableXEnvoyHeaders: old.DisableXEnvoyHeaders,
|
||||
}
|
||||
|
||||
err := validGlobal(newGlobal)
|
||||
if err != nil {
|
||||
IngressLog.Errorf("data:%+v convert to global-option config error, error: %+v", newGlobal, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
result, _ := compareGlobal(oldGlobal, newGlobal)
|
||||
|
||||
switch result {
|
||||
case ResultReplace:
|
||||
if newGlobalCopy, err := deepCopyGlobal(newGlobal); err != nil {
|
||||
IngressLog.Infof("global-option config deepcopy error:%v", err)
|
||||
} else {
|
||||
g.SetGlobal(newGlobalCopy)
|
||||
IngressLog.Infof("AddOrUpdate Higress config global-option")
|
||||
g.eventHandler(higressGlobalEnvoyFilterName)
|
||||
IngressLog.Infof("send event with filter name:%s", higressGlobalEnvoyFilterName)
|
||||
}
|
||||
case ResultDelete:
|
||||
g.SetGlobal(NewDefaultGlobalOption())
|
||||
IngressLog.Infof("Delete Higress config global-option")
|
||||
g.eventHandler(higressGlobalEnvoyFilterName)
|
||||
IngressLog.Infof("send event with filter name:%s", higressGlobalEnvoyFilterName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *GlobalOptionController) ValidHigressConfig(higressConfig *HigressConfig) error {
|
||||
if higressConfig == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if higressConfig.Downstream == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
global := &Global{
|
||||
Downstream: higressConfig.Downstream,
|
||||
AddXRealIpHeader: higressConfig.AddXRealIpHeader,
|
||||
DisableXEnvoyHeaders: higressConfig.DisableXEnvoyHeaders,
|
||||
}
|
||||
|
||||
return validGlobal(global)
|
||||
}
|
||||
|
||||
func (g *GlobalOptionController) ConstructEnvoyFilters() ([]*config.Config, error) {
|
||||
configPatch := make([]*networking.EnvoyFilter_EnvoyConfigObjectPatch, 0)
|
||||
global := g.GetGlobal()
|
||||
if global == nil {
|
||||
configs := make([]*config.Config, 0)
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
namespace := g.Namespace
|
||||
|
||||
if global.AddXRealIpHeader {
|
||||
addXRealIpStruct := g.constructAddXRealIpHeader()
|
||||
addXRealIpHeaderConfig := g.generateAddXRealIpHeaderEnvoyFilter(addXRealIpStruct, namespace)
|
||||
configPatch = append(configPatch, addXRealIpHeaderConfig...)
|
||||
}
|
||||
|
||||
if global.DisableXEnvoyHeaders {
|
||||
disableXEnvoyHeadersStruct := g.constructDisableXEnvoyHeaders()
|
||||
disableXEnvoyHeadersConfig := g.generateDisableXEnvoyHeadersEnvoyFilter(disableXEnvoyHeadersStruct, namespace)
|
||||
configPatch = append(configPatch, disableXEnvoyHeadersConfig...)
|
||||
}
|
||||
|
||||
if global.Downstream == nil {
|
||||
return generateEnvoyFilter(namespace, configPatch), nil
|
||||
}
|
||||
|
||||
downstreamStruct := g.constructDownstream(global.Downstream)
|
||||
bufferLimitStruct := g.constructBufferLimit(global.Downstream)
|
||||
if len(downstreamStruct) == 0 && len(bufferLimitStruct) == 0 {
|
||||
return generateEnvoyFilter(namespace, configPatch), nil
|
||||
}
|
||||
|
||||
downstreamConfig := g.generateDownstreamEnvoyFilter(downstreamStruct, bufferLimitStruct, namespace)
|
||||
configPatch = append(configPatch, downstreamConfig...)
|
||||
|
||||
return generateEnvoyFilter(namespace, configPatch), nil
|
||||
}
|
||||
|
||||
func generateEnvoyFilter(namespace string, configPatch []*networking.EnvoyFilter_EnvoyConfigObjectPatch) []*config.Config {
|
||||
configs := make([]*config.Config, 0)
|
||||
envoyConfig := &config.Config{
|
||||
Meta: config.Meta{
|
||||
GroupVersionKind: gvk.EnvoyFilter,
|
||||
Name: higressGlobalEnvoyFilterName,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: &networking.EnvoyFilter{
|
||||
ConfigPatches: configPatch,
|
||||
},
|
||||
}
|
||||
configs = append(configs, envoyConfig)
|
||||
return configs
|
||||
}
|
||||
|
||||
func (g *GlobalOptionController) RegisterItemEventHandler(eventHandler ItemEventHandler) {
|
||||
g.eventHandler = eventHandler
|
||||
}
|
||||
|
||||
// generateDownstreamEnvoyFilter generates the downstream envoy filter.
|
||||
func (g *GlobalOptionController) generateDownstreamEnvoyFilter(downstreamValueStruct string, bufferLimitStruct string, namespace string) []*networking.EnvoyFilter_EnvoyConfigObjectPatch {
|
||||
downstreamConfig := []*networking.EnvoyFilter_EnvoyConfigObjectPatch{
|
||||
{
|
||||
ApplyTo: networking.EnvoyFilter_NETWORK_FILTER,
|
||||
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
|
||||
Context: networking.EnvoyFilter_GATEWAY,
|
||||
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
|
||||
Listener: &networking.EnvoyFilter_ListenerMatch{
|
||||
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
|
||||
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
|
||||
Name: "envoy.filters.network.http_connection_manager",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Patch: &networking.EnvoyFilter_Patch{
|
||||
Operation: networking.EnvoyFilter_Patch_MERGE,
|
||||
Value: util.BuildPatchStruct(downstreamValueStruct),
|
||||
},
|
||||
},
|
||||
{
|
||||
ApplyTo: networking.EnvoyFilter_LISTENER,
|
||||
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
|
||||
Context: networking.EnvoyFilter_GATEWAY,
|
||||
},
|
||||
Patch: &networking.EnvoyFilter_Patch{
|
||||
Operation: networking.EnvoyFilter_Patch_MERGE,
|
||||
Value: util.BuildPatchStruct(bufferLimitStruct),
|
||||
},
|
||||
},
|
||||
}
|
||||
return downstreamConfig
|
||||
}
|
||||
|
||||
// generateAddXRealIpHeaderEnvoyFilter generates the add x-real-ip header envoy filter.
|
||||
func (g *GlobalOptionController) generateAddXRealIpHeaderEnvoyFilter(addXRealIpHeaderStruct string, namespace string) []*networking.EnvoyFilter_EnvoyConfigObjectPatch {
|
||||
addXRealIpHeaderConfig := []*networking.EnvoyFilter_EnvoyConfigObjectPatch{
|
||||
{
|
||||
ApplyTo: networking.EnvoyFilter_ROUTE_CONFIGURATION,
|
||||
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
|
||||
Context: networking.EnvoyFilter_GATEWAY,
|
||||
},
|
||||
Patch: &networking.EnvoyFilter_Patch{
|
||||
Operation: networking.EnvoyFilter_Patch_MERGE,
|
||||
Value: util.BuildPatchStruct(addXRealIpHeaderStruct),
|
||||
},
|
||||
},
|
||||
}
|
||||
return addXRealIpHeaderConfig
|
||||
}
|
||||
|
||||
// generateDisableXEnvoyHeadersEnvoyFilter generates the disable x-envoy headers envoy filter.
|
||||
func (g *GlobalOptionController) generateDisableXEnvoyHeadersEnvoyFilter(disableXEnvoyStruct string, namespace string) []*networking.EnvoyFilter_EnvoyConfigObjectPatch {
|
||||
disableXEnvoyHeadersConfig := []*networking.EnvoyFilter_EnvoyConfigObjectPatch{
|
||||
{
|
||||
ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
|
||||
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
|
||||
Context: networking.EnvoyFilter_GATEWAY,
|
||||
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
|
||||
Listener: &networking.EnvoyFilter_ListenerMatch{
|
||||
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
|
||||
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
|
||||
Name: "envoy.filters.network.http_connection_manager",
|
||||
SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{
|
||||
Name: "envoy.filters.http.router",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Patch: &networking.EnvoyFilter_Patch{
|
||||
Operation: networking.EnvoyFilter_Patch_REPLACE,
|
||||
Value: util.BuildPatchStruct(disableXEnvoyStruct),
|
||||
},
|
||||
},
|
||||
}
|
||||
return disableXEnvoyHeadersConfig
|
||||
}
|
||||
|
||||
// constructDownstream constructs the downstream config.
|
||||
func (g *GlobalOptionController) constructDownstream(downstream *Downstream) string {
|
||||
downstreamConfig := ""
|
||||
idleTimeout := downstream.IdleTimeout
|
||||
maxRequestHeadersKb := downstream.MaxRequestHeadersKb
|
||||
|
||||
if downstream.Http2 != nil {
|
||||
maxConcurrentStreams := downstream.Http2.MaxConcurrentStreams
|
||||
initialStreamWindowSize := downstream.Http2.InitialStreamWindowSize
|
||||
initialConnectionWindowSize := downstream.Http2.InitialConnectionWindowSize
|
||||
|
||||
downstreamConfig = fmt.Sprintf(`
|
||||
{
|
||||
"name": "envoy.filters.network.http_connection_manager",
|
||||
"typed_config": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
|
||||
"common_http_protocol_options": {
|
||||
"idleTimeout": "%ds"
|
||||
},
|
||||
"http2_protocol_options": {
|
||||
"maxConcurrentStreams": %d,
|
||||
"initialStreamWindowSize": %d,
|
||||
"initialConnectionWindowSize": %d
|
||||
},
|
||||
"maxRequestHeadersKb": %d,
|
||||
"streamIdleTimeout": "%ds"
|
||||
}
|
||||
}
|
||||
`, idleTimeout, maxConcurrentStreams, initialStreamWindowSize, initialConnectionWindowSize, maxRequestHeadersKb, idleTimeout)
|
||||
return downstreamConfig
|
||||
}
|
||||
|
||||
downstreamConfig = fmt.Sprintf(`
|
||||
{
|
||||
"name": "envoy.filters.network.http_connection_manager",
|
||||
"typed_config": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
|
||||
"common_http_protocol_options": {
|
||||
"idleTimeout": "%ds"
|
||||
},
|
||||
"maxRequestHeadersKb": %d,
|
||||
"streamIdleTimeout": "%ds"
|
||||
}
|
||||
}
|
||||
`, idleTimeout, maxRequestHeadersKb, idleTimeout)
|
||||
|
||||
return downstreamConfig
|
||||
}
|
||||
|
||||
// constructAddXRealIpHeader constructs the add x-real-ip header config.
|
||||
func (g *GlobalOptionController) constructAddXRealIpHeader() string {
|
||||
addXRealIpHeaderStruct := fmt.Sprintf(`
|
||||
{
|
||||
"request_headers_to_add": [
|
||||
{
|
||||
"append": false,
|
||||
"header": {
|
||||
"key": "x-real-ip",
|
||||
"value": "%%REQ(X-ENVOY-EXTERNAL-ADDRESS)%%"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
`)
|
||||
return addXRealIpHeaderStruct
|
||||
}
|
||||
|
||||
// constructDisableXEnvoyHeaders constructs the disable x-envoy headers config.
|
||||
func (g *GlobalOptionController) constructDisableXEnvoyHeaders() string {
|
||||
disableXEnvoyHeadersStruct := fmt.Sprintf(`
|
||||
{
|
||||
"name": "envoy.filters.http.router",
|
||||
"typed_config": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router",
|
||||
"suppress_envoy_headers": true
|
||||
}
|
||||
}
|
||||
`)
|
||||
return disableXEnvoyHeadersStruct
|
||||
}
|
||||
|
||||
// constructBufferLimit constructs the buffer limit config.
|
||||
func (g *GlobalOptionController) constructBufferLimit(downstream *Downstream) string {
|
||||
return fmt.Sprintf(`
|
||||
{
|
||||
"per_connection_buffer_limit_bytes": %d
|
||||
}
|
||||
`, downstream.ConnectionBufferLimits)
|
||||
}
|
||||
252
pkg/ingress/kube/configmap/global_test.go
Normal file
252
pkg/ingress/kube/configmap/global_test.go
Normal file
@@ -0,0 +1,252 @@
|
||||
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
//
|
||||
// Licensed 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 configmap
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/alibaba/higress/pkg/ingress/kube/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_validGlobal(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
global *Global
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "default",
|
||||
global: NewDefaultGlobalOption(),
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
name: "nil",
|
||||
global: nil,
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
name: "downstream nil",
|
||||
global: &Global{
|
||||
Downstream: nil,
|
||||
AddXRealIpHeader: true,
|
||||
DisableXEnvoyHeaders: true,
|
||||
},
|
||||
wantErr: nil,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := validGlobal(tt.global)
|
||||
assert.Equal(t, tt.wantErr, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_compareGlobal(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
old *Global
|
||||
new *Global
|
||||
want Result
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "compare both nil",
|
||||
old: nil,
|
||||
new: nil,
|
||||
want: ResultNothing,
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
name: "compare new nil 1",
|
||||
old: NewDefaultGlobalOption(),
|
||||
new: nil,
|
||||
want: ResultDelete,
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
name: "compare new nil 2",
|
||||
old: NewDefaultGlobalOption(),
|
||||
new: &Global{},
|
||||
want: ResultDelete,
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
name: "compare result equal",
|
||||
old: NewDefaultGlobalOption(),
|
||||
new: NewDefaultGlobalOption(),
|
||||
want: ResultNothing,
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
name: "compare result not equal",
|
||||
old: NewDefaultGlobalOption(),
|
||||
new: &Global{
|
||||
Downstream: &Downstream{
|
||||
IdleTimeout: 1,
|
||||
},
|
||||
AddXRealIpHeader: true,
|
||||
DisableXEnvoyHeaders: true,
|
||||
},
|
||||
want: ResultReplace,
|
||||
wantErr: nil,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := compareGlobal(tt.old, tt.new)
|
||||
assert.Equal(t, tt.wantErr, err)
|
||||
assert.Equal(t, tt.want, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_deepCopyGlobal(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
global *Global
|
||||
want *Global
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "deep copy 1",
|
||||
global: NewDefaultGlobalOption(),
|
||||
want: NewDefaultGlobalOption(),
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
name: "deep copy 2",
|
||||
global: &Global{
|
||||
Downstream: &Downstream{
|
||||
IdleTimeout: 1,
|
||||
MaxRequestHeadersKb: 9600,
|
||||
ConnectionBufferLimits: 4096,
|
||||
Http2: NewDefaultHttp2(),
|
||||
},
|
||||
AddXRealIpHeader: true,
|
||||
DisableXEnvoyHeaders: true,
|
||||
},
|
||||
want: &Global{
|
||||
Downstream: &Downstream{
|
||||
IdleTimeout: 1,
|
||||
MaxRequestHeadersKb: 9600,
|
||||
ConnectionBufferLimits: 4096,
|
||||
Http2: NewDefaultHttp2(),
|
||||
},
|
||||
AddXRealIpHeader: true,
|
||||
DisableXEnvoyHeaders: true,
|
||||
},
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
name: "deep copy 3",
|
||||
global: &Global{
|
||||
Downstream: &Downstream{},
|
||||
AddXRealIpHeader: true,
|
||||
DisableXEnvoyHeaders: true,
|
||||
},
|
||||
want: &Global{
|
||||
Downstream: NewDefaultDownstream(),
|
||||
AddXRealIpHeader: true,
|
||||
DisableXEnvoyHeaders: true,
|
||||
},
|
||||
wantErr: nil,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
global, err := deepCopyGlobal(tt.global)
|
||||
assert.Equal(t, tt.wantErr, err)
|
||||
assert.Equal(t, tt.want, global)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_AddOrUpdateHigressConfig(t *testing.T) {
|
||||
eventPush := "default"
|
||||
defaultHandler := func(name string) {
|
||||
eventPush = "push"
|
||||
}
|
||||
defaultName := util.ClusterNamespacedName{}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
old *HigressConfig
|
||||
new *HigressConfig
|
||||
wantErr error
|
||||
wantEventPush string
|
||||
wantGlobal *Global
|
||||
}{
|
||||
{
|
||||
name: "default",
|
||||
new: NewDefaultHigressConfig(),
|
||||
old: NewDefaultHigressConfig(),
|
||||
wantErr: nil,
|
||||
wantEventPush: "default",
|
||||
wantGlobal: NewDefaultGlobalOption(),
|
||||
},
|
||||
{
|
||||
name: "replace and push",
|
||||
old: NewDefaultHigressConfig(),
|
||||
new: &HigressConfig{
|
||||
Downstream: &Downstream{
|
||||
IdleTimeout: 1,
|
||||
},
|
||||
AddXRealIpHeader: true,
|
||||
DisableXEnvoyHeaders: true,
|
||||
},
|
||||
wantErr: nil,
|
||||
wantEventPush: "push",
|
||||
wantGlobal: &Global{
|
||||
Downstream: &Downstream{
|
||||
IdleTimeout: 1,
|
||||
MaxRequestHeadersKb: defaultMaxRequestHeadersKb,
|
||||
ConnectionBufferLimits: defaultConnectionBufferLimits,
|
||||
Http2: NewDefaultHttp2(),
|
||||
},
|
||||
AddXRealIpHeader: true,
|
||||
DisableXEnvoyHeaders: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "delete and push",
|
||||
old: &HigressConfig{
|
||||
Downstream: NewDefaultDownstream(),
|
||||
AddXRealIpHeader: defaultAddXRealIpHeader,
|
||||
DisableXEnvoyHeaders: defaultDisableXEnvoyHeaders,
|
||||
},
|
||||
new: &HigressConfig{},
|
||||
wantErr: nil,
|
||||
wantEventPush: "push",
|
||||
wantGlobal: &Global{
|
||||
Downstream: NewDefaultDownstream(),
|
||||
AddXRealIpHeader: defaultAddXRealIpHeader,
|
||||
DisableXEnvoyHeaders: defaultDisableXEnvoyHeaders,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := NewGlobalOptionController("higress-namespace")
|
||||
g.eventHandler = defaultHandler
|
||||
eventPush = "default"
|
||||
err := g.AddOrUpdateHigressConfig(defaultName, tt.old, tt.new)
|
||||
assert.Equal(t, tt.wantErr, err)
|
||||
assert.Equal(t, tt.wantEventPush, eventPush)
|
||||
assert.Equal(t, tt.wantGlobal, g.GetGlobal())
|
||||
})
|
||||
}
|
||||
}
|
||||
340
pkg/ingress/kube/configmap/gzip.go
Normal file
340
pkg/ingress/kube/configmap/gzip.go
Normal file
@@ -0,0 +1,340 @@
|
||||
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
//
|
||||
// Licensed 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 configmap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/alibaba/higress/pkg/ingress/kube/util"
|
||||
. "github.com/alibaba/higress/pkg/ingress/log"
|
||||
networking "istio.io/api/networking/v1alpha3"
|
||||
"istio.io/istio/pkg/config"
|
||||
"istio.io/istio/pkg/config/schema/gvk"
|
||||
)
|
||||
|
||||
const (
|
||||
higressGzipEnvoyFilterName = "higress-config-gzip"
|
||||
compressionStrategyValues = "DEFAULT_STRATEGY,FILTERED,HUFFMAN_ONLY,RLE,FIXED"
|
||||
compressionLevelValues = "BEST_COMPRESSION,BEST_SPEED,COMPRESSION_LEVEL_1,COMPRESSION_LEVEL_2,COMPRESSION_LEVEL_3,COMPRESSION_LEVEL_4,COMPRESSION_LEVEL_5,COMPRESSION_LEVEL_6,COMPRESSION_LEVEL_7,COMPRESSION_LEVEL_8,COMPRESSION_LEVEL_9"
|
||||
)
|
||||
|
||||
type Gzip struct {
|
||||
// Flag to control gzip
|
||||
Enable bool `json:"enable,omitempty"`
|
||||
MinContentLength int32 `json:"minContentLength,omitempty"`
|
||||
ContentType []string `json:"contentType,omitempty"`
|
||||
DisableOnEtagHeader bool `json:"disableOnEtagHeader,omitempty"`
|
||||
// Value from 1 to 9 that controls the amount of internal memory used by zlib.
|
||||
// Higher values use more memory, but are faster and produce better compression results. The default value is 5.
|
||||
MemoryLevel int32 `json:"memoryLevel,omitempty"`
|
||||
// Value from 9 to 15 that represents the base two logarithmic of the compressor’s window size.
|
||||
// Larger window results in better compression at the expense of memory usage.
|
||||
// The default is 12 which will produce a 4096 bytes window
|
||||
WindowBits int32 `json:"windowBits,omitempty"`
|
||||
// Value for Zlib’s next output buffer. If not set, defaults to 4096.
|
||||
ChunkSize int32 `json:"chunkSize,omitempty"`
|
||||
// A value used for selecting the zlib compression level.
|
||||
// From COMPRESSION_LEVEL_1 to COMPRESSION_LEVEL_9
|
||||
// BEST_COMPRESSION == COMPRESSION_LEVEL_9 , BEST_SPEED == COMPRESSION_LEVEL_1
|
||||
CompressionLevel string `json:"compressionLevel,omitempty"`
|
||||
// A value used for selecting the zlib compression strategy which is directly related to the characteristics of the content.
|
||||
// Most of the time “DEFAULT_STRATEGY”
|
||||
// Value is one of DEFAULT_STRATEGY, FILTERED, HUFFMAN_ONLY, RLE, FIXED
|
||||
CompressionStrategy string `json:"compressionStrategy,omitempty"`
|
||||
}
|
||||
|
||||
func validGzip(g *Gzip) error {
|
||||
if g == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if g.MinContentLength <= 0 {
|
||||
return errors.New("minContentLength can not be less than zero")
|
||||
}
|
||||
|
||||
if len(g.ContentType) == 0 {
|
||||
return errors.New("content type can not be empty")
|
||||
}
|
||||
|
||||
if !(g.MemoryLevel >= 1 && g.MemoryLevel <= 9) {
|
||||
return errors.New("memory level need be between 1 and 9")
|
||||
}
|
||||
|
||||
if !(g.WindowBits >= 9 && g.WindowBits <= 15) {
|
||||
return errors.New("window bits need be between 9 and 15")
|
||||
}
|
||||
|
||||
if g.ChunkSize <= 0 {
|
||||
return errors.New("chunk size need be large than zero")
|
||||
}
|
||||
|
||||
compressionLevels := strings.Split(compressionLevelValues, ",")
|
||||
isFound := false
|
||||
for _, v := range compressionLevels {
|
||||
if g.CompressionLevel == v {
|
||||
isFound = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isFound {
|
||||
return fmt.Errorf("compressionLevel need be one of %s", compressionLevelValues)
|
||||
}
|
||||
|
||||
isFound = false
|
||||
compressionStrategies := strings.Split(compressionStrategyValues, ",")
|
||||
for _, v := range compressionStrategies {
|
||||
if g.CompressionStrategy == v {
|
||||
isFound = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isFound {
|
||||
return fmt.Errorf("compressionStrategy need be one of %s", compressionStrategyValues)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func compareGzip(old *Gzip, new *Gzip) (Result, error) {
|
||||
if old == nil && new == nil {
|
||||
return ResultNothing, nil
|
||||
}
|
||||
|
||||
if new == nil {
|
||||
return ResultDelete, nil
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(old, new) {
|
||||
return ResultReplace, nil
|
||||
}
|
||||
|
||||
return ResultNothing, nil
|
||||
}
|
||||
|
||||
func deepCopyGzip(gzip *Gzip) (*Gzip, error) {
|
||||
newGzip := NewDefaultGzip()
|
||||
newGzip.Enable = gzip.Enable
|
||||
newGzip.MinContentLength = gzip.MinContentLength
|
||||
newGzip.ContentType = make([]string, 0, len(gzip.ContentType))
|
||||
newGzip.ContentType = append(newGzip.ContentType, gzip.ContentType...)
|
||||
newGzip.DisableOnEtagHeader = gzip.DisableOnEtagHeader
|
||||
newGzip.MemoryLevel = gzip.MemoryLevel
|
||||
newGzip.WindowBits = gzip.WindowBits
|
||||
newGzip.ChunkSize = gzip.ChunkSize
|
||||
newGzip.CompressionLevel = gzip.CompressionLevel
|
||||
newGzip.CompressionStrategy = gzip.CompressionStrategy
|
||||
return newGzip, nil
|
||||
}
|
||||
|
||||
func NewDefaultGzip() *Gzip {
|
||||
gzip := &Gzip{
|
||||
Enable: false,
|
||||
MinContentLength: 1024,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
}
|
||||
return gzip
|
||||
}
|
||||
|
||||
type GzipController struct {
|
||||
Namespace string
|
||||
gzip atomic.Value
|
||||
Name string
|
||||
eventHandler ItemEventHandler
|
||||
}
|
||||
|
||||
func NewGzipController(namespace string) *GzipController {
|
||||
gzipController := &GzipController{
|
||||
Namespace: namespace,
|
||||
gzip: atomic.Value{},
|
||||
Name: "gzip",
|
||||
}
|
||||
gzipController.SetGzip(NewDefaultGzip())
|
||||
return gzipController
|
||||
}
|
||||
|
||||
func (g *GzipController) GetName() string {
|
||||
return g.Name
|
||||
}
|
||||
|
||||
func (t *GzipController) SetGzip(gzip *Gzip) {
|
||||
t.gzip.Store(gzip)
|
||||
}
|
||||
|
||||
func (g *GzipController) GetGzip() *Gzip {
|
||||
value := g.gzip.Load()
|
||||
if value != nil {
|
||||
if gzip, ok := value.(*Gzip); ok {
|
||||
return gzip
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *GzipController) AddOrUpdateHigressConfig(name util.ClusterNamespacedName, old *HigressConfig, new *HigressConfig) error {
|
||||
if err := validGzip(new.Gzip); err != nil {
|
||||
IngressLog.Errorf("data:%+v convert to gzip , error: %+v", new.Gzip, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
result, _ := compareGzip(old.Gzip, new.Gzip)
|
||||
|
||||
switch result {
|
||||
case ResultReplace:
|
||||
if newGzip, err := deepCopyGzip(new.Gzip); err != nil {
|
||||
IngressLog.Infof("gzip deepcopy error:%v", err)
|
||||
} else {
|
||||
g.SetGzip(newGzip)
|
||||
IngressLog.Infof("AddOrUpdate Higress config gzip")
|
||||
g.eventHandler(higressGzipEnvoyFilterName)
|
||||
IngressLog.Infof("send event with filter name:%s", higressGzipEnvoyFilterName)
|
||||
}
|
||||
case ResultDelete:
|
||||
g.SetGzip(NewDefaultGzip())
|
||||
IngressLog.Infof("Delete Higress config gzip")
|
||||
g.eventHandler(higressGzipEnvoyFilterName)
|
||||
IngressLog.Infof("send event with filter name:%s", higressGzipEnvoyFilterName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *GzipController) ValidHigressConfig(higressConfig *HigressConfig) error {
|
||||
if higressConfig == nil {
|
||||
return nil
|
||||
}
|
||||
if higressConfig.Gzip == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return validGzip(higressConfig.Gzip)
|
||||
}
|
||||
|
||||
func (g *GzipController) ConstructEnvoyFilters() ([]*config.Config, error) {
|
||||
configs := make([]*config.Config, 0)
|
||||
gzip := g.GetGzip()
|
||||
namespace := g.Namespace
|
||||
|
||||
if gzip == nil {
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
if gzip.Enable == false {
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
gzipStruct := g.constructGzipStruct(gzip, namespace)
|
||||
if len(gzipStruct) == 0 {
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
config := &config.Config{
|
||||
Meta: config.Meta{
|
||||
GroupVersionKind: gvk.EnvoyFilter,
|
||||
Name: higressGzipEnvoyFilterName,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: &networking.EnvoyFilter{
|
||||
ConfigPatches: []*networking.EnvoyFilter_EnvoyConfigObjectPatch{
|
||||
{
|
||||
ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
|
||||
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
|
||||
Context: networking.EnvoyFilter_GATEWAY,
|
||||
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
|
||||
Listener: &networking.EnvoyFilter_ListenerMatch{
|
||||
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
|
||||
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
|
||||
Name: "envoy.filters.network.http_connection_manager",
|
||||
SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{
|
||||
Name: "envoy.filters.http.cors",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Patch: &networking.EnvoyFilter_Patch{
|
||||
Operation: networking.EnvoyFilter_Patch_INSERT_BEFORE,
|
||||
Value: util.BuildPatchStruct(gzipStruct),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
configs = append(configs, config)
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
func (g *GzipController) RegisterItemEventHandler(eventHandler ItemEventHandler) {
|
||||
g.eventHandler = eventHandler
|
||||
}
|
||||
|
||||
func (g *GzipController) constructGzipStruct(gzip *Gzip, namespace string) string {
|
||||
gzipConfig := ""
|
||||
contentType := ""
|
||||
index := 0
|
||||
for _, v := range gzip.ContentType {
|
||||
contentType = contentType + fmt.Sprintf("\"%s\"", v)
|
||||
if index < len(gzip.ContentType)-1 {
|
||||
contentType = contentType + ","
|
||||
}
|
||||
index++
|
||||
}
|
||||
structFmt := `{
|
||||
"name": "envoy.filters.http.compressor",
|
||||
"typed_config": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.http.compressor.v3.Compressor",
|
||||
"response_direction_config": {
|
||||
"common_config": {
|
||||
"min_content_length": %d,
|
||||
"content_type": [%s]
|
||||
},
|
||||
"disable_on_etag_header": %t
|
||||
},
|
||||
"request_direction_config": {
|
||||
"common_config": {
|
||||
"enabled": {
|
||||
"default_value": false,
|
||||
"runtime_key": "request_compressor_enabled"
|
||||
}
|
||||
}
|
||||
},
|
||||
"compressor_library": {
|
||||
"name": "text_optimized",
|
||||
"typed_config": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.compression.gzip.compressor.v3.Gzip",
|
||||
"memory_level": %d,
|
||||
"window_bits": %d,
|
||||
"check_size": %d,
|
||||
"compression_level": "%s",
|
||||
"compression_strategy": "%s"
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
gzipConfig = fmt.Sprintf(structFmt, gzip.MinContentLength, contentType, gzip.DisableOnEtagHeader,
|
||||
gzip.MemoryLevel, gzip.WindowBits, gzip.ChunkSize, gzip.CompressionLevel, gzip.CompressionStrategy)
|
||||
return gzipConfig
|
||||
}
|
||||
522
pkg/ingress/kube/configmap/gzip_test.go
Normal file
522
pkg/ingress/kube/configmap/gzip_test.go
Normal file
@@ -0,0 +1,522 @@
|
||||
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
//
|
||||
// Licensed 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 configmap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/alibaba/higress/pkg/ingress/kube/util"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_validGzip(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
gzip *Gzip
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "default",
|
||||
gzip: &Gzip{
|
||||
Enable: false,
|
||||
MinContentLength: 1024,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
name: "nil",
|
||||
gzip: nil,
|
||||
wantErr: nil,
|
||||
},
|
||||
|
||||
{
|
||||
name: "no content type",
|
||||
gzip: &Gzip{
|
||||
Enable: false,
|
||||
MinContentLength: 1024,
|
||||
ContentType: []string{},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
wantErr: errors.New("content type can not be empty"),
|
||||
},
|
||||
|
||||
{
|
||||
name: "MinContentLength less than zero",
|
||||
gzip: &Gzip{
|
||||
Enable: false,
|
||||
MinContentLength: 0,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
wantErr: errors.New("minContentLength can not be less than zero"),
|
||||
},
|
||||
|
||||
{
|
||||
name: "MemoryLevel less than 1",
|
||||
gzip: &Gzip{
|
||||
Enable: false,
|
||||
MinContentLength: 1024,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
wantErr: errors.New("memory level need be between 1 and 9"),
|
||||
},
|
||||
|
||||
{
|
||||
name: "WindowBits less than 9",
|
||||
gzip: &Gzip{
|
||||
Enable: false,
|
||||
MinContentLength: 1024,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 8,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
wantErr: errors.New("window bits need be between 9 and 15"),
|
||||
},
|
||||
|
||||
{
|
||||
name: "ChunkSize less than zero",
|
||||
gzip: &Gzip{
|
||||
Enable: false,
|
||||
MinContentLength: 1024,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
wantErr: errors.New("chunk size need be large than zero"),
|
||||
},
|
||||
|
||||
{
|
||||
name: "CompressionLevel is not right",
|
||||
gzip: &Gzip{
|
||||
Enable: false,
|
||||
MinContentLength: 1024,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSIONA",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
wantErr: fmt.Errorf("compressionLevel need be one of %s", compressionLevelValues),
|
||||
},
|
||||
|
||||
{
|
||||
name: "CompressionStrategy is not right",
|
||||
gzip: &Gzip{
|
||||
Enable: false,
|
||||
MinContentLength: 1024,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGYA",
|
||||
},
|
||||
wantErr: fmt.Errorf("compressionStrategy need be one of %s", compressionStrategyValues),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := validGzip(tt.gzip); err != nil {
|
||||
assert.Equal(t, tt.wantErr, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_compareGzip(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
old *Gzip
|
||||
new *Gzip
|
||||
wantResult Result
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "compare both nil",
|
||||
old: nil,
|
||||
new: nil,
|
||||
wantResult: ResultNothing,
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
name: "compare result delete",
|
||||
old: &Gzip{
|
||||
Enable: false,
|
||||
MinContentLength: 1024,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
new: nil,
|
||||
wantResult: ResultDelete,
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
name: "compare result equal",
|
||||
old: &Gzip{
|
||||
Enable: false,
|
||||
MinContentLength: 1024,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
new: &Gzip{
|
||||
Enable: false,
|
||||
MinContentLength: 1024,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
wantResult: ResultNothing,
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
name: "compare result replace",
|
||||
old: &Gzip{
|
||||
Enable: false,
|
||||
MinContentLength: 1024,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
new: &Gzip{
|
||||
Enable: true,
|
||||
MinContentLength: 1024,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
wantResult: ResultReplace,
|
||||
wantErr: nil,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := compareGzip(tt.old, tt.new)
|
||||
assert.Equal(t, tt.wantResult, result)
|
||||
assert.Equal(t, tt.wantErr, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_deepCopyGzip(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
gzip *Gzip
|
||||
wantGzip *Gzip
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "deep copy case 1",
|
||||
gzip: &Gzip{
|
||||
Enable: false,
|
||||
MinContentLength: 102,
|
||||
ContentType: []string{"text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: false,
|
||||
MemoryLevel: 6,
|
||||
WindowBits: 11,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_SPEED",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
wantGzip: &Gzip{
|
||||
Enable: false,
|
||||
MinContentLength: 102,
|
||||
ContentType: []string{"text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: false,
|
||||
MemoryLevel: 6,
|
||||
WindowBits: 11,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_SPEED",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
wantErr: nil,
|
||||
},
|
||||
|
||||
{
|
||||
name: "deep copy case 2",
|
||||
gzip: &Gzip{
|
||||
Enable: true,
|
||||
MinContentLength: 102,
|
||||
ContentType: []string{"text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 6,
|
||||
WindowBits: 11,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_SPEED",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
wantGzip: &Gzip{
|
||||
Enable: true,
|
||||
MinContentLength: 102,
|
||||
ContentType: []string{"text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 6,
|
||||
WindowBits: 11,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_SPEED",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
wantErr: nil,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gzip, err := deepCopyGzip(tt.gzip)
|
||||
assert.Equal(t, tt.wantGzip, gzip)
|
||||
assert.Equal(t, tt.wantErr, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGzipController_AddOrUpdateHigressConfig(t *testing.T) {
|
||||
eventPush := "default"
|
||||
defaultHandler := func(name string) {
|
||||
eventPush = "push"
|
||||
}
|
||||
|
||||
defaultName := util.ClusterNamespacedName{}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
old *HigressConfig
|
||||
new *HigressConfig
|
||||
wantErr error
|
||||
wantEventPush string
|
||||
wantGzip *Gzip
|
||||
}{
|
||||
{
|
||||
name: "default",
|
||||
old: &HigressConfig{
|
||||
Gzip: NewDefaultGzip(),
|
||||
},
|
||||
new: &HigressConfig{
|
||||
Gzip: NewDefaultGzip(),
|
||||
},
|
||||
wantErr: nil,
|
||||
wantEventPush: "default",
|
||||
wantGzip: NewDefaultGzip(),
|
||||
},
|
||||
{
|
||||
name: "replace and push 1",
|
||||
old: &HigressConfig{
|
||||
Gzip: NewDefaultGzip(),
|
||||
},
|
||||
new: &HigressConfig{
|
||||
Gzip: &Gzip{
|
||||
Enable: true,
|
||||
MinContentLength: 1024,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantEventPush: "push",
|
||||
wantGzip: &Gzip{
|
||||
Enable: true,
|
||||
MinContentLength: 1024,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "replace and push 2",
|
||||
old: &HigressConfig{
|
||||
Gzip: &Gzip{
|
||||
Enable: true,
|
||||
MinContentLength: 1024,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
},
|
||||
new: &HigressConfig{
|
||||
Gzip: &Gzip{
|
||||
Enable: true,
|
||||
MinContentLength: 2048,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantEventPush: "push",
|
||||
wantGzip: &Gzip{
|
||||
Enable: true,
|
||||
MinContentLength: 2048,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "replace and push 3",
|
||||
old: &HigressConfig{
|
||||
Gzip: &Gzip{
|
||||
Enable: true,
|
||||
MinContentLength: 1024,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
},
|
||||
new: &HigressConfig{
|
||||
Gzip: &Gzip{
|
||||
Enable: false,
|
||||
MinContentLength: 2048,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantEventPush: "push",
|
||||
wantGzip: &Gzip{
|
||||
Enable: false,
|
||||
MinContentLength: 2048,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "delete and push",
|
||||
old: &HigressConfig{
|
||||
Gzip: &Gzip{
|
||||
Enable: true,
|
||||
MinContentLength: 1024,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
},
|
||||
new: &HigressConfig{
|
||||
Gzip: nil,
|
||||
},
|
||||
wantErr: nil,
|
||||
wantEventPush: "push",
|
||||
wantGzip: NewDefaultGzip(),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := NewGzipController("higress-system")
|
||||
g.eventHandler = defaultHandler
|
||||
eventPush = "default"
|
||||
err := g.AddOrUpdateHigressConfig(defaultName, tt.old, tt.new)
|
||||
assert.Equal(t, tt.wantEventPush, eventPush)
|
||||
assert.Equal(t, tt.wantErr, err)
|
||||
assert.Equal(t, tt.wantGzip, g.GetGzip())
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -117,7 +117,7 @@ func validTracing(t *Tracing) error {
|
||||
}
|
||||
}
|
||||
|
||||
if tracerNum != 1 {
|
||||
if tracerNum != 1 && t.Enable == true {
|
||||
return errors.New("only one of skywalking,zipkin and opentelemetry configuration can be set")
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -373,7 +373,6 @@ func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapp
|
||||
}
|
||||
|
||||
for _, rule := range ingressV1Beta.Rules {
|
||||
cleanHost := common.CleanHost(rule.Host)
|
||||
// Need create builder for every rule.
|
||||
domainBuilder := &common.IngressDomainBuilder{
|
||||
ClusterId: c.options.ClusterId,
|
||||
@@ -401,7 +400,7 @@ func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapp
|
||||
Port: &networking.Port{
|
||||
Number: 80,
|
||||
Protocol: string(protocol.HTTP),
|
||||
Name: common.CreateConvertedName("http-80-ingress", c.options.ClusterId, cfg.Namespace, cfg.Name, cleanHost),
|
||||
Name: common.CreateConvertedName("http-80-ingress", c.options.ClusterId),
|
||||
},
|
||||
Hosts: []string{rule.Host},
|
||||
})
|
||||
@@ -446,7 +445,7 @@ func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapp
|
||||
Port: &networking.Port{
|
||||
Number: 443,
|
||||
Protocol: string(protocol.HTTPS),
|
||||
Name: common.CreateConvertedName("https-443-ingress", c.options.ClusterId, cfg.Namespace, cfg.Name, cleanHost),
|
||||
Name: common.CreateConvertedName("https-443-ingress", c.options.ClusterId),
|
||||
},
|
||||
Hosts: []string{rule.Host},
|
||||
Tls: &networking.ServerTLSSettings{
|
||||
|
||||
@@ -358,7 +358,6 @@ func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapp
|
||||
}
|
||||
|
||||
for _, rule := range ingressV1.Rules {
|
||||
cleanHost := common.CleanHost(rule.Host)
|
||||
// Need create builder for every rule.
|
||||
domainBuilder := &common.IngressDomainBuilder{
|
||||
ClusterId: c.options.ClusterId,
|
||||
@@ -386,7 +385,7 @@ func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapp
|
||||
Port: &networking.Port{
|
||||
Number: 80,
|
||||
Protocol: string(protocol.HTTP),
|
||||
Name: common.CreateConvertedName("http-80-ingress", c.options.ClusterId, cfg.Namespace, cfg.Name, cleanHost),
|
||||
Name: common.CreateConvertedName("http-80-ingress", c.options.ClusterId),
|
||||
},
|
||||
Hosts: []string{rule.Host},
|
||||
})
|
||||
@@ -431,7 +430,7 @@ func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapp
|
||||
Port: &networking.Port{
|
||||
Number: 443,
|
||||
Protocol: string(protocol.HTTPS),
|
||||
Name: common.CreateConvertedName("https-443-ingress", c.options.ClusterId, cfg.Namespace, cfg.Name, cleanHost),
|
||||
Name: common.CreateConvertedName("https-443-ingress", c.options.ClusterId),
|
||||
},
|
||||
Hosts: []string{rule.Host},
|
||||
Tls: &networking.ServerTLSSettings{
|
||||
|
||||
@@ -16,7 +16,6 @@ package kingress
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/alibaba/higress/pkg/ingress/kube/annotations"
|
||||
"path"
|
||||
"reflect"
|
||||
"sort"
|
||||
@@ -24,7 +23,6 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/alibaba/higress/pkg/kube"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
networking "istio.io/api/networking/v1alpha3"
|
||||
"istio.io/istio/pilot/pkg/model"
|
||||
@@ -46,10 +44,12 @@ import (
|
||||
ingress "knative.dev/networking/pkg/apis/networking/v1alpha1"
|
||||
networkingv1alpha1 "knative.dev/networking/pkg/client/listers/networking/v1alpha1"
|
||||
|
||||
"github.com/alibaba/higress/pkg/ingress/kube/annotations"
|
||||
"github.com/alibaba/higress/pkg/ingress/kube/common"
|
||||
"github.com/alibaba/higress/pkg/ingress/kube/kingress/resources"
|
||||
"github.com/alibaba/higress/pkg/ingress/kube/secret"
|
||||
. "github.com/alibaba/higress/pkg/ingress/log"
|
||||
"github.com/alibaba/higress/pkg/kube"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -337,7 +337,6 @@ func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapp
|
||||
|
||||
for _, rule := range kingressv1alpha1.Rules {
|
||||
for _, ruleHost := range rule.Hosts {
|
||||
cleanHost := common.CleanHost(ruleHost)
|
||||
// Need create builder for every rule.
|
||||
domainBuilder := &common.IngressDomainBuilder{
|
||||
ClusterId: c.options.ClusterId,
|
||||
@@ -364,7 +363,7 @@ func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapp
|
||||
Port: &networking.Port{
|
||||
Number: 8081,
|
||||
Protocol: string(protocol.HTTP),
|
||||
Name: common.CreateConvertedName("http-8081-ingress", c.options.ClusterId, cfg.Namespace, cfg.Name, cleanHost),
|
||||
Name: common.CreateConvertedName("http-8081-ingress", c.options.ClusterId),
|
||||
},
|
||||
Hosts: []string{ruleHost},
|
||||
})
|
||||
@@ -374,7 +373,7 @@ func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapp
|
||||
Port: &networking.Port{
|
||||
Number: 80,
|
||||
Protocol: string(protocol.HTTP),
|
||||
Name: common.CreateConvertedName("http-80-ingress", c.options.ClusterId, cfg.Namespace, cfg.Name, cleanHost),
|
||||
Name: common.CreateConvertedName("http-80-ingress", c.options.ClusterId),
|
||||
},
|
||||
Hosts: []string{ruleHost},
|
||||
})
|
||||
@@ -436,7 +435,7 @@ func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapp
|
||||
Port: &networking.Port{
|
||||
Number: 443,
|
||||
Protocol: string(protocol.HTTPS),
|
||||
Name: common.CreateConvertedName("https-443-ingress", c.options.ClusterId, cfg.Namespace, cfg.Name, cleanHost),
|
||||
Name: common.CreateConvertedName("https-443-ingress", c.options.ClusterId),
|
||||
},
|
||||
Hosts: []string{ruleHost},
|
||||
Tls: &networking.ServerTLSSettings{
|
||||
|
||||
@@ -347,13 +347,13 @@ bool PluginRootContext::checkPlugin(
|
||||
deniedInvalidDate();
|
||||
return false;
|
||||
}
|
||||
time_offset = std::abs((long long)(timestamp - current_time));
|
||||
// milliseconds to nanoseconds
|
||||
time_offset *= 1e6;
|
||||
timestamp *= 1e6;
|
||||
// seconds
|
||||
if (date.size() < MILLISEC_MIN_LENGTH) {
|
||||
time_offset *= 1e3;
|
||||
timestamp *= 1e3;
|
||||
}
|
||||
time_offset = std::abs((long long)(timestamp - current_time));
|
||||
}
|
||||
if (time_offset > rule.date_nano_offset) {
|
||||
LOG_DEBUG(absl::StrFormat("date expired, offset is: %u",
|
||||
|
||||
@@ -19,6 +19,7 @@ package main
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
|
||||
@@ -292,19 +293,19 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, config BasicAuthConfig, log w
|
||||
}
|
||||
|
||||
func deniedNoBasicAuthData() types.Action {
|
||||
_ = proxywasm.SendHttpResponse(401, WWWAuthenticateHeader(protectionSpace),
|
||||
_ = proxywasm.SendHttpResponse(http.StatusUnauthorized, WWWAuthenticateHeader(protectionSpace),
|
||||
[]byte("Request denied by Basic Auth check. No Basic Authentication information found."), -1)
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
func deniedInvalidCredentials() types.Action {
|
||||
_ = proxywasm.SendHttpResponse(401, WWWAuthenticateHeader(protectionSpace),
|
||||
_ = proxywasm.SendHttpResponse(http.StatusUnauthorized, WWWAuthenticateHeader(protectionSpace),
|
||||
[]byte("Request denied by Basic Auth check. Invalid username and/or password."), -1)
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
func deniedUnauthorizedConsumer() types.Action {
|
||||
_ = proxywasm.SendHttpResponse(403, WWWAuthenticateHeader(protectionSpace),
|
||||
_ = proxywasm.SendHttpResponse(http.StatusForbidden, WWWAuthenticateHeader(protectionSpace),
|
||||
[]byte("Request denied by Basic Auth check. Unauthorized consumer."), -1)
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
@@ -92,20 +92,20 @@ const bodyTemplate string = `
|
||||
|
||||
func onHttpRequestHeaders(ctx wrapper.HttpContext, config MyConfig, log wrapper.Log) types.Action {
|
||||
pairs := strings.SplitN(ctx.Path(), "?", 2)
|
||||
|
||||
|
||||
if len(pairs) < 2 {
|
||||
proxywasm.SendHttpResponse(400, nil, []byte("1-need prompt param"), -1)
|
||||
proxywasm.SendHttpResponse(http.StatusBadRequest, nil, []byte("1-need prompt param"), -1)
|
||||
return types.ActionContinue
|
||||
}
|
||||
querys, err := url.ParseQuery(pairs[1])
|
||||
if err != nil {
|
||||
proxywasm.SendHttpResponse(400, nil, []byte("2-need prompt param"), -1)
|
||||
proxywasm.SendHttpResponse(http.StatusBadRequest, nil, []byte("2-need prompt param"), -1)
|
||||
return types.ActionContinue
|
||||
}
|
||||
var prompt []string
|
||||
var ok bool
|
||||
if prompt, ok = querys[config.PromptParam]; !ok || len(prompt) == 0 {
|
||||
proxywasm.SendHttpResponse(400, nil, []byte("3-need prompt param"), -1)
|
||||
proxywasm.SendHttpResponse(http.StatusBadRequest, nil, []byte("3-need prompt param"), -1)
|
||||
return types.ActionContinue
|
||||
}
|
||||
body := fmt.Sprintf(bodyTemplate, config.Model, prompt[0], config.HumainId, config.AIId)
|
||||
@@ -121,7 +121,7 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, config MyConfig, log wrapper.
|
||||
proxywasm.SendHttpResponse(uint32(statusCode), headers, responseBody, -1)
|
||||
}, 10000)
|
||||
if err != nil {
|
||||
proxywasm.SendHttpResponse(500, nil, []byte("Internel Error: "+err.Error()), -1)
|
||||
proxywasm.SendHttpResponse(http.StatusInternalServerError, nil, []byte("Internel Error: "+err.Error()), -1)
|
||||
return types.ActionContinue
|
||||
}
|
||||
return types.ActionPause
|
||||
|
||||
@@ -17,6 +17,8 @@ package main
|
||||
import (
|
||||
"cors/config"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
|
||||
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
|
||||
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
|
||||
@@ -28,8 +30,6 @@ func main() {
|
||||
"cors",
|
||||
wrapper.ParseConfigBy(parseConfig),
|
||||
wrapper.ProcessRequestHeadersBy(onHttpRequestHeaders),
|
||||
wrapper.ProcessRequestBodyBy(onHttpRequestBody),
|
||||
wrapper.ProcessResponseBodyBy(onHttpResponseBody),
|
||||
wrapper.ProcessResponseHeadersBy(onHttpResponseHeaders),
|
||||
)
|
||||
}
|
||||
@@ -94,7 +94,7 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, corsConfig config.CorsConfig,
|
||||
if !httpCorsContext.IsValid {
|
||||
headers := make([][2]string, 0)
|
||||
headers = append(headers, [2]string{config.HeaderPluginTrace, "trace"})
|
||||
proxywasm.SendHttpResponse(403, headers, []byte("Invalid CORS request"), -1)
|
||||
proxywasm.SendHttpResponse(http.StatusForbidden, headers, []byte("Invalid CORS request"), -1)
|
||||
return types.ActionPause
|
||||
}
|
||||
|
||||
@@ -102,18 +102,13 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, corsConfig config.CorsConfig,
|
||||
if httpCorsContext.IsPreFlight {
|
||||
headers := make([][2]string, 0)
|
||||
headers = append(headers, [2]string{config.HeaderPluginTrace, "trace"})
|
||||
proxywasm.SendHttpResponse(200, headers, nil, -1)
|
||||
proxywasm.SendHttpResponse(http.StatusOK, headers, nil, -1)
|
||||
return types.ActionPause
|
||||
}
|
||||
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
func onHttpRequestBody(ctx wrapper.HttpContext, corsConfig config.CorsConfig, body []byte, log wrapper.Log) types.Action {
|
||||
log.Debug("onHttpRequestBody()")
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
func onHttpResponseHeaders(ctx wrapper.HttpContext, corsConfig config.CorsConfig, log wrapper.Log) types.Action {
|
||||
log.Debug("onHttpResponseHeaders()")
|
||||
// Remove trace header if existed
|
||||
@@ -162,8 +157,3 @@ func onHttpResponseHeaders(ctx wrapper.HttpContext, corsConfig config.CorsConfig
|
||||
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
func onHttpResponseBody(ctx wrapper.HttpContext, corsConfig config.CorsConfig, body []byte, log wrapper.Log) types.Action {
|
||||
log.Debug("onHttpResponseBody()")
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime"
|
||||
|
||||
. "github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
|
||||
@@ -34,6 +35,6 @@ func onHttpRequestHeaders(ctx HttpContext, config MyConfig, log Log) types.Actio
|
||||
log.Infof("alloc success, point address: %p", b)
|
||||
memstats := fmt.Sprintf(`{"Sys": %d,"HeapSys": %d,"HeapIdle": %d,"HeapInuse": %d,"HeapReleased": %d}`, m.Sys, m.HeapSys, m.HeapIdle, m.HeapInuse, m.HeapReleased)
|
||||
log.Info(memstats)
|
||||
proxywasm.SendHttpResponse(200, [][2]string{{"Content-Type", "application/json"}}, []byte(memstats), -1)
|
||||
proxywasm.SendHttpResponse(http.StatusOK, [][2]string{{"Content-Type", "application/json"}}, []byte(memstats), -1)
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
|
||||
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
|
||||
|
||||
@@ -36,6 +38,6 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, config HelloWorldConfig, log
|
||||
if err != nil {
|
||||
log.Critical("failed to set request header")
|
||||
}
|
||||
proxywasm.SendHttpResponse(200, nil, []byte("hello world"), -1)
|
||||
proxywasm.SendHttpResponse(http.StatusOK, nil, []byte("hello world"), -1)
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
122
plugins/wasm-go/extensions/key-auth/README.md
Normal file
122
plugins/wasm-go/extensions/key-auth/README.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# 功能说明
|
||||
`key-auth`插件实现了基于 API Key 进行认证鉴权的功能,支持从 HTTP 请求的 URL 参数或者请求头解析 API Key,同时验证该 API Key 是否有权限访问。
|
||||
|
||||
# 配置字段
|
||||
|
||||
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|
||||
| ----------- | --------------- | ------------------------------------------- | ------ | ----------------------------------------------------------- |
|
||||
| `global_auth` | bool | 选填 | - | 若配置为true,则全局生效认证机制; 若配置为false,则只对做了配置的域名和路由生效认证机制; 若不配置则仅当没有域名和路由配置时全局生效(兼容机制) |
|
||||
| `consumers` | array of object | 必填 | - | 配置服务的调用者,用于对请求进行认证 |
|
||||
| `keys` | array of string | 必填 | - | API Key 的来源字段名称,可以是 URL 参数或者 HTTP 请求头名称 |
|
||||
| `in_query` | bool | `in_query` 和 `in_header` 至少有一个为 true | true | 配置 true 时,网关会尝试从 URL 参数中解析 API Key |
|
||||
| `in_header` | bool | `in_query` 和 `in_header` 至少有一个为 true | true | 配置 true 时,网关会尝试从 HTTP 请求头中解析 API Key |
|
||||
|
||||
`consumers`中每一项的配置字段说明如下:
|
||||
|
||||
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|
||||
| ------------ | -------- | -------- | ------ | ------------------------ |
|
||||
| `credential` | string | 必填 | - | 配置该consumer的访问凭证 |
|
||||
| `name` | string | 必填 | - | 配置该consumer的名称 |
|
||||
|
||||
|
||||
**注意:**
|
||||
- 对于通过认证鉴权的请求,请求的header会被添加一个`X-Mse-Consumer`字段,用以标识调用者的名称。
|
||||
|
||||
# 配置示例
|
||||
|
||||
## 对特定路由或域名开启
|
||||
|
||||
以下配置将对网关特定路由或域名开启 Key Auth 认证和鉴权,注意`credential`字段不能重复
|
||||
|
||||
```yaml
|
||||
global_auth: true
|
||||
consumers:
|
||||
- credential: 2bda943c-ba2b-11ec-ba07-00163e1250b5
|
||||
name: consumer1
|
||||
- credential: c8c8e9ca-558e-4a2d-bb62-e700dcc40e35
|
||||
name: consumer2
|
||||
keys:
|
||||
- apikey
|
||||
- x-api-key
|
||||
```
|
||||
|
||||
**路由级配置**
|
||||
|
||||
对 route-a 和 route-b 这两个路由做如下配置:
|
||||
|
||||
```yaml
|
||||
allow:
|
||||
- consumer1
|
||||
```
|
||||
|
||||
对 *.example.com 和 test.com 在这两个域名做如下配置:
|
||||
|
||||
```yaml
|
||||
allow:
|
||||
- consumer2
|
||||
```
|
||||
|
||||
### 根据该配置,下列请求可以允许访问:
|
||||
|
||||
假设以下请求会匹配到route-a这条路由
|
||||
|
||||
**将 API Key 设置在 url 参数中**
|
||||
```bash
|
||||
curl http://xxx.hello.com/test?apikey=2bda943c-ba2b-11ec-ba07-00163e1250b5
|
||||
```
|
||||
**将 API Key 设置在 http 请求头中**
|
||||
```bash
|
||||
curl http://xxx.hello.com/test -H 'x-api-key: 2bda943c-ba2b-11ec-ba07-00163e1250b5'
|
||||
```
|
||||
|
||||
认证鉴权通过后,请求的header中会被添加一个`X-Mse-Consumer`字段,在此例中其值为`consumer1`,用以标识调用方的名称
|
||||
|
||||
### 下列请求将拒绝访问:
|
||||
|
||||
**请求未提供 API Key,返回401**
|
||||
```bash
|
||||
curl http://xxx.hello.com/test
|
||||
```
|
||||
**请求提供的 API Key 无权访问,返回401**
|
||||
```bash
|
||||
curl http://xxx.hello.com/test?apikey=926d90ac-ba2e-11ec-ab68-00163e1250b5
|
||||
```
|
||||
|
||||
**根据请求提供的 API Key匹配到的调用者无访问权限,返回403**
|
||||
```bash
|
||||
# consumer2不在route-a的allow列表里
|
||||
curl http://xxx.hello.com/test?apikey=c8c8e9ca-558e-4a2d-bb62-e700dcc40e35
|
||||
```
|
||||
|
||||
## 网关实例级别开启
|
||||
|
||||
以下配置未指定`matchRules`字段,因此将对网关实例级别开启全局 Key Auth 认证.
|
||||
|
||||
```yaml
|
||||
defaultConfig
|
||||
consumers:
|
||||
- credential: 2bda943c-ba2b-11ec-ba07-00163e1250b5
|
||||
name: consumer1
|
||||
- credential: c8c8e9ca-558e-4a2d-bb62-e700dcc40e35
|
||||
name: consumer2
|
||||
keys:
|
||||
- apikey
|
||||
in_query: true
|
||||
```
|
||||
|
||||
开启`matchRules`方式如下:
|
||||
```yaml
|
||||
matchRules:
|
||||
- config:
|
||||
allow:
|
||||
- consumer1
|
||||
```
|
||||
|
||||
# 相关错误码
|
||||
|
||||
| HTTP 状态码 | 出错信息 | 原因说明 |
|
||||
| ----------- | --------------------------------------------------------- | ----------------------- |
|
||||
| 401 | Request denied by Key Auth check. Muti API key found in request | 请求提供多个 API Key |
|
||||
| 401 | Request denied by Key Auth check. No API key found in request | 请求未提供 API Key |
|
||||
| 401 | Request denied by Key Auth check. Invalid API key | 不允许当前 API Key 访问 |
|
||||
| 403 | Request denied by Key Auth check. Unauthorized consumer | 请求的调用方无访问权限 |
|
||||
109
plugins/wasm-go/extensions/key-auth/README_EN.md
Normal file
109
plugins/wasm-go/extensions/key-auth/README_EN.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# Features
|
||||
The `key-auth` plug-in implements the authentication function based on the API Key, supports parsing the API Key from the URL parameter or request header of the HTTP request, and verifies whether the API Key has permission to access.
|
||||
|
||||
# Configuration field
|
||||
|
||||
| Name | Data Type | Parameter requirements | Default| Description |
|
||||
| ----------- | --------------- | -------------------------------------------------------- | ------ | --------------------------------------------------------------------------------------------------------- |
|
||||
| `global_auth` | bool | Optional | - | If configured to true, the authentication mechanism will take effect globally; if configured to false, the authentication mechanism will only take effect for the configured domain names and routes; if not configured, the authentication mechanism will only take effect globally when no domain names and routes are configured (compatibility mechanism) |
|
||||
| `consumers` | array of object | Required | - | Configure the caller of the service to authenticate the request. |
|
||||
| `keys` | array of string | Required | - | The name of the source field of the API Key, which can be a URL parameter or an HTTP request header name. |
|
||||
| `in_query` | bool | At least one of `in_query` and `in_header` must be true. | true | When configured true, the gateway will try to parse the API Key from the URL parameters. |
|
||||
| `in_header` | bool | The same as above. | true | The same as above. |
|
||||
|
||||
The configuration fields of each item in `consumers` are described as follows:
|
||||
|
||||
| Name | Data Type | Parameter requirements | Default | Description |
|
||||
| ------------ | --------- | -----------------------| ------ | ------------------------------------------- |
|
||||
| `credential` | string | Required | - | Configure the consumer's access credentials. |
|
||||
| `name` | string | Required | - | Configure the name of the consumer. |
|
||||
|
||||
**Warning:**
|
||||
- For a request that passes authentication, an `X-Mse-Consumer` field will be added to the request header to identify the name of the caller.
|
||||
|
||||
# Example configuration
|
||||
|
||||
## Enabled for specific routes or domains
|
||||
|
||||
The following configuration will enable Key Auth authentication and authentication for gateway-specific routes or domain names. Note that the `credential` field can not be repeated.
|
||||
|
||||
```yaml
|
||||
global_auth: true
|
||||
consumers:
|
||||
- credential: 2bda943c-ba2b-11ec-ba07-00163e1250b5
|
||||
name: consumer1
|
||||
- credential: c8c8e9ca-558e-4a2d-bb62-e700dcc40e35
|
||||
name: consumer2
|
||||
keys:
|
||||
- apikey
|
||||
- x-api-key
|
||||
in_query: true
|
||||
```
|
||||
|
||||
The `route-a` and `route-b` specified in `_match_route_` in this example are the route names filled in when creating the gateway route. When these two routes are matched, calls whose `name` is `consumer1` will be allowed Access by callers, other callers are not allowed to access;
|
||||
|
||||
`*.example.com` and `test.com` specified in `_match_domain_` in this example are used to match the domain name of the request. When the domain name matches, the caller whose `name` is `consumer2` will be allowed to access, and other calls access is not allowed.
|
||||
|
||||
### Depending on this configuration, the following requests would allow access:
|
||||
|
||||
Assume that the following request will match the route-a route:
|
||||
|
||||
**Set the API Key in the url parameter**
|
||||
```bash
|
||||
curl http://xxx.hello.com/test?apikey=2bda943c-ba2b-11ec-ba07-00163e1250b5
|
||||
```
|
||||
**Set the API Key in the http request header**
|
||||
```bash
|
||||
curl http://xxx.hello.com/test -H 'x-api-key: 2bda943c-ba2b-11ec-ba07-00163e1250b5'
|
||||
```
|
||||
|
||||
After the authentication is passed, an `X-Mse-Consumer` field will be added to the header of the request. In this example, its value is `consumer1`, which is used to identify the name of the caller.
|
||||
|
||||
### The following requests will deny access:
|
||||
|
||||
**The request does not provide an API Key, return 401**
|
||||
```bash
|
||||
curl http://xxx.hello.com/test
|
||||
```
|
||||
**The API Key provided by the request is not authorized to access, return 401**
|
||||
```bash
|
||||
curl http://xxx.hello.com/test?apikey=926d90ac-ba2e-11ec-ab68-00163e1250b5
|
||||
```
|
||||
|
||||
**The caller matched according to the API Key provided in the request has no access rights, return 403**
|
||||
```bash
|
||||
# consumer2 is not in the allow list of route-a
|
||||
curl http://xxx.hello.com/test?apikey=c8c8e9ca-558e-4a2d-bb62-e700dcc40e35
|
||||
```
|
||||
|
||||
## Gateway instance level enabled
|
||||
|
||||
The following configuration does not specify the `matchRules` field, so Key Auth authentication will be enabled at the gateway instance level.
|
||||
|
||||
```yaml
|
||||
consumers:
|
||||
- credential: 2bda943c-ba2b-11ec-ba07-00163e1250b5
|
||||
name: consumer1
|
||||
- credential: c8c8e9ca-558e-4a2d-bb62-e700dcc40e35
|
||||
name: consumer2
|
||||
keys:
|
||||
- apikey
|
||||
in_query: true
|
||||
```
|
||||
|
||||
configuration specify the `matchRules` field, like:
|
||||
```yaml
|
||||
matchRules:
|
||||
- config:
|
||||
allow:
|
||||
- consumer1
|
||||
```
|
||||
|
||||
# Error code
|
||||
|
||||
| HTTP status code | Error information | Reason |
|
||||
| ---------------- | --------------------------------------------------------- | -------------------------------------------- |
|
||||
| 401 | Muti API key found in request. | Muti API provided by request Key. |
|
||||
| 401 | No API key found in request. | API not provided by request Key. |
|
||||
| 401 | Request denied by Key Auth check. Invalid API key. | Current API Key access is not allowed. |
|
||||
| 403 | Request denied by Key Auth check. Unauthorized consumer. | The requested caller does not have access. |
|
||||
19
plugins/wasm-go/extensions/key-auth/go.mod
Normal file
19
plugins/wasm-go/extensions/key-auth/go.mod
Normal file
@@ -0,0 +1,19 @@
|
||||
module key-auth
|
||||
|
||||
go 1.19
|
||||
|
||||
replace github.com/alibaba/higress/plugins/wasm-go => ../..
|
||||
|
||||
require (
|
||||
github.com/alibaba/higress/plugins/wasm-go v0.0.0-20231017105619-a18879bf867c
|
||||
github.com/tetratelabs/proxy-wasm-go-sdk v0.22.0
|
||||
github.com/tidwall/gjson v1.14.4
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 // indirect
|
||||
github.com/magefile/mage v1.14.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
)
|
||||
18
plugins/wasm-go/extensions/key-auth/go.sum
Normal file
18
plugins/wasm-go/extensions/key-auth/go.sum
Normal file
@@ -0,0 +1,18 @@
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 h1:IHDghbGQ2DTIXHBHxWfqCYQW1fKjyJ/I7W1pMyUDeEA=
|
||||
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520/go.mod h1:Nz8ORLaFiLWotg6GeKlJMhv8cci8mM43uEnLA5t8iew=
|
||||
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
|
||||
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/tetratelabs/proxy-wasm-go-sdk v0.22.0 h1:kS7BvMKN+FiptV4pfwiNX8e3q14evxAWkhYbxt8EI1M=
|
||||
github.com/tetratelabs/proxy-wasm-go-sdk v0.22.0/go.mod h1:qkW5MBz2jch2u8bS59wws65WC+Gtx3x0aPUX5JL7CXI=
|
||||
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
|
||||
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
62
plugins/wasm-go/extensions/key-auth/keyauth.yaml
Normal file
62
plugins/wasm-go/extensions/key-auth/keyauth.yaml
Normal file
@@ -0,0 +1,62 @@
|
||||
apiVersion: networking.higress.io/v1
|
||||
kind: McpBridge
|
||||
metadata:
|
||||
name: mcp-keyauth-httpbin
|
||||
namespace: higress-system
|
||||
spec:
|
||||
registries:
|
||||
- domain: httpbin.org
|
||||
name: httpbin
|
||||
port: 80
|
||||
type: dns
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
annotations:
|
||||
higress.io/destination: httpbin.dns
|
||||
higress.io/upstream-vhost: "httpbin.org"
|
||||
higress.io/backend-protocol: HTTP
|
||||
name: ingress-keyauth-httpbin
|
||||
namespace: higress-system
|
||||
spec:
|
||||
ingressClassName: higress
|
||||
rules:
|
||||
- host: httpbin.example.com
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
resource:
|
||||
apiGroup: networking.higress.io
|
||||
kind: McpBridge
|
||||
name: mcp-keyauth-httpbin
|
||||
path: /
|
||||
pathType: Prefix
|
||||
---
|
||||
apiVersion: extensions.higress.io/v1alpha1
|
||||
kind: WasmPlugin
|
||||
metadata:
|
||||
name: wasm-keyauth-httpbin
|
||||
namespace: higress-system
|
||||
spec:
|
||||
defaultConfig:
|
||||
consumers:
|
||||
- credential: 2bda943c-ba2b-11ec-ba07-00163e1250b5
|
||||
name: consumer1
|
||||
- credential: c8c8e9ca-558e-4a2d-bb62-e700dcc40e35
|
||||
name: consumer2
|
||||
global_auth: false
|
||||
keys:
|
||||
- x-api-key
|
||||
- apikey
|
||||
in_header: true
|
||||
defaultConfigDisable: false
|
||||
matchRules:
|
||||
- config:
|
||||
allow:
|
||||
- consumer1
|
||||
configDisable: false
|
||||
ingress:
|
||||
- ingress-keyauth-httpbin
|
||||
url: oci://docker.io/dongjiang1989/keyauth:1.0.0
|
||||
imagePullPolicy: Always
|
||||
360
plugins/wasm-go/extensions/key-auth/main.go
Normal file
360
plugins/wasm-go/extensions/key-auth/main.go
Normal file
@@ -0,0 +1,360 @@
|
||||
// Copyright (c) 2023 Alibaba Group Holding Ltd.
|
||||
//
|
||||
// Licensed 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 (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
|
||||
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
|
||||
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
var (
|
||||
ruleSet bool // 插件是否至少在一个 domain 或 route 上生效
|
||||
protectionSpace = "MSE Gateway" // 认证失败时,返回响应头 WWW-Authenticate: Key realm=MSE Gateway
|
||||
)
|
||||
|
||||
func main() {
|
||||
wrapper.SetCtx(
|
||||
"key-auth", // middleware name
|
||||
wrapper.ParseOverrideConfigBy(parseGlobalConfig, parseOverrideRuleConfig),
|
||||
wrapper.ProcessRequestHeadersBy(onHttpRequestHeaders),
|
||||
)
|
||||
}
|
||||
|
||||
type Consumer struct {
|
||||
// @Title 名称
|
||||
// @Title en-US Name
|
||||
// @Description 该调用方的名称。
|
||||
// @Description en-US The name of the consumer.
|
||||
Name string `yaml:"name"`
|
||||
|
||||
// @Title 访问凭证
|
||||
// @Title en-US Credential
|
||||
// @Description 该调用方的访问凭证。
|
||||
// @Description en-US The credential of the consumer.
|
||||
// @Scope GLOBAL
|
||||
Credential string `yaml:"credential"`
|
||||
}
|
||||
|
||||
// @Name key-auth
|
||||
// @Category auth
|
||||
// @Phase AUTHN
|
||||
// @Priority 321
|
||||
// @Title zh-CN Key Auth
|
||||
// @Description zh-CN 本插件实现了实现了基于 API Key 进行认证鉴权的功能.
|
||||
// @Description en-US This plugin implements an authentication function based on API Key Auth standard.
|
||||
// @IconUrl https://img.alicdn.com/imgextra/i4/O1CN01BPFGlT1pGZ2VDLgaH_!!6000000005333-2-tps-42-42.png
|
||||
// @Version 1.0.0
|
||||
//
|
||||
// @Contact.name Higress Team
|
||||
// @Contact.url http://higress.io/
|
||||
// @Contact.email admin@higress.io
|
||||
//
|
||||
// @Example
|
||||
// global_auth: false
|
||||
// consumers:
|
||||
// - name: consumer1
|
||||
// credential: token1
|
||||
// - name: consumer2
|
||||
// credential: token2
|
||||
//
|
||||
// keys:
|
||||
// - x-api-key
|
||||
// - token
|
||||
//
|
||||
// in_query: true
|
||||
// @End
|
||||
type KeyAuthConfig struct {
|
||||
// @Title 是否开启全局认证
|
||||
// @Title en-US Enable Global Auth
|
||||
// @Description 若不开启全局认证,则全局配置只提供凭证信息。只有在域名或路由上进行了配置才会启用认证。
|
||||
// @Description en-US If set to false, only consumer info will be accepted from the global config. Auth feature shall only be enabled if the corresponding domain or route is configured.
|
||||
// @Scope GLOBAL
|
||||
globalAuth *bool `yaml:"global_auth,omitempty"` //是否开启全局认证. 若不开启全局认证,则全局配置只提供凭证信息。只有在域名或路由上进行了配置才会启用认证。
|
||||
|
||||
// @Title API Key 的来源字段名称列表
|
||||
// @Title en-US The name of the source field of the API Key
|
||||
// @Description API Key 的来源字段名称,可以是 URL 参数或者 HTTP 请求头名称.
|
||||
// @Description en-US The name of the source field of the API Key, which can be a URL parameter or an HTTP request header name.
|
||||
// @Scope GLOBAL
|
||||
Keys []string `yaml:"keys"` // key auth names
|
||||
|
||||
// @Title key是否来源于URL参数
|
||||
// @Title en-US the API Key from the URL parameters.
|
||||
// @Description 如果配置 true 时,网关会尝试从 URL 参数中解析 API Key
|
||||
// @Description en-US When configured true, the gateway will try to parse the API Key from the URL parameters.
|
||||
// @Scope GLOBAL
|
||||
InQuery bool `yaml:"in_query,omitempty"`
|
||||
|
||||
// @Title key是否来源于Header
|
||||
// @Title en-US the API Key from the HTTP request header name.
|
||||
// @Description 配置 true 时,网关会尝试从 URL header头中解析 API Key
|
||||
// @Description en-US When configured true, the gateway will try to parse the API Key from the HTTP request header name.
|
||||
// @Scope GLOBAL
|
||||
InHeader bool `yaml:"in_header,omitempty"`
|
||||
|
||||
// @Title 调用方列表
|
||||
// @Title en-US Consumer List
|
||||
// @Description 服务调用方列表,用于对请求进行认证。
|
||||
// @Description en-US List of service consumers which will be used in request authentication.
|
||||
// @Scope GLOBAL
|
||||
consumers []Consumer `yaml:"consumers"`
|
||||
|
||||
// @Title 授权访问的调用方列表
|
||||
// @Title en-US Allowed Consumers
|
||||
// @Description 对于匹配上述条件的请求,允许访问的调用方列表。
|
||||
// @Description en-US Consumers to be allowed for matched requests.
|
||||
allow []string `yaml:"allow"`
|
||||
|
||||
credential2Name map[string]string `yaml:"-"`
|
||||
}
|
||||
|
||||
func parseGlobalConfig(json gjson.Result, global *KeyAuthConfig, log wrapper.Log) error {
|
||||
log.Debug("global config")
|
||||
|
||||
// init
|
||||
ruleSet = false
|
||||
global.credential2Name = make(map[string]string)
|
||||
|
||||
// global_auth
|
||||
globalAuth := json.Get("global_auth")
|
||||
if globalAuth.Exists() {
|
||||
ga := globalAuth.Bool()
|
||||
global.globalAuth = &ga
|
||||
}
|
||||
|
||||
// keys
|
||||
names := json.Get("keys")
|
||||
if !names.Exists() {
|
||||
return errors.New("keys is required")
|
||||
}
|
||||
if len(names.Array()) == 0 {
|
||||
return errors.New("keys cannot be empty")
|
||||
}
|
||||
|
||||
for _, name := range names.Array() {
|
||||
global.Keys = append(global.Keys, name.String())
|
||||
}
|
||||
|
||||
// in_query and in_header
|
||||
in_query := json.Get("in_query")
|
||||
in_header := json.Get("in_header")
|
||||
if !in_query.Exists() && !in_header.Exists() {
|
||||
return errors.New("must one of in_query/in_header required")
|
||||
}
|
||||
|
||||
if in_query.Exists() {
|
||||
global.InQuery = in_query.Bool()
|
||||
}
|
||||
if in_header.Exists() {
|
||||
global.InHeader = in_header.Bool()
|
||||
}
|
||||
|
||||
// consumers
|
||||
consumers := json.Get("consumers")
|
||||
if !consumers.Exists() {
|
||||
return errors.New("consumers is required")
|
||||
}
|
||||
if len(consumers.Array()) == 0 {
|
||||
return errors.New("consumers cannot be empty")
|
||||
}
|
||||
|
||||
for _, item := range consumers.Array() {
|
||||
name := item.Get("name")
|
||||
if !name.Exists() || name.String() == "" {
|
||||
return errors.New("consumer name is required")
|
||||
}
|
||||
credential := item.Get("credential")
|
||||
if !credential.Exists() || credential.String() == "" {
|
||||
return errors.New("consumer credential is required")
|
||||
}
|
||||
if _, ok := global.credential2Name[credential.String()]; ok {
|
||||
return errors.New("duplicate consumer credential: " + credential.String())
|
||||
}
|
||||
|
||||
consumer := Consumer{
|
||||
Name: name.String(),
|
||||
Credential: credential.String(),
|
||||
}
|
||||
global.consumers = append(global.consumers, consumer)
|
||||
global.credential2Name[credential.String()] = name.String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseOverrideRuleConfig(json gjson.Result, global KeyAuthConfig, config *KeyAuthConfig, log wrapper.Log) error {
|
||||
log.Debug("domain/route config")
|
||||
|
||||
*config = global
|
||||
|
||||
allow := json.Get("allow")
|
||||
if !allow.Exists() {
|
||||
return errors.New("allow is required")
|
||||
}
|
||||
if len(allow.Array()) == 0 {
|
||||
return errors.New("allow cannot be empty")
|
||||
}
|
||||
|
||||
for _, item := range allow.Array() {
|
||||
config.allow = append(config.allow, item.String())
|
||||
}
|
||||
ruleSet = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// key-auth 插件认证逻辑:
|
||||
// - global_auth == true 开启全局生效:
|
||||
// - 若当前 domain/route 未配置 allow 列表,即未配置该插件:则在所有 consumers 中查找,如果找到则认证通过,否则认证失败 (1*)
|
||||
// - 若当前 domain/route 配置了该插件:则在 allow 列表中查找,如果找到则认证通过,否则认证失败
|
||||
//
|
||||
// - global_auth == false 非全局生效:(2*)
|
||||
// - 若当前 domain/route 未配置该插件:则直接放行
|
||||
// - 若当前 domain/route 配置了该插件:则在 allow 列表中查找,如果找到则认证通过,否则认证失败
|
||||
//
|
||||
// - global_auth 未设置:
|
||||
// - 若没有一个 domain/route 配置该插件:则遵循 (1*)
|
||||
// - 若有至少一个 domain/route 配置该插件:则遵循 (2*)
|
||||
func onHttpRequestHeaders(ctx wrapper.HttpContext, config KeyAuthConfig, log wrapper.Log) types.Action {
|
||||
var (
|
||||
noAllow = len(config.allow) == 0 // 未配置 allow 列表,表示插件在该 domain/route 未生效
|
||||
globalAuthNoSet = config.globalAuth == nil
|
||||
globalAuthSetTrue = !globalAuthNoSet && *config.globalAuth
|
||||
globalAuthSetFalse = !globalAuthNoSet && !*config.globalAuth
|
||||
)
|
||||
// 不需要认证而直接放行的情况:
|
||||
// - global_auth == false 且 当前 domain/route 未配置该插件
|
||||
// - global_auth 未设置 且 有至少一个 domain/route 配置该插件 且 当前 domain/route 未配置该插件
|
||||
if globalAuthSetFalse || (globalAuthNoSet && ruleSet) {
|
||||
if noAllow {
|
||||
log.Info("authorization is not required")
|
||||
return types.ActionContinue
|
||||
}
|
||||
}
|
||||
|
||||
// 以下需要认证:
|
||||
// - 从 header 中获取 tokens 信息
|
||||
// - 从 query 中获取 tokens 信息
|
||||
var tokens []string
|
||||
if config.InHeader {
|
||||
// 匹配keys中的 keyname
|
||||
for _, key := range config.Keys {
|
||||
value, err := proxywasm.GetHttpRequestHeader(key)
|
||||
if err == nil && value != "" {
|
||||
tokens = append(tokens, value)
|
||||
}
|
||||
}
|
||||
} else if config.InQuery {
|
||||
requestUrl, _ := proxywasm.GetHttpRequestHeader(":path")
|
||||
url, _ := url.Parse(requestUrl)
|
||||
queryValues := url.Query()
|
||||
for _, key := range config.Keys {
|
||||
values, ok := queryValues[key]
|
||||
if ok && len(values) > 0 {
|
||||
tokens = append(tokens, values...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// header/query
|
||||
if len(tokens) > 1 {
|
||||
return deniedMutiKeyAuthData()
|
||||
} else if len(tokens) <= 0 {
|
||||
return deniedNoKeyAuthData()
|
||||
}
|
||||
|
||||
// 验证token
|
||||
name, ok := config.credential2Name[tokens[0]]
|
||||
if !ok {
|
||||
log.Warnf("credential %q is not configured", tokens[0])
|
||||
return deniedUnauthorizedConsumer()
|
||||
}
|
||||
|
||||
// 全局生效:
|
||||
// - global_auth == true 且 当前 domain/route 未配置该插件
|
||||
// - global_auth 未设置 且 没有任何一个 domain/route 配置该插件
|
||||
if (globalAuthSetTrue && noAllow) || (globalAuthNoSet && !ruleSet) {
|
||||
log.Infof("consumer %q authenticated", name)
|
||||
return authenticated(name)
|
||||
}
|
||||
|
||||
// 全局生效,但当前 domain/route 配置了 allow 列表
|
||||
if globalAuthSetTrue && !noAllow {
|
||||
if !contains(config.allow, name) {
|
||||
log.Warnf("consumer %q is not allowed", name)
|
||||
return deniedUnauthorizedConsumer()
|
||||
}
|
||||
log.Infof("consumer %q authenticated", name)
|
||||
return authenticated(name)
|
||||
}
|
||||
|
||||
// 非全局生效
|
||||
if globalAuthSetFalse || (globalAuthNoSet && ruleSet) {
|
||||
if !noAllow { // 配置了 allow 列表
|
||||
if !contains(config.allow, name) {
|
||||
log.Warnf("consumer %q is not allowed", name)
|
||||
return deniedUnauthorizedConsumer()
|
||||
}
|
||||
log.Infof("consumer %q authenticated", name)
|
||||
return authenticated(name)
|
||||
}
|
||||
}
|
||||
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
func deniedMutiKeyAuthData() types.Action {
|
||||
_ = proxywasm.SendHttpResponse(http.StatusUnauthorized, WWWAuthenticateHeader(protectionSpace),
|
||||
[]byte("Request denied by Key Auth check. Muti Key Authentication information found."), -1)
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
func deniedNoKeyAuthData() types.Action {
|
||||
_ = proxywasm.SendHttpResponse(http.StatusUnauthorized, WWWAuthenticateHeader(protectionSpace),
|
||||
[]byte("Request denied by Key Auth check. No Key Authentication information found."), -1)
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
func deniedUnauthorizedConsumer() types.Action {
|
||||
_ = proxywasm.SendHttpResponse(http.StatusForbidden, WWWAuthenticateHeader(protectionSpace),
|
||||
[]byte("Request denied by Key Auth check. Unauthorized consumer."), -1)
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
func authenticated(name string) types.Action {
|
||||
_ = proxywasm.AddHttpRequestHeader("X-Mse-Consumer", name)
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
func contains(arr []string, item string) bool {
|
||||
for _, i := range arr {
|
||||
if i == item {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func WWWAuthenticateHeader(realm string) [][2]string {
|
||||
return [][2]string{
|
||||
{"WWW-Authenticate", fmt.Sprintf("Key realm=%s", realm)},
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
# 功能说明
|
||||
`jwt-auth`插件基于wasm-go实现了Token解析认证功能,可以判断Token是否有效,如果Token有效则继续访问后端微服务,Token无效或不存在直接拒绝并返回401
|
||||
`simple-jwt-auth`插件基于wasm-go实现了Token解析认证功能,可以判断Token是否有效,如果Token有效则继续访问后端微服务,Token无效或不存在直接拒绝并返回401
|
||||
|
||||
# 配置字段
|
||||
| 名称 | 数据类型 | 填写要求 | 描述 |
|
||||
1
plugins/wasm-go/extensions/simple-jwt-auth/VERSION
Normal file
1
plugins/wasm-go/extensions/simple-jwt-auth/VERSION
Normal file
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user