Compare commits

..

16 Commits

Author SHA1 Message Date
澄潭
b16d5a4d8d Support switching between mesh mode on or off (#140) 2023-01-19 16:29:01 +08:00
澄潭
a58c005dab support simple install without istio (#139) 2023-01-19 09:54:50 +08:00
Xunzhuo
41f66a7e8b feat: add support for ingress e2e test framework (#133)
Signed-off-by: bitliu <bitliu@tencent.com>
2023-01-18 17:36:10 +08:00
澄潭
d40a7c1f34 Support wasm api (#129) 2023-01-18 14:56:51 +08:00
gczz2022
2133c273e9 opt: remove redundant registration code (#128) 2023-01-18 14:43:44 +08:00
Xunzhuo
20ddb3393a feat: use echoserver to demonstrate ingress abilities (#132)
Signed-off-by: bitliu <bitliu@tencent.com>
2023-01-18 14:43:16 +08:00
Xunzhuo
a3658ed9b5 chore: just schedule codeQL (#130)
Signed-off-by: bitliu <bitliu@tencent.com>
2023-01-18 13:52:33 +08:00
Xunzhuo
b410fc96e3 feat: add lint/e2e tests support (#126)
Signed-off-by: bitliu <bitliu@tencent.com>
2023-01-18 10:14:22 +08:00
Xunzhuo
0bf395a423 feat: init build-and-test workflows (#124)
Signed-off-by: bitliu <bitliu@tencent.com>
2023-01-17 13:56:48 +08:00
Xunzhuo
7c5542802b chore: add more target to clean (#123)
Signed-off-by: bitliu <bitliu@tencent.com>
2023-01-17 10:51:37 +08:00
charlie
616b37a268 UT: Increase unit test coverage of pkg/bootstrap (#101)
Signed-off-by: charlie <qianglin98@qq.com>
2023-01-14 14:50:15 +08:00
澄潭
926f858a13 support multi destination (#119) 2023-01-12 11:20:24 +08:00
Kent Dong
46487905a2 Add English translation of the key_rate_limit extension. (#118) 2023-01-11 11:06:32 +08:00
澄潭
ad4fbf2c54 Update README.md 2023-01-09 10:19:02 +08:00
澄潭
4a69d9e605 support xds auth (#117) 2023-01-04 17:52:07 +08:00
澄潭
79c894373c Support sidecar inject (#114) 2022-12-21 15:22:22 +08:00
138 changed files with 12723 additions and 254 deletions

83
.github/workflows/build-and-test.yml vendored Normal file
View File

@@ -0,0 +1,83 @@
name: "Build and Test"
on:
push:
branches: [ main ]
pull_request:
branches: ["*"]
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
coverage-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# test
- name: Run Coverage Tests
run: GOPROXY="https://proxy.golang.org,direct" make go.test.coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
fail_ci_if_error: true
files: ./coverage.xml
verbose: true
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
needs: [lint,coverage-test]
steps:
- name: "Setup Go"
uses: actions/setup-go@v3
with:
go-version: 1.19
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: "checkout ${{ github.ref }}"
uses: actions/checkout@v3
with:
fetch-depth: 2
- name: "Build Higress Binary"
run: GOPROXY="https://proxy.golang.org,direct" make build
- name: Upload Higress Binary
uses: actions/upload-artifact@v3
with:
name: higress
path: out/
conformance-test:
runs-on: ubuntu-latest
needs: [build]
steps:
- uses: actions/checkout@v3
e2e-test:
runs-on: ubuntu-latest
needs: [build]
steps:
- name: "Setup Go"
uses: actions/setup-go@v3
with:
go-version: 1.19
- uses: actions/checkout@v3
- name: "Run E2E Tests"
run: make e2e-test
publish:
runs-on: ubuntu-latest
needs: [conformance-test,e2e-test]
steps:
- uses: actions/checkout@v3

View File

@@ -1,36 +0,0 @@
name: "build and codecov"
on:
push:
branches: [ main ]
pull_request:
branches: ["*"]
jobs:
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
strategy:
matrix:
golang:
- 1.19
steps:
- name: "set up go"
uses: actions/setup-go@v3
with:
go-version: 1.19
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: "checkout ${{ github.ref }}"
uses: actions/checkout@v3
with:
fetch-depth: 2
- name: "run go build"
run: GOPROXY="https://proxy.golang.org,direct" make build
- name: "run go test and out codecov"
run: make prebuild; go test ./cmd/... ./pkg/... -race -coverprofile=coverage.out -covermode=atomic
- name: "upload coverage"
uses: codecov/codecov-action@v3

View File

@@ -12,11 +12,6 @@
name: "CodeQL"
on:
push:
branches: [ develop, main ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
schedule:
- cron: '36 19 * * 6'

5
.gitignore vendored
View File

@@ -3,8 +3,11 @@ out
*.out
*.tgz
*.wasm
.DS_Store
coverage.xml
.idea/
bazel-bin
bazel-out
bazel-testlogs
bazel-wasm-cpp
bazel-wasm-cpp
tools/bin/

View File

@@ -23,6 +23,9 @@ header:
- '.gitmodules'
- 'plugins/**'
- 'CODEOWNERS'
- 'VERSION'
- 'tools/'
- 'test/README.md'
comment: on-failure
dependency:

View File

@@ -36,9 +36,9 @@ ifeq ($(BUILD_WITH_CONTAINER),1)
# environment. This is needed to allow overrides from Makefile.overrides.mk.
export
$(shell $(shell pwd)/script/setup_env.sh)
$(shell $(shell pwd)/tools/hack/setup_env.sh)
RUN = ./script/run.sh
RUN = ./tools/hack/run.sh
MAKE_DOCKER = $(RUN) make --no-print-directory -e -f Makefile.core.mk
@@ -58,7 +58,7 @@ else
# If we are not in build container, we need a workaround to get environment properly set
# Write to file, then include
$(shell mkdir -p out)
$(shell $(shell pwd)/script/setup_env.sh envfile > out/.env)
$(shell $(shell pwd)/tools/hack/setup_env.sh envfile > out/.env)
include out/.env
# An export free of arugments in a Makefile places all variables in the Makefile into the
# environment. This behavior may be surprising to many that use shell often, which simply

View File

@@ -41,18 +41,22 @@ submodule:
git submodule update --init
prebuild: submodule
./script/prebuild.sh
./tools/hack/prebuild.sh
.PHONY: default
default: build
.PHONY: go.test.coverage
go.test.coverage: prebuild
go test ./cmd/... ./pkg/... -race -coverprofile=coverage.xml -covermode=atomic
.PHONY: build
build: prebuild $(OUT)
GOPROXY=$(GOPROXY) GOOS=$(GOOS_LOCAL) GOARCH=$(GOARCH_LOCAL) LDFLAGS=$(RELEASE_LDFLAGS) script/gobuild.sh $(OUT)/ $(BINARIES)
GOPROXY=$(GOPROXY) GOOS=$(GOOS_LOCAL) GOARCH=$(GOARCH_LOCAL) LDFLAGS=$(RELEASE_LDFLAGS) tools/hack/gobuild.sh $(OUT)/ $(BINARIES)
.PHONY: build-linux
build-linux: prebuild $(OUT)
GOPROXY=$(GOPROXY) GOOS=linux GOARCH=$(GOARCH_LOCAL) LDFLAGS=$(RELEASE_LDFLAGS) script/gobuild.sh $(OUT_LINUX)/ $(BINARIES)
GOPROXY=$(GOPROXY) GOOS=linux GOARCH=$(GOARCH_LOCAL) LDFLAGS=$(RELEASE_LDFLAGS) tools/hack/gobuild.sh $(OUT_LINUX)/ $(BINARIES)
# Create targets for OUT_LINUX/binary
# There are two use cases here:
@@ -65,7 +69,7 @@ ifeq ($(BUILD_ALL),true)
$(OUT_LINUX)/$(shell basename $(1)): build-linux
else
$(OUT_LINUX)/$(shell basename $(1)): $(OUT_LINUX)
GOPROXY=$(GOPROXY) GOOS=linux GOARCH=$(GOARCH_LOCAL) LDFLAGS=$(RELEASE_LDFLAGS) script/gobuild.sh $(OUT_LINUX)/ -tags=$(2) $(1)
GOPROXY=$(GOPROXY) GOOS=linux GOARCH=$(GOARCH_LOCAL) LDFLAGS=$(RELEASE_LDFLAGS) tools/hack/gobuild.sh $(OUT_LINUX)/ -tags=$(2) $(1)
endif
endef
@@ -86,7 +90,7 @@ include docker/docker.mk
docker-build: docker.higress ## Build and push docker images to registry defined by $HUB and $TAG
export PARENT_GIT_TAG:=$(shell git describe --tags)
export PARENT_GIT_TAG:=$(shell cat VERSION)
export PARENT_GIT_REVISION:=$(TAG)
export ENVOY_TAR_PATH:=/home/package/envoy.tar.gz
@@ -111,13 +115,18 @@ define create_ns
endef
install: pre-install
$(call create_ns,istio-system)
$(call create_ns,higress-system)
helm install istio helm/kind/istio -n istio-system
helm install higress helm/kind/higress -n higress-system
helm install higress helm/kind/higress -n higress-system --create-namespace
ENVOY_LATEST_IMAGE_TAG ?= 0.6.0
ISTIO_LATEST_IMAGE_TAG ?= 0.6.0
install-dev: pre-install
helm install higress helm/higress -n higress-system --create-namespace --set-json='controller.tag="$(TAG)"' --set-json='gateway.replicas=1' --set-json='gateway.tag="$(ENVOY_LATEST_IMAGE_TAG)"' --set-json='global.kind=true'
uninstall:
helm uninstall higress -n higress-system
upgrade: pre-install
helm upgrade istio helm/kind/istio -n istio-system
helm upgrade higress helm/kind/higress -n higress-system
helm-push:
@@ -154,6 +163,38 @@ clean-istio:
clean-gateway: clean-istio
rm -rf external/envoy
rm -rf external/proxy
rm external/package/envoy.tar.gz
rm -rf external/package/envoy.tar.gz
clean: clean-higress clean-gateway
clean-env:
rm -rf out/
clean-tool:
rm -rf tools/bin
clean: clean-higress clean-gateway clean-istio clean-env clean-tool
include tools/tools.mk
include tools/lint.mk
.PHONY: e2e-test
e2e-test: $(tools/kind) delete-cluster create-cluster kube-load-image install-dev run-e2e-test delete-cluster
create-cluster: $(tools/kind)
tools/hack/create-cluster.sh
.PHONY: delete-cluster
delete-cluster: $(tools/kind) ## Delete kind cluster.
$(tools/kind) delete cluster --name higress
.PHONY: kube-load-image
kube-load-image: docker-build $(tools/kind) ## Install the EG 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)
.PHONY: run-e2e-test
run-e2e-test:
@echo -e "\n\033[36mRunning higress conformance tests...\033[0m"
@echo -e "\n\033[36mWaiting higress-controller to be ready...\033[0m\n"
kubectl wait --timeout=5m -n higress-system deployment/higress-controller --for=condition=Available
@echo -e "\n\033[36mWaiting higress-gateway to be ready...\033[0m\n"
kubectl wait --timeout=5m -n higress-system deployment/higress-gateway --for=condition=Available
go test -v -tags conformance ./test/ingress/e2e_test.go --ingress-class=higress --debug=true --use-unique-ports=true

View File

@@ -151,11 +151,9 @@ kind.exe create cluster --name higress --config=cluster.conf
kubectl.exe config use-context kind-higress
```
#### 第三步、 安装 istio & higress
#### 第三步、 安装 higress
```bash
kubectl create ns istio-system
helm install istio -n istio-system oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/charts/istio-local
kubectl create ns higress-system
helm install higress -n higress-system oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/charts/higress-local
```
@@ -182,38 +180,21 @@ curl localhost/bar
```bash
kubectl delete -f https://github.com/alibaba/higress/releases/download/v0.5.2/quickstart.yaml
helm uninstall istio -n istio-system
helm uninstall higress -n higress-system
kubectl delete ns istio-system
kubectl delete ns higress-system
```
### 生产环境
#### 第一步、 安装 istio
可以选择安装 higress 发行的 istio 版本:
```bash
kubectl create ns istio-system
helm install istio -n istio-system oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/charts/istio
```
或者选择安装官方 istio 版本 (将失去部分能力,例如通过 Ingress 注解实现限流的功能):
https://istio.io/latest/docs/setup/install
#### 第二步、 安装 higress
#### 第一步、 安装 higress
```bash
kubectl create ns higress-system
helm install higress -n higress-system oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/charts/higress
```
#### 第步、 创建 Ingress 资源并测试
#### 第步、 创建 Ingress 资源并测试
假设在 default 命名空间下已经部署了一个 test service服务端口为 80 ,则创建下面这个 K8s Ingress
@@ -245,12 +226,8 @@ curl "$(k get svc -n higress-system higress-gateway -o jsonpath='{.status.loadBa
#### 卸载资源
```bash
helm uninstall istio -n istio-system
helm uninstall higress -n higress-system
kubectl delete ns istio-system
kubectl delete ns higress-system
```
@@ -265,8 +242,10 @@ kubectl delete ns higress-system
- Mailing list: higress@googlegroups.com
社区交流群:
![image](https://user-images.githubusercontent.com/6763318/205646934-93b7a711-ac3e-448a-a7ce-2156e31d0f7e.png)
![image](https://img.alicdn.com/imgextra/i1/O1CN01d7LmWu1rMB71rfRhA_!!6000000005616-2-tps-720-405.png)
开发者群:
![image](https://user-images.githubusercontent.com/6763318/205646842-2a636aeb-08e2-458c-9478-7c3d8f8c2cde.png)
![image](https://img.alicdn.com/imgextra/i2/O1CN010jFMgn1qTDaHqeIgH_!!6000000005496-2-tps-406-531.png)

View File

@@ -124,10 +124,10 @@ kind.exe create cluster --name higress --config=cluster.conf
kubectl.exe config use-context kind-higress
```
#### step 3. install istio & higress
#### step 3. install higress
```bash
helm install istio -n istio-system oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/charts/istio-local
kubectl create ns higress-system
helm install higress -n higress-system oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/charts/higress-local
```
Note: The helm version needs to be upgraded to **v3.8.0** and above
@@ -151,38 +151,21 @@ curl localhost/bar
```bash
kubectl delete -f https://kind.sigs.k8s.io/examples/ingress/usage.yaml
helm uninstall istio -n istio-system
helm uninstall higress -n higress-system
kubectl delete ns istio-system
kubectl delete ns higress-system
```
### Production Environment
#### step 1. install istio
select higress istio:
```bash
kubectl create ns istio-system
helm install istio -n istio-system oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/charts/istio
```
or select official istio (lose some abilities, such as using annotation to limit request rate):
https://istio.io/latest/docs/setup/install
#### step 2. install higress
#### step 1. install higress
```bash
kubectl create ns higress-system
helm install higress -n higress-system oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/charts/higress
```
#### step 3. create the ingress and test it
#### step 2. create the ingress and test it
for example there is a service `test` in default namespace.
@@ -212,12 +195,8 @@ curl "$(k get svc -n higress-system higress-gateway -o jsonpath='{.status.loadBa
#### Clean-Up
```bash
helm uninstall istio -n istio-system
helm uninstall higress -n higress-system
kubectl delete ns istio-system
kubectl delete ns higress-system
```

1
VERSION Normal file
View File

@@ -0,0 +1 @@
v0.6.0

View File

@@ -9,6 +9,8 @@ openapi:
directories:
networking/v1:
- mode: perFile
extensions/v1alpha1:
- mode: perFile
# All is used when generating all types referenced in the above directories to
# one file.

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,152 @@
// 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.
// Modified by Higress Authors
syntax = "proto3";
import "google/protobuf/wrappers.proto";
import "google/protobuf/struct.proto";
// $schema: higress.extensions.v1alpha1.WasmPlugin
// $title: WasmPlugin
// $description: Extend the functionality provided by the envoy through WebAssembly filters.
package higress.extensions.v1alpha1;
option go_package="github.com/alibaba/higress/api/extensions/v1alpha1";
// <!-- crd generation tags
// +cue-gen:WasmPlugin:groupName:extensions.higress.io
// +cue-gen:WasmPlugin:version:v1alpha1
// +cue-gen:WasmPlugin:storageVersion
// +cue-gen:WasmPlugin:annotations:helm.sh/resource-policy=keep
// +cue-gen:WasmPlugin:subresource:status
// +cue-gen:WasmPlugin:scope:Namespaced
// +cue-gen:WasmPlugin:resource:categories=higress-io,extensions-higress-io
// +cue-gen:WasmPlugin:preserveUnknownFields:pluginConfig,defaultConfig,matchRules.[].config
// +cue-gen:WasmPlugin:printerColumn:name=Age,type=date,JSONPath=.metadata.creationTimestamp,description="CreationTimestamp is a timestamp
// representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations.
// Clients may not set this value. It is represented in RFC3339 form and is in UTC.
// Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata"
// -->
//
// <!-- go code generation tags
// +kubetype-gen
// +kubetype-gen:groupVersion=extensions.higress.io/v1alpha1
// +genclient
// +k8s:deepcopy-gen=true
// -->
message WasmPlugin {
// URL of a Wasm module or OCI container. If no scheme is present,
// defaults to `oci://`, referencing an OCI image. Other valid schemes
// are `file://` for referencing .wasm module files present locally
// within the proxy container, and `http[s]://` for .wasm module files
// hosted remotely.
string url = 2;
// SHA256 checksum that will be used to verify Wasm module or OCI container.
// If the `url` field already references a SHA256 (using the `@sha256:`
// notation), it must match the value of this field. If an OCI image is
// referenced by tag and this field is set, its checksum will be verified
// against the contents of this field after pulling.
string sha256 = 3;
// The pull behaviour to be applied when fetching an OCI image. Only
// relevant when images are referenced by tag instead of SHA. Defaults
// to IfNotPresent, except when an OCI image is referenced in the `url`
// and the `latest` tag is used, in which case `Always` is the default,
// mirroring K8s behaviour.
// Setting is ignored if `url` field is referencing a Wasm module directly
// using `file://` or `http[s]://`
PullPolicy image_pull_policy = 4;
// Credentials to use for OCI image pulling.
// Name of a K8s Secret in the same namespace as the `WasmPlugin` that
// contains a docker pull secret which is to be used to authenticate
// against the registry when pulling the image.
string image_pull_secret = 5;
// Public key that will be used to verify signatures of signed OCI images
// or Wasm modules. Must be supplied in PEM format.
string verification_key = 6;
// The configuration that will be passed on to the plugin.
google.protobuf.Struct plugin_config = 7;
// The plugin name to be used in the Envoy configuration (used to be called
// `rootID`). Some .wasm modules might require this value to select the Wasm
// plugin to execute.
string plugin_name = 8;
// Determines where in the filter chain this `WasmPlugin` is to be injected.
PluginPhase phase = 9;
// Determines ordering of `WasmPlugins` in the same `phase`.
// When multiple `WasmPlugins` are applied to the same workload in the
// same `phase`, they will be applied by priority, in descending order.
// If `priority` is not set, or two `WasmPlugins` exist with the same
// value, the ordering will be deterministically derived from name and
// namespace of the `WasmPlugins`. Defaults to `0`.
google.protobuf.Int64Value priority = 10;
// Extended by Higress, the default configuration takes effect globally
google.protobuf.Struct default_config = 101;
// Extended by Higress, matching rules take effect
repeated MatchRule match_rules = 102;
}
// Extended by Higress
message MatchRule {
repeated string ingress = 1;
repeated string domain = 2;
google.protobuf.Struct config = 3;
}
// The phase in the filter chain where the plugin will be injected.
enum PluginPhase {
// Control plane decides where to insert the plugin. This will generally
// be at the end of the filter chain, right before the Router.
// Do not specify `PluginPhase` if the plugin is independent of others.
UNSPECIFIED_PHASE = 0;
// Insert plugin before Istio authentication filters.
AUTHN = 1;
// Insert plugin before Istio authorization filters and after Istio authentication filters.
AUTHZ = 2;
// Insert plugin before Istio stats filters and after Istio authorization filters.
STATS = 3;
}
// The pull behaviour to be applied when fetching an OCI image,
// mirroring K8s behaviour.
//
// <!--
// buf:lint:ignore ENUM_VALUE_UPPER_SNAKE_CASE
// -->
enum PullPolicy {
// Defaults to IfNotPresent, except for OCI images with tag `latest`, for which
// the default will be Always.
UNSPECIFIED_POLICY = 0;
// If an existing version of the image has been pulled before, that
// will be used. If no version of the image is present locally, we
// will pull the latest version.
IfNotPresent = 1;
// We will always pull the latest version of an image when applying
// this plugin.
Always = 2;
}

View File

@@ -0,0 +1,58 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: extensions/v1alpha1/wasm.proto
package v1alpha1
import (
fmt "fmt"
proto "github.com/gogo/protobuf/proto"
_ "github.com/gogo/protobuf/types"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// DeepCopyInto supports using WasmPlugin within kubernetes types, where deepcopy-gen is used.
func (in *WasmPlugin) DeepCopyInto(out *WasmPlugin) {
p := proto.Clone(in).(*WasmPlugin)
*out = *p
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WasmPlugin. Required by controller-gen.
func (in *WasmPlugin) DeepCopy() *WasmPlugin {
if in == nil {
return nil
}
out := new(WasmPlugin)
in.DeepCopyInto(out)
return out
}
// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new WasmPlugin. Required by controller-gen.
func (in *WasmPlugin) DeepCopyInterface() interface{} {
return in.DeepCopy()
}
// DeepCopyInto supports using MatchRule within kubernetes types, where deepcopy-gen is used.
func (in *MatchRule) DeepCopyInto(out *MatchRule) {
p := proto.Clone(in).(*MatchRule)
*out = *p
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MatchRule. Required by controller-gen.
func (in *MatchRule) DeepCopy() *MatchRule {
if in == nil {
return nil
}
out := new(MatchRule)
in.DeepCopyInto(out)
return out
}
// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new MatchRule. Required by controller-gen.
func (in *MatchRule) DeepCopyInterface() interface{} {
return in.DeepCopy()
}

View File

@@ -0,0 +1,45 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: extensions/v1alpha1/wasm.proto
package v1alpha1
import (
bytes "bytes"
fmt "fmt"
github_com_gogo_protobuf_jsonpb "github.com/gogo/protobuf/jsonpb"
proto "github.com/gogo/protobuf/proto"
_ "github.com/gogo/protobuf/types"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// MarshalJSON is a custom marshaler for WasmPlugin
func (this *WasmPlugin) MarshalJSON() ([]byte, error) {
str, err := WasmMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for WasmPlugin
func (this *WasmPlugin) UnmarshalJSON(b []byte) error {
return WasmUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for MatchRule
func (this *MatchRule) MarshalJSON() ([]byte, error) {
str, err := WasmMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for MatchRule
func (this *MatchRule) UnmarshalJSON(b []byte) error {
return WasmUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
var (
WasmMarshaler = &github_com_gogo_protobuf_jsonpb.Marshaler{}
WasmUnmarshaler = &github_com_gogo_protobuf_jsonpb.Unmarshaler{AllowUnknownFields: true}
)

View File

@@ -4,7 +4,8 @@ set -eu
# Generate all protos
buf generate \
--path networking \
--path networking \
--path extensions
# Generate CRDs
cue-gen -verbose -f=./cue.yaml -crd=true

View File

@@ -1,6 +1,108 @@
# DO NOT EDIT - Generated by Cue OpenAPI generator based on Istio APIs.
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
"helm.sh/resource-policy": keep
name: wasmplugins.extensions.higress.io
spec:
group: extensions.higress.io
names:
categories:
- higress-io
- extensions-higress-io
kind: WasmPlugin
listKind: WasmPluginList
plural: wasmplugins
singular: wasmplugin
scope: Namespaced
versions:
- additionalPrinterColumns:
- description: 'CreationTimestamp is a timestamp representing the server time
when this object was created. It is not guaranteed to be set in happens-before
order across separate operations. Clients may not set this value. It is represented
in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1alpha1
schema:
openAPIV3Schema:
properties:
spec:
properties:
defaultConfig:
type: object
x-kubernetes-preserve-unknown-fields: true
imagePullPolicy:
description: The pull behaviour to be applied when fetching an OCI
image.
enum:
- UNSPECIFIED_POLICY
- IfNotPresent
- Always
type: string
imagePullSecret:
description: Credentials to use for OCI image pulling.
type: string
matchRules:
items:
properties:
config:
type: object
x-kubernetes-preserve-unknown-fields: true
domain:
items:
type: string
type: array
ingress:
items:
type: string
type: array
type: object
type: array
phase:
description: Determines where in the filter chain this `WasmPlugin`
is to be injected.
enum:
- UNSPECIFIED_PHASE
- AUTHN
- AUTHZ
- STATS
type: string
pluginConfig:
description: The configuration that will be passed on to the plugin.
type: object
x-kubernetes-preserve-unknown-fields: true
pluginName:
type: string
priority:
description: Determines ordering of `WasmPlugins` in the same `phase`.
nullable: true
type: integer
sha256:
description: SHA256 checksum that will be used to verify Wasm module
or OCI container.
type: string
url:
description: URL of a Wasm module or OCI container.
type: string
verificationKey:
type: string
type: object
status:
type: object
x-kubernetes-preserve-unknown-fields: true
type: object
served: true
storage: true
subresources:
status: {}
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
"helm.sh/resource-policy": keep

View File

@@ -1,17 +1,3 @@
// 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.
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: networking/v1/mcp_bridge.proto

View File

@@ -1,17 +1,3 @@
// 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.
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: networking/v1/mcp_bridge.proto

View File

@@ -1,17 +1,3 @@
// 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.
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: networking/v1/mcp_bridge.proto

View File

@@ -28,7 +28,8 @@ comma := ,
# source packages to scan for kubetype-gen tags
kube_source_packages = $(subst $(space),$(empty), \
github.com/alibaba/higress/api/networking/v1 \
github.com/alibaba/higress/api/networking/v1, \
github.com/alibaba/higress/api/extensions/v1alpha1 \
)
# base output package for generated files
@@ -38,7 +39,8 @@ kube_api_base_package = $(kube_base_output_package)/apis
# source packages to scan for kubernetes generator tags, e.g. deepcopy-gen, client-gen, etc.
# these should correspond to the output packages from kubetype-gen
kube_api_packages = $(subst $(space),$(empty), \
$(kube_api_base_package)/networking/v1 \
$(kube_api_base_package)/networking/v1, \
$(kube_api_base_package)/extensions/v1alpha1 \
)
# base output package used by kubernetes client-gen
kube_clientset_package = $(kube_base_output_package)/clientset

View File

@@ -0,0 +1,21 @@
// 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.
// Code generated by kubetype-gen. DO NOT EDIT.
// Package has auto-generated kube type wrappers for raw types.
// +k8s:openapi-gen=true
// +k8s:deepcopy-gen=package
// +groupName=extensions.higress.io
package v1alpha1

View File

@@ -0,0 +1,49 @@
// 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.
// Code generated by kubetype-gen. DO NOT EDIT.
package v1alpha1
import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema"
)
var (
// Package-wide variables from generator "register".
SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"}
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
localSchemeBuilder = &SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
)
const (
// Package-wide consts from generator "register".
GroupName = "extensions.higress.io"
)
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&WasmPlugin{},
&WasmPluginList{},
)
v1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}

View File

@@ -0,0 +1,69 @@
// 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.
// Code generated by kubetype-gen. DO NOT EDIT.
package v1alpha1
import (
extensionsv1alpha1 "github.com/alibaba/higress/api/extensions/v1alpha1"
metav1alpha1 "istio.io/api/meta/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
//
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// <!-- crd generation tags
// +cue-gen:WasmPlugin:groupName:extensions.higress.io
// +cue-gen:WasmPlugin:version:v1alpha1
// +cue-gen:WasmPlugin:storageVersion
// +cue-gen:WasmPlugin:annotations:helm.sh/resource-policy=keep
// +cue-gen:WasmPlugin:subresource:status
// +cue-gen:WasmPlugin:scope:Namespaced
// +cue-gen:WasmPlugin:resource:categories=higress-io,extensions-higress-io
// +cue-gen:WasmPlugin:preserveUnknownFields:pluginConfig,defaultConfig,matchRules.[].config
// +cue-gen:WasmPlugin:printerColumn:name=Age,type=date,JSONPath=.metadata.creationTimestamp,description="CreationTimestamp is a timestamp
// representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations.
// Clients may not set this value. It is represented in RFC3339 form and is in UTC.
// Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata"
// -->
//
// <!-- go code generation tags
// +kubetype-gen
// +kubetype-gen:groupVersion=extensions.higress.io/v1alpha1
// +genclient
// +k8s:deepcopy-gen=true
// -->
type WasmPlugin struct {
v1.TypeMeta `json:",inline"`
// +optional
v1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// Spec defines the implementation of this definition.
// +optional
Spec extensionsv1alpha1.WasmPlugin `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
Status metav1alpha1.IstioStatus `json:"status"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// WasmPluginList is a collection of WasmPlugins.
type WasmPluginList struct {
v1.TypeMeta `json:",inline"`
// +optional
v1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
Items []WasmPlugin `json:"items" protobuf:"bytes,2,rep,name=items"`
}

View File

@@ -0,0 +1,85 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
// 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.
// Code generated by deepcopy-gen. DO NOT EDIT.
package v1alpha1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WasmPlugin) DeepCopyInto(out *WasmPlugin) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WasmPlugin.
func (in *WasmPlugin) DeepCopy() *WasmPlugin {
if in == nil {
return nil
}
out := new(WasmPlugin)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *WasmPlugin) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WasmPluginList) DeepCopyInto(out *WasmPluginList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]WasmPlugin, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WasmPluginList.
func (in *WasmPluginList) DeepCopy() *WasmPluginList {
if in == nil {
return nil
}
out := new(WasmPluginList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *WasmPluginList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}

View File

@@ -19,6 +19,7 @@ package versioned
import (
"fmt"
extensionsv1alpha1 "github.com/alibaba/higress/client/pkg/clientset/versioned/typed/extensions/v1alpha1"
networkingv1 "github.com/alibaba/higress/client/pkg/clientset/versioned/typed/networking/v1"
discovery "k8s.io/client-go/discovery"
rest "k8s.io/client-go/rest"
@@ -27,6 +28,7 @@ import (
type Interface interface {
Discovery() discovery.DiscoveryInterface
ExtensionsV1alpha1() extensionsv1alpha1.ExtensionsV1alpha1Interface
NetworkingV1() networkingv1.NetworkingV1Interface
}
@@ -34,7 +36,13 @@ type Interface interface {
// version included in a Clientset.
type Clientset struct {
*discovery.DiscoveryClient
networkingV1 *networkingv1.NetworkingV1Client
extensionsV1alpha1 *extensionsv1alpha1.ExtensionsV1alpha1Client
networkingV1 *networkingv1.NetworkingV1Client
}
// ExtensionsV1alpha1 retrieves the ExtensionsV1alpha1Client
func (c *Clientset) ExtensionsV1alpha1() extensionsv1alpha1.ExtensionsV1alpha1Interface {
return c.extensionsV1alpha1
}
// NetworkingV1 retrieves the NetworkingV1Client
@@ -63,6 +71,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
}
var cs Clientset
var err error
cs.extensionsV1alpha1, err = extensionsv1alpha1.NewForConfig(&configShallowCopy)
if err != nil {
return nil, err
}
cs.networkingV1, err = networkingv1.NewForConfig(&configShallowCopy)
if err != nil {
return nil, err
@@ -79,6 +91,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
// panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) *Clientset {
var cs Clientset
cs.extensionsV1alpha1 = extensionsv1alpha1.NewForConfigOrDie(c)
cs.networkingV1 = networkingv1.NewForConfigOrDie(c)
cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c)
@@ -88,6 +101,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset {
// New creates a new Clientset for the given RESTClient.
func New(c rest.Interface) *Clientset {
var cs Clientset
cs.extensionsV1alpha1 = extensionsv1alpha1.New(c)
cs.networkingV1 = networkingv1.New(c)
cs.DiscoveryClient = discovery.NewDiscoveryClient(c)

View File

@@ -18,6 +18,8 @@ package fake
import (
clientset "github.com/alibaba/higress/client/pkg/clientset/versioned"
extensionsv1alpha1 "github.com/alibaba/higress/client/pkg/clientset/versioned/typed/extensions/v1alpha1"
fakeextensionsv1alpha1 "github.com/alibaba/higress/client/pkg/clientset/versioned/typed/extensions/v1alpha1/fake"
networkingv1 "github.com/alibaba/higress/client/pkg/clientset/versioned/typed/networking/v1"
fakenetworkingv1 "github.com/alibaba/higress/client/pkg/clientset/versioned/typed/networking/v1/fake"
"k8s.io/apimachinery/pkg/runtime"
@@ -74,6 +76,11 @@ func (c *Clientset) Tracker() testing.ObjectTracker {
var _ clientset.Interface = &Clientset{}
// ExtensionsV1alpha1 retrieves the ExtensionsV1alpha1Client
func (c *Clientset) ExtensionsV1alpha1() extensionsv1alpha1.ExtensionsV1alpha1Interface {
return &fakeextensionsv1alpha1.FakeExtensionsV1alpha1{Fake: &c.Fake}
}
// NetworkingV1 retrieves the NetworkingV1Client
func (c *Clientset) NetworkingV1() networkingv1.NetworkingV1Interface {
return &fakenetworkingv1.FakeNetworkingV1{Fake: &c.Fake}

View File

@@ -17,6 +17,7 @@
package fake
import (
extensionsv1alpha1 "github.com/alibaba/higress/client/pkg/apis/extensions/v1alpha1"
networkingv1 "github.com/alibaba/higress/client/pkg/apis/networking/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
@@ -29,6 +30,7 @@ var scheme = runtime.NewScheme()
var codecs = serializer.NewCodecFactory(scheme)
var parameterCodec = runtime.NewParameterCodec(scheme)
var localSchemeBuilder = runtime.SchemeBuilder{
extensionsv1alpha1.AddToScheme,
networkingv1.AddToScheme,
}

View File

@@ -17,6 +17,7 @@
package scheme
import (
extensionsv1alpha1 "github.com/alibaba/higress/client/pkg/apis/extensions/v1alpha1"
networkingv1 "github.com/alibaba/higress/client/pkg/apis/networking/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
@@ -29,6 +30,7 @@ var Scheme = runtime.NewScheme()
var Codecs = serializer.NewCodecFactory(Scheme)
var ParameterCodec = runtime.NewParameterCodec(Scheme)
var localSchemeBuilder = runtime.SchemeBuilder{
extensionsv1alpha1.AddToScheme,
networkingv1.AddToScheme,
}

View File

@@ -0,0 +1,18 @@
// 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.
// Code generated by client-gen. DO NOT EDIT.
// This package has the automatically generated typed clients.
package v1alpha1

View File

@@ -0,0 +1,87 @@
// 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.
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
import (
v1alpha1 "github.com/alibaba/higress/client/pkg/apis/extensions/v1alpha1"
"github.com/alibaba/higress/client/pkg/clientset/versioned/scheme"
rest "k8s.io/client-go/rest"
)
type ExtensionsV1alpha1Interface interface {
RESTClient() rest.Interface
WasmPluginsGetter
}
// ExtensionsV1alpha1Client is used to interact with features provided by the extensions.higress.io group.
type ExtensionsV1alpha1Client struct {
restClient rest.Interface
}
func (c *ExtensionsV1alpha1Client) WasmPlugins(namespace string) WasmPluginInterface {
return newWasmPlugins(c, namespace)
}
// NewForConfig creates a new ExtensionsV1alpha1Client for the given config.
func NewForConfig(c *rest.Config) (*ExtensionsV1alpha1Client, error) {
config := *c
if err := setConfigDefaults(&config); err != nil {
return nil, err
}
client, err := rest.RESTClientFor(&config)
if err != nil {
return nil, err
}
return &ExtensionsV1alpha1Client{client}, nil
}
// NewForConfigOrDie creates a new ExtensionsV1alpha1Client for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) *ExtensionsV1alpha1Client {
client, err := NewForConfig(c)
if err != nil {
panic(err)
}
return client
}
// New creates a new ExtensionsV1alpha1Client for the given RESTClient.
func New(c rest.Interface) *ExtensionsV1alpha1Client {
return &ExtensionsV1alpha1Client{c}
}
func setConfigDefaults(config *rest.Config) error {
gv := v1alpha1.SchemeGroupVersion
config.GroupVersion = &gv
config.APIPath = "/apis"
config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
if config.UserAgent == "" {
config.UserAgent = rest.DefaultKubernetesUserAgent()
}
return nil
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *ExtensionsV1alpha1Client) RESTClient() rest.Interface {
if c == nil {
return nil
}
return c.restClient
}

View File

@@ -0,0 +1,18 @@
// 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.
// Code generated by client-gen. DO NOT EDIT.
// Package fake has the automatically generated clients.
package fake

View File

@@ -0,0 +1,38 @@
// 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.
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
v1alpha1 "github.com/alibaba/higress/client/pkg/clientset/versioned/typed/extensions/v1alpha1"
rest "k8s.io/client-go/rest"
testing "k8s.io/client-go/testing"
)
type FakeExtensionsV1alpha1 struct {
*testing.Fake
}
func (c *FakeExtensionsV1alpha1) WasmPlugins(namespace string) v1alpha1.WasmPluginInterface {
return &FakeWasmPlugins{c, namespace}
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *FakeExtensionsV1alpha1) RESTClient() rest.Interface {
var ret *rest.RESTClient
return ret
}

View File

@@ -0,0 +1,140 @@
// 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.
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
"context"
v1alpha1 "github.com/alibaba/higress/client/pkg/apis/extensions/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
schema "k8s.io/apimachinery/pkg/runtime/schema"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
testing "k8s.io/client-go/testing"
)
// FakeWasmPlugins implements WasmPluginInterface
type FakeWasmPlugins struct {
Fake *FakeExtensionsV1alpha1
ns string
}
var wasmpluginsResource = schema.GroupVersionResource{Group: "extensions.higress.io", Version: "v1alpha1", Resource: "wasmplugins"}
var wasmpluginsKind = schema.GroupVersionKind{Group: "extensions.higress.io", Version: "v1alpha1", Kind: "WasmPlugin"}
// Get takes name of the wasmPlugin, and returns the corresponding wasmPlugin object, and an error if there is any.
func (c *FakeWasmPlugins) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.WasmPlugin, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(wasmpluginsResource, c.ns, name), &v1alpha1.WasmPlugin{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.WasmPlugin), err
}
// List takes label and field selectors, and returns the list of WasmPlugins that match those selectors.
func (c *FakeWasmPlugins) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.WasmPluginList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(wasmpluginsResource, wasmpluginsKind, c.ns, opts), &v1alpha1.WasmPluginList{})
if obj == nil {
return nil, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &v1alpha1.WasmPluginList{ListMeta: obj.(*v1alpha1.WasmPluginList).ListMeta}
for _, item := range obj.(*v1alpha1.WasmPluginList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested wasmPlugins.
func (c *FakeWasmPlugins) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(wasmpluginsResource, c.ns, opts))
}
// Create takes the representation of a wasmPlugin and creates it. Returns the server's representation of the wasmPlugin, and an error, if there is any.
func (c *FakeWasmPlugins) Create(ctx context.Context, wasmPlugin *v1alpha1.WasmPlugin, opts v1.CreateOptions) (result *v1alpha1.WasmPlugin, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(wasmpluginsResource, c.ns, wasmPlugin), &v1alpha1.WasmPlugin{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.WasmPlugin), err
}
// Update takes the representation of a wasmPlugin and updates it. Returns the server's representation of the wasmPlugin, and an error, if there is any.
func (c *FakeWasmPlugins) Update(ctx context.Context, wasmPlugin *v1alpha1.WasmPlugin, opts v1.UpdateOptions) (result *v1alpha1.WasmPlugin, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(wasmpluginsResource, c.ns, wasmPlugin), &v1alpha1.WasmPlugin{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.WasmPlugin), err
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *FakeWasmPlugins) UpdateStatus(ctx context.Context, wasmPlugin *v1alpha1.WasmPlugin, opts v1.UpdateOptions) (*v1alpha1.WasmPlugin, error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(wasmpluginsResource, "status", c.ns, wasmPlugin), &v1alpha1.WasmPlugin{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.WasmPlugin), err
}
// Delete takes name of the wasmPlugin and deletes it. Returns an error if one occurs.
func (c *FakeWasmPlugins) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteAction(wasmpluginsResource, c.ns, name), &v1alpha1.WasmPlugin{})
return err
}
// DeleteCollection deletes a collection of objects.
func (c *FakeWasmPlugins) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(wasmpluginsResource, c.ns, listOpts)
_, err := c.Fake.Invokes(action, &v1alpha1.WasmPluginList{})
return err
}
// Patch applies the patch and returns the patched wasmPlugin.
func (c *FakeWasmPlugins) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.WasmPlugin, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(wasmpluginsResource, c.ns, name, pt, data, subresources...), &v1alpha1.WasmPlugin{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.WasmPlugin), err
}

View File

@@ -0,0 +1,19 @@
// 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.
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
type WasmPluginExpansion interface{}

View File

@@ -0,0 +1,193 @@
// 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.
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
import (
"context"
"time"
v1alpha1 "github.com/alibaba/higress/client/pkg/apis/extensions/v1alpha1"
scheme "github.com/alibaba/higress/client/pkg/clientset/versioned/scheme"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
)
// WasmPluginsGetter has a method to return a WasmPluginInterface.
// A group's client should implement this interface.
type WasmPluginsGetter interface {
WasmPlugins(namespace string) WasmPluginInterface
}
// WasmPluginInterface has methods to work with WasmPlugin resources.
type WasmPluginInterface interface {
Create(ctx context.Context, wasmPlugin *v1alpha1.WasmPlugin, opts v1.CreateOptions) (*v1alpha1.WasmPlugin, error)
Update(ctx context.Context, wasmPlugin *v1alpha1.WasmPlugin, opts v1.UpdateOptions) (*v1alpha1.WasmPlugin, error)
UpdateStatus(ctx context.Context, wasmPlugin *v1alpha1.WasmPlugin, opts v1.UpdateOptions) (*v1alpha1.WasmPlugin, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.WasmPlugin, error)
List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.WasmPluginList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.WasmPlugin, err error)
WasmPluginExpansion
}
// wasmPlugins implements WasmPluginInterface
type wasmPlugins struct {
client rest.Interface
ns string
}
// newWasmPlugins returns a WasmPlugins
func newWasmPlugins(c *ExtensionsV1alpha1Client, namespace string) *wasmPlugins {
return &wasmPlugins{
client: c.RESTClient(),
ns: namespace,
}
}
// Get takes name of the wasmPlugin, and returns the corresponding wasmPlugin object, and an error if there is any.
func (c *wasmPlugins) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.WasmPlugin, err error) {
result = &v1alpha1.WasmPlugin{}
err = c.client.Get().
Namespace(c.ns).
Resource("wasmplugins").
Name(name).
VersionedParams(&options, scheme.ParameterCodec).
Do(ctx).
Into(result)
return
}
// List takes label and field selectors, and returns the list of WasmPlugins that match those selectors.
func (c *wasmPlugins) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.WasmPluginList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v1alpha1.WasmPluginList{}
err = c.client.Get().
Namespace(c.ns).
Resource("wasmplugins").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do(ctx).
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested wasmPlugins.
func (c *wasmPlugins) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
opts.Watch = true
return c.client.Get().
Namespace(c.ns).
Resource("wasmplugins").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Watch(ctx)
}
// Create takes the representation of a wasmPlugin and creates it. Returns the server's representation of the wasmPlugin, and an error, if there is any.
func (c *wasmPlugins) Create(ctx context.Context, wasmPlugin *v1alpha1.WasmPlugin, opts v1.CreateOptions) (result *v1alpha1.WasmPlugin, err error) {
result = &v1alpha1.WasmPlugin{}
err = c.client.Post().
Namespace(c.ns).
Resource("wasmplugins").
VersionedParams(&opts, scheme.ParameterCodec).
Body(wasmPlugin).
Do(ctx).
Into(result)
return
}
// Update takes the representation of a wasmPlugin and updates it. Returns the server's representation of the wasmPlugin, and an error, if there is any.
func (c *wasmPlugins) Update(ctx context.Context, wasmPlugin *v1alpha1.WasmPlugin, opts v1.UpdateOptions) (result *v1alpha1.WasmPlugin, err error) {
result = &v1alpha1.WasmPlugin{}
err = c.client.Put().
Namespace(c.ns).
Resource("wasmplugins").
Name(wasmPlugin.Name).
VersionedParams(&opts, scheme.ParameterCodec).
Body(wasmPlugin).
Do(ctx).
Into(result)
return
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *wasmPlugins) UpdateStatus(ctx context.Context, wasmPlugin *v1alpha1.WasmPlugin, opts v1.UpdateOptions) (result *v1alpha1.WasmPlugin, err error) {
result = &v1alpha1.WasmPlugin{}
err = c.client.Put().
Namespace(c.ns).
Resource("wasmplugins").
Name(wasmPlugin.Name).
SubResource("status").
VersionedParams(&opts, scheme.ParameterCodec).
Body(wasmPlugin).
Do(ctx).
Into(result)
return
}
// Delete takes name of the wasmPlugin and deletes it. Returns an error if one occurs.
func (c *wasmPlugins) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("wasmplugins").
Name(name).
Body(&opts).
Do(ctx).
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *wasmPlugins) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
var timeout time.Duration
if listOpts.TimeoutSeconds != nil {
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
}
return c.client.Delete().
Namespace(c.ns).
Resource("wasmplugins").
VersionedParams(&listOpts, scheme.ParameterCodec).
Timeout(timeout).
Body(&opts).
Do(ctx).
Error()
}
// Patch applies the patch and returns the patched wasmPlugin.
func (c *wasmPlugins) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.WasmPlugin, err error) {
result = &v1alpha1.WasmPlugin{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("wasmplugins").
Name(name).
SubResource(subresources...).
VersionedParams(&opts, scheme.ParameterCodec).
Body(data).
Do(ctx).
Into(result)
return
}

View File

@@ -0,0 +1,44 @@
// 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.
// Code generated by informer-gen. DO NOT EDIT.
package extensions
import (
v1alpha1 "github.com/alibaba/higress/client/pkg/informers/externalversions/extensions/v1alpha1"
internalinterfaces "github.com/alibaba/higress/client/pkg/informers/externalversions/internalinterfaces"
)
// Interface provides access to each of this group's versions.
type Interface interface {
// V1alpha1 provides access to shared informers for resources in V1alpha1.
V1alpha1() v1alpha1.Interface
}
type group struct {
factory internalinterfaces.SharedInformerFactory
namespace string
tweakListOptions internalinterfaces.TweakListOptionsFunc
}
// New returns a new Interface.
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
// V1alpha1 returns a new v1alpha1.Interface.
func (g *group) V1alpha1() v1alpha1.Interface {
return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions)
}

View File

@@ -0,0 +1,43 @@
// 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.
// Code generated by informer-gen. DO NOT EDIT.
package v1alpha1
import (
internalinterfaces "github.com/alibaba/higress/client/pkg/informers/externalversions/internalinterfaces"
)
// Interface provides access to all the informers in this group version.
type Interface interface {
// WasmPlugins returns a WasmPluginInformer.
WasmPlugins() WasmPluginInformer
}
type version struct {
factory internalinterfaces.SharedInformerFactory
namespace string
tweakListOptions internalinterfaces.TweakListOptionsFunc
}
// New returns a new Interface.
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
// WasmPlugins returns a WasmPluginInformer.
func (v *version) WasmPlugins() WasmPluginInformer {
return &wasmPluginInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}

View File

@@ -0,0 +1,88 @@
// 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.
// Code generated by informer-gen. DO NOT EDIT.
package v1alpha1
import (
"context"
time "time"
extensionsv1alpha1 "github.com/alibaba/higress/client/pkg/apis/extensions/v1alpha1"
versioned "github.com/alibaba/higress/client/pkg/clientset/versioned"
internalinterfaces "github.com/alibaba/higress/client/pkg/informers/externalversions/internalinterfaces"
v1alpha1 "github.com/alibaba/higress/client/pkg/listers/extensions/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
// WasmPluginInformer provides access to a shared informer and lister for
// WasmPlugins.
type WasmPluginInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1alpha1.WasmPluginLister
}
type wasmPluginInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewWasmPluginInformer constructs a new informer for WasmPlugin type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewWasmPluginInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredWasmPluginInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredWasmPluginInformer constructs a new informer for WasmPlugin type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredWasmPluginInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.ExtensionsV1alpha1().WasmPlugins(namespace).List(context.TODO(), options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.ExtensionsV1alpha1().WasmPlugins(namespace).Watch(context.TODO(), options)
},
},
&extensionsv1alpha1.WasmPlugin{},
resyncPeriod,
indexers,
)
}
func (f *wasmPluginInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredWasmPluginInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *wasmPluginInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&extensionsv1alpha1.WasmPlugin{}, f.defaultInformer)
}
func (f *wasmPluginInformer) Lister() v1alpha1.WasmPluginLister {
return v1alpha1.NewWasmPluginLister(f.Informer().GetIndexer())
}

View File

@@ -22,6 +22,7 @@ import (
time "time"
versioned "github.com/alibaba/higress/client/pkg/clientset/versioned"
extensions "github.com/alibaba/higress/client/pkg/informers/externalversions/extensions"
internalinterfaces "github.com/alibaba/higress/client/pkg/informers/externalversions/internalinterfaces"
networking "github.com/alibaba/higress/client/pkg/informers/externalversions/networking"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -170,9 +171,14 @@ type SharedInformerFactory interface {
ForResource(resource schema.GroupVersionResource) (GenericInformer, error)
WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool
Extensions() extensions.Interface
Networking() networking.Interface
}
func (f *sharedInformerFactory) Extensions() extensions.Interface {
return extensions.New(f, f.namespace, f.tweakListOptions)
}
func (f *sharedInformerFactory) Networking() networking.Interface {
return networking.New(f, f.namespace, f.tweakListOptions)
}

View File

@@ -19,6 +19,7 @@ package externalversions
import (
"fmt"
v1alpha1 "github.com/alibaba/higress/client/pkg/apis/extensions/v1alpha1"
v1 "github.com/alibaba/higress/client/pkg/apis/networking/v1"
schema "k8s.io/apimachinery/pkg/runtime/schema"
cache "k8s.io/client-go/tools/cache"
@@ -50,7 +51,11 @@ func (f *genericInformer) Lister() cache.GenericLister {
// TODO extend this to unknown resources with a client pool
func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
switch resource {
// Group=networking.higress.io, Version=v1
// Group=extensions.higress.io, Version=v1alpha1
case v1alpha1.SchemeGroupVersion.WithResource("wasmplugins"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Extensions().V1alpha1().WasmPlugins().Informer()}, nil
// Group=networking.higress.io, Version=v1
case v1.SchemeGroupVersion.WithResource("mcpbridges"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Networking().V1().McpBridges().Informer()}, nil

View File

@@ -0,0 +1,25 @@
// 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.
// Code generated by lister-gen. DO NOT EDIT.
package v1alpha1
// WasmPluginListerExpansion allows custom methods to be added to
// WasmPluginLister.
type WasmPluginListerExpansion interface{}
// WasmPluginNamespaceListerExpansion allows custom methods to be added to
// WasmPluginNamespaceLister.
type WasmPluginNamespaceListerExpansion interface{}

View File

@@ -0,0 +1,92 @@
// 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.
// Code generated by lister-gen. DO NOT EDIT.
package v1alpha1
import (
v1alpha1 "github.com/alibaba/higress/client/pkg/apis/extensions/v1alpha1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/cache"
)
// WasmPluginLister helps list WasmPlugins.
type WasmPluginLister interface {
// List lists all WasmPlugins in the indexer.
List(selector labels.Selector) (ret []*v1alpha1.WasmPlugin, err error)
// WasmPlugins returns an object that can list and get WasmPlugins.
WasmPlugins(namespace string) WasmPluginNamespaceLister
WasmPluginListerExpansion
}
// wasmPluginLister implements the WasmPluginLister interface.
type wasmPluginLister struct {
indexer cache.Indexer
}
// NewWasmPluginLister returns a new WasmPluginLister.
func NewWasmPluginLister(indexer cache.Indexer) WasmPluginLister {
return &wasmPluginLister{indexer: indexer}
}
// List lists all WasmPlugins in the indexer.
func (s *wasmPluginLister) List(selector labels.Selector) (ret []*v1alpha1.WasmPlugin, err error) {
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
ret = append(ret, m.(*v1alpha1.WasmPlugin))
})
return ret, err
}
// WasmPlugins returns an object that can list and get WasmPlugins.
func (s *wasmPluginLister) WasmPlugins(namespace string) WasmPluginNamespaceLister {
return wasmPluginNamespaceLister{indexer: s.indexer, namespace: namespace}
}
// WasmPluginNamespaceLister helps list and get WasmPlugins.
type WasmPluginNamespaceLister interface {
// List lists all WasmPlugins in the indexer for a given namespace.
List(selector labels.Selector) (ret []*v1alpha1.WasmPlugin, err error)
// Get retrieves the WasmPlugin from the indexer for a given namespace and name.
Get(name string) (*v1alpha1.WasmPlugin, error)
WasmPluginNamespaceListerExpansion
}
// wasmPluginNamespaceLister implements the WasmPluginNamespaceLister
// interface.
type wasmPluginNamespaceLister struct {
indexer cache.Indexer
namespace string
}
// List lists all WasmPlugins in the indexer for a given namespace.
func (s wasmPluginNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.WasmPlugin, err error) {
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
ret = append(ret, m.(*v1alpha1.WasmPlugin))
})
return ret, err
}
// Get retrieves the WasmPlugin from the indexer for a given namespace and name.
func (s wasmPluginNamespaceLister) Get(name string) (*v1alpha1.WasmPlugin, error) {
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(v1alpha1.Resource("wasmplugin"), name)
}
return obj.(*v1alpha1.WasmPlugin), nil
}

2
go.mod
View File

@@ -16,6 +16,7 @@ replace github.com/docker/docker => github.com/moby/moby v17.12.0-ce-rc1.0.20200
replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.5
require (
github.com/agiledragon/gomonkey/v2 v2.9.0
github.com/dubbogo/go-zookeeper v1.0.4-0.20211212162352-f9d2183d89d5
github.com/dubbogo/gost v1.13.1
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1
@@ -70,6 +71,7 @@ require (
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect
github.com/cncf/xds/go v0.0.0-20220520190051-1e77728a1eaa // indirect
github.com/containerd/continuity v0.1.0 // indirect
github.com/coreos/go-oidc/v3 v3.1.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0 // indirect
github.com/docker/cli v20.10.7+incompatible // indirect

3
go.sum
View File

@@ -156,6 +156,8 @@ github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrU
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/agiledragon/gomonkey/v2 v2.9.0 h1:PDiKKybR596O6FHW+RVSG0Z7uGCBNbmbUXh3uCNQ7Hc=
github.com/agiledragon/gomonkey/v2 v2.9.0/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
github.com/ahmetb/gen-crd-api-reference-docs v0.3.0/go.mod h1:TdjdkYhlOifCQWPs1UdTma97kQQMozf5h26hTuG70u8=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@@ -354,6 +356,7 @@ github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmeka
github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-oidc/v3 v3.1.0 h1:6avEvcdvTa1qYsOZ6I5PRkSYHzpTNWgKYmaJfaYbrRw=
github.com/coreos/go-oidc/v3 v3.1.0/go.mod h1:rEJ/idjfUyfkBit1eI1fvyr+64/g9dcKpAm8MJMesvo=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=

View File

@@ -1,5 +1,5 @@
apiVersion: v2
appVersion: 0.5.3
appVersion: 0.6.0
description: Helm chart for deploying higress gateways
icon: https://higress.io/img/higress_logo_small.png
keywords:
@@ -9,4 +9,4 @@ name: higress
sources:
- http://github.com/alibaba/higress
type: application
version: 0.5.3
version: 0.6.0

View File

@@ -1,6 +1,108 @@
# DO NOT EDIT - Generated by Cue OpenAPI generator based on Istio APIs.
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
"helm.sh/resource-policy": keep
name: wasmplugins.extensions.higress.io
spec:
group: extensions.higress.io
names:
categories:
- higress-io
- extensions-higress-io
kind: WasmPlugin
listKind: WasmPluginList
plural: wasmplugins
singular: wasmplugin
scope: Namespaced
versions:
- additionalPrinterColumns:
- description: 'CreationTimestamp is a timestamp representing the server time
when this object was created. It is not guaranteed to be set in happens-before
order across separate operations. Clients may not set this value. It is represented
in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1alpha1
schema:
openAPIV3Schema:
properties:
spec:
properties:
defaultConfig:
type: object
x-kubernetes-preserve-unknown-fields: true
imagePullPolicy:
description: The pull behaviour to be applied when fetching an OCI
image.
enum:
- UNSPECIFIED_POLICY
- IfNotPresent
- Always
type: string
imagePullSecret:
description: Credentials to use for OCI image pulling.
type: string
matchRules:
items:
properties:
config:
type: object
x-kubernetes-preserve-unknown-fields: true
domain:
items:
type: string
type: array
ingress:
items:
type: string
type: array
type: object
type: array
phase:
description: Determines where in the filter chain this `WasmPlugin`
is to be injected.
enum:
- UNSPECIFIED_PHASE
- AUTHN
- AUTHZ
- STATS
type: string
pluginConfig:
description: The configuration that will be passed on to the plugin.
type: object
x-kubernetes-preserve-unknown-fields: true
pluginName:
type: string
priority:
description: Determines ordering of `WasmPlugins` in the same `phase`.
nullable: true
type: integer
sha256:
description: SHA256 checksum that will be used to verify Wasm module
or OCI container.
type: string
url:
description: URL of a Wasm module or OCI container.
type: string
verificationKey:
type: string
type: object
status:
type: object
x-kubernetes-preserve-unknown-fields: true
type: object
served: true
storage: true
subresources:
status: {}
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
"helm.sh/resource-policy": keep

View File

@@ -1,8 +1,85 @@
{{- define "mesh" }}
# The trust domain corresponds to the trust root of a system.
# Refer to https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md#21-trust-domain
trustDomain: "cluster.local"
accessLogEncoding: TEXT
accessLogFile: "/dev/stdout"
accessLogFormat: '{"authority":"%REQ(:AUTHORITY)%","bytes_received":"%BYTES_RECEIVED%","bytes_sent":"%BYTES_SENT%","downstream_local_address":"%DOWNSTREAM_LOCAL_ADDRESS%","downstream_remote_address":"%DOWNSTREAM_REMOTE_ADDRESS%","duration":"%DURATION%","istio_policy_status":"%DYNAMIC_METADATA(istio.mixer:status)%","method":"%REQ(:METHOD)%","path":"%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%","protocol":"%PROTOCOL%","request_id":"%REQ(X-REQUEST-ID)%","requested_server_name":"%REQUESTED_SERVER_NAME%","response_code":"%RESPONSE_CODE%","response_flags":"%RESPONSE_FLAGS%","route_name":"%ROUTE_NAME%","start_time":"%START_TIME%","trace_id":"%REQ(X-B3-TRACEID)%","upstream_cluster":"%UPSTREAM_CLUSTER%","upstream_host":"%UPSTREAM_HOST%","upstream_local_address":"%UPSTREAM_LOCAL_ADDRESS%","upstream_service_time":"%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%","upstream_transport_failure_reason":"%UPSTREAM_TRANSPORT_FAILURE_REASON%","user_agent":"%REQ(USER-AGENT)%","x_forwarded_for":"%REQ(X-FORWARDED-FOR)%"}
'
dnsRefreshRate: 200s
enableAutoMtls: false
enablePrometheusMerge: false
protocolDetectionTimeout: 100ms
# The namespace to treat as the administrative root namespace for Istio configuration.
# When processing a leaf namespace Istio will search for declarations in that namespace first
# and if none are found it will search in the root namespace. Any matching declaration found in the root namespace
# is processed as if it were declared in the leaf namespace.
{{- if .Values.global.enableMesh }}
rootNamespace: {{ .Values.meshConfig.rootNamespace | default .Values.global.istioNamespace }}
{{- else }}
rootNamespace: {{ .Release.Namespace }}
{{- end }}
configSources:
- address: "xds://127.0.0.1:15051"
defaultConfig:
discoveryAddress: {{ printf "istiod.%s.svc" .Values.istioNamespace }}:15012
{{- if .Values.global.meshID }}
meshId: {{ .Values.global.meshID }}
{{- end }}
tracing:
{{- if eq .Values.global.proxy.tracer "lightstep" }}
lightstep:
# Address of the LightStep Satellite pool
address: {{ .Values.global.tracer.lightstep.address }}
# Access Token used to communicate with the Satellite pool
accessToken: {{ .Values.global.tracer.lightstep.accessToken }}
{{- else if eq .Values.global.proxy.tracer "zipkin" }}
zipkin:
# Address of the Zipkin collector
address: {{ .Values.global.tracer.zipkin.address | default (print "zipkin." .Release.Namespace ":9411") }}
{{- else if eq .Values.global.proxy.tracer "datadog" }}
datadog:
# Address of the Datadog Agent
address: {{ .Values.global.tracer.datadog.address | default "$(HOST_IP):8126" }}
{{- else if eq .Values.global.proxy.tracer "stackdriver" }}
stackdriver:
# enables trace output to stdout.
{{- if $.Values.global.tracer.stackdriver.debug }}
debug: {{ $.Values.global.tracer.stackdriver.debug }}
{{- end }}
{{- if $.Values.global.tracer.stackdriver.maxNumberOfAttributes }}
# The global default max number of attributes per span.
maxNumberOfAttributes: {{ $.Values.global.tracer.stackdriver.maxNumberOfAttributes | default "200" }}
{{- end }}
{{- if $.Values.global.tracer.stackdriver.maxNumberOfAnnotations }}
# The global default max number of annotation events per span.
maxNumberOfAnnotations: {{ $.Values.global.tracer.stackdriver.maxNumberOfAnnotations | default "200" }}
{{- end }}
{{- if $.Values.global.tracer.stackdriver.maxNumberOfMessageEvents }}
# The global default max number of message events per span.
maxNumberOfMessageEvents: {{ $.Values.global.tracer.stackdriver.maxNumberOfMessageEvents | default "200" }}
{{- end }}
{{- else if eq .Values.global.proxy.tracer "openCensusAgent" }}
{{/* Fill in openCensusAgent configuration from meshConfig so it isn't overwritten below */}}
{{ toYaml $.Values.meshConfig.defaultConfig.tracing | indent 8 }}
{{- else }}
{}
{{- end }}
{{- if .Values.global.remotePilotAddress }}
{{- if not .Values.global.externalIstiod }}
discoveryAddress: {{ printf "istiod-remote.%s.svc" .Release.Namespace }}:15012
{{- else }}
discoveryAddress: {{ printf "istiod.%s.svc" .Release.Namespace }}:15012
{{- end }}
{{- else }}
{{- if .Values.global.enableMesh }}
discoveryAddress: {{ printf "istiod.%s.svc" .Values.global.istioNamespace }}:15012
{{- else }}
discoveryAddress: higress-controller.{{.Release.Namespace}}.svc:15012
{{- end }}
{{- end }}
proxyStatsMatcher:
inclusionRegexps:
- ".*"
@@ -21,6 +98,16 @@ metadata:
labels:
{{- include "gateway.labels" . | nindent 4 }}
data:
# Configuration file for the mesh networks to be used by the Split Horizon EDS.
meshNetworks: |-
{{- if .Values.global.meshNetworks }}
networks:
{{ toYaml .Values.global.meshNetworks | trim | indent 6 }}
{{- else }}
networks: {}
{{- end }}
mesh: |-
{{- if .Values.meshConfig }}
{{ $mesh | toYaml | indent 4 }}

View File

@@ -42,6 +42,67 @@ rules:
resources: ["mcpbridges"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["extensions.higress.io"]
resources: ["wasmplugins"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "watch", "list", "update", "patch", "create", "delete"]
# auto-detect installed CRD definitions
- apiGroups: ["apiextensions.k8s.io"]
resources: ["customresourcedefinitions"]
verbs: ["get", "list", "watch"]
# discovery and routing
- apiGroups: [""]
resources: ["pods", "nodes", "services", "namespaces", "endpoints"]
verbs: ["get", "list", "watch"]
- apiGroups: ["discovery.k8s.io"]
resources: ["endpointslices"]
verbs: ["get", "list", "watch"]
# Istiod and bootstrap.
- apiGroups: ["certificates.k8s.io"]
resources:
- "certificatesigningrequests"
- "certificatesigningrequests/approval"
- "certificatesigningrequests/status"
verbs: ["update", "create", "get", "delete", "watch"]
- apiGroups: ["certificates.k8s.io"]
resources:
- "signers"
resourceNames:
- "kubernetes.io/legacy-unknown"
verbs: ["approve"]
# Used by Istiod to verify the JWT tokens
- apiGroups: ["authentication.k8s.io"]
resources: ["tokenreviews"]
verbs: ["create"]
# Used by Istiod to verify gateway SDS
- apiGroups: ["authorization.k8s.io"]
resources: ["subjectaccessreviews"]
verbs: ["create"]
# Used for MCS serviceexport management
- apiGroups: ["multicluster.x-k8s.io"]
resources: ["serviceexports"]
verbs: [ "get", "watch", "list", "create", "delete"]
# Used for MCS serviceimport management
- apiGroups: ["multicluster.x-k8s.io"]
resources: ["serviceimports"]
verbs: ["get", "watch", "list"]
# sidecar injection controller
- apiGroups: ["admissionregistration.k8s.io"]
resources: ["mutatingwebhookconfigurations"]
verbs: ["get", "list", "watch", "update", "patch"]
# configuration validation webhook controller
- apiGroups: ["admissionregistration.k8s.io"]
resources: ["validatingwebhookconfigurations"]
verbs: ["get", "list", "watch", "update"]

View File

@@ -28,6 +28,139 @@ spec:
securityContext:
{{- toYaml .Values.controller.podSecurityContext | nindent 8 }}
containers:
{{- if not .Values.global.enableMesh }}
- 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 .Values.global.tag }}"
{{- end }}
{{- if .Values.global.imagePullPolicy }}
imagePullPolicy: {{ .Values.global.imagePullPolicy }}
{{- end }}
args:
- "discovery"
- --monitoringAddr=:15014
{{- if .Values.global.logging.level }}
- --log_output_level={{ .Values.global.logging.level }}
{{- end}}
{{- if .Values.global.logAsJson }}
- --log_as_json
{{- end }}
- --domain
- {{ .Values.global.proxy.clusterDomain }}
{{- if .Values.global.oneNamespace }}
- "-a"
- {{ .Release.Namespace }}
{{- end }}
{{- if .Values.pilot.plugins }}
- --plugins={{ .Values.pilot.plugins }}
{{- end }}
- --keepaliveMaxServerConnectionAge
- "{{ .Values.pilot.keepaliveMaxServerConnectionAge }}"
ports:
- containerPort: 8080
protocol: TCP
- containerPort: 15010
protocol: TCP
- containerPort: 15017
protocol: TCP
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 1
periodSeconds: 3
timeoutSeconds: 5
env:
- name: HIGRESS_CONTROLLER_SVC
value: "127.0.0.1"
- name: HIGRESS_CONTROLLER_PORT
value: "15051"
- name: REVISION
value: "{{ .Values.revision | default `default` }}"
- name: JWT_POLICY
value: {{ .Values.global.jwtPolicy }}
- name: PILOT_CERT_PROVIDER
value: "istiod"
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: SERVICE_ACCOUNT
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.serviceAccountName
- name: KUBECONFIG
value: /var/run/secrets/remote/config
{{- if .Values.pilot.env }}
{{- range $key, $val := .Values.pilot.env }}
- name: {{ $key }}
value: "{{ $val }}"
{{- end }}
{{- end }}
{{- if .Values.pilot.traceSampling }}
- name: PILOT_TRACE_SAMPLING
value: "{{ .Values.pilot.traceSampling }}"
{{- end }}
- name: PILOT_ENABLE_PROTOCOL_SNIFFING_FOR_OUTBOUND
value: "{{ .Values.pilot.enableProtocolSniffingForOutbound }}"
- name: PILOT_ENABLE_PROTOCOL_SNIFFING_FOR_INBOUND
value: "{{ .Values.pilot.enableProtocolSniffingForInbound }}"
- name: ISTIOD_ADDR
value: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}.{{ .Release.Namespace }}.svc:15012
- name: PILOT_ENABLE_ANALYSIS
value: "{{ .Values.global.istiod.enableAnalysis }}"
- name: CLUSTER_ID
value: "{{ $.Values.global.multiCluster.clusterName | default `Kubernetes` }}"
{{- if not .Values.global.enableMesh }}
- name: CUSTOM_CA_CERT_NAME
value: "higress-ca-root-cert"
{{- end }}
{{- if not .Values.global.kind }}
resources:
{{- if .Values.pilot.resources }}
{{ toYaml .Values.pilot.resources | trim | indent 12 }}
{{- else }}
{{ toYaml .Values.global.defaultResources | trim | indent 12 }}
{{- end }}
{{- end }}
securityContext:
readOnlyRootFilesystem: true
runAsUser: 1337
runAsGroup: 1337
runAsNonRoot: true
capabilities:
drop:
- ALL
volumeMounts:
- name: config
mountPath: /etc/istio/config
{{- if eq .Values.global.jwtPolicy "third-party-jwt" }}
- name: istio-token
mountPath: /var/run/secrets/tokens
readOnly: true
{{- end }}
- name: local-certs
mountPath: /var/run/secrets/istio-dns
- name: cacerts
mountPath: /etc/cacerts
readOnly: true
- name: istio-kubeconfig
mountPath: /var/run/secrets/remote
readOnly: true
{{- if .Values.pilot.jwksResolverExtraRootCA }}
- name: extracacerts
mountPath: /cacerts
{{- end }}
{{- end }}
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.controller.securityContext | nindent 12 }}
@@ -95,3 +228,36 @@ spec:
volumes:
- name: log
emptyDir: {}
{{- if not .Values.global.enableMesh }}
- name: config
configMap:
name: higress-config
# Technically not needed on this pod - but it helps debugging/testing SDS
# Should be removed after everything works.
- emptyDir:
medium: Memory
name: local-certs
{{- if eq .Values.global.jwtPolicy "third-party-jwt" }}
- name: istio-token
projected:
sources:
- serviceAccountToken:
audience: {{ .Values.global.sds.token.aud }}
expirationSeconds: 43200
path: istio-token
# Optional: user-generated root
- name: cacerts
secret:
secretName: cacerts
optional: true
- name: istio-kubeconfig
secret:
secretName: istio-kubeconfig
optional: true
{{- if .Values.pilot.jwksResolverExtraRootCA }}
- name: extracacerts
configMap:
name: pilot-jwks-extra-cacerts{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,13 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ include "controller.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "controller.labels" . | nindent 4 }}
rules:
# For storing CA secret
- apiGroups: [""]
resources: ["secrets"]
# TODO lock this down to istio-ca-cert if not using the DNS cert mesh config
verbs: ["create", "get", "watch", "list", "update", "delete"]

View File

@@ -0,0 +1,15 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ include "controller.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "controller.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ include "controller.serviceAccountName" . }}
subjects:
- kind: ServiceAccount
name: {{ include "controller.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}

View File

@@ -8,5 +8,20 @@ spec:
type: {{ .Values.controller.service.type }}
ports:
{{- toYaml .Values.controller.ports | nindent 4 }}
{{- if not .Values.global.enableMesh }}
- port: 15010
name: grpc-xds # plaintext
protocol: TCP
- port: 15012
name: https-dns # mTLS with k8s-signed cert
protocol: TCP
- port: 443
name: https-webhook # validation and injection
targetPort: 15017
protocol: TCP
- port: 15014
name: http-monitoring # prometheus stats
protocol: TCP
{{- end }}
selector:
{{- include "controller.selectorLabels" . | nindent 4 }}

View File

@@ -21,12 +21,19 @@ spec:
strategy:
rollingUpdate:
maxSurge: {{ .Values.gateway.rollingMaxSurge }}
{{- if .Values.global.kind }}
maxUnavailable: 100%
{{- else }}
maxUnavailable: {{ .Values.gateway.rollingMaxUnavailable }}
{{- end }}
template:
metadata:
{{- with .Values.gateway.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- if .Values.global.enableMesh }}
"enableMesh": "true"
{{- end }}
{{- if .Values.gateway.podAnnotations }}
{{- toYaml .Values.gateway.podAnnotations | nindent 8 }}
{{- end }}
labels:
sidecar.istio.io/inject: "false"
@@ -122,7 +129,7 @@ spec:
- name: ENABLE_INGRESS_GATEWAY_SDS
value: "false"
- name: JWT_POLICY
value: {{ .Values.gateway.jwtPolicy }}
value: {{ .Values.global.jwtPolicy }}
- name: ISTIO_META_HTTP10
value: "1"
- name: ISTIO_META_CLUSTER_ID
@@ -166,7 +173,7 @@ spec:
{{- toYaml .Values.gateway.resources | nindent 12 }}
{{- end }}
volumeMounts:
{{- if eq .Values.gateway.jwtPolicy "third-party-jwt" }}
{{- if eq .Values.global.jwtPolicy "third-party-jwt" }}
- name: istio-token
mountPath: /var/run/secrets/tokens
readOnly: true
@@ -198,7 +205,7 @@ spec:
{{- toYaml . | nindent 8 }}
{{- end }}
volumes:
{{- if eq .Values.gateway.jwtPolicy "third-party-jwt" }}
{{- if eq .Values.global.jwtPolicy "third-party-jwt" }}
- name: istio-token
projected:
sources:
@@ -209,7 +216,11 @@ spec:
{{- end }}
- name: istio-ca-root-cert
configMap:
{{- if .Values.global.enableMesh }}
name: istio-ca-root-cert
{{- else }}
name: higress-ca-root-cert
{{- end }}
- name: config
configMap:
name: higress-config

View File

@@ -1,17 +0,0 @@
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: global
namespace: {{ .Release.Namespace }}
spec:
selector:
higress: {{ .Release.Namespace }}-{{ include "gateway.name" . }}
servers:
- hosts:
- "*"
port:
name: http-80
number: 80
protocol: HTTP
---

View File

@@ -3,18 +3,360 @@ global:
# for internal usage only, not to be configured by users.
autoscalingv2API: true
kind: false
enableMesh: false
# Used to locate istiod.
istioNamespace: istio-system
# enable pod disruption budget for the control plane, which is used to
# ensure Istio control plane components are gradually upgraded or recovered.
defaultPodDisruptionBudget:
enabled: false
# The values aren't mutable due to a current PodDisruptionBudget limitation
# minAvailable: 1
# A minimal set of requested resources to applied to all deployments so that
# Horizontal Pod Autoscaler will be able to function (if set).
# Each component can overwrite these default values by adding its own resources
# block in the relevant section below and setting the desired resources values.
defaultResources:
requests:
cpu: 10m
# memory: 128Mi
# limits:
# cpu: 100m
# memory: 128Mi
# Default hub for Istio images.
# Releases are published to docker hub under 'istio' project.
# Dev builds from prow are on gcr.io
hub: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress
# Default tag for Istio images.
tag: 0.6.0
# Specify image pull policy if default behavior isn't desired.
# Default behavior: latest images will be Always else IfNotPresent.
imagePullPolicy: ""
# ImagePullSecrets for all ServiceAccount, list of secrets in the same namespace
# to use for pulling any images in pods that reference this ServiceAccount.
# For components that don't use ServiceAccounts (i.e. grafana, servicegraph, tracing)
# ImagePullSecrets will be added to the corresponding Deployment(StatefulSet) objects.
# Must be set for any cluster configured with private docker registry.
imagePullSecrets: []
# - private-registry-key
# Enabled by default in master for maximising testing.
istiod:
enableAnalysis: false
# To output all istio components logs in json format by adding --log_as_json argument to each container argument
logAsJson: false
# Comma-separated minimum per-scope logging level of messages to output, in the form of <scope>:<level>,<scope>:<level>
# The control plane has different scopes depending on component, but can configure default log level across all components
# If empty, default scope and level will be used as configured in code
logging:
level: "default:info"
omitSidecarInjectorConfigMap: false
# Whether to restrict the applications namespace the controller manages;
# If not set, controller watches all namespaces
oneNamespace: false
# Configure whether Operator manages webhook configurations. The current behavior
# of Istiod is to manage its own webhook configurations.
# When this option is set as true, Istio Operator, instead of webhooks, manages the
# webhook configurations. When this option is set as false, webhooks manage their
# own webhook configurations.
operatorManageWebhooks: false
# Custom DNS config for the pod to resolve names of services in other
# clusters. Use this to add additional search domains, and other settings.
# see
# https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#dns-config
# This does not apply to gateway pods as they typically need a different
# set of DNS settings than the normal application pods (e.g., in
# multicluster scenarios).
# NOTE: If using templates, follow the pattern in the commented example below.
#podDNSSearchNamespaces:
#- global
#- "{{ valueOrDefault .DeploymentMeta.Namespace \"default\" }}.global"
# Kubernetes >=v1.11.0 will create two PriorityClass, including system-cluster-critical and
# system-node-critical, it is better to configure this in order to make sure your Istio pods
# will not be killed because of low priority class.
# Refer to https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass
# for more detail.
priorityClassName: ""
proxy:
image: proxyv2
# This controls the 'policy' in the sidecar injector.
autoInject: enabled
# CAUTION: It is important to ensure that all Istio helm charts specify the same clusterDomain value
# cluster domain. Default value is "cluster.local".
clusterDomain: "cluster.local"
# Per Component log level for proxy, applies to gateways and sidecars. If a component level is
# not set, then the global "logLevel" will be used.
componentLogLevel: "misc:error"
# If set, newly injected sidecars will have core dumps enabled.
enableCoreDump: false
# istio ingress capture allowlist
# examples:
# Redirect only selected ports: --includeInboundPorts="80,8080"
excludeInboundPorts: ""
includeInboundPorts: "*"
# istio egress capture allowlist
# https://istio.io/docs/tasks/traffic-management/egress.html#calling-external-services-directly
# example: includeIPRanges: "172.30.0.0/16,172.20.0.0/16"
# would only capture egress traffic on those two IP Ranges, all other outbound traffic would
# be allowed by the sidecar
includeIPRanges: "*"
excludeIPRanges: ""
includeOutboundPorts: ""
excludeOutboundPorts: ""
# Log level for proxy, applies to gateways and sidecars.
# Expected values are: trace|debug|info|warning|error|critical|off
logLevel: warning
#If set to true, istio-proxy container will have privileged securityContext
privileged: false
# The number of successive failed probes before indicating readiness failure.
readinessFailureThreshold: 30
# The initial delay for readiness probes in seconds.
readinessInitialDelaySeconds: 1
# The period between readiness probes.
readinessPeriodSeconds: 2
# Resources for the sidecar.
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 2000m
memory: 1024Mi
# Default port for Pilot agent health checks. A value of 0 will disable health checking.
statusPort: 15020
# Specify which tracer to use. One of: zipkin, lightstep, datadog, stackdriver.
# If using stackdriver tracer outside GCP, set env GOOGLE_APPLICATION_CREDENTIALS to the GCP credential file.
tracer: "zipkin"
# Controls if sidecar is injected at the front of the container list and blocks the start of the other containers until the proxy is ready
holdApplicationUntilProxyStarts: false
proxy_init:
# Base name for the proxy_init container, used to configure iptables.
image: proxyv2
resources:
limits:
cpu: 2000m
memory: 1024Mi
requests:
cpu: 10m
memory: 10Mi
# configure remote pilot and istiod service and endpoint
remotePilotAddress: ""
##############################################################################################
# The following values are found in other charts. To effectively modify these values, make #
# make sure they are consistent across your Istio helm charts #
##############################################################################################
# The customized CA address to retrieve certificates for the pods in the cluster.
# CSR clients such as the Istio Agent and ingress gateways can use this to specify the CA endpoint.
# If not set explicitly, default to the Istio discovery address.
caAddress: ""
# Configure a remote cluster data plane controlled by an external istiod.
# When set to true, istiod is not deployed locally and only a subset of the other
# discovery charts are enabled.
externalIstiod: false
# Configure a remote cluster as the config cluster for an external istiod.
configCluster: false
# Configure the policy for validating JWT.
# Currently, two options are supported: "third-party-jwt" and "first-party-jwt".
jwtPolicy: "third-party-jwt"
# Mesh ID means Mesh Identifier. It should be unique within the scope where
# meshes will interact with each other, but it is not required to be
# globally/universally unique. For example, if any of the following are true,
# then two meshes must have different Mesh IDs:
# - Meshes will have their telemetry aggregated in one place
# - Meshes will be federated together
# - Policy will be written referencing one mesh from the other
#
# If an administrator expects that any of these conditions may become true in
# the future, they should ensure their meshes have different Mesh IDs
# assigned.
#
# Within a multicluster mesh, each cluster must be (manually or auto)
# configured to have the same Mesh ID value. If an existing cluster 'joins' a
# multicluster mesh, it will need to be migrated to the new mesh ID. Details
# of migration TBD, and it may be a disruptive operation to change the Mesh
# ID post-install.
#
# If the mesh admin does not specify a value, Istio will use the value of the
# mesh's Trust Domain. The best practice is to select a proper Trust Domain
# value.
meshID: ""
# Configure the mesh networks to be used by the Split Horizon EDS.
#
# The following example defines two networks with different endpoints association methods.
# For `network1` all endpoints that their IP belongs to the provided CIDR range will be
# mapped to network1. The gateway for this network example is specified by its public IP
# address and port.
# The second network, `network2`, in this example is defined differently with all endpoints
# retrieved through the specified Multi-Cluster registry being mapped to network2. The
# gateway is also defined differently with the name of the gateway service on the remote
# cluster. The public IP for the gateway will be determined from that remote service (only
# LoadBalancer gateway service type is currently supported, for a NodePort type gateway service,
# it still need to be configured manually).
#
# meshNetworks:
# network1:
# endpoints:
# - fromCidr: "192.168.0.1/24"
# gateways:
# - address: 1.1.1.1
# port: 80
# network2:
# endpoints:
# - fromRegistry: reg1
# gateways:
# - registryServiceName: istio-ingressgateway.istio-system.svc.cluster.local
# port: 443
#
meshNetworks: {}
# Use the user-specified, secret volume mounted key and certs for Pilot and workloads.
mountMtlsCerts: false
multiCluster:
# Set to true to connect two kubernetes clusters via their respective
# ingressgateway services when pods in each cluster cannot directly
# talk to one another. All clusters should be using Istio mTLS and must
# have a shared root CA for this model to work.
enabled: true
# Should be set to the name of the cluster this installation will run in. This is required for sidecar injection
# to properly label proxies
clusterName: ""
# Network defines the network this cluster belong to. This name
# corresponds to the networks in the map of mesh networks.
network: ""
# Configure the certificate provider for control plane communication.
# Currently, two providers are supported: "kubernetes" and "istiod".
# As some platforms may not have kubernetes signing APIs,
# Istiod is the default
pilotCertProvider: istiod
sds:
# The JWT token for SDS and the aud field of such JWT. See RFC 7519, section 4.1.3.
# When a CSR is sent from Istio Agent to the CA (e.g. Istiod), this aud is to make sure the
# JWT is intended for the CA.
token:
aud: istio-ca
sts:
# The service port used by Security Token Service (STS) server to handle token exchange requests.
# Setting this port to a non-zero value enables STS server.
servicePort: 0
# Configuration for each of the supported tracers
tracer:
# Configuration for envoy to send trace data to LightStep.
# Disabled by default.
# address: the <host>:<port> of the satellite pool
# accessToken: required for sending data to the pool
#
datadog:
# Host:Port for submitting traces to the Datadog agent.
address: "$(HOST_IP):8126"
lightstep:
address: "" # example: lightstep-satellite:443
accessToken: "" # example: abcdefg1234567
stackdriver:
# enables trace output to stdout.
debug: false
# The global default max number of message events per span.
maxNumberOfMessageEvents: 200
# The global default max number of annotation events per span.
maxNumberOfAnnotations: 200
# The global default max number of attributes per span.
maxNumberOfAttributes: 200
zipkin:
# Host:Port for reporting trace data in zipkin format. If not specified, will default to
# zipkin service (port 9411) in the same namespace as the other istio components.
address: ""
# Use the Mesh Control Protocol (MCP) for configuring Istiod. Requires an MCP source.
useMCP: false
# The name of the CA for workload certificates.
# For example, when caName=GkeWorkloadCertificate, GKE workload certificates
# will be used as the certificates for workloads.
# The default value is "" and when caName="", the CA will be configured by other
# mechanisms (e.g., environmental variable CA_PROVIDER).
caName: ""
hub: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress
ingressClass: ""
watchNamespace: ""
enableStatus: false
clusterName: ""
istioNamespace: "istio-system"
meshConfig: {}
# meshConfig defines runtime configuration of components, including Istiod and istio-agent behavior
# See https://istio.io/docs/reference/config/istio.mesh.v1alpha1/ for all available options
meshConfig:
enablePrometheusMerge: true
# Config for the default ProxyConfig.
# Initially using directly the proxy metadata - can also be activated using annotations
# on the pod. This is an unsupported low-level API, pending review and decisions on
# enabling the feature. Enabling the DNS listener is safe - and allows further testing
# and gradual adoption by setting capture only on specific workloads. It also allows
# VMs to use other DNS options, like dnsmasq or unbound.
# The namespace to treat as the administrative root namespace for Istio configuration.
# When processing a leaf namespace Istio will search for declarations in that namespace first
# and if none are found it will search in the root namespace. Any matching declaration found in the root namespace
# is processed as if it were declared in the leaf namespace.
rootNamespace:
# The trust domain corresponds to the trust root of a system
# Refer to https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md#21-trust-domain
trustDomain: "cluster.local"
# TODO: the intent is to eventually have this enabled by default when security is used.
# It is not clear if user should normally need to configure - the metadata is typically
# used as an escape and to control testing and rollout, but it is not intended as a long-term
# stable API.
# What we may configure in mesh config is the ".global" - and use of other suffixes.
# No hurry to do this in 1.6, we're trying to prove the code.
gateway:
name: "higress-gateway"
replicas: 2
image: gateway
tag: "bf607ae5541ce5c1cc95b4f98b3fd50a83346d33"
tag: "0.6.0"
# revision declares which revision this gateway is a part of
revision: ""
@@ -35,10 +377,6 @@ gateway:
# Pod environment variables
env: {}
# Configure the policy for validating JWT, it is used for istio authentication.
# Currently, two options are supported: "third-party-jwt" and "first-party-jwt".
jwtPolicy: "third-party-jwt"
hostNetwork: false
# Labels to apply to all resources
@@ -51,8 +389,7 @@ gateway:
prometheus.io/port: "15020"
prometheus.io/scrape: "true"
prometheus.io/path: "/stats/prometheus"
inject.istio.io/templates: "gateway"
sidecar.istio.io/inject: "true"
sidecar.istio.io/inject: "false"
# Define the security context for the pod.
# If unset, this will be automatically set to the minimum privileges required to bind to port 80 and 443.
@@ -111,7 +448,7 @@ controller:
name: "higress-controller"
replicas: 1
image: higress
tag: "bf607ae5541ce5c1cc95b4f98b3fd50a83346d33"
tag: "0.6.0"
env: {}
labels: {}
@@ -191,3 +528,73 @@ controller:
maxReplicas: 5
targetCPUUtilizationPercentage: 80
## Discovery Settings
pilot:
autoscaleEnabled: false
autoscaleMin: 1
autoscaleMax: 5
replicaCount: 1
rollingMaxSurge: 100%
rollingMaxUnavailable: 25%
hub: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress
tag: 0.6.0
# Can be a full hub/image:tag
image: pilot
traceSampling: 1.0
# Resources for a small pilot install
resources:
requests:
cpu: 500m
memory: 2048Mi
env:
PILOT_SCOPE_GATEWAY_TO_NAMESPACE: "true"
PILOT_ENABLE_METADATA_EXCHANGE: "false"
PILOT_ENABLE_CROSS_CLUSTER_WORKLOAD_ENTRY: "false"
VALIDATION_ENABLED: "false"
cpu:
targetAverageUtilization: 80
# if protocol sniffing is enabled for outbound
enableProtocolSniffingForOutbound: true
# if protocol sniffing is enabled for inbound
enableProtocolSniffingForInbound: true
nodeSelector: {}
podAnnotations: {}
serviceAnnotations: {}
# You can use jwksResolverExtraRootCA to provide a root certificate
# in PEM format. This will then be trusted by pilot when resolving
# JWKS URIs.
jwksResolverExtraRootCA: ""
# This is used to set the source of configuration for
# the associated address in configSource, if nothing is specificed
# the default MCP is assumed.
configSource:
subscribedResources: []
plugins: []
# The following is used to limit how long a sidecar can be connected
# to a pilot. It balances out load across pilot instances at the cost of
# increasing system churn.
keepaliveMaxServerConnectionAge: 30m
# Additional labels to apply to the deployment.
deploymentLabels: {}
## Mesh config settings
# Install the mesh config map, generated from values.yaml.
# If false, pilot wil use default values (by default) or user-supplied values.
configMap: true
# Additional labels to apply on the pod level for monitoring and logging configuration.
podLabels: {}

View File

@@ -1,5 +1,5 @@
apiVersion: v2
appVersion: 1.12.3
appVersion: 1.12.4
description: Helm chart for deploying higress istio
name: istio
sources:
@@ -12,4 +12,4 @@ dependencies:
repository: "file://../istiod"
version: 1.12.0
type: application
version: 1.12.3
version: 1.12.4

View File

@@ -0,0 +1,215 @@
{{- $containers := list }}
{{- range $index, $container := .Spec.Containers }}{{ if not (eq $container.Name "istio-proxy") }}{{ $containers = append $containers $container.Name }}{{end}}{{- end}}
metadata:
labels:
service.istio.io/canonical-name: {{ index .ObjectMeta.Labels `service.istio.io/canonical-name` | default (index .ObjectMeta.Labels `app.kubernetes.io/name`) | default (index .ObjectMeta.Labels `app`) | default .DeploymentMeta.Name | quote }}
service.istio.io/canonical-revision: {{ index .ObjectMeta.Labels `service.istio.io/canonical-revision` | default (index .ObjectMeta.Labels `app.kubernetes.io/version`) | default (index .ObjectMeta.Labels `version`) | default "latest" | quote }}
istio.io/rev: {{ .Revision | default "default" | quote }}
annotations: {
{{- if eq (len $containers) 1 }}
kubectl.kubernetes.io/default-logs-container: "{{ index $containers 0 }}",
kubectl.kubernetes.io/default-container: "{{ index $containers 0 }}",
{{ end }}
}
spec:
containers:
- name: istio-proxy
{{- if contains "/" .Values.global.proxy.image }}
image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image }}"
{{- else }}
image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}"
{{- end }}
ports:
- containerPort: 15090
protocol: TCP
name: http-envoy-prom
args:
- proxy
- router
- --domain
- $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }}
- --proxyLogLevel={{ annotation .ObjectMeta `sidecar.istio.io/logLevel` .Values.global.proxy.logLevel }}
- --proxyComponentLogLevel={{ annotation .ObjectMeta `sidecar.istio.io/componentLogLevel` .Values.global.proxy.componentLogLevel }}
- --log_output_level={{ annotation .ObjectMeta `sidecar.istio.io/agentLogLevel` .Values.global.logging.level }}
{{- if .Values.global.sts.servicePort }}
- --stsPort={{ .Values.global.sts.servicePort }}
{{- end }}
{{- if .Values.global.logAsJson }}
- --log_as_json
{{- end }}
{{- if .Values.global.proxy.lifecycle }}
lifecycle:
{{ toYaml .Values.global.proxy.lifecycle | indent 6 }}
{{- end }}
env:
- name: JWT_POLICY
value: {{ .Values.global.jwtPolicy }}
- name: PILOT_CERT_PROVIDER
value: {{ .Values.global.pilotCertProvider }}
- name: CA_ADDR
{{- if .Values.global.caAddress }}
value: {{ .Values.global.caAddress }}
{{- else }}
value: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}.{{ .Values.global.istioNamespace }}.svc:15012
{{- end }}
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: INSTANCE_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: SERVICE_ACCOUNT
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
- name: HOST_IP
valueFrom:
fieldRef:
fieldPath: status.hostIP
- name: PROXY_CONFIG
value: |
{{ protoToJSON .ProxyConfig }}
- name: ISTIO_META_POD_PORTS
value: |-
[
{{- $first := true }}
{{- range $index1, $c := .Spec.Containers }}
{{- range $index2, $p := $c.Ports }}
{{- if (structToJSON $p) }}
{{if not $first}},{{end}}{{ structToJSON $p }}
{{- $first = false }}
{{- end }}
{{- end}}
{{- end}}
]
- name: ISTIO_META_APP_CONTAINERS
value: "{{ $containers | join "," }}"
- name: ISTIO_META_CLUSTER_ID
value: "{{ valueOrDefault .Values.global.multiCluster.clusterName `Kubernetes` }}"
- name: ISTIO_META_INTERCEPTION_MODE
value: "{{ .ProxyConfig.InterceptionMode.String }}"
{{- if .Values.global.network }}
- name: ISTIO_META_NETWORK
value: "{{ .Values.global.network }}"
{{- end }}
{{- if .DeploymentMeta.Name }}
- name: ISTIO_META_WORKLOAD_NAME
value: "{{ .DeploymentMeta.Name }}"
{{ end }}
{{- if and .TypeMeta.APIVersion .DeploymentMeta.Name }}
- name: ISTIO_META_OWNER
value: kubernetes://apis/{{ .TypeMeta.APIVersion }}/namespaces/{{ valueOrDefault .DeploymentMeta.Namespace `default` }}/{{ toLower .TypeMeta.Kind}}s/{{ .DeploymentMeta.Name }}
{{- end}}
{{- if .Values.global.meshID }}
- name: ISTIO_META_MESH_ID
value: "{{ .Values.global.meshID }}"
{{- else if (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }}
- name: ISTIO_META_MESH_ID
value: "{{ (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }}"
{{- end }}
{{- with (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }}
- name: TRUST_DOMAIN
value: "{{ . }}"
{{- end }}
{{- range $key, $value := .ProxyConfig.ProxyMetadata }}
- name: {{ $key }}
value: "{{ $value }}"
{{- end }}
{{with .Values.global.imagePullPolicy }}imagePullPolicy: "{{.}}"{{end}}
readinessProbe:
httpGet:
path: /healthz/ready
port: 15021
initialDelaySeconds: {{.Values.global.proxy.readinessInitialDelaySeconds }}
periodSeconds: {{ .Values.global.proxy.readinessPeriodSeconds }}
timeoutSeconds: 3
failureThreshold: {{ .Values.global.proxy.readinessFailureThreshold }}
volumeMounts:
{{- if eq .Values.global.caName "GkeWorkloadCertificate" }}
- name: gke-workload-certificate
mountPath: /var/run/secrets/workload-spiffe-credentials
readOnly: true
{{- end }}
{{- if eq .Values.global.pilotCertProvider "istiod" }}
- mountPath: /var/run/secrets/istio
name: istiod-ca-cert
{{- end }}
- mountPath: /var/lib/istio/data
name: istio-data
# SDS channel between istioagent and Envoy
- mountPath: /etc/istio/proxy
name: istio-envoy
{{- if eq .Values.global.jwtPolicy "third-party-jwt" }}
- mountPath: /var/run/secrets/tokens
name: istio-token
{{- end }}
{{- if .Values.global.mountMtlsCerts }}
# Use the key and cert mounted to /etc/certs/ for the in-cluster mTLS communications.
- mountPath: /etc/certs/
name: istio-certs
readOnly: true
{{- end }}
- name: istio-podinfo
mountPath: /etc/istio/pod
volumes:
{{- if eq .Values.global.caName "GkeWorkloadCertificate" }}
- name: gke-workload-certificate
csi:
driver: workloadcertificates.security.cloud.google.com
{{- end }}
# SDS channel between istioagent and Envoy
- emptyDir:
medium: Memory
name: istio-envoy
- name: istio-data
emptyDir: {}
- name: istio-podinfo
downwardAPI:
items:
- path: "labels"
fieldRef:
fieldPath: metadata.labels
- path: "annotations"
fieldRef:
fieldPath: metadata.annotations
{{- if eq .Values.global.jwtPolicy "third-party-jwt" }}
- name: istio-token
projected:
sources:
- serviceAccountToken:
path: istio-token
expirationSeconds: 43200
audience: {{ .Values.global.sds.token.aud }}
{{- end }}
{{- if eq .Values.global.pilotCertProvider "istiod" }}
- name: istiod-ca-cert
configMap:
name: istio-ca-root-cert
{{- end }}
{{- if .Values.global.mountMtlsCerts }}
# Use the key and cert mounted to /etc/certs/ for the in-cluster mTLS communications.
- name: istio-certs
secret:
optional: true
{{ if eq .Spec.ServiceAccountName "" }}
secretName: istio.default
{{ else -}}
secretName: {{ printf "istio.%s" .Spec.ServiceAccountName }}
{{ end -}}
{{- end }}
{{- if .Values.global.imagePullSecrets }}
imagePullSecrets:
{{- range .Values.global.imagePullSecrets }}
- name: {{ . }}
{{- end }}
{{- end }}
{{- if eq (env "ENABLE_LEGACY_FSGROUP_INJECTION" "true") "true" }}
securityContext:
fsGroup: 1337
{{- end }}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,233 @@
{{- $containers := list }}
{{- range $index, $container := .Spec.Containers }}{{ if not (eq $container.Name "istio-proxy") }}{{ $containers = append $containers $container.Name }}{{end}}{{- end}}
metadata:
annotations: {
{{- if eq (len $containers) 1 }}
kubectl.kubernetes.io/default-logs-container: "{{ index $containers 0 }}",
kubectl.kubernetes.io/default-container: "{{ index $containers 0 }}",
{{ end }}
sidecar.istio.io/rewriteAppHTTPProbers: "false",
}
spec:
containers:
{{- range $index, $container := .Spec.Containers }}
{{ if not (eq $container.Name "istio-proxy") }}
- name: {{ $container.Name }}
env:
- name: "GRPC_XDS_EXPERIMENTAL_SECURITY_SUPPORT"
value: "true"
- name: "GRPC_XDS_BOOTSTRAP"
value: "/etc/istio/proxy/grpc-bootstrap.json"
volumeMounts:
- mountPath: /var/lib/istio/data
name: istio-data
# UDS channel between istioagent and gRPC client for XDS/SDS
- mountPath: /etc/istio/proxy
name: istio-xds
{{- end }}
{{- end }}
- name: istio-proxy
{{- if contains "/" (annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image) }}
image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image }}"
{{- else }}
image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}"
{{- end }}
args:
- proxy
- sidecar
- --domain
- $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }}
- --log_output_level={{ annotation .ObjectMeta `sidecar.istio.io/agentLogLevel` .Values.global.logging.level }}
{{- if .Values.global.sts.servicePort }}
- --stsPort={{ .Values.global.sts.servicePort }}
{{- end }}
{{- if .Values.global.logAsJson }}
- --log_as_json
{{- end }}
env:
- name: ISTIO_META_GENERATOR
value: grpc
- name: OUTPUT_CERTS
value: /var/lib/istio/data
{{- if eq (env "PILOT_ENABLE_INBOUND_PASSTHROUGH" "true") "false" }}
- name: REWRITE_PROBE_LEGACY_LOCALHOST_DESTINATION
value: "true"
{{- end }}
- name: JWT_POLICY
value: {{ .Values.global.jwtPolicy }}
- name: PILOT_CERT_PROVIDER
value: {{ .Values.global.pilotCertProvider }}
- name: CA_ADDR
{{- if .Values.global.caAddress }}
value: {{ .Values.global.caAddress }}
{{- else }}
value: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}.{{ .Values.global.istioNamespace }}.svc:15012
{{- end }}
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: INSTANCE_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: SERVICE_ACCOUNT
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
- name: HOST_IP
valueFrom:
fieldRef:
fieldPath: status.hostIP
- name: PROXY_CONFIG
value: |
{{ protoToJSON .ProxyConfig }}
- name: ISTIO_META_POD_PORTS
value: |-
[
{{- $first := true }}
{{- range $index1, $c := .Spec.Containers }}
{{- range $index2, $p := $c.Ports }}
{{- if (structToJSON $p) }}
{{if not $first}},{{end}}{{ structToJSON $p }}
{{- $first = false }}
{{- end }}
{{- end}}
{{- end}}
]
- name: ISTIO_META_APP_CONTAINERS
value: "{{ $containers | join "," }}"
- name: ISTIO_META_CLUSTER_ID
value: "{{ valueOrDefault .Values.global.multiCluster.clusterName `Kubernetes` }}"
- name: ISTIO_META_INTERCEPTION_MODE
value: "{{ or (index .ObjectMeta.Annotations `sidecar.istio.io/interceptionMode`) .ProxyConfig.InterceptionMode.String }}"
{{- if .Values.global.network }}
- name: ISTIO_META_NETWORK
value: "{{ .Values.global.network }}"
{{- end }}
{{- if .DeploymentMeta.Name }}
- name: ISTIO_META_WORKLOAD_NAME
value: "{{ .DeploymentMeta.Name }}"
{{ end }}
{{- if and .TypeMeta.APIVersion .DeploymentMeta.Name }}
- name: ISTIO_META_OWNER
value: kubernetes://apis/{{ .TypeMeta.APIVersion }}/namespaces/{{ valueOrDefault .DeploymentMeta.Namespace `default` }}/{{ toLower .TypeMeta.Kind}}s/{{ .DeploymentMeta.Name }}
{{- end}}
{{- if .Values.global.meshID }}
- name: ISTIO_META_MESH_ID
value: "{{ .Values.global.meshID }}"
{{- else if (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }}
- name: ISTIO_META_MESH_ID
value: "{{ (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }}"
{{- end }}
{{- with (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }}
- name: TRUST_DOMAIN
value: "{{ . }}"
{{- end }}
{{- range $key, $value := .ProxyConfig.ProxyMetadata }}
- name: {{ $key }}
value: "{{ $value }}"
{{- end }}
# grpc uses xds:/// to resolve no need to resolve VIP
- name: ISTIO_META_DNS_CAPTURE
value: "false"
- name: DISABLE_ENVOY
value: "true"
{{with .Values.global.imagePullPolicy }}imagePullPolicy: "{{.}}"{{end}}
{{ if ne (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) `0` }}
readinessProbe:
httpGet:
path: /healthz/ready
port: {{ .Values.global.proxy.statusPort }}
initialDelaySeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/initialDelaySeconds` .Values.global.proxy.readinessInitialDelaySeconds }}
periodSeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/periodSeconds` .Values.global.proxy.readinessPeriodSeconds }}
timeoutSeconds: 3
failureThreshold: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/failureThreshold` .Values.global.proxy.readinessFailureThreshold }}
{{ end -}}
resources:
{{- if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit`) }}
{{- if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) }}
requests:
{{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) -}}
cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU` }}"
{{ end }}
{{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}}
memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory` }}"
{{ end }}
{{- end }}
{{- if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit`) }}
limits:
{{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit`) -}}
cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit` }}"
{{ end }}
{{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit`) -}}
memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit` }}"
{{ end }}
{{- end }}
{{- else }}
{{- if .Values.global.proxy.resources }}
{{ toYaml .Values.global.proxy.resources | indent 6 }}
{{- end }}
{{- end }}
volumeMounts:
{{- if eq .Values.global.pilotCertProvider "istiod" }}
- mountPath: /var/run/secrets/istio
name: istiod-ca-cert
{{- end }}
- mountPath: /var/lib/istio/data
name: istio-data
# UDS channel between istioagent and gRPC client for XDS/SDS
- mountPath: /etc/istio/proxy
name: istio-xds
{{- if eq .Values.global.jwtPolicy "third-party-jwt" }}
- mountPath: /var/run/secrets/tokens
name: istio-token
{{- end }}
- name: istio-podinfo
mountPath: /etc/istio/pod
{{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount` }}
{{ range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount`) }}
- name: "{{ $index }}"
{{ toYaml $value | indent 6 }}
{{ end }}
{{- end }}
volumes:
# UDS channel between istioagent and gRPC client for XDS/SDS
- emptyDir:
medium: Memory
name: istio-xds
- name: istio-data
emptyDir: {}
- name: istio-podinfo
downwardAPI:
items:
- path: "labels"
fieldRef:
fieldPath: metadata.labels
- path: "annotations"
fieldRef:
fieldPath: metadata.annotations
{{- if eq .Values.global.jwtPolicy "third-party-jwt" }}
- name: istio-token
projected:
sources:
- serviceAccountToken:
path: istio-token
expirationSeconds: 43200
audience: {{ .Values.global.sds.token.aud }}
{{- end }}
{{- if eq .Values.global.pilotCertProvider "istiod" }}
- name: istiod-ca-cert
configMap:
name: istio-ca-root-cert
{{- end }}
{{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolume` }}
{{range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolume`) }}
- name: "{{ $index }}"
{{ toYaml $value | indent 4 }}
{{ end }}
{{ end }}

View File

@@ -0,0 +1,64 @@
metadata:
sidecar.istio.io/rewriteAppHTTPProbers: "false"
spec:
initContainers:
- name: grpc-bootstrap-init
image: busybox:1.28
volumeMounts:
- mountPath: /var/lib/grpc/data/
name: grpc-io-proxyless-bootstrap
env:
- name: INSTANCE_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: ISTIO_NAMESPACE
value: |
{{ .Values.global.istioNamespace }}
command:
- sh
- "-c"
- |-
NODE_ID="sidecar~${INSTANCE_IP}~${POD_NAME}.${POD_NAMESPACE}~cluster.local"
SERVER_URI="dns:///istiod.${ISTIO_NAMESPACE}.svc:15010"
echo '
{
"xds_servers": [
{
"server_uri": "'${SERVER_URI}'",
"channel_creds": [{"type": "insecure"}],
"server_features" : ["xds_v3"]
}
],
"node": {
"id": "'${NODE_ID}'",
"metadata": {
"GENERATOR": "grpc"
}
}
}' > /var/lib/grpc/data/bootstrap.json
containers:
{{- range $index, $container := .Spec.Containers }}
- name: {{ $container.Name }}
env:
- name: GRPC_XDS_BOOTSTRAP
value: /var/lib/grpc/data/bootstrap.json
- name: GRPC_GO_LOG_VERBOSITY_LEVEL
value: "99"
- name: GRPC_GO_LOG_SEVERITY_LEVEL
value: info
volumeMounts:
- mountPath: /var/lib/grpc/data/
name: grpc-io-proxyless-bootstrap
{{- end }}
volumes:
- name: grpc-io-proxyless-bootstrap
emptyDir: {}

View File

@@ -0,0 +1,491 @@
{{- $containers := list }}
{{- range $index, $container := .Spec.Containers }}{{ if not (eq $container.Name "istio-proxy") }}{{ $containers = append $containers $container.Name }}{{end}}{{- end}}
metadata:
labels:
security.istio.io/tlsMode: {{ index .ObjectMeta.Labels `security.istio.io/tlsMode` | default "istio" | quote }}
service.istio.io/canonical-name: {{ index .ObjectMeta.Labels `service.istio.io/canonical-name` | default (index .ObjectMeta.Labels `app.kubernetes.io/name`) | default (index .ObjectMeta.Labels `app`) | default .DeploymentMeta.Name | quote }}
service.istio.io/canonical-revision: {{ index .ObjectMeta.Labels `service.istio.io/canonical-revision` | default (index .ObjectMeta.Labels `app.kubernetes.io/version`) | default (index .ObjectMeta.Labels `version`) | default "latest" | quote }}
annotations: {
{{- if eq (len $containers) 1 }}
kubectl.kubernetes.io/default-logs-container: "{{ index $containers 0 }}",
kubectl.kubernetes.io/default-container: "{{ index $containers 0 }}",
{{ end }}
{{- if .Values.istio_cni.enabled }}
{{- if not .Values.istio_cni.chained }}
k8s.v1.cni.cncf.io/networks: '{{ appendMultusNetwork (index .ObjectMeta.Annotations `k8s.v1.cni.cncf.io/networks`) `istio-cni` }}',
{{- end }}
sidecar.istio.io/interceptionMode: "{{ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode }}",
{{ with annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` .Values.global.proxy.includeIPRanges }}traffic.sidecar.istio.io/includeOutboundIPRanges: "{{.}}",{{ end }}
{{ with annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundIPRanges` .Values.global.proxy.excludeIPRanges }}traffic.sidecar.istio.io/excludeOutboundIPRanges: "{{.}}",{{ end }}
traffic.sidecar.istio.io/includeInboundPorts: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` `*` }}",
traffic.sidecar.istio.io/excludeInboundPorts: "{{ excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}",
{{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/includeOutboundPorts`) (ne (valueOrDefault .Values.global.proxy.includeOutboundPorts "") "") }}
traffic.sidecar.istio.io/includeOutboundPorts: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundPorts` .Values.global.proxy.includeOutboundPorts }}",
{{- end }}
{{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeOutboundPorts`) (ne .Values.global.proxy.excludeOutboundPorts "") }}
traffic.sidecar.istio.io/excludeOutboundPorts: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundPorts` .Values.global.proxy.excludeOutboundPorts }}",
{{- end }}
{{ with index .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces` }}traffic.sidecar.istio.io/kubevirtInterfaces: "{{.}}",{{ end }}
{{- end }}
}
spec:
{{- $holdProxy := or .ProxyConfig.HoldApplicationUntilProxyStarts.GetValue .Values.global.proxy.holdApplicationUntilProxyStarts }}
initContainers:
{{ if ne (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `NONE` }}
{{ if .Values.istio_cni.enabled -}}
- name: istio-validation
{{ else -}}
- name: istio-init
{{ end -}}
{{- if contains "/" (annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy_init.image) }}
image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy_init.image }}"
{{- else }}
image: "{{ .Values.global.hub }}/{{ .Values.global.proxy_init.image }}:{{ .Values.global.tag }}"
{{- end }}
args:
- istio-iptables
- "-p"
- {{ .MeshConfig.ProxyListenPort | default "15001" | quote }}
- "-z"
- "15006"
- "-u"
- "1337"
- "-m"
- "{{ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode }}"
- "-i"
- "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` .Values.global.proxy.includeIPRanges }}"
- "-x"
- "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundIPRanges` .Values.global.proxy.excludeIPRanges }}"
- "-b"
- "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` `*` }}"
- "-d"
{{- if excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}
- "15090,15021,{{ excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}"
{{- else }}
- "15090,15021"
{{- end }}
{{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/includeOutboundPorts`) (ne (valueOrDefault .Values.global.proxy.includeOutboundPorts "") "") -}}
- "-q"
- "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundPorts` .Values.global.proxy.includeOutboundPorts }}"
{{ end -}}
{{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeOutboundPorts`) (ne (valueOrDefault .Values.global.proxy.excludeOutboundPorts "") "") -}}
- "-o"
- "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundPorts` .Values.global.proxy.excludeOutboundPorts }}"
{{ end -}}
{{ if (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces`) -}}
- "-k"
- "{{ index .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces` }}"
{{ end -}}
{{ if .Values.istio_cni.enabled -}}
- "--run-validation"
- "--skip-rule-apply"
{{ end -}}
{{with .Values.global.imagePullPolicy }}imagePullPolicy: "{{.}}"{{end}}
{{- if .ProxyConfig.ProxyMetadata }}
env:
{{- range $key, $value := .ProxyConfig.ProxyMetadata }}
- name: {{ $key }}
value: "{{ $value }}"
{{- end }}
{{- end }}
resources:
{{- if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit`) }}
{{- if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) }}
requests:
{{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) -}}
cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU` }}"
{{ end }}
{{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}}
memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory` }}"
{{ end }}
{{- end }}
{{- if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit`) }}
limits:
{{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit`) -}}
cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit` }}"
{{ end }}
{{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit`) -}}
memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit` }}"
{{ end }}
{{- end }}
{{- else }}
{{- if .Values.global.proxy.resources }}
{{ toYaml .Values.global.proxy.resources | indent 6 }}
{{- end }}
{{- end }}
securityContext:
allowPrivilegeEscalation: {{ .Values.global.proxy.privileged }}
privileged: {{ .Values.global.proxy.privileged }}
capabilities:
{{- if not .Values.istio_cni.enabled }}
add:
- NET_ADMIN
- NET_RAW
{{- end }}
drop:
- ALL
{{- if not .Values.istio_cni.enabled }}
readOnlyRootFilesystem: false
runAsGroup: 0
runAsNonRoot: false
runAsUser: 0
{{- else }}
readOnlyRootFilesystem: true
runAsGroup: 1337
runAsUser: 1337
runAsNonRoot: true
{{- end }}
restartPolicy: Always
{{ end -}}
{{- if eq (annotation .ObjectMeta `sidecar.istio.io/enableCoreDump` .Values.global.proxy.enableCoreDump) "true" }}
- name: enable-core-dump
args:
- -c
- sysctl -w kernel.core_pattern=/var/lib/istio/data/core.proxy && ulimit -c unlimited
command:
- /bin/sh
{{- if contains "/" (annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy_init.image) }}
image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy_init.image }}"
{{- else }}
image: "{{ .Values.global.hub }}/{{ .Values.global.proxy_init.image }}:{{ .Values.global.tag }}"
{{- end }}
{{with .Values.global.imagePullPolicy }}imagePullPolicy: "{{.}}"{{end}}
resources: {}
securityContext:
allowPrivilegeEscalation: true
capabilities:
add:
- SYS_ADMIN
drop:
- ALL
privileged: true
readOnlyRootFilesystem: false
runAsGroup: 0
runAsNonRoot: false
runAsUser: 0
{{ end }}
containers:
- name: istio-proxy
{{- if contains "/" (annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image) }}
image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image }}"
{{- else }}
image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}"
{{- end }}
ports:
- containerPort: 15090
protocol: TCP
name: http-envoy-prom
args:
- proxy
- sidecar
- --domain
- $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }}
- --proxyLogLevel={{ annotation .ObjectMeta `sidecar.istio.io/logLevel` .Values.global.proxy.logLevel }}
- --proxyComponentLogLevel={{ annotation .ObjectMeta `sidecar.istio.io/componentLogLevel` .Values.global.proxy.componentLogLevel }}
- --log_output_level={{ annotation .ObjectMeta `sidecar.istio.io/agentLogLevel` .Values.global.logging.level }}
{{- if .Values.global.sts.servicePort }}
- --stsPort={{ .Values.global.sts.servicePort }}
{{- end }}
{{- if .Values.global.logAsJson }}
- --log_as_json
{{- end }}
{{- if gt .EstimatedConcurrency 0 }}
- --concurrency
- "{{ .EstimatedConcurrency }}"
{{- end -}}
{{- if .Values.global.proxy.lifecycle }}
lifecycle:
{{ toYaml .Values.global.proxy.lifecycle | indent 6 }}
{{- else if $holdProxy }}
lifecycle:
postStart:
exec:
command:
- pilot-agent
- wait
{{- end }}
env:
{{- if eq (env "PILOT_ENABLE_INBOUND_PASSTHROUGH" "true") "false" }}
- name: REWRITE_PROBE_LEGACY_LOCALHOST_DESTINATION
value: "true"
{{- end }}
- name: JWT_POLICY
value: {{ .Values.global.jwtPolicy }}
- name: PILOT_CERT_PROVIDER
value: {{ .Values.global.pilotCertProvider }}
- name: CA_ADDR
{{- if .Values.global.caAddress }}
value: {{ .Values.global.caAddress }}
{{- else }}
value: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}.{{ .Values.global.istioNamespace }}.svc:15012
{{- end }}
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: INSTANCE_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: SERVICE_ACCOUNT
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
- name: HOST_IP
valueFrom:
fieldRef:
fieldPath: status.hostIP
- name: PROXY_CONFIG
value: |
{{ protoToJSON .ProxyConfig }}
- name: ISTIO_META_POD_PORTS
value: |-
[
{{- $first := true }}
{{- range $index1, $c := .Spec.Containers }}
{{- range $index2, $p := $c.Ports }}
{{- if (structToJSON $p) }}
{{if not $first}},{{end}}{{ structToJSON $p }}
{{- $first = false }}
{{- end }}
{{- end}}
{{- end}}
]
- name: ISTIO_META_APP_CONTAINERS
value: "{{ $containers | join "," }}"
- name: ISTIO_META_CLUSTER_ID
value: "{{ valueOrDefault .Values.global.multiCluster.clusterName `Kubernetes` }}"
- name: ISTIO_META_INTERCEPTION_MODE
value: "{{ or (index .ObjectMeta.Annotations `sidecar.istio.io/interceptionMode`) .ProxyConfig.InterceptionMode.String }}"
{{- if .Values.global.network }}
- name: ISTIO_META_NETWORK
value: "{{ .Values.global.network }}"
{{- end }}
{{- if .DeploymentMeta.Name }}
- name: ISTIO_META_WORKLOAD_NAME
value: "{{ .DeploymentMeta.Name }}"
{{ end }}
{{- if and .TypeMeta.APIVersion .DeploymentMeta.Name }}
- name: ISTIO_META_OWNER
value: kubernetes://apis/{{ .TypeMeta.APIVersion }}/namespaces/{{ valueOrDefault .DeploymentMeta.Namespace `default` }}/{{ toLower .TypeMeta.Kind}}s/{{ .DeploymentMeta.Name }}
{{- end}}
{{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }}
- name: ISTIO_BOOTSTRAP_OVERRIDE
value: "/etc/istio/custom-bootstrap/custom_bootstrap.json"
{{- end }}
{{- if .Values.global.meshID }}
- name: ISTIO_META_MESH_ID
value: "{{ .Values.global.meshID }}"
{{- else if (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }}
- name: ISTIO_META_MESH_ID
value: "{{ (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }}"
{{- end }}
{{- with (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }}
- name: TRUST_DOMAIN
value: "{{ . }}"
{{- end }}
{{- if and (eq .Values.global.proxy.tracer "datadog") (isset .ObjectMeta.Annotations `apm.datadoghq.com/env`) }}
{{- range $key, $value := fromJSON (index .ObjectMeta.Annotations `apm.datadoghq.com/env`) }}
- name: {{ $key }}
value: "{{ $value }}"
{{- end }}
{{- end }}
{{- range $key, $value := .ProxyConfig.ProxyMetadata }}
- name: {{ $key }}
value: "{{ $value }}"
{{- end }}
{{with .Values.global.imagePullPolicy }}imagePullPolicy: "{{.}}"{{end}}
{{ if ne (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) `0` }}
readinessProbe:
httpGet:
path: /healthz/ready
port: 15021
initialDelaySeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/initialDelaySeconds` .Values.global.proxy.readinessInitialDelaySeconds }}
periodSeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/periodSeconds` .Values.global.proxy.readinessPeriodSeconds }}
timeoutSeconds: 3
failureThreshold: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/failureThreshold` .Values.global.proxy.readinessFailureThreshold }}
{{ end -}}
securityContext:
{{- if eq (index .ProxyConfig.ProxyMetadata "IPTABLES_TRACE_LOGGING") "true" }}
allowPrivilegeEscalation: true
capabilities:
add:
- NET_ADMIN
drop:
- ALL
privileged: true
readOnlyRootFilesystem: {{ ne (annotation .ObjectMeta `sidecar.istio.io/enableCoreDump` .Values.global.proxy.enableCoreDump) "true" }}
runAsGroup: 1337
fsGroup: 1337
runAsNonRoot: false
runAsUser: 0
{{- else }}
allowPrivilegeEscalation: {{ .Values.global.proxy.privileged }}
capabilities:
{{ if or (eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY`) (eq (annotation .ObjectMeta `sidecar.istio.io/capNetBindService` .Values.global.proxy.capNetBindService) `true`) -}}
add:
{{ if eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY` -}}
- NET_ADMIN
{{- end }}
{{ if eq (annotation .ObjectMeta `sidecar.istio.io/capNetBindService` .Values.global.proxy.capNetBindService) `true` -}}
- NET_BIND_SERVICE
{{- end }}
{{- end }}
drop:
- ALL
privileged: {{ .Values.global.proxy.privileged }}
readOnlyRootFilesystem: {{ ne (annotation .ObjectMeta `sidecar.istio.io/enableCoreDump` .Values.global.proxy.enableCoreDump) "true" }}
runAsGroup: 1337
fsGroup: 1337
{{ if or (eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY`) (eq (annotation .ObjectMeta `sidecar.istio.io/capNetBindService` .Values.global.proxy.capNetBindService) `true`) -}}
runAsNonRoot: false
runAsUser: 0
{{- else -}}
runAsNonRoot: true
runAsUser: 1337
{{- end }}
{{- end }}
resources:
{{- if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit`) }}
{{- if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) }}
requests:
{{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) -}}
cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU` }}"
{{ end }}
{{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}}
memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory` }}"
{{ end }}
{{- end }}
{{- if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit`) }}
limits:
{{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit`) -}}
cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit` }}"
{{ end }}
{{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit`) -}}
memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit` }}"
{{ end }}
{{- end }}
{{- else }}
{{- if .Values.global.proxy.resources }}
{{ toYaml .Values.global.proxy.resources | indent 6 }}
{{- end }}
{{- end }}
volumeMounts:
{{- if eq .Values.global.caName "GkeWorkloadCertificate" }}
- name: gke-workload-certificate
mountPath: /var/run/secrets/workload-spiffe-credentials
readOnly: true
{{- end }}
{{- if eq .Values.global.pilotCertProvider "istiod" }}
- mountPath: /var/run/secrets/istio
name: istiod-ca-cert
{{- end }}
- mountPath: /var/lib/istio/data
name: istio-data
{{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }}
- mountPath: /etc/istio/custom-bootstrap
name: custom-bootstrap-volume
{{- end }}
# SDS channel between istioagent and Envoy
- mountPath: /etc/istio/proxy
name: istio-envoy
{{- if eq .Values.global.jwtPolicy "third-party-jwt" }}
- mountPath: /var/run/secrets/tokens
name: istio-token
{{- end }}
{{- if .Values.global.mountMtlsCerts }}
# Use the key and cert mounted to /etc/certs/ for the in-cluster mTLS communications.
- mountPath: /etc/certs/
name: istio-certs
readOnly: true
{{- end }}
- name: istio-podinfo
mountPath: /etc/istio/pod
{{- if and (eq .Values.global.proxy.tracer "lightstep") .ProxyConfig.GetTracing.GetTlsSettings }}
- mountPath: {{ directory .ProxyConfig.GetTracing.GetTlsSettings.GetCaCertificates }}
name: lightstep-certs
readOnly: true
{{- end }}
{{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount` }}
{{ range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount`) }}
- name: "{{ $index }}"
{{ toYaml $value | indent 6 }}
{{ end }}
{{- end }}
volumes:
{{- if eq .Values.global.caName "GkeWorkloadCertificate" }}
- name: gke-workload-certificate
csi:
driver: workloadcertificates.security.cloud.google.com
{{- end }}
{{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }}
- name: custom-bootstrap-volume
configMap:
name: {{ annotation .ObjectMeta `sidecar.istio.io/bootstrapOverride` "" }}
{{- end }}
# SDS channel between istioagent and Envoy
- emptyDir:
medium: Memory
name: istio-envoy
- name: istio-data
emptyDir: {}
- name: istio-podinfo
downwardAPI:
items:
- path: "labels"
fieldRef:
fieldPath: metadata.labels
- path: "annotations"
fieldRef:
fieldPath: metadata.annotations
{{- if eq .Values.global.jwtPolicy "third-party-jwt" }}
- name: istio-token
projected:
sources:
- serviceAccountToken:
path: istio-token
expirationSeconds: 43200
audience: {{ .Values.global.sds.token.aud }}
{{- end }}
{{- if eq .Values.global.pilotCertProvider "istiod" }}
- name: istiod-ca-cert
configMap:
name: istio-ca-root-cert
{{- end }}
{{- if .Values.global.mountMtlsCerts }}
# Use the key and cert mounted to /etc/certs/ for the in-cluster mTLS communications.
- name: istio-certs
secret:
optional: true
{{ if eq .Spec.ServiceAccountName "" }}
secretName: istio.default
{{ else -}}
secretName: {{ printf "istio.%s" .Spec.ServiceAccountName }}
{{ end -}}
{{- end }}
{{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolume` }}
{{range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolume`) }}
- name: "{{ $index }}"
{{ toYaml $value | indent 4 }}
{{ end }}
{{ end }}
{{- if and (eq .Values.global.proxy.tracer "lightstep") .ProxyConfig.GetTracing.GetTlsSettings }}
- name: lightstep-certs
secret:
optional: true
secretName: lightstep.cacert
{{- end }}
{{- if .Values.global.imagePullSecrets }}
imagePullSecrets:
{{- range .Values.global.imagePullSecrets }}
- name: {{ . }}
{{- end }}
{{- end }}
{{- if eq (env "ENABLE_LEGACY_FSGROUP_INJECTION" "true") "true" }}
securityContext:
fsGroup: 1337
{{- end }}

