Compare commits

...

165 Commits

Author SHA1 Message Date
澄潭
1c415c60c3 rel: Release v1.4.2 (#1159) 2024-07-26 13:55:03 +08:00
澄潭
59acb61926 Update Makefile.core.mk 2024-07-26 13:50:16 +08:00
澄潭
29079f4e2a Support set buffer limit (#1153) 2024-07-25 20:42:39 +08:00
澄潭
95edce024d support custom trace span tag (#1156) 2024-07-25 20:42:09 +08:00
Kent Dong
b6d07a157c feat: Always buffer request body in ai-proxy plugin (#1155) 2024-07-25 19:35:39 +08:00
澄潭
10569f49ae support keep original auth header (#1151) 2024-07-24 19:31:38 +08:00
Jun
2a588c99c7 fix: add full push when higress-https configmap updated and fix certmagic storage (#1105) 2024-07-24 19:30:40 +08:00
Kent Dong
0cfef34bff feat: Support fallback route in ai-proxy plugin (#1123) 2024-07-24 19:25:32 +08:00
rinfx
5c2b5d5750 potential bug fix (#1141) 2024-07-24 19:24:47 +08:00
rinfx
8f483518a9 support take effect on api level (#1150) 2024-07-24 19:23:55 +08:00
Kent Dong
f6ee4ed166 fix: Bypass the response body processing in ai-proxy if it is returned internally (#1149) 2024-07-24 16:18:00 +08:00
Kent Dong
9a9e924037 feat: Make higress-core and higress-gateway as the default container (#1144) 2024-07-24 11:25:16 +08:00
jiaomh
e7d66f691f chore: Update multiple dependencies to the latest version (#1143) 2024-07-23 11:48:44 +08:00
rinfx
8c48fcb423 update template decorator (#1142) 2024-07-22 17:04:55 +08:00
007gzs
ef31e09310 feat: add rust demo plugin request block (#1091)
Co-authored-by: Yi <lynskylate@gmail.com>
2024-07-22 15:49:06 +08:00
韩贤涛
c0f2cafdc8 feat: support ext_auth wasmplugin (#1103) 2024-07-17 15:30:32 +08:00
Kent Dong
d5a9ff3a98 fix: Fix possible type-casting related panics in ai-proxy plugin (#1127) 2024-07-16 18:38:43 +08:00
Kent Dong
f069ad5b0d feat: Add statusCodeDetails info when returning response in Wasm plugins directly (#1116) 2024-07-16 09:52:46 +08:00
xu.zhao
85219b6c53 fix: controller has no right to watch deployment (#1089)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2024-07-15 16:34:24 +08:00
mamba
5041277be3 feat: 🎸 add frontend gray plugin (#1120)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2024-07-15 15:47:04 +08:00
rinfx
c00c8827f9 support service-level match config (#1112) 2024-07-15 14:00:02 +08:00
rinfx
46218058d1 token-ratelimit crash bugfix (#1119) 2024-07-12 15:05:15 +08:00
Kent Dong
5306385e6b feat: Support loading custom parameters in build-and-push-wasm-plugin-image.yaml (#1118) 2024-07-12 14:23:12 +08:00
Se7en
4e881fdd3f doc: update cluster-key-rate-limit doc (#1113)
Co-authored-by: 澄潭 <zty98751@alibaba-inc.com>
Co-authored-by: Kent Dong <ch3cho@qq.com>
2024-07-11 17:31:14 +08:00
Kent Dong
59aa3b5488 fix: Use "controller.name" to refer the controller service in higress-config (#1108) 2024-07-11 16:14:16 +08:00
Kent Dong
c40cf85aad fix: Fix the incorrect image name used in build-and-push-wasm-plugin-image.yaml (#1109) 2024-07-10 13:51:13 +08:00
Kent Dong
7c749b864c fix: Fix some bugs in build-and-push-wasm-plugin-image.yaml (#1107) 2024-07-10 13:41:58 +08:00
Yiiong
74ddbf02f6 feat:add build-and-push-wasm-plugin-image.yaml (#1069)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2024-07-08 21:44:58 +08:00
zzjin
60c56a16ab Support CredentialConfig.TLSSecret with namespace. Resolve: #1066 (#1095)
Signed-off-by: zzjin <tczzjin@gmail.com>
2024-07-08 19:49:51 +08:00
Kent Dong
5a2c6835f7 feat: Support embeddings API for Qwen in the ai-proxy plugin (#1079) 2024-07-08 19:37:08 +08:00
Kent Dong
12a5612450 feat: Support model prefix mapping in ai-proxy (#1097) 2024-07-08 19:33:08 +08:00
nohup
b9f5c4d1f2 feat: support Cloudflare Workers AI (#1068)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2024-07-08 19:27:11 +08:00
Jun
d7bdcbd026 fix priorityClassName missed (#1096) 2024-07-08 19:26:08 +08:00
野生程序员
dd284d1f24 feat: loadBalancerClass (#1071) 2024-07-08 10:58:33 +08:00
jiaomh
a7ee523c98 Update test/README.md (#1098) 2024-07-07 10:06:32 +08:00
Kent Dong
4bbfb131ee feat: Load 3rd-party images from higress image repo (#1067) 2024-07-04 20:14:00 +08:00
Se7en
6fd71f9749 fix: prometheus port (#1076) 2024-07-03 13:46:32 +08:00
pepesi
e0159f501a fix jwt-auth plugin claims_to_headers failed (#1075) 2024-07-03 10:11:17 +08:00
Kent Dong
56226d5052 feat: Create an IngressClass resource in the helm chart (#1072) 2024-07-02 21:22:00 +08:00
pepesi
086a9cc973 fixed ai-statistics plugin statistics error (#1060) 2024-07-02 20:35:12 +08:00
Tao Jikun
e389313aa3 feat: update doc for running Ingress API conformance tests (#1065)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2024-06-27 14:55:10 +08:00
澄潭
f64c601264 compatiable with openai sdk (#1061)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2024-06-27 09:30:52 +08:00
co63oc
9c6ea109f8 Fix typos (#1053) 2024-06-26 19:47:39 +08:00
yy
4ca2d23404 feat: helm charts support installing gateway in daemonset mod. (#1054) 2024-06-26 19:47:20 +08:00
co63oc
0ce52de59b Fix typos (#1050) 2024-06-22 16:22:03 +08:00
澄潭
81e459da01 Update Makefile.core.mk 2024-06-19 17:40:22 +08:00
澄潭
63539ca15c rel:Release v1.4.1 (#1048) 2024-06-19 17:12:51 +08:00
澄潭
1eea75f130 Update Makefile.core.mk 2024-06-19 17:00:06 +08:00
The Wind
d333656cc3 feat: support summary output for route/cluster/listener in hgctl gateway-config command (#995) (#996) 2024-06-19 13:55:59 +08:00
Se7en
51dca7055a feat: support claude ai model (#969)
Signed-off-by: chengzw <chengzw258@163.com>
2024-06-19 13:53:21 +08:00
Chi Kai
ab1bc0a73a feat: support stepfun model (#1012)
Co-authored-by: Kent Dong <kentstl@163.com>
2024-06-19 13:51:02 +08:00
Kent Dong
ffee7dc5ea fix: Accommodate the incomplete function name in the initial event from Qwen (#1045) 2024-06-19 13:48:20 +08:00
rinfx
1ea87f0e7a add plugin: ai-token-ratelimit (#1015) 2024-06-19 13:46:59 +08:00
rinfx
7164653446 ai rag updates (#1046) 2024-06-19 13:46:17 +08:00
澄潭
2a1a391054 Optimize the effectiveness speed of xds and add AI-related metric tags (#1047) 2024-06-19 13:45:42 +08:00
rinfx
0785d4aac4 add plugin: ai-statistics (#1011) 2024-06-18 17:53:04 +08:00
rinfx
4ca4bec2b5 add plugin: ai-transformer (#1035) 2024-06-18 17:51:38 +08:00
rinfx
174350d3fb add plugin: ai-rag (#1038) 2024-06-17 15:37:00 +08:00
rinfx
0380cb03d3 add plugin: ai-prompt-template (#1019) 2024-06-17 15:33:05 +08:00
rinfx
15d9f76ff9 add plugin: ai-prompt-decorator (#1021) 2024-06-17 15:31:34 +08:00
rinfx
5f15017963 add plugin: ai-security-guard (#1034) 2024-06-17 10:41:46 +08:00
韩贤涛
634de3f7f8 feat: cluster key rate limit enhancement (#1036) 2024-06-17 10:37:03 +08:00
韩贤涛
12cc44b324 feat: cluster key rate limit (#1002) 2024-06-12 14:51:46 +08:00
韩贤涛
d53c713561 feat: support minimax ai model (#1033) 2024-06-09 21:01:31 +08:00
澄潭
5acc6f73b2 fix prometheus stats (#1031) 2024-06-07 17:24:19 +08:00
韩贤涛
2db0b60a98 feat: support baidu ernie bot ai model (#1024)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2024-06-06 18:19:55 +08:00
nash5
c6e3db95e0 feature: add hunyuan llm support for plugins/ai-proxy (#1018)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2024-06-06 18:11:51 +08:00
Ink33
ed976c6d06 feat(plugin): implement golang version of plugin jwt-auth (#743)
Signed-off-by: Ink33 <Ink33@smlk.org>
2024-06-06 10:22:51 +08:00
Jun
6a40d83ec0 enable automatichttps (#1026) 2024-06-04 09:35:30 +08:00
Jun
2807ddfbb7 Feat https fallback (#1020) 2024-05-31 14:04:02 +08:00
Kent Dong
6e4ade05a8 doc: Add instructions of how to build ai-proxy plugin (#1005) 2024-05-31 13:59:43 +08:00
Kent Dong
bdd050b926 fix: Fix tool_calls compatibility issues with LobeChat (#1009) 2024-05-30 19:20:48 +08:00
澄潭
38ddc49360 Optimize the method for judging streaming responses (#1017) 2024-05-30 17:50:28 +08:00
澄潭
26ec0d3d55 Update manifests.yaml 2024-05-30 10:42:54 +08:00
澄潭
909f8bc719 Update main.go 2024-05-30 10:26:52 +08:00
澄潭
863d0e5872 Update main.go 2024-05-30 09:53:48 +08:00
澄潭
3e7a63bd9b rel: Release v1.4.0 (#1014) 2024-05-29 21:20:50 +08:00
澄潭
206152daa0 Update Makefile.core.mk 2024-05-29 21:16:09 +08:00
澄潭
812edf1490 add ai cache plugin (#1010) 2024-05-29 21:10:22 +08:00
澄潭
b00f79f3af optimize mcp cds (#1013) 2024-05-29 19:43:40 +08:00
澄潭
ed05da13f4 Update manifests.yaml 2024-05-29 19:25:03 +08:00
澄潭
53bccf89f4 Update Makefile.core.mk 2024-05-28 14:05:22 +08:00
Yang Beining
51b9d9ec4b feat: Add the ZhipuAI (ChatGLM) provider to the ai-proxy wasm plugin #950 (#1007)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2024-05-28 11:29:36 +08:00
Yifan Gao
50f79c9099 feat: support ollama ai model (#1001)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2024-05-28 10:55:59 +08:00
澄潭
93966bf14b fix vs merge (#1006) 2024-05-27 23:05:39 +08:00
澄潭
ffa690994b fix wasm recover (#1003) 2024-05-27 18:08:43 +08:00
澄潭
ca1ad1dc73 Fixed the issue where an empty string system prompt would be set when enabling file id. (#999) 2024-05-24 16:27:02 +08:00
澄潭
e09edff827 Fix the issue with multiple system prompts when using qwen-long file id mode. (#994)
Signed-off-by: johnlanni <zty98751@alibaba-inc.com>
2024-05-24 14:43:34 +08:00
Ink33
2fee28d4e8 feat: run the specific e2e test with environment variable (#975)
Signed-off-by: Ink33 <Ink33@smlk.org>
2024-05-23 17:36:24 +08:00
澄潭
78418b50ff Update Makefile.core.mk 2024-05-23 14:27:19 +08:00
Kent Dong
7fcb608fce fix: Fix the incorrect usage of DisableReroute (#991) 2024-05-23 09:35:57 +08:00
goooogoooo
10f1adc730 feat: support deepseek ai model (#989)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2024-05-23 09:26:03 +08:00
澄潭
e4d535ea65 fix transformer plugin (#990) 2024-05-22 21:05:05 +08:00
Kent Dong
76b5f2af79 feat: Enhance the feature of ai-proxy plugin (#976) 2024-05-22 20:30:46 +08:00
Ziyi Li
fc6a6aad89 feat: add baichuan llm support (#979)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2024-05-22 09:26:22 +08:00
澄潭
af8eff2bd6 optimize default action of route envoyfilter (#985) 2024-05-21 23:57:13 +08:00
澄潭
d91b22f8c2 Update Makefile.core.mk 2024-05-21 23:53:49 +08:00
澄潭
f4a73b986c keep bootstrap same with istio-ingress-gateway (#986) 2024-05-21 23:52:37 +08:00
澄潭
bff21b2307 fix proxy wasm 0_2_100 (#984) 2024-05-21 23:05:56 +08:00
Chi Kai
33013d07f4 feat: support yi ai model (#980) 2024-05-21 18:17:28 +08:00
澄潭
22a3e7018b Update CODEOWNERS 2024-05-20 17:24:00 +08:00
澄潭
2ff56c82f8 rel: Release v1.4.0-rc.1 (#973) 2024-05-19 17:55:31 +08:00
澄潭
9b50343618 Update build-and-test-plugin.yaml 2024-05-19 17:33:06 +08:00
澄潭
f9994237d1 Update Makefile.core.mk 2024-05-19 17:31:03 +08:00
澄潭
ae54318557 Update Makefile.core.mk 2024-05-19 17:01:07 +08:00
澄潭
0ec6719751 Add proxy start script (#972)
Signed-off-by: zty98751 <zty98751@alibaba-inc.com>
Co-authored-by: Kent Dong <ch3cho@qq.com>
2024-05-19 16:48:55 +08:00
澄潭
dfa1be3b47 support redis call (#971)
Signed-off-by: zty98751 <zty98751@alibaba-inc.com>
2024-05-19 12:43:29 +08:00
澄潭
95aa69cb95 optimize rds cache (#970) 2024-05-18 19:22:09 +08:00
澄潭
5333031f31 fix mcp destination bug (#968) 2024-05-18 15:55:42 +08:00
Se7en
31242c36ba feat: support groq ai model (#967) 2024-05-17 14:44:41 +08:00
Kent Dong
3119ec8e24 feat: Improve model parsing function of "hgctl plugin build" command (#966) 2024-05-16 14:38:46 +08:00
rinfx
42c9c3d824 waf skip body when protocol is grpc, websocket or sse (#943) 2024-05-15 20:34:47 +08:00
Kent Dong
8736188e6a fix: Add "protocol" field into the readme of ai-proxy (#942) 2024-05-15 20:26:05 +08:00
Kent Dong
559a109ae5 feat: Refactor Qwen stream event processing workflow (#939) 2024-05-15 11:43:45 +08:00
韩贤涛
8043780de0 fix: when multiple http2Rpc config constructHttp2RpcEnvoyFilter (… (#935) 2024-05-14 19:17:48 +08:00
Kent Dong
333f9b48f3 feat: Add an AI-Proxy Wasm plugin (#921)
Co-authored-by: 澄潭 <zty98751@alibaba-inc.com>
2024-05-14 17:00:12 +08:00
rinfx
5c7736980c Support multi ontick (#932) 2024-05-13 20:31:54 +08:00
澄潭
2031c659c2 feat: Wasm go sdk support process streaming body (#933) 2024-05-10 18:53:34 +08:00
Jun
03d2f01274 feat:add higress automatic https (#854)
Co-authored-by: 澄潭 <zty98751@alibaba-inc.com>
2024-05-09 10:56:28 +08:00
澄潭
6577ae8822 Update main.go 2024-05-08 10:32:10 +08:00
dongdongh233
a8c74c8302 Feature/add e2e testcase for issue 862 (#899) 2024-04-28 14:21:09 +08:00
韩贤涛
a787088c0e feature: add registry watcherStatus endpoint (#913) (#915)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2024-04-24 10:39:41 +08:00
Lex.Chen
e68b5c86c4 Update README.md (#909) 2024-04-23 15:36:16 +08:00
Kent Dong
5fec6e9ab7 fix: Refresh go.mod and go.sum file contents (#919) 2024-04-23 15:34:25 +08:00
澄潭
3b2196d0f8 fix env var of ISTIO_GPRC_MAXRECVMSGSIZE (#923)
Signed-off-by: johnlanni <zty98751@alibaba-inc.com>
2024-04-23 11:58:30 +08:00
Kent Dong
a592b2b103 feat: Write the original host header before changed by Wasm plugin into access log (#920) 2024-04-23 10:50:45 +08:00
澄潭
37fb2a52c0 rel: Release 1.3.6 (#918)
Signed-off-by: johnlanni <zty98751@alibaba-inc.com>
2024-04-22 19:33:42 +08:00
澄潭
41491166e3 Update Makefile.core.mk 2024-04-22 19:26:36 +08:00
澄潭
29baf8576e Fix the issue of istio VirtualService not supporting multiple domain names when using SRDS (#917) 2024-04-22 19:03:53 +08:00
fsl
f1cadcbd73 fix: get the container access docker compose ps (#870)
Signed-off-by: fengshunli <1171313930@qq.com>
2024-04-18 18:56:16 +08:00
澄潭
8c817cf80a Update README.md 2024-04-16 09:45:59 +08:00
澄潭
a67ce1d223 Update httproute-limit.go 2024-04-10 11:02:14 +08:00
澄潭
fb18782a80 Update build-and-test.yaml 2024-04-10 10:32:44 +08:00
澄潭
026840b59b Update README_EN.md 2024-04-10 10:31:08 +08:00
澄潭
75599ef804 Update README.md 2024-04-10 10:30:27 +08:00
Kent Dong
fe039d46f2 fix: Fix the "Build Status" badge on README pages (#904) 2024-04-10 10:22:28 +08:00
alexzzh
6c7b1757b6 feat: higress global configmap support config route timeout (#883) 2024-04-07 10:45:25 +08:00
Kent Dong
dfc9ae412e fix: Improve error handling in the plugin config model parser of hgctl (#891) 2024-04-03 09:49:06 +08:00
alexzzh
b4f72d3584 optimize on construct envoyfilter (#889) 2024-04-01 19:18:38 +08:00
澄潭
cba2890e14 Update README.md 2024-03-29 16:49:01 +08:00
澄潭
e844daea66 Feat: transformer plugin support map from body to header (#892) 2024-03-29 16:20:16 +08:00
澄潭
717e3bf51f optimize logic for empty config wasm plugin (#898) 2024-03-29 16:17:36 +08:00
澄潭
ba0df237da fix wasm priority logic (#897) 2024-03-29 14:03:02 +08:00
dongdongh233
08e56780f0 e2e: add testcases for rate limit annotations (#879) 2024-03-27 14:57:32 +08:00
澄潭
a45748bb0b fix priority type of wasmplugin (#881) 2024-03-26 19:54:08 +08:00
brother-戎
97cf58e973 test: add httproute-response-header-control for #863 (#875) 2024-03-26 19:08:23 +08:00
Kent Dong
4d6aa25b19 fix: Consider the new ingress package is available as default (#880) 2024-03-26 16:12:56 +08:00
rinfx
25c2f6e42e update redis wrapper (#864) 2024-03-18 16:37:10 +08:00
Kent Dong
ed55b65443 feat: Support publishing hgctl packages to GitHub releases (#869) 2024-03-13 13:41:36 +08:00
澄潭
d64c266ee4 fix file name (#867) 2024-03-12 16:45:05 +08:00
Bowen Li
32b602704e feat: add plugin - cache control (#810) 2024-03-12 16:42:53 +08:00
renz7
3128df9abd feat: add ip-restriction wasm-go plugin (#759) 2024-03-12 16:25:44 +08:00
澄潭
cc6043de15 fix route name from gateway api (#866) 2024-03-08 17:35:04 +08:00
澄潭
c9f1f94130 rel: Release version 1.3.5 (#856) 2024-03-04 19:06:05 +08:00
澄潭
5554189851 Update Makefile.core.mk 2024-03-04 18:57:21 +08:00
澄潭
eb1f99391a fix rds cache with gateway api (#855) 2024-03-04 18:36:55 +08:00
澄潭
7d4ab04030 support nil wasmplugin config in ingress-level (#852) 2024-03-01 15:25:57 +08:00
澄潭
9c112a03db Update build-and-test-plugin.yaml 2024-02-26 19:46:14 +08:00
rinfx
9be4f7d587 replace proxy-wasm-go-sdk (#842) 2024-02-26 19:19:49 +08:00
rinfx
50a219ed01 Support redis call (#756)
Co-authored-by: Xunzhuo <bitliu@tencent.com>
2024-02-23 14:51:27 +08:00
Uncle-Justice
e55a3c0f5b feat: custom listening port for gateway pod in helm (#829) 2024-02-23 13:37:50 +08:00
baerwang
e0e4fc3507 chore: e2e build wasm plugin retry (#838) 2024-02-23 13:36:48 +08:00
SJC
3967eec852 feat: hgctl install profile support resource configuration (#823) 2024-02-23 13:35:09 +08:00
澄潭
f537a1c3ea fix: content-type not work in custom response plugin (#833) 2024-02-21 14:00:43 +08:00
澄潭
b652f3e666 optimize: add klog for debuging requests with apiserver (#830) 2024-02-20 17:01:39 +08:00
365 changed files with 30586 additions and 1054 deletions

View File

@@ -0,0 +1,114 @@
name: Build and Push Wasm Plugin Image
on:
push:
tags:
- "wasm-go-*-v*.*.*" # 匹配 wasm-go-{pluginName}-vX.Y.Z 格式的标签
workflow_dispatch:
inputs:
plugin_name:
description: 'Name of the plugin'
required: true
type: string
version:
description: 'Version of the plugin (optional, without leading v)'
required: false
type: string
jobs:
build-and-push-wasm-plugin-image:
runs-on: ubuntu-latest
environment:
name: image-registry-msg
env:
IMAGE_REGISTRY_SERVICE: ${{ vars.IMAGE_REGISTRY || 'higress-registry.cn-hangzhou.cr.aliyuncs.com' }}
IMAGE_REPOSITORY: ${{ vars.PLUGIN_IMAGE_REPOSITORY || 'plugins' }}
GO_VERSION: 1.19
TINYGO_VERSION: 0.28.1
ORAS_VERSION: 1.0.0
steps:
- name: Set plugin_name and version from inputs or ref_name
id: set_vars
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
plugin_name="${{ github.event.inputs.plugin_name }}"
version="${{ github.event.inputs.version }}"
else
ref_name=${{ github.ref_name }}
plugin_name=${ref_name#*-*-} # 删除插件名前面的字段(wasm-go-)
plugin_name=${plugin_name%-*} # 删除插件名后面的字段(-vX.Y.Z)
version=$(echo "$ref_name" | awk -F'v' '{print $2}')
fi
echo "PLUGIN_NAME=$plugin_name" >> $GITHUB_ENV
echo "VERSION=$version" >> $GITHUB_ENV
- name: Checkout code
uses: actions/checkout@v3
- name: File Check
run: |
workspace=${{ github.workspace }}/plugins/wasm-go/extensions/${PLUGIN_NAME}
push_command="./plugin.tar.gz:application/vnd.oci.image.layer.v1.tar+gzip"
# 查找spec.yaml
if [ -f "${workspace}/spec.yaml" ]; then
echo "spec.yaml exists"
push_command="./spec.yaml:application/vnd.module.wasm.spec.v1+yaml $push_command "
fi
# 查找README.md
if [ -f "${workspace}/README.md" ];then
echo "README.md exists"
push_command="./README.md:application/vnd.module.wasm.doc.v1+markdown $push_command "
fi
# 查找README_{lang}.md
for file in ${workspace}/README_*.md; do
if [ -f "$file" ]; then
file_name=$(basename $file)
echo "$file_name exists"
lang=$(basename $file | sed 's/README_//; s/.md//')
push_command="./$file_name:application/vnd.module.wasm.doc.v1.$lang+markdown $push_command "
fi
done
echo "PUSH_COMMAND=\"$push_command\"" >> $GITHUB_ENV
- name: Run a wasm-go-builder
env:
PLUGIN_NAME: ${{ env.PLUGIN_NAME }}
BUILDER_IMAGE: higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins/wasm-go-builder:go${{ env.GO_VERSION }}-tinygo${{ env.TINYGO_VERSION }}-oras${{ env.ORAS_VERSION }}
run: |
docker run -itd --name builder -v ${{ github.workspace }}:/workspace -e PLUGIN_NAME=${{ env.PLUGIN_NAME }} --rm ${{ env.BUILDER_IMAGE }} /bin/bash
- name: Build Image and Push
run: |
push_command=${{ env.PUSH_COMMAND }}
push_command=${push_command#\"}
push_command=${push_command%\"} # 删除PUSH_COMMAND中的双引号确保oras push正常解析
target_image="${{ env.IMAGE_REGISTRY_SERVICE }}/${{ env.IMAGE_REPOSITORY}}/${{ env.PLUGIN_NAME }}:${{ env.VERSION }}"
echo "TargetImage=${target_image}"
cd ${{ github.workspace }}/plugins/wasm-go/extensions/${PLUGIN_NAME}
if [ -f ./.buildrc ]; then
echo 'Found .buildrc file, sourcing it...'
. ./.buildrc
else
echo '.buildrc file not found'
fi
echo "EXTRA_TAGS=${EXTRA_TAGS}"
command="
set -e
cd /workspace/plugins/wasm-go/extensions/${PLUGIN_NAME}
go mod tidy
tinygo build -o ./plugin.wasm -scheduler=none -target=wasi -gc=custom -tags=\"custommalloc nottinygc_finalizer ${EXTRA_TAGS}\" .
tar czvf plugin.tar.gz plugin.wasm
echo ${{ secrets.REGISTRY_PASSWORD }} | oras login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin ${{ env.IMAGE_REGISTRY_SERVICE }}
oras push ${target_image} ${push_command}
"
docker exec builder bash -c "$command"

View File

@@ -7,19 +7,20 @@ on:
- 'plugins/**'
- 'test/**'
pull_request:
branches: ["*"]
branches: [ "*" ]
paths:
- 'plugins/**'
- 'test/**'
workflow_dispatch: ~
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: 1.19
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
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
@@ -29,40 +30,55 @@ jobs:
strategy:
matrix:
# TODO(Xunzhuo): Enable C WASM Filters in CI
wasmPluginType: [ GO ]
wasmPluginType: [ GO, RUST ]
steps:
- uses: actions/checkout@v3
- name: "Setup Go"
uses: actions/setup-go@v3
with:
go-version: 1.19
- uses: actions/checkout@v4
- name: Setup Golang Caches
uses: actions/cache@v3
with:
path: |-
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-go
- name: Setup Submodule Caches
uses: actions/cache@v3
with:
path: |-
- name: Free Up GitHub Actions Ubuntu Runner Disk Space 🔧
uses: jlumbroso/free-disk-space@main
with:
tool-cache: false
android: true
dotnet: true
haskell: true
large-packages: true
swap-storage: true
- name: "Setup Go"
uses: actions/setup-go@v5
with:
go-version: 1.19
- name: Setup Golang Caches
uses: actions/cache@v4
with:
path: |-
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-go
- name: Setup Submodule Caches
uses: actions/cache@v4
with:
path: |-
.git/modules
key: ${{ runner.os }}-submodules-cache-${{ github.run_id }}
restore-keys: ${{ runner.os }}-submodules-cache
- run: git stash # restore patch
key: ${{ runner.os }}-submodules-cache-${{ github.run_id }}
restore-keys: ${{ runner.os }}-submodules-cache
- name: "Run Ingress WasmPlugins Tests"
run: GOPROXY="https://proxy.golang.org,direct" PLUGIN_TYPE=${{ matrix.wasmPluginType }} make higress-wasmplugin-test
- run: git stash # restore patch
- name: "Run Ingress WasmPlugins Tests"
uses: nick-fields/retry@v3
with:
timeout_minutes: 25
max_attempts: 3
retry_on: error
command: GOPROXY="https://proxy.golang.org,direct" PLUGIN_TYPE=${{ matrix.wasmPluginType }} make higress-wasmplugin-test
publish:
runs-on: ubuntu-latest
needs: [higress-wasmplugin-test]
needs: [ higress-wasmplugin-test ]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

View File

@@ -10,8 +10,8 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: 1.19
# There are too many lint errors in current code bases
@@ -21,10 +21,10 @@ jobs:
coverage-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup Golang Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
~/.cache/go-build
@@ -33,7 +33,7 @@ jobs:
restore-keys: ${{ runner.os }}-go
- name: Setup Submodule Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
.git/modules
@@ -46,9 +46,9 @@ jobs:
- 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
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: true
fail_ci_if_error: false
files: ./coverage.xml
verbose: true
@@ -58,17 +58,17 @@ jobs:
needs: [lint,coverage-test]
steps:
- name: "Checkout ${{ github.ref }}"
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: "Setup Go"
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: 1.19
- name: Setup Golang Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
~/.cache/go-build
@@ -77,7 +77,7 @@ jobs:
restore-keys: ${{ runner.os }}-go
- name: Setup Submodule Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
.git/modules
@@ -90,7 +90,7 @@ jobs:
run: GOPROXY="https://proxy.golang.org,direct" make build
- name: Upload Higress Binary
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: higress
path: out/
@@ -108,12 +108,12 @@ jobs:
- uses: actions/checkout@v3
- name: "Setup Go"
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: 1.19
- name: Setup Golang Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
~/.cache/go-build
@@ -123,7 +123,7 @@ jobs:
${{ runner.os }}-go
- name: Setup Submodule Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
.git/modules
@@ -139,4 +139,4 @@ jobs:
runs-on: ubuntu-latest
needs: [higress-conformance-test,gateway-conformance-test]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

View File

@@ -16,7 +16,7 @@ jobs:
CONTROLLER_IMAGE_NAME: ${{ vars.CONTROLLER_IMAGE_NAME || 'higress/higress' }}
steps:
- name: "Checkout ${{ github.ref }}"
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 1
@@ -31,12 +31,12 @@ jobs:
swap-storage: true
- name: "Setup Go"
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: 1.19
- name: Setup Golang Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
~/.cache/go-build
@@ -45,7 +45,7 @@ jobs:
restore-keys: ${{ runner.os }}-go
- name: Setup Submodule Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
envoy
@@ -56,7 +56,7 @@ jobs:
- name: Calculate Docker metadata
id: docker-meta
uses: docker/metadata-action@v4
uses: docker/metadata-action@v5
with:
images: |
${{ env.CONTROLLER_IMAGE_REGISTRY }}/${{ env.CONTROLLER_IMAGE_NAME }}
@@ -67,7 +67,7 @@ jobs:
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
- name: Login to Docker Registry
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.CONTROLLER_IMAGE_REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
@@ -92,7 +92,7 @@ jobs:
PILOT_IMAGE_NAME: ${{ vars.PILOT_IMAGE_NAME || 'higress/pilot' }}
steps:
- name: "Checkout ${{ github.ref }}"
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 1
@@ -107,12 +107,12 @@ jobs:
swap-storage: true
- name: "Setup Go"
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: 1.19
- name: Setup Golang Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
~/.cache/go-build
@@ -121,7 +121,7 @@ jobs:
restore-keys: ${{ runner.os }}-go
- name: Setup Submodule Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
envoy
@@ -132,7 +132,7 @@ jobs:
- name: Calculate Docker metadata
id: docker-meta
uses: docker/metadata-action@v4
uses: docker/metadata-action@v5
with:
images: |
${{ env.PILOT_IMAGE_REGISTRY }}/${{ env.PILOT_IMAGE_NAME }}
@@ -143,7 +143,7 @@ jobs:
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
- name: Login to Docker Registry
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.PILOT_IMAGE_REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
@@ -169,7 +169,7 @@ jobs:
GATEWAY_IMAGE_NAME: ${{ vars.GATEWAY_IMAGE_NAME || 'higress/gateway' }}
steps:
- name: "Checkout ${{ github.ref }}"
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 1
@@ -184,12 +184,12 @@ jobs:
swap-storage: true
- name: "Setup Go"
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: 1.19
- name: Setup Golang Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
~/.cache/go-build
@@ -198,7 +198,7 @@ jobs:
restore-keys: ${{ runner.os }}-go
- name: Setup Submodule Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |-
envoy
@@ -209,7 +209,7 @@ jobs:
- name: Calculate Docker metadata
id: docker-meta
uses: docker/metadata-action@v4
uses: docker/metadata-action@v5
with:
images: |
${{ env.GATEWAY_IMAGE_REGISTRY }}/${{ env.GATEWAY_IMAGE_NAME }}
@@ -220,7 +220,7 @@ jobs:
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
- name: Login to Docker Registry
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.GATEWAY_IMAGE_REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}

View File

@@ -34,11 +34,11 @@ jobs:
steps:
# step 1
- name: "Checkout repository"
uses: actions/checkout@v2
uses: actions/checkout@v4
# step 2: Initializes the CodeQL tools for scanning.
- name: "Initialize CodeQL"
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -50,7 +50,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: "Autobuild"
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v2
# step 4
# Command-line programs to run using the OS shell.
@@ -66,4 +66,4 @@ jobs:
# step 5
- name: "Perform CodeQL Analysis"
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2

View File

@@ -14,7 +14,7 @@ jobs:
steps:
# Step 1
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
# Step 2
- id: package
name: Prepare Standalone Package

View File

@@ -14,7 +14,7 @@ jobs:
steps:
# Step 1
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
# Step 2
- name: Download Helm Charts Index
uses: doggycool/ossutil-github-action@master

View File

@@ -9,7 +9,7 @@ jobs:
latest-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Build hgctl latest multiarch binaries
run: |
@@ -46,7 +46,7 @@ jobs:
GITHUB_REPOSITORY: ${{ github.repository_owner }}/${{ github.event.repository.name }}
- name: Recreate the Latest Release and Tag
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
with:
draft: false
prerelease: true

View File

@@ -10,7 +10,7 @@ jobs:
steps:
# step 1
- name: Checkout
uses: actions/checkout@v2.4.0
uses: actions/checkout@v4
# step 2
- name: Check License Header
uses: apache/skywalking-eyes/header@25edfc2fd8d52fb266653fb5f6c42da633d85c07
@@ -24,4 +24,4 @@ jobs:
with:
log: info
config: .licenserc.yaml
mode: check
mode: check

37
.github/workflows/release-hgctl.yaml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: Release hgctl to GitHub
on:
push:
tags:
- "v*.*.*"
workflow_dispatch: ~
jobs:
release-hgctl:
runs-on: ubuntu-latest
env:
HGCTL_VERSION: ${{github.ref_name}}
steps:
- uses: actions/checkout@v4
- name: Build hgctl latest multiarch binaries
run: |
GOPROXY="https://proxy.golang.org,direct" make build-hgctl-multiarch
tar -zcvf hgctl_${{ env.HGCTL_VERSION }}_linux_amd64.tar.gz out/linux_amd64/
tar -zcvf hgctl_${{ env.HGCTL_VERSION }}_linux_arm64.tar.gz out/linux_arm64/
tar -zcvf hgctl_${{ env.HGCTL_VERSION }}_darwin_amd64.tar.gz out/darwin_amd64/
tar -zcvf hgctl_${{ env.HGCTL_VERSION }}_darwin_arm64.tar.gz out/darwin_arm64/
zip -q -r hgctl_${{ env.HGCTL_VERSION }}_windows_amd64.zip out/windows_amd64/
zip -q -r hgctl_${{ env.HGCTL_VERSION }}_windows_arm64.zip out/windows_arm64/
- name: Upload hgctl packages to the GitHub release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
hgctl_${{ env.HGCTL_VERSION }}_linux_amd64.tar.gz
hgctl_${{ env.HGCTL_VERSION }}_linux_arm64.tar.gz
hgctl_${{ env.HGCTL_VERSION }}_darwin_amd64.tar.gz
hgctl_${{ env.HGCTL_VERSION }}_darwin_arm64.tar.gz
hgctl_${{ env.HGCTL_VERSION }}_windows_amd64.zip
hgctl_${{ env.HGCTL_VERSION }}_windows_arm64.zip

View File

@@ -2,7 +2,7 @@
/envoy @gengleilei @johnlanni
/istio @SpecialYang @johnlanni
/pkg @SpecialYang @johnlanni @CH3CHO
/plugins @johnlanni @WeixinX
/plugins @johnlanni @WeixinX @CH3CHO
/registry @NameHaibinZhang @2456868764 @johnlanni
/test @Xunzhuo @2456868764 @CH3CHO
/tools @johnlanni @Xunzhuo @2456868764

View File

@@ -138,11 +138,11 @@ export ENVOY_TAR_PATH:=/home/package/envoy.tar.gz
external/package/envoy-amd64.tar.gz:
# cd external/proxy; BUILD_WITH_CONTAINER=1 make test_release
cd external/package; wget -O envoy-amd64.tar.gz "https://github.com/alibaba/higress/releases/download/v1.3.4-rc.1/envoy-symbol-amd64.tar.gz"
cd external/package; wget -O envoy-amd64.tar.gz "https://github.com/alibaba/higress/releases/download/v1.4.1/envoy-symbol-amd64.tar.gz"
external/package/envoy-arm64.tar.gz:
# cd external/proxy; BUILD_WITH_CONTAINER=1 make test_release
cd external/package; wget -O envoy-arm64.tar.gz "https://github.com/alibaba/higress/releases/download/v1.3.4-rc.1/envoy-symbol-arm64.tar.gz"
cd external/package; wget -O envoy-arm64.tar.gz "https://github.com/alibaba/higress/releases/download/v1.4.1/envoy-symbol-arm64.tar.gz"
build-pilot:
cd external/istio; rm -rf out/linux_amd64; GOOS_LOCAL=linux TARGET_OS=linux TARGET_ARCH=amd64 BUILD_WITH_CONTAINER=1 make build-linux
@@ -177,8 +177,8 @@ install: pre-install
cd helm/higress; helm dependency build
helm install higress helm/higress -n higress-system --create-namespace --set 'global.local=true'
ENVOY_LATEST_IMAGE_TAG ?= sha-a68dde0
ISTIO_LATEST_IMAGE_TAG ?= sha-a68dde0
ENVOY_LATEST_IMAGE_TAG ?= sha-63539ca
ISTIO_LATEST_IMAGE_TAG ?= sha-63539ca
install-dev: pre-install
helm install higress helm/core -n higress-system --create-namespace --set 'controller.tag=$(TAG)' --set 'gateway.replicas=1' --set 'pilot.tag=$(ISTIO_LATEST_IMAGE_TAG)' --set 'gateway.tag=$(ENVOY_LATEST_IMAGE_TAG)' --set 'global.local=true'
@@ -305,7 +305,7 @@ run-higress-e2e-test:
kubectl wait --timeout=10m -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=10m -n higress-system deployment/higress-gateway --for=condition=Available
go test -v -tags conformance ./test/e2e/e2e_test.go --ingress-class=higress --debug=true --test-area=all
go test -v -tags conformance ./test/e2e/e2e_test.go --ingress-class=higress --debug=true --test-area=all --execute-tests=$(TEST_SHORTNAME)
# run-higress-e2e-test-run starts to run ingress e2e conformance tests.
.PHONY: run-higress-e2e-test-run
@@ -315,7 +315,7 @@ run-higress-e2e-test-run:
kubectl wait --timeout=10m -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=10m -n higress-system deployment/higress-gateway --for=condition=Available
go test -v -tags conformance ./test/e2e/e2e_test.go --ingress-class=higress --debug=true --test-area=run
go test -v -tags conformance ./test/e2e/e2e_test.go --ingress-class=higress --debug=true --test-area=run --execute-tests=$(TEST_SHORTNAME)
# run-higress-e2e-test-clean starts to clean ingress e2e tests.
.PHONY: run-higress-e2e-test-clean
@@ -345,7 +345,7 @@ run-higress-e2e-test-wasmplugin:
kubectl wait --timeout=10m -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=10m -n higress-system deployment/higress-gateway --for=condition=Available
go test -v -tags conformance ./test/e2e/e2e_test.go -isWasmPluginTest=true -wasmPluginType=$(PLUGIN_TYPE) -wasmPluginName=$(PLUGIN_NAME) --ingress-class=higress --debug=true --test-area=all
go test -v -tags conformance ./test/e2e/e2e_test.go -isWasmPluginTest=true -wasmPluginType=$(PLUGIN_TYPE) -wasmPluginName=$(PLUGIN_NAME) --ingress-class=higress --debug=true --test-area=all --execute-tests=$(TEST_SHORTNAME)
# run-higress-e2e-test-wasmplugin-run starts to run ingress e2e conformance tests.
.PHONY: run-higress-e2e-test-wasmplugin-run
@@ -355,7 +355,7 @@ run-higress-e2e-test-wasmplugin-run:
kubectl wait --timeout=10m -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=10m -n higress-system deployment/higress-gateway --for=condition=Available
go test -v -tags conformance ./test/e2e/e2e_test.go -isWasmPluginTest=true -wasmPluginType=$(PLUGIN_TYPE) -wasmPluginName=$(PLUGIN_NAME) --ingress-class=higress --debug=true --test-area=run
go test -v -tags conformance ./test/e2e/e2e_test.go -isWasmPluginTest=true -wasmPluginType=$(PLUGIN_TYPE) -wasmPluginName=$(PLUGIN_NAME) --ingress-class=higress --debug=true --test-area=run --execute-tests=$(TEST_SHORTNAME)
# run-higress-e2e-test-wasmplugin-clean starts to clean ingress e2e tests.
.PHONY: run-higress-e2e-test-wasmplugin-clean

View File

@@ -1,10 +1,10 @@
<h1 align="center">
<img src="https://img.alicdn.com/imgextra/i2/O1CN01NwxLDd20nxfGBjxmZ_!!6000000006895-2-tps-960-290.png" alt="Higress" width="240" height="72.5">
<br>
Next-generation Cloud Native Gateway
Cloud Native API Gateway
</h1>
[![Build Status](https://github.com/alibaba/higress/workflows/build%20and%20codecov/badge.svg?branch=main)](https://github.com/alibaba/higress/actions)
[![Build Status](https://github.com/alibaba/higress/actions/workflows/build-and-test.yaml/badge.svg?branch=main)](https://github.com/alibaba/higress/actions)
[![license](https://img.shields.io/github/license/alibaba/higress.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
[**官网**](https://higress.io/) &nbsp; |
@@ -19,7 +19,7 @@
</p>
Higress 是基于阿里内部两年多的 Envoy Gateway 实践沉淀,以开源 [Istio](https://github.com/istio/istio) 与 [Envoy](https://github.com/envoyproxy/envoy) 为核心构建的下一代云原生网关。Higress 实现了安全防护网关、流量网关、微服务网关三层网关合一,可以显著降低网关的部署和运维成本。
Higress 是基于阿里内部两年多的 Envoy Gateway 实践沉淀,以开源 [Istio](https://github.com/istio/istio) 与 [Envoy](https://github.com/envoyproxy/envoy) 为核心构建的云原生 API 网关。Higress 实现了安全防护网关、流量网关、微服务网关三层网关合一,可以显著降低网关的部署和运维成本。
![arch](https://img.alicdn.com/imgextra/i1/O1CN01iO9ph825juHbOIg75_!!6000000007563-2-tps-2483-2024.png)
@@ -119,9 +119,13 @@ Higress 是基于阿里内部两年多的 Envoy Gateway 实践沉淀,以开源
如果没有 Envoy 和 Istio 的开源工作Higress 就不可能实现,在这里向这两个项目献上最诚挚的敬意。
### 联系我们
社区交流群:
### 交流群
![image](https://img.alicdn.com/imgextra/i2/O1CN01qPd7Ix1uZPVEsWjWp_!!6000000006051-0-tps-720-405.jpg)
### 技术分享
微信公众号:
![](https://img.alicdn.com/imgextra/i1/O1CN01WnQt0q1tcmqVDU73u_!!6000000005923-0-tps-258-258.jpg)

View File

@@ -1,10 +1,10 @@
<h1 align="center">
<img src="https://img.alicdn.com/imgextra/i2/O1CN01NwxLDd20nxfGBjxmZ_!!6000000006895-2-tps-960-290.png" alt="Higress" width="240" height="72.5">
<br>
Next-generation Cloud Native Gateway
Cloud Native API Gateway
</h1>
[![Build Status](https://github.com/alibaba/higress/workflows/build%20and%20codecov/badge.svg?branch=main)](https://github.com/alibaba/higress/actions)
[![Build Status](https://github.com/alibaba/higress/actions/workflows/build-and-test.yaml/badge.svg?branch=main)](https://github.com/alibaba/higress/actions)
[![license](https://img.shields.io/github/license/alibaba/higress.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
[**Official Site**](https://higress.io/en-us/) &nbsp; |
@@ -18,7 +18,7 @@
English | <a href="README.md">中文<a/>
</p>
Higress is a next-generation cloud-native gateway based on Alibaba's internal gateway practices.
Higress is a cloud-native api gateway based on Alibaba's internal gateway practices.
Powered by [Istio](https://github.com/istio/istio) and [Envoy](https://github.com/envoyproxy/envoy), Higress realizes the integration of the triple gateway architecture of traffic gateway, microservice gateway and security gateway, thereby greatly reducing the costs of deployment, operation and maintenance.

View File

@@ -1 +1 @@
v1.3.4
v1.4.2

View File

@@ -166,7 +166,7 @@ type WasmPlugin struct {
// 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`.
Priority *types.Int64Value `protobuf:"bytes,10,opt,name=priority,proto3" json:"priority,omitempty"`
Priority *types.Int32Value `protobuf:"bytes,10,opt,name=priority,proto3" json:"priority,omitempty"`
// Extended by Higress, the default configuration takes effect globally
DefaultConfig *types.Struct `protobuf:"bytes,101,opt,name=default_config,json=defaultConfig,proto3" json:"default_config,omitempty"`
// Extended by Higress, matching rules take effect
@@ -267,7 +267,7 @@ func (m *WasmPlugin) GetPhase() PluginPhase {
return PluginPhase_UNSPECIFIED_PHASE
}
func (m *WasmPlugin) GetPriority() *types.Int64Value {
func (m *WasmPlugin) GetPriority() *types.Int32Value {
if m != nil {
return m.Priority
}
@@ -377,46 +377,46 @@ func init() {
func init() { proto.RegisterFile("extensions/v1alpha1/wasm.proto", fileDescriptor_4d60b240916c4e18) }
var fileDescriptor_4d60b240916c4e18 = []byte{
// 617 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x94, 0xdf, 0x4e, 0x13, 0x41,
0x14, 0xc6, 0xd9, 0x16, 0x0a, 0x3d, 0x05, 0x5c, 0x26, 0x8a, 0x13, 0x30, 0xb5, 0x21, 0x51, 0x57,
0x2e, 0x76, 0x43, 0x45, 0xbc, 0x31, 0xc4, 0x02, 0x55, 0x1a, 0xb5, 0x6e, 0x76, 0x41, 0x23, 0x37,
0x9b, 0xe9, 0x32, 0xdd, 0x4e, 0x9c, 0xfd, 0x93, 0x9d, 0x59, 0xb0, 0x0f, 0xe2, 0x3b, 0x79, 0xe9,
0x23, 0x18, 0xde, 0xc2, 0x3b, 0xd3, 0xd9, 0x2d, 0x6d, 0xd1, 0xf4, 0x6e, 0xe6, 0x9c, 0xdf, 0x39,
0xe7, 0xfb, 0xce, 0x4e, 0x16, 0xea, 0xf4, 0xbb, 0xa4, 0x91, 0x60, 0x71, 0x24, 0xac, 0xab, 0x3d,
0xc2, 0x93, 0x01, 0xd9, 0xb3, 0xae, 0x89, 0x08, 0xcd, 0x24, 0x8d, 0x65, 0x8c, 0xb6, 0x07, 0x2c,
0x48, 0xa9, 0x10, 0xe6, 0x84, 0x33, 0xc7, 0xdc, 0x56, 0x3d, 0x88, 0xe3, 0x80, 0x53, 0x4b, 0xa1,
0xbd, 0xac, 0x6f, 0x5d, 0xa7, 0x24, 0x49, 0x68, 0x2a, 0xf2, 0xe2, 0xad, 0x47, 0x77, 0xf3, 0x42,
0xa6, 0x99, 0x2f, 0xf3, 0xec, 0xce, 0x9f, 0x45, 0x80, 0x2f, 0x44, 0x84, 0x36, 0xcf, 0x02, 0x16,
0x21, 0x1d, 0xca, 0x59, 0xca, 0x71, 0xa9, 0xa1, 0x19, 0x55, 0x67, 0x74, 0x44, 0x9b, 0x50, 0x11,
0x03, 0xd2, 0x7c, 0x79, 0x80, 0xcb, 0x2a, 0x58, 0xdc, 0x90, 0x0b, 0x1b, 0x2c, 0x24, 0x01, 0xf5,
0x92, 0x8c, 0x73, 0x2f, 0x89, 0x39, 0xf3, 0x87, 0x78, 0xb1, 0xa1, 0x19, 0xeb, 0xcd, 0x67, 0xe6,
0x1c, 0xbd, 0xa6, 0x9d, 0x71, 0x6e, 0x2b, 0xdc, 0xb9, 0xa7, 0x3a, 0x4c, 0x02, 0x68, 0x77, 0xa6,
0xa9, 0xa0, 0x7e, 0x4a, 0x25, 0x5e, 0x52, 0x73, 0x27, 0xac, 0xab, 0xc2, 0xe8, 0x39, 0xe8, 0x57,
0x34, 0x65, 0x7d, 0xe6, 0x13, 0xc9, 0xe2, 0xc8, 0xfb, 0x46, 0x87, 0xb8, 0x92, 0xa3, 0xd3, 0xf1,
0xf7, 0x74, 0x88, 0x5e, 0xc3, 0x5a, 0xa2, 0xfc, 0x79, 0x7e, 0x1c, 0xf5, 0x59, 0x80, 0x97, 0x1b,
0x9a, 0x51, 0x6b, 0x3e, 0x34, 0xf3, 0xd5, 0x98, 0xe3, 0xd5, 0x98, 0xae, 0x5a, 0x8d, 0xb3, 0x9a,
0xd3, 0xc7, 0x0a, 0x46, 0x8f, 0xa1, 0x56, 0x54, 0x47, 0x24, 0xa4, 0x78, 0x45, 0xcd, 0x80, 0x3c,
0xd4, 0x25, 0x21, 0x45, 0x87, 0xb0, 0x94, 0x0c, 0x88, 0xa0, 0xb8, 0xaa, 0xec, 0x1b, 0xf3, 0xed,
0xab, 0x3a, 0x7b, 0xc4, 0x3b, 0x79, 0x19, 0x7a, 0x05, 0x2b, 0x49, 0xca, 0xe2, 0x94, 0xc9, 0x21,
0x06, 0xa5, 0x6c, 0xfb, 0x1f, 0x65, 0x9d, 0x48, 0x1e, 0xec, 0x7f, 0x26, 0x3c, 0xa3, 0xce, 0x2d,
0x8c, 0x0e, 0x61, 0xfd, 0x92, 0xf6, 0x49, 0xc6, 0xe5, 0xd8, 0x18, 0x9d, 0x6f, 0x6c, 0xad, 0xc0,
0x0b, 0x67, 0xef, 0xa0, 0x16, 0x12, 0xe9, 0x0f, 0xbc, 0x34, 0xe3, 0x54, 0xe0, 0x7e, 0xa3, 0x6c,
0xd4, 0x9a, 0x4f, 0xe7, 0xca, 0xff, 0x38, 0xe2, 0x9d, 0x8c, 0x53, 0x07, 0xc2, 0xf1, 0x51, 0xa0,
0x7d, 0xd8, 0x9c, 0x15, 0xe2, 0x5d, 0x32, 0x41, 0x7a, 0x9c, 0xe2, 0xa0, 0xa1, 0x19, 0x2b, 0xce,
0xfd, 0x99, 0xb9, 0x27, 0x79, 0x6e, 0xe7, 0x87, 0x06, 0xd5, 0xdb, 0x7e, 0x08, 0xc3, 0x32, 0x8b,
0xd4, 0x60, 0xac, 0x35, 0xca, 0x46, 0xd5, 0x19, 0x5f, 0x47, 0x4f, 0xf0, 0x32, 0x0e, 0x09, 0x8b,
0x70, 0x49, 0x25, 0x8a, 0x1b, 0xb2, 0xa0, 0x52, 0xd8, 0x2e, 0xcf, 0xb7, 0x5d, 0x60, 0xe8, 0x09,
0xac, 0xdf, 0x91, 0xb7, 0xa8, 0xe4, 0xad, 0xf9, 0xd3, 0xba, 0x76, 0xdb, 0x50, 0x9b, 0xfa, 0x4a,
0xe8, 0x01, 0x6c, 0x9c, 0x77, 0x5d, 0xbb, 0x7d, 0xdc, 0x79, 0xdb, 0x69, 0x9f, 0x78, 0xf6, 0x69,
0xcb, 0x6d, 0xeb, 0x0b, 0xa8, 0x0a, 0x4b, 0xad, 0xf3, 0xb3, 0xd3, 0xae, 0xae, 0x8d, 0x8f, 0x17,
0x7a, 0x69, 0x74, 0x74, 0xcf, 0x5a, 0x67, 0xae, 0x5e, 0xde, 0x3d, 0x02, 0x98, 0x7a, 0xda, 0x9b,
0x80, 0x66, 0xba, 0x7c, 0xfa, 0xd0, 0x39, 0xfe, 0xaa, 0x2f, 0x20, 0x1d, 0x56, 0x3b, 0xfd, 0x6e,
0x2c, 0xed, 0x94, 0x0a, 0x1a, 0x49, 0x5d, 0x43, 0x00, 0x95, 0x16, 0xbf, 0x26, 0x43, 0xa1, 0x97,
0x8e, 0xde, 0xfc, 0xbc, 0xa9, 0x6b, 0xbf, 0x6e, 0xea, 0xda, 0xef, 0x9b, 0xba, 0x76, 0xd1, 0x0c,
0x98, 0x1c, 0x64, 0x3d, 0xd3, 0x8f, 0x43, 0x8b, 0x70, 0xd6, 0x23, 0x3d, 0x62, 0x15, 0x1f, 0xcb,
0x22, 0x09, 0xb3, 0xfe, 0xf3, 0x1b, 0xe9, 0x55, 0xd4, 0x32, 0x5e, 0xfc, 0x0d, 0x00, 0x00, 0xff,
0xff, 0x48, 0x74, 0xbe, 0xc1, 0x64, 0x04, 0x00, 0x00,
// 619 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x94, 0xdd, 0x4e, 0xdb, 0x4c,
0x10, 0x86, 0x71, 0x02, 0x81, 0x4c, 0x80, 0xcf, 0xac, 0xbe, 0xd2, 0x15, 0x54, 0x69, 0x84, 0xd4,
0xd6, 0xe5, 0xc0, 0x16, 0xa1, 0x3f, 0x27, 0x15, 0x6a, 0x80, 0xb4, 0x44, 0x6d, 0x53, 0xcb, 0x86,
0x56, 0xe5, 0xc4, 0xda, 0x98, 0x8d, 0xb3, 0xea, 0xfa, 0x47, 0xde, 0x35, 0x34, 0x17, 0xd2, 0x7b,
0xea, 0x61, 0x2f, 0xa1, 0xe2, 0x2e, 0x7a, 0x56, 0x65, 0x6d, 0x43, 0x42, 0xab, 0x9c, 0xed, 0xce,
0x3c, 0x33, 0xf3, 0xbe, 0xe3, 0x95, 0xa1, 0x49, 0xbf, 0x49, 0x1a, 0x09, 0x16, 0x47, 0xc2, 0xba,
0xdc, 0x23, 0x3c, 0x19, 0x91, 0x3d, 0xeb, 0x8a, 0x88, 0xd0, 0x4c, 0xd2, 0x58, 0xc6, 0x68, 0x7b,
0xc4, 0x82, 0x94, 0x0a, 0x61, 0xde, 0x72, 0x66, 0xc9, 0x6d, 0x35, 0x83, 0x38, 0x0e, 0x38, 0xb5,
0x14, 0x3a, 0xc8, 0x86, 0xd6, 0x55, 0x4a, 0x92, 0x84, 0xa6, 0x22, 0x2f, 0xde, 0x7a, 0x70, 0x37,
0x2f, 0x64, 0x9a, 0xf9, 0x32, 0xcf, 0xee, 0xfc, 0x5e, 0x04, 0xf8, 0x4c, 0x44, 0x68, 0xf3, 0x2c,
0x60, 0x11, 0xd2, 0xa1, 0x9a, 0xa5, 0x1c, 0x57, 0x5a, 0x9a, 0x51, 0x77, 0x26, 0x47, 0xb4, 0x09,
0x35, 0x31, 0x22, 0xed, 0xe7, 0x2f, 0x70, 0x55, 0x05, 0x8b, 0x1b, 0x72, 0x61, 0x83, 0x85, 0x24,
0xa0, 0x5e, 0x92, 0x71, 0xee, 0x25, 0x31, 0x67, 0xfe, 0x18, 0x2f, 0xb6, 0x34, 0x63, 0xbd, 0xfd,
0xc4, 0x9c, 0xa3, 0xd7, 0xb4, 0x33, 0xce, 0x6d, 0x85, 0x3b, 0xff, 0xa9, 0x0e, 0xb7, 0x01, 0xb4,
0x3b, 0xd3, 0x54, 0x50, 0x3f, 0xa5, 0x12, 0x2f, 0xa9, 0xb9, 0xb7, 0xac, 0xab, 0xc2, 0xe8, 0x29,
0xe8, 0x97, 0x34, 0x65, 0x43, 0xe6, 0x13, 0xc9, 0xe2, 0xc8, 0xfb, 0x4a, 0xc7, 0xb8, 0x96, 0xa3,
0xd3, 0xf1, 0x77, 0x74, 0x8c, 0x5e, 0xc1, 0x5a, 0xa2, 0xfc, 0x79, 0x7e, 0x1c, 0x0d, 0x59, 0x80,
0x97, 0x5b, 0x9a, 0xd1, 0x68, 0xdf, 0x37, 0xf3, 0xd5, 0x98, 0xe5, 0x6a, 0x4c, 0x57, 0xad, 0xc6,
0x59, 0xcd, 0xe9, 0x23, 0x05, 0xa3, 0x87, 0xd0, 0x28, 0xaa, 0x23, 0x12, 0x52, 0xbc, 0xa2, 0x66,
0x40, 0x1e, 0xea, 0x93, 0x90, 0xa2, 0x03, 0x58, 0x4a, 0x46, 0x44, 0x50, 0x5c, 0x57, 0xf6, 0x8d,
0xf9, 0xf6, 0x55, 0x9d, 0x3d, 0xe1, 0x9d, 0xbc, 0x0c, 0xbd, 0x84, 0x95, 0x24, 0x65, 0x71, 0xca,
0xe4, 0x18, 0x83, 0x52, 0xb6, 0xfd, 0x97, 0xb2, 0x5e, 0x24, 0xf7, 0xdb, 0x9f, 0x08, 0xcf, 0xa8,
0x73, 0x03, 0xa3, 0x03, 0x58, 0xbf, 0xa0, 0x43, 0x92, 0x71, 0x59, 0x1a, 0xa3, 0xf3, 0x8d, 0xad,
0x15, 0x78, 0xe1, 0xec, 0x2d, 0x34, 0x42, 0x22, 0xfd, 0x91, 0x97, 0x66, 0x9c, 0x0a, 0x3c, 0x6c,
0x55, 0x8d, 0x46, 0xfb, 0xf1, 0x5c, 0xf9, 0x1f, 0x26, 0xbc, 0x93, 0x71, 0xea, 0x40, 0x58, 0x1e,
0x05, 0x7a, 0x06, 0x9b, 0xb3, 0x42, 0xbc, 0x0b, 0x26, 0xc8, 0x80, 0x53, 0x1c, 0xb4, 0x34, 0x63,
0xc5, 0xf9, 0x7f, 0x66, 0xee, 0x71, 0x9e, 0xdb, 0xf9, 0xae, 0x41, 0xfd, 0xa6, 0x1f, 0xc2, 0xb0,
0xcc, 0x22, 0x35, 0x18, 0x6b, 0xad, 0xaa, 0x51, 0x77, 0xca, 0xeb, 0xe4, 0x09, 0x5e, 0xc4, 0x21,
0x61, 0x11, 0xae, 0xa8, 0x44, 0x71, 0x43, 0x16, 0xd4, 0x0a, 0xdb, 0xd5, 0xf9, 0xb6, 0x0b, 0x0c,
0x3d, 0x82, 0xf5, 0x3b, 0xf2, 0x16, 0x95, 0xbc, 0x35, 0x7f, 0x5a, 0xd7, 0x6e, 0x17, 0x1a, 0x53,
0x5f, 0x09, 0xdd, 0x83, 0x8d, 0xb3, 0xbe, 0x6b, 0x77, 0x8f, 0x7a, 0x6f, 0x7a, 0xdd, 0x63, 0xcf,
0x3e, 0xe9, 0xb8, 0x5d, 0x7d, 0x01, 0xd5, 0x61, 0xa9, 0x73, 0x76, 0x7a, 0xd2, 0xd7, 0xb5, 0xf2,
0x78, 0xae, 0x57, 0x26, 0x47, 0xf7, 0xb4, 0x73, 0xea, 0xea, 0xd5, 0xdd, 0x43, 0x80, 0xa9, 0xa7,
0xbd, 0x09, 0x68, 0xa6, 0xcb, 0xc7, 0xf7, 0xbd, 0xa3, 0x2f, 0xfa, 0x02, 0xd2, 0x61, 0xb5, 0x37,
0xec, 0xc7, 0xd2, 0x4e, 0xa9, 0xa0, 0x91, 0xd4, 0x35, 0x04, 0x50, 0xeb, 0xf0, 0x2b, 0x32, 0x16,
0x7a, 0xe5, 0xf0, 0xf5, 0x8f, 0xeb, 0xa6, 0xf6, 0xf3, 0xba, 0xa9, 0xfd, 0xba, 0x6e, 0x6a, 0xe7,
0xed, 0x80, 0xc9, 0x51, 0x36, 0x30, 0xfd, 0x38, 0xb4, 0x08, 0x67, 0x03, 0x32, 0x20, 0x56, 0xf1,
0xb1, 0x2c, 0x92, 0x30, 0xeb, 0x1f, 0xbf, 0x91, 0x41, 0x4d, 0x2d, 0x63, 0xff, 0x4f, 0x00, 0x00,
0x00, 0xff, 0xff, 0xb9, 0xf2, 0x67, 0xbe, 0x64, 0x04, 0x00, 0x00,
}
func (m *WasmPlugin) Marshal() (dAtA []byte, err error) {
@@ -1024,7 +1024,7 @@ func (m *WasmPlugin) Unmarshal(dAtA []byte) error {
return io.ErrUnexpectedEOF
}
if m.Priority == nil {
m.Priority = &types.Int64Value{}
m.Priority = &types.Int32Value{}
}
if err := m.Priority.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err

View File

@@ -98,7 +98,7 @@ message WasmPlugin {
// 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;
google.protobuf.Int32Value priority = 10;
// Extended by Higress, the default configuration takes effect globally
google.protobuf.Struct default_config = 101;

View File

@@ -22,6 +22,7 @@ import (
"github.com/alibaba/higress/pkg/cmd/hgctl/kubernetes"
"github.com/alibaba/higress/pkg/cmd/options"
"istio.io/istio/istioctl/pkg/writer/envoy/configdump"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/yaml"
)
@@ -61,6 +62,23 @@ func NewDefaultGetEnvoyConfigOptions() *GetEnvoyConfigOptions {
}
}
func setupConfigdumpEnvoyConfigWriter(debug []byte, stdout io.Writer) (*configdump.ConfigWriter, error) {
cw := &configdump.ConfigWriter{Stdout: stdout}
err := cw.Prime(debug)
if err != nil {
return nil, err
}
return cw, nil
}
func GetEnvoyConfigWriter(config *GetEnvoyConfigOptions, stdout io.Writer) (*configdump.ConfigWriter, error) {
configDump, err := retrieveConfigDump(config.PodName, config.PodNamespace, config.BindAddress, config.IncludeEds)
if err != nil {
return nil, err
}
return setupConfigdumpEnvoyConfigWriter(configDump, stdout)
}
func GetEnvoyConfig(config *GetEnvoyConfigOptions) ([]byte, error) {
configDump, err := retrieveConfigDump(config.PodName, config.PodNamespace, config.BindAddress, config.IncludeEds)
if err != nil {
@@ -144,14 +162,12 @@ func formatGatewayConfig(configDump any, output string) ([]byte, error) {
if err != nil {
return nil, err
}
if output == "yaml" {
out, err = yaml.JSONToYAML(out)
if err != nil {
return nil, err
}
}
return out, nil
}

View File

@@ -18,10 +18,13 @@ import (
"fmt"
"os"
"istio.io/pkg/log"
"github.com/alibaba/higress/pkg/cmd"
)
func main() {
log.EnableKlogWithCobra()
if err := cmd.GetRootCommand().Execute(); err != nil {
_, _ = fmt.Fprintln(os.Stderr, err)
os.Exit(1)

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,14 @@
diff -Naur envoy/bazel/repository_locations.bzl envoy-new/bazel/repository_locations.bzl
--- envoy/bazel/repository_locations.bzl 2024-05-21 22:49:46.686598518 +0800
+++ envoy-new/bazel/repository_locations.bzl 2024-05-21 22:49:02.554597652 +0800
@@ -1031,8 +1031,8 @@
project_name = "WebAssembly for Proxies (C++ host implementation)",
project_desc = "WebAssembly for Proxies (C++ host implementation)",
project_url = "https://github.com/higress-group/proxy-wasm-cpp-host",
- version = "f8b624dc6c37d4e0a3c1b332652746793e2031ad",
- sha256 = "ba20328101c91d0ae6383947ced99620cd9b4ea22ab2fda6b26f343b38c3be83",
+ version = "cad2eb04d402dbf559101f3cb4f44da0d9c5b0b0",
+ sha256 = "4efbcc97c58994fab92c9dc50c051ad16463647d4c0c6df36a7204d2984c1e63",
strip_prefix = "proxy-wasm-cpp-host-{version}",
urls = ["https://github.com/higress-group/proxy-wasm-cpp-host/archive/{version}.tar.gz"],
use_category = ["dataplane_ext"],

View File

@@ -0,0 +1,25 @@
diff -Naur envoy/bazel/repository_locations.bzl envoy-new/bazel/repository_locations.bzl
--- envoy/bazel/repository_locations.bzl 2024-05-27 18:04:13.116443196 +0800
+++ envoy-new/bazel/repository_locations.bzl 2024-05-27 18:02:24.812441069 +0800
@@ -1031,8 +1031,8 @@
project_name = "WebAssembly for Proxies (C++ host implementation)",
project_desc = "WebAssembly for Proxies (C++ host implementation)",
project_url = "https://github.com/higress-group/proxy-wasm-cpp-host",
- version = "cad2eb04d402dbf559101f3cb4f44da0d9c5b0b0",
- sha256 = "4efbcc97c58994fab92c9dc50c051ad16463647d4c0c6df36a7204d2984c1e63",
+ version = "28a33a5a3e6c1ff8f53128a74e89aeca47850f68",
+ sha256 = "1aaa5898c169aeff115eff2fedf58095b3509d2e59861ad498e661a990d78b3d",
strip_prefix = "proxy-wasm-cpp-host-{version}",
urls = ["https://github.com/higress-group/proxy-wasm-cpp-host/archive/{version}.tar.gz"],
use_category = ["dataplane_ext"],
diff -Naur envoy/source/extensions/filters/http/wasm/wasm_filter.h envoy-new/source/extensions/filters/http/wasm/wasm_filter.h
--- envoy/source/extensions/filters/http/wasm/wasm_filter.h 2024-05-27 18:04:13.112443196 +0800
+++ envoy-new/source/extensions/filters/http/wasm/wasm_filter.h 2024-05-27 18:03:25.360442258 +0800
@@ -51,6 +51,7 @@
if (opt_ref->recover()) {
ENVOY_LOG(info, "wasm vm recover success");
wasm = opt_ref->handle()->wasmHandle()->wasm().get();
+ handle = opt_ref->handle();
} else {
ENVOY_LOG(info, "wasm vm recover failed");
failed = true;

View File

@@ -0,0 +1,259 @@
diff --git a/source/common/router/BUILD b/source/common/router/BUILD
index 5c58501..4db76cd 100644
--- a/source/common/router/BUILD
+++ b/source/common/router/BUILD
@@ -212,6 +212,7 @@ envoy_cc_library(
"//envoy/router:rds_interface",
"//envoy/router:scopes_interface",
"//envoy/thread_local:thread_local_interface",
+ "//source/common/protobuf:utility_lib",
"@envoy_api//envoy/config/route/v3:pkg_cc_proto",
"@envoy_api//envoy/extensions/filters/network/http_connection_manager/v3:pkg_cc_proto",
],
diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc
index ff7b4c8..5ac4523 100644
--- a/source/common/router/config_impl.cc
+++ b/source/common/router/config_impl.cc
@@ -550,19 +550,11 @@ RouteEntryImplBase::RouteEntryImplBase(const VirtualHostImpl& vhost,
"not be stripped: {}",
path_redirect_);
}
- ENVOY_LOG(info, "route stats is {}, name is {}", route.stat_prefix(), route.name());
if (!route.stat_prefix().empty()) {
route_stats_context_ = std::make_unique<RouteStatsContext>(
factory_context.scope(), factory_context.routerContext().routeStatNames(), vhost.statName(),
route.stat_prefix());
- } else if (!route.name().empty()) {
- // Added by Ingress
- // use route_name as default stat_prefix
- route_stats_context_ = std::make_unique<RouteStatsContext>(
- factory_context.scope(), factory_context.routerContext().routeStatNames(), vhost.statName(),
- route.name());
}
- // End Added
}
bool RouteEntryImplBase::evaluateRuntimeMatch(const uint64_t random_value) const {
@@ -1415,9 +1407,7 @@ VirtualHostImpl::VirtualHostImpl(
retry_shadow_buffer_limit_(PROTOBUF_GET_WRAPPED_OR_DEFAULT(
virtual_host, per_request_buffer_limit_bytes, std::numeric_limits<uint32_t>::max())),
include_attempt_count_in_request_(virtual_host.include_request_attempt_count()),
- include_attempt_count_in_response_(virtual_host.include_attempt_count_in_response()),
- virtual_cluster_catch_all_(*vcluster_scope_,
- factory_context.routerContext().virtualClusterStatNames()) {
+ include_attempt_count_in_response_(virtual_host.include_attempt_count_in_response()) {
switch (virtual_host.require_tls()) {
case envoy::config::route::v3::VirtualHost::NONE:
ssl_requirements_ = SslRequirements::None;
@@ -1478,10 +1468,14 @@ VirtualHostImpl::VirtualHostImpl(
}
}
- for (const auto& virtual_cluster : virtual_host.virtual_clusters()) {
- virtual_clusters_.push_back(
- VirtualClusterEntry(virtual_cluster, *vcluster_scope_,
- factory_context.routerContext().virtualClusterStatNames()));
+ if (!virtual_host.virtual_clusters().empty()) {
+ virtual_cluster_catch_all_ = std::make_unique<CatchAllVirtualCluster>(
+ *vcluster_scope_, factory_context.routerContext().virtualClusterStatNames());
+ for (const auto& virtual_cluster : virtual_host.virtual_clusters()) {
+ virtual_clusters_.push_back(
+ VirtualClusterEntry(virtual_cluster, *vcluster_scope_,
+ factory_context.routerContext().virtualClusterStatNames()));
+ }
}
if (virtual_host.has_cors()) {
@@ -1774,7 +1768,7 @@ VirtualHostImpl::virtualClusterFromEntries(const Http::HeaderMap& headers) const
}
if (!virtual_clusters_.empty()) {
- return &virtual_cluster_catch_all_;
+ return virtual_cluster_catch_all_.get();
}
return nullptr;
diff --git a/source/common/router/config_impl.h b/source/common/router/config_impl.h
index cf0ddf3..d83eb94 100644
--- a/source/common/router/config_impl.h
+++ b/source/common/router/config_impl.h
@@ -352,10 +352,10 @@ private:
const bool include_attempt_count_in_response_;
absl::optional<envoy::config::route::v3::RetryPolicy> retry_policy_;
absl::optional<envoy::config::route::v3::HedgePolicy> hedge_policy_;
- const CatchAllVirtualCluster virtual_cluster_catch_all_;
#if defined(ALIMESH)
std::vector<std::string> allow_server_names_;
#endif
+ std::unique_ptr<const CatchAllVirtualCluster> virtual_cluster_catch_all_;
};
using VirtualHostSharedPtr = std::shared_ptr<VirtualHostImpl>;
diff --git a/source/common/router/scoped_config_impl.cc b/source/common/router/scoped_config_impl.cc
index 594d571..6482615 100644
--- a/source/common/router/scoped_config_impl.cc
+++ b/source/common/router/scoped_config_impl.cc
@@ -7,6 +7,8 @@
#include "source/common/http/header_utility.h"
#endif
+#include "source/common/protobuf/utility.h"
+
namespace Envoy {
namespace Router {
@@ -239,7 +241,8 @@ HeaderValueExtractorImpl::computeFragment(const Http::HeaderMap& headers) const
ScopedRouteInfo::ScopedRouteInfo(envoy::config::route::v3::ScopedRouteConfiguration&& config_proto,
ConfigConstSharedPtr&& route_config)
- : config_proto_(std::move(config_proto)), route_config_(std::move(route_config)) {
+ : config_proto_(std::move(config_proto)), route_config_(std::move(route_config)),
+ config_hash_(MessageUtil::hash(config_proto)) {
// TODO(stevenzzzz): Maybe worth a KeyBuilder abstraction when there are more than one type of
// Fragment.
for (const auto& fragment : config_proto_.key().fragments()) {
diff --git a/source/common/router/scoped_config_impl.h b/source/common/router/scoped_config_impl.h
index 9f6a1b2..28e2ee5 100644
--- a/source/common/router/scoped_config_impl.h
+++ b/source/common/router/scoped_config_impl.h
@@ -154,11 +154,13 @@ public:
return config_proto_;
}
const std::string& scopeName() const { return config_proto_.name(); }
+ uint64_t configHash() const { return config_hash_; }
private:
envoy::config::route::v3::ScopedRouteConfiguration config_proto_;
ScopeKey scope_key_;
ConfigConstSharedPtr route_config_;
+ const uint64_t config_hash_;
};
using ScopedRouteInfoConstSharedPtr = std::shared_ptr<const ScopedRouteInfo>;
// Ordered map for consistent config dumping.
diff --git a/source/common/router/scoped_rds.cc b/source/common/router/scoped_rds.cc
index 133e91e..9b2096e 100644
--- a/source/common/router/scoped_rds.cc
+++ b/source/common/router/scoped_rds.cc
@@ -245,6 +245,11 @@ bool ScopedRdsConfigSubscription::addOrUpdateScopes(
dynamic_cast<const envoy::config::route::v3::ScopedRouteConfiguration&>(
resource.get().resource());
const std::string scope_name = scoped_route_config.name();
+ if (const auto& scope_info_iter = scoped_route_map_.find(scope_name);
+ scope_info_iter != scoped_route_map_.end() &&
+ scope_info_iter->second->configHash() == MessageUtil::hash(scoped_route_config)) {
+ continue;
+ }
rds.set_route_config_name(scoped_route_config.route_configuration_name());
std::unique_ptr<RdsRouteConfigProviderHelper> rds_config_provider_helper;
std::shared_ptr<ScopedRouteInfo> scoped_route_info = nullptr;
@@ -398,6 +403,7 @@ void ScopedRdsConfigSubscription::onRdsConfigUpdate(const std::string& scope_nam
auto new_scoped_route_info = std::make_shared<ScopedRouteInfo>(
envoy::config::route::v3::ScopedRouteConfiguration(iter->second->configProto()),
std::move(new_rds_config));
+ scoped_route_map_[new_scoped_route_info->scopeName()] = new_scoped_route_info;
applyConfigUpdate([new_scoped_route_info](ConfigProvider::ConfigConstSharedPtr config)
-> ConfigProvider::ConfigConstSharedPtr {
auto* thread_local_scoped_config =
diff --git a/source/common/router/scoped_rds.h b/source/common/router/scoped_rds.h
index d21d812..a510c1f 100644
--- a/source/common/router/scoped_rds.h
+++ b/source/common/router/scoped_rds.h
@@ -104,7 +104,7 @@ struct ScopedRdsStats {
// A scoped RDS subscription to be used with the dynamic scoped RDS ConfigProvider.
class ScopedRdsConfigSubscription
: public Envoy::Config::DeltaConfigSubscriptionInstance,
- Envoy::Config::SubscriptionBase<envoy::config::route::v3::ScopedRouteConfiguration> {
+ public Envoy::Config::SubscriptionBase<envoy::config::route::v3::ScopedRouteConfiguration> {
public:
using ScopedRouteConfigurationMap =
std::map<std::string, envoy::config::route::v3::ScopedRouteConfiguration>;
diff --git a/test/common/router/scoped_config_impl_test.cc b/test/common/router/scoped_config_impl_test.cc
index f63f258..69a2f4b 100644
--- a/test/common/router/scoped_config_impl_test.cc
+++ b/test/common/router/scoped_config_impl_test.cc
@@ -452,6 +452,24 @@ TEST_F(ScopedRouteInfoTest, Creation) {
EXPECT_EQ(info_->scopeKey(), makeKey({"foo", "bar"}));
}
+// Tests that config hash changes if ScopedRouteConfiguration of the ScopedRouteInfo changes.
+TEST_F(ScopedRouteInfoTest, Hash) {
+ const envoy::config::route::v3::ScopedRouteConfiguration config_copy = scoped_route_config_;
+ info_ = std::make_unique<ScopedRouteInfo>(scoped_route_config_, route_config_);
+ EXPECT_EQ(info_->routeConfig().get(), route_config_.get());
+ EXPECT_TRUE(TestUtility::protoEqual(info_->configProto(), config_copy));
+ EXPECT_EQ(info_->scopeName(), "foo_scope");
+ EXPECT_EQ(info_->scopeKey(), makeKey({"foo", "bar"}));
+
+ const auto info2 = std::make_unique<ScopedRouteInfo>(scoped_route_config_, route_config_);
+ ASSERT_EQ(info2->configHash(), info_->configHash());
+
+ // Mutate the config and hash should be different now.
+ scoped_route_config_.set_on_demand(true);
+ const auto info3 = std::make_unique<ScopedRouteInfo>(scoped_route_config_, route_config_);
+ ASSERT_NE(info3->configHash(), info_->configHash());
+}
+
class ScopedConfigImplTest : public testing::Test {
public:
void SetUp() override {
diff --git a/test/common/router/scoped_rds_test.cc b/test/common/router/scoped_rds_test.cc
index 09b96a6..b4776c9 100644
--- a/test/common/router/scoped_rds_test.cc
+++ b/test/common/router/scoped_rds_test.cc
@@ -13,6 +13,7 @@
#include "envoy/stats/scope.h"
#include "source/common/config/api_version.h"
+#include "source/common/config/config_provider_impl.h"
#include "source/common/config/grpc_mux_impl.h"
#include "source/common/protobuf/message_validator_impl.h"
#include "source/common/router/scoped_rds.h"
@@ -365,6 +366,48 @@ key:
"Didn't find a registered implementation for name: 'filter.unknown'");
}
+// Test that scopes with same config as existing scopes will be skipped in a config push.
+TEST_F(ScopedRdsTest, UnchangedScopesAreSkipped) {
+ setup();
+ init_watcher_.expectReady();
+ const std::string config_yaml = R"EOF(
+name: foo_scope
+route_configuration_name: foo_routes
+key:
+ fragments:
+ - string_key: x-foo-key
+)EOF";
+ const auto resource = parseScopedRouteConfigurationFromYaml(config_yaml);
+ const std::string config_yaml2 = R"EOF(
+name: foo_scope2
+route_configuration_name: foo_routes
+key:
+ fragments:
+ - string_key: x-bar-key
+)EOF";
+ const auto resource_2 = parseScopedRouteConfigurationFromYaml(config_yaml2);
+
+ // Delta API.
+ const auto decoded_resources = TestUtility::decodeResources({resource, resource_2});
+ context_init_manager_.initialize(init_watcher_);
+ EXPECT_NO_THROW(srds_subscription_->onConfigUpdate(decoded_resources.refvec_, {}, "v1"));
+ EXPECT_EQ(1UL,
+ server_factory_context_.scope_.counter("foo.scoped_rds.foo_scoped_routes.config_reload")
+ .value());
+ EXPECT_EQ(2UL, all_scopes_.value());
+ pushRdsConfig({"foo_routes"}, "111");
+ Envoy::Router::ScopedRdsConfigSubscription* srds_delta_subscription =
+ static_cast<Envoy::Router::ScopedRdsConfigSubscription*>(srds_subscription_);
+ ASSERT_NE(srds_delta_subscription, nullptr);
+ ASSERT_EQ("v1", srds_delta_subscription->configInfo()->last_config_version_);
+ // Push again the same set of config with different version number, the config will be skipped.
+ EXPECT_NO_THROW(srds_subscription_->onConfigUpdate(decoded_resources.refvec_, {}, "123"));
+ ASSERT_EQ("v1", srds_delta_subscription->configInfo()->last_config_version_);
+ EXPECT_EQ(2UL,
+ server_factory_context_.scope_.counter("foo.scoped_rds.foo_scoped_routes.config_reload")
+ .value());
+}
+
// Test ignoring the optional unknown factory in the per-virtualhost typed config.
TEST_F(ScopedRdsTest, OptionalUnknownFactoryForPerVirtualHostTypedConfig) {
OptionalHttpFilters optional_http_filters;

View File

@@ -0,0 +1,13 @@
diff --git a/source/common/http/headers.h b/source/common/http/headers.h
index a7a8a3393e..6af4a2852d 100644
--- a/source/common/http/headers.h
+++ b/source/common/http/headers.h
@@ -123,7 +123,7 @@ public:
const LowerCaseString TriCostTime{"req-cost-time"};
const LowerCaseString TriStartTime{"req-start-time"};
const LowerCaseString TriRespStartTime{"resp-start-time"};
- const LowerCaseString EnvoyOriginalHost{"original-host"};
+ const LowerCaseString EnvoyOriginalHost{"x-envoy-original-host"};
const LowerCaseString HigressOriginalService{"x-higress-original-service"};
} AliExtendedValues;
#endif

View File

@@ -0,0 +1,43 @@
diff --git a/source/extensions/common/wasm/context.cc b/source/extensions/common/wasm/context.cc
index 9642d8abd3..410baa856f 100644
--- a/source/extensions/common/wasm/context.cc
+++ b/source/extensions/common/wasm/context.cc
@@ -62,6 +62,21 @@ constexpr absl::string_view CelStateKeyPrefix = "wasm.";
#if defined(ALIMESH)
constexpr std::string_view ClearRouteCacheKey = "clear_route_cache";
constexpr std::string_view DisableClearRouteCache = "off";
+constexpr std::string_view SetDecoderBufferLimit = "set_decoder_buffer_limit";
+constexpr std::string_view SetEncoderBufferLimit = "set_encoder_buffer_limit";
+
+bool stringViewToUint32(std::string_view str, uint32_t& out_value) {
+ try {
+ unsigned long temp = std::stoul(std::string(str));
+ if (temp <= std::numeric_limits<uint32_t>::max()) {
+ out_value = static_cast<uint32_t>(temp);
+ return true;
+ }
+ } catch (const std::exception& e) {
+ ENVOY_LOG_MISC(critical, "stringToUint exception '{}'", e.what());
+ }
+ return false;
+}
#endif
using HashPolicy = envoy::config::route::v3::RouteAction::HashPolicy;
@@ -1280,6 +1295,16 @@ WasmResult Context::setProperty(std::string_view path, std::string_view value) {
} else {
disable_clear_route_cache_ = false;
}
+ } else if (path == SetDecoderBufferLimit && decoder_callbacks_) {
+ uint32_t buffer_limit;
+ if (stringViewToUint32(value, buffer_limit)) {
+ decoder_callbacks_->setDecoderBufferLimit(buffer_limit);
+ }
+ } else if (path == SetEncoderBufferLimit && encoder_callbacks_) {
+ uint32_t buffer_limit;
+ if (stringViewToUint32(value, buffer_limit)) {
+ encoder_callbacks_->setEncoderBufferLimit(buffer_limit);
+ }
}
#endif
if (!state->setValue(toAbslStringView(value))) {

View File

@@ -0,0 +1,106 @@
diff --git a/envoy/stream_info/stream_info.h b/envoy/stream_info/stream_info.h
index c6d82db4f4..09717673b0 100644
--- a/envoy/stream_info/stream_info.h
+++ b/envoy/stream_info/stream_info.h
@@ -613,7 +613,21 @@ public:
* @return the number of times the request was attempted upstream, absl::nullopt if the request
* was never attempted upstream.
*/
+
virtual absl::optional<uint32_t> attemptCount() const PURE;
+
+#ifdef ALIMESH
+ /**
+ * @param key the filter state key set by wasm filter.
+ * @param value the filter state value set by wasm filter.
+ */
+ virtual void setCustomSpanTag(const std::string& key, const std::string& value) PURE;
+
+ /**
+ * @return the key-value map of filter states set by wasm filter.
+ */
+ virtual const std::unordered_map<std::string, std::string>& getCustomSpanTagMap() const PURE;
+#endif
};
} // namespace StreamInfo
diff --git a/source/common/stream_info/stream_info_impl.h b/source/common/stream_info/stream_info_impl.h
index 6ce2afe773..d5e7a80b37 100644
--- a/source/common/stream_info/stream_info_impl.h
+++ b/source/common/stream_info/stream_info_impl.h
@@ -291,6 +291,20 @@ struct StreamInfoImpl : public StreamInfo {
absl::optional<uint32_t> attemptCount() const override { return attempt_count_; }
+#ifdef ALIMESH
+ void setCustomSpanTag(const std::string& key, const std::string& value) override {
+ auto it = custom_span_tags_.find(key);
+ if (it != custom_span_tags_.end()) {
+ it->second = value;
+ } else {
+ custom_span_tags_.emplace(key, value);
+ }
+ }
+
+ const std::unordered_map<std::string, std::string>& getCustomSpanTagMap() const override {
+ return custom_span_tags_;
+ }
+#endif
TimeSource& time_source_;
const SystemTime start_time_;
const MonotonicTime start_time_monotonic_;
@@ -350,6 +364,9 @@ private:
absl::optional<Upstream::ClusterInfoConstSharedPtr> upstream_cluster_info_;
std::string filter_chain_name_;
Tracing::Reason trace_reason_;
+#ifdef ALIMESH
+ std::unordered_map<std::string, std::string> custom_span_tags_;
+#endif
};
} // namespace StreamInfo
diff --git a/source/common/tracing/http_tracer_impl.cc b/source/common/tracing/http_tracer_impl.cc
index e55cf00e0a..f94e9101d7 100644
--- a/source/common/tracing/http_tracer_impl.cc
+++ b/source/common/tracing/http_tracer_impl.cc
@@ -214,6 +214,14 @@ void HttpTracerUtility::setCommonTags(Span& span, const Http::ResponseHeaderMap*
span.setTag(Tracing::Tags::get().Component, Tracing::Tags::get().Proxy);
+#ifdef ALIMESH
+ // Wasm filter state
+ const auto& custom_span_tags = stream_info.getCustomSpanTagMap();
+ for (const auto& it : custom_span_tags) {
+ span.setTag(it.first, it.second);
+ }
+#endif
+
if (nullptr != stream_info.upstreamHost()) {
span.setTag(Tracing::Tags::get().UpstreamCluster, stream_info.upstreamHost()->cluster().name());
span.setTag(Tracing::Tags::get().UpstreamClusterName,
diff --git a/source/extensions/common/wasm/context.cc b/source/extensions/common/wasm/context.cc
index 410baa856f..b11ecf1cd6 100644
--- a/source/extensions/common/wasm/context.cc
+++ b/source/extensions/common/wasm/context.cc
@@ -60,6 +60,7 @@ namespace {
constexpr absl::string_view CelStateKeyPrefix = "wasm.";
#if defined(ALIMESH)
+constexpr absl::string_view CustomeTraceSpanTagPrefix = "trace_span_tag.";
constexpr std::string_view ClearRouteCacheKey = "clear_route_cache";
constexpr std::string_view DisableClearRouteCache = "off";
constexpr std::string_view SetDecoderBufferLimit = "set_decoder_buffer_limit";
@@ -1271,6 +1272,13 @@ WasmResult Context::setProperty(std::string_view path, std::string_view value) {
if (!stream_info) {
return WasmResult::NotFound;
}
+#ifdef ALIMESH
+ if (absl::StartsWith(absl::string_view{path.data(), path.size()}, CustomeTraceSpanTagPrefix)) {
+ stream_info->setCustomSpanTag(std::string(path.substr(CustomeTraceSpanTagPrefix.size())),
+ std::string(value));
+ return WasmResult::Ok;
+ }
+#endif
std::string key;
absl::StrAppend(&key, CelStateKeyPrefix, toAbslStringView(path));
CelState* state;

341
get_helm.sh Executable file
View File

@@ -0,0 +1,341 @@
#!/usr/bin/env bash
# Copyright The Helm 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.
# The install script is based off of the MIT-licensed script from glide,
# the package manager for Go: https://github.com/Masterminds/glide.sh/blob/master/get
: ${BINARY_NAME:="helm"}
: ${USE_SUDO:="true"}
: ${DEBUG:="false"}
: ${VERIFY_CHECKSUM:="true"}
: ${VERIFY_SIGNATURES:="false"}
: ${HELM_INSTALL_DIR:="/usr/local/bin"}
: ${GPG_PUBRING:="pubring.kbx"}
HAS_CURL="$(type "curl" &> /dev/null && echo true || echo false)"
HAS_WGET="$(type "wget" &> /dev/null && echo true || echo false)"
HAS_OPENSSL="$(type "openssl" &> /dev/null && echo true || echo false)"
HAS_GPG="$(type "gpg" &> /dev/null && echo true || echo false)"
HAS_GIT="$(type "git" &> /dev/null && echo true || echo false)"
# initArch discovers the architecture for this system.
initArch() {
ARCH=$(uname -m)
case $ARCH in
armv5*) ARCH="armv5";;
armv6*) ARCH="armv6";;
armv7*) ARCH="arm";;
aarch64) ARCH="arm64";;
x86) ARCH="386";;
x86_64) ARCH="amd64";;
i686) ARCH="386";;
i386) ARCH="386";;
esac
}
# initOS discovers the operating system for this system.
initOS() {
OS=$(echo `uname`|tr '[:upper:]' '[:lower:]')
case "$OS" in
# Minimalist GNU for Windows
mingw*|cygwin*) OS='windows';;
esac
}
# runs the given command as root (detects if we are root already)
runAsRoot() {
if [ $EUID -ne 0 -a "$USE_SUDO" = "true" ]; then
sudo "${@}"
else
"${@}"
fi
}
# verifySupported checks that the os/arch combination is supported for
# binary builds, as well whether or not necessary tools are present.
verifySupported() {
local supported="darwin-amd64\ndarwin-arm64\nlinux-386\nlinux-amd64\nlinux-arm\nlinux-arm64\nlinux-ppc64le\nlinux-s390x\nlinux-riscv64\nwindows-amd64\nwindows-arm64"
if ! echo "${supported}" | grep -q "${OS}-${ARCH}"; then
echo "No prebuilt binary for ${OS}-${ARCH}."
echo "To build from source, go to https://github.com/helm/helm"
exit 1
fi
if [ "${HAS_CURL}" != "true" ] && [ "${HAS_WGET}" != "true" ]; then
echo "Either curl or wget is required"
exit 1
fi
if [ "${VERIFY_CHECKSUM}" == "true" ] && [ "${HAS_OPENSSL}" != "true" ]; then
echo "In order to verify checksum, openssl must first be installed."
echo "Please install openssl or set VERIFY_CHECKSUM=false in your environment."
exit 1
fi
if [ "${VERIFY_SIGNATURES}" == "true" ]; then
if [ "${HAS_GPG}" != "true" ]; then
echo "In order to verify signatures, gpg must first be installed."
echo "Please install gpg or set VERIFY_SIGNATURES=false in your environment."
exit 1
fi
if [ "${OS}" != "linux" ]; then
echo "Signature verification is currently only supported on Linux."
echo "Please set VERIFY_SIGNATURES=false or verify the signatures manually."
exit 1
fi
fi
if [ "${HAS_GIT}" != "true" ]; then
echo "[WARNING] Could not find git. It is required for plugin installation."
fi
}
# checkDesiredVersion checks if the desired version is available.
checkDesiredVersion() {
if [ "x$DESIRED_VERSION" == "x" ]; then
# Get tag from release URL
local latest_release_url="https://get.helm.sh/helm-latest-version"
local latest_release_response=""
if [ "${HAS_CURL}" == "true" ]; then
latest_release_response=$( curl -L --silent --show-error --fail "$latest_release_url" 2>&1 || true )
elif [ "${HAS_WGET}" == "true" ]; then
latest_release_response=$( wget "$latest_release_url" -q -O - 2>&1 || true )
fi
TAG=$( echo "$latest_release_response" | grep '^v[0-9]' )
if [ "x$TAG" == "x" ]; then
printf "Could not retrieve the latest release tag information from %s: %s\n" "${latest_release_url}" "${latest_release_response}"
exit 1
fi
else
TAG=$DESIRED_VERSION
fi
}
# checkHelmInstalledVersion checks which version of helm is installed and
# if it needs to be changed.
checkHelmInstalledVersion() {
if [[ -f "${HELM_INSTALL_DIR}/${BINARY_NAME}" ]]; then
local version=$("${HELM_INSTALL_DIR}/${BINARY_NAME}" version --template="{{ .Version }}")
if [[ "$version" == "$TAG" ]]; then
echo "Helm ${version} is already ${DESIRED_VERSION:-latest}"
return 0
else
echo "Helm ${TAG} is available. Changing from version ${version}."
return 1
fi
else
return 1
fi
}
# downloadFile downloads the latest binary package and also the checksum
# for that binary.
downloadFile() {
HELM_DIST="helm-$TAG-$OS-$ARCH.tar.gz"
DOWNLOAD_URL="https://get.helm.sh/$HELM_DIST"
CHECKSUM_URL="$DOWNLOAD_URL.sha256"
HELM_TMP_ROOT="$(mktemp -dt helm-installer-XXXXXX)"
HELM_TMP_FILE="$HELM_TMP_ROOT/$HELM_DIST"
HELM_SUM_FILE="$HELM_TMP_ROOT/$HELM_DIST.sha256"
echo "Downloading $DOWNLOAD_URL"
if [ "${HAS_CURL}" == "true" ]; then
curl -SsL "$CHECKSUM_URL" -o "$HELM_SUM_FILE"
curl -SsL "$DOWNLOAD_URL" -o "$HELM_TMP_FILE"
elif [ "${HAS_WGET}" == "true" ]; then
wget -q -O "$HELM_SUM_FILE" "$CHECKSUM_URL"
wget -q -O "$HELM_TMP_FILE" "$DOWNLOAD_URL"
fi
}
# verifyFile verifies the SHA256 checksum of the binary package
# and the GPG signatures for both the package and checksum file
# (depending on settings in environment).
verifyFile() {
if [ "${VERIFY_CHECKSUM}" == "true" ]; then
verifyChecksum
fi
if [ "${VERIFY_SIGNATURES}" == "true" ]; then
verifySignatures
fi
}
# installFile installs the Helm binary.
installFile() {
HELM_TMP="$HELM_TMP_ROOT/$BINARY_NAME"
mkdir -p "$HELM_TMP"
tar xf "$HELM_TMP_FILE" -C "$HELM_TMP"
HELM_TMP_BIN="$HELM_TMP/$OS-$ARCH/helm"
echo "Preparing to install $BINARY_NAME into ${HELM_INSTALL_DIR}"
runAsRoot cp "$HELM_TMP_BIN" "$HELM_INSTALL_DIR/$BINARY_NAME"
echo "$BINARY_NAME installed into $HELM_INSTALL_DIR/$BINARY_NAME"
}
# verifyChecksum verifies the SHA256 checksum of the binary package.
verifyChecksum() {
printf "Verifying checksum... "
local sum=$(openssl sha1 -sha256 ${HELM_TMP_FILE} | awk '{print $2}')
local expected_sum=$(cat ${HELM_SUM_FILE})
if [ "$sum" != "$expected_sum" ]; then
echo "SHA sum of ${HELM_TMP_FILE} does not match. Aborting."
exit 1
fi
echo "Done."
}
# verifySignatures obtains the latest KEYS file from GitHub main branch
# as well as the signature .asc files from the specific GitHub release,
# then verifies that the release artifacts were signed by a maintainer's key.
verifySignatures() {
printf "Verifying signatures... "
local keys_filename="KEYS"
local github_keys_url="https://raw.githubusercontent.com/helm/helm/main/${keys_filename}"
if [ "${HAS_CURL}" == "true" ]; then
curl -SsL "${github_keys_url}" -o "${HELM_TMP_ROOT}/${keys_filename}"
elif [ "${HAS_WGET}" == "true" ]; then
wget -q -O "${HELM_TMP_ROOT}/${keys_filename}" "${github_keys_url}"
fi
local gpg_keyring="${HELM_TMP_ROOT}/keyring.gpg"
local gpg_homedir="${HELM_TMP_ROOT}/gnupg"
mkdir -p -m 0700 "${gpg_homedir}"
local gpg_stderr_device="/dev/null"
if [ "${DEBUG}" == "true" ]; then
gpg_stderr_device="/dev/stderr"
fi
gpg --batch --quiet --homedir="${gpg_homedir}" --import "${HELM_TMP_ROOT}/${keys_filename}" 2> "${gpg_stderr_device}"
gpg --batch --no-default-keyring --keyring "${gpg_homedir}/${GPG_PUBRING}" --export > "${gpg_keyring}"
local github_release_url="https://github.com/helm/helm/releases/download/${TAG}"
if [ "${HAS_CURL}" == "true" ]; then
curl -SsL "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" -o "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc"
curl -SsL "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" -o "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc"
elif [ "${HAS_WGET}" == "true" ]; then
wget -q -O "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc"
wget -q -O "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc"
fi
local error_text="If you think this might be a potential security issue,"
error_text="${error_text}\nplease see here: https://github.com/helm/community/blob/master/SECURITY.md"
local num_goodlines_sha=$(gpg --verify --keyring="${gpg_keyring}" --status-fd=1 "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" 2> "${gpg_stderr_device}" | grep -c -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)')
if [[ ${num_goodlines_sha} -lt 2 ]]; then
echo "Unable to verify the signature of helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256!"
echo -e "${error_text}"
exit 1
fi
local num_goodlines_tar=$(gpg --verify --keyring="${gpg_keyring}" --status-fd=1 "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" 2> "${gpg_stderr_device}" | grep -c -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)')
if [[ ${num_goodlines_tar} -lt 2 ]]; then
echo "Unable to verify the signature of helm-${TAG}-${OS}-${ARCH}.tar.gz!"
echo -e "${error_text}"
exit 1
fi
echo "Done."
}
# fail_trap is executed if an error occurs.
fail_trap() {
result=$?
if [ "$result" != "0" ]; then
if [[ -n "$INPUT_ARGUMENTS" ]]; then
echo "Failed to install $BINARY_NAME with the arguments provided: $INPUT_ARGUMENTS"
help
else
echo "Failed to install $BINARY_NAME"
fi
echo -e "\tFor support, go to https://github.com/helm/helm."
fi
cleanup
exit $result
}
# testVersion tests the installed client to make sure it is working.
testVersion() {
set +e
HELM="$(command -v $BINARY_NAME)"
if [ "$?" = "1" ]; then
echo "$BINARY_NAME not found. Is $HELM_INSTALL_DIR on your "'$PATH?'
exit 1
fi
set -e
}
# help provides possible cli installation arguments
help () {
echo "Accepted cli arguments are:"
echo -e "\t[--help|-h ] ->> prints this help"
echo -e "\t[--version|-v <desired_version>] . When not defined it fetches the latest release from GitHub"
echo -e "\te.g. --version v3.0.0 or -v canary"
echo -e "\t[--no-sudo] ->> install without sudo"
}
# cleanup temporary files to avoid https://github.com/helm/helm/issues/2977
cleanup() {
if [[ -d "${HELM_TMP_ROOT:-}" ]]; then
rm -rf "$HELM_TMP_ROOT"
fi
}
# Execution
#Stop execution on any error
trap "fail_trap" EXIT
set -e
# Set debug if desired
if [ "${DEBUG}" == "true" ]; then
set -x
fi
# Parsing input arguments (if any)
export INPUT_ARGUMENTS="${@}"
set -u
while [[ $# -gt 0 ]]; do
case $1 in
'--version'|-v)
shift
if [[ $# -ne 0 ]]; then
export DESIRED_VERSION="${1}"
if [[ "$1" != "v"* ]]; then
echo "Expected version arg ('${DESIRED_VERSION}') to begin with 'v', fixing..."
export DESIRED_VERSION="v${1}"
fi
else
echo -e "Please provide the desired version. e.g. --version v3.0.0 or -v canary"
exit 0
fi
;;
'--no-sudo')
USE_SUDO="false"
;;
'--help'|-h)
help
exit 0
;;
*) exit 1
;;
esac
shift
done
set +u
initArch
initOS
verifySupported
checkDesiredVersion
if ! checkHelmInstalledVersion; then
downloadFile
verifyFile
installFile
fi
testVersion
cleanup

31
go.mod
View File

@@ -44,13 +44,13 @@ require (
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.8.1
github.com/stretchr/testify v1.8.3
go.uber.org/atomic v1.9.0
go.uber.org/atomic v1.11.0
google.golang.org/grpc v1.48.0
google.golang.org/protobuf v1.28.1
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
istio.io/api v0.0.0-20211122181927-8da52c66ff23
istio.io/client-go v1.12.0-rc.1.0.20211118171212-b744b6f111e4
istio.io/client-go v1.12.0-rc.1.0.20211118171212-b744b6f111e4 // indirect
istio.io/gogo-genproto v0.0.0-20211115195057-0e34bdd2be67
istio.io/istio v0.0.0
istio.io/pkg v0.0.0-20211115195056-e379f31ee62a
@@ -172,6 +172,7 @@ require (
github.com/json-iterator/go v1.1.12 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/klauspost/compress v1.15.9 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
@@ -185,6 +186,7 @@ require (
github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f // indirect
github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect
github.com/lib/pq v1.10.0 // indirect
github.com/libdns/libdns v0.2.1 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
@@ -194,7 +196,7 @@ require (
github.com/mattn/go-shellwords v1.0.12 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/miekg/dns v1.1.43 // indirect
github.com/miekg/dns v1.1.55 // indirect
github.com/miekg/pkcs11 v1.1.1 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
@@ -248,20 +250,21 @@ require (
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect
github.com/yl2chen/cidranger v1.0.2 // indirect
github.com/zeebo/blake3 v0.2.3 // indirect
go.opencensus.io v0.23.0 // indirect
go.opentelemetry.io/proto/otlp v0.12.0 // indirect
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
go.uber.org/multierr v1.7.0 // indirect
go.uber.org/zap v1.21.0 // indirect
golang.org/x/crypto v0.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/mod v0.11.0 // indirect
golang.org/x/oauth2 v0.6.0 // indirect
golang.org/x/sync v0.2.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/term v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/term v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect
golang.org/x/tools v0.10.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
gomodules.xyz/jsonpatch/v3 v3.0.1 // indirect
gomodules.xyz/orderedmap v0.1.0 // indirect
@@ -300,11 +303,17 @@ replace istio.io/client-go => ./external/client-go
replace istio.io/istio => ./external/istio
replace github.com/caddyserver/certmagic => github.com/2456868764/certmagic v1.0.2
require (
github.com/caddyserver/certmagic v0.20.0
github.com/evanphx/json-patch/v5 v5.6.0
github.com/google/yamlfmt v0.10.0
github.com/kylelemons/godebug v1.1.0
github.com/mholt/acmez v1.2.0
github.com/tidwall/gjson v1.17.0
go.uber.org/zap v1.24.0
golang.org/x/net v0.17.0
helm.sh/helm/v3 v3.7.1
k8s.io/apiextensions-apiserver v0.25.4
knative.dev/networking v0.0.0-20220302134042-e8b2eb995165

58
go.sum
View File

@@ -61,6 +61,8 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/2456868764/certmagic v1.0.2 h1:xYoN4z6seONwT85llWXZcASvQME8TOSiSWQvLJsGGsE=
github.com/2456868764/certmagic v1.0.2/go.mod h1:LOn81EQYMPajdew6Ln6SVdHPxPqPv6jwsUg92kiNlcQ=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20210929163055-e81b3f25be97/go.mod h1:WpB7kf89yJUETZxQnP1kgYPNwlT2jjdDYUCoxVggM3g=
github.com/AlecAivazis/survey/v2 v2.3.6 h1:NvTuVHISgTHEHeBFqt6BHOe4Ny/NwGZr7w+F8S9ziyw=
github.com/AlecAivazis/survey/v2 v2.3.6/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI=
@@ -1006,6 +1008,9 @@ github.com/klauspost/compress v1.13.0/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -1055,6 +1060,8 @@ github.com/lib/pq v0.0.0-20150723085316-0dad96c0b94f/go.mod h1:5WUZQaWbwv1U+lTRe
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.0 h1:Zx5DJFEYQXio93kgXnQ09fXNiUKsqv4OUEu2UtGcB1E=
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis=
github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
@@ -1145,13 +1152,16 @@ github.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqA
github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30=
github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.17/go.mod h1:WgzbA6oji13JREwiNsRDNfl7jYdPnmz+VEuLrA+/48M=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo=
github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
@@ -1658,6 +1668,12 @@ github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
github.com/zclconf/go-cty v1.4.0/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ=
github.com/zclconf/go-cty v1.7.1/go.mod h1:VDR4+I79ubFBGm1uJac1226K5yANQFHeauxPBoP54+o=
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ=
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
@@ -1711,8 +1727,9 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
@@ -1722,8 +1739,9 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec=
go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
@@ -1733,8 +1751,9 @@ go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -1775,8 +1794,8 @@ golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1817,7 +1836,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1894,8 +1914,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -1932,8 +1952,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -2074,15 +2094,16 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -2092,8 +2113,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -2182,7 +2203,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -1,5 +1,5 @@
apiVersion: v2
appVersion: 1.3.4
appVersion: 1.4.2
description: Helm chart for deploying higress gateways
icon: https://higress.io/img/higress_logo_small.png
home: http://higress.io/
@@ -10,4 +10,4 @@ name: higress-core
sources:
- http://github.com/alibaba/higress
type: application
version: 1.3.4
version: 1.4.2

View File

@@ -3,9 +3,13 @@
# Refer to https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md#21-trust-domain
trustDomain: "cluster.local"
accessLogEncoding: TEXT
{{- if .Values.global.o11y.enabled }}
accessLogFile: "/var/log/proxy/access.log"
{{- else }}
accessLogFile: "/dev/stdout"
{{- end }}
ingressControllerMode: "OFF"
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)%"}
accessLogFormat: '{"authority":"%REQ(X-ENVOY-ORIGINAL-HOST?: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
@@ -84,7 +88,7 @@
{{- if .Values.global.enableHigressIstio }}
discoveryAddress: {{ printf "istiod.%s.svc" .Values.global.istioNamespace }}:15012
{{- else }}
discoveryAddress: higress-controller.{{.Release.Namespace}}.svc:15012
discoveryAddress: {{ include "controller.name" . }}.{{.Release.Namespace}}.svc:15012
{{- end }}
{{- end }}
proxyStatsMatcher:

View File

@@ -9,7 +9,7 @@ rules:
# ingress controller
- apiGroups: ["extensions", "networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "list", "watch"]
verbs: ["create", "get", "list", "watch", "update", "delete", "patch"]
- apiGroups: ["extensions", "networking.k8s.io"]
resources: ["ingresses/status"]
verbs: ["*"]
@@ -36,7 +36,7 @@ rules:
# Needed for multicluster secret reading, possibly ingress certs in the future
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "watch", "list"]
verbs: ["get", "watch", "list", "create", "update", "delete", "patch"]
- apiGroups: ["networking.higress.io"]
resources: ["mcpbridges"]
@@ -61,12 +61,12 @@ rules:
# discovery and routing
- apiGroups: [""]
resources: ["pods", "nodes", "services", "namespaces", "endpoints"]
resources: ["pods", "nodes", "services", "namespaces", "endpoints", "deployments"]
verbs: ["get", "list", "watch"]
- apiGroups: ["discovery.k8s.io"]
resources: ["endpointslices"]
verbs: ["get", "list", "watch"]
# Istiod and bootstrap.
- apiGroups: ["certificates.k8s.io"]
resources:
@@ -100,7 +100,7 @@ rules:
- apiGroups: ["multicluster.x-k8s.io"]
resources: ["serviceimports"]
verbs: ["get", "watch", "list"]
# sidecar injection controller
- apiGroups: ["admissionregistration.k8s.io"]
resources: ["mutatingwebhookconfigurations"]

View File

@@ -26,9 +26,70 @@ spec:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "controller.serviceAccountName" . }}
{{- if .Values.global.priorityClassName }}
priorityClassName: "{{ .Values.global.priorityClassName }}"
{{- end }}
securityContext:
{{- toYaml .Values.controller.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.controller.securityContext | nindent 12 }}
image: "{{ .Values.controller.hub | default .Values.global.hub }}/{{ .Values.controller.image | default "higress" }}:{{ .Values.controller.tag | default .Chart.AppVersion }}"
args:
- "serve"
- --gatewaySelectorKey=higress
- --gatewaySelectorValue={{ .Release.Namespace }}-{{ include "gateway.name" . }}
- --gatewayHttpPort={{ .Values.gateway.httpPort }}
- --gatewayHttpsPort={{ .Values.gateway.httpsPort }}
{{- if not .Values.global.enableStatus }}
- --enableStatus={{ .Values.global.enableStatus }}
{{- end }}
- --ingressClass={{ .Values.global.ingressClass }}
{{- if .Values.global.watchNamespace }}
- --watchNamespace={{ .Values.global.watchNamespace }}
{{- end }}
- --enableAutomaticHttps={{ .Values.controller.automaticHttps.enabled }}
- --automaticHttpsEmail={{ .Values.controller.automaticHttps.email }}
env:
- 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: DOMAIN_SUFFIX
value: {{ .Values.global.proxy.clusterDomain }}
{{- if .Values.controller.env }}
{{- range $key, $val := .Values.controller.env }}
- name: {{ $key }}
value: "{{ $val }}"
{{- end }}
{{- end }}
ports:
{{- range $idx, $port := .Values.controller.ports }}
- name: {{ $port.name }}
containerPort: {{ $port.port }}
protocol: {{ $port.protocol }}
{{- end }}
readinessProbe:
{{- toYaml .Values.controller.probe | nindent 12 }}
{{- if not (or .Values.global.local .Values.global.kind) }}
resources:
{{- toYaml .Values.controller.resources | nindent 12 }}
{{- end }}
volumeMounts:
- name: log
mountPath: /var/log
{{- if not .Values.global.enableHigressIstio }}
- name: discovery
image: "{{ .Values.pilot.hub | default .Values.global.hub }}/{{ .Values.pilot.image | default "pilot" }}:{{ .Values.pilot.tag | default .Chart.AppVersion }}"
@@ -70,6 +131,10 @@ spec:
periodSeconds: 3
timeoutSeconds: 5
env:
- name: PILOT_ENABLE_HEADLESS_SERVICE_POD_LISTENERS
value: "false"
- name: HIGRESS_SYSTEM_NS
value: "{{ .Release.Namespace }}"
- name: DEFAULT_UPSTREAM_CONCURRENCY_THRESHOLD
value: "{{ .Values.global.defaultUpstreamConcurrencyThreshold }}"
- name: ISTIO_GPRC_MAXRECVMSGSIZE
@@ -187,60 +252,6 @@ spec:
mountPath: /cacerts
{{- end }}
{{- end }}
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.controller.securityContext | nindent 12 }}
image: "{{ .Values.controller.hub | default .Values.global.hub }}/{{ .Values.controller.image | default "higress" }}:{{ .Values.controller.tag | default .Chart.AppVersion }}"
args:
- "serve"
- --gatewaySelectorKey=higress
- --gatewaySelectorValue={{ .Release.Namespace }}-{{ include "gateway.name" . }}
{{- if not .Values.global.enableStatus }}
- --enableStatus={{ .Values.global.enableStatus }}
{{- end }}
- --ingressClass={{ .Values.global.ingressClass }}
{{- if .Values.global.watchNamespace }}
- --watchNamespace={{ .Values.global.watchNamespace }}
{{- end }}
env:
- 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: DOMAIN_SUFFIX
value: {{ .Values.global.proxy.clusterDomain }}
{{- if .Values.controller.env }}
{{- range $key, $val := .Values.controller.env }}
- name: {{ $key }}
value: "{{ $val }}"
{{- end }}
{{- end }}
ports:
{{- range $idx, $port := .Values.controller.ports }}
- name: {{ $port.name }}
containerPort: {{ $port.port }}
protocol: {{ $port.protocol }}
{{- end }}
readinessProbe:
{{- toYaml .Values.controller.probe | nindent 12 }}
{{- if not (or .Values.global.local .Values.global.kind) }}
resources:
{{- toYaml .Values.controller.resources | nindent 12 }}
{{- end }}
volumeMounts:
- name: log
mountPath: /var/log
{{- with .Values.controller.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}

View File

@@ -0,0 +1,332 @@
{{- if eq .Values.gateway.kind "DaemonSet" -}}
{{- $o11y := .Values.global.o11y }}
{{- $unprivilegedPortSupported := true }}
{{- range $index, $node := (lookup "v1" "Node" "default" "").items }}
{{- $kernelVersion := $node.status.nodeInfo.kernelVersion }}
{{- if $kernelVersion }}
{{- $kernelVersion = regexFind "^(\\d+\\.\\d+\\.\\d+)" $kernelVersion }}
{{- if and $kernelVersion (semverCompare "<4.11.0" $kernelVersion) }}
{{- $unprivilegedPortSupported = false }}
{{- end }}
{{- end }}
{{- end -}}
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: {{ include "gateway.name" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "gateway.labels" . | nindent 4}}
annotations:
{{- .Values.gateway.annotations | toYaml | nindent 4 }}
spec:
selector:
matchLabels:
{{- include "gateway.selectorLabels" . | nindent 6 }}
template:
metadata:
annotations:
{{- if .Values.global.enableHigressIstio }}
"enableHigressIstio": "true"
{{- end }}
{{- if .Values.gateway.podAnnotations }}
{{- toYaml .Values.gateway.podAnnotations | nindent 8 }}
{{- end }}
labels:
sidecar.istio.io/inject: "false"
{{- with .Values.gateway.revision }}
istio.io/rev: {{ . }}
{{- end }}
{{- include "gateway.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.gateway.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "gateway.serviceAccountName" . }}
{{- if .Values.global.priorityClassName }}
priorityClassName: "{{ .Values.global.priorityClassName }}"
{{- end }}
securityContext:
{{- if .Values.gateway.securityContext }}
{{- toYaml .Values.gateway.securityContext | nindent 8 }}
{{- else if and $unprivilegedPortSupported (and (not .Values.gateway.hostNetwork) (semverCompare ">=1.22-0" .Capabilities.KubeVersion.GitVersion)) }}
# Safe since 1.22: https://github.com/kubernetes/kubernetes/pull/103326
sysctls:
- name: net.ipv4.ip_unprivileged_port_start
value: "0"
{{- end }}
containers:
{{- if $o11y.enabled }}
{{- $config := $o11y.promtail }}
- name: promtail
image: {{ $config.image.repository }}:{{ $config.image.tag }}
imagePullPolicy: IfNotPresent
args:
- -config.file=/etc/promtail/promtail.yaml
env:
- name: 'HOSTNAME'
valueFrom:
fieldRef:
fieldPath: 'spec.nodeName'
ports:
- containerPort: {{ $config.port }}
name: http-metrics
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /ready
port: {{ $config.port }}
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
volumeMounts:
- name: promtail-config
mountPath: "/etc/promtail"
- name: log
mountPath: /var/log/proxy
- name: tmp
mountPath: /tmp
{{- end }}
- name: higress-gateway
image: "{{ .Values.gateway.hub | default .Values.global.hub }}/{{ .Values.gateway.image | default "gateway" }}:{{ .Values.gateway.tag | default .Chart.AppVersion }}"
args:
- proxy
- router
- --domain
- $(POD_NAMESPACE).svc.cluster.local
- --proxyLogLevel=warning
- --proxyComponentLogLevel=misc:error
- --log_output_level=all:info
- --serviceCluster=higress-gateway
securityContext:
{{- if .Values.gateway.containerSecurityContext }}
{{- toYaml .Values.gateway.containerSecurityContext | nindent 12 }}
{{- else if and $unprivilegedPortSupported (and (not .Values.gateway.hostNetwork) (semverCompare ">=1.22-0" .Capabilities.KubeVersion.GitVersion)) }}
# Safe since 1.22: https://github.com/kubernetes/kubernetes/pull/103326
capabilities:
drop:
- ALL
allowPrivilegeEscalation: false
privileged: false
# When enabling lite metrics, the configuration template files need to be replaced.
{{- if not .Values.global.liteMetrics }}
readOnlyRootFilesystem: true
{{- end }}
runAsUser: 1337
runAsGroup: 1337
runAsNonRoot: true
{{- else }}
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
runAsUser: 0
runAsGroup: 1337
runAsNonRoot: false
allowPrivilegeEscalation: true
{{- end }}
env:
- name: NODE_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: INSTANCE_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.podIP
- name: HOST_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.hostIP
- name: SERVICE_ACCOUNT
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
- name: PILOT_XDS_SEND_TIMEOUT
value: 60s
- name: PROXY_XDS_VIA_AGENT
value: "true"
- name: ENABLE_INGRESS_GATEWAY_SDS
value: "false"
- name: JWT_POLICY
value: {{ include "controller.jwtPolicy" . }}
- name: ISTIO_META_HTTP10
value: "1"
- name: ISTIO_META_CLUSTER_ID
value: "{{ $.Values.clusterName | default `Kubernetes` }}"
- name: INSTANCE_NAME
value: "higress-gateway"
{{- if .Values.global.liteMetrics }}
- name: LITE_METRICS
value: "on"
{{- end }}
{{- if include "skywalking.enabled" . }}
- name: ISTIO_BOOTSTRAP_OVERRIDE
value: /etc/istio/custom-bootstrap/custom_bootstrap.json
{{- end }}
{{- with .Values.gateway.networkGateway }}
- name: ISTIO_META_REQUESTED_NETWORK_VIEW
value: "{{.}}"
{{- end }}
{{- range $key, $val := .Values.env }}
- name: {{ $key }}
value: {{ $val | quote }}
{{- end }}
ports:
- containerPort: 15090
protocol: TCP
name: http-envoy-prom
{{- if or .Values.global.local .Values.global.kind }}
- containerPort: {{ .Values.gateway.httpPort }}
hostPort: {{ .Values.gateway.httpPort }}
name: http
protocol: TCP
- containerPort: {{ .Values.gateway.httpsPort }}
hostPort: {{ .Values.gateway.httpsPort }}
name: https
protocol: TCP
{{- end }}
readinessProbe:
failureThreshold: {{ .Values.gateway.readinessFailureThreshold }}
httpGet:
path: /healthz/ready
port: 15021
scheme: HTTP
initialDelaySeconds: {{ .Values.gateway.readinessInitialDelaySeconds }}
periodSeconds: {{ .Values.gateway.readinessPeriodSeconds }}
successThreshold: {{ .Values.gateway.readinessSuccessThreshold }}
timeoutSeconds: {{ .Values.gateway.readinessTimeoutSeconds }}
{{- if not (or .Values.global.local .Values.global.kind) }}
resources:
{{- toYaml .Values.gateway.resources | nindent 12 }}
{{- end }}
volumeMounts:
{{- if eq (include "controller.jwtPolicy" .) "third-party-jwt" }}
- name: istio-token
mountPath: /var/run/secrets/tokens
readOnly: true
{{- end }}
- name: config
mountPath: /etc/istio/config
- name: istio-ca-root-cert
mountPath: /var/run/secrets/istio
- name: istio-data
mountPath: /var/lib/istio/data
- name: podinfo
mountPath: /etc/istio/pod
- name: proxy-socket
mountPath: /etc/istio/proxy
{{- if include "skywalking.enabled" . }}
- mountPath: /etc/istio/custom-bootstrap
name: custom-bootstrap-volume
{{- end }}
{{- if .Values.global.volumeWasmPlugins }}
- mountPath: /opt/plugins
name: local-wasmplugins-volume
{{- end }}
{{- if $o11y.enabled }}
- mountPath: /var/log/proxy
name: log
{{- end }}
{{- if .Values.gateway.hostNetwork }}
hostNetwork: {{ .Values.gateway.hostNetwork }}
dnsPolicy: ClusterFirstWithHostNet
{{- end }}
{{- with .Values.gateway.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.gateway.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.gateway.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
volumes:
{{- if eq (include "controller.jwtPolicy" .) "third-party-jwt" }}
- name: istio-token
projected:
sources:
- serviceAccountToken:
audience: istio-ca
expirationSeconds: 43200
path: istio-token
{{- end }}
- name: istio-ca-root-cert
configMap:
{{- if .Values.global.enableHigressIstio }}
name: istio-ca-root-cert
{{- else }}
name: higress-ca-root-cert
{{- end }}
- name: config
configMap:
name: higress-config
{{- if include "skywalking.enabled" . }}
- configMap:
defaultMode: 420
name: higress-custom-bootstrap
name: custom-bootstrap-volume
{{- end }}
- name: istio-data
emptyDir: {}
- name: proxy-socket
emptyDir: {}
{{- if $o11y.enabled }}
- name: log
emptyDir: {}
- name: tmp
emptyDir: {}
- name: promtail-config
configMap:
name: higress-promtail
{{- end }}
- name: podinfo
downwardAPI:
defaultMode: 420
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.labels
path: labels
- fieldRef:
apiVersion: v1
fieldPath: metadata.annotations
path: annotations
- path: cpu-request
resourceFieldRef:
containerName: higress-gateway
divisor: 1m
resource: requests.cpu
- path: cpu-limit
resourceFieldRef:
containerName: higress-gateway
divisor: 1m
resource: limits.cpu
{{- if .Values.global.volumeWasmPlugins }}
- name: local-wasmplugins-volume
hostPath:
path: /opt/plugins
type: Directory
{{- end }}
{{- end }}

View File

@@ -1,3 +1,5 @@
{{- if eq .Values.gateway.kind "Deployment" -}}
{{- $o11y := .Values.global.o11y }}
{{- $unprivilegedPortSupported := true }}
{{- range $index, $node := (lookup "v1" "Node" "default" "").items }}
{{- $kernelVersion := $node.status.nodeInfo.kernelVersion }}
@@ -57,6 +59,9 @@ spec:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "gateway.serviceAccountName" . }}
{{- if .Values.global.priorityClassName }}
priorityClassName: "{{ .Values.global.priorityClassName }}"
{{- end }}
securityContext:
{{- if .Values.gateway.securityContext }}
{{- toYaml .Values.gateway.securityContext | nindent 8 }}
@@ -88,7 +93,10 @@ spec:
- ALL
allowPrivilegeEscalation: false
privileged: false
# When enabling lite metrics, the configuration template files need to be replaced.
{{- if not .Values.global.liteMetrics }}
readOnlyRootFilesystem: true
{{- end }}
runAsUser: 1337
runAsGroup: 1337
runAsNonRoot: true
@@ -102,7 +110,6 @@ spec:
runAsGroup: 1337
runAsNonRoot: false
allowPrivilegeEscalation: true
readOnlyRootFilesystem: true
{{- end }}
env:
- name: NODE_NAME
@@ -148,6 +155,10 @@ spec:
value: "{{ $.Values.clusterName | default `Kubernetes` }}"
- name: INSTANCE_NAME
value: "higress-gateway"
{{- if .Values.global.liteMetrics }}
- name: LITE_METRICS
value: "on"
{{- end }}
{{- if include "skywalking.enabled" . }}
- name: ISTIO_BOOTSTRAP_OVERRIDE
value: /etc/istio/custom-bootstrap/custom_bootstrap.json
@@ -161,16 +172,19 @@ spec:
value: {{ $val | quote }}
{{- end }}
ports:
- containerPort: 15020
protocol: TCP
name: istio-prom
- containerPort: 15090
protocol: TCP
name: http-envoy-prom
{{- if or .Values.global.local .Values.global.kind }}
- containerPort: 80
hostPort: 80
- containerPort: {{ .Values.gateway.httpPort }}
hostPort: {{ .Values.gateway.httpPort }}
name: http
protocol: TCP
- containerPort: 443
hostPort: 443
- containerPort: {{ .Values.gateway.httpsPort }}
hostPort: {{ .Values.gateway.httpsPort }}
name: https
protocol: TCP
{{- end }}
@@ -200,7 +214,7 @@ spec:
mountPath: /var/run/secrets/istio
- name: istio-data
mountPath: /var/lib/istio/data
- name: podinfo
- name: podinfo
mountPath: /etc/istio/pod
- name: proxy-socket
mountPath: /etc/istio/proxy
@@ -212,6 +226,44 @@ spec:
- mountPath: /opt/plugins
name: local-wasmplugins-volume
{{- end }}
{{- if $o11y.enabled }}
- mountPath: /var/log/proxy
name: log
{{- end }}
{{- if $o11y.enabled }}
{{- $config := $o11y.promtail }}
- name: promtail
image: {{ $config.image.repository }}:{{ $config.image.tag }}
imagePullPolicy: IfNotPresent
args:
- -config.file=/etc/promtail/promtail.yaml
env:
- name: 'HOSTNAME'
valueFrom:
fieldRef:
fieldPath: 'spec.nodeName'
ports:
- containerPort: {{ $config.port }}
name: http-metrics
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /ready
port: {{ $config.port }}
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
volumeMounts:
- name: promtail-config
mountPath: "/etc/promtail"
- name: log
mountPath: /var/log/proxy
- name: tmp
mountPath: /tmp
{{- end }}
{{- if .Values.gateway.hostNetwork }}
hostNetwork: {{ .Values.gateway.hostNetwork }}
dnsPolicy: ClusterFirstWithHostNet
@@ -258,6 +310,15 @@ spec:
emptyDir: {}
- name: proxy-socket
emptyDir: {}
{{- if $o11y.enabled }}
- name: log
emptyDir: {}
- name: tmp
emptyDir: {}
- name: promtail-config
configMap:
name: higress-promtail
{{- end }}
- name: podinfo
downwardAPI:
defaultMode: 420
@@ -286,3 +347,4 @@ spec:
path: /opt/plugins
type: Directory
{{- end }}
{{- end }}

View File

@@ -0,0 +1,6 @@
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: {{ .Values.global.ingressClass }}
spec:
controller: higress.io/higress-controller

View File

@@ -0,0 +1,64 @@
{{- $o11y := .Values.global.o11y }}
{{- if $o11y.enabled }}
{{- $config := $o11y.promtail }}
apiVersion: v1
kind: ConfigMap
metadata:
name: higress-promtail
namespace: {{ .Release.Namespace }}
data:
promtail.yaml: |
server:
log_level: info
http_listen_port: {{ $config.port }}
clients:
- url: http://higress-console-loki.{{ .Release.Namespace }}:3100/loki/api/v1/push
positions:
filename: /tmp/promtail-positions.yaml
target_config:
sync_period: 10s
scrape_configs:
- job_name: access-logs
static_configs:
- targets:
- localhost
labels:
__path__: /var/log/proxy/access.log
pipeline_stages:
- json:
expressions:
authority:
method:
path:
protocol:
request_id:
response_code:
response_flags:
route_name:
trace_id:
upstream_cluster:
upstream_host:
upstream_transport_failure_reason:
user_agent:
x_forwarded_for:
- labels:
authority:
method:
path:
protocol:
request_id:
response_code:
response_flags:
route_name:
trace_id:
upstream_cluster:
upstream_host:
upstream_transport_failure_reason:
user_agent:
x_forwarded_for:
- timestamp:
source: timestamp
format: RFC3339Nano
{{- end }}

View File

@@ -15,6 +15,9 @@ spec:
{{- with .Values.gateway.service.loadBalancerIP }}
loadBalancerIP: "{{ . }}"
{{- end }}
{{- with .Values.gateway.service.loadBalancerClass }}
loadBalancerClass: "{{ . }}"
{{- end }}
{{- with .Values.gateway.service.loadBalancerSourceRanges }}
loadBalancerSourceRanges:
{{ toYaml . | indent 4 }}

View File

@@ -1,6 +1,7 @@
revision: ""
global:
xdsMaxRecvMsgSize: 104857600
liteMetrics: true
xdsMaxRecvMsgSize: "104857600"
defaultUpstreamConcurrencyThreshold: 10000
enableSRDS: true
onDemandRDS: false
@@ -337,6 +338,20 @@ global:
# Use the Mesh Control Protocol (MCP) for configuring Istiod. Requires an MCP source.
useMCP: false
# Observability (o11y) configurations
o11y:
enabled: false
promtail:
image:
repository: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/promtail
tag: 2.9.4
port: 3101
resources:
limits:
cpu: 500m
memory: 2Gi
securityContext: {}
# The name of the CA for workload certificates.
# For example, when caName=GkeWorkloadCertificate, GKE workload certificates
# will be used as the certificates for workloads.
@@ -381,6 +396,9 @@ gateway:
replicas: 2
image: gateway
# -- Use a `DaemonSet` or `Deployment`
kind: Deployment
# The number of successive failed probes before indicating readiness failure.
readinessFailureThreshold: 30
@@ -417,7 +435,8 @@ gateway:
# Pod environment variables
env: {}
httpPort: 80
httpsPort: 443
hostNetwork: false
# Labels to apply to all resources
@@ -452,6 +471,7 @@ gateway:
targetPort: 443
annotations: {}
loadBalancerIP: ""
loadBalancerClass: ""
loadBalancerSourceRanges: []
externalTrafficPolicy: ""
@@ -528,6 +548,12 @@ controller:
"port": 8888,
"targetPort": 8888,
},
{
"name": "http-solver",
"protocol": "TCP",
"port": 8889,
"targetPort": 8889,
},
{
"name": "grpc",
"protocol": "TCP",
@@ -566,6 +592,9 @@ controller:
minReplicas: 1
maxReplicas: 5
targetCPUUtilizationPercentage: 80
automaticHttps:
enabled: true
email: ""
## Discovery Settings
pilot:

View File

@@ -1,9 +1,9 @@
dependencies:
- name: higress-core
repository: file://../core
version: 1.3.4
version: 1.4.2
- name: higress-console
repository: https://higress.io/helm-charts/
version: 1.3.2
digest: sha256:1a5849d5ead79151e42ce419a96669f6691567e6fbf155643a928e6b62c3daa1
generated: "2024-02-20T11:54:00.898489+08:00"
version: 1.4.2
digest: sha256:31b557e55584e589b140ae9b89cfc8b99df91771c7d28465c3a2b06a4f35a192
generated: "2024-07-26T13:53:23.225023+08:00"

View File

@@ -1,5 +1,5 @@
apiVersion: v2
appVersion: 1.3.4
appVersion: 1.4.2
description: Helm chart for deploying Higress gateways
icon: https://higress.io/img/higress_logo_small.png
home: http://higress.io/
@@ -12,9 +12,9 @@ sources:
dependencies:
- name: higress-core
repository: "file://../core"
version: 1.3.4
version: 1.4.2
- name: higress-console
repository: "https://higress.io/helm-charts/"
version: 1.3.2
version: 1.4.2
type: application
version: 1.3.4
version: 1.4.2

View File

@@ -0,0 +1,132 @@
diff -Naur istio/pilot/pkg/config/kube/gateway/conversion.go istio-new/pilot/pkg/config/kube/gateway/conversion.go
--- istio/pilot/pkg/config/kube/gateway/conversion.go 2024-03-04 17:35:34.000000000 +0800
+++ istio-new/pilot/pkg/config/kube/gateway/conversion.go 2024-03-04 16:58:26.000000000 +0800
@@ -450,7 +450,7 @@
name = fmt.Sprintf("%s/%s/%s.%s", obj.GroupVersionKind.Kind, obj.Name, *sectionName, obj.Namespace)
}
return map[string]string{
- constants.InternalParentName: name,
+ constants.InternalParentNames: name,
}
}
diff -Naur istio/pilot/pkg/networking/core/v1alpha3/gateway.go istio-new/pilot/pkg/networking/core/v1alpha3/gateway.go
--- istio/pilot/pkg/networking/core/v1alpha3/gateway.go 2024-03-04 17:35:34.000000000 +0800
+++ istio-new/pilot/pkg/networking/core/v1alpha3/gateway.go 2024-03-04 17:23:10.000000000 +0800
@@ -49,6 +49,7 @@
"istio.io/istio/pkg/config/gateway"
"istio.io/istio/pkg/config/host"
"istio.io/istio/pkg/config/protocol"
+ "istio.io/istio/pkg/config/schema/gvk"
"istio.io/istio/pkg/config/security"
"istio.io/istio/pkg/proto"
"istio.io/istio/pkg/util/istiomultierror"
@@ -453,12 +454,43 @@
return nil, false
}
+ hostVs := push.VirtualServicesForHost(node, hostRDSHost)
+
+ var httpRoutes []config.Config
+
+ for _, vs := range hostVs {
+ if len(vs.Annotations) == 0 {
+ continue
+ }
+ if parents, ok := vs.Annotations[constants.InternalParentNames]; ok {
+ typeNames := strings.Split(parents, ",")
+ for _, typeName := range typeNames {
+ if !strings.HasPrefix(typeName, "HTTPRoute/") {
+ continue
+ }
+ nsNameStr := strings.TrimPrefix(typeName, "HTTPRoute/")
+ nsName := strings.SplitN(nsNameStr, ".", 2)
+ if len(nsName) != 2 {
+ continue
+ }
+ httpRoutes = append(httpRoutes, config.Config{
+ Meta: config.Meta{
+ GroupVersionKind: gvk.HTTPRoute,
+ Name: nsName[0],
+ Namespace: nsName[1],
+ },
+ })
+ }
+ }
+ }
+
routeCache := &istio_route.Cache{
RouteName: routeName,
ProxyVersion: node.Metadata.IstioVersion,
ListenerPort: rdsPort,
// Use same host vs to cache, although the cache can be cleared when the port is different, this can be accepted
- VirtualServices: push.VirtualServicesForHost(node, hostRDSHost),
+ VirtualServices: hostVs,
+ HTTPRoutes: httpRoutes,
EnvoyFilterKeys: efKeys,
}
diff -Naur istio/pilot/pkg/networking/core/v1alpha3/route/route_cache.go istio-new/pilot/pkg/networking/core/v1alpha3/route/route_cache.go
--- istio/pilot/pkg/networking/core/v1alpha3/route/route_cache.go 2024-03-04 17:35:30.000000000 +0800
+++ istio-new/pilot/pkg/networking/core/v1alpha3/route/route_cache.go 2024-03-04 17:24:19.000000000 +0800
@@ -43,9 +43,12 @@
// This depends on DNSCapture.
DNSAutoAllocate bool
- ListenerPort int
- Services []*model.Service
- VirtualServices []config.Config
+ ListenerPort int
+ Services []*model.Service
+ VirtualServices []config.Config
+ // Added by ingress
+ HTTPRoutes []config.Config
+ // End added by ingress
DestinationRules []*config.Config
EnvoyFilterKeys []string
}
@@ -81,6 +84,11 @@
for _, vs := range r.VirtualServices {
configs = append(configs, model.ConfigKey{Kind: gvk.VirtualService, Name: vs.Name, Namespace: vs.Namespace})
}
+ // Added by ingress
+ for _, route := range r.HTTPRoutes {
+ configs = append(configs, model.ConfigKey{Kind: gvk.HTTPRoute, Name: route.Name, Namespace: route.Namespace})
+ }
+ // End added by ingress
for _, dr := range r.DestinationRules {
configs = append(configs, model.ConfigKey{Kind: gvk.DestinationRule, Name: dr.Name, Namespace: dr.Namespace})
}
@@ -107,6 +115,11 @@
for _, vs := range r.VirtualServices {
params = append(params, vs.Name+"/"+vs.Namespace)
}
+ // Added by ingress
+ for _, route := range r.HTTPRoutes {
+ params = append(params, route.Name+"/"+route.Namespace)
+ }
+ // End added by ingress
for _, dr := range r.DestinationRules {
params = append(params, dr.Name+"/"+dr.Namespace)
}
diff -Naur istio/pkg/config/constants/constants.go istio-new/pkg/config/constants/constants.go
--- istio/pkg/config/constants/constants.go 2024-03-04 17:35:34.000000000 +0800
+++ istio-new/pkg/config/constants/constants.go 2024-03-04 16:58:05.000000000 +0800
@@ -15,8 +15,6 @@
package constants
const (
- InternalParentNames = "internal.istio.io/parents"
-
InternalRouteSemantics = "internal.istio.io/route-semantics"
RouteSemanticsGateway = "gateway"
@@ -129,7 +127,7 @@
AlwaysPushLabel = "internal.istio.io/always-push"
// InternalParentName declares the original resource of an internally-generate config. This is used by the gateway-api.
- InternalParentName = "internal.istio.io/parent"
+ InternalParentNames = "internal.istio.io/parents"
// TrustworthyJWTPath is the default 3P token to authenticate with third party services
TrustworthyJWTPath = "./var/run/secrets/tokens/istio-token"

View File

@@ -0,0 +1,56 @@
diff -Naur istio/pilot/pkg/config/kube/gateway/conversion.go istio-new/pilot/pkg/config/kube/gateway/conversion.go
--- istio/pilot/pkg/config/kube/gateway/conversion.go 2024-03-08 17:23:49.000000000 +0800
+++ istio-new/pilot/pkg/config/kube/gateway/conversion.go 2024-03-08 17:02:50.000000000 +0800
@@ -16,6 +16,7 @@
import (
"fmt"
+ "path"
"regexp"
"sort"
"strconv"
@@ -28,6 +29,7 @@
gatewayapiV1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
istio "istio.io/api/networking/v1alpha3"
+ "istio.io/istio/pilot/pkg/features"
"istio.io/istio/pilot/pkg/model"
"istio.io/istio/pilot/pkg/model/credentials"
"istio.io/istio/pilot/pkg/model/kstatus"
@@ -290,6 +292,16 @@
return ret
}
+// Added by ingress
+func generateRouteName(obj config.Config) string {
+ if obj.Namespace == features.HigressSystemNs {
+ return obj.Name
+ }
+ return path.Join(obj.Namespace, obj.Name)
+}
+
+// End added by ingress
+
func buildHTTPVirtualServices(ctx *KubernetesResources, obj config.Config, gateways map[parentKey]map[gatewayapiV1beta1.SectionName]*parentInfo, gatewayRoutes map[string]map[string]*config.Config, domain string) {
route := obj.Spec.(*gatewayapiV1beta1.HTTPRouteSpec)
@@ -307,7 +319,7 @@
for _, r := range route.Rules {
// TODO: implement rewrite, timeout, mirror, corspolicy, retries
vs := &istio.HTTPRoute{
- Name: obj.Name,
+ Name: generateRouteName(obj),
}
for _, match := range r.Matches {
uri, err := createURIMatch(match)
diff -Naur istio/pilot/pkg/features/pilot.go istio-new/pilot/pkg/features/pilot.go
--- istio/pilot/pkg/features/pilot.go 2024-03-08 17:23:49.000000000 +0800
+++ istio-new/pilot/pkg/features/pilot.go 2024-03-08 17:00:05.000000000 +0800
@@ -577,6 +577,7 @@
"If enabled, the on demand filter will be added to the HCM filters").Get()
DefaultUpstreamConcurrencyThreshold = env.RegisterIntVar("DEFAULT_UPSTREAM_CONCURRENCY_THRESHOLD", 1000000,
"The default threshold of max_requests/max_pending_requests/max_connections of circuit breaker").Get()
+ HigressSystemNs = env.RegisterStringVar("HIGRESS_SYSTEM_NS", "higress-system", "The system namespace of Higress").Get()
// End added by ingress
)

View File

@@ -0,0 +1,20 @@
diff -Naur istio/pilot/pkg/networking/core/v1alpha3/gateway.go istio-new/pilot/pkg/networking/core/v1alpha3/gateway.go
--- istio/pilot/pkg/networking/core/v1alpha3/gateway.go 2024-04-22 18:08:26.000000000 +0800
+++ istio-new/pilot/pkg/networking/core/v1alpha3/gateway.go 2024-04-22 18:07:46.000000000 +0800
@@ -581,13 +581,13 @@
continue
}
if len(virtualService.Spec.(*networking.VirtualService).Hosts) > 1 {
- copiedVS := &networking.VirtualService{}
- copiedVS = virtualService.Spec.(*networking.VirtualService)
+ copiedVS := networking.VirtualService{}
+ copiedVS = *(virtualService.Spec.(*networking.VirtualService))
copiedVS.Hosts = []string{selectHost}
selectedVirtualServices = append(selectedVirtualServices, virtualServiceContext{
virtualService: config.Config{
Meta: virtualService.Meta,
- Spec: copiedVS,
+ Spec: &copiedVS,
Status: virtualService.Status,
},
server: vsCtx.server,

View File

@@ -0,0 +1,83 @@
diff -Naur istio/pilot/pkg/networking/core/v1alpha3/gateway.go istio-new/pilot/pkg/networking/core/v1alpha3/gateway.go
--- istio/pilot/pkg/networking/core/v1alpha3/gateway.go 2024-05-18 19:09:14.000000000 +0800
+++ istio-new/pilot/pkg/networking/core/v1alpha3/gateway.go 2024-05-18 18:08:30.000000000 +0800
@@ -457,8 +457,46 @@
hostVs := push.VirtualServicesForHost(node, hostRDSHost)
var httpRoutes []config.Config
+ var vsDependent []config.Config
+
+ cacheable := true
for _, vs := range hostVs {
+ vsSpec := vs.Spec.(*networking.VirtualService)
+ for _, vsHttpRoute := range vsSpec.Http {
+ // check if dynamic port exists, we should not cache RDS
+ for _, vsRoute := range vsHttpRoute.Route {
+ if vsRoute.Destination.Port == nil {
+ cacheable = false
+ }
+ for _, fallbackDestination := range vsRoute.FallbackClusters {
+ if fallbackDestination.Port == nil {
+ cacheable = false
+ }
+ }
+ }
+ if vsHttpRoute.Mirror != nil && vsHttpRoute.Mirror.Port == nil {
+ cacheable = false
+ }
+ if vsHttpRoute.Delegate != nil {
+ vsDependent = append(vsDependent, config.Config{
+ Meta: config.Meta{
+ GroupVersionKind: gvk.VirtualService,
+ Name: vsHttpRoute.Delegate.Name,
+ Namespace: vsHttpRoute.Delegate.Namespace,
+ },
+ Spec: networking.VirtualService{},
+ })
+ }
+ }
+ vsDependent = append(vsDependent, config.Config{
+ Meta: config.Meta{
+ GroupVersionKind: gvk.VirtualService,
+ Name: vs.Name,
+ Namespace: vs.Namespace,
+ },
+ Spec: vs.Spec,
+ })
if len(vs.Annotations) == 0 {
continue
}
@@ -489,14 +527,19 @@
ProxyVersion: node.Metadata.IstioVersion,
ListenerPort: rdsPort,
// Use same host vs to cache, although the cache can be cleared when the port is different, this can be accepted
- VirtualServices: hostVs,
+ VirtualServices: vsDependent,
HTTPRoutes: httpRoutes,
EnvoyFilterKeys: efKeys,
}
- resource, exist := configgen.Cache.Get(routeCache)
- if exist {
- return resource, true
+ var resource *discovery.Resource
+ if cacheable {
+ resource, exist := configgen.Cache.Get(routeCache)
+ if exist {
+ return resource, true
+ }
+ } else {
+ log.Warnf("route cache is disabled for RDS:%s", routeName)
}
listenerPort := uint32(rdsPort)
@@ -727,7 +770,7 @@
Resource: util.MessageToAny(routeCfg),
}
- if features.EnableRDSCaching {
+ if features.EnableRDSCaching && cacheable {
configgen.Cache.Add(routeCache, req, resource)
}

View File

@@ -0,0 +1,752 @@
diff -Naur istio/pilot/docker/Dockerfile.proxyv2 istio-new/pilot/docker/Dockerfile.proxyv2
--- istio/pilot/docker/Dockerfile.proxyv2 2024-05-19 16:40:42.706769894 +0800
+++ istio-new/pilot/docker/Dockerfile.proxyv2 2024-05-19 16:07:20.630730574 +0800
@@ -28,6 +28,7 @@
# Copy Envoy bootstrap templates used by pilot-agent
COPY envoy_bootstrap.json /var/lib/istio/envoy/envoy_bootstrap_tmpl.json
+COPY envoy_bootstrap_lite.json /var/lib/istio/envoy/envoy_bootstrap_lite_tmpl.json
COPY gcp_envoy_bootstrap.json /var/lib/istio/envoy/gcp_envoy_bootstrap_tmpl.json
# Install Envoy.
@@ -47,5 +48,30 @@
# COPY metadata-exchange-filter.wasm /etc/istio/extensions/metadata-exchange-filter.wasm
# COPY metadata-exchange-filter.compiled.wasm /etc/istio/extensions/metadata-exchange-filter.compiled.wasm
+RUN apt-get update && \
+ apt-get install --no-install-recommends -y \
+ logrotate \
+ cron \
+ && apt-get upgrade -y \
+ && apt-get clean
+
+# Latest releases available at https://github.com/aptible/supercronic/releases
+ENV SUPERCRONIC_URL=https://higress.io/release-binary/supercronic-linux-${TARGETARCH:-amd64} \
+ SUPERCRONIC=supercronic-linux-${TARGETARCH:-amd64}
+
+RUN curl -fsSLO "$SUPERCRONIC_URL" \
+ && chmod +x "$SUPERCRONIC" \
+ && mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}" \
+ && ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic
+
+
+COPY higress-proxy-start.sh /usr/local/bin/higress-proxy-start.sh
+
+COPY higress-proxy-container-init.sh /usr/local/bin/higress-proxy-container-init.sh
+
+RUN chmod a+x /usr/local/bin/higress-proxy-container-init.sh;/usr/local/bin/higress-proxy-container-init.sh
+
+RUN chmod a+x /usr/local/bin/higress-proxy-start.sh
+
# The pilot-agent will bootstrap Envoy.
-ENTRYPOINT ["/usr/local/bin/pilot-agent"]
+ENTRYPOINT ["/usr/local/bin/higress-proxy-start.sh"]
diff -Naur istio/tools/istio-docker.mk istio-new/tools/istio-docker.mk
--- istio/tools/istio-docker.mk 2024-05-19 16:40:42.734769895 +0800
+++ istio-new/tools/istio-docker.mk 2024-05-19 16:02:43.222725126 +0800
@@ -96,6 +96,9 @@
docker.proxyv2: BUILD_ARGS=--build-arg proxy_version=istio-proxy:${PROXY_REPO_SHA} --build-arg istio_version=${VERSION} --build-arg BASE_VERSION=${BASE_VERSION} --build-arg SIDECAR=${SIDECAR} --build-arg HUB=${HUB}
docker.proxyv2: ${ISTIO_ENVOY_BOOTSTRAP_CONFIG_DIR}/envoy_bootstrap.json
docker.proxyv2: ${ISTIO_ENVOY_BOOTSTRAP_CONFIG_DIR}/gcp_envoy_bootstrap.json
+docker.proxyv2: ${ISTIO_ENVOY_BOOTSTRAP_CONFIG_DIR}/higress-proxy-start.sh
+docker.proxyv2: ${ISTIO_ENVOY_BOOTSTRAP_CONFIG_DIR}/higress-proxy-container-init.sh
+docker.proxyv2: ${ISTIO_ENVOY_BOOTSTRAP_CONFIG_DIR}/envoy_bootstrap_lite.json
docker.proxyv2: ${ISTIO_ENVOY_LINUX_ARM64_RELEASE_DIR}/${SIDECAR}
docker.proxyv2: ${ISTIO_ENVOY_LINUX_AMD64_RELEASE_DIR}/${SIDECAR}
docker.proxyv2: $(ISTIO_OUT_LINUX)/pilot-agent
diff -Naur istio/tools/packaging/common/envoy_bootstrap_lite.json istio-new/tools/packaging/common/envoy_bootstrap_lite.json
--- istio/tools/packaging/common/envoy_bootstrap_lite.json 1970-01-01 08:00:00.000000000 +0800
+++ istio-new/tools/packaging/common/envoy_bootstrap_lite.json 2024-05-19 16:36:39.274765113 +0800
@@ -0,0 +1,642 @@
+{
+ "node": {
+ "id": "{{ .nodeID }}",
+ "cluster": "{{ .cluster }}",
+ "locality": {
+ {{- if .region }}
+ "region": "{{ .region }}"
+ {{- end }}
+ {{- if .zone }}
+ {{- if .region }}
+ ,
+ {{- end }}
+ "zone": "{{ .zone }}"
+ {{- end }}
+ {{- if .sub_zone }}
+ {{- if or .region .zone }}
+ ,
+ {{- end }}
+ "sub_zone": "{{ .sub_zone }}"
+ {{- end }}
+ },
+ "metadata": {{ .meta_json_str }}
+ },
+ "layered_runtime": {
+ "layers": [
+ {
+ "name": "global config",
+ "static_layer": {{ .runtime_flags }}
+ },
+ {
+ "name": "admin",
+ "admin_layer": {}
+ }
+ ]
+ },
+ "stats_config": {
+ "use_all_default_tags": false,
+ "stats_tags": [
+ {
+ "tag_name": "response_code_class",
+ "regex": "_rq(_(\\dxx))$"
+ },
+ {
+ "tag_name": "listener_address",
+ "regex": "^listener\\.(((?:[_.[:digit:]]*|[_\\[\\]aAbBcCdDeEfF[:digit:]]*))\\.)"
+ },
+ {
+ "tag_name": "http_conn_manager_prefix",
+ "regex": "^http\\.(((outbound_([0-9]{1,3}\\.{0,1}){4}_\\d{0,5})|([^\\.]+))\\.)"
+ },
+ {
+ "tag_name": "cluster_name",
+ "regex": "^cluster\\.((.*?)\\.)(http1\\.|http2\\.|health_check\\.|zone\\.|external\\.|circuit_breakers\\.|[^\\.]+$)"
+ }
+ ],
+ "stats_matcher": {
+ "exclusion_list": {
+ "patterns": [
+ {
+ "prefix": "vhost"
+ },
+ {
+ "safe_regex": {"regex": "^http.*rds.*", "google_re2":{}}
+ }
+ ]
+ }
+ }
+ },
+ "admin": {
+ "access_log_path": "/dev/null",
+ "profile_path": "/var/lib/istio/data/envoy.prof",
+ "address": {
+ "socket_address": {
+ "address": "{{ .localhost }}",
+ "port_value": {{ .config.ProxyAdminPort }}
+ }
+ }
+ },
+ "dynamic_resources": {
+ "lds_config": {
+ "ads": {},
+ "initial_fetch_timeout": "0s",
+ "resource_api_version": "V3"
+ },
+ "cds_config": {
+ "ads": {},
+ "initial_fetch_timeout": "0s",
+ "resource_api_version": "V3"
+ },
+ "ads_config": {
+ "api_type": "{{ .xds_type }}",
+ "set_node_on_first_message_only": true,
+ "transport_api_version": "V3",
+ "grpc_services": [
+ {
+ "envoy_grpc": {
+ "cluster_name": "xds-grpc"
+ }
+ }
+ ]
+ }
+ },
+ "static_resources": {
+ "clusters": [
+ {
+ "name": "prometheus_stats",
+ "type": "STATIC",
+ "connect_timeout": "0.250s",
+ "lb_policy": "ROUND_ROBIN",
+ "load_assignment": {
+ "cluster_name": "prometheus_stats",
+ "endpoints": [{
+ "lb_endpoints": [{
+ "endpoint": {
+ "address":{
+ "socket_address": {
+ "protocol": "TCP",
+ "address": "{{ .localhost }}",
+ "port_value": {{ .config.ProxyAdminPort }}
+ }
+ }
+ }
+ }]
+ }]
+ }
+ },
+ {
+ "name": "agent",
+ "type": "STATIC",
+ "connect_timeout": "0.250s",
+ "lb_policy": "ROUND_ROBIN",
+ "load_assignment": {
+ "cluster_name": "agent",
+ "endpoints": [{
+ "lb_endpoints": [{
+ "endpoint": {
+ "address":{
+ "socket_address": {
+ "protocol": "TCP",
+ "address": "{{ .localhost }}",
+ "port_value": {{ .config.StatusPort }}
+ }
+ }
+ }
+ }]
+ }]
+ }
+ },
+ {
+ "name": "sds-grpc",
+ "type": "STATIC",
+ "typed_extension_protocol_options": {
+ "envoy.extensions.upstreams.http.v3.HttpProtocolOptions": {
+ "@type": "type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions",
+ "explicit_http_config": {
+ "http2_protocol_options": {}
+ }
+ }
+ },
+ "connect_timeout": "1s",
+ "lb_policy": "ROUND_ROBIN",
+ "load_assignment": {
+ "cluster_name": "sds-grpc",
+ "endpoints": [{
+ "lb_endpoints": [{
+ "endpoint": {
+ "address":{
+ "pipe": {
+ "path": "{{ .config.ConfigPath }}/SDS"
+ }
+ }
+ }
+ }]
+ }]
+ }
+ },
+ {
+ "name": "xds-grpc",
+ "type" : "STATIC",
+ "connect_timeout": "1s",
+ "lb_policy": "ROUND_ROBIN",
+ "load_assignment": {
+ "cluster_name": "xds-grpc",
+ "endpoints": [{
+ "lb_endpoints": [{
+ "endpoint": {
+ "address":{
+ "pipe": {
+ "path": "{{ .config.ConfigPath }}/XDS"
+ }
+ }
+ }
+ }]
+ }]
+ },
+ "circuit_breakers": {
+ "thresholds": [
+ {
+ "priority": "DEFAULT",
+ "max_connections": 100000,
+ "max_pending_requests": 100000,
+ "max_requests": 100000
+ },
+ {
+ "priority": "HIGH",
+ "max_connections": 100000,
+ "max_pending_requests": 100000,
+ "max_requests": 100000
+ }
+ ]
+ },
+ "upstream_connection_options": {
+ "tcp_keepalive": {
+ "keepalive_time": 300
+ }
+ },
+ "max_requests_per_connection": 1,
+ "typed_extension_protocol_options": {
+ "envoy.extensions.upstreams.http.v3.HttpProtocolOptions": {
+ "@type": "type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions",
+ "explicit_http_config": {
+ "http2_protocol_options": {}
+ }
+ }
+ }
+ }
+ {{ if .zipkin }}
+ ,
+ {
+ "name": "zipkin",
+ {{- if .tracing_tls }}
+ "transport_socket": {{ .tracing_tls }},
+ {{- end }}
+ "type": "STRICT_DNS",
+ "respect_dns_ttl": true,
+ "dns_lookup_family": "{{ .dns_lookup_family }}",
+ "dns_refresh_rate": "30s",
+ "connect_timeout": "1s",
+ "lb_policy": "ROUND_ROBIN",
+ "load_assignment": {
+ "cluster_name": "zipkin",
+ "endpoints": [{
+ "lb_endpoints": [{
+ "endpoint": {
+ "address":{
+ "socket_address": {{ .zipkin }}
+ }
+ }
+ }]
+ }]
+ }
+ }
+ {{ else if .lightstep }}
+ ,
+ {
+ "name": "lightstep",
+ {{- if .tracing_tls }}
+ "transport_socket": {{ .tracing_tls }},
+ {{- end }}
+ "typed_extension_protocol_options": {
+ "envoy.extensions.upstreams.http.v3.HttpProtocolOptions": {
+ "@type": "type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions",
+ "explicit_http_config": {
+ "http2_protocol_options": {}
+ }
+ }
+ },
+ "type": "STRICT_DNS",
+ "respect_dns_ttl": true,
+ "dns_lookup_family": "{{ .dns_lookup_family }}",
+ "connect_timeout": "1s",
+ "lb_policy": "ROUND_ROBIN",
+ "load_assignment": {
+ "cluster_name": "lightstep",
+ "endpoints": [{
+ "lb_endpoints": [{
+ "endpoint": {
+ "address":{
+ "socket_address": {{ .lightstep }}
+ }
+ }
+ }]
+ }]
+ }
+ }
+ {{ else if .datadog }}
+ ,
+ {
+ "name": "datadog_agent",
+ {{- if .tracing_tls }}
+ "transport_socket": {{ .tracing_tls }},
+ {{- end }}
+ "connect_timeout": "1s",
+ "type": "STRICT_DNS",
+ "respect_dns_ttl": true,
+ "dns_lookup_family": "{{ .dns_lookup_family }}",
+ "lb_policy": "ROUND_ROBIN",
+ "load_assignment": {
+ "cluster_name": "datadog_agent",
+ "endpoints": [{
+ "lb_endpoints": [{
+ "endpoint": {
+ "address":{
+ "socket_address": {{ .datadog }}
+ }
+ }
+ }]
+ }]
+ }
+ }
+ {{ end }}
+ {{- if .envoy_metrics_service_address }}
+ ,
+ {
+ "name": "envoy_metrics_service",
+ "type": "STRICT_DNS",
+ {{- if .envoy_metrics_service_tls }}
+ "transport_socket": {{ .envoy_metrics_service_tls }},
+ {{- end }}
+ {{- if .envoy_metrics_service_tcp_keepalive }}
+ "upstream_connection_options": {{ .envoy_metrics_service_tcp_keepalive }},
+ {{- end }}
+ "respect_dns_ttl": true,
+ "dns_lookup_family": "{{ .dns_lookup_family }}",
+ "connect_timeout": "1s",
+ "lb_policy": "ROUND_ROBIN",
+ "typed_extension_protocol_options": {
+ "envoy.extensions.upstreams.http.v3.HttpProtocolOptions": {
+ "@type": "type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions",
+ "explicit_http_config": {
+ "http2_protocol_options": {}
+ }
+ }
+ },
+ "load_assignment": {
+ "cluster_name": "envoy_metrics_service",
+ "endpoints": [{
+ "lb_endpoints": [{
+ "endpoint": {
+ "address":{
+ "socket_address": {{ .envoy_metrics_service_address }}
+ }
+ }
+ }]
+ }]
+ }
+ }
+ {{ end }}
+ {{ if .envoy_accesslog_service_address }}
+ ,
+ {
+ "name": "envoy_accesslog_service",
+ "type": "STRICT_DNS",
+ {{- if .envoy_accesslog_service_tls }}
+ "transport_socket": {{ .envoy_accesslog_service_tls }},
+ {{- end }}
+ {{- if .envoy_accesslog_service_tcp_keepalive }}
+ "upstream_connection_options": {{ .envoy_accesslog_service_tcp_keepalive }},
+ {{ end }}
+ "respect_dns_ttl": true,
+ "dns_lookup_family": "{{ .dns_lookup_family }}",
+ "connect_timeout": "1s",
+ "lb_policy": "ROUND_ROBIN",
+ "typed_extension_protocol_options": {
+ "envoy.extensions.upstreams.http.v3.HttpProtocolOptions": {
+ "@type": "type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions",
+ "explicit_http_config": {
+ "http2_protocol_options": {}
+ }
+ }
+ },
+ "load_assignment": {
+ "cluster_name": "envoy_accesslog_service",
+ "endpoints": [{
+ "lb_endpoints": [{
+ "endpoint": {
+ "address":{
+ "socket_address": {{ .envoy_accesslog_service_address }}
+ }
+ }
+ }]
+ }]
+ }
+ }
+ {{ end }}
+ ],
+ "listeners":[
+ {
+ "address": {
+ "socket_address": {
+ "protocol": "TCP",
+ "address": "{{ .wildcard }}",
+ "port_value": {{ .envoy_prometheus_port }}
+ }
+ },
+ "filter_chains": [
+ {
+ "filters": [
+ {
+ "name": "envoy.filters.network.http_connection_manager",
+ "typed_config": {
+ "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
+ "codec_type": "AUTO",
+ "stat_prefix": "stats",
+ "route_config": {
+ "virtual_hosts": [
+ {
+ "name": "backend",
+ "domains": [
+ "*"
+ ],
+ "routes": [
+ {
+ "match": {
+ "prefix": "/stats/prometheus"
+ },
+ "route": {
+ "cluster": "prometheus_stats"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "http_filters": [{
+ "name": "envoy.filters.http.router",
+ "typed_config": {
+ "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router"
+ }
+ }]
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "address": {
+ "socket_address": {
+ "protocol": "TCP",
+ "address": "{{ .wildcard }}",
+ "port_value": {{ .envoy_status_port }}
+ }
+ },
+ "filter_chains": [
+ {
+ "filters": [
+ {
+ "name": "envoy.filters.network.http_connection_manager",
+ "typed_config": {
+ "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
+ "codec_type": "AUTO",
+ "stat_prefix": "agent",
+ "route_config": {
+ "virtual_hosts": [
+ {
+ "name": "backend",
+ "domains": [
+ "*"
+ ],
+ "routes": [
+ {
+ "match": {
+ "prefix": "/healthz/ready"
+ },
+ "route": {
+ "cluster": "agent"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "http_filters": [{
+ "name": "envoy.filters.http.router",
+ "typed_config": {
+ "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router"
+ }
+ }]
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ {{- if .zipkin }}
+ ,
+ "tracing": {
+ "http": {
+ "name": "envoy.tracers.zipkin",
+ "typed_config": {
+ "@type": "type.googleapis.com/envoy.config.trace.v3.ZipkinConfig",
+ "collector_cluster": "zipkin",
+ "collector_endpoint": "/api/v2/spans",
+ "collector_endpoint_version": "HTTP_JSON",
+ "trace_id_128bit": true,
+ "shared_span_context": false
+ }
+ }
+ }
+ {{- else if .lightstep }}
+ ,
+ "tracing": {
+ "http": {
+ "name": "envoy.tracers.lightstep",
+ "typed_config": {
+ "@type": "type.googleapis.com/envoy.config.trace.v3.LightstepConfig",
+ "collector_cluster": "lightstep",
+ "access_token_file": "{{ .lightstepToken}}"
+ }
+ }
+ }
+ {{- else if .datadog }}
+ ,
+ "tracing": {
+ "http": {
+ "name": "envoy.tracers.datadog",
+ "typed_config": {
+ "@type": "type.googleapis.com/envoy.config.trace.v3.DatadogConfig",
+ "collector_cluster": "datadog_agent",
+ "service_name": "{{ .cluster }}"
+ }
+ }
+ }
+ {{- else if .openCensusAgent }}
+ ,
+ "tracing": {
+ "http": {
+ "name": "envoy.tracers.opencensus",
+ "typed_config": {
+ "@type": "type.googleapis.com/envoy.config.trace.v3.OpenCensusConfig",
+ "ocagent_exporter_enabled": true,
+ "ocagent_address": "{{ .openCensusAgent }}",
+ "incoming_trace_context": {{ .openCensusAgentContexts }},
+ "outgoing_trace_context": {{ .openCensusAgentContexts }},
+ "trace_config": {
+ "constant_sampler": {
+ "decision": "ALWAYS_PARENT"
+ },
+ "max_number_of_annotations": 200,
+ "max_number_of_attributes": 200,
+ "max_number_of_message_events": 200,
+ "max_number_of_links": 200
+ }
+ }
+ }
+ }
+ {{- else if .stackdriver }}
+ ,
+ "tracing": {
+ "http": {
+ "name": "envoy.tracers.opencensus",
+ "typed_config": {
+ "@type": "type.googleapis.com/envoy.config.trace.v3.OpenCensusConfig",
+ "stackdriver_exporter_enabled": true,
+ "stackdriver_project_id": "{{ .stackdriverProjectID }}",
+ {{ if .sts_port }}
+ "stackdriver_grpc_service": {
+ "google_grpc": {
+ "target_uri": "cloudtrace.googleapis.com",
+ "stat_prefix": "oc_stackdriver_tracer",
+ "channel_credentials": {
+ "ssl_credentials": {}
+ },
+ "call_credentials": [{
+ "sts_service": {
+ "token_exchange_service_uri": "http://localhost:{{ .sts_port }}/token",
+ "subject_token_path": "/var/run/secrets/tokens/istio-token",
+ "subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
+ "scope": "https://www.googleapis.com/auth/cloud-platform"
+ }
+ }]
+ },
+ "initial_metadata": [
+ {{ if .gcp_project_id }}
+ {
+ "key": "x-goog-user-project",
+ "value": "{{ .gcp_project_id }}"
+ }
+ {{ end }}
+ ]
+ },
+ {{ end }}
+ "stdout_exporter_enabled": {{ .stackdriverDebug }},
+ "incoming_trace_context": ["CLOUD_TRACE_CONTEXT", "TRACE_CONTEXT", "GRPC_TRACE_BIN", "B3"],
+ "outgoing_trace_context": ["CLOUD_TRACE_CONTEXT", "TRACE_CONTEXT", "GRPC_TRACE_BIN", "B3"],
+ "trace_config":{
+ "constant_sampler":{
+ "decision": "ALWAYS_PARENT"
+ },
+ "max_number_of_annotations": {{ .stackdriverMaxAnnotations }},
+ "max_number_of_attributes": {{ .stackdriverMaxAttributes }},
+ "max_number_of_message_events": {{ .stackdriverMaxEvents }},
+ "max_number_of_links": 200
+ }
+ }
+ }}
+ {{ end }}
+ {{ if or .envoy_metrics_service_address .statsd }}
+ ,
+ "stats_sinks": [
+ {{ if .envoy_metrics_service_address }}
+ {
+ "name": "envoy.stat_sinks.metrics_service",
+ "typed_config": {
+ "@type": "type.googleapis.com/envoy.config.metrics.v3.MetricsServiceConfig",
+ "transport_api_version": "V3",
+ "grpc_service": {
+ "envoy_grpc": {
+ "cluster_name": "envoy_metrics_service"
+ }
+ }
+ }
+ }
+ {{ end }}
+ {{ if and .envoy_metrics_service_address .statsd }}
+ ,
+ {{ end }}
+ {{ if .statsd }}
+ {
+ "name": "envoy.stat_sinks.statsd",
+ "typed_config": {
+ "@type": "type.googleapis.com/envoy.config.metrics.v3.StatsdSink",
+ "address": {
+ "socket_address": {{ .statsd }}
+ }
+ }
+ }
+ {{ end }}
+ ]
+ {{ end }}
+ {{ if .outlier_log_path }}
+ ,
+ "cluster_manager": {
+ "outlier_detection": {
+ "event_log_path": "{{ .outlier_log_path }}"
+ }
+ }
+ {{ end }}
+}
diff -Naur istio/tools/packaging/common/higress-proxy-container-init.sh istio-new/tools/packaging/common/higress-proxy-container-init.sh
--- istio/tools/packaging/common/higress-proxy-container-init.sh 1970-01-01 08:00:00.000000000 +0800
+++ istio-new/tools/packaging/common/higress-proxy-container-init.sh 2024-05-19 16:30:06.202757394 +0800
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+mkdir -p /var/log/proxy
+
+mkdir -p /var/lib/istio
+
+chown -R 1337.1337 /var/log/proxy
+
+chown -R 1337.1337 /var/lib/logrotate
+
+chown -R 1337.1337 /var/lib/istio
+
+cat <<EOF > /etc/logrotate.d/higress-logrotate
+/var/log/proxy/access.log
+{
+su 1337 1337
+rotate 5
+create 644 1337 1337
+nocompress
+notifempty
+minsize 100M
+postrotate
+ ps aux|grep "envoy -c"|grep -v "grep"|awk '{print $2}'|xargs -i kill -SIGUSR1 {}
+endscript
+}
+EOF
+
+chmod -R 0644 /etc/logrotate.d/higress-logrotate
+
+cat <<EOF > /var/lib/istio/cron.txt
+* * * * * /usr/sbin/logrotate /etc/logrotate.d/higress-logrotate
+EOF
diff -Naur istio/tools/packaging/common/higress-proxy-start.sh istio-new/tools/packaging/common/higress-proxy-start.sh
--- istio/tools/packaging/common/higress-proxy-start.sh 1970-01-01 08:00:00.000000000 +0800
+++ istio-new/tools/packaging/common/higress-proxy-start.sh 2024-05-19 16:33:18.802761176 +0800
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+if [ -n "$LITE_METRICS" ]; then
+ cp /var/lib/istio/envoy/envoy_bootstrap_lite_tmpl.json /var/lib/istio/envoy/envoy_bootstrap_tmpl.json
+fi
+
+nohup supercronic /var/lib/istio/cron.txt &> /dev/null &
+
+/usr/local/bin/pilot-agent $*
+

View File

@@ -0,0 +1,83 @@
diff -Naur istio/tools/packaging/common/envoy_bootstrap.json istio-new/tools/packaging/common/envoy_bootstrap.json
--- istio/tools/packaging/common/envoy_bootstrap.json 2024-05-21 23:46:21.000000000 +0800
+++ istio-new/tools/packaging/common/envoy_bootstrap.json 2024-05-21 23:47:54.000000000 +0800
@@ -37,55 +37,15 @@
"use_all_default_tags": false,
"stats_tags": [
{
- "tag_name": "phase",
- "regex": "(_phase=([a-z_]+))"
- },
- {
- "tag_name": "ruleid",
- "regex": "(_ruleid=([0-9]+))"
- },
- {
- "tag_name": "route",
- "regex": "^vhost\\..*?\\.route\\.([^\\.]+\\.)upstream"
- },
- {
- "tag_name": "ecds_name",
- "regex": "extension_config_discovery\\.(.*?\\.)[^\\.]+$"
- },
- {
- "tag_name": "rds_name",
- "regex": "rds\\.(.*?\\.)[^\\.]+$"
- },
- {
- "tag_name": "sds_name",
- "regex": "sds\\.(.*?\\.)[^\\.]+$"
- },
- {
- "tag_name": "vhost",
- "regex": "^vhost\\.((.*?)\\.)(vcluster|route)"
- },
- {
- "tag_name": "vcluster",
- "regex": "vcluster\\.((.*?)\\.)upstream"
- },
- {
- "tag_name": "dest_zone",
- "regex": "zone\\.[^\\.]+\\.([^\\.]+\\.)"
- },
- {
- "tag_name": "from_zone",
- "regex": "zone\\.([^\\.]+\\.)"
- },
- {
"tag_name": "cluster_name",
- "regex": "^cluster\\.((.*?)\\.)(http1\\.|http2\\.|health_check\\.|zone\\.|external\\.|circuit_breakers\\.|[^\\.]+$)"
+ "regex": "^cluster\\.((.+?(\\..+?\\.svc\\.cluster\\.local)?)\\.)"
},
{
"tag_name": "tcp_prefix",
"regex": "^tcp\\.((.*?)\\.)\\w+?$"
},
{
- "regex": "(response_code=\\.=(.+?);\\.;)|_rq(_(\\.d{3}))$",
+ "regex": "_rq(_(\\d{3}))$",
"tag_name": "response_code"
},
{
@@ -98,7 +58,7 @@
},
{
"tag_name": "http_conn_manager_prefix",
- "regex": "^http\\.(((outbound_([0-9]{1,3}\\.{0,1}){4}_\\d{0,5})|([^\\.]+))\\.)"
+ "regex": "^http\\.(((?:[_.[:digit:]]*|[_\\[\\]aAbBcCdDeEfF[:digit:]]*))\\.)"
},
{
"tag_name": "listener_address",
@@ -108,12 +68,6 @@
"tag_name": "mongo_prefix",
"regex": "^mongo\\.(.+?)\\.(collection|cmd|cx_|op_|delays_|decoding_)(.*?)$"
},
- {{- range $a, $tag := .extraStatTags }}
- {
- "regex": "({{ $tag }}=\\.=(.*?);\\.;)",
- "tag_name": "{{ $tag }}"
- },
- {{- end }}
{
"regex": "(cache\\.(.+?)\\.)",
"tag_name": "cache"

View File

@@ -0,0 +1,69 @@
diff -Naur istio/pilot/pkg/model/push_context.go istio-new/pilot/pkg/model/push_context.go
--- istio/pilot/pkg/model/push_context.go 2024-05-27 23:03:09.000000000 +0800
+++ istio-new/pilot/pkg/model/push_context.go 2024-05-27 21:33:45.000000000 +0800
@@ -1482,8 +1482,14 @@
ns := virtualService.Namespace
rule := virtualService.Spec.(*networking.VirtualService)
// Added by ingress
- for _, host := range rule.Hosts {
- ps.virtualServiceIndex.byHost[host] = append(ps.virtualServiceIndex.byHost[host], virtualService)
+ if len(rule.Gateways) > 0 {
+ if len(rule.Hosts) == 0 {
+ ps.virtualServiceIndex.byHost[constants.GlobalWildcardHost] = append(ps.virtualServiceIndex.byHost[constants.GlobalWildcardHost], virtualService)
+ } else {
+ for _, host := range rule.Hosts {
+ ps.virtualServiceIndex.byHost[host] = append(ps.virtualServiceIndex.byHost[host], virtualService)
+ }
+ }
}
// End added by ingress
gwNames := getGatewayNames(rule)
diff -Naur istio/pilot/pkg/networking/core/v1alpha3/gateway.go istio-new/pilot/pkg/networking/core/v1alpha3/gateway.go
--- istio/pilot/pkg/networking/core/v1alpha3/gateway.go 2024-05-27 23:03:09.000000000 +0800
+++ istio-new/pilot/pkg/networking/core/v1alpha3/gateway.go 2024-05-27 22:58:33.000000000 +0800
@@ -376,8 +376,15 @@
gatewayVirtualServices[gatewayName] = virtualServices
}
for _, virtualService := range virtualServices {
- for _, host := range virtualService.Spec.(*networking.VirtualService).Hosts {
- hostSet.Insert(host)
+ rule := virtualService.Spec.(*networking.VirtualService)
+ if len(rule.Gateways) > 0 {
+ if len(rule.Hosts) == 0 {
+ hostSet.Insert(constants.GlobalWildcardHost)
+ break
+ }
+ for _, host := range rule.Hosts {
+ hostSet.Insert(host)
+ }
}
}
}
@@ -689,7 +696,7 @@
vHost = &route.VirtualHost{
Name: util.DomainName(hostRDSHost, port),
Domains: buildGatewayVirtualHostDomains(hostRDSHost, port),
- Routes: routes,
+ Routes: append(routes[:0:0], routes...),
IncludeRequestAttemptCount: true,
TypedPerFilterConfig: mseingress.ConstructTypedPerFilterConfigForVHost(globalHTTPFilters, virtualService),
}
@@ -884,7 +891,7 @@
newVHost := &route.VirtualHost{
Name: util.DomainName(string(hostname), port),
Domains: buildGatewayVirtualHostDomains(string(hostname), port),
- Routes: routes,
+ Routes: append(routes[:0:0], routes...),
IncludeRequestAttemptCount: true,
TypedPerFilterConfig: mseingress.ConstructTypedPerFilterConfigForVHost(globalHTTPFilters, virtualService),
}
diff -Naur istio/pkg/config/constants/constants.go istio-new/pkg/config/constants/constants.go
--- istio/pkg/config/constants/constants.go 2024-05-27 23:03:09.000000000 +0800
+++ istio-new/pkg/config/constants/constants.go 2024-05-27 21:31:58.000000000 +0800
@@ -145,5 +145,6 @@
// Added by ingress
HigressHostRDSNamePrefix = "higress-rds-"
DefaultScopedRouteName = "scoped-route"
+ GlobalWildcardHost = "*"
// End added by ingress
)

View File

@@ -0,0 +1,17 @@
diff -Naur istio/pilot/pkg/model/push_context.go istio-new/pilot/pkg/model/push_context.go
--- istio/pilot/pkg/model/push_context.go 2024-05-29 19:29:45.000000000 +0800
+++ istio-new/pilot/pkg/model/push_context.go 2024-05-29 19:11:03.000000000 +0800
@@ -769,6 +769,13 @@
for _, s := range svcs {
svcHost := string(s.Hostname)
+ // Added by ingress
+ if s.Attributes.Namespace == "mcp" {
+ gwSvcs = append(gwSvcs, s)
+ continue
+ }
+ // End added by ingress
+
if _, ok := hostsFromGateways[svcHost]; ok {
gwSvcs = append(gwSvcs, s)
}

View File

@@ -0,0 +1,21 @@
diff -Naur istio/tools/packaging/common/envoy_bootstrap.json istio-new/tools/packaging/common/envoy_bootstrap.json
--- istio/tools/packaging/common/envoy_bootstrap.json 2024-06-07 16:50:21.000000000 +0800
+++ istio-new/tools/packaging/common/envoy_bootstrap.json 2024-06-07 16:47:42.000000000 +0800
@@ -38,7 +38,7 @@
"stats_tags": [
{
"tag_name": "cluster_name",
- "regex": "^cluster\\.((.+?(\\..+?\\.svc\\.cluster\\.local)?)\\.)"
+ "regex": "^cluster\\.((.*?)\\.)(http1\\.|http2\\.|health_check\\.|zone\\.|external\\.|circuit_breakers\\.|[^\\.]+$)"
},
{
"tag_name": "tcp_prefix",
@@ -58,7 +58,7 @@
},
{
"tag_name": "http_conn_manager_prefix",
- "regex": "^http\\.(((?:[_.[:digit:]]*|[_\\[\\]aAbBcCdDeEfF[:digit:]]*))\\.)"
+ "regex": "^http\\.(((outbound_([0-9]{1,3}\\.{0,1}){4}_\\d{0,5})|([^\\.]+))\\.)"
},
{
"tag_name": "listener_address",

View File

@@ -0,0 +1,53 @@
diff -Naur istio/tools/packaging/common/envoy_bootstrap.json istio-new/tools/packaging/common/envoy_bootstrap.json
--- istio/tools/packaging/common/envoy_bootstrap.json 2024-06-19 13:39:49.179159469 +0800
+++ istio-new/tools/packaging/common/envoy_bootstrap.json 2024-06-19 13:39:28.299159059 +0800
@@ -37,6 +37,18 @@
"use_all_default_tags": false,
"stats_tags": [
{
+ "tag_name": "ai_route",
+ "regex": "^wasmcustom\\.route\\.((.*?)\\.)upstream"
+ },
+ {
+ "tag_name": "ai_cluster",
+ "regex": "^wasmcustom\\..*?\\.upstream\\.((.*?)\\.)model"
+ },
+ {
+ "tag_name": "ai_model",
+ "regex": "^wasmcustom\\..*?\\.model\\.((.*?)\\.)(input_token|output_token)"
+ },
+ {
"tag_name": "cluster_name",
"regex": "^cluster\\.((.*?)\\.)(http1\\.|http2\\.|health_check\\.|zone\\.|external\\.|circuit_breakers\\.|[^\\.]+$)"
},
diff -Naur istio/tools/packaging/common/envoy_bootstrap_lite.json istio-new/tools/packaging/common/envoy_bootstrap_lite.json
--- istio/tools/packaging/common/envoy_bootstrap_lite.json 2024-06-19 13:39:49.175159469 +0800
+++ istio-new/tools/packaging/common/envoy_bootstrap_lite.json 2024-06-19 13:38:52.283158352 +0800
@@ -37,6 +37,18 @@
"use_all_default_tags": false,
"stats_tags": [
{
+ "tag_name": "ai_route",
+ "regex": "^wasmcustom\\.route\\.((.*?)\\.)upstream"
+ },
+ {
+ "tag_name": "ai_cluster",
+ "regex": "^wasmcustom\\..*?\\.upstream\\.((.*?)\\.)model"
+ },
+ {
+ "tag_name": "ai_model",
+ "regex": "^wasmcustom\\..*?\\.model\\.((.*?)\\.)(input_token|output_token)"
+ },
+ {
"tag_name": "response_code_class",
"regex": "_rq(_(\\dxx))$"
},
@@ -60,7 +72,7 @@
"prefix": "vhost"
},
{
- "safe_regex": {"regex": "^http.*rds.*", "google_re2":{}}
+ "safe_regex": {"regex": "^http.*\\.rds\\..*", "google_re2":{}}
}
]
}

View File

@@ -0,0 +1,38 @@
diff -Naur proxy/scripts/release-binary.sh proxy-new/scripts/release-binary.sh
--- proxy/scripts/release-binary.sh 2024-05-19 12:33:33.254478650 +0800
+++ proxy-new/scripts/release-binary.sh 2024-05-19 12:31:11.714475870 +0800
@@ -112,7 +112,7 @@
# k8-opt is the output directory for x86_64 optimized builds (-c opt, so --config=release-symbol and --config=release).
# k8-dbg is the output directory for -c dbg builds.
#for config in release release-symbol debug
-for config in release
+for config in release release-symbol
do
case $config in
"release" )
diff -Naur proxy/scripts/release-binary.sh proxy-new/scripts/release-binary.sh
--- proxy/scripts/release-binary.sh 2024-05-19 12:27:51.030471929 +0800
+++ proxy-new/scripts/release-binary.sh 2024-05-19 12:04:55.738444918 +0800
@@ -152,10 +152,6 @@
echo "Building ${config} proxy"
BINARY_NAME="${HOME}/package/${BINARY_BASE_NAME}.tar.gz"
SHA256_NAME="${HOME}/${BINARY_BASE_NAME}-${SHA}.sha256"
- # All cores are used by com_googlesource_chromium_v8:build within.
- # Prebuild this target to avoid stacking this ram intensive task with others.
- # shellcheck disable=SC2086
- bazel build ${BAZEL_BUILD_ARGS} ${CONFIG_PARAMS} @com_googlesource_chromium_v8//:build
# shellcheck disable=SC2086
bazel build ${BAZEL_BUILD_ARGS} ${CONFIG_PARAMS} //src/envoy:envoy_tar
BAZEL_TARGET="${BAZEL_OUT}/src/envoy/envoy_tar.tar.gz"
diff -Naur proxy/tools/deb/test/build_docker.sh proxy-new/tools/deb/test/build_docker.sh
--- proxy/tools/deb/test/build_docker.sh 2024-05-19 12:27:51.030471929 +0800
+++ proxy-new/tools/deb/test/build_docker.sh 2024-05-19 12:05:07.978445159 +0800
@@ -20,8 +20,6 @@
# Script requires a working docker on the test machine
# It is run in the proxy dir, will create a docker image with proxy deb installed
-
-bazel build @com_googlesource_chromium_v8//:build
bazel build tools/deb:istio-proxy
PROJECT="istio-testing"

View File

@@ -20,6 +20,7 @@ import (
"net/http"
"time"
"github.com/alibaba/higress/pkg/cert"
"github.com/alibaba/higress/pkg/ingress/kube/common"
"github.com/alibaba/higress/pkg/ingress/mcp"
"github.com/alibaba/higress/pkg/ingress/translation"
@@ -110,6 +111,11 @@ type ServerArgs struct {
KeepStaleWhenEmpty bool
GatewaySelectorKey string
GatewaySelectorValue string
GatewayHttpPort uint32
GatewayHttpsPort uint32
EnableAutomaticHttps bool
AutomaticHttpsEmail string
CertHttpAddress string
}
type readinessProbe func() (bool, error)
@@ -131,6 +137,7 @@ type Server struct {
xdsServer *xds.DiscoveryServer
server server.Instance
readinessProbes map[string]readinessProbe
certServer *cert.Server
}
var (
@@ -166,6 +173,7 @@ func NewServer(args *ServerArgs) (*Server, error) {
s.initConfigController,
s.initRegistryEventHandlers,
s.initAuthenticators,
s.initAutomaticHttps,
}
for _, f := range initFuncList {
@@ -220,6 +228,8 @@ func (s *Server) initConfigController() error {
SystemNamespace: ns,
GatewaySelectorKey: s.GatewaySelectorKey,
GatewaySelectorValue: s.GatewaySelectorValue,
GatewayHttpPort: s.GatewayHttpPort,
GatewayHttpsPort: s.GatewayHttpsPort,
}
if options.ClusterId == "Kubernetes" {
options.ClusterId = ""
@@ -283,6 +293,15 @@ func (s *Server) Start(stop <-chan struct{}) error {
}
}()
if s.EnableAutomaticHttps {
go func() {
log.Infof("starting Automatic Cert HTTP service at %s", s.CertHttpAddress)
if err := s.certServer.Run(stop); err != nil {
log.Errorf("error serving Automatic Cert HTTP server: %v", err)
}
}()
}
s.waitForShutDown(stop)
return nil
}
@@ -366,6 +385,26 @@ func (s *Server) initAuthenticators() error {
return nil
}
func (s *Server) initAutomaticHttps() error {
certOption := &cert.Option{
Namespace: PodNamespace,
ServerAddress: s.CertHttpAddress,
Email: s.AutomaticHttpsEmail,
}
certServer, err := cert.NewServer(s.kubeClient.Kube(), s.xdsServer, certOption)
if err != nil {
return err
}
s.certServer = certServer
log.Infof("init cert default config")
s.certServer.InitDefaultConfig()
if !s.EnableAutomaticHttps {
log.Info("automatic https is disabled")
return nil
}
return s.certServer.InitServer()
}
func (s *Server) initKubeClient() error {
if s.kubeClient != nil {
// Already initialized by startup arguments
@@ -394,6 +433,7 @@ func (s *Server) initHttpServer() error {
}
s.xdsServer.AddDebugHandlers(s.httpMux, nil, true, nil)
s.httpMux.HandleFunc("/ready", s.readyHandler)
s.httpMux.HandleFunc("/registry/watcherStatus", s.registryWatcherStatusHandler)
return nil
}
@@ -409,6 +449,43 @@ func (s *Server) readyHandler(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
}
func (s *Server) registryWatcherStatusHandler(w http.ResponseWriter, _ *http.Request) {
ingressTranslation, ok := s.environment.IngressStore.(*translation.IngressTranslation)
if !ok {
http.Error(w, "IngressStore not found", http.StatusNotFound)
return
}
ingressConfig := ingressTranslation.GetIngressConfig()
if ingressConfig == nil {
http.Error(w, "IngressConfig not found", http.StatusNotFound)
return
}
registryReconciler := ingressConfig.RegistryReconciler
if registryReconciler == nil {
http.Error(w, "RegistryReconciler not found", http.StatusNotFound)
return
}
watcherStatusList := registryReconciler.GetRegistryWatcherStatusList()
writeJSON(w, watcherStatusList)
}
func writeJSON(w http.ResponseWriter, obj interface{}) {
w.Header().Set("Content-Type", "application/json")
b, err := config.ToJSON(obj)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(err.Error()))
return
}
_, err = w.Write(b)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
// cachesSynced checks whether caches have been synced.
func (s *Server) cachesSynced() bool {
return s.configController.HasSynced()

250
pkg/cert/certmgr.go Normal file
View File

@@ -0,0 +1,250 @@
// 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 cert
import (
"context"
"fmt"
"os"
"reflect"
"sync"
"github.com/caddyserver/certmagic"
"github.com/mholt/acmez"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"istio.io/istio/pilot/pkg/model"
"k8s.io/client-go/kubernetes"
)
const (
EventCertObtained = "cert_obtained"
)
var (
cfg *certmagic.Config
)
type CertMgr struct {
cfg *certmagic.Config
client kubernetes.Interface
namespace string
mux sync.RWMutex
storage certmagic.Storage
cache *certmagic.Cache
myACME *certmagic.ACMEIssuer
ingressSolver acmez.Solver
configMgr *ConfigMgr
secretMgr *SecretMgr
XDSUpdater model.XDSUpdater
}
func InitCertMgr(opts *Option, clientSet kubernetes.Interface, config *Config, XDSUpdater model.XDSUpdater, configMgr *ConfigMgr) (*CertMgr, error) {
CertLog.Infof("certmgr init config: %+v", config)
// Init certmagic config
// First make a pointer to a Cache as we need to reference the same Cache in
// GetConfigForCert below.
var cache *certmagic.Cache
var storage certmagic.Storage
storage, _ = NewConfigmapStorage(opts.Namespace, clientSet)
renewalWindowRatio := float64(config.RenewBeforeDays) / float64(RenewMaxDays)
logger := zap.New(zapcore.NewCore(
zapcore.NewConsoleEncoder(zap.NewProductionEncoderConfig()),
os.Stderr,
zap.DebugLevel,
))
magicConfig := certmagic.Config{
RenewalWindowRatio: renewalWindowRatio,
Storage: storage,
Logger: logger,
}
cache = certmagic.NewCache(certmagic.CacheOptions{
GetConfigForCert: func(cert certmagic.Certificate) (*certmagic.Config, error) {
// Here we use New to get a valid Config associated with the same cache.
// The provided Config is used as a template and will be completed with
// any defaults that are set in the Default config.
return cfg, nil
},
Logger: logger,
})
// init certmagic
cfg = certmagic.New(cache, magicConfig)
// Init certmagic acme
issuer := config.GetIssuer(IssuerTypeLetsencrypt)
if issuer == nil {
// should never happen here
return nil, fmt.Errorf("there is no Letsencrypt Issuer found in config")
}
myACME := certmagic.NewACMEIssuer(cfg, certmagic.ACMEIssuer{
//CA: certmagic.LetsEncryptStagingCA,
CA: certmagic.LetsEncryptProductionCA,
Email: issuer.Email,
Agreed: true,
DisableHTTPChallenge: false,
DisableTLSALPNChallenge: true,
})
// inject http01 solver
ingressSolver, _ := NewIngressSolver(opts.Namespace, clientSet, myACME)
myACME.Http01Solver = ingressSolver
// init issuers
cfg.Issuers = []certmagic.Issuer{myACME}
secretMgr, _ := NewSecretMgr(opts.Namespace, clientSet)
certMgr := &CertMgr{
cfg: cfg,
client: clientSet,
namespace: opts.Namespace,
myACME: myACME,
ingressSolver: ingressSolver,
configMgr: configMgr,
secretMgr: secretMgr,
cache: cache,
XDSUpdater: XDSUpdater,
}
certMgr.cfg.OnEvent = certMgr.OnEvent
return certMgr, nil
}
func (s *CertMgr) Reconcile(ctx context.Context, oldConfig *Config, newConfig *Config) error {
CertLog.Infof("cermgr reconcile old config:%+v to new config:%+v", oldConfig, newConfig)
// sync email
if oldConfig != nil && newConfig != nil {
oldIssuer := oldConfig.GetIssuer(IssuerTypeLetsencrypt)
newIssuer := newConfig.GetIssuer(IssuerTypeLetsencrypt)
if oldIssuer.Email != newIssuer.Email {
// TODO before sync email, maybe need to clean up cache and account
}
}
// sync domains
newDomains := make([]string, 0)
newDomainsMap := make(map[string]string, 0)
removeDomains := make([]string, 0)
if newConfig != nil {
for _, config := range newConfig.CredentialConfig {
if config.TLSIssuer == IssuerTypeLetsencrypt {
for _, newDomain := range config.Domains {
newDomains = append(newDomains, newDomain)
newDomainsMap[newDomain] = newDomain
}
}
}
}
if oldConfig != nil {
for _, config := range oldConfig.CredentialConfig {
if config.TLSIssuer == IssuerTypeLetsencrypt {
for _, oldDomain := range config.Domains {
if _, ok := newDomainsMap[oldDomain]; !ok {
removeDomains = append(removeDomains, oldDomain)
}
}
}
}
}
if newConfig.AutomaticHttps == true {
newIssuer := newConfig.GetIssuer(IssuerTypeLetsencrypt)
// clean up unused domains
s.cleanSync(context.Background(), removeDomains)
// sync email
s.myACME.Email = newIssuer.Email
// sync RenewalWindowRatio
renewalWindowRatio := float64(newConfig.RenewBeforeDays) / float64(RenewMaxDays)
s.cfg.RenewalWindowRatio = renewalWindowRatio
// start cache
s.cache.Start()
// sync domains
s.configMgr.SetConfig(newConfig)
CertLog.Infof("certMgr start to manageSync domains:+v%", newDomains)
s.manageSync(context.Background(), newDomains)
CertLog.Infof("certMgr manageSync domains done")
} else {
// stop cache maintainAssets
s.cache.Stop()
s.configMgr.SetConfig(newConfig)
}
if oldConfig != nil && newConfig != nil {
if oldConfig.FallbackForInvalidSecret != newConfig.FallbackForInvalidSecret || !reflect.DeepEqual(oldConfig.CredentialConfig, newConfig.CredentialConfig) {
CertLog.Infof("ingress need to full push")
s.XDSUpdater.ConfigUpdate(&model.PushRequest{
Full: true,
Reason: []model.TriggerReason{"higress-https-updated"},
})
}
}
return nil
}
func (s *CertMgr) manageSync(ctx context.Context, domainNames []string) error {
CertLog.Infof("cert manage sync domains:%v", domainNames)
return s.cfg.ManageSync(ctx, domainNames)
}
func (s *CertMgr) cleanSync(ctx context.Context, domainNames []string) error {
//TODO implement clean up domains
CertLog.Infof("cert clean sync domains:%v", domainNames)
return nil
}
func (s *CertMgr) OnEvent(ctx context.Context, event string, data map[string]any) error {
CertLog.Infof("certmgr receive event:% data:%+v", event, data)
/**
event: cert_obtained
cfg.emit(ctx, "cert_obtained", map[string]any{
"renewal": true,
"remaining": timeLeft,
"identifier": name,
"issuer": issuerKey,
"storage_path": StorageKeys.CertsSitePrefix(issuerKey, certKey),
"private_key_path": StorageKeys.SitePrivateKey(issuerKey, certKey),
"certificate_path": StorageKeys.SiteCert(issuerKey, certKey),
"metadata_path": StorageKeys.SiteMeta(issuerKey, certKey),
})
*/
if event == EventCertObtained {
// obtain certificate and update secret
domain := data["identifier"].(string)
isRenew := data["renewal"].(bool)
privateKeyPath := data["private_key_path"].(string)
certificatePath := data["certificate_path"].(string)
privateKey, err := s.cfg.Storage.Load(context.Background(), privateKeyPath)
certificate, err := s.cfg.Storage.Load(context.Background(), certificatePath)
certChain, err := parseCertsFromPEMBundle(certificate)
if err != nil {
return err
}
notAfterTime := notAfter(certChain[0])
notBeforeTime := notBefore(certChain[0])
secretName := s.configMgr.GetConfig().GetSecretNameByDomain(IssuerTypeLetsencrypt, domain)
if len(secretName) == 0 {
CertLog.Errorf("can not find secret name for domain % in config", domain)
return nil
}
err2 := s.secretMgr.Update(domain, secretName, privateKey, certificate, notBeforeTime, notAfterTime, isRenew)
if err2 != nil {
CertLog.Errorf("update secretName %s for domain %s error: %v", secretName, domain, err2)
}
return err
}
return nil
}

311
pkg/cert/config.go Normal file
View File

@@ -0,0 +1,311 @@
// 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 cert
import (
"context"
"fmt"
"strings"
"sync/atomic"
"time"
"istio.io/istio/pkg/config/host"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"sigs.k8s.io/yaml"
)
const (
ConfigmapCertName = "higress-https"
ConfigmapCertConfigKey = "cert"
DefaultRenewBeforeDays = 30
RenewMaxDays = 90
)
type IssuerName string
const (
IssuerTypeAliyunSSL IssuerName = "aliyunssl"
IssuerTypeLetsencrypt IssuerName = "letsencrypt"
)
// Config is the configuration of automatic https.
type Config struct {
AutomaticHttps bool `json:"automaticHttps"`
FallbackForInvalidSecret bool `json:"fallbackForInvalidSecret"`
RenewBeforeDays int `json:"renewBeforeDays"`
CredentialConfig []CredentialEntry `json:"credentialConfig"`
ACMEIssuer []ACMEIssuerEntry `json:"acmeIssuer"`
Version string `json:"version"`
}
func (c *Config) GetIssuer(issuerName IssuerName) *ACMEIssuerEntry {
for _, issuer := range c.ACMEIssuer {
if issuer.Name == issuerName {
return &issuer
}
}
return nil
}
func (c *Config) MatchSecretNameByDomain(domain string) string {
for _, credential := range c.CredentialConfig {
for _, credDomain := range credential.Domains {
if host.Name(strings.ToLower(domain)).SubsetOf(host.Name(strings.ToLower(credDomain))) {
return credential.TLSSecret
}
}
}
return ""
}
func (c *Config) GetSecretNameByDomain(issuerName IssuerName, domain string) string {
for _, credential := range c.CredentialConfig {
if credential.TLSIssuer == issuerName {
for _, credDomain := range credential.Domains {
if host.Name(strings.ToLower(domain)).SubsetOf(host.Name(strings.ToLower(credDomain))) {
return credential.TLSSecret
}
}
}
}
return ""
}
func ParseTLSSecret(tlsSecret string) (string, string) {
secrets := strings.Split(tlsSecret, "/")
switch len(secrets) {
case 1:
return "", tlsSecret
case 2:
return secrets[0], secrets[1]
}
return "", ""
}
func (c *Config) Validate() error {
// check acmeIssuer
if c.AutomaticHttps {
if len(c.ACMEIssuer) == 0 {
return fmt.Errorf("no acmeIssuer configuration found when automaticHttps is enable")
}
for _, issuer := range c.ACMEIssuer {
switch issuer.Name {
case IssuerTypeLetsencrypt:
if issuer.Email == "" {
return fmt.Errorf("acmeIssuer %s email is empty", issuer.Name)
}
if !ValidateEmail(issuer.Email) {
return fmt.Errorf("acmeIssuer %s email %s is invalid", issuer.Name, issuer.Email)
}
default:
return fmt.Errorf("acmeIssuer name %s is not supported", issuer.Name)
}
}
}
// check credentialConfig
for _, credential := range c.CredentialConfig {
if len(credential.Domains) == 0 {
return fmt.Errorf("credentialConfig domains is empty")
}
if credential.TLSSecret == "" {
return fmt.Errorf("credentialConfig tlsSecret is empty")
} else {
ns, secret := ParseTLSSecret(credential.TLSSecret)
if ns == "" && secret == "" {
return fmt.Errorf("credentialConfig tlsSecret %s is not supported", credential.TLSSecret)
}
}
if credential.TLSIssuer == IssuerTypeLetsencrypt {
if len(credential.Domains) > 1 {
return fmt.Errorf("credentialConfig tlsIssuer %s only support one domain", credential.TLSIssuer)
}
}
if credential.TLSIssuer != IssuerTypeLetsencrypt && len(credential.TLSIssuer) > 0 {
return fmt.Errorf("credential tls issuer %s is not supported", credential.TLSIssuer)
}
}
if c.RenewBeforeDays <= 0 {
return fmt.Errorf("RenewBeforeDays should be large than zero")
}
if c.RenewBeforeDays >= RenewMaxDays {
return fmt.Errorf("RenewBeforeDays should be less than %d", RenewMaxDays)
}
return nil
}
type CredentialEntry struct {
Domains []string `json:"domains"`
TLSIssuer IssuerName `json:"tlsIssuer,omitempty"`
TLSSecret string `json:"tlsSecret,omitempty"`
CACertSecret string `json:"cacertSecret,omitempty"`
}
type ACMEIssuerEntry struct {
Name IssuerName `json:"name"`
Email string `json:"email"`
AK string `json:"ak"` // Only applicable for certain issuers like 'aliyunssl'
SK string `json:"sk"` // Only applicable for certain issuers like 'aliyunssl'
}
type ConfigMgr struct {
client kubernetes.Interface
config atomic.Value
namespace string
}
func (c *ConfigMgr) SetConfig(config *Config) {
c.config.Store(config)
}
func (c *ConfigMgr) GetConfig() *Config {
value := c.config.Load()
if value != nil {
if config, ok := value.(*Config); ok {
return config
}
}
return nil
}
func (c *ConfigMgr) InitConfig(email string) (*Config, error) {
var defaultConfig *Config
cm, err := c.GetConfigmap()
if err != nil {
if errors.IsNotFound(err) {
if len(strings.TrimSpace(email)) == 0 {
email = getRandEmail()
}
defaultConfig = newDefaultConfig(email)
err2 := c.ApplyConfigmap(defaultConfig)
if err2 != nil {
return nil, err2
}
}
return nil, err
} else {
defaultConfig, err = c.ParseConfigFromConfigmap(cm)
if err != nil {
return nil, err
}
}
return defaultConfig, nil
}
func (c *ConfigMgr) ParseConfigFromConfigmap(configmap *v1.ConfigMap) (*Config, error) {
if _, ok := configmap.Data[ConfigmapCertConfigKey]; !ok {
return nil, fmt.Errorf("no cert key %s in configmap %s", ConfigmapCertConfigKey, configmap.Name)
}
config := newDefaultConfig("")
if err := yaml.Unmarshal([]byte(configmap.Data[ConfigmapCertConfigKey]), config); err != nil {
return nil, fmt.Errorf("data:%s, convert to higress config error, error: %+v", configmap.Data[ConfigmapCertConfigKey], err)
}
// validate config
if err := config.Validate(); err != nil {
return nil, err
}
return config, nil
}
func (c *ConfigMgr) GetConfigFromConfigmap() (*Config, error) {
var config *Config
cm, err := c.GetConfigmap()
if err != nil {
return nil, err
} else {
config, err = c.ParseConfigFromConfigmap(cm)
if err != nil {
return nil, err
}
}
return config, nil
}
func (c *ConfigMgr) GetConfigmap() (configmap *v1.ConfigMap, err error) {
configmapName := ConfigmapCertName
cm, err := c.client.CoreV1().ConfigMaps(c.namespace).Get(context.Background(), configmapName, metav1.GetOptions{})
return cm, err
}
func (c *ConfigMgr) ApplyConfigmap(config *Config) error {
configmapName := ConfigmapCertName
cm := &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Namespace: c.namespace,
Name: configmapName,
},
}
bytes, err := yaml.Marshal(config)
if err != nil {
return err
}
cm.Data = make(map[string]string, 0)
cm.Data[ConfigmapCertConfigKey] = string(bytes)
_, err = c.client.CoreV1().ConfigMaps(c.namespace).Get(context.Background(), configmapName, metav1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
if _, err = c.client.CoreV1().ConfigMaps(c.namespace).Create(context.Background(), cm, metav1.CreateOptions{}); err != nil {
return err
}
} else {
return err
}
} else {
if _, err = c.client.CoreV1().ConfigMaps(c.namespace).Update(context.Background(), cm, metav1.UpdateOptions{}); err != nil {
return err
}
}
return nil
}
func NewConfigMgr(namespace string, client kubernetes.Interface) (*ConfigMgr, error) {
configMgr := &ConfigMgr{
client: client,
namespace: namespace,
}
return configMgr, nil
}
func newDefaultConfig(email string) *Config {
defaultIssuer := []ACMEIssuerEntry{
{
Name: IssuerTypeLetsencrypt,
Email: email,
},
}
defaultCredentialConfig := make([]CredentialEntry, 0)
config := &Config{
AutomaticHttps: true,
FallbackForInvalidSecret: false,
RenewBeforeDays: DefaultRenewBeforeDays,
ACMEIssuer: defaultIssuer,
CredentialConfig: defaultCredentialConfig,
Version: time.Now().Format("20060102030405"),
}
return config
}
func getRandEmail() string {
num1 := rangeRandom(100, 100000)
num2 := rangeRandom(100, 100000)
return fmt.Sprintf("your%d@yours%d.com", num1, num2)
}

155
pkg/cert/config_test.go Normal file
View File

@@ -0,0 +1,155 @@
// 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 cert
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestMatchSecretNameByDomain(t *testing.T) {
tests := []struct {
name string
domain string
credentialCfg []CredentialEntry
expected string
}{
{
name: "Exact match",
domain: "example.com",
credentialCfg: []CredentialEntry{
{
Domains: []string{"example.com"},
TLSSecret: "example-com-tls",
},
},
expected: "example-com-tls",
},
{
name: "Exact match ignore case ",
domain: "eXample.com",
credentialCfg: []CredentialEntry{
{
Domains: []string{"example.com"},
TLSSecret: "example-com-tls",
},
},
expected: "example-com-tls",
},
{
name: "Wildcard match",
domain: "sub.example.com",
credentialCfg: []CredentialEntry{
{
Domains: []string{"*.example.com"},
TLSSecret: "wildcard-example-com-tls",
},
},
expected: "wildcard-example-com-tls",
},
{
name: "Wildcard match ignore case",
domain: "sub.Example.com",
credentialCfg: []CredentialEntry{
{
Domains: []string{"*.example.com"},
TLSSecret: "wildcard-example-com-tls",
},
},
expected: "wildcard-example-com-tls",
},
{
name: "* match",
domain: "blog.example.co.uk",
credentialCfg: []CredentialEntry{
{
Domains: []string{"*"},
TLSSecret: "blog-co-uk-tls",
},
},
expected: "blog-co-uk-tls",
},
{
name: "No match",
domain: "unknown.com",
credentialCfg: []CredentialEntry{
{
Domains: []string{"example.com"},
TLSSecret: "example-com-tls",
},
},
expected: "",
},
{
name: "Multiple matches - first match wins",
domain: "example.com",
credentialCfg: []CredentialEntry{
{
Domains: []string{"example.com"},
TLSSecret: "example-com-tls",
},
{
Domains: []string{"*.example.com"},
TLSSecret: "wildcard-example-com-tls",
},
},
expected: "example-com-tls",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cfg := Config{CredentialConfig: tt.credentialCfg}
result := cfg.MatchSecretNameByDomain(tt.domain)
assert.Equal(t, tt.expected, result)
})
}
}
func TestParseTLSSecret(t *testing.T) {
tests := []struct {
tlsSecret string
expectedNamespace string
expectedSecretName string
}{
{
tlsSecret: "example-com-tls",
expectedNamespace: "",
expectedSecretName: "example-com-tls",
},
{
tlsSecret: "kube-system/example-com-tls",
expectedNamespace: "kube-system",
expectedSecretName: "example-com-tls",
},
{
tlsSecret: "kube-system/example-com/wildcard",
expectedNamespace: "",
expectedSecretName: "",
},
}
for _, tt := range tests {
t.Run(tt.tlsSecret, func(t *testing.T) {
resultNamespace, resultSecretName := ParseTLSSecret(tt.tlsSecret)
assert.Equal(t, tt.expectedNamespace, resultNamespace)
assert.Equal(t, tt.expectedSecretName, resultSecretName)
})
}
}

165
pkg/cert/controller.go Normal file
View File

@@ -0,0 +1,165 @@
// 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 cert
import (
"context"
"fmt"
"reflect"
"time"
"k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/informers"
v1informer "k8s.io/client-go/informers/core/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
)
const (
workNum = 1
maxRetry = 2
configMapName = "higress-https"
)
type Controller struct {
namespace string
ConfigMapInformer v1informer.ConfigMapInformer
client kubernetes.Interface
queue workqueue.RateLimitingInterface
configMgr *ConfigMgr
server *Server
certMgr *CertMgr
factory informers.SharedInformerFactory
}
func (c *Controller) addConfigmap(obj interface{}) {
key, err := cache.MetaNamespaceKeyFunc(obj)
if err != nil {
return
}
namespace, name, _ := cache.SplitMetaNamespaceKey(key)
if namespace != c.namespace || name != configMapName {
return
}
c.enqueue(name)
}
func (c *Controller) updateConfigmap(oldObj interface{}, newObj interface{}) {
key, err := cache.MetaNamespaceKeyFunc(oldObj)
if err != nil {
return
}
namespace, name, _ := cache.SplitMetaNamespaceKey(key)
if namespace != c.namespace || name != configMapName {
return
}
if reflect.DeepEqual(oldObj, newObj) {
return
}
c.enqueue(name)
}
func (c *Controller) enqueue(name string) {
c.queue.Add(name)
}
func (c *Controller) cachesSynced() bool {
return c.ConfigMapInformer.Informer().HasSynced()
}
func (c *Controller) Run(stopCh <-chan struct{}) error {
defer runtime.HandleCrash()
defer c.queue.ShutDown()
CertLog.Info("Waiting for informer caches to sync")
c.factory.Start(stopCh)
if ok := cache.WaitForCacheSync(stopCh, c.cachesSynced); !ok {
return fmt.Errorf("failed to wait for caches to sync")
}
CertLog.Info("Starting controller")
// Launch one workers to process configmap resources
for i := 0; i < workNum; i++ {
go wait.Until(c.worker, time.Minute, stopCh)
}
CertLog.Info("Started workers")
<-stopCh
CertLog.Info("Shutting down workers")
return nil
}
func (c *Controller) worker() {
for c.processNextItem() {
}
}
func (c *Controller) processNextItem() bool {
item, shutdown := c.queue.Get()
if shutdown {
return false
}
defer c.queue.Done(item)
key := item.(string)
CertLog.Infof("controller process item:%s", key)
err := c.syncConfigmap(key)
if err != nil {
c.handleError(key, err)
}
return true
}
func (c *Controller) syncConfigmap(key string) error {
configmap, err := c.ConfigMapInformer.Lister().ConfigMaps(c.namespace).Get(key)
if err != nil {
return err
}
newConfig, err := c.configMgr.ParseConfigFromConfigmap(configmap)
if err != nil {
return err
}
oldConfig := c.configMgr.GetConfig()
// reconcile old config and new config
return c.certMgr.Reconcile(context.Background(), oldConfig, newConfig)
}
func (c *Controller) handleError(key string, err error) {
runtime.HandleError(err)
CertLog.Errorf("%+v", err)
c.queue.Forget(key)
}
func NewController(client kubernetes.Interface, namespace string, certMgr *CertMgr, configMgr *ConfigMgr) (*Controller, error) {
kubeInformerFactory := informers.NewSharedInformerFactoryWithOptions(client, 0, informers.WithNamespace(namespace))
configmapInformer := kubeInformerFactory.Core().V1().ConfigMaps()
c := &Controller{
certMgr: certMgr,
configMgr: configMgr,
client: client,
namespace: namespace,
factory: kubeInformerFactory,
ConfigMapInformer: configmapInformer,
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "ingressManage"),
}
CertLog.Info("Setting up configmap informer event handlers")
configmapInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: c.addConfigmap,
UpdateFunc: c.updateConfigmap,
})
return c, nil
}

158
pkg/cert/ingress.go Normal file
View File

@@ -0,0 +1,158 @@
// 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 cert
import (
"context"
"strings"
"sync"
"time"
"github.com/caddyserver/certmagic"
"github.com/mholt/acmez"
"github.com/mholt/acmez/acme"
v1 "k8s.io/api/networking/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
const (
IngressClassName = "higress"
IngressServiceName = "higress-controller"
IngressNamePefix = "higress-http-solver-"
IngressPathPrefix = "/.well-known/acme-challenge/"
IngressServicePort = 8889
)
type IngressSolver struct {
client kubernetes.Interface
acmeIssuer *certmagic.ACMEIssuer
solversMu sync.Mutex
namespace string
ingressDelay time.Duration
}
func NewIngressSolver(namespace string, client kubernetes.Interface, acmeIssuer *certmagic.ACMEIssuer) (acmez.Solver, error) {
solver := &IngressSolver{
namespace: namespace,
client: client,
acmeIssuer: acmeIssuer,
ingressDelay: 5 * time.Second,
}
return solver, nil
}
func (s *IngressSolver) Present(_ context.Context, challenge acme.Challenge) error {
CertLog.Infof("ingress solver present challenge:%+v", challenge)
s.solversMu.Lock()
defer s.solversMu.Unlock()
ingressName := s.getIngressName(challenge)
ingress := s.constructIngress(challenge)
CertLog.Infof("update ingress name:%s, ingress:%v", ingressName, ingress)
_, err := s.client.NetworkingV1().Ingresses(s.namespace).Get(context.Background(), ingressName, metav1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
// create ingress
_, err2 := s.client.NetworkingV1().Ingresses(s.namespace).Create(context.Background(), ingress, metav1.CreateOptions{})
return err2
}
return err
}
_, err1 := s.client.NetworkingV1().Ingresses(s.namespace).Update(context.Background(), ingress, metav1.UpdateOptions{})
if err1 != nil {
return err1
}
return nil
}
func (s *IngressSolver) Wait(ctx context.Context, challenge acme.Challenge) error {
CertLog.Infof("ingress solver wait challenge:%+v", challenge)
// wait for ingress ready
if s.ingressDelay > 0 {
select {
case <-time.After(s.ingressDelay):
case <-ctx.Done():
return ctx.Err()
}
}
CertLog.Infof("ingress solver wait challenge done")
return nil
}
func (s *IngressSolver) CleanUp(_ context.Context, challenge acme.Challenge) error {
CertLog.Infof("ingress solver cleanup challenge:%+v", challenge)
s.solversMu.Lock()
defer s.solversMu.Unlock()
ingressName := s.getIngressName(challenge)
CertLog.Infof("cleanup ingress name:%s", ingressName)
err := s.client.NetworkingV1().Ingresses(s.namespace).Delete(context.Background(), ingressName, metav1.DeleteOptions{})
if err != nil {
return err
}
return nil
}
func (s *IngressSolver) Delete(_ context.Context, challenge acme.Challenge) error {
s.solversMu.Lock()
defer s.solversMu.Unlock()
err := s.client.NetworkingV1().Ingresses(s.namespace).Delete(context.Background(), s.getIngressName(challenge), metav1.DeleteOptions{})
if err != nil {
return err
}
return nil
}
func (s *IngressSolver) getIngressName(challenge acme.Challenge) string {
return IngressNamePefix + strings.ReplaceAll(challenge.Identifier.Value, ".", "-")
}
func (s *IngressSolver) constructIngress(challenge acme.Challenge) *v1.Ingress {
ingressClassName := IngressClassName
ingressDomain := challenge.Identifier.Value
ingressPath := IngressPathPrefix + challenge.Token
ingress := v1.Ingress{}
ingress.Name = s.getIngressName(challenge)
ingress.Namespace = s.namespace
pathType := v1.PathTypePrefix
ingress.Spec = v1.IngressSpec{
IngressClassName: &ingressClassName,
Rules: []v1.IngressRule{
{
Host: ingressDomain,
IngressRuleValue: v1.IngressRuleValue{
HTTP: &v1.HTTPIngressRuleValue{
Paths: []v1.HTTPIngressPath{
{
Path: ingressPath,
PathType: &pathType,
Backend: v1.IngressBackend{
Service: &v1.IngressServiceBackend{
Name: IngressServiceName,
Port: v1.ServiceBackendPort{
Number: IngressServicePort,
},
},
},
},
},
},
},
},
},
}
return &ingress
}

19
pkg/cert/log.go Normal file
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 cert
import "istio.io/pkg/log"
var CertLog = log.RegisterScope("cert", "Higress Cert process.", 0)

101
pkg/cert/secret.go Normal file
View File

@@ -0,0 +1,101 @@
// 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 cert
import (
"context"
"fmt"
"strconv"
"time"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
type SecretMgr struct {
client kubernetes.Interface
namespace string
}
func NewSecretMgr(namespace string, client kubernetes.Interface) (*SecretMgr, error) {
secretMgr := &SecretMgr{
namespace: namespace,
client: client,
}
return secretMgr, nil
}
func (s *SecretMgr) Update(domain string, secretName string, privateKey []byte, certificate []byte, notBefore time.Time, notAfter time.Time, isRenew bool) error {
CertLog.Infof("update secret, domain:%s, secretName:%s, notBefore:%v, notAfter:%v, isRenew:%t", domain, secretName, notBefore, notAfter, isRenew)
name := secretName
namespace := s.namespace
namespaceP, secretP := ParseTLSSecret(secretName)
if namespaceP != "" {
namespace = namespaceP
name = secretP
}
secret := s.constructSecret(domain, name, namespace, privateKey, certificate, notBefore, notAfter, isRenew)
_, err := s.client.CoreV1().Secrets(namespace).Get(context.Background(), name, metav1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
// create secret
_, err2 := s.client.CoreV1().Secrets(namespace).Create(context.Background(), secret, metav1.CreateOptions{})
return err2
}
return err
}
// check secret annotations
if _, ok := secret.Annotations["higress.io/cert-domain"]; !ok {
return fmt.Errorf("the secret name %s is not automatic https secret name for the domain:%s, please rename it in config", secretName, domain)
}
_, err1 := s.client.CoreV1().Secrets(namespace).Update(context.Background(), secret, metav1.UpdateOptions{})
if err1 != nil {
return err1
}
return nil
}
func (s *SecretMgr) constructSecret(domain string, name string, namespace string, privateKey []byte, certificate []byte, notBefore time.Time, notAfter time.Time, isRenew bool) *v1.Secret {
annotationMap := make(map[string]string, 0)
annotationMap["higress.io/cert-domain"] = domain
annotationMap["higress.io/cert-notAfter"] = notAfter.Format("2006-01-02 15:04:05")
annotationMap["higress.io/cert-notBefore"] = notBefore.Format("2006-01-02 15:04:05")
annotationMap["higress.io/cert-renew"] = strconv.FormatBool(isRenew)
annotationMap["higress.io/cert-source"] = string(IssuerTypeLetsencrypt)
if isRenew {
annotationMap["higress.io/cert-renew-time"] = time.Now().Format("2006-01-02 15:04:05")
}
// Required fields:
// - Secret.Data["tls.key"] - TLS private key.
// Secret.Data["tls.crt"] - TLS certificate.
dataMap := make(map[string][]byte, 0)
dataMap["tls.key"] = privateKey
dataMap["tls.crt"] = certificate
secret := &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Annotations: annotationMap,
},
Type: v1.SecretTypeTLS,
Data: dataMap,
}
return secret
}

118
pkg/cert/server.go Normal file
View File

@@ -0,0 +1,118 @@
// 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 cert
import (
"context"
"fmt"
"net"
"net/http"
"time"
"github.com/caddyserver/certmagic"
"istio.io/istio/pilot/pkg/model"
"k8s.io/client-go/kubernetes"
)
type Option struct {
Namespace string
ServerAddress string
Email string
}
type Server struct {
httpServer *http.Server
opts *Option
clientSet kubernetes.Interface
controller *Controller
certMgr *CertMgr
XDSUpdater model.XDSUpdater
}
func NewServer(clientSet kubernetes.Interface, XDSUpdater model.XDSUpdater, opts *Option) (*Server, error) {
server := &Server{
clientSet: clientSet,
opts: opts,
XDSUpdater: XDSUpdater,
}
return server, nil
}
func (s *Server) InitDefaultConfig() error {
configMgr, _ := NewConfigMgr(s.opts.Namespace, s.clientSet)
// init config if there is not existed
_, err := configMgr.InitConfig(s.opts.Email)
if err != nil {
return err
}
return nil
}
func (s *Server) InitServer() error {
configMgr, _ := NewConfigMgr(s.opts.Namespace, s.clientSet)
// init config if there is not existed
defaultConfig, err := configMgr.InitConfig(s.opts.Email)
if err != nil {
return err
}
// init certmgr
certMgr, err := InitCertMgr(s.opts, s.clientSet, defaultConfig, s.XDSUpdater, configMgr) // config and start
s.certMgr = certMgr
// init controller
controller, err := NewController(s.clientSet, s.opts.Namespace, certMgr, configMgr)
s.controller = controller
// init http server
s.initHttpServer()
return nil
}
func (s *Server) initHttpServer() error {
CertLog.Infof("server init http server")
ctx := context.Background()
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Lookit my cool website over HTTPS!")
})
httpServer := &http.Server{
ReadHeaderTimeout: 5 * time.Second,
ReadTimeout: 5 * time.Second,
WriteTimeout: 5 * time.Second,
IdleTimeout: 5 * time.Second,
Addr: s.opts.ServerAddress,
BaseContext: func(listener net.Listener) context.Context { return ctx },
}
cfg := s.certMgr.cfg
if len(cfg.Issuers) > 0 {
if am, ok := cfg.Issuers[0].(*certmagic.ACMEIssuer); ok {
httpServer.Handler = am.HTTPChallengeHandler(mux)
}
} else {
httpServer.Handler = mux
}
s.httpServer = httpServer
return nil
}
func (s *Server) Run(stopCh <-chan struct{}) error {
go s.controller.Run(stopCh)
CertLog.Infof("server run")
go func() {
<-stopCh
CertLog.Infof("server http server shutdown now...")
s.httpServer.Shutdown(context.Background())
}()
err := s.httpServer.ListenAndServe()
return err
}

352
pkg/cert/storage.go Normal file
View File

@@ -0,0 +1,352 @@
// 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 cert
import (
"context"
"encoding/json"
"fmt"
"io/fs"
"path"
"strings"
"sync"
"time"
"github.com/caddyserver/certmagic"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
const (
CertificatesPrefix = "certificates"
ConfigmapStoreCertficatesPrefix = "higress-cert-store-certificates-"
ConfigmapStoreDefaultName = "higress-cert-store-default"
)
var _ certmagic.Storage = (*ConfigmapStorage)(nil)
type ConfigmapStorage struct {
namespace string
client kubernetes.Interface
mux sync.RWMutex
}
type HashValue struct {
K string `json:"k,omitempty"`
V []byte `json:"v,omitempty"`
}
func NewConfigmapStorage(namespace string, client kubernetes.Interface) (certmagic.Storage, error) {
storage := &ConfigmapStorage{
namespace: namespace,
client: client,
}
return storage, nil
}
// Exists returns true if key exists in s.
func (s *ConfigmapStorage) Exists(_ context.Context, key string) bool {
s.mux.RLock()
defer s.mux.RUnlock()
cm, err := s.getConfigmapStoreByKey(key)
if err != nil {
return false
}
if cm.Data == nil {
return false
}
hashKey := fastHash([]byte(key))
if _, ok := cm.Data[hashKey]; ok {
return true
}
return false
}
// Store saves value at key.
func (s *ConfigmapStorage) Store(_ context.Context, key string, value []byte) error {
s.mux.Lock()
defer s.mux.Unlock()
cm, err := s.getConfigmapStoreByKey(key)
if err != nil {
return err
}
if cm.Data == nil {
cm.Data = make(map[string]string, 0)
}
hashKey := fastHash([]byte(key))
hashV := &HashValue{
K: key,
V: value,
}
bytes, err := json.Marshal(hashV)
if err != nil {
return err
}
cm.Data[hashKey] = string(bytes)
return s.updateConfigmap(cm)
}
// Load retrieves the value at key.
func (s *ConfigmapStorage) Load(_ context.Context, key string) ([]byte, error) {
s.mux.RLock()
defer s.mux.RUnlock()
var value []byte
cm, err := s.getConfigmapStoreByKey(key)
if err != nil {
return value, err
}
if cm.Data == nil {
return value, fs.ErrNotExist
}
hashKey := fastHash([]byte(key))
if v, ok := cm.Data[hashKey]; ok {
hV := &HashValue{}
err = json.Unmarshal([]byte(v), hV)
if err != nil {
return value, err
}
return hV.V, nil
}
return value, fs.ErrNotExist
}
// Delete deletes the value at key.
func (s *ConfigmapStorage) Delete(_ context.Context, key string) error {
s.mux.Lock()
defer s.mux.Unlock()
cm, err := s.getConfigmapStoreByKey(key)
if err != nil {
return err
}
if cm.Data == nil {
cm.Data = make(map[string]string, 0)
}
hashKey := fastHash([]byte(key))
delete(cm.Data, hashKey)
return s.updateConfigmap(cm)
}
// List returns all keys that match the prefix.
// If the prefix is "/certificates", it retrieves all ConfigMaps, otherwise only one.
func (s *ConfigmapStorage) List(ctx context.Context, prefix string, recursive bool) ([]string, error) {
s.mux.RLock()
defer s.mux.RUnlock()
var keys []string
var configmapKeys []string
visitedDirs := make(map[string]struct{})
// Check if the prefix corresponds to a specific key
hashPrefix := fastHash([]byte(prefix))
if strings.HasPrefix(prefix, CertificatesPrefix) {
// If the prefix is "certificates/", get all ConfigMaps and traverse each one
// List all ConfigMaps in the namespace with label higress.io/cert-https=true
configmaps, err := s.client.CoreV1().ConfigMaps(s.namespace).List(ctx, metav1.ListOptions{FieldSelector: "metadata.annotations['higress.io/cert-https'] == 'true'"})
if err != nil {
return keys, err
}
for _, cm := range configmaps.Items {
// Check if the ConfigMap name starts with the expected prefix
if strings.HasPrefix(cm.Name, ConfigmapStoreCertficatesPrefix) {
// Add the keys from Data field to the list
for _, v := range cm.Data {
// Unmarshal the value into hashValue struct
var hv HashValue
if err := json.Unmarshal([]byte(v), &hv); err != nil {
return nil, err
}
// Check if the key starts with the specified prefix
if strings.HasPrefix(hv.K, prefix) {
// Add the key to the list
configmapKeys = append(configmapKeys, hv.K)
}
}
}
}
} else {
// If not starting with "/certificates", get the specific ConfigMap
cm, err := s.getConfigmapStoreByKey(prefix)
if err != nil {
return keys, err
}
if _, ok := cm.Data[hashPrefix]; ok {
// The prefix corresponds to a specific key, add it to the list
configmapKeys = append(configmapKeys, prefix)
} else {
// The prefix is considered a directory
for _, v := range cm.Data {
// Unmarshal the value into hashValue struct
var hv HashValue
if err := json.Unmarshal([]byte(v), &hv); err != nil {
return nil, err
}
// Check if the key starts with the specified prefix
if strings.HasPrefix(hv.K, prefix) {
// Add the key to the list
configmapKeys = append(configmapKeys, hv.K)
}
}
}
}
// return all
if recursive {
return configmapKeys, nil
}
// only return sub dirs
for _, key := range configmapKeys {
subPath := strings.TrimPrefix(strings.ReplaceAll(key, prefix, ""), "/")
paths := strings.Split(subPath, "/")
if len(paths) > 0 {
subDir := path.Join(prefix, paths[0])
if _, ok := visitedDirs[subDir]; !ok {
keys = append(keys, subDir)
}
visitedDirs[subDir] = struct{}{}
}
}
return keys, nil
}
// Stat returns information about key. only support for no certificates path
func (s *ConfigmapStorage) Stat(_ context.Context, key string) (certmagic.KeyInfo, error) {
s.mux.RLock()
defer s.mux.RUnlock()
// Create a new KeyInfo struct
info := certmagic.KeyInfo{}
// Get the ConfigMap containing the keys
cm, err := s.getConfigmapStoreByKey(key)
if err != nil {
return info, err
}
// Check if the key exists in the ConfigMap
hashKey := fastHash([]byte(key))
if data, ok := cm.Data[hashKey]; ok {
// The key exists, populate the KeyInfo struct
info.Key = key
info.Modified = time.Now() // Since we're not tracking modification time in ConfigMap
info.Size = int64(len(data))
info.IsTerminal = true
} else {
// Check if there are other keys with the same prefix
prefixKeys := make([]string, 0)
for _, v := range cm.Data {
var hv HashValue
if err := json.Unmarshal([]byte(v), &hv); err != nil {
return info, err
}
// Check if the key starts with the specified prefix
if strings.HasPrefix(hv.K, key) {
// Add the key to the list
prefixKeys = append(prefixKeys, hv.K)
}
}
// If there are multiple keys with the same prefix, then it's not a terminal node
if len(prefixKeys) > 0 {
info.Key = key
info.IsTerminal = false
} else {
return info, fmt.Errorf("prefix '%s' is not existed", key)
}
}
return info, nil
}
// Lock obtains a lock named by the given name. It blocks
// until the lock can be obtained or an error is returned.
func (s *ConfigmapStorage) Lock(ctx context.Context, name string) error {
return nil
}
// Unlock releases the lock for name.
func (s *ConfigmapStorage) Unlock(_ context.Context, name string) error {
return nil
}
func (s *ConfigmapStorage) String() string {
return "ConfigmapStorage"
}
// getConfigmapStoreNameByKey determines the storage name for a given key.
// It checks if the key starts with 'certificates/' and if so, the key pattern should match one of the following:
// 'certificates/<issuerKey>/<domain>/<domain>.json',
// 'certificates/<issuerKey>/<domain>/<domain>.crt',
// or 'certificates/<issuerKey>/<domain>/<domain>.key'.
// It then returns the corresponding ConfigMap name.
// If the key does not start with 'certificates/', it returns the default store name.
//
// Parameters:
//
// key - The configuration map key that needs to be mapped to a storage name.
//
// Returns:
//
// string - The calculated or default storage name based on the key.
func (s *ConfigmapStorage) getConfigmapStoreNameByKey(key string) string {
if strings.HasPrefix(key, "certificates/") {
parts := strings.Split(key, "/")
if len(parts) >= 4 && parts[0] == "certificates" {
domain := parts[2]
issuerKey := parts[1]
return ConfigmapStoreCertficatesPrefix + fastHash([]byte(issuerKey+domain))
}
}
return ConfigmapStoreDefaultName
}
func (s *ConfigmapStorage) getConfigmapStoreByKey(key string) (*v1.ConfigMap, error) {
configmapName := s.getConfigmapStoreNameByKey(key)
cm, err := s.client.CoreV1().ConfigMaps(s.namespace).Get(context.Background(), configmapName, metav1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
// Save default ConfigMap
cm = &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Namespace: s.namespace,
Name: configmapName,
Annotations: map[string]string{"higress.io/cert-https": "true"},
},
}
_, err = s.client.CoreV1().ConfigMaps(s.namespace).Create(context.Background(), cm, metav1.CreateOptions{})
if err != nil {
return nil, err
}
} else {
return nil, err
}
}
return cm, nil
}
// updateConfigmap adds or updates the annotation higress.io/cert-https to true.
func (s *ConfigmapStorage) updateConfigmap(configmap *v1.ConfigMap) error {
if configmap.ObjectMeta.Annotations == nil {
configmap.ObjectMeta.Annotations = make(map[string]string)
}
configmap.ObjectMeta.Annotations["higress.io/cert-https"] = "true"
_, err := s.client.CoreV1().ConfigMaps(configmap.Namespace).Update(context.Background(), configmap, metav1.UpdateOptions{})
return err
}

332
pkg/cert/storage_test.go Normal file
View File

@@ -0,0 +1,332 @@
// 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 cert
import (
"context"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"testing"
"github.com/stretchr/testify/assert"
"k8s.io/client-go/kubernetes/fake"
)
func TestGetConfigmapStoreNameByKey(t *testing.T) {
// Create a fake client for testing
fakeClient := fake.NewSimpleClientset()
// Create a new ConfigmapStorage instance for testing
namespace := "your-namespace"
storage := &ConfigmapStorage{
namespace: namespace,
client: fakeClient,
}
tests := []struct {
name string
key string
expected string
}{
{
name: "certificate crt",
key: "certificates/issuerKey/domain/domain.crt",
expected: "higress-cert-store-certificates-" + fastHash([]byte("issuerKey"+"domain")),
},
{
name: "47.237.14.136.sslip.io crt",
key: "certificates/acme-v02.api.letsencrypt.org-directory/47.237.14.136.sslip.io/47.237.14.136.sslip.io.crt",
expected: "higress-cert-store-certificates-" + fastHash([]byte("acme-v02.api.letsencrypt.org-directory"+"47.237.14.136.sslip.io")),
},
{
name: "certificate meta",
key: "certificates/issuerKey/domain/domain.json",
expected: "higress-cert-store-certificates-" + fastHash([]byte("issuerKey"+"domain")),
},
{
name: "certificate key",
key: "certificates/issuerKey/domain/domain.key",
expected: "higress-cert-store-certificates-" + fastHash([]byte("issuerKey"+"domain")),
},
{
name: "user key",
key: "users/hello/2",
expected: "higress-cert-store-default",
},
{
name: "Empty Key",
key: "",
expected: "higress-cert-store-default",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
storageName := storage.getConfigmapStoreNameByKey(test.key)
assert.Equal(t, test.expected, storageName)
})
}
}
func TestExists(t *testing.T) {
// Create a fake client for testing
fakeClient := fake.NewSimpleClientset()
// Create a new ConfigmapStorage instance for testing
namespace := "your-namespace"
storage, err := NewConfigmapStorage(namespace, fakeClient)
assert.NoError(t, err)
// Store a test key
testKey := "certificates/issuer1/domain1/domain1.crt"
err = storage.Store(context.Background(), testKey, []byte("test-data"))
assert.NoError(t, err)
// Define test cases
tests := []struct {
name string
key string
shouldExist bool
}{
{
name: "Existing Key",
key: "certificates/issuer1/domain1/domain1.crt",
shouldExist: true,
},
{
name: "Non-Existent Key1",
key: "certificates/issuer2/domain2/domain2.crt",
shouldExist: false,
},
{
name: "Non-Existent Key2",
key: "users/hello/a",
shouldExist: false,
},
// Add more test cases as needed
}
// Run tests
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
exists := storage.Exists(context.Background(), test.key)
assert.Equal(t, test.shouldExist, exists)
})
}
}
func TestLoad(t *testing.T) {
// Create a fake client for testing
fakeClient := fake.NewSimpleClientset()
// Create a new ConfigmapStorage instance for testing
namespace := "your-namespace"
storage, err := NewConfigmapStorage(namespace, fakeClient)
assert.NoError(t, err)
// Store a test key
testKey := "certificates/issuer1/domain1/domain1.crt"
testValue := []byte("test-data")
err = storage.Store(context.Background(), testKey, testValue)
assert.NoError(t, err)
// Define test cases
tests := []struct {
name string
key string
expected []byte
shouldError bool
}{
{
name: "Existing Key",
key: "certificates/issuer1/domain1/domain1.crt",
expected: testValue,
shouldError: false,
},
{
name: "Non-Existent Key",
key: "certificates/issuer2/domain2/domain2.crt",
expected: nil,
shouldError: true,
},
// Add more test cases as needed
}
// Run tests
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
value, err := storage.Load(context.Background(), test.key)
if test.shouldError {
assert.Error(t, err)
assert.Nil(t, value)
} else {
assert.NoError(t, err)
assert.Equal(t, test.expected, value)
}
})
}
}
func TestStore(t *testing.T) {
// Create a fake client for testing
fakeClient := fake.NewSimpleClientset()
// Create a new ConfigmapStorage instance for testing
namespace := "your-namespace"
storage := ConfigmapStorage{
namespace: namespace,
client: fakeClient,
}
// Define test cases
tests := []struct {
name string
key string
value []byte
expected map[string]string
expectedConfigmapName string
shouldError bool
}{
{
name: "Store Key with certificates prefix",
key: "certificates/issuer1/domain1/domain1.crt",
value: []byte("test-data1"),
expected: map[string]string{fastHash([]byte("certificates/issuer1/domain1/domain1.crt")): `{"k":"certificates/issuer1/domain1/domain1.crt","v":"dGVzdC1kYXRhMQ=="}`},
expectedConfigmapName: "higress-cert-store-certificates-" + fastHash([]byte("issuer1"+"domain1")),
shouldError: false,
},
{
name: "Store Key with certificates prefix (additional data)",
key: "certificates/issuer2/domain2/domain2.crt",
value: []byte("test-data2"),
expected: map[string]string{
fastHash([]byte("certificates/issuer2/domain2/domain2.crt")): `{"k":"certificates/issuer2/domain2/domain2.crt","v":"dGVzdC1kYXRhMg=="}`,
},
expectedConfigmapName: "higress-cert-store-certificates-" + fastHash([]byte("issuer2"+"domain2")),
shouldError: false,
},
{
name: "Store Key without certificates prefix",
key: "other/path/data.txt",
value: []byte("test-data3"),
expected: map[string]string{fastHash([]byte("other/path/data.txt")): `{"k":"other/path/data.txt","v":"dGVzdC1kYXRhMw=="}`},
expectedConfigmapName: "higress-cert-store-default",
shouldError: false,
},
// Add more test cases as needed
}
// Run tests
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := storage.Store(context.Background(), test.key, test.value)
if test.shouldError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
// Check the contents of the ConfigMap after storing
configmapName := storage.getConfigmapStoreNameByKey(test.key)
cm, err := fakeClient.CoreV1().ConfigMaps(namespace).Get(context.Background(), configmapName, metav1.GetOptions{})
assert.NoError(t, err)
// Check if the data is as expected
assert.Equal(t, test.expected, cm.Data)
// Check if the configmapName is correct
assert.Equal(t, test.expectedConfigmapName, configmapName)
}
})
}
}
func TestList(t *testing.T) {
// Create a fake client for testing
fakeClient := fake.NewSimpleClientset()
// Create a new ConfigmapStorage instance for testing
namespace := "your-namespace"
storage, err := NewConfigmapStorage(namespace, fakeClient)
assert.NoError(t, err)
// Store some test data
// Store some test data
testKeys := []string{
"certificates/issuer1/domain1/domain1.crt",
"certificates/issuer1/domain2/domain2.crt",
"certificates/issuer1/domain3/domain3.crt", // Added another domain for issuer1
"certificates/issuer2/domain4/domain4.crt",
"certificates/issuer2/domain5/domain5.crt",
"certificates/issuer3/domain6/domain6.crt", // Two-level subdirectory under issuer3
"certificates/issuer3/subdomain1/subdomain2/domain7.crt", // Two more levels under issuer3
"other-prefix/key1/file1",
"other-prefix/key1/file2",
"other-prefix/key2/file3",
"other-prefix/key2/file4",
}
for _, key := range testKeys {
err := storage.Store(context.Background(), key, []byte("test-data"))
assert.NoError(t, err)
}
// Define test cases
tests := []struct {
name string
prefix string
recursive bool
expected []string
}{
{
name: "List Certificates (Non-Recursive)",
prefix: "certificates",
recursive: false,
expected: []string{"certificates/issuer1", "certificates/issuer2", "certificates/issuer3"},
},
{
name: "List Certificates (Recursive)",
prefix: "certificates",
recursive: true,
expected: []string{"certificates/issuer1/domain1/domain1.crt", "certificates/issuer1/domain2/domain2.crt", "certificates/issuer1/domain3/domain3.crt", "certificates/issuer2/domain4/domain4.crt", "certificates/issuer2/domain5/domain5.crt", "certificates/issuer3/domain6/domain6.crt", "certificates/issuer3/subdomain1/subdomain2/domain7.crt"},
},
{
name: "List Other Prefix (Non-Recursive)",
prefix: "other-prefix",
recursive: false,
expected: []string{"other-prefix/key1", "other-prefix/key2"},
},
{
name: "List Other Prefix (Non-Recursive)",
prefix: "other-prefix/key1",
recursive: false,
expected: []string{"other-prefix/key1/file1", "other-prefix/key1/file2"},
},
{
name: "List Other Prefix (Recursive)",
prefix: "other-prefix",
recursive: true,
expected: []string{"other-prefix/key1/file1", "other-prefix/key1/file2", "other-prefix/key2/file3", "other-prefix/key2/file4"},
},
}
// Run tests
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
keys, err := storage.List(context.Background(), test.prefix, test.recursive)
assert.NoError(t, err)
assert.ElementsMatch(t, test.expected, keys)
})
}
}

97
pkg/cert/util.go Normal file
View File

@@ -0,0 +1,97 @@
// 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 cert
import (
"crypto/x509"
"encoding/pem"
"fmt"
"hash/fnv"
"math/rand"
"net"
"regexp"
"time"
)
// parseCertsFromPEMBundle parses a certificate bundle from top to bottom and returns
// a slice of x509 certificates. This function will error if no certificates are found.
func parseCertsFromPEMBundle(bundle []byte) ([]*x509.Certificate, error) {
var certificates []*x509.Certificate
var certDERBlock *pem.Block
for {
certDERBlock, bundle = pem.Decode(bundle)
if certDERBlock == nil {
break
}
if certDERBlock.Type == "CERTIFICATE" {
cert, err := x509.ParseCertificate(certDERBlock.Bytes)
if err != nil {
return nil, err
}
certificates = append(certificates, cert)
}
}
if len(certificates) == 0 {
return nil, fmt.Errorf("no certificates found in bundle")
}
return certificates, nil
}
func notAfter(cert *x509.Certificate) time.Time {
if cert == nil {
return time.Time{}
}
return cert.NotAfter.Truncate(time.Second).Add(1 * time.Second)
}
func notBefore(cert *x509.Certificate) time.Time {
if cert == nil {
return time.Time{}
}
return cert.NotBefore.Truncate(time.Second).Add(1 * time.Second)
}
// hostOnly returns only the host portion of hostport.
// If there is no port or if there is an error splitting
// the port off, the whole input string is returned.
func hostOnly(hostport string) string {
host, _, err := net.SplitHostPort(hostport)
if err != nil {
return hostport // OK; probably had no port to begin with
}
return host
}
func rangeRandom(min, max int) (number int) {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
number = r.Intn(max-min) + min
return number
}
func ValidateEmail(email string) bool {
pattern := `^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`
regExp := regexp.MustCompile(pattern)
if regExp.MatchString(email) {
return true
} else {
return false
}
}
func fastHash(input []byte) string {
h := fnv.New32a()
h.Write(input)
return fmt.Sprintf("%x", h.Sum32())
}

View File

@@ -15,7 +15,8 @@
package hgctl
const (
yamlOutput = "yaml"
jsonOutput = "json"
flagsOutput = "flags"
summaryOutput = "short"
yamlOutput = "yaml"
jsonOutput = "json"
flagsOutput = "flags"
)

View File

@@ -19,6 +19,7 @@ import (
"github.com/alibaba/higress/cmd/hgctl/config"
"github.com/spf13/cobra"
"istio.io/istio/istioctl/pkg/writer/envoy/configdump"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
)
@@ -49,17 +50,23 @@ func runClusterConfig(c *cobra.Command, args []string) error {
if len(args) != 0 {
podName = args[0]
}
envoyConfig, err := config.GetEnvoyConfig(&config.GetEnvoyConfigOptions{
configWriter, err := config.GetEnvoyConfigWriter(&config.GetEnvoyConfigOptions{
PodName: podName,
PodNamespace: podNamespace,
BindAddress: bindAddress,
Output: output,
EnvoyConfigType: config.ClusterEnvoyConfigType,
IncludeEds: true,
})
}, c.OutOrStdout())
if err != nil {
return err
}
_, err = fmt.Fprintln(c.OutOrStdout(), string(envoyConfig))
return err
switch output {
case summaryOutput:
return configWriter.PrintClusterSummary(configdump.ClusterFilter{})
case jsonOutput, yamlOutput:
return configWriter.PrintClusterDump(configdump.ClusterFilter{}, output)
default:
return fmt.Errorf("output format %q not supported", output)
}
}

View File

@@ -52,7 +52,7 @@ func newConfigCommand() *cobra.Command {
flags := cfgCommand.Flags()
options.AddKubeConfigFlags(flags)
cfgCommand.PersistentFlags().StringVarP(&output, "output", "o", "json", "One of 'yaml' or 'json'")
cfgCommand.PersistentFlags().StringVarP(&output, "output", "o", "json", "Output format: one of json|yaml|short")
cfgCommand.PersistentFlags().StringVarP(&podNamespace, "namespace", "n", "higress-system", "Namespace where envoy proxy pod are installed.")
return cfgCommand

View File

@@ -19,6 +19,7 @@ import (
"github.com/alibaba/higress/cmd/hgctl/config"
"github.com/spf13/cobra"
"istio.io/istio/istioctl/pkg/writer/envoy/configdump"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
)
@@ -49,17 +50,23 @@ func runListenerConfig(c *cobra.Command, args []string) error {
if len(args) != 0 {
podName = args[0]
}
envoyConfig, err := config.GetEnvoyConfig(&config.GetEnvoyConfigOptions{
configWriter, err := config.GetEnvoyConfigWriter(&config.GetEnvoyConfigOptions{
PodName: podName,
PodNamespace: podNamespace,
BindAddress: bindAddress,
Output: output,
EnvoyConfigType: config.ListenerEnvoyConfigType,
IncludeEds: true,
})
}, c.OutOrStdout())
if err != nil {
return err
}
_, err = fmt.Fprintln(c.OutOrStdout(), string(envoyConfig))
return err
switch output {
case summaryOutput:
return configWriter.PrintListenerSummary(configdump.ListenerFilter{Verbose: true})
case jsonOutput, yamlOutput:
return configWriter.PrintListenerDump(configdump.ListenerFilter{Verbose: true}, output)
default:
return fmt.Errorf("output format %q not supported", output)
}
}

View File

@@ -19,6 +19,7 @@ import (
"github.com/alibaba/higress/cmd/hgctl/config"
"github.com/spf13/cobra"
"istio.io/istio/istioctl/pkg/writer/envoy/configdump"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
)
@@ -49,17 +50,23 @@ func runRouteConfig(c *cobra.Command, args []string) error {
if len(args) != 0 {
podName = args[0]
}
envoyConfig, err := config.GetEnvoyConfig(&config.GetEnvoyConfigOptions{
configWriter, err := config.GetEnvoyConfigWriter(&config.GetEnvoyConfigOptions{
PodName: podName,
PodNamespace: podNamespace,
BindAddress: bindAddress,
Output: output,
EnvoyConfigType: config.RouteEnvoyConfigType,
IncludeEds: true,
})
}, c.OutOrStdout())
if err != nil {
return err
}
_, err = fmt.Fprintln(c.OutOrStdout(), string(envoyConfig))
return err
switch output {
case summaryOutput:
return configWriter.PrintRouteSummary(configdump.RouteFilter{Verbose: true})
case jsonOutput, yamlOutput:
return configWriter.PrintRouteDump(configdump.RouteFilter{Verbose: true}, output)
default:
return fmt.Errorf("output format %q not supported", output)
}
}

View File

@@ -24,14 +24,13 @@ import (
"runtime"
"strings"
"github.com/alibaba/higress/pkg/cmd/hgctl/kubernetes"
"github.com/alibaba/higress/pkg/cmd/options"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/flags"
types2 "github.com/docker/docker/api/types"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
"github.com/alibaba/higress/pkg/cmd/hgctl/docker"
"github.com/alibaba/higress/pkg/cmd/hgctl/kubernetes"
"github.com/alibaba/higress/pkg/cmd/options"
)
var (
@@ -55,7 +54,9 @@ var (
proxyAdminPort int
docker = false
project = "higress"
dockerCli = false
)
const (
@@ -107,7 +108,7 @@ func newDashboardCmd() *cobra.Command {
consoleCmd := consoleDashCmd()
consoleCmd.PersistentFlags().IntVar(&consolePort, "ui-port", defaultConsolePort, "The component dashboard UI port.")
consoleCmd.PersistentFlags().BoolVar(&docker, "docker", false, "Search higress console from docker")
consoleCmd.PersistentFlags().BoolVar(&dockerCli, "docker", false, "Search higress console from docker")
dashboardCmd.AddCommand(consoleCmd)
controllerDebugCmd := controllerDebugCmd()
@@ -165,23 +166,23 @@ func consoleDashCmd() *cobra.Command {
hgctl dash console
hgctl d console`,
RunE: func(cmd *cobra.Command, args []string) error {
if docker {
return accessDocker(cmd)
if dockerCli {
return accessDockerCompose(cmd)
}
client, err := kubernetes.NewCLIClient(options.DefaultConfigFlags.ToRawKubeConfigLoader())
if err != nil {
fmt.Printf("build kubernetes CLI client fail: %v\ntry to access docker container\n", err)
return accessDocker(cmd)
return accessDockerCompose(cmd)
}
pl, err := client.PodsForSelector(addonNamespace, "app.kubernetes.io/name=higress-console")
if err != nil {
fmt.Printf("build kubernetes CLI client fail: %v\ntry to access docker container\n", err)
return accessDocker(cmd)
return accessDockerCompose(cmd)
}
if len(pl.Items) < 1 {
fmt.Printf("no higress console pods found\ntry to access docker container\n")
return accessDocker(cmd)
return accessDockerCompose(cmd)
}
// only use the first pod in the list
@@ -193,27 +194,26 @@ func consoleDashCmd() *cobra.Command {
return cmd
}
// accessDocker access docker container
func accessDocker(cmd *cobra.Command) error {
dockerCli, err := command.NewDockerCli(command.WithCombinedStreams(os.Stdout))
// accessDockerCompose access docker compose ps
func accessDockerCompose(cmd *cobra.Command) error {
cli, err := docker.NewCompose(cmd.OutOrStdout())
if err != nil {
return fmt.Errorf("build docker CLI client fail: %w", err)
return errors.Wrap(err, "failed to build the docker compose client")
}
err = dockerCli.Initialize(flags.NewClientOptions())
list, err := cli.Ps(context.TODO(), project)
if err != nil {
return fmt.Errorf("docker client initialize fail: %w", err)
return errors.Wrap(err, "failed to build the docker compose ps")
}
apiClient := dockerCli.Client()
list, err := apiClient.ContainerList(context.Background(), types2.ContainerListOptions{})
for _, container := range list {
for i, name := range container.Names {
if strings.Contains(name, "higress-console") {
port := container.Ports[i].PublicPort
// not support define ip address
url := fmt.Sprintf("http://localhost:%d", port)
if strings.Contains(container.Service, "console") {
// not support define ip address
if container.Publishers != nil {
url := fmt.Sprintf("http://localhost:%d", container.Publishers[0].PublishedPort)
openBrowser(url, cmd.OutOrStdout(), browser)
return nil
}
return nil
}
}
return errors.New("no higress console container found")
@@ -425,7 +425,7 @@ func openCommand(writer io.Writer, command string, args ...string) {
_, err := exec.LookPath(command)
if err != nil {
if errors.Is(err, exec.ErrNotFound) {
fmt.Fprintf(writer, "Could not open your browser. Please open it maually.\n")
fmt.Fprintf(writer, "Could not open your browser. Please open it manually.\n")
return
}
fmt.Fprintf(writer, "Failed to open browser; open %s in your browser.\nError: %s\n", args[0], err.Error())

View File

@@ -109,3 +109,7 @@ func (c Compose) List(ctx context.Context) ([]api.Stack, error) {
func (c Compose) Down(ctx context.Context, name string) error {
return c.client.Down(ctx, name, api.DownOptions{})
}
func (c Compose) Ps(ctx context.Context, name string) ([]api.ContainerSummary, error) {
return c.client.Ps(ctx, name, api.PsOptions{})
}

View File

@@ -17,6 +17,7 @@ package helm
import (
"errors"
"fmt"
"regexp"
"strings"
"istio.io/istio/operator/pkg/util"
@@ -84,9 +85,10 @@ func (p ProfileGlobal) Validate(install InstallMode) []error {
}
type ProfileConsole struct {
Port uint32 `json:"port,omitempty"`
Replicas uint32 `json:"replicas,omitempty"`
O11yEnabled bool `json:"o11YEnabled,omitempty"`
Port uint32 `json:"port,omitempty"`
Replicas uint32 `json:"replicas,omitempty"`
O11yEnabled bool `json:"o11YEnabled,omitempty"`
Resources Resource `json:"resources,omitempty"`
}
func (p ProfileConsole) SetFlags(install InstallMode) ([]string, error) {
@@ -112,14 +114,31 @@ func (p ProfileConsole) Validate(install InstallMode) []error {
}
}
// set default value
if p.Resources.Requests.CPU == "" {
p.Resources.Requests.CPU = "250m"
}
if p.Resources.Requests.Memory == "" {
p.Resources.Requests.Memory = "512Mi"
}
if p.Resources.Limits.CPU == "" {
p.Resources.Limits.CPU = "2000m"
}
if p.Resources.Limits.Memory == "" {
p.Resources.Limits.Memory = "2048Mi"
}
errs = append(errs, p.Resources.Validate()...)
return errs
}
type ProfileGateway struct {
Replicas uint32 `json:"replicas,omitempty"`
HttpPort uint32 `json:"httpPort,omitempty"`
HttpsPort uint32 `json:"httpsPort,omitempty"`
MetricsPort uint32 `json:"metricsPort,omitempty"`
Replicas uint32 `json:"replicas,omitempty"`
HttpPort uint32 `json:"httpPort,omitempty"`
HttpsPort uint32 `json:"httpsPort,omitempty"`
MetricsPort uint32 `json:"metricsPort,omitempty"`
Resources Resource `json:"resources,omitempty"`
}
func (p ProfileGateway) SetFlags(install InstallMode) ([]string, error) {
@@ -149,11 +168,29 @@ func (p ProfileGateway) Validate(install InstallMode) []error {
errs = append(errs, errors.New("gateway.MetricsPort need be large than zero"))
}
}
// set default value
if p.Resources.Requests.CPU == "" {
p.Resources.Requests.CPU = "2000m"
}
if p.Resources.Requests.Memory == "" {
p.Resources.Requests.Memory = "2048Mi"
}
if p.Resources.Limits.CPU == "" {
p.Resources.Limits.CPU = "2000m"
}
if p.Resources.Limits.Memory == "" {
p.Resources.Limits.Memory = "2048Mi"
}
errs = append(errs, p.Resources.Validate()...)
return errs
}
type ProfileController struct {
Replicas uint32 `json:"replicas,omitempty"`
Replicas uint32 `json:"replicas,omitempty"`
Resources Resource `json:"resources,omitempty"`
}
func (p ProfileController) SetFlags(install InstallMode) ([]string, error) {
@@ -171,6 +208,23 @@ func (p ProfileController) Validate(install InstallMode) []error {
errs = append(errs, errors.New("controller.replica need be large than zero"))
}
}
// set default value
if p.Resources.Requests.CPU == "" {
p.Resources.Requests.CPU = "500m"
}
if p.Resources.Requests.Memory == "" {
p.Resources.Requests.Memory = "2048Mi"
}
if p.Resources.Limits.CPU == "" {
p.Resources.Limits.CPU = "1000m"
}
if p.Resources.Limits.Memory == "" {
p.Resources.Limits.Memory = "2048Mi"
}
errs = append(errs, p.Resources.Validate()...)
return errs
}
@@ -248,14 +302,62 @@ func (p *Profile) ValuesYaml() (string, error) {
setFlags = append(setFlags, controllerFlags...)
valueOverlayYAML := ""
if p.Values != nil {
out, err := yaml.Marshal(p.Values)
if err != nil {
return "", err
}
valueOverlayYAML = string(out)
if p.Values == nil {
p.Values = make(map[string]any)
}
resourceMap := make(map[string]any)
resourceMap["higress-core"] = map[string]interface{}{
"controller": map[string]interface{}{
"resources": map[string]interface{}{
"requests": map[string]interface{}{
"cpu": p.Controller.Resources.Requests.CPU,
"memory": p.Controller.Resources.Requests.Memory,
},
"limits": map[string]interface{}{
"cpu": p.Controller.Resources.Limits.CPU,
"memory": p.Controller.Resources.Limits.Memory,
},
},
},
"gateway": map[string]interface{}{
"resources": map[string]interface{}{
"requests": map[string]interface{}{
"cpu": p.Gateway.Resources.Requests.CPU,
"memory": p.Gateway.Resources.Requests.Memory,
},
"limits": map[string]interface{}{
"cpu": p.Gateway.Resources.Limits.CPU,
"memory": p.Gateway.Resources.Limits.Memory,
},
},
},
}
resourceMap["higress-console"] = map[string]interface{}{
"resources": map[string]interface{}{
"requests": map[string]interface{}{
"cpu": p.Console.Resources.Requests.CPU,
"memory": p.Console.Resources.Requests.Memory,
},
"limits": map[string]interface{}{
"cpu": p.Console.Resources.Limits.CPU,
"memory": p.Console.Resources.Limits.Memory,
},
},
}
resourceYAML, err := yaml.Marshal(resourceMap)
if err != nil {
return "", err
}
out, err := yaml.Marshal(p.Values)
if err != nil {
return "", err
}
valueOverlayYAML, err = util.OverlayYAML(string(resourceYAML), string(out))
flagsYAML, err := overlaySetFlagValues("", setFlags)
if err != nil {
return "", err
@@ -343,3 +445,54 @@ func ToString(errors []error, separator string) string {
}
return out
}
type Resource struct {
Requests Requests `json:"requests,omitempty"`
Limits Limits `json:"limits,omitempty"`
}
type Requests struct {
CPU string `json:"cpu,omitempty"`
Memory string `json:"memory,omitempty"`
}
type Limits struct {
CPU string `json:"cpu,omitempty"`
Memory string `json:"memory,omitempty"`
}
func (r Resource) Validate() []error {
errs := make([]error, 0)
r.Requests.CPU = strings.ReplaceAll(r.Requests.CPU, " ", "")
r.Requests.Memory = strings.ReplaceAll(r.Requests.Memory, " ", "")
r.Limits.CPU = strings.ReplaceAll(r.Limits.CPU, " ", "")
r.Limits.Memory = strings.ReplaceAll(r.Limits.Memory, " ", "")
if !isValidK8SResourceFormat(r.Requests.CPU) {
errs = append(errs, fmt.Errorf("requests CPU has invalid format"))
}
if !isValidK8SResourceFormat(r.Requests.Memory) {
errs = append(errs, fmt.Errorf("requests memory has invalid format"))
}
if !isValidK8SResourceFormat(r.Limits.CPU) {
errs = append(errs, fmt.Errorf("limits CPU has invalid format"))
}
if !isValidK8SResourceFormat(r.Limits.Memory) {
errs = append(errs, fmt.Errorf("limits memory has invalid format"))
}
return errs
}
func isValidK8SResourceFormat(resource string) bool {
pattern := `^\d+((n|u|m|k|Ki|M|Mi|G|Gi|T|Ti|P|Pi|E|Ei)?)$`
match, _ := regexp.MatchString(pattern, resource)
if !match {
return false
}
if len(resource) == 0 || resource[0] == '-' || resource[0] == '0' {
return false
}
return true
}

View File

@@ -28,7 +28,7 @@ import (
const (
setFlagHelpStr = `Override an higress profile value, e.g. to choose a profile
(--set profile=local-k8s), or override profile values (--set gateway.replicas=2), or override helm values (--set values.global.proxy.resources.requsts.cpu=500m).`
(--set profile=local-k8s), or override profile values (--set gateway.replicas=2), or override helm values (--set values.global.proxy.resources.requests.cpu=500m).`
// manifestsFlagHelpStr is the command line description for --manifests
manifestsFlagHelpStr = `Specify a path to a directory of profiles
(e.g. ~/Downloads/higress/manifests).`
@@ -101,7 +101,7 @@ func newInstallCmd() *cobra.Command {
hgctl install --set profile=local-k8s --set global.enableIstioAPI=true --set gateway.replicas=2"
# To override helm setting
hgctl install --set profile=local-k8s --set values.global.proxy.resources.requsts.cpu=500m"
hgctl install --set profile=local-k8s --set values.global.proxy.resources.requests.cpu=500m"
`,
@@ -175,7 +175,7 @@ func promptInstall(writer io.Writer, profileName string) bool {
func promptProfileName(writer io.Writer) string {
answer := ""
fmt.Fprintf(writer, "\nPlease select higress install configration profile:\n")
fmt.Fprintf(writer, "\nPlease select higress install configuration profile:\n")
fmt.Fprintf(writer, "\n1.Install higress to local kubernetes cluster like kind etc.\n")
fmt.Fprintf(writer, "\n2.Install higress to kubernetes cluster\n")
fmt.Fprintf(writer, "\n3.Install higress to local docker environment\n")

View File

@@ -176,7 +176,7 @@ func (a *Agent) checkSudoPermission() error {
case <-time.After(5 * time.Second):
cmd2.Process.Signal(os.Interrupt)
if !a.quiet {
fmt.Fprintf(a.writer, "checked result: timeout execeed and need sudo with password\n")
fmt.Fprintf(a.writer, "checked result: timeout exceed and need sudo with password\n")
}
a.runSudoState = SudoWithPassword

View File

@@ -10,15 +10,36 @@ console:
port: 8080
replicas: 1
o11yEnabled: false
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: 2000m
memory: 2048Mi
gateway:
replicas: 1
httpPort: 80
httpsPort: 443
metricsPort: 15020
resources:
requests:
cpu: 2000m
memory: 2048Mi
limits:
cpu: 2000m
memory: 2048Mi
controller:
replicas: 1
resources:
requests:
cpu: 500m
memory: 2048Mi
limits:
cpu: 1000m
memory: 2048Mi
storage:
url: nacos://127.0.0.1:8848 # file://opt/higress/conf

View File

@@ -9,12 +9,33 @@ global:
console:
replicas: 1
o11yEnabled: false
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: 2000m
memory: 2048Mi
gateway:
replicas: 2
resources:
requests:
cpu: 2000m
memory: 2048Mi
limits:
cpu: 2000m
memory: 2048Mi
controller:
replicas: 1
resources:
requests:
cpu: 500m
memory: 2048Mi
limits:
cpu: 1000m
memory: 2048Mi
# values passed through to helm
values:

View File

@@ -9,12 +9,33 @@ global:
console:
replicas: 1
o11yEnabled: true
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: 2000m
memory: 2048Mi
gateway:
replicas: 1
resources:
requests:
cpu: 2000m
memory: 2048Mi
limits:
cpu: 2000m
memory: 2048Mi
controller:
replicas: 1
resources:
requests:
cpu: 500m
memory: 2048Mi
limits:
cpu: 1000m
memory: 2048Mi
# values passed through to helm
values:

View File

@@ -18,6 +18,7 @@ import (
"fmt"
"io"
"os"
"os/exec"
"github.com/alibaba/higress/pkg/cmd/hgctl/plugin/option"
"github.com/alibaba/higress/pkg/cmd/hgctl/plugin/utils"
@@ -86,6 +87,12 @@ func runInit(w io.Writer, target string) (err error) {
return errors.Wrap(err, "failed to create option.yaml")
}
cmd := exec.Command("go", "mod", "tidy")
cmd.Dir = dir
if err := cmd.Run(); err != nil {
return errors.Wrap(err, "failed to run go mod tidy")
}
fmt.Fprintf(w, "Initialized the project in %q\n", dir)
return nil

View File

@@ -31,8 +31,8 @@ package main
import (
"github.com/tidwall/gjson"
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm"
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm/types"
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
)
@@ -93,8 +93,8 @@ module {{ .Name }}
go 1.19
require (
github.com/alibaba/higress/plugins/wasm-go v0.0.0-20231019123123-86b223bc75f1
github.com/tetratelabs/proxy-wasm-go-sdk v0.22.0
github.com/alibaba/higress/plugins/wasm-go main
github.com/higress-group/proxy-wasm-go-sdk main
github.com/tidwall/gjson v1.14.3
)
`

View File

@@ -75,9 +75,15 @@ static_resources:
stat_prefix: ingress_http
# Output envoy logs to stdout
access_log:
- name: envoy.access_loggers.stdout
- name: envoy.access_loggers.file
filter:
not_health_check_filter: {}
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
"@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
path: /dev/stdout
log_format:
text_format_source:
inline_string: "{\"authority\":\"%REQ(X-ENVOY-ORIGINAL-HOST?: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)%\"}\n"
# Modify as required
route_config:
name: local_route

View File

@@ -124,7 +124,7 @@ func (s *JSONSchemaPropsOrBool) UnmarshalJSON(data []byte) error {
func (s JSONSchemaPropsOrBool) MarshalYAML() (interface{}, error) {
if s.Schema != nil {
return yaml.Marshal(s.Schema)
return s.Schema, nil
}
if s.Schema == nil && !s.Allows {

View File

@@ -33,7 +33,7 @@ type WasmPluginMeta struct {
Spec WasmPluginSpec `json:"spec" yaml:"spec"`
}
func defaultWsamPluginMeta() *WasmPluginMeta {
func defaultWasmPluginMeta() *WasmPluginMeta {
return &WasmPluginMeta{
APIVersion: "1.0.0",
Info: WasmPluginInfo{
@@ -77,7 +77,7 @@ func ParseGoSrc(dir, model string) (*WasmPluginMeta, error) {
if err != nil {
return nil, err
}
meta := defaultWsamPluginMeta()
meta := defaultWasmPluginMeta()
meta.setByConfigModel(m)
return meta, nil
}
@@ -96,26 +96,33 @@ func recursiveSetSchema(model *Model, parent *JSONSchemaProps) (string, *JSONSch
}
newName := cur.HandleFieldTags(model.Tag, parent, model.Name)
if IsArray(model.Type) {
item := NewJSONSchemaProps()
item.Type = GetItemType(cur.Type)
cur.Type = "array"
if IsObject(item.Type) {
item.Properties = make(map[string]JSONSchemaProps)
for _, field := range model.Fields {
name, child := recursiveSetSchema(&field, cur)
item.Properties[name] = *child
}
}
cur.Items = &JSONSchemaPropsOrArray{Schema: item}
itemModel := &*model
itemModel.Type = GetItemType(model.Type)
_, itemSchema := recursiveSetSchema(itemModel, nil)
cur.Items = &JSONSchemaPropsOrArray{Schema: itemSchema}
} else if IsMap(model.Type) {
cur.Type = "object"
valueModel := &*model
valueModel.Type = GetValueType(model.Type)
valueModel.Tag = ""
valueModel.Doc = ""
_, valueSchema := recursiveSetSchema(valueModel, nil)
cur.AdditionalProperties = &JSONSchemaPropsOrBool{Schema: valueSchema}
} else if IsObject(model.Type) { // type may be `array of object`, and it is handled in the first branch
for _, field := range model.Fields {
name, child := recursiveSetSchema(&field, cur)
cur.Properties[name] = *child
}
cur.Properties = make(map[string]JSONSchemaProps)
recursiveObjectProperties(cur, model)
}
return newName, cur
}
func recursiveObjectProperties(parent *JSONSchemaProps, model *Model) {
for _, field := range model.Fields {
name, child := recursiveSetSchema(&field, parent)
parent.Properties[name] = *child
}
}
func (meta *WasmPluginMeta) setModelAnnotations(comment string) {
as := GetAnnotations(comment)
for _, a := range as {

View File

@@ -30,6 +30,7 @@ import (
const (
ArrayPrefix = "array of "
MapPrefix = "map of "
ObjectSuffix = "object"
)
@@ -40,7 +41,23 @@ func IsArray(typ string) bool {
// GetItemType returns the item type of array, e.g.: array of int -> int
func GetItemType(typ string) string {
return strings.TrimPrefix(typ, ArrayPrefix)
if !IsArray(typ) {
return typ
}
return typ[len(ArrayPrefix):]
}
// IsMap returns true if the given type is a `map of <type>`
func IsMap(typ string) bool {
return strings.HasPrefix(typ, MapPrefix)
}
// GetValueType returns the value type of map, e.g.: map of int -> int
func GetValueType(typ string) string {
if !IsMap(typ) {
return typ
}
return typ[len(MapPrefix):]
}
// IsObject returns true if the given type is an `object` or an `array of object`
@@ -50,7 +67,7 @@ func IsObject(typ string) bool {
var (
ErrInvalidModel = errors.New("invalid model")
ErrInvalidFiledType = errors.New("invalid field type")
ErrInvalidFieldType = errors.New("invalid field type")
)
type ModelParser struct {
@@ -248,24 +265,24 @@ func (p *ModelParser) parseModelFields(model string) (fields []Model, err error)
if field.Tag != nil {
ignore, err := fd.setTag(field.Tag.Value)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse tag %q of the field %q", fd.Tag, fd.Name)
return nil, errors.Wrapf(err, "failed to parse tag %q of the field %q", field.Tag, fd.Name)
}
if ignore {
continue
}
}
fd.Type, err = p.parseFiledType(pkgName, field.Type)
fd.Type, err = p.parseFieldType(pkgName, field.Type)
if err != nil {
return nil, err
return nil, errors.Wrapf(err, "failed to parse type %q of the field %q", field.Type, fd.Name)
}
if IsObject(fd.Type) {
subModel, err := p.getModelName(field.Type)
subModel, err := p.doGetModelName(pkgName, field.Type)
if err != nil {
return nil, err
return nil, errors.Wrapf(err, "failed to get the sub-model name of the field %q with type %q", fd.Name, field.Type)
}
fd.Fields, err = p.parseModelFields(subModel)
if err != nil {
return nil, err
return nil, errors.Wrapf(err, "failed to parse sub-model of the field %q with type %q", fd.Name, field.Type)
}
}
fields = append(fields, fd)
@@ -313,51 +330,63 @@ func (p *ModelParser) doGetModelName(pkgName string, typ ast.Expr) (string, erro
return p.doGetModelName(pkgName, t.X)
case *ast.ArrayType: // slice or array
return p.doGetModelName(pkgName, t.Elt)
case *ast.MapType:
return p.doGetModelName(pkgName, t.Value)
case *ast.SelectorExpr: // <pkg_name>.<field_name>
pkg, ok := t.X.(*ast.Ident)
if !ok {
return "", ErrInvalidFiledType
return "", ErrInvalidFieldType
}
pName := pkg.Name + "."
return p.doGetModelName(pName, t.Sel)
case *ast.Ident:
return pkgName + t.Name, nil
default:
return "", ErrInvalidFiledType
return "", ErrInvalidFieldType
}
}
func (p *ModelParser) parseFiledType(pkgName string, typ ast.Expr) (string, error) {
func (p *ModelParser) parseFieldType(pkgName string, typ ast.Expr) (string, error) {
switch t := typ.(type) {
case *ast.StructType: // nested struct
return string(JsonTypeObject), nil
case *ast.StarExpr: // *int -> int
return p.parseFiledType(pkgName, t.X)
return p.parseFieldType(pkgName, t.X)
case *ast.ArrayType: // slice or array
ret, err := p.parseFiledType(pkgName, t.Elt)
ret, err := p.parseFieldType(pkgName, t.Elt)
if err != nil {
return "", err
}
return ArrayPrefix + ret, nil
case *ast.MapType:
if keyIdent, ok := t.Key.(*ast.Ident); !ok {
return "", ErrInvalidFieldType
} else if keyIdent.Name != "string" {
return "", ErrInvalidFieldType
} else if ret, err := p.parseFieldType(pkgName, t.Value); err != nil {
return "", err
} else {
return MapPrefix + ret, nil
}
case *ast.SelectorExpr: // <pkg_name>.<field_name>
pkg, ok := t.X.(*ast.Ident)
if !ok {
return "", ErrInvalidFiledType
return "", ErrInvalidFieldType
}
pName := pkg.Name + "."
return p.parseFiledType(pName, t.Sel)
return p.parseFieldType(pName, t.Sel)
case *ast.Ident:
fName := pkgName + t.Name
if _, ok := p.structs[fName]; ok {
return string(JsonTypeObject), nil
}
if alias, ok := p.alias[fName]; ok {
return p.parseFiledType(pkgName, alias.expr)
return p.parseFieldType(pkgName, alias.expr)
}
jsonType, err := convert2JsonType(t.Name)
return string(jsonType), err
default:
return "", ErrInvalidFiledType
return "", ErrInvalidFieldType
}
}
@@ -375,7 +404,7 @@ func convert2JsonType(typ string) (JsonType, error) {
case "struct":
return JsonTypeObject, nil
default:
return "", ErrInvalidFiledType
return "", ErrInvalidFieldType
}
}
@@ -388,4 +417,5 @@ const (
JsonTypeString JsonType = "string"
JsonTypeObject JsonType = "object"
JsonTypeArray JsonType = "array"
JsonTypeMap JsonType = "map"
)

View File

@@ -108,7 +108,7 @@ func upgrade(writer io.Writer, iArgs *InstallArgs) error {
func promptUpgrade(writer io.Writer) bool {
answer := ""
for {
fmt.Fprintf(writer, "All Higress resources will be upgraed from the cluster. \nProceed? (y/N)")
fmt.Fprintf(writer, "All Higress resources will be upgrade from the cluster. \nProceed? (y/N)")
fmt.Scanln(&answer)
if strings.TrimSpace(answer) == "y" {
fmt.Fprintf(writer, "\n")
@@ -170,7 +170,7 @@ func promptProfileContexts(writer io.Writer, profileContexts []*installer.Profil
if len(profileContexts) == 1 {
fmt.Fprintf(writer, "\nFound a profile:: ")
} else {
fmt.Fprintf(writer, "\nPlease select higress installed configration profiles:\n")
fmt.Fprintf(writer, "\nPlease select higress installed configuration profiles:\n")
}
index := 1
for _, profileContext := range profileContexts {

View File

@@ -76,6 +76,7 @@ func getServerCommand() *cobra.Command {
Debug: true,
NativeIstio: true,
HttpAddress: ":8888",
CertHttpAddress: ":8889",
GrpcAddress: ":15051",
GrpcKeepAliveOptions: keepalive.DefaultOption(),
XdsOptions: bootstrap.XdsOptions{
@@ -112,6 +113,14 @@ func getServerCommand() *cobra.Command {
serveCmd.PersistentFlags().IntVar(&serverArgs.RegistryOptions.KubeOptions.KubernetesAPIBurst, "kubernetesApiBurst", 160,
"Maximum burst for throttle when communicating with the kubernetes API")
serveCmd.PersistentFlags().Uint32Var(&serverArgs.GatewayHttpPort, "gatewayHttpPort", 80,
"Http listening port of gateway pod")
serveCmd.PersistentFlags().Uint32Var(&serverArgs.GatewayHttpsPort, "gatewayHttpsPort", 443,
"Https listening port of gateway pod")
serveCmd.PersistentFlags().BoolVar(&serverArgs.EnableAutomaticHttps, "enableAutomaticHttps", false, "if true, enables automatic https")
serveCmd.PersistentFlags().StringVar(&serverArgs.AutomaticHttpsEmail, "automaticHttpsEmail", "", "email for automatic https")
serveCmd.PersistentFlags().StringVar(&serverArgs.CertHttpAddress, "certHttpAddress", serverArgs.CertHttpAddress, "the cert http address")
loggingOptions.AttachCobraFlags(serveCmd)
serverArgs.GrpcKeepAliveOptions.AttachCobraFlags(serveCmd)

View File

@@ -51,6 +51,7 @@ import (
higressv1 "github.com/alibaba/higress/api/networking/v1"
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/cert"
"github.com/alibaba/higress/pkg/ingress/kube/annotations"
"github.com/alibaba/higress/pkg/ingress/kube/common"
"github.com/alibaba/higress/pkg/ingress/kube/configmap"
@@ -144,6 +145,8 @@ type IngressConfig struct {
namespace string
clusterId string
httpsConfigMgr *cert.ConfigMgr
}
func NewIngressConfig(localKubeClient kube.Client, XDSUpdater model.XDSUpdater, namespace, clusterId string) *IngressConfig {
@@ -180,6 +183,9 @@ func NewIngressConfig(localKubeClient kube.Client, XDSUpdater model.XDSUpdater,
higressConfigController := configmap.NewController(localKubeClient, clusterId, namespace)
config.configmapMgr = configmap.NewConfigmapMgr(XDSUpdater, namespace, higressConfigController, higressConfigController.Lister())
httpsConfigMgr, _ := cert.NewConfigMgr(namespace, localKubeClient)
config.httpsConfigMgr = httpsConfigMgr
return config
}
@@ -347,6 +353,10 @@ func (m *IngressConfig) convertGateways(configs []common.WrapperConfig) []config
Gateways: map[string]*common.WrapperGateway{},
}
httpsCredentialConfig, err := m.httpsConfigMgr.GetConfigFromConfigmap()
if err != nil {
IngressLog.Errorf("Get higress https configmap err %v", err)
}
for idx := range configs {
cfg := configs[idx]
clusterId := common.GetClusterId(cfg.Config.Annotations)
@@ -356,7 +366,7 @@ func (m *IngressConfig) convertGateways(configs []common.WrapperConfig) []config
if ingressController == nil {
continue
}
if err := ingressController.ConvertGateway(&convertOptions, &cfg); err != nil {
if err := ingressController.ConvertGateway(&convertOptions, &cfg, httpsCredentialConfig); err != nil {
IngressLog.Errorf("Convert ingress %s/%s to gateway fail in cluster %s, err %v", cfg.Config.Namespace, cfg.Config.Name, clusterId, err)
}
}
@@ -513,6 +523,7 @@ func (m *IngressConfig) convertEnvoyFilter(convertOptions *common.ConvertOptions
var envoyFilters []config.Config
mappings := map[string]*common.Rule{}
initHttp2RpcGlobalConfig := true
for _, routes := range convertOptions.HTTPRoutes {
for _, route := range routes {
if strings.HasSuffix(route.HTTPRoute.Name, "app-root") {
@@ -522,12 +533,13 @@ func (m *IngressConfig) convertEnvoyFilter(convertOptions *common.ConvertOptions
http2rpc := route.WrapperConfig.AnnotationsConfig.Http2Rpc
if http2rpc != nil {
IngressLog.Infof("Found http2rpc for name %s", http2rpc.Name)
envoyFilter, err := m.constructHttp2RpcEnvoyFilter(http2rpc, route, m.namespace)
envoyFilter, err := m.constructHttp2RpcEnvoyFilter(http2rpc, route, m.namespace, initHttp2RpcGlobalConfig)
if err != nil {
IngressLog.Infof("Construct http2rpc EnvoyFilter error %v", err)
} else {
IngressLog.Infof("Append http2rpc EnvoyFilter for name %s", http2rpc.Name)
envoyFilters = append(envoyFilters, *envoyFilter)
initHttp2RpcGlobalConfig = false
}
}
@@ -798,7 +810,9 @@ func (m *IngressConfig) convertIstioWasmPlugin(obj *higressext.WasmPlugin) (*ext
PluginConfig: obj.PluginConfig,
PluginName: obj.PluginName,
Phase: extensions.PluginPhase(obj.Phase),
Priority: obj.Priority,
}
if obj.GetPriority() != nil {
result.Priority = &types.Int64Value{Value: int64(obj.GetPriority().Value)}
}
if result.PluginConfig != nil {
return result, nil
@@ -819,7 +833,9 @@ func (m *IngressConfig) convertIstioWasmPlugin(obj *higressext.WasmPlugin) (*ext
continue
}
if rule.Config == nil {
return nil, errors.New("invalid rule has no config")
rule.Config = &types.Struct{
Fields: map[string]*types.Value{},
}
}
v := &types.Value_StructValue{
StructValue: rule.Config,
@@ -902,7 +918,7 @@ func (m *IngressConfig) AddOrUpdateWasmPlugin(clusterNamespacedName util.Cluster
Labels: map[string]string{constants.AlwaysPushLabel: "true"},
}
for _, f := range m.wasmPluginHandlers {
IngressLog.Debug("WasmPlugin triggerd update")
IngressLog.Debug("WasmPlugin triggered update")
f(config.Config{Meta: metadata}, config.Config{Meta: metadata}, model.EventUpdate)
}
istioWasmPlugin, err := m.convertIstioWasmPlugin(&wasmPlugin.Spec)
@@ -944,7 +960,7 @@ func (m *IngressConfig) DeleteWasmPlugin(clusterNamespacedName util.ClusterNames
Labels: map[string]string{constants.AlwaysPushLabel: "true"},
}
for _, f := range m.wasmPluginHandlers {
IngressLog.Debug("WasmPlugin triggerd update")
IngressLog.Debug("WasmPlugin triggered update")
f(config.Config{Meta: metadata}, config.Config{Meta: metadata}, model.EventDelete)
}
}
@@ -971,7 +987,7 @@ func (m *IngressConfig) AddOrUpdateMcpBridge(clusterNamespacedName util.ClusterN
Labels: map[string]string{constants.AlwaysPushLabel: "true"},
}
for _, f := range m.serviceEntryHandlers {
IngressLog.Debug("McpBridge triggerd serviceEntry update")
IngressLog.Debug("McpBridge triggered serviceEntry update")
f(config.Config{Meta: metadata}, config.Config{Meta: metadata}, model.EventUpdate)
}
}, m.localKubeClient, m.namespace)
@@ -1026,7 +1042,7 @@ func (m *IngressConfig) AddOrUpdateHttp2Rpc(clusterNamespacedName util.ClusterNa
}
func (m *IngressConfig) DeleteHttp2Rpc(clusterNamespacedName util.ClusterNamespacedName) {
IngressLog.Infof("Http2Rpc triggerd deleted event %s", clusterNamespacedName.Name)
IngressLog.Infof("Http2Rpc triggered deleted event %s", clusterNamespacedName.Name)
if clusterNamespacedName.Namespace != m.namespace {
return
}
@@ -1038,7 +1054,7 @@ func (m *IngressConfig) DeleteHttp2Rpc(clusterNamespacedName util.ClusterNamespa
}
m.mutex.Unlock()
if hit {
IngressLog.Infof("Http2Rpc triggerd deleted event executed %s", clusterNamespacedName.Name)
IngressLog.Infof("Http2Rpc triggered deleted event executed %s", clusterNamespacedName.Name)
push := func(kind config.GroupVersionKind) {
m.XDSUpdater.ConfigUpdate(&model.PushRequest{
Full: true,
@@ -1139,18 +1155,18 @@ func (m *IngressConfig) applyCanaryIngresses(convertOptions *common.ConvertOptio
}
}
func (m *IngressConfig) constructHttp2RpcEnvoyFilter(http2rpcConfig *annotations.Http2RpcConfig, route *common.WrapperHTTPRoute, namespace string) (*config.Config, error) {
func (m *IngressConfig) constructHttp2RpcEnvoyFilter(http2rpcConfig *annotations.Http2RpcConfig, route *common.WrapperHTTPRoute, namespace string, initHttp2RpcGlobalConfig bool) (*config.Config, error) {
mappings := m.http2rpcs
IngressLog.Infof("Found http2rpc mappings %v", mappings)
if _, exist := mappings[http2rpcConfig.Name]; !exist {
IngressLog.Errorf("Http2RpcConfig name %s, not found Http2Rpc CRD", http2rpcConfig.Name)
return nil, errors.New("invalid http2rpcConfig has no useable http2rpc")
return nil, errors.New("invalid http2rpcConfig has no usable http2rpc")
}
http2rpcCRD := mappings[http2rpcConfig.Name]
if http2rpcCRD.GetDubbo() == nil {
IngressLog.Errorf("Http2RpcConfig name %s, only support Http2Rpc CRD Dubbo Service type", http2rpcConfig.Name)
return nil, errors.New("invalid http2rpcConfig has no useable http2rpc")
return nil, errors.New("invalid http2rpcConfig has no usable http2rpc")
}
httpRoute := route.HTTPRoute
@@ -1159,75 +1175,39 @@ func (m *IngressConfig) constructHttp2RpcEnvoyFilter(http2rpcConfig *annotations
if err != nil {
return nil, errors.New(err.Error())
}
return &config.Config{
Meta: config.Meta{
GroupVersionKind: gvk.EnvoyFilter,
Name: common.CreateConvertedName(constants.IstioIngressGatewayName, http2rpcConfig.Name),
Namespace: namespace,
configPatches := []*networking.EnvoyFilter_EnvoyConfigObjectPatch{
{
ApplyTo: networking.EnvoyFilter_HTTP_ROUTE,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_GATEWAY,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{
RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{
Vhost: &networking.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{
Route: &networking.EnvoyFilter_RouteConfigurationMatch_RouteMatch{
Name: httpRoute.Name,
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: typeStruct,
},
},
Spec: &networking.EnvoyFilter{
ConfigPatches: []*networking.EnvoyFilter_EnvoyConfigObjectPatch{
{
ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_GATEWAY,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: "envoy.filters.network.http_connection_manager",
SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{
Name: "envoy.filters.http.router",
},
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_INSERT_BEFORE,
Value: buildPatchStruct(`{
"name":"envoy.filters.http.http_dubbo_transcoder",
"typed_config":{
"@type":"type.googleapis.com/udpa.type.v1.TypedStruct",
"type_url":"type.googleapis.com/envoy.extensions.filters.http.http_dubbo_transcoder.v3.HttpDubboTranscoder"
}
}`),
{
ApplyTo: networking.EnvoyFilter_CLUSTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_GATEWAY,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Cluster{
Cluster: &networking.EnvoyFilter_ClusterMatch{
Service: httpRouteDestination.Destination.Host,
},
},
{
ApplyTo: networking.EnvoyFilter_HTTP_ROUTE,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_GATEWAY,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{
RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{
Vhost: &networking.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{
Route: &networking.EnvoyFilter_RouteConfigurationMatch_RouteMatch{
Name: httpRoute.Name,
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: typeStruct,
},
},
{
ApplyTo: networking.EnvoyFilter_CLUSTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_GATEWAY,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Cluster{
Cluster: &networking.EnvoyFilter_ClusterMatch{
Service: httpRouteDestination.Destination.Host,
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: buildPatchStruct(`{
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: buildPatchStruct(`{
"upstream_config": {
"name":"envoy.upstreams.http.dubbo_tcp",
"typed_config":{
@@ -1236,9 +1216,47 @@ func (m *IngressConfig) constructHttp2RpcEnvoyFilter(http2rpcConfig *annotations
}
}
}`),
},
},
}
if initHttp2RpcGlobalConfig {
configPatches = append(configPatches, &networking.EnvoyFilter_EnvoyConfigObjectPatch{
ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_GATEWAY,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: "envoy.filters.network.http_connection_manager",
SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{
Name: "envoy.filters.http.router",
},
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_INSERT_BEFORE,
Value: buildPatchStruct(`{
"name":"envoy.filters.http.http_dubbo_transcoder",
"typed_config":{
"@type":"type.googleapis.com/udpa.type.v1.TypedStruct",
"type_url":"type.googleapis.com/envoy.extensions.filters.http.http_dubbo_transcoder.v3.HttpDubboTranscoder"
}
}`),
},
})
}
return &config.Config{
Meta: config.Meta{
GroupVersionKind: gvk.EnvoyFilter,
Name: common.CreateConvertedName(constants.IstioIngressGatewayName, http2rpcConfig.Name),
Namespace: namespace,
},
Spec: &networking.EnvoyFilter{
ConfigPatches: configPatches,
},
}, nil
}
@@ -1275,7 +1293,7 @@ func (m *IngressConfig) constructHttp2RpcMethods(dubbo *higressv1.DubboService)
var method = make(map[string]interface{})
method["name"] = serviceMethod.GetServiceMethod()
var params []interface{}
// paramFromEntireBody is for methods with single parameter. So when paramFromEntireBody exists, we just ignore parmas.
// paramFromEntireBody is for methods with single parameter. So when paramFromEntireBody exists, we just ignore params.
var paramFromEntireBody = serviceMethod.GetParamFromEntireBody()
if paramFromEntireBody != nil {
var param = make(map[string]interface{})

View File

@@ -111,14 +111,18 @@ func TestNormalizeWeightedCluster(t *testing.T) {
func TestConvertGatewaysForIngress(t *testing.T) {
fake := kube.NewFakeClient()
v1Beta1Options := common.Options{
Enable: true,
ClusterId: "ingress-v1beta1",
RawClusterId: "ingress-v1beta1__",
Enable: true,
ClusterId: "ingress-v1beta1",
RawClusterId: "ingress-v1beta1__",
GatewayHttpPort: 80,
GatewayHttpsPort: 443,
}
v1Options := common.Options{
Enable: true,
ClusterId: "ingress-v1",
RawClusterId: "ingress-v1__",
Enable: true,
ClusterId: "ingress-v1",
RawClusterId: "ingress-v1__",
GatewayHttpPort: 80,
GatewayHttpsPort: 443,
}
ingressV1Beta1Controller := controllerv1beta1.NewController(fake, fake, v1Beta1Options, nil)
ingressV1Controller := controllerv1.NewController(fake, fake, v1Options, nil)

View File

@@ -17,14 +17,14 @@ package common
import (
"strings"
"github.com/alibaba/higress/pkg/cert"
"github.com/alibaba/higress/pkg/ingress/kube/annotations"
networking "istio.io/api/networking/v1alpha3"
"istio.io/istio/pilot/pkg/model"
"istio.io/istio/pkg/config"
gatewaytool "istio.io/istio/pkg/config/gateway"
listerv1 "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/tools/cache"
"github.com/alibaba/higress/pkg/ingress/kube/annotations"
)
type ServiceKey struct {
@@ -121,7 +121,7 @@ type IngressController interface {
SecretLister() listerv1.SecretLister
ConvertGateway(convertOptions *ConvertOptions, wrapper *WrapperConfig) error
ConvertGateway(convertOptions *ConvertOptions, wrapper *WrapperConfig, httpsCredentialConfig *cert.Config) error
ConvertHTTPRoute(convertOptions *ConvertOptions, wrapper *WrapperConfig) error

View File

@@ -105,6 +105,8 @@ type Options struct {
SystemNamespace string
GatewaySelectorKey string
GatewaySelectorValue string
GatewayHttpPort uint32
GatewayHttpsPort uint32
}
type BasicAuthRules struct {

View File

@@ -48,13 +48,15 @@ func V1Available(client kube.Client) bool {
serverVersion, err := client.GetKubernetesVersion()
if err != nil {
return false
// Consider the new ingress package is available as default
return true
}
runningVersion, err := version.ParseGeneric(serverVersion.String())
if err != nil {
// Consider the new ingress package is available as default
IngressLog.Errorf("unexpected error parsing running Kubernetes version: %v", err)
return false
return true
}
return runningVersion.AtLeast(version119)

View File

@@ -38,6 +38,7 @@ const (
maxInitialConnectionWindowSize = 2147483647
defaultIdleTimeout = 180
defaultRouteTimeout = 0
defaultUpStreamIdleTimeout = 10
defaultUpStreamConnectionBufferLimits = 10485760
defaultMaxRequestHeadersKb = 60
@@ -67,6 +68,8 @@ type Downstream struct {
ConnectionBufferLimits uint32 `json:"connectionBufferLimits,omitempty"`
// Http2 configures HTTP/2 specific options.
Http2 *Http2 `json:"http2,omitempty"`
//RouteTimeout limits the time that timeout for the route.
RouteTimeout uint32 `json:"routeTimeout"`
}
// Upstream configures the behavior of the upstream connection.
@@ -158,6 +161,7 @@ func deepCopyGlobal(global *Global) (*Global, error) {
newGlobal.Downstream.Http2.InitialStreamWindowSize = global.Downstream.Http2.InitialStreamWindowSize
newGlobal.Downstream.Http2.InitialConnectionWindowSize = global.Downstream.Http2.InitialConnectionWindowSize
}
newGlobal.Downstream.RouteTimeout = global.Downstream.RouteTimeout
}
if global.Upstream != nil {
newGlobal.Upstream.IdleTimeout = global.Upstream.IdleTimeout
@@ -185,6 +189,7 @@ func NewDefaultDownstream() *Downstream {
MaxRequestHeadersKb: defaultMaxRequestHeadersKb,
ConnectionBufferLimits: defaultConnectionBufferLimits,
Http2: NewDefaultHttp2(),
RouteTimeout: defaultRouteTimeout,
}
}
@@ -308,8 +313,7 @@ func (g *GlobalOptionController) ConstructEnvoyFilters() ([]*config.Config, erro
configPatch := make([]*networking.EnvoyFilter_EnvoyConfigObjectPatch, 0)
global := g.GetGlobal()
if global == nil {
configs := make([]*config.Config, 0)
return configs, nil
return []*config.Config{}, nil
}
namespace := g.Namespace
@@ -326,31 +330,29 @@ func (g *GlobalOptionController) ConstructEnvoyFilters() ([]*config.Config, erro
configPatch = append(configPatch, disableXEnvoyHeadersConfig...)
}
if global.Downstream == nil {
return generateEnvoyFilter(namespace, configPatch), nil
if global.Downstream != nil {
downstreamStruct := g.constructDownstream(global.Downstream)
bufferLimitStruct := g.constructBufferLimit(global.Downstream)
routeTimeoutStruct := g.constructRouteTimeout(global.Downstream)
downstreamConfig := g.generateDownstreamEnvoyFilter(downstreamStruct, bufferLimitStruct, routeTimeoutStruct, namespace)
if downstreamConfig != nil {
configPatch = append(configPatch, downstreamConfig...)
}
}
downstreamStruct := g.constructDownstream(global.Downstream)
bufferLimitStruct := g.constructBufferLimit(global.Downstream)
if len(downstreamStruct) == 0 && len(bufferLimitStruct) == 0 {
return generateEnvoyFilter(namespace, configPatch), nil
if global.Upstream != nil {
upstreamStruct := g.constructUpstream(global.Upstream)
bufferLimitStruct := g.constructUpstreamBufferLimit(global.Upstream)
upstreamConfig := g.generateUpstreamEnvoyFilter(upstreamStruct, bufferLimitStruct, namespace)
if upstreamConfig != nil {
configPatch = append(configPatch, upstreamConfig...)
}
}
downstreamConfig := g.generateDownstreamEnvoyFilter(downstreamStruct, bufferLimitStruct, namespace)
configPatch = append(configPatch, downstreamConfig...)
if global.Upstream == nil {
return generateEnvoyFilter(namespace, configPatch), nil
if len(configPatch) == 0 {
return []*config.Config{}, nil
}
upstreamStruct := g.constructUpstream(global.Upstream)
bufferLimitStruct = g.constructUpstreamBufferLimit(global.Upstream)
if len(upstreamStruct) == 0 {
return generateEnvoyFilter(namespace, configPatch), nil
}
upstreamConfig := g.generateUpstreamEnvoyFilter(upstreamStruct, bufferLimitStruct, namespace)
configPatch = append(configPatch, upstreamConfig...)
return generateEnvoyFilter(namespace, configPatch), nil
}
@@ -375,9 +377,11 @@ func (g *GlobalOptionController) RegisterItemEventHandler(eventHandler ItemEvent
}
// generateDownstreamEnvoyFilter generates the downstream envoy filter.
func (g *GlobalOptionController) generateDownstreamEnvoyFilter(downstreamValueStruct string, bufferLimitStruct string, namespace string) []*networking.EnvoyFilter_EnvoyConfigObjectPatch {
downstreamConfig := []*networking.EnvoyFilter_EnvoyConfigObjectPatch{
{
func (g *GlobalOptionController) generateDownstreamEnvoyFilter(downstreamValueStruct string, bufferLimitStruct string, routeTimeoutStruct string, namespace string) []*networking.EnvoyFilter_EnvoyConfigObjectPatch {
var downstreamConfig []*networking.EnvoyFilter_EnvoyConfigObjectPatch
if len(downstreamValueStruct) != 0 {
downstreamConfig = append(downstreamConfig, &networking.EnvoyFilter_EnvoyConfigObjectPatch{
ApplyTo: networking.EnvoyFilter_NETWORK_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_GATEWAY,
@@ -395,8 +399,11 @@ func (g *GlobalOptionController) generateDownstreamEnvoyFilter(downstreamValueSt
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: util.BuildPatchStruct(downstreamValueStruct),
},
},
{
})
}
if len(bufferLimitStruct) != 0 {
downstreamConfig = append(downstreamConfig, &networking.EnvoyFilter_EnvoyConfigObjectPatch{
ApplyTo: networking.EnvoyFilter_LISTENER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_GATEWAY,
@@ -405,14 +412,39 @@ func (g *GlobalOptionController) generateDownstreamEnvoyFilter(downstreamValueSt
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: util.BuildPatchStruct(bufferLimitStruct),
},
},
})
}
if len(routeTimeoutStruct) != 0 {
downstreamConfig = append(downstreamConfig, &networking.EnvoyFilter_EnvoyConfigObjectPatch{
ApplyTo: networking.EnvoyFilter_HTTP_ROUTE,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_GATEWAY,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{
RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{
Vhost: &networking.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{
Route: &networking.EnvoyFilter_RouteConfigurationMatch_RouteMatch{
Action: networking.EnvoyFilter_RouteConfigurationMatch_RouteMatch_ROUTE,
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: util.BuildPatchStruct(routeTimeoutStruct),
},
})
}
return downstreamConfig
}
func (g *GlobalOptionController) generateUpstreamEnvoyFilter(upstreamValueStruct string, bufferLimit string, namespace string) []*networking.EnvoyFilter_EnvoyConfigObjectPatch {
upstreamConfig := []*networking.EnvoyFilter_EnvoyConfigObjectPatch{
{
var upstreamConfig []*networking.EnvoyFilter_EnvoyConfigObjectPatch
if len(upstreamValueStruct) != 0 {
upstreamConfig = append(upstreamConfig, &networking.EnvoyFilter_EnvoyConfigObjectPatch{
ApplyTo: networking.EnvoyFilter_CLUSTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_GATEWAY,
@@ -421,8 +453,11 @@ func (g *GlobalOptionController) generateUpstreamEnvoyFilter(upstreamValueStruct
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: util.BuildPatchStruct(upstreamValueStruct),
},
},
{
})
}
if len(bufferLimit) != 0 {
upstreamConfig = append(upstreamConfig, &networking.EnvoyFilter_EnvoyConfigObjectPatch{
ApplyTo: networking.EnvoyFilter_CLUSTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_GATEWAY,
@@ -431,8 +466,9 @@ func (g *GlobalOptionController) generateUpstreamEnvoyFilter(upstreamValueStruct
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: util.BuildPatchStruct(bufferLimit),
},
},
})
}
return upstreamConfig
}
@@ -597,3 +633,17 @@ func (g *GlobalOptionController) constructBufferLimit(downstream *Downstream) st
}
`, downstream.ConnectionBufferLimits)
}
// constructRouteTimeout constructs the route timeout config.
func (g *GlobalOptionController) constructRouteTimeout(downstream *Downstream) string {
if downstream.RouteTimeout == 0 {
return ""
}
return fmt.Sprintf(`
{
"route": {
"timeout": "%ds"
}
}
`, downstream.RouteTimeout)
}

View File

@@ -24,6 +24,8 @@ import (
"sync"
"time"
"github.com/alibaba/higress/pkg/cert"
"github.com/hashicorp/go-multierror"
networking "istio.io/api/networking/v1alpha3"
"istio.io/istio/pilot/pkg/model"
@@ -53,6 +55,7 @@ import (
"github.com/alibaba/higress/pkg/ingress/kube/secret"
"github.com/alibaba/higress/pkg/ingress/kube/util"
. "github.com/alibaba/higress/pkg/ingress/log"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
)
var (
@@ -348,7 +351,7 @@ func extractTLSSecretName(host string, tls []ingress.IngressTLS) string {
return ""
}
func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapper *common.WrapperConfig) error {
func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapper *common.WrapperConfig, httpsCredentialConfig *cert.Config) error {
if convertOptions == nil {
return fmt.Errorf("convertOptions is nil")
}
@@ -371,7 +374,6 @@ func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapp
common.IncrementInvalidIngress(c.options.ClusterId, common.EmptyRule)
return fmt.Errorf("invalid ingress rule %s:%s in cluster %s, either `defaultBackend` or `rules` must be specified", cfg.Namespace, cfg.Name, c.options.ClusterId)
}
for _, rule := range ingressV1Beta.Rules {
// Need create builder for every rule.
domainBuilder := &common.IngressDomainBuilder{
@@ -422,13 +424,42 @@ func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapp
// Get tls secret matching the rule host
secretName := extractTLSSecretName(rule.Host, ingressV1Beta.TLS)
secretNamespace := cfg.Namespace
if secretName != "" {
if httpsCredentialConfig != nil && httpsCredentialConfig.FallbackForInvalidSecret {
_, err := c.secretController.Lister().Secrets(secretNamespace).Get(secretName)
if err != nil {
if k8serrors.IsNotFound(err) {
// If there is no matching secret, try to get it from configmap.
secretName = httpsCredentialConfig.MatchSecretNameByDomain(rule.Host)
secretNamespace = c.options.SystemNamespace
namespace, secret := cert.ParseTLSSecret(secretName)
if namespace != "" {
secretNamespace = namespace
secretName = secret
}
}
}
}
} else {
// If there is no matching secret, try to get it from configmap.
if httpsCredentialConfig != nil {
secretName = httpsCredentialConfig.MatchSecretNameByDomain(rule.Host)
secretNamespace = c.options.SystemNamespace
namespace, secret := cert.ParseTLSSecret(secretName)
if namespace != "" {
secretNamespace = namespace
secretName = secret
}
}
}
if secretName == "" {
// There no matching secret, so just skip.
continue
}
domainBuilder.Protocol = common.HTTPS
domainBuilder.SecretName = path.Join(c.options.ClusterId, cfg.Namespace, secretName)
domainBuilder.SecretName = path.Join(c.options.ClusterId, secretNamespace, secretName)
// There is a matching secret and the gateway has already a tls secret.
// We should report the duplicated tls secret event.
@@ -450,7 +481,7 @@ func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapp
Hosts: []string{rule.Host},
Tls: &networking.ServerTLSSettings{
Mode: networking.ServerTLSSettings_SIMPLE,
CredentialName: credentials.ToKubernetesIngressResource(c.options.RawClusterId, cfg.Namespace, secretName),
CredentialName: credentials.ToKubernetesIngressResource(c.options.RawClusterId, secretNamespace, secretName),
},
})
@@ -879,15 +910,28 @@ func (c *controller) storeBackendTrafficPolicy(wrapper *common.WrapperConfig, ba
}
if common.ValidateBackendResource(backend.Resource) && wrapper.AnnotationsConfig.Destination != nil {
for _, dest := range wrapper.AnnotationsConfig.Destination.McpDestination {
portNumber := dest.Destination.GetPort().GetNumber()
serviceKey := common.ServiceKey{
Namespace: "mcp",
Name: dest.Destination.Host,
Port: int32(portNumber),
ServiceFQDN: dest.Destination.Host,
}
if _, exist := store[serviceKey]; !exist {
store[serviceKey] = &common.WrapperTrafficPolicy{
TrafficPolicy: &networking.TrafficPolicy{},
WrapperConfig: wrapper,
if serviceKey.Port != 0 {
store[serviceKey] = &common.WrapperTrafficPolicy{
PortTrafficPolicy: &networking.TrafficPolicy_PortTrafficPolicy{
Port: &networking.PortSelector{
Number: uint32(serviceKey.Port),
},
},
WrapperConfig: wrapper,
}
} else {
store[serviceKey] = &common.WrapperTrafficPolicy{
TrafficPolicy: &networking.TrafficPolicy{},
WrapperConfig: wrapper,
}
}
}
}

View File

@@ -334,7 +334,7 @@ func testConvertGateway(t *testing.T, c common.IngressController) {
}
for _, testcase := range testcases {
err := c.ConvertGateway(testcase.input.options, testcase.input.wrapperConfig)
err := c.ConvertGateway(testcase.input.options, testcase.input.wrapperConfig, nil)
if err != nil {
require.Equal(t, testcase.expectNoError, false)
} else {

View File

@@ -20,10 +20,12 @@ import (
"path"
"reflect"
"sort"
"strconv"
"strings"
"sync"
"time"
"github.com/alibaba/higress/pkg/cert"
"github.com/hashicorp/go-multierror"
networking "istio.io/api/networking/v1alpha3"
"istio.io/istio/pilot/pkg/model"
@@ -52,6 +54,7 @@ import (
"github.com/alibaba/higress/pkg/ingress/kube/secret"
"github.com/alibaba/higress/pkg/ingress/kube/util"
. "github.com/alibaba/higress/pkg/ingress/log"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
)
var (
@@ -340,7 +343,7 @@ func extractTLSSecretName(host string, tls []ingress.IngressTLS) string {
return ""
}
func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapper *common.WrapperConfig) error {
func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapper *common.WrapperConfig, httpsCredentialConfig *cert.Config) error {
// Ignore canary config.
if wrapper.AnnotationsConfig.IsCanary() {
return nil
@@ -383,9 +386,9 @@ func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapp
}
wrapperGateway.Gateway.Servers = append(wrapperGateway.Gateway.Servers, &networking.Server{
Port: &networking.Port{
Number: 80,
Number: c.options.GatewayHttpPort,
Protocol: string(protocol.HTTP),
Name: common.CreateConvertedName("http-80-ingress", c.options.ClusterId),
Name: common.CreateConvertedName("http-"+strconv.FormatUint(uint64(c.options.GatewayHttpPort), 10)+"-ingress", c.options.ClusterId),
},
Hosts: []string{rule.Host},
})
@@ -407,13 +410,43 @@ func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapp
// Get tls secret matching the rule host
secretName := extractTLSSecretName(rule.Host, ingressV1.TLS)
secretNamespace := cfg.Namespace
if secretName != "" {
if httpsCredentialConfig != nil && httpsCredentialConfig.FallbackForInvalidSecret {
_, err := c.secretController.Lister().Secrets(secretNamespace).Get(secretName)
if err != nil {
if k8serrors.IsNotFound(err) {
// If there is no matching secret, try to get it from configmap.
secretName = httpsCredentialConfig.MatchSecretNameByDomain(rule.Host)
secretNamespace = c.options.SystemNamespace
namespace, secret := cert.ParseTLSSecret(secretName)
if namespace != "" {
secretNamespace = namespace
secretName = secret
}
}
}
}
} else {
// If there is no matching secret, try to get it from configmap.
if httpsCredentialConfig != nil {
secretName = httpsCredentialConfig.MatchSecretNameByDomain(rule.Host)
secretNamespace = c.options.SystemNamespace
namespace, secret := cert.ParseTLSSecret(secretName)
if namespace != "" {
secretNamespace = namespace
secretName = secret
}
}
}
if secretName == "" {
// There no matching secret, so just skip.
continue
}
domainBuilder.Protocol = common.HTTPS
domainBuilder.SecretName = path.Join(c.options.ClusterId, cfg.Namespace, secretName)
domainBuilder.SecretName = path.Join(c.options.ClusterId, secretNamespace, secretName)
// There is a matching secret and the gateway has already a tls secret.
// We should report the duplicated tls secret event.
@@ -428,14 +461,14 @@ func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapp
// Append https server
wrapperGateway.Gateway.Servers = append(wrapperGateway.Gateway.Servers, &networking.Server{
Port: &networking.Port{
Number: 443,
Number: uint32(c.options.GatewayHttpsPort),
Protocol: string(protocol.HTTPS),
Name: common.CreateConvertedName("https-443-ingress", c.options.ClusterId),
Name: common.CreateConvertedName("https-"+strconv.FormatUint(uint64(c.options.GatewayHttpsPort), 10)+"-ingress", c.options.ClusterId),
},
Hosts: []string{rule.Host},
Tls: &networking.ServerTLSSettings{
Mode: networking.ServerTLSSettings_SIMPLE,
CredentialName: credentials.ToKubernetesIngressResource(c.options.RawClusterId, cfg.Namespace, secretName),
CredentialName: credentials.ToKubernetesIngressResource(c.options.RawClusterId, secretNamespace, secretName),
},
})
@@ -878,15 +911,28 @@ func (c *controller) storeBackendTrafficPolicy(wrapper *common.WrapperConfig, ba
}
if common.ValidateBackendResource(backend.Resource) && wrapper.AnnotationsConfig.Destination != nil {
for _, dest := range wrapper.AnnotationsConfig.Destination.McpDestination {
portNumber := dest.Destination.GetPort().GetNumber()
serviceKey := common.ServiceKey{
Namespace: "mcp",
Name: dest.Destination.Host,
Port: int32(portNumber),
ServiceFQDN: dest.Destination.Host,
}
if _, exist := store[serviceKey]; !exist {
store[serviceKey] = &common.WrapperTrafficPolicy{
TrafficPolicy: &networking.TrafficPolicy{},
WrapperConfig: wrapper,
if serviceKey.Port != 0 {
store[serviceKey] = &common.WrapperTrafficPolicy{
PortTrafficPolicy: &networking.TrafficPolicy_PortTrafficPolicy{
Port: &networking.PortSelector{
Number: uint32(serviceKey.Port),
},
},
WrapperConfig: wrapper,
}
} else {
store[serviceKey] = &common.WrapperTrafficPolicy{
TrafficPolicy: &networking.TrafficPolicy{},
WrapperConfig: wrapper,
}
}
}
}

View File

@@ -73,6 +73,10 @@ func (m *IngressTranslation) InitializeCluster(ingressController common.IngressC
return nil
}
func (m *IngressTranslation) GetIngressConfig() *ingressconfig.IngressConfig {
return m.ingressConfig
}
func (m *IngressTranslation) RegisterEventHandler(kind config.GroupVersionKind, f model.EventHandler) {
m.ingressConfig.RegisterEventHandler(kind, f)
if m.kingressConfig != nil {

View File

@@ -2,7 +2,7 @@
目前 Higress 提供了 c++ 和 golang 两种 Wasm 插件开发框架,支持 Wasm 插件路由&域名级匹配生效。
同时提供了多个内置插件,用户可以基于 Higress 提供的官方镜像仓库直接使用这些插件:
同时提供了多个内置插件,用户可以基于 Higress 提供的官方镜像仓库直接使用这些插件(以 c++ 版本举例)
[basic-auth](./wasm-cpp/extensions/basic_auth)Basic Auth 认证鉴权
@@ -20,7 +20,7 @@
[request-block](./wasm-cpp/extensions/request_block):自定义请求屏蔽
使用方式具体可以参考此[文档](./wasm-go/README.md) 中相关说明。
使用方式具体可以参考此 [wasm-cpp Plugin文档](./wasm-cpp/README.md) ,或 [wasm-go Plugin文档](./wasm-go/README.md) 中相关说明。
所有内置插件都已上传至 Higress 的官方镜像仓库higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins
@@ -46,7 +46,7 @@ spec:
如果您想要为 Higress 贡献插件请参考下述说明。
根据你选择的开发语言,将插件代码放到 [wasm-cpp/extensions](./wasm-cpp/extensions) ,或者 [go-cpp/extensions](./wasm-go/extensions) 目录下。
根据你选择的开发语言,将插件代码放到 [wasm-cpp/extensions](./wasm-cpp/extensions) ,或者 [wasm-go/extensions](./wasm-go/extensions) 目录下。
除了代码以外,需要额外提供一个 README.md 文件说明插件配置方式,以及 VERSION 文件用于记录插件版本,用作推送镜像时的 tag。

View File

@@ -12,10 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
load("@proxy_wasm_cpp_sdk//bazel/wasm:wasm.bzl", "wasm_cc_binary")
load("@proxy_wasm_cpp_sdk//bazel:defs.bzl", "proxy_wasm_cc_binary")
load("//bazel:wasm.bzl", "declare_wasm_image_targets")
wasm_cc_binary(
proxy_wasm_cc_binary(
name = "basic_auth.wasm",
srcs = [
"plugin.cc",
@@ -28,7 +28,6 @@ wasm_cc_binary(
"//common:crypto_util",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/time",
"@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics",
],
)

View File

@@ -74,9 +74,7 @@ bool PluginRootContext::parsePluginConfig(const json& configuration,
}
if (absl::AsciiStrToLower(pair[0]) ==
Wasm::Common::Http::Header::ContentType) {
rule.content_type = pair[1];
has_content_type = true;
return true;
}
rule.headers.emplace_back(pair[0], pair[1]);
return true;
@@ -105,13 +103,11 @@ bool PluginRootContext::parsePluginConfig(const json& configuration,
if (!rule.body.empty() && !has_content_type) {
auto try_decode_json = Wasm::Common::JsonParse(rule.body);
if (try_decode_json.has_value()) {
rule.content_type = "application/json; charset=utf-8";
// rule.headers.emplace_back(Wasm::Common::Http::Header::ContentType,
// "application/json; charset=utf-8");
rule.headers.emplace_back(Wasm::Common::Http::Header::ContentType,
"application/json; charset=utf-8");
} else {
rule.content_type = "text/plain; charset=utf-8";
// rule.headers.emplace_back(Wasm::Common::Http::Header::ContentType,
// "text/plain; charset=utf-8");
rule.headers.emplace_back(Wasm::Common::Http::Header::ContentType,
"text/plain; charset=utf-8");
}
}
return true;
@@ -139,8 +135,6 @@ FilterHeadersStatus PluginRootContext::onResponse(
if (!hit) {
return FilterHeadersStatus::Continue;
}
replaceResponseHeader(Wasm::Common::Http::Header::ContentType,
rule.content_type);
sendLocalResponse(rule.status_code, "", rule.body, rule.headers);
return FilterHeadersStatus::StopIteration;
}

View File

@@ -40,7 +40,6 @@ namespace custom_response {
struct CustomResponseConfigRule {
std::vector<std::string> enable_on_status;
std::vector<std::pair<std::string, std::string>> headers;
std::string content_type;
int32_t status_code = 200;
std::string body;
};

View File

@@ -146,12 +146,66 @@ TEST_F(CustomResponseTest, EnableOnStatus) {
status_code_ = "429";
EXPECT_EQ(context_->onRequestHeaders(0, false),
FilterHeadersStatus::Continue);
EXPECT_CALL(*mock_context_, sendLocalResponse(233, testing::_, testing::_,
testing::_, testing::_));
EXPECT_CALL(
*mock_context_,
sendLocalResponse(
233, testing::_,
testing::ElementsAre(
testing::Pair("abc", "123"), testing::Pair("zty", "test"),
testing::Pair("content-type", "application/json; charset=utf-8")),
testing::_, testing::_));
EXPECT_EQ(context_->onResponseHeaders(0, false),
FilterHeadersStatus::StopIteration);
}
TEST_F(CustomResponseTest, ContentTypePlain) {
std::string configuration = R"(
{
"status_code": 200,
"body": "abc"
})";
BufferBase buffer;
buffer.set({configuration.data(), configuration.size()});
EXPECT_CALL(*mock_context_, getBuffer(WasmBufferType::PluginConfiguration))
.WillOnce([&buffer](WasmBufferType) { return &buffer; });
EXPECT_TRUE(root_context_->configure(configuration.size()));
EXPECT_CALL(
*mock_context_,
sendLocalResponse(200, testing::_,
testing::ElementsAre(testing::Pair(
"content-type", "text/plain; charset=utf-8")),
testing::_, testing::_));
EXPECT_EQ(context_->onRequestHeaders(0, false),
FilterHeadersStatus::StopIteration);
}
TEST_F(CustomResponseTest, ContentTypeCustom) {
std::string configuration = R"(
{
"status_code": 200,
"headers": ["content-type=application/custom"],
"body": "abc"
})";
BufferBase buffer;
buffer.set({configuration.data(), configuration.size()});
EXPECT_CALL(*mock_context_, getBuffer(WasmBufferType::PluginConfiguration))
.WillOnce([&buffer](WasmBufferType) { return &buffer; });
EXPECT_TRUE(root_context_->configure(configuration.size()));
EXPECT_CALL(*mock_context_,
sendLocalResponse(200, testing::_,
testing::ElementsAre(testing::Pair(
"content-type", "application/custom")),
testing::_, testing::_));
EXPECT_EQ(context_->onRequestHeaders(0, false),
FilterHeadersStatus::StopIteration);
}
TEST_F(CustomResponseTest, NoGlobalRule) {
std::string configuration = R"(
{

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