View File

@@ -1,5 +1,5 @@
{{- if and .Values.pilot.autoscaleEnabled .Values.pilot.autoscaleMin .Values.pilot.autoscaleMax }}
{{- if not .Values.global.autoscalingv2API }}
{{- if not .Values.extra.autoscalingv2API }}
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:

View File

@@ -19,7 +19,7 @@
configSources:
- address: k8s://
- address: {{ printf "xds://%s.%s:%s" .Values.global.higressName .Values.global.higressNamespace .Values.global.higressPort }}
- address: {{ printf "xds://%s.%s:%s" .Values.extra.higressName .Values.extra.higressNamespace .Values.extra.higressPort }}
defaultConfig:
{{- if .Values.global.meshID }}

View File

@@ -113,9 +113,9 @@ spec:
timeoutSeconds: 5
env:
- name: HIGRESS_CONTROLLER_SVC
value: {{ printf "%s.%s" .Values.global.higressName .Values.global.higressNamespace }}
value: {{ printf "%s.%s" .Values.extra.higressName .Values.extra.higressNamespace }}
- name: HIGRESS_CONTROLLER_PORT
value: "{{ .Values.global.higressPort }}"
value: "{{ .Values.extra.higressPort }}"
- name: REVISION
value: "{{ .Values.revision | default `default` }}"
- name: JWT_POLICY
@@ -159,7 +159,7 @@ spec:
value: "{{ .Values.global.istiod.enableAnalysis }}"
- name: CLUSTER_ID
value: "{{ $.Values.global.multiCluster.clusterName | default `Kubernetes` }}"
{{- if not .Values.global.kind }}
{{- if not .Values.extra.kind }}
resources:
{{- if .Values.pilot.resources }}
{{ toYaml .Values.pilot.resources | trim | indent 12 }}

View File

@@ -10,7 +10,7 @@ pilot:
rollingMaxUnavailable: 25%
hub: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress
tag: bf607ae5541ce5c1cc95b4f98b3fd50a83346d33
tag: 0.6.0
# Can be a full hub/image:tag
image: pilot
@@ -220,7 +220,7 @@ meshConfig:
# What we may configure in mesh config is the ".global" - and use of other suffixes.
# No hurry to do this in 1.6, we're trying to prove the code.
global:
extra:
kind: false
# whether to use autoscaling/v2 template for HPA settings
# for internal usage only, not to be configured by users.
@@ -228,6 +228,8 @@ global:
higressName: "higress-controller"
higressNamespace: "higress-system"
higressPort: "15051"
global:
# Used to locate istiod.
istioNamespace: istio-system
# enable pod disruption budget for the control plane, which is used to
@@ -254,7 +256,7 @@ global:
# Dev builds from prow are on gcr.io
hub: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress
# Default tag for Istio images.
tag: bf607ae5541ce5c1cc95b4f98b3fd50a83346d33
tag: 0.6.0
# Specify image pull policy if default behavior isn't desired.
# Default behavior: latest images will be Always else IfNotPresent.

View File

@@ -1,6 +1,6 @@
dependencies:
- name: higress
repository: file://../../higress
version: 0.5.3
digest: sha256:31fd001a558b73f3a5b86d607ccf2c4ff7f206fc232068cfc6722ccd02081031
generated: "2022-12-16T17:21:23.630507+08:00"
version: 0.6.0
digest: sha256:d5a9a1a3ee640635a1251ac1535a95db79975b39f6ab6b7c742c3e0d11f33533
generated: "2023-01-19T10:31:59.206741+08:00"

View File

@@ -1,5 +1,5 @@
apiVersion: v2
appVersion: 0.5.3
appVersion: 0.6.0
description: Helm chart for deploying higress gateways
icon: https://higress.io/img/higress_logo_small.png
keywords:
@@ -11,6 +11,6 @@ sources:
dependencies:
- name: higress
repository: "file://../../higress"
version: 0.5.3
version: 0.6.0
type: application
version: 0.5.3
version: 0.6.0

View File

@@ -1,5 +1,5 @@
apiVersion: v2
appVersion: 1.12.3
appVersion: 1.12.4
description: Helm chart for deploying higress istio
name: istio-local
sources:
@@ -12,4 +12,4 @@ dependencies:
repository: "file://../../istiod"
version: 1.12.0
type: application
version: 1.12.3
version: 1.12.4

View File

@@ -0,0 +1,30 @@
diff -Naur istio/pilot/pkg/features/pilot.go istio_new/pilot/pkg/features/pilot.go
--- istio/pilot/pkg/features/pilot.go 2023-01-19 11:17:16.000000000 +0800
+++ istio_new/pilot/pkg/features/pilot.go 2023-01-19 11:03:37.000000000 +0800
@@ -562,6 +562,11 @@
PrioritizedLeaderElection = env.RegisterBoolVar("PRIORITIZED_LEADER_ELECTION", true,
"If enabled, the default revision will steal leader locks from non-default revisions").Get()
+
+ // Added by ingress
+ CustomCACertConfigMapName = env.RegisterStringVar("CUSTOM_CA_CERT_NAME", "",
+ "Defines the configmap's name of istio's root ca certificate").Get()
+ // End added by ingress
)
// UnsafeFeaturesEnabled returns true if any unsafe features are enabled.
diff -Naur istio/pilot/pkg/serviceregistry/kube/controller/namespacecontroller.go istio_new/pilot/pkg/serviceregistry/kube/controller/namespacecontroller.go
--- istio/pilot/pkg/serviceregistry/kube/controller/namespacecontroller.go 2023-01-19 11:17:19.000000000 +0800
+++ istio_new/pilot/pkg/serviceregistry/kube/controller/namespacecontroller.go 2023-01-19 11:20:32.000000000 +0800
@@ -50,6 +50,11 @@
if features.ClusterName != "" && features.ClusterName != "Kubernetes" {
dynamicCACertNamespaceConfigMap = fmt.Sprintf("%s-ca-root-cert", features.ClusterName)
}
+ // Added by ingress
+ if features.CustomCACertConfigMapName != "" {
+ dynamicCACertNamespaceConfigMap = features.CustomCACertConfigMapName
+ }
+ // End added by ingress
}
// NamespaceController manages reconciles a configmap in each namespace with a desired set of data.

View File

@@ -25,6 +25,7 @@ import (
"google.golang.org/grpc/reflection"
"istio.io/api/mesh/v1alpha1"
configaggregate "istio.io/istio/pilot/pkg/config/aggregate"
"istio.io/istio/pilot/pkg/features"
istiogrpc "istio.io/istio/pilot/pkg/grpc"
"istio.io/istio/pilot/pkg/model"
"istio.io/istio/pilot/pkg/server"
@@ -37,6 +38,9 @@ import (
"istio.io/istio/pkg/config/schema/gvk"
"istio.io/istio/pkg/keepalive"
istiokube "istio.io/istio/pkg/kube"
"istio.io/istio/pkg/security"
"istio.io/istio/security/pkg/server/ca/authenticate"
"istio.io/istio/security/pkg/server/ca/authenticate/kubeauth"
"istio.io/pkg/env"
"istio.io/pkg/ledger"
"istio.io/pkg/log"
@@ -149,6 +153,7 @@ func NewServer(args *ServerArgs) (*Server, error) {
s.initHttpServer,
s.initConfigController,
s.initRegistryEventHandlers,
s.initAuthenticators,
}
for _, f := range initFuncList {
@@ -156,6 +161,7 @@ func NewServer(args *ServerArgs) (*Server, error) {
return nil, err
}
}
s.server.RunComponent(func(stop <-chan struct{}) error {
s.kubeClient.RunAndWait(stop)
return nil
@@ -223,7 +229,9 @@ func (s *Server) initConfigController() error {
// Defer starting the controller until after the service is created.
s.server.RunComponent(func(stop <-chan struct{}) error {
ingressConfig.InitializeCluster(ingressController, stop)
if err := ingressConfig.InitializeCluster(ingressController, stop); err != nil {
return err
}
go s.configController.Run(stop)
return nil
})
@@ -316,8 +324,7 @@ func (s *Server) initXdsServer() error {
s.xdsServer.Start(stop)
return nil
})
s.initGrpcServer()
return nil
return s.initGrpcServer()
}
func (s *Server) initGrpcServer() error {
@@ -332,6 +339,18 @@ func (s *Server) initGrpcServer() error {
return nil
}
func (s *Server) initAuthenticators() error {
authenticators := []security.Authenticator{
&authenticate.ClientCertAuthenticator{},
}
authenticators = append(authenticators,
kubeauth.NewKubeJWTAuthenticator(s.environment.Watcher, s.kubeClient, s.RegistryOptions.KubeOptions.ClusterID, nil, features.JwtPolicy))
if features.XDSAuth {
s.xdsServer.Authenticators = authenticators
}
return nil
}
func (s *Server) initKubeClient() error {
if s.kubeClient != nil {
// Already initialized by startup arguments
@@ -363,6 +382,7 @@ func (s *Server) initHttpServer() error {
return nil
}
// readyHandler checks whether the http server is ready
func (s *Server) readyHandler(w http.ResponseWriter, _ *http.Request) {
for name, fn := range s.readinessProbes {
if ready, err := fn(); !ready {
@@ -376,10 +396,7 @@ func (s *Server) readyHandler(w http.ResponseWriter, _ *http.Request) {
// cachesSynced checks whether caches have been synced.
func (s *Server) cachesSynced() bool {
if !s.configController.HasSynced() {
return false
}
return true
return s.configController.HasSynced()
}
func (s *Server) waitForCacheSync(stop <-chan struct{}) bool {

View File

@@ -0,0 +1,66 @@
// 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 bootstrap
import (
"context"
"testing"
"github.com/agiledragon/gomonkey/v2"
"istio.io/istio/pilot/pkg/features"
"istio.io/istio/pkg/keepalive"
higresskube "github.com/alibaba/higress/pkg/kube"
)
func TestStartWithNoError(t *testing.T) {
var (
s *Server
err error
)
mockFn := func(s *Server) error {
s.kubeClient = higresskube.NewFakeClient()
return nil
}
gomonkey.ApplyFunc((*Server).initKubeClient, mockFn)
if s, err = NewServer(newServerArgs()); err != nil {
t.Errorf("failed to create server: %v", err)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if err = s.Start(ctx.Done()); err != nil {
t.Errorf("failed to start the server: %v", err)
}
}
func newServerArgs() *ServerArgs {
return &ServerArgs{
Debug: true,
NativeIstio: true,
HttpAddress: ":8888",
GrpcAddress: ":15051",
GrpcKeepAliveOptions: keepalive.DefaultOption(),
XdsOptions: XdsOptions{
DebounceAfter: features.DebounceAfter,
DebounceMax: features.DebounceMax,
EnableEDSDebounce: features.EnableEDSDebounce,
},
}
}

View File

@@ -16,6 +16,8 @@ package config
import (
"encoding/json"
"errors"
"fmt"
"strings"
"sync"
@@ -23,9 +25,12 @@ import (
wasm "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/wasm/v3"
httppb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/wasm/v3"
"github.com/gogo/protobuf/types"
"github.com/golang/protobuf/ptypes/wrappers"
"google.golang.org/protobuf/types/known/anypb"
extensions "istio.io/api/extensions/v1alpha1"
networking "istio.io/api/networking/v1alpha3"
istiotype "istio.io/api/type/v1beta1"
"istio.io/istio/pilot/pkg/model"
networkingutil "istio.io/istio/pilot/pkg/networking/util"
"istio.io/istio/pilot/pkg/util/sets"
@@ -36,6 +41,8 @@ import (
listersv1 "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/tools/cache"
higressext "github.com/alibaba/higress/api/extensions/v1alpha1"
extlisterv1 "github.com/alibaba/higress/client/pkg/listers/extensions/v1alpha1"
netlisterv1 "github.com/alibaba/higress/client/pkg/listers/networking/v1"
"github.com/alibaba/higress/pkg/ingress/kube/annotations"
"github.com/alibaba/higress/pkg/ingress/kube/common"
@@ -44,6 +51,7 @@ import (
"github.com/alibaba/higress/pkg/ingress/kube/mcpbridge"
"github.com/alibaba/higress/pkg/ingress/kube/secret"
"github.com/alibaba/higress/pkg/ingress/kube/util"
"github.com/alibaba/higress/pkg/ingress/kube/wasmplugin"
. "github.com/alibaba/higress/pkg/ingress/log"
"github.com/alibaba/higress/pkg/kube"
"github.com/alibaba/higress/registry/reconcile"
@@ -69,6 +77,7 @@ type IngressConfig struct {
destinationRuleHandlers []model.EventHandler
envoyFilterHandlers []model.EventHandler
serviceEntryHandlers []model.EventHandler
wasmPluginHandlers []model.EventHandler
watchErrorHandler cache.WatchErrorHandler
cachedEnvoyFilters []config.Config
@@ -83,6 +92,12 @@ type IngressConfig struct {
mcpbridgeLister netlisterv1.McpBridgeLister
wasmPluginController wasmplugin.WasmPluginController
wasmPluginLister extlisterv1.WasmPluginLister
wasmPlugins map[string]*extensions.WasmPlugin
XDSUpdater model.XDSUpdater
annotationHandler annotations.AnnotationHandler
@@ -109,11 +124,17 @@ func NewIngressConfig(localKubeClient kube.Client, XDSUpdater model.XDSUpdater,
watchedSecretSet: sets.NewSet(),
namespace: namespace,
mcpbridgeReconciled: true,
wasmPlugins: make(map[string]*extensions.WasmPlugin),
}
mcpbridgeController := mcpbridge.NewController(localKubeClient, clusterId)
mcpbridgeController.AddEventHandler(config.AddOrUpdateMcpBridge, config.DeleteMcpBridge)
config.mcpbridgeController = mcpbridgeController
config.mcpbridgeLister = mcpbridgeController.Lister()
wasmPluginController := wasmplugin.NewController(localKubeClient, clusterId)
wasmPluginController.AddEventHandler(config.AddOrUpdateWasmPlugin, config.DeleteWasmPlugin)
config.wasmPluginController = wasmPluginController
config.wasmPluginLister = wasmPluginController.Lister()
return config
}
@@ -134,6 +155,9 @@ func (m *IngressConfig) RegisterEventHandler(kind config.GroupVersionKind, f mod
case gvk.ServiceEntry:
m.serviceEntryHandlers = append(m.serviceEntryHandlers, f)
case gvk.WasmPlugin:
m.wasmPluginHandlers = append(m.wasmPluginHandlers, f)
}
for _, remoteIngressController := range m.remoteIngressControllers {
@@ -158,19 +182,6 @@ func (m *IngressConfig) AddLocalCluster(options common.Options) common.IngressCo
}
func (m *IngressConfig) InitializeCluster(ingressController common.IngressController, stop <-chan struct{}) error {
for _, handler := range m.virtualServiceHandlers {
ingressController.RegisterEventHandler(gvk.VirtualService, handler)
}
for _, handler := range m.gatewayHandlers {
ingressController.RegisterEventHandler(gvk.Gateway, handler)
}
for _, handler := range m.destinationRuleHandlers {
ingressController.RegisterEventHandler(gvk.DestinationRule, handler)
}
for _, handler := range m.envoyFilterHandlers {
ingressController.RegisterEventHandler(gvk.EnvoyFilter, handler)
}
_ = ingressController.SetWatchErrorHandler(m.watchErrorHandler)
go ingressController.Run(stop)
@@ -182,7 +193,8 @@ func (m *IngressConfig) List(typ config.GroupVersionKind, namespace string) ([]c
typ != gvk.VirtualService &&
typ != gvk.DestinationRule &&
typ != gvk.EnvoyFilter &&
typ != gvk.ServiceEntry {
typ != gvk.ServiceEntry &&
typ != gvk.WasmPlugin {
return nil, common.ErrUnsupportedOp
}
@@ -219,6 +231,8 @@ func (m *IngressConfig) List(typ config.GroupVersionKind, namespace string) ([]c
return m.convertDestinationRule(wrapperConfigs), nil
case gvk.ServiceEntry:
return m.convertServiceEntry(wrapperConfigs), nil
case gvk.WasmPlugin:
return m.convertWasmPlugin(wrapperConfigs), nil
}
return nil, nil
@@ -485,6 +499,23 @@ func (m *IngressConfig) convertEnvoyFilter(convertOptions *common.ConvertOptions
m.mutex.Unlock()
}
func (m *IngressConfig) convertWasmPlugin([]common.WrapperConfig) []config.Config {
m.mutex.RLock()
defer m.mutex.RUnlock()
out := make([]config.Config, 0, len(m.wasmPlugins))
for name, wasmPlugin := range m.wasmPlugins {
out = append(out, config.Config{
Meta: config.Meta{
GroupVersionKind: gvk.WasmPlugin,
Name: name,
Namespace: m.namespace,
},
Spec: wasmPlugin,
})
}
return out
}
func (m *IngressConfig) convertServiceEntry([]common.WrapperConfig) []config.Config {
if m.RegistryReconciler == nil {
return nil
@@ -656,6 +687,153 @@ func (m *IngressConfig) applyInternalActiveRedirect(convertOptions *common.Conve
}
}
func (m *IngressConfig) convertIstioWasmPlugin(obj *higressext.WasmPlugin) (*extensions.WasmPlugin, error) {
result := &extensions.WasmPlugin{
Selector: &istiotype.WorkloadSelector{
MatchLabels: map[string]string{
"higress": m.namespace + "-higress-gateway",
},
},
Url: obj.Url,
Sha256: obj.Sha256,
ImagePullPolicy: extensions.PullPolicy(obj.ImagePullPolicy),
ImagePullSecret: obj.ImagePullSecret,
VerificationKey: obj.VerificationKey,
PluginConfig: obj.PluginConfig,
PluginName: obj.PluginName,
Phase: extensions.PluginPhase(obj.Phase),
Priority: obj.Priority,
}
if result.PluginConfig != nil {
return result, nil
}
result.PluginConfig = obj.DefaultConfig
if len(obj.MatchRules) > 0 {
if result.PluginConfig == nil {
result.PluginConfig = &types.Struct{
Fields: map[string]*types.Value{},
}
}
var ruleValues []*types.Value
for _, rule := range obj.MatchRules {
if rule.Config == nil {
return nil, errors.New("invalid rule has no config")
}
v := &types.Value_StructValue{
StructValue: rule.Config,
}
var matchItems []*types.Value
for _, ing := range rule.Ingress {
matchItems = append(matchItems, &types.Value{
Kind: &types.Value_StringValue{
StringValue: ing,
},
})
}
if len(matchItems) > 0 {
v.StructValue.Fields["_match_route_"] = &types.Value{
Kind: &types.Value_ListValue{
ListValue: &types.ListValue{
Values: matchItems,
},
},
}
ruleValues = append(ruleValues, &types.Value{
Kind: v,
})
continue
}
for _, domain := range rule.Domain {
matchItems = append(matchItems, &types.Value{
Kind: &types.Value_StringValue{
StringValue: domain,
},
})
}
if len(matchItems) == 0 {
return nil, fmt.Errorf("invalid match rule has no match condition, rule:%v", rule)
}
v.StructValue.Fields["_match_domain_"] = &types.Value{
Kind: &types.Value_ListValue{
ListValue: &types.ListValue{
Values: matchItems,
},
},
}
ruleValues = append(ruleValues, &types.Value{
Kind: v,
})
}
result.PluginConfig.Fields["_rules_"] = &types.Value{
Kind: &types.Value_ListValue{
ListValue: &types.ListValue{
Values: ruleValues,
},
},
}
}
return result, nil
}
func (m *IngressConfig) AddOrUpdateWasmPlugin(clusterNamespacedName util.ClusterNamespacedName) {
if clusterNamespacedName.Namespace != m.namespace {
return
}
wasmPlugin, err := m.wasmPluginLister.WasmPlugins(clusterNamespacedName.Namespace).Get(clusterNamespacedName.Name)
if err != nil {
IngressLog.Errorf("wasmPlugin is not found, namespace:%s, name:%s",
clusterNamespacedName.Namespace, clusterNamespacedName.Name)
return
}
metadata := config.Meta{
Name: clusterNamespacedName.Name + "-wasmplugin",
Namespace: clusterNamespacedName.Namespace,
GroupVersionKind: gvk.WasmPlugin,
// Set this label so that we do not compare configs and just push.
Labels: map[string]string{constants.AlwaysPushLabel: "true"},
}
for _, f := range m.wasmPluginHandlers {
IngressLog.Debug("WasmPlugin triggerd update")
f(config.Config{Meta: metadata}, config.Config{Meta: metadata}, model.EventUpdate)
}
istioWasmPlugin, err := m.convertIstioWasmPlugin(&wasmPlugin.Spec)
if err != nil {
IngressLog.Errorf("invalid wasmPlugin:%s, err:%v", clusterNamespacedName.Name, err)
return
}
IngressLog.Debugf("wasmPlugin:%s convert to istioWasmPlugin:%v", clusterNamespacedName.Name, istioWasmPlugin)
m.mutex.Lock()
m.wasmPlugins[clusterNamespacedName.Name] = istioWasmPlugin
m.mutex.Unlock()
}
func (m *IngressConfig) DeleteWasmPlugin(clusterNamespacedName util.ClusterNamespacedName) {
if clusterNamespacedName.Namespace != m.namespace {
return
}
var hit bool
m.mutex.Lock()
if _, ok := m.wasmPlugins[clusterNamespacedName.Name]; ok {
delete(m.wasmPlugins, clusterNamespacedName.Name)
hit = true
}
m.mutex.Unlock()
if hit {
metadata := config.Meta{
Name: clusterNamespacedName.Name + "-wasmplugin",
Namespace: clusterNamespacedName.Namespace,
GroupVersionKind: gvk.WasmPlugin,
// Set this label so that we do not compare configs and just push.
Labels: map[string]string{constants.AlwaysPushLabel: "true"},
}
for _, f := range m.wasmPluginHandlers {
IngressLog.Debug("WasmPlugin triggerd update")
f(config.Config{Meta: metadata}, config.Config{Meta: metadata}, model.EventDelete)
}
}
}
func (m *IngressConfig) AddOrUpdateMcpBridge(clusterNamespacedName util.ClusterNamespacedName) {
// TODO: get resource name from config
if clusterNamespacedName.Name != "default" || clusterNamespacedName.Namespace != m.namespace {
@@ -873,7 +1051,8 @@ func constructBasicAuthEnvoyFilter(rules *common.BasicAuthRules, namespace strin
}
func (m *IngressConfig) Run(stop <-chan struct{}) {
m.mcpbridgeController.Run(stop)
go m.mcpbridgeController.Run(stop)
go m.wasmPluginController.Run(stop)
}
func (m *IngressConfig) HasSynced() bool {
@@ -887,6 +1066,9 @@ func (m *IngressConfig) HasSynced() bool {
if !m.mcpbridgeController.HasSynced() || !m.mcpbridgeReconciled {
return false
}
if !m.wasmPluginController.HasSynced() {
return false
}
IngressLog.Info("Ingress config controller synced.")
return true
}

View File

@@ -32,6 +32,7 @@ var _ Parser = destination{}
type DestinationConfig struct {
McpDestination []*networking.HTTPRouteDestination
WeightSum int64
}
type destination struct{}
@@ -99,11 +100,11 @@ func (a destination) Parse(annotations Annotations, config *Ingress, globalConte
destinations = append(destinations, dest)
}
if weightSum != 100 {
IngressLog.Errorf("destination has invalid weight sum %d within ingress %s/%s", weightSum, config.Namespace, config.Name)
return nil
IngressLog.Warnf("destination has invalid weight sum %d within ingress %s/%s", weightSum, config.Namespace, config.Name)
}
config.Destination = &DestinationConfig{
McpDestination: destinations,
WeightSum: weightSum,
}
return nil
}

View File

@@ -25,4 +25,5 @@ var IngressIR = collection.NewSchemasBuilder().
MustAdd(collections.IstioNetworkingV1Alpha3Gateways).
MustAdd(collections.IstioNetworkingV1Alpha3Serviceentries).
MustAdd(collections.IstioNetworkingV1Alpha3Virtualservices).
MustAdd(collections.IstioExtensionsV1Alpha1Wasmplugins).
Build()

View File

@@ -277,12 +277,15 @@ func partMd5(raw string) string {
return encoded[:4] + encoded[len(encoded)-4:]
}
func GenerateUniqueRouteName(route *WrapperHTTPRoute) string {
func GenerateUniqueRouteName(defaultNs string, route *WrapperHTTPRoute) string {
if route.WrapperConfig.Config.Namespace == defaultNs {
return route.WrapperConfig.Config.Name
}
return route.Meta()
}
func GenerateUniqueRouteNameWithSuffix(route *WrapperHTTPRoute, suffix string) string {
return CreateConvertedName(route.Meta(), suffix)
func GenerateUniqueRouteNameWithSuffix(defaultNs string, route *WrapperHTTPRoute, suffix string) string {
return CreateConvertedName(GenerateUniqueRouteName(defaultNs, route), suffix)
}
func SplitServiceFQDN(fqdn string) (string, string, bool) {
@@ -295,12 +298,15 @@ func SplitServiceFQDN(fqdn string) (string, string, bool) {
func ConvertBackendService(routeDestination *networking.HTTPRouteDestination) model.BackendService {
parts := strings.Split(routeDestination.Destination.Host, ".")
return model.BackendService{
service := model.BackendService{
Namespace: parts[1],
Name: parts[0],
Port: routeDestination.Destination.Port.Number,
Weight: routeDestination.Weight,
}
if routeDestination.Destination.Port != nil {
service.Port = routeDestination.Destination.Port.Number
}
return service
}
func getLoadBalancerIp(svc *v1.Service) []string {

View File

@@ -198,7 +198,8 @@ func TestGenerateUniqueRouteName(t *testing.T) {
},
}
assert.Equal(t, "bar/foo", GenerateUniqueRouteName(input))
assert.Equal(t, "bar/foo", GenerateUniqueRouteName("xxx", input))
assert.Equal(t, "foo", GenerateUniqueRouteName("bar", input))
}

View File

@@ -548,7 +548,7 @@ func (c *controller) ConvertHTTPRoute(convertOptions *common.ConvertOptions, wra
}
wrapperHttpRoute.OriginPath = path
wrapperHttpRoute.HTTPRoute.Match = []*networking.HTTPMatchRequest{httpMatch}
wrapperHttpRoute.HTTPRoute.Name = common.GenerateUniqueRouteName(wrapperHttpRoute)
wrapperHttpRoute.HTTPRoute.Name = common.GenerateUniqueRouteName(c.options.SystemNamespace, wrapperHttpRoute)
ingressRouteBuilder := convertOptions.IngressRouteCache.New(wrapperHttpRoute)
@@ -575,6 +575,10 @@ func (c *controller) ConvertHTTPRoute(convertOptions *common.ConvertOptions, wra
destinationConfig := wrapper.AnnotationsConfig.Destination
wrapperHttpRoute.HTTPRoute.Route, event = c.backendToRouteDestination(&httpPath.Backend, cfg.Namespace, ingressRouteBuilder, destinationConfig)
if destinationConfig != nil {
wrapperHttpRoute.WeightTotal = int32(destinationConfig.WeightSum)
}
if ingressRouteBuilder.Event != common.Normal {
event = ingressRouteBuilder.Event
}
@@ -749,7 +753,7 @@ func (c *controller) ApplyCanaryIngress(convertOptions *common.ConvertOptions, w
}
canary.OriginPath = path
canary.HTTPRoute.Match = []*networking.HTTPMatchRequest{httpMatch}
canary.HTTPRoute.Name = common.GenerateUniqueRouteName(canary)
canary.HTTPRoute.Name = common.GenerateUniqueRouteName(c.options.SystemNamespace, canary)
ingressRouteBuilder := convertOptions.IngressRouteCache.New(canary)
// backend service check
@@ -777,7 +781,7 @@ func (c *controller) ApplyCanaryIngress(convertOptions *common.ConvertOptions, w
if byHeader {
IngressLog.Debug("Insert canary route by header")
annotations.ApplyByHeader(canary.HTTPRoute, route.HTTPRoute, canary.WrapperConfig.AnnotationsConfig)
canary.HTTPRoute.Name = common.GenerateUniqueRouteName(canary)
canary.HTTPRoute.Name = common.GenerateUniqueRouteName(c.options.SystemNamespace, canary)
} else {
IngressLog.Debug("Merge canary route by weight")
if route.WeightTotal == 0 {
@@ -805,7 +809,7 @@ func (c *controller) ApplyCanaryIngress(convertOptions *common.ConvertOptions, w
convertOptions.HTTPRoutes[rule.Host] = routes
// Recreate route name.
ingressRouteBuilder.RouteName = common.GenerateUniqueRouteName(canary)
ingressRouteBuilder.RouteName = common.GenerateUniqueRouteName(c.options.SystemNamespace, canary)
convertOptions.IngressRouteCache.Add(ingressRouteBuilder)
} else {
convertOptions.IngressRouteCache.Update(targetRoute)
@@ -931,7 +935,7 @@ func (c *controller) createDefaultRoute(wrapper *common.WrapperConfig, backend *
OriginPathType: common.Prefix,
OriginPath: "/",
}
route.HTTPRoute.Name = common.GenerateUniqueRouteNameWithSuffix(route, "default")
route.HTTPRoute.Name = common.GenerateUniqueRouteNameWithSuffix(c.options.SystemNamespace, route, "default")
return route
}
@@ -961,7 +965,7 @@ func (c *controller) createServiceKey(service *ingress.IngressBackend, namespace
}
func isCanaryRoute(canary, route *common.WrapperHTTPRoute) bool {
return !strings.HasSuffix(route.HTTPRoute.Name, "-canary") && canary.OriginPath == route.OriginPath &&
return !route.WrapperConfig.AnnotationsConfig.IsCanary() && canary.OriginPath == route.OriginPath &&
canary.OriginPathType == route.OriginPathType
}

View File

@@ -544,7 +544,7 @@ func (c *controller) ConvertHTTPRoute(convertOptions *common.ConvertOptions, wra
}
wrapperHttpRoute.OriginPath = path
wrapperHttpRoute.HTTPRoute.Match = []*networking.HTTPMatchRequest{httpMatch}
wrapperHttpRoute.HTTPRoute.Name = common.GenerateUniqueRouteName(wrapperHttpRoute)
wrapperHttpRoute.HTTPRoute.Name = common.GenerateUniqueRouteName(c.options.SystemNamespace, wrapperHttpRoute)
ingressRouteBuilder := convertOptions.IngressRouteCache.New(wrapperHttpRoute)
@@ -570,6 +570,11 @@ func (c *controller) ConvertHTTPRoute(convertOptions *common.ConvertOptions, wra
var event common.Event
destinationConfig := wrapper.AnnotationsConfig.Destination
wrapperHttpRoute.HTTPRoute.Route, event = c.backendToRouteDestination(&httpPath.Backend, cfg.Namespace, ingressRouteBuilder, destinationConfig)
if destinationConfig != nil {
wrapperHttpRoute.WeightTotal = int32(destinationConfig.WeightSum)
}
if ingressRouteBuilder.Event != common.Normal {
event = ingressRouteBuilder.Event
}
@@ -745,7 +750,7 @@ func (c *controller) ApplyCanaryIngress(convertOptions *common.ConvertOptions, w
}
canary.OriginPath = path
canary.HTTPRoute.Match = []*networking.HTTPMatchRequest{httpMatch}
canary.HTTPRoute.Name = common.GenerateUniqueRouteName(canary)
canary.HTTPRoute.Name = common.GenerateUniqueRouteName(c.options.SystemNamespace, canary)
ingressRouteBuilder := convertOptions.IngressRouteCache.New(canary)
// backend service check
@@ -773,7 +778,7 @@ func (c *controller) ApplyCanaryIngress(convertOptions *common.ConvertOptions, w
if byHeader {
IngressLog.Debug("Insert canary route by header")
annotations.ApplyByHeader(canary.HTTPRoute, route.HTTPRoute, canary.WrapperConfig.AnnotationsConfig)
canary.HTTPRoute.Name = common.GenerateUniqueRouteName(canary)
canary.HTTPRoute.Name = common.GenerateUniqueRouteName(c.options.SystemNamespace, canary)
} else {
IngressLog.Debug("Merge canary route by weight")
if route.WeightTotal == 0 {
@@ -801,7 +806,7 @@ func (c *controller) ApplyCanaryIngress(convertOptions *common.ConvertOptions, w
convertOptions.HTTPRoutes[rule.Host] = routes
// Recreate route name.
ingressRouteBuilder.RouteName = common.GenerateUniqueRouteName(canary)
ingressRouteBuilder.RouteName = common.GenerateUniqueRouteName(c.options.SystemNamespace, canary)
convertOptions.IngressRouteCache.Add(ingressRouteBuilder)
} else {
convertOptions.IngressRouteCache.Update(targetRoute)
@@ -925,7 +930,7 @@ func (c *controller) createDefaultRoute(wrapper *common.WrapperConfig, backend *
OriginPathType: common.Prefix,
OriginPath: "/",
}
route.HTTPRoute.Name = common.GenerateUniqueRouteNameWithSuffix(route, "default")
route.HTTPRoute.Name = common.GenerateUniqueRouteNameWithSuffix(c.options.SystemNamespace, route, "default")
return route
}

View File

@@ -0,0 +1,46 @@
// 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 wasmplugin
import (
"time"
"istio.io/istio/pkg/kube/controllers"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/tools/cache"
v1 "github.com/alibaba/higress/client/pkg/apis/extensions/v1alpha1"
"github.com/alibaba/higress/client/pkg/clientset/versioned"
informersv1 "github.com/alibaba/higress/client/pkg/informers/externalversions/extensions/v1alpha1"
listersv1 "github.com/alibaba/higress/client/pkg/listers/extensions/v1alpha1"
"github.com/alibaba/higress/pkg/ingress/kube/controller"
kubeclient "github.com/alibaba/higress/pkg/kube"
)
type WasmPluginController controller.Controller[listersv1.WasmPluginLister]
func NewController(client kubeclient.Client, clusterId string) WasmPluginController {
informer := client.HigressInformer().InformerFor(&v1.WasmPlugin{}, func(k versioned.Interface, resync time.Duration) cache.SharedIndexInformer {
return informersv1.NewWasmPluginInformer(k, metav1.NamespaceAll, resync,
cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
})
return controller.NewCommonController("wasmplugin", listersv1.NewWasmPluginLister(informer.GetIndexer()),
informer, GetWasmPlugin, clusterId)
}
func GetWasmPlugin(lister listersv1.WasmPluginLister, namespacedName types.NamespacedName) (controllers.Object, error) {
return lister.WasmPlugins(namespacedName.Namespace).Get(namespacedName.Name)
}

View File

@@ -61,6 +61,7 @@ func NewFakeClient(objects ...runtime.Object) Client {
}
c.higress = higressfake.NewSimpleClientset()
c.higressInformer = higressinformer.NewSharedInformerFactoryWithOptions(c.higress, resyncInterval)
c.informerWatchesPending = atomic.NewInt32(0)
// https://github.com/kubernetes/kubernetes/issues/95372
// There is a race condition in the client fakes, where events that happen between the List and Watch

View File

@@ -1,3 +1,7 @@
<p>
<a href="README_EN.md"> English </a> | 中文
</p>
# 功能说明
`key-rate-limit`插件实现了基于特定键值实现限流,键值来源可以是 URL 参数、HTTP 请求头

View File

@@ -0,0 +1,70 @@
<p>
English | <a href="README.md">中文</a>
</p>
# Description
`key-rate-limit` plugin implements a rate-limiting function based on specific key-values. The key-values may come from URL parameters or HTTP headers.
# Configuration Fields
| Name | Type | Requirement | Default Value | Description |
| -------- | -------- | -------- | -------- | -------- |
| limit_by_header | string | Optional. Choose one from following: `limit_by_header`, `limit_by_param`. | - | The name of HTTP header used to obtain key-value used in rate-limiting. |
| limit_by_param | string | Optional. Choose one from following: `limit_by_header`, `limit_by_param`. | - | The name of URL parameter used to obtain key-value used in rate-limiting. |
| limit_keys | array of object | Required | - | Rate-limiting thresholds when matching specific key-values |
Field descriptions of `limit_keys` items:
| Name | Type | Requirement | Default Value | Description |
| -------- | -------- | -------- | -------- | -------- |
| key | string | Required | - | Value to match of the specific key |
| query_per_second | number | Optional. Choose one from following: `query_per_second`, `query_per_minute`, `query_per_hour`, `query_per_day`. | - | Number of requests allowed per second |
| query_per_minute | number | Optional. Choose one from following: `query_per_second`, `query_per_minute`, `query_per_hour`, `query_per_day`. | - | Number of requests allowed per minute |
| query_per_hour | number | Optional. Choose one from following: `query_per_second`, `query_per_minute`, `query_per_hour`, `query_per_day`. | - | Number of requests allowed per hour |
| query_per_day | number | Optional. Choose one from following: `query_per_second`, `query_per_minute`, `query_per_hour`, `query_per_day`. | - | Number of requests allowed per day |
# Configuration Samples
## Use query parameter `apikey` for rate-limiting
```yaml
limit_by_param: apikey
limit_keys:
- key: 9a342114-ba8a-11ec-b1bf-00163e1250b5
query_per_second: 10
- key: a6a6d7f2-ba8a-11ec-bec2-00163e1250b5
query_per_minute: 100
```
## Use HTTP header parameter `x-ca-key` for rate-limiting
```yaml
limit_by_header: x-ca-key
limit_keys:
- key: 102234
query_per_second: 10
- key: 308239
query_per_hour: 10
```
## Enable rate-limiting for specific routes or domains
```yaml
# Use _rules_ field for fine-grained rule configurations
_rules_:
# Rule 1: Match by route name
- _match_route_:
- route-a
- route-b
limit_by_header: x-ca-key
limit_keys:
- key: 102234
query_per_second: 10
# Rule 2: Match by domain
- _match_domain_:
- "*.example.com"
- test.com
limit_by_header: x-ca-key
limit_keys:
- key: 102234
query_per_second: 100
```
In the rule sample of `_match_route_`, `route-a` and `route-b` are the route names provided when creating a new gateway route. When the current route names matches the configuration, the rule following shall be applied.
In the rule sample of `_match_domain_`, `*.example.com` and `test.com` are the domain names used for request matching. When the current domain name matches the configuration, the rule following shall be applied.
All rules shall be checked following the order of items in the `_rules_` fieldThe first matched rule will be applied. All remained will be ignored.

View File

@@ -0,0 +1,62 @@
apiVersion: v1
kind: Service
metadata:
name: backend
labels:
app: backend
service: backend
spec:
ports:
- name: http
port: 3000
targetPort: 3000
selector:
app: backend
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
replicas: 1
selector:
matchLabels:
app: backend
version: v1
template:
metadata:
labels:
app: backend
version: v1
spec:
containers:
- image: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/echoserver:v20221109-7ee2f3e
imagePullPolicy: IfNotPresent
name: backend
ports:
- containerPort: 3000
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-world
spec:
rules:
- http:
paths:
- pathType: Prefix
path: "/hello-world"
backend:
service:
name: backend
port:
number: 3000

View File

@@ -0,0 +1,21 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
higress.io/destination: service-provider-gray.DEFAULT-GROUP.public.nacos
nginx.ingress.kubernetes.io/canary: 'true'
nginx.ingress.kubernetes.io/canary-by-header: x-user-id
nginx.ingress.kubernetes.io/canary-by-header-value: '100'
name: echo-gray
namespace: default
spec:
rules:
- http:
paths:
- backend:
resource:
apiGroup: networking.higress.io
kind: McpBridge
name: default
path: /echo
pathType: Prefix

View File

@@ -0,0 +1,21 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
higress.io/destination: |
33% service-provider.DEFAULT-GROUP.public.nacos
33% service-provider-gray.DEFAULT-GROUP.public.nacos
34% bar-service.default.svc.cluster.local:5678
name: echo
namespace: default
spec:
rules:
- http:
paths:
- backend:
resource:
apiGroup: networking.higress.io
kind: McpBridge
name: default
path: /echo
pathType: Prefix

View File

@@ -0,0 +1,10 @@
apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
name: request-block
namespace: higress-system
spec:
url: oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins/request-block:1.0.0
defaultConfig:
block_urls:
- "swagger.html"

View File

@@ -0,0 +1,21 @@
apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
name: request-block
namespace: higress-system
spec:
url: oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins/request-block:1.0.0
defaultConfig:
block_urls:
- "swagger.html"
matchRules:
- ingress:
- default/foo
config:
block_bodys:
- "foo"
- ingress:
- default/bar
config:
block_bodys:
- "bar"

42
test/README.md Normal file
View File

@@ -0,0 +1,42 @@
# Higress E2E Tests
Higress e2e tests are mainly focusing on two parts for now:
+ Conformance Test for Ingress API
+ Conformance Test for Gateway API
## Ingress APIs Conformance Tests
Higress provides make target to run ingress api conformance tests: `make e2e-test`. It can be divided into below steps:
1. delete-cluster: checks if we have undeleted kind cluster.
2. create-cluster: create a new kind cluster.
3. kube-load-image: build a dev image of higress, and load it into kind cluster.
4. install-dev: install higress-controller with dev image, and latest higress-gateway, istiod with helm.
5. run-e2e-test:
1. Setup conformance suite, like define what conformance tests we want to run, in `e2e_test.go` / `higressTests Slice`. Each case we choose to open is difined in `test/ingress/conformance/tests`.
2. Prepare resources and install them into cluster, like backend services/deployments.
3. Load conformance tests we choose to open in `e2e_test.go` / `higressTests Slice`, and run them one by one, fail if it is not expected.
### How to write a test case
To add a new test case, you firstly need to add `xxx.go` and `xxx.yaml` in `test/ingress/conformance/tests`. `xxx.yaml` is the Ingress resource you need to apply in the cluster, `xxx.go` defines the HigressConformanceTest.
And after that, you should add your defined HigressConformanceTest to `e2e_test.go` / `higressTests Slice`.
You can understand it quickly just by looking at codes in `test/ingress/conformance/tests/httproute-simple-same-namespace.go` and `test/ingress/conformance/tests/httproute-simple-same-namespace.yaml`, and try to write one.
## Gateway APIs Conformance Tests
Gateway API Conformance tests are based on the suite provided by `kubernetes-sig/gateway-api`, we can reuse that,
and descide what conformance tests we need to open. Conformance tests of Gateway API.
This API covers a broad set of features and use cases and has been implemented widely.
This combination of both a large feature set and variety of implementations requires
clear conformance definitions and tests to ensure the API provides a consistent experience wherever it is used.
Gateway API includes a set of conformance tests. These create a series of Gateways and Routes with the specified
GatewayClass, and test that the implementation matches the API specification.
Each release contains a set of conformance tests, these will continue to expand as the API evolves.
Currently conformance tests cover the majority of Core capabilities in the standard channel, in addition to some Extended capabilities.

15
test/gateway/e2e.go Normal file
View File

@@ -0,0 +1,15 @@
// 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 gateway

15
test/gateway/e2e_test.go Normal file
View File

@@ -0,0 +1,15 @@
// 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 gateway

View File

@@ -0,0 +1,320 @@
# 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.
# This file contains the base resources that most conformance tests will rely
# on. This includes 3 namespaces along with Gateways, Services and Deployments
# that can be used as backends for routing traffic. The most important
# resources included are the Gateways (all in the higress-conformance-infra
# namespace):
# - same-namespace (only supports route in same ns)
# - all-namespaces (supports routes in all ns)
# - backend-namespaces (supports routes in ns with backend label)
apiVersion: v1
kind: Namespace
metadata:
name: higress-conformance-infra
labels:
higress-conformance: infra
---
apiVersion: v1
kind: Service
metadata:
name: infra-backend-v1
namespace: higress-conformance-infra
spec:
selector:
app: infra-backend-v1
ports:
- protocol: TCP
port: 8080
targetPort: 3000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: infra-backend-v1
namespace: higress-conformance-infra
labels:
app: infra-backend-v1
spec:
replicas: 2
selector:
matchLabels:
app: infra-backend-v1
template:
metadata:
labels:
app: infra-backend-v1
spec:
containers:
- name: infra-backend-v1
# From https://github.com/kubernetes-sigs/ingress-controller-conformance/tree/master/images/echoserver
image: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/echoserver:v20221109-7ee2f3e
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
resources:
requests:
cpu: 10m
---
apiVersion: v1
kind: Service
metadata:
name: infra-backend-v2
namespace: higress-conformance-infra
spec:
selector:
app: infra-backend-v2
ports:
- protocol: TCP
port: 8080
targetPort: 3000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: infra-backend-v2
namespace: higress-conformance-infra
labels:
app: infra-backend-v2
spec:
replicas: 2
selector:
matchLabels:
app: infra-backend-v2
template:
metadata:
labels:
app: infra-backend-v2
spec:
containers:
- name: infra-backend-v2
image: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/echoserver:v20221109-7ee2f3e
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
resources:
requests:
cpu: 10m
---
apiVersion: v1
kind: Service
metadata:
name: infra-backend-v3
namespace: higress-conformance-infra
spec:
selector:
app: infra-backend-v3
ports:
- protocol: TCP
port: 8080
targetPort: 3000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: infra-backend-v3
namespace: higress-conformance-infra
labels:
app: infra-backend-v3
spec:
replicas: 2
selector:
matchLabels:
app: infra-backend-v3
template:
metadata:
labels:
app: infra-backend-v3
spec:
containers:
- name: infra-backend-v3
image: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/echoserver:v20221109-7ee2f3e
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
resources:
requests:
cpu: 10m
---
apiVersion: v1
kind: Namespace
metadata:
name: higress-conformance-app-backend
labels:
higress-conformance: backend
---
apiVersion: v1
kind: Service
metadata:
name: app-backend-v1
namespace: higress-conformance-app-backend
spec:
selector:
app: app-backend-v1
ports:
- protocol: TCP
port: 8080
targetPort: 3000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-backend-v1
namespace: higress-conformance-app-backend
labels:
app: app-backend-v1
spec:
replicas: 2
selector:
matchLabels:
app: app-backend-v1
template:
metadata:
labels:
app: app-backend-v1
spec:
containers:
- name: app-backend-v1
image: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/echoserver:v20221109-7ee2f3e
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
resources:
requests:
cpu: 10m
---
apiVersion: v1
kind: Service
metadata:
name: app-backend-v2
namespace: higress-conformance-app-backend
spec:
selector:
app: app-backend-v2
ports:
- protocol: TCP
port: 8080
targetPort: 3000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-backend-v2
namespace: higress-conformance-app-backend
labels:
app: app-backend-v2
spec:
replicas: 2
selector:
matchLabels:
app: app-backend-v2
template:
metadata:
labels:
app: app-backend-v2
spec:
containers:
- name: app-backend-v2
image: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/echoserver:v20221109-7ee2f3e
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
resources:
requests:
cpu: 10m
---
apiVersion: v1
kind: Namespace
metadata:
name: higress-conformance-web-backend
labels:
higress-conformance: backend
---
apiVersion: v1
kind: Service
metadata:
name: web-backend
namespace: higress-conformance-web-backend
spec:
selector:
app: web-backend
ports:
- protocol: TCP
port: 8080
targetPort: 3000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-backend
namespace: higress-conformance-web-backend
labels:
app: web-backend
spec:
replicas: 2
selector:
matchLabels:
app: web-backend
template:
metadata:
labels:
app: web-backend
spec:
containers:
- name: web-backend
image: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/echoserver:v20221109-7ee2f3e
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
resources:
requests:
cpu: 10m

View File

@@ -0,0 +1,20 @@
// 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 ingress
import "embed"
//go:embed tests/* base/*
var Manifests embed.FS

View File

@@ -0,0 +1,43 @@
// 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 tests
import (
"testing"
"github.com/alibaba/higress/test/ingress/conformance/utils/http"
"github.com/alibaba/higress/test/ingress/conformance/utils/suite"
)
func init() {
HigressConformanceTests = append(HigressConformanceTests, HTTPRouteSimpleSameNamespace)
}
var HTTPRouteSimpleSameNamespace = suite.ConformanceTest{
ShortName: "HTTPRouteSimpleSameNamespace",
Description: "A single Ingress in the higress-conformance-infra namespace attaches to a Gateway in the same namespace",
Manifests: []string{"tests/httproute-simple-same-namespace.yaml"},
Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
t.Run("Simple HTTP request should reach infra-backend", func(t *testing.T) {
http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, suite.GatewayAddress, http.ExpectedResponse{
Request: http.Request{Path: "/hello-world"},
Response: http.Response{StatusCode: 200},
Backend: "infra-backend-v1",
Namespace: "higress-conformance-infra",
})
})
},
}

View File

@@ -0,0 +1,30 @@
# 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.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: higress-conformance-infra-test
namespace: higress-conformance-infra
spec:
rules:
- http:
paths:
- pathType: Prefix
path: "/hello-world"
backend:
service:
name: infra-backend-v1
port:
number: 8080

View File

@@ -0,0 +1,19 @@
// 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 tests
import "github.com/alibaba/higress/test/ingress/conformance/utils/suite"
var HigressConformanceTests []suite.ConformanceTest

View File

@@ -0,0 +1,133 @@
// 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 config
import "time"
type TimeoutConfig struct {
// CreateTimeout represents the maximum time for a Kubernetes object to be created.
// Max value for conformant implementation: None
CreateTimeout time.Duration
// DeleteTimeout represents the maximum time for a Kubernetes object to be deleted.
// Max value for conformant implementation: None
DeleteTimeout time.Duration
// GetTimeout represents the maximum time to get a Kubernetes object.
// Max value for conformant implementation: None
GetTimeout time.Duration
// GatewayMustHaveAddress represents the maximum time for at least one IP Address has been set in the status of a Gateway.
// Max value for conformant implementation: None
GatewayMustHaveAddress time.Duration
// GatewayStatusMustHaveListeners represents the maximum time for a Gateway to have listeners in status that match the expected listeners.
// Max value for conformant implementation: None
GatewayStatusMustHaveListeners time.Duration
// GWCMustBeAccepted represents the maximum time for a GatewayClass to have an Accepted condition set to true.
// Max value for conformant implementation: None
GWCMustBeAccepted time.Duration
// HTTPRouteMustNotHaveParents represents the maximum time for an HTTPRoute to have either no parents or a single parent that is not accepted.
// Max value for conformant implementation: None
HTTPRouteMustNotHaveParents time.Duration
// HTTPRouteMustHaveCondition represents the maximum time for an HTTPRoute to have the supplied Condition.
// Max value for conformant implementation: None
HTTPRouteMustHaveCondition time.Duration
// HTTPRouteMustHaveParents represents the maximum time for an HTTPRoute to have parents in status that match the expected parents.
// Max value for conformant implementation: None
HTTPRouteMustHaveParents time.Duration
// ManifestFetchTimeout represents the maximum time for getting content from a https:// URL.
// Max value for conformant implementation: None
ManifestFetchTimeout time.Duration
// MaxTimeToConsistency is the maximum time for requiredConsecutiveSuccesses (default 3) requests to succeed in a row before failing the test.
// Max value for conformant implementation: 30 seconds
MaxTimeToConsistency time.Duration
// NamespacesMustBeReady represents the maximum time for all Pods and Gateways in a namespaces to be marked as ready.
// Max value for conformant implementation: None
NamespacesMustBeReady time.Duration
// RequestTimeout represents the maximum time for making an HTTP Request with the roundtripper.
// Max value for conformant implementation: None
RequestTimeout time.Duration
}
// DefaultTimeoutConfig populates a TimeoutConfig with the default values.
func DefaultTimeoutConfig() TimeoutConfig {
return TimeoutConfig{
CreateTimeout: 60 * time.Second,
DeleteTimeout: 10 * time.Second,
GetTimeout: 10 * time.Second,
GatewayMustHaveAddress: 180 * time.Second,
GatewayStatusMustHaveListeners: 60 * time.Second,
GWCMustBeAccepted: 180 * time.Second,
HTTPRouteMustNotHaveParents: 60 * time.Second,
HTTPRouteMustHaveCondition: 60 * time.Second,
HTTPRouteMustHaveParents: 60 * time.Second,
ManifestFetchTimeout: 10 * time.Second,
MaxTimeToConsistency: 30 * time.Second,
NamespacesMustBeReady: 300 * time.Second,
RequestTimeout: 10 * time.Second,
}
}
func SetupTimeoutConfig(timeoutConfig *TimeoutConfig) {
defaultTimeoutConfig := DefaultTimeoutConfig()
if timeoutConfig.CreateTimeout == 0 {
timeoutConfig.CreateTimeout = defaultTimeoutConfig.CreateTimeout
}
if timeoutConfig.DeleteTimeout == 0 {
timeoutConfig.DeleteTimeout = defaultTimeoutConfig.DeleteTimeout
}
if timeoutConfig.GetTimeout == 0 {
timeoutConfig.GetTimeout = defaultTimeoutConfig.GetTimeout
}
if timeoutConfig.GatewayMustHaveAddress == 0 {
timeoutConfig.GatewayMustHaveAddress = defaultTimeoutConfig.GatewayMustHaveAddress
}
if timeoutConfig.GatewayStatusMustHaveListeners == 0 {
timeoutConfig.GatewayStatusMustHaveListeners = defaultTimeoutConfig.GatewayStatusMustHaveListeners
}
if timeoutConfig.GWCMustBeAccepted == 0 {
timeoutConfig.GWCMustBeAccepted = defaultTimeoutConfig.GWCMustBeAccepted
}
if timeoutConfig.HTTPRouteMustNotHaveParents == 0 {
timeoutConfig.HTTPRouteMustNotHaveParents = defaultTimeoutConfig.HTTPRouteMustNotHaveParents
}
if timeoutConfig.HTTPRouteMustHaveCondition == 0 {
timeoutConfig.HTTPRouteMustHaveCondition = defaultTimeoutConfig.HTTPRouteMustHaveCondition
}
if timeoutConfig.HTTPRouteMustHaveParents == 0 {
timeoutConfig.HTTPRouteMustHaveParents = defaultTimeoutConfig.HTTPRouteMustHaveParents
}
if timeoutConfig.ManifestFetchTimeout == 0 {
timeoutConfig.ManifestFetchTimeout = defaultTimeoutConfig.ManifestFetchTimeout
}
if timeoutConfig.MaxTimeToConsistency == 0 {
timeoutConfig.MaxTimeToConsistency = defaultTimeoutConfig.MaxTimeToConsistency
}
if timeoutConfig.NamespacesMustBeReady == 0 {
timeoutConfig.NamespacesMustBeReady = defaultTimeoutConfig.NamespacesMustBeReady
}
if timeoutConfig.RequestTimeout == 0 {
timeoutConfig.RequestTimeout = defaultTimeoutConfig.RequestTimeout
}
}

View File

@@ -0,0 +1,27 @@
// 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 flags
import (
"flag"
)
var (
IngressClassName = flag.String("ingress-class", "higress", "Name of IngressClass to use for tests")
ShowDebug = flag.Bool("debug", false, "Whether to print debug logs")
CleanupBaseResources = flag.Bool("cleanup-base-resources", true, "Whether to cleanup base test resources after the run")
SupportedFeatures = flag.String("supported-features", "", "Supported features included in conformance tests suites")
ExemptFeatures = flag.String("exempt-features", "", "Exempt Features excluded from conformance tests suites")
)

View File

@@ -0,0 +1,354 @@
// 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 http
import (
"fmt"
"net/url"
"strings"
"testing"
"time"
"github.com/alibaba/higress/test/ingress/conformance/utils/config"
"github.com/alibaba/higress/test/ingress/conformance/utils/roundtripper"
)
// ExpectedResponse defines the response expected for a given request.
type ExpectedResponse struct {
// Request defines the request to make.
Request Request
// ExpectedRequest defines the request that
// is expected to arrive at the backend. If
// not specified, the backend request will be
// expected to match Request.
ExpectedRequest *ExpectedRequest
RedirectRequest *roundtripper.RedirectRequest
// BackendSetResponseHeaders is a set of headers
// the echoserver should set in its response.
BackendSetResponseHeaders map[string]string
// Response defines what response the test case
// should receive.
Response Response
Backend string
Namespace string
// User Given TestCase name
TestCaseName string
}
// Request can be used as both the request to make and a means to verify
// that echoserver received the expected request. Note that multiple header
// values can be provided, as a comma-separated value.
type Request struct {
Host string
Method string
Path string
Headers map[string]string
UnfollowRedirect bool
}
// ExpectedRequest defines expected properties of a request that reaches a backend.
type ExpectedRequest struct {
Request
// AbsentHeaders are names of headers that are expected
// *not* to be present on the request.
AbsentHeaders []string
}
// Response defines expected properties of a response from a backend.
type Response struct {
StatusCode int
Headers map[string]string
AbsentHeaders []string
}
// requiredConsecutiveSuccesses is the number of requests that must succeed in a row
// for MakeRequestAndExpectEventuallyConsistentResponse to consider the response "consistent"
// before making additional assertions on the response body. If this number is not reached within
// maxTimeToConsistency, the test will fail.
const requiredConsecutiveSuccesses = 3
// MakeRequestAndExpectEventuallyConsistentResponse makes a request with the given parameters,
// understanding that the request may fail for some amount of time.
//
// Once the request succeeds consistently with the response having the expected status code, make
// additional assertions on the response body using the provided ExpectedResponse.
func MakeRequestAndExpectEventuallyConsistentResponse(t *testing.T, r roundtripper.RoundTripper, timeoutConfig config.TimeoutConfig, gwAddr string, expected ExpectedResponse) {
t.Helper()
if expected.Request.Method == "" {
expected.Request.Method = "GET"
}
if expected.Response.StatusCode == 0 {
expected.Response.StatusCode = 200
}
t.Logf("Making %s request to http://%s%s", expected.Request.Method, gwAddr, expected.Request.Path)
path, query, _ := strings.Cut(expected.Request.Path, "?")
req := roundtripper.Request{
Method: expected.Request.Method,
Host: expected.Request.Host,
URL: url.URL{Scheme: "http", Host: gwAddr, Path: path, RawQuery: query},
Protocol: "HTTP",
Headers: map[string][]string{},
UnfollowRedirect: expected.Request.UnfollowRedirect,
}
if expected.Request.Headers != nil {
for name, value := range expected.Request.Headers {
req.Headers[name] = []string{value}
}
}
backendSetHeaders := []string{}
for name, val := range expected.BackendSetResponseHeaders {
backendSetHeaders = append(backendSetHeaders, name+":"+val)
}
req.Headers["X-Echo-Set-Header"] = []string{strings.Join(backendSetHeaders, ",")}
WaitForConsistentResponse(t, r, req, expected, requiredConsecutiveSuccesses, timeoutConfig.MaxTimeToConsistency)
}
// awaitConvergence runs the given function until it returns 'true' `threshold` times in a row.
// Each failed attempt has a 1s delay; successful attempts have no delay.
func awaitConvergence(t *testing.T, threshold int, maxTimeToConsistency time.Duration, fn func(elapsed time.Duration) bool) {
successes := 0
attempts := 0
start := time.Now()
to := time.After(maxTimeToConsistency)
delay := time.Second
for {
select {
case <-to:
t.Fatalf("timeout while waiting after %d attempts", attempts)
default:
}
completed := fn(time.Now().Sub(start))
attempts++
if completed {
successes++
if successes >= threshold {
return
}
// Skip delay if we have a success
continue
}
successes = 0
select {
// Capture the overall timeout
case <-to:
t.Fatalf("timeout while waiting after %d attempts, %d/%d sucessess", attempts, successes, threshold)
// And the per-try delay
case <-time.After(delay):
}
}
}
// WaitForConsistentResponse repeats the provided request until it completes with a response having
// the expected response consistently. The provided threshold determines how many times in
// a row this must occur to be considered "consistent".
func WaitForConsistentResponse(t *testing.T, r roundtripper.RoundTripper, req roundtripper.Request, expected ExpectedResponse, threshold int, maxTimeToConsistency time.Duration) {
awaitConvergence(t, threshold, maxTimeToConsistency, func(elapsed time.Duration) bool {
cReq, cRes, err := r.CaptureRoundTrip(req)
if err != nil {
t.Logf("Request failed, not ready yet: %v (after %v)", err.Error(), elapsed)
return false
}
if err := CompareRequest(&req, cReq, cRes, expected); err != nil {
t.Logf("Response expectation failed for request: %v not ready yet: %v (after %v)", req, err, elapsed)
return false
}
return true
})
t.Logf("Request passed")
}
func CompareRequest(req *roundtripper.Request, cReq *roundtripper.CapturedRequest, cRes *roundtripper.CapturedResponse, expected ExpectedResponse) error {
if expected.Response.StatusCode != cRes.StatusCode {
return fmt.Errorf("expected status code to be %d, got %d", expected.Response.StatusCode, cRes.StatusCode)
}
if cRes.StatusCode == 200 {
// The request expected to arrive at the backend is
// the same as the request made, unless otherwise
// specified.
if expected.ExpectedRequest == nil {
expected.ExpectedRequest = &ExpectedRequest{Request: expected.Request}
}
if expected.ExpectedRequest.Method == "" {
expected.ExpectedRequest.Method = "GET"
}
if expected.ExpectedRequest.Host != "" && expected.ExpectedRequest.Host != cReq.Host {
return fmt.Errorf("expected host to be %s, got %s", expected.ExpectedRequest.Host, cReq.Host)
}
if expected.ExpectedRequest.Path != cReq.Path {
return fmt.Errorf("expected path to be %s, got %s", expected.ExpectedRequest.Path, cReq.Path)
}
if expected.ExpectedRequest.Method != cReq.Method {
return fmt.Errorf("expected method to be %s, got %s", expected.ExpectedRequest.Method, cReq.Method)
}
if expected.Namespace != cReq.Namespace {
return fmt.Errorf("expected namespace to be %s, got %s", expected.Namespace, cReq.Namespace)
}
if expected.ExpectedRequest.Headers != nil {
if cReq.Headers == nil {
return fmt.Errorf("no headers captured, expected %v", len(expected.ExpectedRequest.Headers))
}
for name, val := range cReq.Headers {
cReq.Headers[strings.ToLower(name)] = val
}
for name, expectedVal := range expected.ExpectedRequest.Headers {
actualVal, ok := cReq.Headers[strings.ToLower(name)]
if !ok {
return fmt.Errorf("expected %s header to be set, actual headers: %v", name, cReq.Headers)
} else if strings.Join(actualVal, ",") != expectedVal {
return fmt.Errorf("expected %s header to be set to %s, got %s", name, expectedVal, strings.Join(actualVal, ","))
}
}
}
if expected.Response.Headers != nil {
if cRes.Headers == nil {
return fmt.Errorf("no headers captured, expected %v", len(expected.ExpectedRequest.Headers))
}
for name, val := range cRes.Headers {
cRes.Headers[strings.ToLower(name)] = val
}
for name, expectedVal := range expected.Response.Headers {
actualVal, ok := cRes.Headers[strings.ToLower(name)]
if !ok {
return fmt.Errorf("expected %s header to be set, actual headers: %v", name, cRes.Headers)
} else if strings.Join(actualVal, ",") != expectedVal {
return fmt.Errorf("expected %s header to be set to %s, got %s", name, expectedVal, strings.Join(actualVal, ","))
}
}
}
if len(expected.Response.AbsentHeaders) > 0 {
for name, val := range cRes.Headers {
cRes.Headers[strings.ToLower(name)] = val
}
for _, name := range expected.Response.AbsentHeaders {
val, ok := cRes.Headers[strings.ToLower(name)]
if ok {
return fmt.Errorf("expected %s header to not be set, got %s", name, val)
}
}
}
// Verify that headers expected *not* to be present on the
// request are actually not present.
if len(expected.ExpectedRequest.AbsentHeaders) > 0 {
for name, val := range cReq.Headers {
cReq.Headers[strings.ToLower(name)] = val
}
for _, name := range expected.ExpectedRequest.AbsentHeaders {
val, ok := cReq.Headers[strings.ToLower(name)]
if ok {
return fmt.Errorf("expected %s header to not be set, got %s", name, val)
}
}
}
if !strings.HasPrefix(cReq.Pod, expected.Backend) {
return fmt.Errorf("expected pod name to start with %s, got %s", expected.Backend, cReq.Pod)
}
} else if roundtripper.IsRedirect(cRes.StatusCode) {
if expected.RedirectRequest == nil {
return nil
}
setRedirectRequestDefaults(req, cRes, &expected)
if expected.RedirectRequest.Host != cRes.RedirectRequest.Host {
return fmt.Errorf("expected redirected hostname to be %s, got %s", expected.RedirectRequest.Host, cRes.RedirectRequest.Host)
}
if expected.RedirectRequest.Port != cRes.RedirectRequest.Port {
return fmt.Errorf("expected redirected port to be %s, got %s", expected.RedirectRequest.Port, cRes.RedirectRequest.Port)
}
if expected.RedirectRequest.Scheme != cRes.RedirectRequest.Scheme {
return fmt.Errorf("expected redirected scheme to be %s, got %s", expected.RedirectRequest.Scheme, cRes.RedirectRequest.Scheme)
}
if expected.RedirectRequest.Path != cRes.RedirectRequest.Path {
return fmt.Errorf("expected redirected path to be %s, got %s", expected.RedirectRequest.Path, cRes.RedirectRequest.Path)
}
}
return nil
}
// Get User-defined test case name or generate from expected response to a given request.
func (er *ExpectedResponse) GetTestCaseName(i int) string {
// If TestCase name is provided then use that or else generate one.
if er.TestCaseName != "" {
return er.TestCaseName
}
headerStr := ""
reqStr := ""
if er.Request.Headers != nil {
headerStr = " with headers"
}
reqStr = fmt.Sprintf("%d request to '%s%s'%s", i, er.Request.Host, er.Request.Path, headerStr)
if er.Backend != "" {
return fmt.Sprintf("%s should go to %s", reqStr, er.Backend)
}
return fmt.Sprintf("%s should receive a %d", reqStr, er.Response.StatusCode)
}
func setRedirectRequestDefaults(req *roundtripper.Request, cRes *roundtripper.CapturedResponse, expected *ExpectedResponse) {
// If the expected host is nil it means we do not test host redirect.
// In that case we are setting it to the one we got from the response because we do not know the ip/host of the gateway.
if expected.RedirectRequest.Host == "" {
expected.RedirectRequest.Host = cRes.RedirectRequest.Host
}
if expected.RedirectRequest.Port == "" {
expected.RedirectRequest.Port = req.URL.Port()
}
if expected.RedirectRequest.Scheme == "" {
expected.RedirectRequest.Scheme = req.URL.Scheme
}
if expected.RedirectRequest.Path == "" {
expected.RedirectRequest.Path = req.URL.Path
}
}

View File

@@ -0,0 +1,229 @@
// 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 kubernetes
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"net/http"
"strings"
"testing"
ingress "github.com/alibaba/higress/test/ingress/conformance"
"github.com/stretchr/testify/require"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/yaml"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/alibaba/higress/test/ingress/conformance/utils/config"
)
// Applier prepares manifests depending on the available options and applies
// them to the Kubernetes cluster.
type Applier struct {
NamespaceLabels map[string]string
// ValidUniqueListenerPorts maps each listener port of each Gateway in the
// manifests to a valid, unique port. There must be as many
// ValidUniqueListenerPorts as there are listeners in the set of manifests.
// For example, given two Gateways, each with 2 listeners, there should be
// four ValidUniqueListenerPorts.
// If empty or nil, ports are not modified.
ValidUniqueListenerPorts []int
// IngressClass will be used as the spec.gatewayClassName when applying Gateway resources
IngressClass string
// ControllerName will be used as the spec.controllerName when applying GatewayClass resources
ControllerName string
}
// prepareNamespace adjusts the Namespace labels.
func prepareNamespace(t *testing.T, uObj *unstructured.Unstructured, namespaceLabels map[string]string) {
labels, _, err := unstructured.NestedStringMap(uObj.Object, "metadata", "labels")
require.NoErrorf(t, err, "error getting labels on Namespace %s", uObj.GetName())
for k, v := range namespaceLabels {
if labels == nil {
labels = map[string]string{}
}
labels[k] = v
}
// SetNestedStringMap converts nil to an empty map
if labels != nil {
err = unstructured.SetNestedStringMap(uObj.Object, labels, "metadata", "labels")
}
require.NoErrorf(t, err, "error setting labels on Namespace %s", uObj.GetName())
}
// prepareResources uses the options from an Applier to tweak resources given by
// a set of manifests.
func (a Applier) prepareResources(t *testing.T, decoder *yaml.YAMLOrJSONDecoder) ([]unstructured.Unstructured, error) {
var resources []unstructured.Unstructured
for {
uObj := unstructured.Unstructured{}
if err := decoder.Decode(&uObj); err != nil {
if errors.Is(err, io.EOF) {
break
}
return nil, err
}
if len(uObj.Object) == 0 {
continue
}
if uObj.GetKind() == "Namespace" && uObj.GetObjectKind().GroupVersionKind().Group == "" {
prepareNamespace(t, &uObj, a.NamespaceLabels)
}
resources = append(resources, uObj)
}
return resources, nil
}
func (a Applier) MustApplyObjectsWithCleanup(t *testing.T, c client.Client, timeoutConfig config.TimeoutConfig, resources []client.Object, cleanup bool) {
for _, resource := range resources {
resource := resource
ctx, cancel := context.WithTimeout(context.Background(), timeoutConfig.CreateTimeout)
defer cancel()
t.Logf("Creating %s %s", resource.GetName(), resource.GetObjectKind().GroupVersionKind().Kind)
err := c.Create(ctx, resource)
if err != nil {
if !apierrors.IsAlreadyExists(err) {
require.NoError(t, err, "error creating resource")
}
}
if cleanup {
t.Cleanup(func() {
ctx, cancel = context.WithTimeout(context.Background(), timeoutConfig.DeleteTimeout)
defer cancel()
t.Logf("Deleting %s %s", resource.GetName(), resource.GetObjectKind().GroupVersionKind().Kind)
err = c.Delete(ctx, resource)
require.NoErrorf(t, err, "error deleting resource")
})
}
}
}
// MustApplyWithCleanup creates or updates Kubernetes resources defined with the
// provided YAML file and registers a cleanup function for resources it created.
// Note that this does not remove resources that already existed in the cluster.
func (a Applier) MustApplyWithCleanup(t *testing.T, c client.Client, timeoutConfig config.TimeoutConfig, location string, cleanup bool) {
data, err := getContentsFromPathOrURL(location, timeoutConfig)
require.NoError(t, err)
decoder := yaml.NewYAMLOrJSONDecoder(data, 4096)
resources, err := a.prepareResources(t, decoder)
if err != nil {
t.Logf("manifest: %s", data.String())
require.NoErrorf(t, err, "error parsing manifest")
}
for i := range resources {
uObj := &resources[i]
ctx, cancel := context.WithTimeout(context.Background(), timeoutConfig.CreateTimeout)
defer cancel()
namespacedName := types.NamespacedName{Namespace: uObj.GetNamespace(), Name: uObj.GetName()}
fetchedObj := uObj.DeepCopy()
err := c.Get(ctx, namespacedName, fetchedObj)
if err != nil {
if !apierrors.IsNotFound(err) {
require.NoErrorf(t, err, "error getting resource")
}
t.Logf("Creating %s %s", uObj.GetName(), uObj.GetKind())
err = c.Create(ctx, uObj)
require.NoErrorf(t, err, "error creating resource")
if cleanup {
t.Cleanup(func() {
ctx, cancel = context.WithTimeout(context.Background(), timeoutConfig.DeleteTimeout)
defer cancel()
t.Logf("Deleting %s %s", uObj.GetName(), uObj.GetKind())
err = c.Delete(ctx, uObj)
require.NoErrorf(t, err, "error deleting resource")
})
}
continue
}
uObj.SetResourceVersion(fetchedObj.GetResourceVersion())
t.Logf("Updating %s %s", uObj.GetName(), uObj.GetKind())
err = c.Update(ctx, uObj)
if cleanup {
t.Cleanup(func() {
ctx, cancel = context.WithTimeout(context.Background(), timeoutConfig.DeleteTimeout)
defer cancel()
t.Logf("Deleting %s %s", uObj.GetName(), uObj.GetKind())
err = c.Delete(ctx, uObj)
require.NoErrorf(t, err, "error deleting resource")
})
}
require.NoErrorf(t, err, "error updating resource")
}
}
// getContentsFromPathOrURL takes a string that can either be a local file
// path or an https:// URL to YAML manifests and provides the contents.
func getContentsFromPathOrURL(location string, timeoutConfig config.TimeoutConfig) (*bytes.Buffer, error) {
if strings.HasPrefix(location, "http://") {
return nil, fmt.Errorf("data can't be retrieved from %s: http is not supported, use https", location)
} else if strings.HasPrefix(location, "https://") {
ctx, cancel := context.WithTimeout(context.Background(), timeoutConfig.ManifestFetchTimeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, location, nil)
if err != nil {
return nil, err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
manifests := new(bytes.Buffer)
count, err := manifests.ReadFrom(resp.Body)
if err != nil {
return nil, err
}
if resp.ContentLength != -1 && count != resp.ContentLength {
return nil, fmt.Errorf("received %d bytes from %s, expected %d", count, location, resp.ContentLength)
}
return manifests, nil
}
b, err := ingress.Manifests.ReadFile(location)
if err != nil {
return nil, err
}
return bytes.NewBuffer(b), nil
}

Some files were not shown because too many files have changed in this diff Show More