Compare commits

...

316 Commits

Author SHA1 Message Date
Se7en
6a289d914f Update README.md 2025-05-14 17:46:51 +08:00
Rishi Mondal
675a8ce4a9 Add test translation workflow (#2228)
Signed-off-by: Rishi Mondal <mavrickrishi@gmail.com>
2025-05-14 17:35:50 +08:00
澄潭
06c5ddd80b Update README.md 2025-05-14 16:25:00 +08:00
EricaLiu
8ccc170500 fix : fix issue #2222 (#2231) 2025-05-14 15:40:19 +08:00
韩贤涛
ff308d5292 fix: Remove the Authorization request header when using AI-proxy to proxy Gemini (#2220) 2025-05-13 09:36:04 +08:00
littlejian
af8502b0b0 feat: update translate-readme action (#2208) 2025-05-12 14:34:04 +08:00
Kent Dong
c683936b1c fix: Fix the incorrect rewrite config generated for Nacos 3 MCP Servers (#2211) 2025-05-12 14:30:37 +08:00
Xijun Dai
8b3f1aab1a feat(ai-proxy): support Amazon Bedrock Image Generation (#2212)
Signed-off-by: Xijun Dai <daixijun1990@gmail.com>
Co-authored-by: Kent Dong <ch3cho@qq.com>
2025-05-10 09:54:31 +08:00
johnlanni
b5eadcdbee release v2.1.3 2025-05-09 15:30:22 +08:00
EricaLiu
8ca8fd27ab fix param type error (#2204) 2025-05-09 14:55:10 +08:00
Kent Dong
ab014cf912 feat: Add SSE direct proxy support to mcp-session filter (#2157) 2025-05-09 14:28:42 +08:00
EricaLiu
3f67b05fab fix : fix vs rewrite when mcp protocol is http (#2203) 2025-05-09 14:03:31 +08:00
HaoJie Liu
cd271c1f87 fix(ai-statistics): adjust requestBodyBufferLimit (#2192)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2025-05-08 16:18:50 +08:00
johnlanni
755de5ae67 add original path info in mcp-server 2025-05-07 21:17:18 +08:00
johnlanni
40402e7dbd refactor route call in mcp-server 2025-05-07 20:36:41 +08:00
johnlanni
0a2fb35ae2 fix gemini provider in ai-proxy 2025-05-07 16:54:40 +08:00
澄潭
b16954d8c1 Update README.md 2025-05-07 15:27:28 +08:00
Kent Dong
29370b18d7 feat: Support /v1/models API in ai-proxy (#2164) 2025-05-06 15:53:13 +08:00
EricaLiu
c9733d405c fix : Add nacos username and password login option (#2170) 2025-05-06 15:18:45 +08:00
johnlanni
ec6004dd27 update golang filter dependency 2025-04-30 23:33:04 +08:00
Jingze
ea9a6de8c3 fix: update golang filter README (#2147) 2025-04-29 22:08:10 +08:00
github-actions[bot]
5e40a700ae Update helm translated README.zh.md (#2152) 2025-04-29 21:04:23 +08:00
johnlanni
48b220453b release 2.1.2 2025-04-29 20:53:50 +08:00
mirror
489a800868 add: add mcp-context7 descriptions (#2149) 2025-04-29 20:44:00 +08:00
澄潭
60c9f21e1c When the service source type is nacos3, if mcpserver is turned off, then the discovery mechanism of nacos2 will be enabled (#2150) 2025-04-29 17:29:52 +08:00
Jingze
ab73f21017 fix: make mcp server redis client config based (#2145)
Co-authored-by: daijingze_mac <18373118@buaa.edu.cn>
2025-04-29 14:27:48 +08:00
EricaLiu
806563298b fix : when nacos push empty service instance list, should skip generate (#2144) 2025-04-29 11:38:51 +08:00
github-actions[bot]
02fabbb35f Update helm translated README.zh.md (#2141) 2025-04-29 09:28:20 +08:00
johnlanni
07154d1f49 set mcp-go dependency to 0.12 2025-04-28 23:02:28 +08:00
johnlanni
db30c0962a update go mod 2025-04-28 22:04:21 +08:00
johnlanni
731fe43d14 update envoy-release version 2025-04-28 21:59:30 +08:00
EricaLiu
5bd20aa559 feat : support mcp server auto discovery for nacos registry (#2122)
Co-authored-by: 澄潭 <zty98751@alibaba-inc.com>
2025-04-28 21:58:17 +08:00
johnlanni
a2e4f944e9 rel 2.1.2-rc.1 2025-04-28 20:39:02 +08:00
johnlanni
7955aec639 change golang-filter build image 2025-04-28 19:43:17 +08:00
johnlanni
e12feb9f57 golang-filter use go 1.22 2025-04-28 19:21:09 +08:00
zty98751
03b4144cff update submodule commit 2025-04-28 17:42:58 +08:00
Jingze
c382635e7f fix: Refactor MCP Server into MCP Session and MCP Server (#2120) 2025-04-28 13:42:14 +08:00
007gzs
e381806ba0 fix: ai_data_masking add compatibility handling for non-compliant API response structures (#2130) 2025-04-27 14:31:02 +08:00
johnlanni
52114b37f8 update mcp server config fields in mcp-bridge api 2025-04-27 11:10:08 +08:00
mirror
b4e68c02f9 add mcp yuque descriptions (#2125) 2025-04-25 18:08:42 +08:00
Tsukilc
c241ccf19d test: add test for /pkg/ingress/kube/common (#2123) 2025-04-24 20:03:57 +08:00
澄潭
e4fa1e6390 Update README_ZH.md 2025-04-24 19:08:40 +08:00
澄潭
b103b9d7cb Update README.md 2025-04-24 19:08:10 +08:00
johnlanni
90b02a90e0 update mcpbridge proto 2025-04-24 15:52:17 +08:00
mirror
38f718b965 update github & e2bdev mcp descriptions (#2107) 2025-04-23 20:08:21 +08:00
johnlanni
8752a763c2 update all-in-one mcp-server 2025-04-23 14:42:44 +08:00
HaoJie Liu
a57173ce28 feat(ai-proxy): support Amazon Bedrock (#2039) 2025-04-22 22:36:14 +08:00
mirror
3a8d8f5b94 update mcp descriptions (#2105) 2025-04-22 17:01:41 +08:00
Kent Dong
1c37c361e1 feat: Support extracting model argument from body in multipart/form-data format (#1940) 2025-04-22 13:52:50 +08:00
Se7en
b8133a95b2 feat: optimize elasticsearch ai-search plugin and update related docs" (#2100) 2025-04-22 13:33:38 +08:00
johnlanni
36d5d391b8 update README.md 2025-04-21 09:59:37 +08:00
johnlanni
1da9a07866 update README 2025-04-21 09:56:23 +08:00
ZeruiYang
8620838f8b fix: update module replacements (#2090) 2025-04-19 18:13:42 +08:00
waTErMo0n
e7d2005382 feat:Getting MatchLabels dynamically via gatewaySelectorKey/Value #1857 (#1883) 2025-04-18 17:46:47 +08:00
johnlanni
4f47d3fc12 rel: Release 2.1.1 2025-04-18 16:47:07 +08:00
rinfx
6773482300 Enhance the compatibility of AI observability plugins with different LLM suppliers (#2088) 2025-04-18 16:19:59 +08:00
johnlanni
b6d61f9568 update README 2025-04-18 13:43:33 +08:00
Jingze
1834d4acef fix: support mcp server database reconnect and fix tool/list method denied (#2074) 2025-04-18 11:19:56 +08:00
johnlanni
7f9ae38e51 update all-in-one mcp-server depenednecy 2025-04-17 16:25:00 +08:00
mirror
b13bce6a36 add mcp descriptions (#2080) 2025-04-17 13:46:31 +08:00
liseri
275cac9dbb fix wasm-go/jwt-auth claims_to_headers bug (#2057)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2025-04-16 20:25:01 +08:00
澄潭
8cce7f5d50 add mcp servers (#2076) 2025-04-16 14:48:53 +08:00
rinfx
4f0834d817 rm plugin id after use (#2070) 2025-04-15 19:47:43 +08:00
Kent Dong
7cf0dae824 feat: Support building waf plugin using Makefile (#2061) 2025-04-15 10:25:59 +08:00
johnlanni
707061fb68 release 2.1.1-rc.1 2025-04-14 21:05:00 +08:00
zty98751
3255925bf0 update submodule commit 2025-04-14 20:51:10 +08:00
zty98751
a44f7ef76e update submodule commit 2025-04-14 20:48:42 +08:00
Jingze
c7abfb8aff feat: support config store and redis configuration optional in mcp server (#2035) 2025-04-14 20:52:48 +08:00
johnlanni
ed925ddf84 update amap tools mcp server 2025-04-14 19:41:00 +08:00
johnlanni
1301af4638 remove useless log 2025-04-14 19:14:30 +08:00
johnlanni
de6144439f update all-in-one mcp server 2025-04-14 19:10:02 +08:00
澄潭
e37c4dc286 Fix the issue of traps caused by gc in wasm plugins compiled with go 1.24 (#2054) 2025-04-14 14:46:54 +08:00
小小hao
b8e0baa5ab feat:add GetContextId func for HttpContext (#2043) 2025-04-14 14:40:24 +08:00
Kent Dong
4a157e98e9 fix: Escape asterisk characters in ai-proxy documents (#1999) 2025-04-12 11:14:32 +08:00
澄潭
6af8b17216 Update README.md 2025-04-11 20:07:16 +08:00
Xin Luo
4500b10a42 fix: fix param mapping use %v instead of %s (#2046) 2025-04-11 15:07:46 +08:00
澄潭
c5a86b5298 Update README.md 2025-04-11 14:18:10 +08:00
Xin Luo
36806d9e5c support nacos namespace (#2045) 2025-04-11 14:12:51 +08:00
mamba
d1700009e8 [frontend-gray] 重构业务逻辑,对于微前端和多版本支持更加友好 (#2011) 2025-04-11 10:35:18 +08:00
澄潭
2c3188dad7 Update README.md 2025-04-10 17:32:51 +08:00
澄潭
7d423cddbd Update README.md 2025-04-10 17:29:06 +08:00
澄潭
0e94e1a58a mcp: support amap auto ip detection (#2041) 2025-04-10 17:08:01 +08:00
Se7en
b1307ba97e fix: ai statistics doc (#2040) 2025-04-10 15:38:19 +08:00
Xin Luo
8ae810b01a Feat dynamic tool reset (#2031) 2025-04-09 10:46:36 +08:00
johnlanni
83b38b896c update mcp server readme 2025-04-07 21:06:04 +08:00
johnlanni
1385028f01 update mcp server dependency 2025-04-07 21:04:29 +08:00
littlejian
af663b701a polish translate-readme action (#2020) 2025-04-07 20:23:45 +08:00
DefNed
e5c24a10fb feat: update custom-response plugin to returns different contents for different response status (#2002) 2025-04-06 09:04:40 +08:00
澄潭
ea85ccb694 Update README.md 2025-04-04 13:45:08 +08:00
澄潭
2467004dc9 release 2.1.0 (#2008) 2025-04-02 17:04:13 +08:00
澄潭
5af818a94e optimize: Support viewing MCP debug information in the response code details log field (#2007) 2025-04-02 15:31:09 +08:00
johnlanni
728a9de165 update mcp-server plugin dependency 2025-04-02 13:41:49 +08:00
johnlanni
823527ab94 update higress console to 2.1.0 2025-04-01 23:34:56 +08:00
johnlanni
cb7f6ccd0f Revert "release 2.1.0 (#1998)"
This reverts commit 3c73976130.
2025-04-01 23:33:30 +08:00
澄潭
5107ce5137 fix poll_oneof (#2003) 2025-04-01 23:06:14 +08:00
johnlanni
e6d32aa1cf fix helm README 2025-04-01 23:05:08 +08:00
Jingze
3c73976130 release 2.1.0 (#1998) 2025-04-01 18:45:36 +08:00
澄潭
639956c0b8 release 2.1.0 rc.2 (#1995) 2025-04-01 15:32:33 +08:00
Jingze
a602f7a725 fix: Golang filter supports skipping processing at the body stage. (#1989) 2025-04-01 15:27:38 +08:00
澄潭
7b6e4154f4 update proxy-wasm-cpp-host (#1993) 2025-04-01 14:59:46 +08:00
Xin Luo
12e3f34c0b use custom nacos go sdk for disable log (#1991) 2025-04-01 14:56:55 +08:00
Xin Luo
bdd802f44f feat: support service delete event trigger for tool and some fix (#1987) 2025-04-01 09:43:43 +08:00
littlejian
d58b66df8f feat: Add an optional Redis component to the Higress helm package (#1973) 2025-04-01 09:29:46 +08:00
rinfx
5d99c7d80a rename redis key (#1986) 2025-03-31 22:28:06 +08:00
johnlanni
3428932aca update mcp-server README 2025-03-31 21:51:50 +08:00
澄潭
7ba3f75d41 support rest to mcp (#1988) 2025-03-31 21:41:38 +08:00
Jingze
ae9a06b05c fix: mcp proxy eventData (#1985) 2025-03-31 18:38:52 +08:00
DefNed
9ebe968921 fix: 修复envoy.yaml配置文件中几处问题 (#1983) 2025-03-31 17:06:36 +08:00
Jingze
93e3b086ce fix: fix bug of mcp server proxy (#1981) 2025-03-31 15:40:36 +08:00
小小hao
20dfc3d64f fix inclusionRegexps not working (#1972) 2025-03-30 10:41:01 +08:00
澄潭
492c5d350a Add all in one mcp (#1978) 2025-03-30 00:25:21 +08:00
澄潭
037c71a320 refactor mcp sdk (#1977) 2025-03-29 20:28:10 +08:00
Yiiong
9a07c50f44 docs: 添加Azure OpenAI配置说明 (#1976) 2025-03-29 20:11:48 +08:00
Yiiong
b86e9fc938 feat: add azure embedding to ai-cache (#1975) 2025-03-29 18:08:37 +08:00
Se7en
2014234356 doc: add ai statistics metric doc (#1889) 2025-03-29 16:21:49 +08:00
Jingze
83f69a0186 fix: mcp server config map (#1969)
Co-authored-by: 澄潭 <zty98751@alibaba-inc.com>
2025-03-27 18:13:40 +08:00
Jingze
8495d17070 fix: add match list and wasm mcp-server message pub in redis (#1963) 2025-03-27 17:00:32 +08:00
澄潭
6f762b5e4c fix golang filter build (#1966) 2025-03-27 16:43:06 +08:00
澄潭
96e4713703 update default enable path suffix in model mapper&router plugin (#1962) 2025-03-27 14:15:11 +08:00
Xin Luo
d3887835a3 feat: support nacos mcp registry (#1961) 2025-03-27 09:41:22 +08:00
澄潭
1965d107d0 Update README.md 2025-03-27 00:49:19 +08:00
johnlanni
b2f9bf94fa update README 2025-03-27 00:48:24 +08:00
johnlanni
9257077fa3 update mcp readme 2025-03-27 00:26:02 +08:00
zty98751
7e310a3520 update gomod in hgctl 2025-03-26 21:53:28 +08:00
Jingze
663b28fa9b fix: update log info to debug (#1954) 2025-03-26 21:54:06 +08:00
Kent Dong
9fbe331f5f fix: Fetch get-higress.sh from standalone repo (#1945) 2025-03-26 21:53:39 +08:00
zty98751
dd50ac09dc fix cache action in workflow 2025-03-26 21:43:47 +08:00
澄潭
8450a0869b rel 2.1.0-rc.1 (#1959) 2025-03-26 21:42:25 +08:00
澄潭
bd6708552d key auth support multiple credentials (#1956)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2025-03-26 21:05:55 +08:00
Kent Dong
50cfa0bb4b fix: Fix the incorrect image used to build envoy (#1958) 2025-03-26 20:38:40 +08:00
澄潭
ea0143829d Fix log import (#1957) 2025-03-26 20:27:53 +08:00
Jingze
f83e66c23b feat: update Go filter mcp-server (#1950)
Co-authored-by: johnlanni <zty98751@alibaba-inc.com>
2025-03-26 14:31:23 +08:00
Jingze
87fe1aeeb5 feat: add mcpServer in config map (#1953) 2025-03-26 14:30:41 +08:00
mirror
386a208b14 add: add mcp server amap tools (#1951) 2025-03-25 21:20:36 +08:00
澄潭
ee77ffb753 fix ai-search rewrite query when no search result found (#1949) 2025-03-25 14:24:16 +08:00
澄潭
6eeef07621 revert wrapper changes (#1948) 2025-03-25 11:55:14 +08:00
澄潭
8978a4e0e0 fix invalid ai-proxy cluster (#1947)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2025-03-25 11:20:20 +08:00
007gzs
71029d791d add parse_rule_config fail log (#1938) 2025-03-25 10:44:48 +08:00
澄潭
d9f16f7d5e Add remote mcp server sdk (#1946) 2025-03-24 22:11:45 +08:00
Jingze
f5d20b72e0 feat: add config parse in mcp server (#1944) 2025-03-24 17:52:16 +08:00
Kent Dong
9bde0dfb46 chore: Remove redundant get-higress.sh (#1943) 2025-03-24 14:28:45 +08:00
Jingze
f5c1e7f2ec feat: add golang filter and mcp-server (#1942)
Co-authored-by: johnlanni <zty98751@alibaba-inc.com>
2025-03-24 11:07:03 +08:00
澄潭
45fbc8b084 optimize plugin sdk (#1930) 2025-03-22 22:46:37 +08:00
rinfx
1812a6b0a9 add example for extending span attributes (#1936) 2025-03-21 15:39:52 +08:00
rinfx
2640c76760 improve the logic for constructing redis key (#1933) 2025-03-21 14:02:59 +08:00
rinfx
4223b2d666 Fix the error in the embedding interface under the AI proxy Qwen compatible mode. (#1928) 2025-03-21 08:32:00 +08:00
DefNed
dee4786c1c feat: add buffer_limit functions (#1922)
Co-authored-by: 纪卓志 <jizhuozhi.george@gmail.com>
Co-authored-by: 007gzs <007gzs@gmail.com>
2025-03-20 18:07:13 +08:00
Yiiong
e549c79ae4 feat: add xfyun emb to ai-cache (#1921) 2025-03-20 11:05:36 +08:00
小小hao
6742df57df feat: add ratelimit metrics in the ai-token-ratelimit plugin (#1918) 2025-03-19 21:51:56 +08:00
Kent Dong
eef8adf42f fix: Skip reading non-JSON request bodies in ai-proxy (#1914) 2025-03-18 21:23:54 +08:00
007gzs
029c3e75fc optimization parseIP in xff (#1915) 2025-03-18 15:58:24 +08:00
Kent Dong
9fa3a730d5 feat: Support forwarding embedding calls to Ollama in ai-proxy (#1913) 2025-03-18 10:23:34 +08:00
澄潭
9acaed0b43 Update README_EN.md 2025-03-17 17:40:14 +08:00
澄潭
f95264448c Update README.md 2025-03-17 17:39:46 +08:00
澄潭
e0dc9672ac support nil option in NewCommonVmCtx (#1909) 2025-03-17 15:02:22 +08:00
Kent Dong
5de7c2a5ea feat: Support files and batches APIs provided by Azure OpenAI (#1904) 2025-03-17 11:21:05 +08:00
澄潭
9a89665b22 optimize retry&failover logic (#1903) 2025-03-17 11:19:33 +08:00
Jun
4a82d50d80 add variable from secret when applying istio cr (#1877) 2025-03-17 10:59:05 +08:00
澄潭
34b3fc3114 more optimize of ai search plugin (#1896) 2025-03-14 23:24:22 +08:00
澄潭
f09e029a6b fix chunk merge bug in ai-search (#1895) 2025-03-14 21:52:49 +08:00
澄潭
5e7e20ff7e AI-search plugin supports controlling through the web_search_options parameter. (#1893) 2025-03-14 21:52:33 +08:00
007gzs
26bfdd45ff Rust WASM plugin support for matching service and route name prefixes is effective. (#1882) 2025-03-14 20:43:19 +08:00
澄潭
61defc13c6 fix openai embedding path (#1881) 2025-03-12 13:16:33 +08:00
Se7en
19496e5759 feat: support retry on http status code (#1817)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2025-03-11 13:38:02 +08:00
mamba
beb60fcacd bugfix:【frontend-gray插件】针对fetch的请求,强制不缓存 (#1856) 2025-03-11 12:54:40 +08:00
Se7en
01cc7939ae feat: support elasticsearch hybrid search (#1844) 2025-03-11 11:25:58 +08:00
rinfx
5a5af4ecbf support default value (#1873) 2025-03-11 09:32:11 +08:00
澄潭
d172cf4d19 Update README_EN.md 2025-03-10 17:33:13 +08:00
澄潭
58c4ba2021 Update README.md 2025-03-10 17:32:22 +08:00
rinfx
9e2df8f7c7 add redis init status log (#1867)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2025-03-10 17:10:53 +08:00
Yiiong
b897825069 feat: add huggingface embedding to ai-cache (#1864) 2025-03-10 16:59:13 +08:00
yunmaoQu
f45bc9008a feat: add replay protection plugin (#1672)
Co-authored-by: hanxiantao <601803023@qq.com>
2025-03-10 15:11:13 +08:00
Se7en
5536502c15 feat: allow failover to distinguish between different endpoint of the same provider (#1862) 2025-03-10 10:45:59 +08:00
澄潭
a0c334a7cb optimize model router&mapper (#1866) 2025-03-09 23:07:49 +08:00
澄潭
9e6bd6d2cc optimize ai-search references (#1859) 2025-03-07 10:34:49 +08:00
Kent Dong
ab419efda4 fix: Fix the incorrect reasoning content concat logic in ai-proxy (#1842) 2025-03-07 10:33:45 +08:00
Jacky Wu
d4155411ee fix plugin_wrapper.go log level (#1848) 2025-03-06 14:41:47 +08:00
Jacky Wu
d721c235cb chore: load EXTRA_TAGS from plugin .buildrc file to avoid build issue. (#1852) 2025-03-05 12:15:37 +08:00
澄潭
0905cd0fc0 Set the llm-api-key field of the ai-search plugin to optional (#1846) 2025-03-03 20:42:15 +08:00
Kent Dong
188914a16b feat: Support only watching key resources in one namespace (#1821) 2025-03-03 15:40:44 +08:00
rinfx
988e2c1fa7 add plugin start log in sdk (#1831) 2025-03-03 15:37:23 +08:00
Kent Dong
4f1901586a doc: Update the description of timeout config of ai-proxy (#1845) 2025-03-03 15:33:16 +08:00
Xijun Dai
80b58e86e1 feat(helm): add podLabels to gateway && controller (#1792)
Signed-off-by: Xijun Dai <daixijun1990@gmail.com>
2025-03-03 15:31:28 +08:00
澄潭
ca32e587d3 optimize ai search (#1843) 2025-03-03 09:44:53 +08:00
澄潭
6d2d98f653 Simplify the implementation of ai-search integration with quark and add a tutorial. (#1838) 2025-02-28 18:36:07 +08:00
firebook
2d1d8ac2b1 fix: gateway log config should read from helm\core\values.yaml when deploy with helm (#1834) 2025-02-28 14:14:13 +08:00
Kent Dong
a2b8f9a646 fix: Disable helm-docs action since it's still under development (#1828) 2025-02-28 13:36:44 +08:00
007gzs
5bece9c8ef fix rust_wasm_build (#1824) 2025-02-27 14:15:50 +08:00
Kent Dong
45fdd95a9c feat: Support pushing multi-arch images to a custom image registry (#1815) 2025-02-26 21:15:53 +08:00
Se7en
d3afe345ad fix: remove last failed apiToken from retry apiToken list (#1802) 2025-02-26 21:11:51 +08:00
韩贤涛
90ca903d2e feat: ext-auth plugin: Blacklist and whitelist modes support HTTP request method matching (#1798) 2025-02-26 20:54:52 +08:00
007gzs
2d8a8f26da Ai data masking msg window (#1775) 2025-02-26 20:48:37 +08:00
Se7en
9ea2410388 feat: update ai-token-ratelimit documentation by removing ai-statistics plugin (#1767) 2025-02-26 20:47:37 +08:00
littlejian
9e1792c245 add notes to gateway.rollingMaxUnavailable (#1819) 2025-02-26 20:46:53 +08:00
rinfx
3eda7def89 ai-search support quark (#1811) 2025-02-26 18:42:22 +08:00
澄潭
1787553294 set include_usage by default for all model providers (#1818) 2025-02-26 16:49:16 +08:00
澄潭
f6c48415d1 Add database configuration for plugins that use Redis. (#1814) 2025-02-26 10:52:54 +08:00
MARATRIX Li
e27d3d0971 fix(typo): use the correct bing name for ai-search. (#1807)
Signed-off-by: maratrixx <maratrix@163.com>
2025-02-25 13:37:32 +08:00
Kent Dong
49617c7a98 feat: Unify the SSE processing logic (#1800) 2025-02-25 11:00:18 +08:00
澄潭
53a015d8fe Update arxiv.md 2025-02-24 11:27:55 +08:00
澄潭
e711e9f997 Update full.md 2025-02-24 11:27:33 +08:00
澄潭
8530742472 Update README_EN.md 2025-02-24 11:16:09 +08:00
澄潭
c0c1f5113a Update README.md 2025-02-24 11:15:55 +08:00
澄潭
2e6ddd7e35 Add ai search plugin (#1804) 2025-02-24 11:14:47 +08:00
Kent Dong
2328e19c9d fix: Fix a bug in openaiCustomUrl support (#1790) 2025-02-22 12:12:49 +08:00
Kent Dong
fabc22f218 feat: Support transforming reasoning_content returned by Qwen to OpenAI contract (#1791) 2025-02-21 17:32:02 +08:00
Yiiong
2986e1911d feat: add ollama embedding to ai-cache (#1794) 2025-02-21 15:21:49 +08:00
澄潭
a566f7257d update helm docs (#1782) 2025-02-19 17:48:20 +08:00
澄潭
3dbd1b2731 release 2.0.7 (#1781) 2025-02-19 17:44:08 +08:00
澄潭
7f23980bf5 remove basic-auth useless annotation (#1779) 2025-02-19 15:58:03 +08:00
澄潭
6fb0684c39 fix openai compatiable (#1778) 2025-02-19 15:23:15 +08:00
澄潭
dfac9fa5e6 Update README.md 2025-02-18 14:17:21 +08:00
澄潭
bfd9e3026d Update helm-docs.yaml 2025-02-18 10:00:05 +08:00
澄潭
49aad4152c Supports completions API & support config openai baseUrl through openaiCustomUrl (#1765) 2025-02-18 09:57:48 +08:00
澄潭
94aacf5153 Update helm-docs.yaml
Remove the part that causes the action to fail
2025-02-17 18:59:54 +08:00
littlejian
efcfdbf36e Add translate-readme action to translate English into Chinese (#1711) 2025-02-17 17:34:30 +08:00
澄潭
2dbde1833f ai proxy support passthrough path when api name is unknown (#1754) 2025-02-13 21:22:43 +08:00
mirror
7272eff8b6 update ai-cache extension (#1746) 2025-02-13 19:49:52 +08:00
pepesi
a84a382f1d feature: allow ai-proxy to forward standard AI capabilities that are … (#1704) 2025-02-12 15:23:44 +08:00
韩贤涛
477e44b9f1 e2e: Enhance the e2e testing of the ai-proxy plugin based on the LLM mock server (#1742) 2025-02-11 20:16:03 +08:00
澄潭
512385d225 fix host rewrite in frontend-gray (#1747) 2025-02-08 17:42:29 +08:00
007gzs
b997e6fd26 wasm32-wasi to wasm32-wasip1 (#1716) 2025-02-05 15:35:48 +08:00
韩贤涛
fab3ebb35a ut: add ext-auth unit tests (#1710) 2025-02-05 13:39:10 +08:00
韩贤涛
1431ff9cfe e2e: Enhance the e2e testing of the ai-proxy plugin based on the LLM mock server (#1713) 2025-02-05 10:14:25 +08:00
kai2321
fac2c3e7a3 feat:完善对接dify时返回usage相关信息 (#1715) 2025-02-03 08:35:00 +08:00
韩贤涛
574d1aa36a fix: Path concatenation issue for authentication requests in Envoy authentication mode (#1709) 2025-01-23 15:47:07 +08:00
澄潭
7840167c4a optimize body bufferlimit set in ext-auth plugin (#1707) 2025-01-23 11:52:30 +08:00
韩贤涛
9d8e78dae3 fix: ext-auth crash bugfix (#1705) 2025-01-23 11:29:49 +08:00
Se7en
133a30b8d5 fix: stream response buffer issue (#1703) 2025-01-22 11:28:37 +08:00
kai2321
ce94c6e62d feat:接入dify (#1664) 2025-01-21 16:04:15 +08:00
Xijun Dai
05f251e627 fix gateway env (#1689) 2025-01-21 15:05:14 +08:00
韩贤涛
0259eaddbb feat: Add ext-auth plugin support for authentication blacklists/whitelists (#1694) 2025-01-21 14:28:49 +08:00
Se7en
cfa3baddf8 sync ai-token-ratelimit docs (#1688) 2025-01-19 13:05:25 +08:00
Se7en
b1f625a652 feat: support baidu api key (#1687) 2025-01-19 11:46:29 +08:00
澄潭
fd1eb54f25 Release 2.0.6 (#1686) 2025-01-17 15:22:43 +08:00
澄潭
c7550e2d49 Update deploy-to-oss.yaml 2025-01-17 15:10:40 +08:00
Se7en
ba74f4bbb9 fix: baidu api issue (#1685) 2025-01-16 21:42:43 +08:00
澄潭
9e418dafd9 release 2.0.6-rc.3 (#1680) 2025-01-15 20:47:20 +08:00
澄潭
95523a1bc7 Fix istio lds cache (#1679) 2025-01-15 20:44:13 +08:00
澄潭
dcd8466127 Update build-and-test-plugin.yaml 2025-01-15 20:19:58 +08:00
澄潭
cceae6ad2a update cpp wasm plugins (#1675) 2025-01-15 19:15:11 +08:00
zty98751
32f9a5ff32 fix istio commit 2025-01-15 15:29:44 +08:00
澄潭
6f95297b80 Release 2.0.6-rc.2 (#1671) 2025-01-14 20:10:53 +08:00
Kent Dong
95426d5ccf fix: Fix a typo in the README files of ai-statistics plugin (#1670) 2025-01-14 13:39:55 +08:00
澄潭
a05b6b1e9d add ai_log field (#1669) 2025-01-14 10:03:24 +08:00
Jun
d0628344da add higress architecture doc (#1662) 2025-01-14 09:48:32 +08:00
韩贤涛
a1bf315b13 fix: resolve blocking issue with minimax responses in ai-proxy (#1663) 2025-01-14 09:43:19 +08:00
mamba
b3d9123d59 [frontend-gray] 微前端灰度 场景,支持 IncludePathPrefixes字段 (#1666) 2025-01-13 16:24:51 +08:00
rinfx
817061c6cc remove dependency for ai-statistic (#1660) 2025-01-10 13:43:29 +08:00
rinfx
ea0d5e7564 Improve ai plugins (#1657)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2025-01-09 22:04:51 +08:00
澄潭
2a89c3bb70 Optimize wasmplugin proto (#1656) 2025-01-09 13:19:46 +08:00
johnlanni
a570c72504 Update Chart.lock 2025-01-08 17:14:27 +08:00
澄潭
ab1316dfe1 rel: Release 2.0.6-rc.1 (#1653) 2025-01-08 17:08:09 +08:00
澄潭
e97448b71b Update metrics & enable lds cache (#1650) 2025-01-08 16:49:23 +08:00
澄潭
6820a06a99 fix tls version annotation (#1652) 2025-01-08 15:31:39 +08:00
澄潭
4733af849d Update README.md 2025-01-08 11:30:29 +08:00
yunmaoQu
1c2330e33b feat: add TLS version annotation support for per-rule configuration (#1592)
Co-authored-by: 澄潭 <zty98751@alibaba-inc.com>
2025-01-06 21:29:09 +08:00
澄潭
61fef0ecf8 Release 2.0.5 (#1646) 2025-01-06 19:42:18 +08:00
澄潭
d29b8d7ca8 fix ai proxy checkStream (#1645) 2025-01-06 15:30:02 +08:00
澄潭
2501895b66 ai-cache update body buffer limit size (#1644) 2025-01-06 14:53:29 +08:00
Kent Dong
187a7b5408 fix: Enlarge the default retry timeout in ai-proxy (#1640) 2025-01-03 11:19:40 +08:00
Jingze
00be491d02 feat: support github provider for oidc wasm plugin (#1639) 2025-01-02 10:01:54 +08:00
ayanami-desu
2d74c48e8a Add cohere embedding for ai-cache (#1572) 2024-12-27 17:48:44 +08:00
澄潭
6dc4d43df5 optimize ai cache (#1626) 2024-12-27 10:10:57 +08:00
rinfx
2a4e55d46f move oidcHandler from global to pluginconfig (#1601) 2024-12-26 19:15:20 +08:00
Se7en
579c986915 feat: retry failed request (#1590) 2024-12-26 18:30:50 +08:00
Kent Dong
380717ae3d fix: Make opa listen to all IPs (#1621) 2024-12-26 17:41:28 +08:00
Kent Dong
8f3723f554 feat: Support setting gateway.unprivilegedPortSupported manually (#1616) 2024-12-23 19:45:47 +08:00
VinciWu557
909cc0f088 feat: AI 代理 Wasm 插件接入 Together AI (#1617) 2024-12-23 15:39:56 +08:00
007gzs
4eaf204737 Enhance the capabilities of the AI Intent plugin (#1605) 2024-12-20 10:25:17 +08:00
澄潭
748bcb083a redis wrapper support lazy init and database options (#1602) 2024-12-19 16:22:56 +08:00
澄潭
39c007d045 optimize ai proxy (#1603) 2024-12-19 16:22:35 +08:00
rinfx
d74d327b68 bugfix: cannot parse content if one streaming body has multi chunks (#1606) 2024-12-19 16:21:57 +08:00
澄潭
be27726721 Update CODEOWNERS 2024-12-19 14:36:11 +08:00
澄潭
34cc1c0632 Update README.md 2024-12-18 17:02:28 +08:00
澄潭
5694475872 Update README.md 2024-12-18 16:59:03 +08:00
rinfx
2f5709a93e qwen bailian compatible bug fix (#1597) 2024-12-17 16:57:31 +08:00
StarryNight
2a200cdd42 AI proxy return unified status in header phase (#1588) 2024-12-16 18:41:38 +08:00
rinfx
ec39d56731 AI observability upgrade (#1587)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2024-12-16 10:27:49 +08:00
韩贤涛
8544fa604d feat: support choosing chatCompletionV2 or chatCompletionPro API for minimax provider (#1593) 2024-12-15 15:12:00 +08:00
mirror
0ba63e5dd4 fix: default port of static service in ai-cache plugin (#1591) 2024-12-13 19:03:26 +08:00
mirror
441408c593 docs: fix typos in ai-quota document (#1589) 2024-12-13 08:56:43 +08:00
duxin40
be57960c22 Support OpenAI embedding. (#1542) 2024-12-11 11:42:51 +08:00
rinfx
f32020068a bugfix and extend ai log (#1576) 2024-12-09 20:39:13 +08:00
澄潭
1a8fce48f0 Update release-hgctl.yaml 2024-12-06 14:01:18 +08:00
澄潭
85c7b1f501 rel: Release 2.0.4 (#1571) 2024-12-06 13:52:03 +08:00
pepesi
8f660211e3 feat: ai-proxy support custom error handler by cover util.ErrorHandler (#1537) 2024-12-06 11:47:50 +08:00
rinfx
433227323d extension mechanism for custom logs and span attributes (#1451) 2024-12-05 18:39:00 +08:00
pepesi
b36e5ea26b feat: allow cover api-version when use ai-proxy azure provider (#1535) 2024-12-05 13:41:02 +08:00
rinfx
ce66ff68ce solve aliyun lvwang content length limit problem (#1569) 2024-12-05 13:39:20 +08:00
pepesi
d026f0fca5 feat: ai-proxy support dashscope-finance (#1554) 2024-12-05 11:48:09 +08:00
rinfx
22790aa149 fix moonshot usage compatible problem (#1568) 2024-12-05 11:35:25 +08:00
澄潭
7ce6d7aba1 fix xds cache (#1559) 2024-12-04 00:55:29 +08:00
Se7en
e705a0344f fix: qwen stream issue (#1564) 2024-12-03 13:10:47 +08:00
澄潭
d6094974c2 update ai proxy go mod (#1556) 2024-12-02 14:41:55 +08:00
mamba
6187be97e5 fix: 🐛 frontend-grayurl 解析不正确导致路由失败 (#1550) 2024-11-29 13:09:05 +08:00
澄潭
bb64b43f23 set concurrency argument of proxy by cpu limit/request (#1552) 2024-11-28 16:55:57 +08:00
澄潭
ca7458cf1c Optimize the overall log output (#1549) 2024-11-27 20:44:34 +08:00
Se7en
ee2dd76ae1 feat: migrate baidu provider to v2 api (#1527) 2024-11-27 20:12:00 +08:00
pepesi
8154cf95f1 feat: support custom log (#1521) 2024-11-27 20:11:29 +08:00
澄潭
a7593381e1 fix ai fallback (#1541) 2024-11-25 16:48:59 +08:00
澄潭
e68a8ac25f add model-mapper plugin & optimize model-router plugin (#1538) 2024-11-22 22:24:42 +08:00
Kent Dong
96575b982e fix: Refresh go.mod and go.sum file contents (#1525) 2024-11-22 13:34:55 +08:00
EnableAsync
c2d405b2a7 feat: Enhance ai-cache Plugin with Vector Similarity-Based LLM Cache Recall and Multi-DB Support (#1248) 2024-11-21 16:57:41 +08:00
Jingze
6efb3109f2 fix: update oidc plugin go.mod dependencies (#1522) 2024-11-19 17:33:42 +08:00
Se7en
1b1c08afb7 fix: apitoken failover for coze (#1515) 2024-11-18 15:36:26 +08:00
Se7en
d24123a55f feat: implement apiToken failover mechanism (#1256) 2024-11-16 19:03:09 +08:00
澄潭
f2a5df3949 use the body returned by the ext auth server when auth fails (#1510) 2024-11-14 18:50:33 +08:00
澄潭
ebc5b2987e fix compile of wasm cpp plugins (#1511) 2024-11-14 18:49:21 +08:00
007gzs
ca97cbd75a fix workflows build-and-push-wasm-plugin-image (#1508) 2024-11-13 17:39:24 +08:00
hanans426
a787e237ce 增加快速部署到阿里云的部署方案 (#1506) 2024-11-13 16:26:55 +08:00
纪卓志
6a1bf90d42 feat: supports custom prepare build script (#1490) 2024-11-12 13:45:28 +08:00
007gzs
60e476da87 fix example sse build error (#1503) 2024-11-11 17:47:26 +08:00
rinfx
2cb8558cda Optimize AI security guard plugin (#1473)
Co-authored-by: Kent Dong <ch3cho@qq.com>
2024-11-11 14:49:17 +08:00
littlejian
4d1a037942 feat: Automatically generating markdown documentation for helm charts with helm-docs (#1496) 2024-11-11 11:34:38 +08:00
xingyunyang01
39b6eac9d0 AI Agent plugin adds JSON formatting output feature (#1374) 2024-11-11 11:11:02 +08:00
679 changed files with 80502 additions and 7640 deletions

View File

@@ -42,17 +42,19 @@ jobs:
plugin_type="${{ github.event.inputs.plugin_type }}"
plugin_name="${{ github.event.inputs.plugin_name }}"
version="${{ github.event.inputs.version }}"
builder_image="higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins/wasm-rust-builder:rust${{ env.RUST_VERSION }}-oras${{ env.ORAS_VERSION }}"
else
ref_name=${{ github.ref_name }}
plugin_type=${ref_name#*-} # 删除插件类型前面的字段(wasm-)
plugin_type=${plugin_type%-*} # 删除插件类型后面的字段(-{plugin_name}-vX.Y.Z)
plugin_type=${plugin_type%%-*} # 删除插件类型后面的字段(-{plugin_name}-vX.Y.Z)
plugin_name=${ref_name#*-*-} # 删除插件名前面的字段(wasm-go-)
plugin_name=${plugin_name%-*} # 删除插件名后面的字段(-vX.Y.Z)
version=$(echo "$ref_name" | awk -F'v' '{print $2}')
fi
if [[ "$plugin_type" == "rust" ]]; then
builder_image="higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins/wasm-rust-builder:rust${{ env.RUST_VERSION }}-oras${{ env.ORAS_VERSION }}"
else
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 }}"
fi
echo "PLUGIN_TYPE=$plugin_type" >> $GITHUB_ENV
echo "PLUGIN_NAME=$plugin_name" >> $GITHUB_ENV
echo "VERSION=$version" >> $GITHUB_ENV
@@ -131,8 +133,13 @@ jobs:
command="
set -e
cd /workspace/plugins/wasm-rust/extensions/${PLUGIN_NAME}
cargo build --target wasm32-wasi --release
cp target/wasm32-wasi/release/*.wasm plugin.wasm
if [ -f ./.prebuild ]; then
echo 'Found .prebuild file, sourcing it...'
. ./.prebuild
fi
rustup target add wasm32-wasip1
cargo build --target wasm32-wasip1 --release
cp target/wasm32-wasip1/release/*.wasm plugin.wasm
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}

View File

@@ -6,11 +6,15 @@ on:
paths:
- 'plugins/**'
- 'test/**'
- 'helm/**'
- 'Makefile.core.mk'
pull_request:
branches: [ "*" ]
paths:
- 'plugins/**'
- 'test/**'
- 'helm/**'
- 'Makefile.core.mk'
workflow_dispatch: ~
jobs:
@@ -20,7 +24,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: 1.21.5
go-version: 1.22
# There are too many lint errors in current code bases
# uncomment when we decide what lint should be addressed or ignored.
# - run: make lint
@@ -47,7 +51,7 @@ jobs:
- name: "Setup Go"
uses: actions/setup-go@v5
with:
go-version: 1.21.5
go-version: 1.22
- name: Setup Rust
uses: actions-rs/toolchain@v1

View File

@@ -13,7 +13,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: 1.21.5
go-version: 1.22
# There are too many lint errors in current code bases
# uncomment when we decide what lint should be addressed or ignored.
# - run: make lint
@@ -26,7 +26,7 @@ jobs:
- name: "Setup Go"
uses: actions/setup-go@v5
with:
go-version: 1.21.5
go-version: 1.22
- name: Setup Golang Caches
uses: actions/cache@v4
@@ -64,7 +64,7 @@ jobs:
- name: "Setup Go"
uses: actions/setup-go@v5
with:
go-version: 1.21.5
go-version: 1.22
- name: Setup Golang Caches
uses: actions/cache@v4
@@ -111,7 +111,7 @@ jobs:
- name: "Setup Go"
uses: actions/setup-go@v5
with:
go-version: 1.21.5
go-version: 1.22
- name: Setup Golang Caches
uses: actions/cache@v4

View File

@@ -1,229 +1,258 @@
name: Build Docker Images and Push to Image Registry
on:
push:
tags:
- "v*.*.*"
workflow_dispatch: ~
jobs:
build-controller-image:
runs-on: ubuntu-latest
environment:
name: image-registry-controller
env:
CONTROLLER_IMAGE_REGISTRY: ${{ vars.IMAGE_REGISTRY || 'higress-registry.cn-hangzhou.cr.aliyuncs.com' }}
CONTROLLER_IMAGE_NAME: ${{ vars.CONTROLLER_IMAGE_NAME || 'higress/higress' }}
steps:
- name: "Checkout ${{ github.ref }}"
uses: actions/checkout@v4
with:
fetch-depth: 1
- 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.21.5
- 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: Calculate Docker metadata
id: docker-meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.CONTROLLER_IMAGE_REGISTRY }}/${{ env.CONTROLLER_IMAGE_NAME }}
tags: |
type=sha
type=ref,event=tag
type=semver,pattern={{version}}
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
- name: Login to Docker Registry
uses: docker/login-action@v3
with:
registry: ${{ env.CONTROLLER_IMAGE_REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build Docker Image and Push
run: |
GOPROXY="https://proxy.golang.org,direct" make docker-buildx-push
BUILT_IMAGE="higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/higress"
readarray -t IMAGES <<< "${{ steps.docker-meta.outputs.tags }}"
for image in ${IMAGES[@]}; do
echo "Image: $image"
docker buildx imagetools create $BUILT_IMAGE:$GITHUB_SHA --tag $image
done
build-pilot-image:
runs-on: ubuntu-latest
environment:
name: image-registry-pilot
env:
PILOT_IMAGE_REGISTRY: ${{ vars.IMAGE_REGISTRY || 'higress-registry.cn-hangzhou.cr.aliyuncs.com' }}
PILOT_IMAGE_NAME: ${{ vars.PILOT_IMAGE_NAME || 'higress/pilot' }}
steps:
- name: "Checkout ${{ github.ref }}"
uses: actions/checkout@v4
with:
fetch-depth: 1
- 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.21.5
- 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: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Calculate Docker metadata
id: docker-meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.PILOT_IMAGE_REGISTRY }}/${{ env.PILOT_IMAGE_NAME }}
tags: |
type=sha
type=ref,event=tag
type=semver,pattern={{version}}
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
- name: Login to Docker Registry
uses: docker/login-action@v3
with:
registry: ${{ env.PILOT_IMAGE_REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build Pilot-Discovery Image and Push
run: |
GOPROXY="https://proxy.golang.org,direct" make build-istio
BUILT_IMAGE="higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/pilot"
readarray -t IMAGES <<< "${{ steps.docker-meta.outputs.tags }}"
for image in ${IMAGES[@]}; do
echo "Image: $image"
docker buildx imagetools create $BUILT_IMAGE:$GITHUB_SHA --tag $image
done
build-gateway-image:
runs-on: ubuntu-latest
environment:
name: image-registry-pilot
env:
GATEWAY_IMAGE_REGISTRY: ${{ vars.IMAGE_REGISTRY || 'higress-registry.cn-hangzhou.cr.aliyuncs.com' }}
GATEWAY_IMAGE_NAME: ${{ vars.GATEWAY_IMAGE_NAME || 'higress/gateway' }}
steps:
- name: "Checkout ${{ github.ref }}"
uses: actions/checkout@v4
with:
fetch-depth: 1
- 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.21.5
- 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: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Calculate Docker metadata
id: docker-meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.GATEWAY_IMAGE_REGISTRY }}/${{ env.GATEWAY_IMAGE_NAME }}
tags: |
type=sha
type=ref,event=tag
type=semver,pattern={{version}}
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
- name: Login to Docker Registry
uses: docker/login-action@v3
with:
registry: ${{ env.GATEWAY_IMAGE_REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build Gateway Image and Push
run: |
GOPROXY="https://proxy.golang.org,direct" make build-gateway
BUILT_IMAGE="higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/proxyv2"
readarray -t IMAGES <<< "${{ steps.docker-meta.outputs.tags }}"
for image in ${IMAGES[@]}; do
echo "Image: $image"
docker buildx imagetools create $BUILT_IMAGE:$GITHUB_SHA --tag $image
done
name: Build Docker Images and Push to Image Registry
on:
push:
tags:
- "v*.*.*"
workflow_dispatch: ~
jobs:
build-controller-image:
runs-on: ubuntu-latest
environment:
name: image-registry-controller
env:
CONTROLLER_IMAGE_REGISTRY: ${{ vars.IMAGE_REGISTRY || 'higress-registry.cn-hangzhou.cr.aliyuncs.com' }}
CONTROLLER_IMAGE_NAME: ${{ vars.CONTROLLER_IMAGE_NAME || 'higress/higress' }}
steps:
- name: "Checkout ${{ github.ref }}"
uses: actions/checkout@v4
with:
fetch-depth: 1
- 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.22
- 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: Calculate Docker metadata
id: docker-meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.CONTROLLER_IMAGE_REGISTRY }}/${{ env.CONTROLLER_IMAGE_NAME }}
tags: |
type=sha
type=ref,event=tag
type=semver,pattern={{version}}
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
- name: Login to Docker Registry
uses: docker/login-action@v3
with:
registry: ${{ env.CONTROLLER_IMAGE_REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build Docker Image and Push
run: |
BUILT_IMAGE=""
readarray -t IMAGES <<< "${{ steps.docker-meta.outputs.tags }}"
for image in ${IMAGES[@]}; do
echo "Image: $image"
if [ "$BUILT_IMAGE" == "" ]; then
GOPROXY="https://proxy.golang.org,direct" IMG_URL="$image" make docker-buildx-push
BUILT_IMAGE="$image"
else
docker buildx imagetools create $BUILT_IMAGE --tag $image
fi
done
build-pilot-image:
runs-on: ubuntu-latest
environment:
name: image-registry-pilot
env:
PILOT_IMAGE_REGISTRY: ${{ vars.IMAGE_REGISTRY || 'higress-registry.cn-hangzhou.cr.aliyuncs.com' }}
PILOT_IMAGE_NAME: ${{ vars.PILOT_IMAGE_NAME || 'higress/pilot' }}
steps:
- name: "Checkout ${{ github.ref }}"
uses: actions/checkout@v4
with:
fetch-depth: 1
- 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.22
- 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: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
image: tonistiigi/binfmt:qemu-v7.0.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Cache Docker layers
uses: actions/cache@v4
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Calculate Docker metadata
id: docker-meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.PILOT_IMAGE_REGISTRY }}/${{ env.PILOT_IMAGE_NAME }}
tags: |
type=sha
type=ref,event=tag
type=semver,pattern={{version}}
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
- name: Login to Docker Registry
uses: docker/login-action@v3
with:
registry: ${{ env.PILOT_IMAGE_REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build Pilot-Discovery Image and Push
run: |
BUILT_IMAGE=""
readarray -t IMAGES <<< "${{ steps.docker-meta.outputs.tags }}"
for image in ${IMAGES[@]}; do
echo "Image: $image"
if [ "$BUILT_IMAGE" == "" ]; then
TAG=${image#*:}
HUB=${image%:*}
HUB=${HUB%/*}
BUILT_IMAGE="$HUB/pilot:$TAG"
GOPROXY="https://proxy.golang.org,direct" IMG_URL="$BUILT_IMAGE" make build-istio
fi
if [ "$BUILT_IMAGE" != "$image" ]; then
docker buildx imagetools create $BUILT_IMAGE --tag $image
fi
done
build-gateway-image:
runs-on: ubuntu-latest
environment:
name: image-registry-gateway
env:
GATEWAY_IMAGE_REGISTRY: ${{ vars.IMAGE_REGISTRY || 'higress-registry.cn-hangzhou.cr.aliyuncs.com' }}
GATEWAY_IMAGE_NAME: ${{ vars.GATEWAY_IMAGE_NAME || 'higress/gateway' }}
steps:
- name: "Checkout ${{ github.ref }}"
uses: actions/checkout@v4
with:
fetch-depth: 1
- 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.22
- 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: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
image: tonistiigi/binfmt:qemu-v7.0.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Cache Docker layers
uses: actions/cache@v4
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Calculate Docker metadata
id: docker-meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.GATEWAY_IMAGE_REGISTRY }}/${{ env.GATEWAY_IMAGE_NAME }}
tags: |
type=sha
type=ref,event=tag
type=semver,pattern={{version}}
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
- name: Login to Docker Registry
uses: docker/login-action@v3
with:
registry: ${{ env.GATEWAY_IMAGE_REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build Gateway Image and Push
run: |
BUILT_IMAGE=""
readarray -t IMAGES <<< "${{ steps.docker-meta.outputs.tags }}"
for image in ${IMAGES[@]}; do
echo "Image: $image"
if [ "$BUILT_IMAGE" == "" ]; then
TAG=${image#*:}
HUB=${image%:*}
HUB=${HUB%/*}
BUILT_IMAGE="$HUB/proxyv2:$TAG"
GOPROXY="https://proxy.golang.org,direct" IMG_URL="$BUILT_IMAGE" make build-gateway
fi
if [ "$BUILT_IMAGE" != "$image" ]; then
docker buildx imagetools create $BUILT_IMAGE --tag $image
fi
done

View File

@@ -20,11 +20,11 @@ jobs:
name: Prepare Standalone Package
run: |
mkdir ./artifact
cp ./tools/get-higress.sh ./artifact
LOCAL_RELEASE_URL="https://github.com/higress-group/higress-standalone/releases"
VERSION=$(curl -Ls $LOCAL_RELEASE_URL | grep 'href="/higress-group/higress-standalone/releases/tag/v[0-9]*.[0-9]*.[0-9]*\"' | sed -E 's/.*\/higress-group\/higress-standalone\/releases\/tag\/(v[0-9\.]+)".*/\1/g' | head -1)
DOWNLOAD_URL="https://github.com/higress-group/higress-standalone/archive/refs/tags/${VERSION}.tar.gz"
curl -SsL "$DOWNLOAD_URL" -o "./artifact/higress-${VERSION}.tar.gz"
curl -SsL "https://raw.githubusercontent.com/higress-group/higress-standalone/refs/heads/main/src/get-higress.sh" -o "./artifact/get-higress.sh"
echo -n "$VERSION" > ./artifact/VERSION
echo "Version=$VERSION"
# Step 3

View File

@@ -19,7 +19,7 @@ jobs:
- name: Download Helm Charts Index
uses: doggycool/ossutil-github-action@master
with:
ossArgs: 'cp -r -u oss://higress-website-cn-hongkong/helm-charts/index.yaml ./artifact/'
ossArgs: 'cp oss://higress-website-cn-hongkong/helm-charts/index.yaml ./artifact/'
accessKey: ${{ secrets.ACCESS_KEYID }}
accessSecret: ${{ secrets.ACCESS_KEYSECRET }}
endpoint: oss-cn-hongkong.aliyuncs.com

164
.github/workflows/helm-docs.yaml vendored Normal file
View File

@@ -0,0 +1,164 @@
name: "Helm Docs"
on:
pull_request:
branches:
- "*"
paths:
- 'helm/**'
- '!helm/higress/README.zh.md'
workflow_dispatch: ~
push:
branches: [ main ]
paths:
- 'helm/**'
- '!helm/higress/README.zh.md'
jobs:
helm:
name: Helm Docs
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.22.9'
- name: Run helm-docs
run: |
GOBIN=$PWD GO111MODULE=on go install github.com/norwoodj/helm-docs/cmd/helm-docs@v1.14.2
./helm-docs -c ${GITHUB_WORKSPACE}/helm/higress -f ../core/values.yaml
DIFF=$(git diff ${GITHUB_WORKSPACE}/helm/higress/README.md)
if [ ! -z "$DIFF" ]; then
echo "Please use helm-docs in your clone, of your fork, of the project, and commit a updated README.md for the chart."
fi
git diff --exit-code
rm -f ./helm-docs
translate-readme:
needs: helm
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y jq
- name: Compare README.md
id: compare_readme
run: |
cd ./helm/higress
BASE_BRANCH=${GITHUB_BASE_REF:-main}
git fetch origin $BASE_BRANCH
if git diff --quiet origin/$BASE_BRANCH -- README.md; then
echo "README.md has no local changes compared to $BASE_BRANCH. Skipping translation."
echo "skip_translation=true" >> $GITHUB_ENV
else
echo "README.md has local changes compared to $BASE_BRANCH. Proceeding with translation."
echo "skip_translation=false" >> $GITHUB_ENV
echo "--------- diff ---------"
git diff origin/$BASE_BRANCH -- README.md
echo "------------------------"
fi
- name: Translate README.md to Chinese
if: env.skip_translation == 'false'
env:
API_URL: ${{ secrets.HIGRESS_OPENAI_API_URL }}
API_KEY: ${{ secrets.HIGRESS_OPENAI_API_KEY }}
API_MODEL: ${{ secrets.HIGRESS_OPENAI_API_MODEL }}
run: |
cat << 'EOF' > translate_readme.py
import os
import json
import requests
API_URL = os.environ["API_URL"]
API_KEY = os.environ["API_KEY"]
API_MODEL = os.environ["API_MODEL"]
README_PATH = "./helm/higress/README.md"
OUTPUT_PATH = "./helm/higress/README.zh.md"
def stream_translation(api_url, api_key, payload):
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}",
}
response = requests.post(api_url, headers=headers, json=payload, stream=True)
response.raise_for_status()
with open(OUTPUT_PATH, "w", encoding="utf-8") as out_file:
for line in response.iter_lines(decode_unicode=True):
if line.strip() == "" or not line.startswith("data: "):
continue
data = line[6:]
if data.strip() == "[DONE]":
break
try:
chunk = json.loads(data)
content = chunk["choices"][0]["delta"].get("content", "")
if content:
out_file.write(content)
except Exception as e:
print("Error parsing chunk:", e)
def main():
if not os.path.exists(README_PATH):
print("README.md not found!")
return
with open(README_PATH, "r", encoding="utf-8") as f:
content = f.read()
payload = {
"model": API_MODEL,
"messages": [
{
"role": "system",
"content": "You are a translation assistant that translates English Markdown text to Chinese. Preserve original Markdown formatting and line breaks."
},
{
"role": "user",
"content": content
}
],
"temperature": 0.3,
"stream": True
}
print("Streaming translation started...")
stream_translation(API_URL, API_KEY, payload)
print(f"Translation completed and saved to {OUTPUT_PATH}.")
if __name__ == "__main__":
main()
EOF
python3 translate_readme.py
rm -rf translate_readme.py
- name: Create Pull Request
if: env.skip_translation == 'false'
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "Update helm translated README.zh.md"
branch: update-helm-readme-zh
title: "Update helm translated README.zh.md"
body: |
This PR updates the translated README.zh.md file.
- Automatically generated by GitHub Actions
labels: translation, automated
base: main

View File

@@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: 1.21.5
go-version: 1.22
- name: Build hgctl latest multiarch binaries
run: |
@@ -43,7 +43,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: 1.21.5
go-version: 1.22
- name: Build hgctl latest macos binaries
run: |
@@ -58,14 +58,14 @@ jobs:
hgctl_${{ env.HGCTL_VERSION }}_darwin_arm64.tar.gz
release-hgctl-macos-amd64:
runs-on: macos-12
runs-on: macos-14
env:
HGCTL_VERSION: ${{github.ref_name}}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: 1.21.5
go-version: 1.22
- name: Build hgctl latest macos binaries
run: |

29
.github/workflows/translate-test.yml vendored Normal file
View File

@@ -0,0 +1,29 @@
name: 'Translate GitHub content into English'
on:
issues:
types: [opened, edited]
issue_comment:
types: [created, edited]
discussion:
types: [created, edited]
discussion_comment:
types: [created, edited]
pull_request_target:
types: [opened, edited]
pull_request_review_comment:
types: [created, edited]
jobs:
translate:
permissions:
issues: write
discussions: write
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: lizheming/github-translate-action@main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
APPEND_TRANSLATION: true

2
.gitignore vendored
View File

@@ -16,4 +16,4 @@ helm/**/charts/**.tgz
target/
tools/hack/cluster.conf
envoy/1.20
istio/1.12
istio/1.12

View File

@@ -12,6 +12,7 @@ header:
- 'LICENSE'
- 'api/**'
- 'samples/**'
- 'docs/**'
- '.github/**'
- '.licenserc.yaml'
- 'helm/**'

View File

@@ -2,7 +2,8 @@
/envoy @gengleilei @johnlanni
/istio @SpecialYang @johnlanni
/pkg @SpecialYang @johnlanni @CH3CHO
/plugins @johnlanni @WeixinX @CH3CHO
/plugins @johnlanni @CH3CHO @rinfx
/plugins/wasm-go/extensions/ai-proxy @cr7258 @CH3CHO @rinfx
/plugins/wasm-rust @007gzs @jizhuozhi
/registry @NameHaibinZhang @2456868764 @johnlanni
/test @Xunzhuo @2456868764 @CH3CHO

View File

@@ -144,7 +144,7 @@ docker-buildx-push: clean-env docker.higress-buildx
export PARENT_GIT_TAG:=$(shell cat VERSION)
export PARENT_GIT_REVISION:=$(TAG)
export ENVOY_PACKAGE_URL_PATTERN?=https://github.com/higress-group/proxy/releases/download/v2.0.0/envoy-symbol-ARCH.tar.gz
export ENVOY_PACKAGE_URL_PATTERN?=https://github.com/higress-group/proxy/releases/download/v2.1.5/envoy-symbol-ARCH.tar.gz
build-envoy: prebuild
./tools/hack/build-envoy.sh
@@ -159,16 +159,20 @@ build-pilot-local: prebuild
buildx-prepare:
docker buildx inspect multi-arch >/dev/null 2>&1 || docker buildx create --name multi-arch --platform linux/amd64,linux/arm64 --use
build-gateway: prebuild buildx-prepare
build-gateway: prebuild buildx-prepare build-golang-filter
USE_REAL_USER=1 TARGET_ARCH=amd64 DOCKER_TARGETS="docker.proxyv2" ./tools/hack/build-istio-image.sh init
USE_REAL_USER=1 TARGET_ARCH=arm64 DOCKER_TARGETS="docker.proxyv2" ./tools/hack/build-istio-image.sh init
DOCKER_TARGETS="docker.proxyv2" ./tools/hack/build-istio-image.sh docker.buildx
DOCKER_TARGETS="docker.proxyv2" IMG_URL="${IMG_URL}" ./tools/hack/build-istio-image.sh docker.buildx
build-gateway-local: prebuild
build-gateway-local: prebuild build-golang-filter
TARGET_ARCH=${TARGET_ARCH} DOCKER_TARGETS="docker.proxyv2" ./tools/hack/build-istio-image.sh docker
build-golang-filter:
TARGET_ARCH=amd64 ./tools/hack/build-golang-filters.sh
TARGET_ARCH=arm64 ./tools/hack/build-golang-filters.sh
build-istio: prebuild buildx-prepare
DOCKER_TARGETS="docker.pilot" ./tools/hack/build-istio-image.sh docker.buildx
DOCKER_TARGETS="docker.pilot" IMG_URL="${IMG_URL}" ./tools/hack/build-istio-image.sh docker.buildx
build-istio-local: prebuild
TARGET_ARCH=${TARGET_ARCH} DOCKER_TARGETS="docker.pilot" ./tools/hack/build-istio-image.sh docker
@@ -187,8 +191,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 ?= 2.0.1
ISTIO_LATEST_IMAGE_TAG ?= 2.0.1
ENVOY_LATEST_IMAGE_TAG ?= 958467a353d411ae3f06e03b096bfd342cddb2c6
ISTIO_LATEST_IMAGE_TAG ?= d9c728d3b01f64855e012b08d136e306f1160397
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'
@@ -231,6 +235,7 @@ clean-gateway: clean-istio
rm -rf external/proxy
rm -rf external/go-control-plane
rm -rf external/package/envoy.tar.gz
rm -rf external/package/*.so
clean-env:
rm -rf out/
@@ -299,7 +304,7 @@ kube-load-image: $(tools/kind) ## Install the Higress image to a kind cluster us
tools/hack/docker-pull-image.sh higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/echo-server 1.3.0
tools/hack/docker-pull-image.sh higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/echo-server v1.0
tools/hack/docker-pull-image.sh higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/echo-body 1.0.0
tools/hack/docker-pull-image.sh openpolicyagent/opa latest
tools/hack/docker-pull-image.sh openpolicyagent/opa 0.61.0
tools/hack/docker-pull-image.sh curlimages/curl latest
tools/hack/docker-pull-image.sh registry.cn-hangzhou.aliyuncs.com/2456868764/httpbin 1.0.2
tools/hack/docker-pull-image.sh registry.cn-hangzhou.aliyuncs.com/hinsteny/nacos-standlone-rc3 1.0.0-RC3
@@ -312,7 +317,7 @@ kube-load-image: $(tools/kind) ## Install the Higress image to a kind cluster us
tools/hack/kind-load-image.sh higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/echo-server 1.3.0
tools/hack/kind-load-image.sh higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/echo-server v1.0
tools/hack/kind-load-image.sh higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/echo-body 1.0.0
tools/hack/kind-load-image.sh openpolicyagent/opa latest
tools/hack/kind-load-image.sh openpolicyagent/opa 0.61.0
tools/hack/kind-load-image.sh curlimages/curl latest
tools/hack/kind-load-image.sh registry.cn-hangzhou.aliyuncs.com/2456868764/httpbin 1.0.2
tools/hack/kind-load-image.sh registry.cn-hangzhou.aliyuncs.com/hinsteny/nacos-standlone-rc3 1.0.0-RC3

214
README.md
View File

@@ -6,190 +6,156 @@
</h1>
<h4 align="center"> AI Native API Gateway </h4>
<div align="center">
[![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)
[![discord](https://img.shields.io/discord/1364956090566971515?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square)](https://discord.gg/reymxYM5)
[**官网**](https://higress.cn/) &nbsp; |
&nbsp; [**文档**](https://higress.cn/docs/latest/overview/what-is-higress/) &nbsp; |
&nbsp; [**博客**](https://higress.cn/blog/) &nbsp; |
&nbsp; [**电子书**](https://higress.cn/docs/ebook/wasm14/) &nbsp; |
&nbsp; [**开发指引**](https://higress.cn/docs/latest/dev/architecture/) &nbsp; |
&nbsp; [**AI插件**](https://higress.cn/plugin/) &nbsp;
<a href="https://trendshift.io/repositories/10918" target="_blank"><img src="https://trendshift.io/api/badge/repositories/10918" alt="alibaba%2Fhigress | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a> <a href="https://www.producthunt.com/posts/higress?embed=true&utm_source=badge-featured&utm_medium=badge&utm_souce=badge-higress" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=951287&theme=light&t=1745492822283" alt="Higress - Global&#0032;APIs&#0032;as&#0032;MCP&#0032;powered&#0032;by&#0032;AI&#0032;Gateway | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
</div>
[**Official Site**](https://higress.ai/en/) &nbsp; |
&nbsp; [**MCP Server QuickStart**](https://higress.cn/en/ai/mcp-quick-start/) &nbsp; |
&nbsp; [**Wasm Plugin Hub**](https://higress.cn/en/plugin/) &nbsp; |
<p>
<a href="README_EN.md"> English <a/>| 中文 | <a href="README_JP.md"> 日本語 <a/>
English | <a href="README_ZH.md">中文<a/> | <a href="README_JP.md">日本語<a/>
</p>
## Test What is Higress?
Higress 是一款云原生 API 网关,内核基于 Istio Envoy,可以用 Go/Rust/JS 等编写 Wasm 插件提供了数十个现成的通用插件以及开箱即用的控制台demo 点[这里](http://demo.higress.io/)
Higress is a cloud-native API gateway based on Istio and Envoy, which can be extended with Wasm plugins written in Go/Rust/JS. It provides dozens of ready-to-use general-purpose plugins and an out-of-the-box console (try the [demo here](http://demo.higress.io/)).
Higress 在阿里内部为解决 Tengine reload 对长连接业务有损,以及 gRPC/Dubbo 负载均衡能力不足而诞生。
### Core Use Cases
阿里云基于 Higress 构建了云原生 API 网关产品,为大量企业客户提供 99.99% 的网关高可用保障服务能力。
Higress's AI gateway capabilities support all [mainstream model providers](https://github.com/alibaba/higress/tree/main/plugins/wasm-go/extensions/ai-proxy/provider) both domestic and international. It also supports hosting MCP (Model Context Protocol) Servers through its plugin mechanism, enabling AI Agents to easily call various tools and services. With the [openapi-to-mcp tool](https://github.com/higress-group/openapi-to-mcpserver), you can quickly convert OpenAPI specifications into remote MCP servers for hosting. Higress provides unified management for both LLM API and MCP API.
Higress 基于 AI 网关能力,支撑了通义千问 APP、百炼大模型 API、机器学习 PAI 平台等 AI 业务。同时服务国内头部的 AIGC 企业(如零一万物),以及 AI 产品(如 FastGPT
**🌟 Try it now at [https://mcp.higress.ai/](https://mcp.higress.ai/)** to experience Higress-hosted Remote MCP Servers firsthand:
![](https://img.alicdn.com/imgextra/i2/O1CN011AbR8023V8R5N0HcA_!!6000000007260-2-tps-1080-606.png)
![Higress MCP Server Platform](https://img.alicdn.com/imgextra/i2/O1CN01nmVa0a1aChgpyyWOX_!!6000000003294-0-tps-3430-1742.jpg)
### Enterprise Adoption
Higress was born within Alibaba to solve the issues of Tengine reload affecting long-connection services and insufficient load balancing capabilities for gRPC/Dubbo. Within Alibaba Cloud, Higress's AI gateway capabilities support core AI applications such as Tongyi Bailian model studio, machine learning PAI platform, and other critical AI services. Alibaba Cloud has built its cloud-native API gateway product based on Higress, providing 99.99% gateway high availability guarantee service capabilities for a large number of enterprise customers.
## Summary
- [**快速开始**](#快速开始)
- [**功能展示**](#功能展示)
- [**使用场景**](#使用场景)
- [**核心优势**](#核心优势)
- [**社区**](#社区)
- [**Quick Start**](#quick-start)
- [**Feature Showcase**](#feature-showcase)
- [**Use Cases**](#use-cases)
- [**Core Advantages**](#core-advantages)
- [**Community**](#community)
## 快速开始
## Quick Start
Higress 只需 Docker 即可启动,方便个人开发者在本地搭建学习,或者用于搭建简易站点:
Higress can be started with just Docker, making it convenient for individual developers to set up locally for learning or for building simple sites:
```bash
# 创建一个工作目录
# Create a working directory
mkdir higress; cd higress
# 启动 higress,配置文件会写到工作目录下
# Start higress, configuration files will be written to the working directory
docker run -d --rm --name higress-ai -v ${PWD}:/data \
-p 8001:8001 -p 8080:8080 -p 8443:8443 \
higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/all-in-one:latest
```
监听端口说明如下:
Port descriptions:
- 8001 端口Higress UI 控制台入口
- 8080 端口:网关 HTTP 协议入口
- 8443 端口:网关 HTTPS 协议入口
- Port 8001: Higress UI console entry
- Port 8080: Gateway HTTP protocol entry
- Port 8443: Gateway HTTPS protocol entry
**Higress 的所有 Docker 镜像都一直使用自己独享的仓库,不受 Docker Hub 境内访问受限的影响**
> All Higress Docker images use Higress's own image repository and are not affected by Docker Hub rate limits.
> In addition, the submission and updates of the images are protected by a security scanning mechanism (powered by Alibaba Cloud ACR), making them very secure for use in production environments.
K8s 下使用 Helm 部署等其他安装方式可以参考官网 [Quick Start 文档](https://higress.cn/docs/latest/user/quickstart/)
For other installation methods such as Helm deployment under K8s, please refer to the official [Quick Start documentation](https://higress.io/en-us/docs/user/quickstart).
## Use Cases
## 使用场景
- **MCP Server Hosting**:
- **AI 网关**:
Higress hosts MCP Servers through its plugin mechanism, enabling AI Agents to easily call various tools and services. With the [openapi-to-mcp tool](https://github.com/higress-group/openapi-to-mcpserver), you can quickly convert OpenAPI specifications into remote MCP servers.
Higress 能够用统一的协议对接国内外所有 LLM 模型厂商,同时具备丰富的 AI 可观测、多模型负载均衡/fallback、AI token 流控、AI 缓存等能力:
![](https://img.alicdn.com/imgextra/i1/O1CN01wv8H4g1mS4MUzC1QC_!!6000000004952-2-tps-1764-597.png)
![](https://img.alicdn.com/imgextra/i1/O1CN01fNnhCp1cV8mYPRFeS_!!6000000003605-0-tps-1080-608.jpg)
Key benefits of hosting MCP Servers with Higress:
- Unified authentication and authorization mechanisms
- Fine-grained rate limiting to prevent abuse
- Comprehensive audit logs for all tool calls
- Rich observability for monitoring performance
- Simplified deployment through Higress's plugin mechanism
- Dynamic updates without disruption or connection drops
- **Kubernetes Ingress 网关**:
[Learn more...](https://higress.cn/en/ai/mcp-quick-start/?spm=36971b57.7beea2de.0.0.d85f20a94jsWGm)
Higress 可以作为 K8s 集群的 Ingress 入口网关, 并且兼容了大量 K8s Nginx Ingress 的注解,可以从 K8s Nginx Ingress 快速平滑迁移到 Higress。
- **AI Gateway**:
Higress connects to all LLM model providers using a unified protocol, with AI observability, multi-model load balancing, token rate limiting, and caching capabilities:
![](https://img.alicdn.com/imgextra/i2/O1CN01izmBNX1jbHT7lP3Yr_!!6000000004566-0-tps-1920-1080.jpg)
- **Kubernetes ingress controller**:
Higress can function as a feature-rich ingress controller, which is compatible with many annotations of K8s' nginx ingress controller.
支持 [Gateway API](https://gateway-api.sigs.k8s.io/) 标准,支持用户从 Ingress API 平滑迁移到 Gateway API
相比 ingress-nginx资源开销大幅下降路由变更生效速度有十倍提升
![](https://img.alicdn.com/imgextra/i1/O1CN01bhEtb229eeMNBWmdP_!!6000000008093-2-tps-750-547.png)
![](https://img.alicdn.com/imgextra/i1/O1CN01bqRets1LsBGyitj4S_!!6000000001354-2-tps-887-489.png)
[Gateway API](https://gateway-api.sigs.k8s.io/) support is coming soon and will support smooth migration from Ingress API to Gateway API.
- **微服务网关**:
- **Microservice gateway**:
Higress 可以作为微服务网关, 能够对接多种类型的注册中心发现服务配置路由,例如 Nacos, ZooKeeper, Consul, Eureka 等。
Higress can function as a microservice gateway, which can discovery microservices from various service registries, such as Nacos, ZooKeeper, Consul, Eureka, etc.
并且深度集成了 [Dubbo](https://github.com/apache/dubbo), [Nacos](https://github.com/alibaba/nacos), [Sentinel](https://github.com/alibaba/Sentinel) 等微服务技术栈,基于 Envoy C++ 网关内核的出色性能,相比传统 Java 类微服务网关,可以显著降低资源使用率,减少成本。
![](https://img.alicdn.com/imgextra/i4/O1CN01v4ZbCj1dBjePSMZ17_!!6000000003698-0-tps-1613-926.jpg)
It deeply integrates with [Dubbo](https://github.com/apache/dubbo), [Nacos](https://github.com/alibaba/nacos), [Sentinel](https://github.com/alibaba/Sentinel) and other microservice technology stacks.
- **安全防护网关**:
- **Security gateway**:
Higress 可以作为安全防护网关, 提供 WAF 的能力,并且支持多种认证鉴权策略,例如 key-auth, hmac-auth, jwt-auth, basic-auth, oidc 等。
Higress can be used as a security gateway, supporting WAF and various authentication strategies, such as key-auth, hmac-auth, jwt-auth, basic-auth, oidc, etc.
## 核心优势
- **生产等级**
## Core Advantages
脱胎于阿里巴巴2年多生产验证的内部产品支持每秒请求量达数十万级的大规模场景。
- **Production Grade**
彻底摆脱 Nginx reload 引起的流量抖动,配置变更毫秒级生效且业务无感。对 AI 业务等长连接场景特别友好。
Born from Alibaba's internal product with over 2 years of production validation, supporting large-scale scenarios with hundreds of thousands of requests per second.
- **流式处理**
Completely eliminates traffic jitter caused by Nginx reload, configuration changes take effect in milliseconds and are transparent to business. Especially friendly to long-connection scenarios such as AI businesses.
支持真正的完全流式处理请求/响应 BodyWasm 插件很方便地自定义处理 SSE Server-Sent Events等流式协议的报文。
- **Streaming Processing**
在 AI 业务等大带宽场景下,可以显著降低内存开销。
Supports true complete streaming processing of request/response bodies, Wasm plugins can easily customize the handling of streaming protocols such as SSE (Server-Sent Events).
In high-bandwidth scenarios such as AI businesses, it can significantly reduce memory overhead.
- **便于扩展**
- **Easy to Extend**
提供丰富的官方插件库,涵盖 AI、流量管理、安全防护等常用功能满足90%以上的业务场景需求。
Provides a rich official plugin library covering AI, traffic management, security protection and other common functions, meeting more than 90% of business scenario requirements.
主打 Wasm 插件扩展,通过沙箱隔离确保内存安全,支持多种编程语言,允许插件版本独立升级,实现流量无损热更新网关逻辑。
Focuses on Wasm plugin extensions, ensuring memory safety through sandbox isolation, supporting multiple programming languages, allowing plugin versions to be upgraded independently, and achieving traffic-lossless hot updates of gateway logic.
- **安全易用**
- **Secure and Easy to Use**
基于 Ingress API Gateway API 标准,提供开箱即用的 UI 控制台WAF 防护插件、IP/Cookie CC 防护插件开箱即用。
Based on Ingress API and Gateway API standards, provides out-of-the-box UI console, WAF protection plugin, IP/Cookie CC protection plugin ready to use.
支持对接 Let's Encrypt 自动签发和续签免费证书,并且可以脱离 K8s 部署,一行 Docker 命令即可启动,方便个人开发者使用。
Supports connecting to Let's Encrypt for automatic issuance and renewal of free certificates, and can be deployed outside of K8s, started with a single Docker command, convenient for individual developers to use.
## Community
Join our Discord community! This is where you can connect with developers and other enthusiastic users of Higress.
[![discord](https://img.shields.io/discord/1364956090566971515?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=for-the-badge)](https://discord.gg/reymxYM5)
## 功能展示
### Thanks
### AI 网关 Demo 展示
Higress would not be possible without the valuable open-source work of projects in the community. We would like to extend a special thank you to Envoy and Istio.
[从 OpenAI 到其他大模型30 秒完成迁移
](https://www.bilibili.com/video/BV1dT421a7w7/?spm_id_from=333.788.recommend_more_video.14)
### Related Repositories
- Higress Console: https://github.com/higress-group/higress-console
- Higress Standalone: https://github.com/higress-group/higress-standalone
### Higress UI 控制台
- **丰富的可观测**
提供开箱即用的可观测Grafana&Prometheus 可以使用内置的也可对接自建的
![](./docs/images/monitor.gif)
- **插件扩展机制**
官方提供了多种插件,用户也可以[开发](./plugins/wasm-go)自己的插件,构建成 docker/oci 镜像后在控制台配置,可以实时变更插件逻辑,对流量完全无损。
![](./docs/images/plugin.gif)
- **多种服务发现**
默认提供 K8s Service 服务发现,通过配置可以对接 Nacos/ZooKeeper 等注册中心实现服务发现,也可以基于静态 IP 或者 DNS 来发现
![](./docs/images/service-source.gif)
- **域名和证书**
可以创建管理 TLS 证书,并配置域名的 HTTP/HTTPS 行为,域名策略里支持对特定域名生效插件
![](./docs/images/domain.gif)
- **丰富的路由能力**
通过上面定义的服务发现机制,发现的服务会出现在服务列表中;创建路由时,选择域名,定义路由匹配机制,再选择目标服务进行路由;路由策略里支持对特定路由生效插件
![](./docs/images/route-service.gif)
## 社区
### 感谢
如果没有 Envoy 和 Istio 的开源工作Higress 就不可能实现,在这里向这两个项目献上最诚挚的敬意。
### 交流群
![image](https://img.alicdn.com/imgextra/i2/O1CN01BkopaB22ZsvamFftE_!!6000000007135-0-tps-720-405.jpg)
### 技术分享
微信公众号:
![](https://img.alicdn.com/imgextra/i1/O1CN01WnQt0q1tcmqVDU73u_!!6000000005923-0-tps-258-258.jpg)
### 关联仓库
- Higress 控制台https://github.com/higress-group/higress-console
- Higress独立运行版https://github.com/higress-group/higress-standalone
### 贡献者
### Contributors
<a href="https://github.com/alibaba/higress/graphs/contributors">
<img alt="contributors" src="https://contrib.rocks/image?repo=alibaba/higress"/>
@@ -197,10 +163,10 @@ K8s 下使用 Helm 部署等其他安装方式可以参考官网 [Quick Start
### Star History
[![Star History](https://api.star-history.com/svg?repos=alibaba/higress&type=Date)](https://star-history.com/#alibaba/higress&Date)
[![Star History Chart](https://api.star-history.com/svg?repos=alibaba/higress&type=Date)](https://star-history.com/#alibaba/higress&Date)
<p align="right" style="font-size: 14px; color: #555; margin-top: 20px;">
<a href="#readme-top" style="text-decoration: none; color: #007bff; font-weight: bold;">
返回顶部
Back to Top
</a>
</p>

View File

@@ -1,106 +0,0 @@
<a name="readme-top"></a>
<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>
Cloud Native API Gateway
</h1>
[![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; |
&nbsp; [**Docs**](https://higress.io/en-us/docs/overview/what-is-higress) &nbsp; |
&nbsp; [**Blog**](https://higress.io/en-us/blog) &nbsp; |
&nbsp; [**Developer**](https://higress.io/en-us/docs/developers/developers_dev) &nbsp; |
&nbsp; [**Higress in Cloud**](https://www.alibabacloud.com/product/microservices-engine?spm=higress-website.topbar.0.0.0) &nbsp;
<p>
English | <a href="README.md">中文<a/> | <a href="README_JP.md">日本語<a/>
</p>
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.
<h1 align="center">
<img src="https://img.alicdn.com/imgextra/i1/O1CN01iO9ph825juHbOIg75_!!6000000007563-2-tps-2483-2024.png" alt="Higress Architecture">
</h1>
## Summary
- [**Use Cases**](#use-cases)
- [**Higress Features**](#higress-features)
- [**Quick Start**](https://higress.io/en-us/docs/user/quickstart)
- [**Community**](#community)
- [**Thanks**](#thanks)
## Use Cases
- **Kubernetes ingress controller**:
Higress can function as a feature-rich ingress controller, which is compatible with many annotations of K8s' nginx ingress controller.
[Gateway API](https://gateway-api.sigs.k8s.io/) support is coming soon and will support smooth migration from Ingress API to Gateway API.
- **Microservice gateway**:
Higress can function as a microservice gateway, which can discovery microservices from various service registries, such as Nacos, ZooKeeper, Consul, Eureka, etc.
It deeply integrates with [Dubbo](https://github.com/apache/dubbo), [Nacos](https://github.com/alibaba/nacos), [Sentinel](https://github.com/alibaba/Sentinel) and other microservice technology stacks.
- **Security gateway**:
Higress can be used as a security gateway, supporting WAF and various authentication strategies, such as key-auth, hmac-auth, jwt-auth, basic-auth, oidc, etc.
## Higress Features
- **Easy to use**
Provides one-stop gateway solutions for traffic scheduling, service management, and security protection, support Console, K8s Ingress, and Gateway API configuration methods, and also support HTTP to Dubbo protocol conversion, and easily complete protocol mapping configuration.
- **Easy to expand**
Provides Wasm, Lua, and out-of-process plug-in extension mechanisms, so that multi-language plug-in writing is no longer an obstacle. The granularity of plug-in effectiveness supports not only the global level, domain name level, but also fine-grained routing level
- **Dynamic hot update**
Get rid of the traffic jitter caused by reload at the bottom, the configuration change takes effect in milliseconds and the business is not affected, the Wasm plug-in is hot updated and the traffic is not damaged
- **Smooth upgrade**
Compatible with 80%+ usage scenarios of Nginx Ingress Annotation, and provides more feature-rich annotations, easy to handle Nginx Ingress migration in one step
- **Security**
Provides JWT, OIDC, custom authentication and authentication, deeply integrates open-source web application firewall.
## Community
[Slack](https://w1689142780-euk177225.slack.com/archives/C05GEL4TGTG): to get invited go [here](https://communityinviter.com/apps/w1689142780-euk177225/higress).
### Thanks
Higress would not be possible without the valuable open-source work of projects in the community. We would like to extend a special thank you to Envoy and Istio.
### Related Repositories
- Higress Console: https://github.com/higress-group/higress-console
- Higress Standalone: https://github.com/higress-group/higress-standalone
### Contributors
<a href="https://github.com/alibaba/higress/graphs/contributors">
<img alt="contributors" src="https://contrib.rocks/image?repo=alibaba/higress"/>
</a>
### Star History
[![Star History Chart](https://api.star-history.com/svg?repos=alibaba/higress&type=Date)](https://star-history.com/#alibaba/higress&Date)
<p align="right" style="font-size: 14px; color: #555; margin-top: 20px;">
<a href="#readme-top" style="text-decoration: none; color: #007bff; font-weight: bold;">
↑ Back to Top ↑
</a>
</p>

View File

@@ -22,15 +22,21 @@
</p>
## Higressとは
Higressは、IstioとEnvoyをベースにしたクラウドネイティブAPIゲートウェイで、Go/Rust/JSなどを使用してWasmプラグインを作成できます。数十の既製の汎用プラグインと、すぐに使用できるコンソールを提供していますデモは[こちら](http://demo.higress.io/))。
Higressは、Tengineのリロードが長時間接続のビジネスに影響を与える問題や、gRPC/Dubboの負荷分散能力の不足を解決するために、Alibaba内部で誕生しました。
### 主な使用シナリオ
Alibaba Cloudは、Higressを基盤にクラウドネイティブAPIゲートウェイ製品を構築し、多くの企業顧客に99.99%のゲートウェイ高可用性保証サービスを提供しています。
HigressのAIゲートウェイ機能は、国内外のすべての[主要モデルプロバイダー](https://github.com/alibaba/higress/tree/main/plugins/wasm-go/extensions/ai-proxy/provider)をサポートし、vllm/ollamaなどに基づく自己構築DeepSeekモデルにも対応しています。また、プラグインメカニズムを通じてMCPModel Context Protocolサーバーをホストすることもでき、AI Agentが様々なツールやサービスを簡単に呼び出せるようにします。[openapi-to-mcpツール](https://github.com/higress-group/openapi-to-mcpserver)を使用すると、OpenAPI仕様を迅速にリモートMCPサーバーに変換してホスティングできます。HigressはLLM APIとMCP APIの統一管理を提供します。
Higressは、AIゲートウェイ機能を基盤に、Tongyi Qianwen APP、Bailian大規模モデルAPI、機械学習PAIプラットフォームなどのAIビジネスをサポートしています。また、国内の主要なAIGC企業ZeroOneやAI製品FastGPTにもサービスを提供しています
**🌟 今すぐ[https://mcp.higress.ai/](https://mcp.higress.ai/)で体験**してください。HigressがホストするリモートMCPサーバーを直接体験できます:
![](https://img.alicdn.com/imgextra/i2/O1CN011AbR8023V8R5N0HcA_!!6000000007260-2-tps-1080-606.png)
![Higress MCP Server Platform](https://img.alicdn.com/imgextra/i2/O1CN01nmVa0a1aChgpyyWOX_!!6000000003294-0-tps-3430-1742.jpg)
### 企業での採用
Higressは、Tengineのリロードが長時間接続のビジネスに影響を与える問題や、gRPC/Dubboの負荷分散能力の不足を解決するために、Alibaba内部で誕生しました。Alibaba Cloud内では、HigressのAIゲートウェイ機能がTongyi Qianwen APP、Tongyi Bailian Model Studio、機械学習PAIプラットフォームなどの中核的なAIアプリケーションをサポートしています。また、国内の主要なAIGC企業ZeroOneやAI製品FastGPTにもサービスを提供しています。Alibaba Cloudは、Higressを基盤にクラウドネイティブAPIゲートウェイ製品を構築し、多くの企業顧客に99.99%のゲートウェイ高可用性保証サービスを提供しています。
## 目次
@@ -73,6 +79,20 @@ K8sでのHelmデプロイなどの他のインストール方法については
![](https://img.alicdn.com/imgextra/i1/O1CN01fNnhCp1cV8mYPRFeS_!!6000000003605-0-tps-1080-608.jpg)
- **MCP Server ホスティング**:
Higressは、EnvoyベースのAPIゲートウェイとして、プラグインメカニズムを通じてMCP Serverをホストすることができます。MCPModel Context Protocolは本質的にAIにより親和性の高いAPIであり、AI Agentが様々なツールやサービスを簡単に呼び出せるようにします。Higressはツール呼び出しの認証、認可、レート制限、可観測性などの統一機能を提供し、AIアプリケーションの開発とデプロイを簡素化します。
![](https://img.alicdn.com/imgextra/i3/O1CN01K4qPUX1OliZa8KIPw_!!6000000001746-2-tps-1581-615.png)
Higressを使用してMCP Serverをホストすることで、以下のことが実現できます
- 統一された認証と認可メカニズム、AIツール呼び出しのセキュリティを確保
- きめ細かいレート制限、乱用やリソース枯渇を防止
- 包括的な監査ログ、すべてのツール呼び出し行動を記録
- 豊富な可観測性、ツール呼び出しのパフォーマンスと健全性を監視
- 簡素化されたデプロイと管理、Higressのプラグインメカニズムを通じて新しいMCP Serverを迅速に追加
- 動的更新による無停止Envoyの長時間接続に対する友好的なサポートとWasmプラグインの動的更新メカニズムにより、MCP Serverのロジックをリアルタイムで更新でき、トラフィックに完全に影響を与えず、接続が切断されることはありません
- **Kubernetes Ingressゲートウェイ**:
HigressはK8sクラスターのIngressエントリーポイントゲートウェイとして機能し、多くのK8s Nginx Ingressの注釈に対応しています。K8s Nginx IngressからHigressへのスムーズな移行が可能です。
@@ -203,4 +223,4 @@ WeChat公式アカウント
<a href="#readme-top" style="text-decoration: none; color: #007bff; font-weight: bold;">
↑ トップに戻る ↑
</a>
</p>
</p>

236
README_ZH.md Normal file
View File

@@ -0,0 +1,236 @@
<a name="readme-top"></a>
<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>
AI Gateway
</h1>
<h4 align="center"> AI Native API Gateway </h4>
<div align="center">
[![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)
<a href="https://trendshift.io/repositories/10918" target="_blank"><img src="https://trendshift.io/api/badge/repositories/10918" alt="alibaba%2Fhigress | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a> <a href="https://www.producthunt.com/posts/higress?embed=true&utm_source=badge-featured&utm_medium=badge&utm_souce=badge-higress" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=951287&theme=light&t=1745492822283" alt="Higress - Global&#0032;APIs&#0032;as&#0032;MCP&#0032;powered&#0032;by&#0032;AI&#0032;Gateway | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
</div>
[**官网**](https://higress.cn/) &nbsp; |
&nbsp; [**文档**](https://higress.cn/docs/latest/overview/what-is-higress/) &nbsp; |
&nbsp; [**博客**](https://higress.cn/blog/) &nbsp; |
&nbsp; [**电子书**](https://higress.cn/docs/ebook/wasm14/) &nbsp; |
&nbsp; [**开发指引**](https://higress.cn/docs/latest/dev/architecture/) &nbsp; |
&nbsp; [**AI插件**](https://higress.cn/plugin/) &nbsp;
<p>
<a href="README.md"> English <a/>| 中文 | <a href="README_JP.md"> 日本語 <a/>
</p>
## Higress 是什么?
Higress 是一款云原生 API 网关,内核基于 Istio 和 Envoy可以用 Go/Rust/JS 等编写 Wasm 插件提供了数十个现成的通用插件以及开箱即用的控制台demo 点[这里](http://demo.higress.io/)
### 核心使用场景
Higress 的 AI 网关能力支持国内外所有[主流模型供应商](https://github.com/alibaba/higress/tree/main/plugins/wasm-go/extensions/ai-proxy/provider)和基于 vllm/ollama 等自建的 DeepSeek 模型。同时Higress 支持通过插件方式托管 MCP (Model Context Protocol) 服务器,使 AI Agent 能够更容易地调用各种工具和服务。借助 [openapi-to-mcp 工具](https://github.com/higress-group/openapi-to-mcpserver),您可以快速将 OpenAPI 规范转换为远程 MCP 服务器进行托管。Higress 提供了对 LLM API 和 MCP API 的统一管理。
**🌟 立即体验 [https://mcp.higress.ai/](https://mcp.higress.ai/)** 基于 Higress 托管的远程 MCP 服务器:
![Higress MCP 服务器平台](https://img.alicdn.com/imgextra/i2/O1CN01nmVa0a1aChgpyyWOX_!!6000000003294-0-tps-3430-1742.jpg)
### 生产环境采用
Higress 在阿里内部为解决 Tengine reload 对长连接业务有损,以及 gRPC/Dubbo 负载均衡能力不足而诞生。在阿里云内部Higress 的 AI 网关能力支撑了通义千问 APP、通义百炼模型工作室、机器学习 PAI 平台等核心 AI 应用。同时服务国内头部的 AIGC 企业(如零一万物),以及 AI 产品(如 FastGPT。阿里云基于 Higress 构建了云原生 API 网关产品,为大量企业客户提供 99.99% 的网关高可用保障服务能力。
## Summary
- [**快速开始**](#快速开始)
- [**功能展示**](#功能展示)
- [**使用场景**](#使用场景)
- [**核心优势**](#核心优势)
- [**社区**](#社区)
## 快速开始
Higress 只需 Docker 即可启动,方便个人开发者在本地搭建学习,或者用于搭建简易站点:
```bash
# 创建一个工作目录
mkdir higress; cd higress
# 启动 higress配置文件会写到工作目录下
docker run -d --rm --name higress-ai -v ${PWD}:/data \
-p 8001:8001 -p 8080:8080 -p 8443:8443 \
higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/all-in-one:latest
```
监听端口说明如下:
- 8001 端口Higress UI 控制台入口
- 8080 端口:网关 HTTP 协议入口
- 8443 端口:网关 HTTPS 协议入口
**Higress 的所有 Docker 镜像都一直使用自己独享的仓库,不受 Docker Hub 境内访问受限的影响**
K8s 下使用 Helm 部署等其他安装方式可以参考官网 [Quick Start 文档](https://higress.cn/docs/latest/user/quickstart/)。
如果您是在云上部署,生产环境推荐使用[企业版](https://higress.io/cloud/),开发测试可以使用下面一键部署社区版:
[![Deploy on AlibabaCloud ComputeNest](https://service-info-public.oss-cn-hangzhou.aliyuncs.com/computenest.svg)](https://computenest.console.aliyun.com/service/instance/create/default?type=user&ServiceName=Higress社区版)
## 使用场景
- **AI 网关**:
Higress 能够用统一的协议对接国内外所有 LLM 模型厂商,同时具备丰富的 AI 可观测、多模型负载均衡/fallback、AI token 流控、AI 缓存等能力:
![](https://img.alicdn.com/imgextra/i1/O1CN01fNnhCp1cV8mYPRFeS_!!6000000003605-0-tps-1080-608.jpg)
- **MCP Server 托管**:
Higress 作为基于 Envoy 的 API 网关,支持通过插件方式托管 MCP Server。MCPModel Context Protocol本质是面向 AI 更友好的 API使 AI Agent 能够更容易地调用各种工具和服务。Higress 可以统一处理工具调用的认证/鉴权/限流/观测等能力,简化 AI 应用的开发和部署。
![](https://img.alicdn.com/imgextra/i3/O1CN01K4qPUX1OliZa8KIPw_!!6000000001746-2-tps-1581-615.png)
通过 Higress 托管 MCP Server可以实现
- 统一的认证和鉴权机制,确保 AI 工具调用的安全性
- 精细化的速率限制,防止滥用和资源耗尽
- 完整的审计日志,记录所有工具调用行为
- 丰富的可观测性,监控工具调用的性能和健康状况
- 简化的部署和管理,通过 Higress 插件机制快速添加新的 MCP Server
- 动态更新无损:得益于 Envoy 对长连接保持的友好支持,以及 Wasm 插件的动态更新机制MCP Server 逻辑可以实时更新,且对流量完全无损,不会导致任何连接断开
- **Kubernetes Ingress 网关**:
Higress 可以作为 K8s 集群的 Ingress 入口网关, 并且兼容了大量 K8s Nginx Ingress 的注解,可以从 K8s Nginx Ingress 快速平滑迁移到 Higress。
支持 [Gateway API](https://gateway-api.sigs.k8s.io/) 标准,支持用户从 Ingress API 平滑迁移到 Gateway API。
相比 ingress-nginx资源开销大幅下降路由变更生效速度有十倍提升
![](https://img.alicdn.com/imgextra/i1/O1CN01bhEtb229eeMNBWmdP_!!6000000008093-2-tps-750-547.png)
![](https://img.alicdn.com/imgextra/i1/O1CN01bqRets1LsBGyitj4S_!!6000000001354-2-tps-887-489.png)
- **微服务网关**:
Higress 可以作为微服务网关, 能够对接多种类型的注册中心发现服务配置路由,例如 Nacos, ZooKeeper, Consul, Eureka 等。
并且深度集成了 [Dubbo](https://github.com/apache/dubbo), [Nacos](https://github.com/alibaba/nacos), [Sentinel](https://github.com/alibaba/Sentinel) 等微服务技术栈,基于 Envoy C++ 网关内核的出色性能,相比传统 Java 类微服务网关,可以显著降低资源使用率,减少成本。
![](https://img.alicdn.com/imgextra/i4/O1CN01v4ZbCj1dBjePSMZ17_!!6000000003698-0-tps-1613-926.jpg)
- **安全防护网关**:
Higress 可以作为安全防护网关, 提供 WAF 的能力,并且支持多种认证鉴权策略,例如 key-auth, hmac-auth, jwt-auth, basic-auth, oidc 等。
## 核心优势
- **生产等级**
脱胎于阿里巴巴2年多生产验证的内部产品支持每秒请求量达数十万级的大规模场景。
彻底摆脱 Nginx reload 引起的流量抖动,配置变更毫秒级生效且业务无感。对 AI 业务等长连接场景特别友好。
- **流式处理**
支持真正的完全流式处理请求/响应 BodyWasm 插件很方便地自定义处理 SSE Server-Sent Events等流式协议的报文。
在 AI 业务等大带宽场景下,可以显著降低内存开销。
- **便于扩展**
提供丰富的官方插件库,涵盖 AI、流量管理、安全防护等常用功能满足90%以上的业务场景需求。
主打 Wasm 插件扩展,通过沙箱隔离确保内存安全,支持多种编程语言,允许插件版本独立升级,实现流量无损热更新网关逻辑。
- **安全易用**
基于 Ingress API 和 Gateway API 标准,提供开箱即用的 UI 控制台WAF 防护插件、IP/Cookie CC 防护插件开箱即用。
支持对接 Let's Encrypt 自动签发和续签免费证书,并且可以脱离 K8s 部署,一行 Docker 命令即可启动,方便个人开发者使用。
## 功能展示
### AI 网关 Demo 展示
[从 OpenAI 到其他大模型30 秒完成迁移
](https://www.bilibili.com/video/BV1dT421a7w7/?spm_id_from=333.788.recommend_more_video.14)
### Higress UI 控制台
- **丰富的可观测**
提供开箱即用的可观测Grafana&Prometheus 可以使用内置的也可对接自建的
![](./docs/images/monitor.gif)
- **插件扩展机制**
官方提供了多种插件,用户也可以[开发](./plugins/wasm-go)自己的插件,构建成 docker/oci 镜像后在控制台配置,可以实时变更插件逻辑,对流量完全无损。
![](./docs/images/plugin.gif)
- **多种服务发现**
默认提供 K8s Service 服务发现,通过配置可以对接 Nacos/ZooKeeper 等注册中心实现服务发现,也可以基于静态 IP 或者 DNS 来发现
![](./docs/images/service-source.gif)
- **域名和证书**
可以创建管理 TLS 证书,并配置域名的 HTTP/HTTPS 行为,域名策略里支持对特定域名生效插件
![](./docs/images/domain.gif)
- **丰富的路由能力**
通过上面定义的服务发现机制,发现的服务会出现在服务列表中;创建路由时,选择域名,定义路由匹配机制,再选择目标服务进行路由;路由策略里支持对特定路由生效插件
![](./docs/images/route-service.gif)
## 社区
### 感谢
如果没有 Envoy 和 Istio 的开源工作Higress 就不可能实现,在这里向这两个项目献上最诚挚的敬意。
### 交流群
![image](https://img.alicdn.com/imgextra/i2/O1CN01fZefEP1aPWkzG3A19_!!6000000003322-0-tps-720-405.jpg)
### 技术分享
微信公众号:
![](https://img.alicdn.com/imgextra/i1/O1CN01WnQt0q1tcmqVDU73u_!!6000000005923-0-tps-258-258.jpg)
### 关联仓库
- Higress 控制台https://github.com/higress-group/higress-console
- Higress独立运行版https://github.com/higress-group/higress-standalone
### 贡献者
<a href="https://github.com/alibaba/higress/graphs/contributors">
<img alt="contributors" src="https://contrib.rocks/image?repo=alibaba/higress"/>
</a>
### Star History
[![Star History](https://api.star-history.com/svg?repos=alibaba/higress&type=Date)](https://star-history.com/#alibaba/higress&Date)
<p align="right" style="font-size: 14px; color: #555; margin-top: 20px;">
<a href="#readme-top" style="text-decoration: none; color: #007bff; font-weight: bold;">
↑ 返回顶部 ↑
</a>
</p>

View File

@@ -1 +1 @@
v2.0.3
v2.1.3

View File

@@ -341,7 +341,7 @@ type WasmPlugin struct {
// Extended by Higress, matching rules take effect
MatchRules []*MatchRule `protobuf:"bytes,102,rep,name=match_rules,json=matchRules,proto3" json:"match_rules,omitempty"`
// disable the default config
DefaultConfigDisable bool `protobuf:"varint,103,opt,name=default_config_disable,json=defaultConfigDisable,proto3" json:"default_config_disable,omitempty"`
DefaultConfigDisable *wrappers.BoolValue `protobuf:"bytes,103,opt,name=default_config_disable,json=defaultConfigDisable,proto3" json:"default_config_disable,omitempty"`
}
func (x *WasmPlugin) Reset() {
@@ -467,11 +467,11 @@ func (x *WasmPlugin) GetMatchRules() []*MatchRule {
return nil
}
func (x *WasmPlugin) GetDefaultConfigDisable() bool {
func (x *WasmPlugin) GetDefaultConfigDisable() *wrappers.BoolValue {
if x != nil {
return x.DefaultConfigDisable
}
return false
return nil
}
// Extended by Higress
@@ -480,11 +480,11 @@ type MatchRule struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Ingress []string `protobuf:"bytes,1,rep,name=ingress,proto3" json:"ingress,omitempty"`
Domain []string `protobuf:"bytes,2,rep,name=domain,proto3" json:"domain,omitempty"`
Config *_struct.Struct `protobuf:"bytes,3,opt,name=config,proto3" json:"config,omitempty"`
ConfigDisable bool `protobuf:"varint,4,opt,name=config_disable,json=configDisable,proto3" json:"config_disable,omitempty"`
Service []string `protobuf:"bytes,5,rep,name=service,proto3" json:"service,omitempty"`
Ingress []string `protobuf:"bytes,1,rep,name=ingress,proto3" json:"ingress,omitempty"`
Domain []string `protobuf:"bytes,2,rep,name=domain,proto3" json:"domain,omitempty"`
Config *_struct.Struct `protobuf:"bytes,3,opt,name=config,proto3" json:"config,omitempty"`
ConfigDisable *wrappers.BoolValue `protobuf:"bytes,4,opt,name=config_disable,json=configDisable,proto3" json:"config_disable,omitempty"`
Service []string `protobuf:"bytes,5,rep,name=service,proto3" json:"service,omitempty"`
}
func (x *MatchRule) Reset() {
@@ -540,11 +540,11 @@ func (x *MatchRule) GetConfig() *_struct.Struct {
return nil
}
func (x *MatchRule) GetConfigDisable() bool {
func (x *MatchRule) GetConfigDisable() *wrappers.BoolValue {
if x != nil {
return x.ConfigDisable
}
return false
return nil
}
func (x *MatchRule) GetService() []string {
@@ -686,7 +686,7 @@ var file_extensions_v1alpha1_wasmplugin_proto_rawDesc = []byte{
0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x22, 0x8d, 0x06, 0x0a, 0x0a, 0x57, 0x61, 0x73, 0x6d, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e,
0x6f, 0x22, 0xa9, 0x06, 0x0a, 0x0a, 0x57, 0x61, 0x73, 0x6d, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e,
0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75,
0x72, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x18, 0x03, 0x20, 0x01,
0x28, 0x09, 0x52, 0x06, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x12, 0x53, 0x0a, 0x11, 0x69, 0x6d,
@@ -731,52 +731,55 @@ var file_extensions_v1alpha1_wasmplugin_proto_rawDesc = []byte{
0x73, 0x18, 0x66, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x68, 0x69, 0x67, 0x72, 0x65, 0x73,
0x73, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x61,
0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x52, 0x75, 0x6c, 0x65, 0x52,
0x0a, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x34, 0x0a, 0x16, 0x64,
0x0a, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x50, 0x0a, 0x16, 0x64,
0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x64, 0x69,
0x73, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x67, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x64, 0x65, 0x66,
0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c,
0x65, 0x22, 0xaf, 0x01, 0x0a, 0x09, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x52, 0x75, 0x6c, 0x65, 0x12,
0x18, 0x0a, 0x07, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09,
0x52, 0x07, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d,
0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69,
0x6e, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x64, 0x69, 0x73,
0x61, 0x62, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x22, 0x41, 0x0a, 0x08, 0x56, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x35, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x68,
0x69, 0x67, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
0x73, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x45, 0x6e, 0x76, 0x56, 0x61,
0x72, 0x52, 0x03, 0x65, 0x6e, 0x76, 0x22, 0x7e, 0x0a, 0x06, 0x45, 0x6e, 0x76, 0x56, 0x61, 0x72,
0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x12, 0x4a, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x66, 0x72,
0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x68, 0x69, 0x67, 0x72, 0x65,
0x73, 0x73, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31,
0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x45, 0x6e, 0x76, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53,
0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x46, 0x72, 0x6f, 0x6d,
0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x45, 0x0a, 0x0b, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e,
0x50, 0x68, 0x61, 0x73, 0x65, 0x12, 0x15, 0x0a, 0x11, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49,
0x46, 0x49, 0x45, 0x44, 0x5f, 0x50, 0x48, 0x41, 0x53, 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05,
0x41, 0x55, 0x54, 0x48, 0x4e, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x55, 0x54, 0x48, 0x5a,
0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x54, 0x41, 0x54, 0x53, 0x10, 0x03, 0x2a, 0x42, 0x0a,
0x0a, 0x50, 0x75, 0x6c, 0x6c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x16, 0x0a, 0x12, 0x55,
0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43,
0x59, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x49, 0x66, 0x4e, 0x6f, 0x74, 0x50, 0x72, 0x65, 0x73,
0x65, 0x6e, 0x74, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x10,
0x02, 0x2a, 0x26, 0x0a, 0x0e, 0x45, 0x6e, 0x76, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x6f, 0x75,
0x72, 0x63, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x49, 0x4e, 0x4c, 0x49, 0x4e, 0x45, 0x10, 0x00, 0x12,
0x08, 0x0a, 0x04, 0x48, 0x4f, 0x53, 0x54, 0x10, 0x01, 0x2a, 0x2d, 0x0a, 0x0c, 0x46, 0x61, 0x69,
0x6c, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x41, 0x49,
0x4c, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x41, 0x49,
0x4c, 0x5f, 0x4f, 0x50, 0x45, 0x4e, 0x10, 0x01, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68,
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x6c, 0x69, 0x62, 0x61, 0x62, 0x61, 0x2f, 0x68,
0x69, 0x67, 0x72, 0x65, 0x73, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x78, 0x74, 0x65, 0x6e,
0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x73, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x67, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f,
0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x14, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x22, 0xcb, 0x01,
0x0a, 0x09, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x69,
0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x69, 0x6e,
0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18,
0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x2f, 0x0a,
0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x41,
0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65,
0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c,
0x75, 0x65, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c,
0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x05, 0x20, 0x03,
0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x41, 0x0a, 0x08, 0x56,
0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x35, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x01,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x68, 0x69, 0x67, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x65,
0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68,
0x61, 0x31, 0x2e, 0x45, 0x6e, 0x76, 0x56, 0x61, 0x72, 0x52, 0x03, 0x65, 0x6e, 0x76, 0x22, 0x7e,
0x0a, 0x06, 0x45, 0x6e, 0x76, 0x56, 0x61, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x4a, 0x0a, 0x0a,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e,
0x32, 0x2b, 0x2e, 0x68, 0x69, 0x67, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e,
0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x45,
0x6e, 0x76, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x45,
0x0a, 0x0b, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x50, 0x68, 0x61, 0x73, 0x65, 0x12, 0x15, 0x0a,
0x11, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x5f, 0x50, 0x48, 0x41,
0x53, 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x55, 0x54, 0x48, 0x4e, 0x10, 0x01, 0x12,
0x09, 0x0a, 0x05, 0x41, 0x55, 0x54, 0x48, 0x5a, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x54,
0x41, 0x54, 0x53, 0x10, 0x03, 0x2a, 0x42, 0x0a, 0x0a, 0x50, 0x75, 0x6c, 0x6c, 0x50, 0x6f, 0x6c,
0x69, 0x63, 0x79, 0x12, 0x16, 0x0a, 0x12, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49,
0x45, 0x44, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x49,
0x66, 0x4e, 0x6f, 0x74, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x10, 0x01, 0x12, 0x0a, 0x0a,
0x06, 0x41, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x10, 0x02, 0x2a, 0x26, 0x0a, 0x0e, 0x45, 0x6e, 0x76,
0x56, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x49,
0x4e, 0x4c, 0x49, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x4f, 0x53, 0x54, 0x10,
0x01, 0x2a, 0x2d, 0x0a, 0x0c, 0x46, 0x61, 0x69, 0x6c, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
0x79, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x41, 0x49, 0x4c, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x10,
0x00, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x41, 0x49, 0x4c, 0x5f, 0x4f, 0x50, 0x45, 0x4e, 0x10, 0x01,
0x42, 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61,
0x6c, 0x69, 0x62, 0x61, 0x62, 0x61, 0x2f, 0x68, 0x69, 0x67, 0x72, 0x65, 0x73, 0x73, 0x2f, 0x61,
0x70, 0x69, 0x2f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31,
0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -804,6 +807,7 @@ var file_extensions_v1alpha1_wasmplugin_proto_goTypes = []interface{}{
(*EnvVar)(nil), // 7: higress.extensions.v1alpha1.EnvVar
(*_struct.Struct)(nil), // 8: google.protobuf.Struct
(*wrappers.Int32Value)(nil), // 9: google.protobuf.Int32Value
(*wrappers.BoolValue)(nil), // 10: google.protobuf.BoolValue
}
var file_extensions_v1alpha1_wasmplugin_proto_depIdxs = []int32{
1, // 0: higress.extensions.v1alpha1.WasmPlugin.image_pull_policy:type_name -> higress.extensions.v1alpha1.PullPolicy
@@ -814,14 +818,16 @@ var file_extensions_v1alpha1_wasmplugin_proto_depIdxs = []int32{
6, // 5: higress.extensions.v1alpha1.WasmPlugin.vm_config:type_name -> higress.extensions.v1alpha1.VmConfig
8, // 6: higress.extensions.v1alpha1.WasmPlugin.default_config:type_name -> google.protobuf.Struct
5, // 7: higress.extensions.v1alpha1.WasmPlugin.match_rules:type_name -> higress.extensions.v1alpha1.MatchRule
8, // 8: higress.extensions.v1alpha1.MatchRule.config:type_name -> google.protobuf.Struct
7, // 9: higress.extensions.v1alpha1.VmConfig.env:type_name -> higress.extensions.v1alpha1.EnvVar
2, // 10: higress.extensions.v1alpha1.EnvVar.value_from:type_name -> higress.extensions.v1alpha1.EnvValueSource
11, // [11:11] is the sub-list for method output_type
11, // [11:11] is the sub-list for method input_type
11, // [11:11] is the sub-list for extension type_name
11, // [11:11] is the sub-list for extension extendee
0, // [0:11] is the sub-list for field type_name
10, // 8: higress.extensions.v1alpha1.WasmPlugin.default_config_disable:type_name -> google.protobuf.BoolValue
8, // 9: higress.extensions.v1alpha1.MatchRule.config:type_name -> google.protobuf.Struct
10, // 10: higress.extensions.v1alpha1.MatchRule.config_disable:type_name -> google.protobuf.BoolValue
7, // 11: higress.extensions.v1alpha1.VmConfig.env:type_name -> higress.extensions.v1alpha1.EnvVar
2, // 12: higress.extensions.v1alpha1.EnvVar.value_from:type_name -> higress.extensions.v1alpha1.EnvValueSource
13, // [13:13] is the sub-list for method output_type
13, // [13:13] is the sub-list for method input_type
13, // [13:13] is the sub-list for extension type_name
13, // [13:13] is the sub-list for extension extendee
0, // [0:13] is the sub-list for field type_name
}
func init() { file_extensions_v1alpha1_wasmplugin_proto_init() }

View File

@@ -112,7 +112,7 @@ message WasmPlugin {
// Extended by Higress, matching rules take effect
repeated MatchRule match_rules = 102;
// disable the default config
bool default_config_disable = 103;
google.protobuf.BoolValue default_config_disable = 103;
}
// Extended by Higress
@@ -120,7 +120,7 @@ message MatchRule {
repeated string ingress = 1;
repeated string domain = 2;
google.protobuf.Struct config = 3;
bool config_disable = 4;
google.protobuf.BoolValue config_disable = 4;
repeated string service = 5;
}

View File

@@ -263,6 +263,14 @@ spec:
type: string
domain:
type: string
enableMCPServer:
type: boolean
mcpServerBaseUrl:
type: string
mcpServerExportDomains:
items:
type: string
type: array
nacosAccessKey:
type: string
nacosAddressServer:

View File

@@ -26,6 +26,8 @@
package v1
import (
_ "github.com/golang/protobuf/ptypes/struct"
wrappers "github.com/golang/protobuf/ptypes/wrappers"
_ "google.golang.org/genproto/googleapis/api/annotations"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
@@ -109,25 +111,28 @@ type RegistryConfig struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
Domain string `protobuf:"bytes,3,opt,name=domain,proto3" json:"domain,omitempty"`
Port uint32 `protobuf:"varint,4,opt,name=port,proto3" json:"port,omitempty"`
NacosAddressServer string `protobuf:"bytes,5,opt,name=nacosAddressServer,proto3" json:"nacosAddressServer,omitempty"`
NacosAccessKey string `protobuf:"bytes,6,opt,name=nacosAccessKey,proto3" json:"nacosAccessKey,omitempty"`
NacosSecretKey string `protobuf:"bytes,7,opt,name=nacosSecretKey,proto3" json:"nacosSecretKey,omitempty"`
NacosNamespaceId string `protobuf:"bytes,8,opt,name=nacosNamespaceId,proto3" json:"nacosNamespaceId,omitempty"`
NacosNamespace string `protobuf:"bytes,9,opt,name=nacosNamespace,proto3" json:"nacosNamespace,omitempty"`
NacosGroups []string `protobuf:"bytes,10,rep,name=nacosGroups,proto3" json:"nacosGroups,omitempty"`
NacosRefreshInterval int64 `protobuf:"varint,11,opt,name=nacosRefreshInterval,proto3" json:"nacosRefreshInterval,omitempty"`
ConsulNamespace string `protobuf:"bytes,12,opt,name=consulNamespace,proto3" json:"consulNamespace,omitempty"`
ZkServicesPath []string `protobuf:"bytes,13,rep,name=zkServicesPath,proto3" json:"zkServicesPath,omitempty"`
ConsulDatacenter string `protobuf:"bytes,14,opt,name=consulDatacenter,proto3" json:"consulDatacenter,omitempty"`
ConsulServiceTag string `protobuf:"bytes,15,opt,name=consulServiceTag,proto3" json:"consulServiceTag,omitempty"`
ConsulRefreshInterval int64 `protobuf:"varint,16,opt,name=consulRefreshInterval,proto3" json:"consulRefreshInterval,omitempty"`
AuthSecretName string `protobuf:"bytes,17,opt,name=authSecretName,proto3" json:"authSecretName,omitempty"`
Protocol string `protobuf:"bytes,18,opt,name=protocol,proto3" json:"protocol,omitempty"`
Sni string `protobuf:"bytes,19,opt,name=sni,proto3" json:"sni,omitempty"`
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
Domain string `protobuf:"bytes,3,opt,name=domain,proto3" json:"domain,omitempty"`
Port uint32 `protobuf:"varint,4,opt,name=port,proto3" json:"port,omitempty"`
NacosAddressServer string `protobuf:"bytes,5,opt,name=nacosAddressServer,proto3" json:"nacosAddressServer,omitempty"`
NacosAccessKey string `protobuf:"bytes,6,opt,name=nacosAccessKey,proto3" json:"nacosAccessKey,omitempty"`
NacosSecretKey string `protobuf:"bytes,7,opt,name=nacosSecretKey,proto3" json:"nacosSecretKey,omitempty"`
NacosNamespaceId string `protobuf:"bytes,8,opt,name=nacosNamespaceId,proto3" json:"nacosNamespaceId,omitempty"`
NacosNamespace string `protobuf:"bytes,9,opt,name=nacosNamespace,proto3" json:"nacosNamespace,omitempty"`
NacosGroups []string `protobuf:"bytes,10,rep,name=nacosGroups,proto3" json:"nacosGroups,omitempty"`
NacosRefreshInterval int64 `protobuf:"varint,11,opt,name=nacosRefreshInterval,proto3" json:"nacosRefreshInterval,omitempty"`
ConsulNamespace string `protobuf:"bytes,12,opt,name=consulNamespace,proto3" json:"consulNamespace,omitempty"`
ZkServicesPath []string `protobuf:"bytes,13,rep,name=zkServicesPath,proto3" json:"zkServicesPath,omitempty"`
ConsulDatacenter string `protobuf:"bytes,14,opt,name=consulDatacenter,proto3" json:"consulDatacenter,omitempty"`
ConsulServiceTag string `protobuf:"bytes,15,opt,name=consulServiceTag,proto3" json:"consulServiceTag,omitempty"`
ConsulRefreshInterval int64 `protobuf:"varint,16,opt,name=consulRefreshInterval,proto3" json:"consulRefreshInterval,omitempty"`
AuthSecretName string `protobuf:"bytes,17,opt,name=authSecretName,proto3" json:"authSecretName,omitempty"`
Protocol string `protobuf:"bytes,18,opt,name=protocol,proto3" json:"protocol,omitempty"`
Sni string `protobuf:"bytes,19,opt,name=sni,proto3" json:"sni,omitempty"`
McpServerExportDomains []string `protobuf:"bytes,20,rep,name=mcpServerExportDomains,proto3" json:"mcpServerExportDomains,omitempty"`
McpServerBaseUrl string `protobuf:"bytes,21,opt,name=mcpServerBaseUrl,proto3" json:"mcpServerBaseUrl,omitempty"`
EnableMCPServer *wrappers.BoolValue `protobuf:"bytes,22,opt,name=enableMCPServer,proto3" json:"enableMCPServer,omitempty"`
}
func (x *RegistryConfig) Reset() {
@@ -295,6 +300,27 @@ func (x *RegistryConfig) GetSni() string {
return ""
}
func (x *RegistryConfig) GetMcpServerExportDomains() []string {
if x != nil {
return x.McpServerExportDomains
}
return nil
}
func (x *RegistryConfig) GetMcpServerBaseUrl() string {
if x != nil {
return x.McpServerBaseUrl
}
return ""
}
func (x *RegistryConfig) GetEnableMCPServer() *wrappers.BoolValue {
if x != nil {
return x.EnableMCPServer
}
return nil
}
var File_networking_v1_mcp_bridge_proto protoreflect.FileDescriptor
var file_networking_v1_mcp_bridge_proto_rawDesc = []byte{
@@ -303,61 +329,76 @@ var file_networking_v1_mcp_bridge_proto_rawDesc = []byte{
0x12, 0x15, 0x68, 0x69, 0x67, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72,
0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
0x61, 0x70, 0x69, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69,
0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x52, 0x0a, 0x09, 0x4d, 0x63, 0x70, 0x42,
0x72, 0x69, 0x64, 0x67, 0x65, 0x12, 0x45, 0x0a, 0x0a, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72,
0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x68, 0x69, 0x67, 0x72,
0x65, 0x73, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x76,
0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x52, 0x0a, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0xd3, 0x05, 0x0a,
0x0e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x17, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0,
0x41, 0x02, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x06,
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41,
0x02, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x17, 0x0a, 0x04, 0x70, 0x6f, 0x72,
0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x04, 0x70, 0x6f,
0x72, 0x74, 0x12, 0x2e, 0x0a, 0x12, 0x6e, 0x61, 0x63, 0x6f, 0x73, 0x41, 0x64, 0x64, 0x72, 0x65,
0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12,
0x6e, 0x61, 0x63, 0x6f, 0x73, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76,
0x65, 0x72, 0x12, 0x26, 0x0a, 0x0e, 0x6e, 0x61, 0x63, 0x6f, 0x73, 0x41, 0x63, 0x63, 0x65, 0x73,
0x73, 0x4b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6e, 0x61, 0x63, 0x6f,
0x73, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x6e, 0x61,
0x63, 0x6f, 0x73, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0e, 0x6e, 0x61, 0x63, 0x6f, 0x73, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b,
0x65, 0x79, 0x12, 0x2a, 0x0a, 0x10, 0x6e, 0x61, 0x63, 0x6f, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x73,
0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6e, 0x61,
0x63, 0x6f, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x26,
0x0a, 0x0e, 0x6e, 0x61, 0x63, 0x6f, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65,
0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6e, 0x61, 0x63, 0x6f, 0x73, 0x4e, 0x61, 0x6d,
0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x61, 0x63, 0x6f, 0x73, 0x47,
0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x61, 0x63,
0x6f, 0x73, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x6e, 0x61, 0x63, 0x6f,
0x73, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c,
0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x14, 0x6e, 0x61, 0x63, 0x6f, 0x73, 0x52, 0x65, 0x66,
0x72, 0x65, 0x73, 0x68, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x28, 0x0a, 0x0f,
0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18,
0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x4e, 0x61, 0x6d,
0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x7a, 0x6b, 0x53, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x73, 0x50, 0x61, 0x74, 0x68, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e,
0x7a, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x50, 0x61, 0x74, 0x68, 0x12, 0x2a,
0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74,
0x65, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c,
0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x6f,
0x6e, 0x73, 0x75, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x61, 0x67, 0x18, 0x0f,
0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x53, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x54, 0x61, 0x67, 0x12, 0x34, 0x0a, 0x15, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c,
0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18,
0x10, 0x20, 0x01, 0x28, 0x03, 0x52, 0x15, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x52, 0x65, 0x66,
0x72, 0x65, 0x73, 0x68, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x26, 0x0a, 0x0e,
0x61, 0x75, 0x74, 0x68, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x11,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74,
0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
0x12, 0x10, 0x0a, 0x03, 0x73, 0x6e, 0x69, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73,
0x6e, 0x69, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x61, 0x6c, 0x69, 0x62, 0x61, 0x62, 0x61, 0x2f, 0x68, 0x69, 0x67, 0x72, 0x65, 0x73, 0x73,
0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x2f,
0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65,
0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x52, 0x0a, 0x09, 0x4d, 0x63, 0x70, 0x42, 0x72, 0x69,
0x64, 0x67, 0x65, 0x12, 0x45, 0x0a, 0x0a, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x69, 0x65,
0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x68, 0x69, 0x67, 0x72, 0x65, 0x73,
0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e,
0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0a,
0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0xfd, 0x06, 0x0a, 0x0e, 0x52,
0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x17, 0x0a,
0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02,
0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x06, 0x64, 0x6f,
0x6d, 0x61, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52,
0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x17, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18,
0x04, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74,
0x12, 0x2e, 0x0a, 0x12, 0x6e, 0x61, 0x63, 0x6f, 0x73, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x6e, 0x61,
0x63, 0x6f, 0x73, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
0x12, 0x26, 0x0a, 0x0e, 0x6e, 0x61, 0x63, 0x6f, 0x73, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b,
0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6e, 0x61, 0x63, 0x6f, 0x73, 0x41,
0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x6e, 0x61, 0x63, 0x6f,
0x73, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0e, 0x6e, 0x61, 0x63, 0x6f, 0x73, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79,
0x12, 0x2a, 0x0a, 0x10, 0x6e, 0x61, 0x63, 0x6f, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61,
0x63, 0x65, 0x49, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6e, 0x61, 0x63, 0x6f,
0x73, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x26, 0x0a, 0x0e,
0x6e, 0x61, 0x63, 0x6f, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x09,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6e, 0x61, 0x63, 0x6f, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x73,
0x70, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x61, 0x63, 0x6f, 0x73, 0x47, 0x72, 0x6f,
0x75, 0x70, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x61, 0x63, 0x6f, 0x73,
0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x6e, 0x61, 0x63, 0x6f, 0x73, 0x52,
0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x0b,
0x20, 0x01, 0x28, 0x03, 0x52, 0x14, 0x6e, 0x61, 0x63, 0x6f, 0x73, 0x52, 0x65, 0x66, 0x72, 0x65,
0x73, 0x68, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x28, 0x0a, 0x0f, 0x63, 0x6f,
0x6e, 0x73, 0x75, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x0c, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x73,
0x70, 0x61, 0x63, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x7a, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x73, 0x50, 0x61, 0x74, 0x68, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x7a, 0x6b,
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x50, 0x61, 0x74, 0x68, 0x12, 0x2a, 0x0a, 0x10,
0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72,
0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x44, 0x61,
0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x73,
0x75, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x61, 0x67, 0x18, 0x0f, 0x20, 0x01,
0x28, 0x09, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x54, 0x61, 0x67, 0x12, 0x34, 0x0a, 0x15, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x52, 0x65,
0x66, 0x72, 0x65, 0x73, 0x68, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x10, 0x20,
0x01, 0x28, 0x03, 0x52, 0x15, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x52, 0x65, 0x66, 0x72, 0x65,
0x73, 0x68, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x26, 0x0a, 0x0e, 0x61, 0x75,
0x74, 0x68, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x11, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4e, 0x61,
0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x12,
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x10,
0x0a, 0x03, 0x73, 0x6e, 0x69, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x6e, 0x69,
0x12, 0x36, 0x0a, 0x16, 0x6d, 0x63, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x78, 0x70,
0x6f, 0x72, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x14, 0x20, 0x03, 0x28, 0x09,
0x52, 0x16, 0x6d, 0x63, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x78, 0x70, 0x6f, 0x72,
0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6d, 0x63, 0x70, 0x53,
0x65, 0x72, 0x76, 0x65, 0x72, 0x42, 0x61, 0x73, 0x65, 0x55, 0x72, 0x6c, 0x18, 0x15, 0x20, 0x01,
0x28, 0x09, 0x52, 0x10, 0x6d, 0x63, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x42, 0x61, 0x73,
0x65, 0x55, 0x72, 0x6c, 0x12, 0x44, 0x0a, 0x0f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x43,
0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x65, 0x6e, 0x61, 0x62, 0x6c,
0x65, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x6c, 0x69, 0x62, 0x61, 0x62, 0x61,
0x2f, 0x68, 0x69, 0x67, 0x72, 0x65, 0x73, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6e, 0x65, 0x74,
0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
@@ -374,16 +415,18 @@ func file_networking_v1_mcp_bridge_proto_rawDescGZIP() []byte {
var file_networking_v1_mcp_bridge_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_networking_v1_mcp_bridge_proto_goTypes = []interface{}{
(*McpBridge)(nil), // 0: higress.networking.v1.McpBridge
(*RegistryConfig)(nil), // 1: higress.networking.v1.RegistryConfig
(*McpBridge)(nil), // 0: higress.networking.v1.McpBridge
(*RegistryConfig)(nil), // 1: higress.networking.v1.RegistryConfig
(*wrappers.BoolValue)(nil), // 2: google.protobuf.BoolValue
}
var file_networking_v1_mcp_bridge_proto_depIdxs = []int32{
1, // 0: higress.networking.v1.McpBridge.registries:type_name -> higress.networking.v1.RegistryConfig
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
2, // 1: higress.networking.v1.RegistryConfig.enableMCPServer:type_name -> google.protobuf.BoolValue
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_networking_v1_mcp_bridge_proto_init() }

View File

@@ -15,6 +15,8 @@
syntax = "proto3";
import "google/api/field_behavior.proto";
import "google/protobuf/wrappers.proto";
import "google/protobuf/struct.proto";
// $schema: higress.networking.v1.McpBridge
// $title: McpBridge
@@ -66,4 +68,7 @@ message RegistryConfig {
string authSecretName = 17;
string protocol = 18;
string sni = 19;
repeated string mcpServerExportDomains = 20;
string mcpServerBaseUrl = 21;
google.protobuf.BoolValue enableMCPServer = 22;
}

View File

@@ -35,6 +35,8 @@ DOCKER_ALL_VARIANTS ?= debug distroless
INCLUDE_UNTAGGED_DEFAULT ?= false
DEFAULT_DISTRIBUTION=debug
HIGRESS_DOCKER_BUILDX_RULE ?= $(foreach VARIANT,$(DOCKER_BUILD_VARIANTS), time (mkdir -p $(HIGRESS_DOCKER_BUILD_TOP)/$@ && TARGET_ARCH=$(TARGET_ARCH) ./docker/docker-copy.sh $^ $(HIGRESS_DOCKER_BUILD_TOP)/$@ && cd $(HIGRESS_DOCKER_BUILD_TOP)/$@ $(BUILD_PRE) && docker buildx create --name higress --node higress0 --platform linux/amd64,linux/arm64 --use && docker buildx build --no-cache --platform linux/amd64,linux/arm64 $(BUILD_ARGS) --build-arg BASE_DISTRIBUTION=$(call normalize-tag,$(VARIANT)) -t $(HUB)/higress:$(TAG)$(call variant-tag,$(VARIANT)) -f Dockerfile.higress . --push ); )
HIGRESS_DOCKER_RULE ?= $(foreach VARIANT,$(DOCKER_BUILD_VARIANTS), time (mkdir -p $(HIGRESS_DOCKER_BUILD_TOP)/$@ && TARGET_ARCH=$(TARGET_ARCH) ./docker/docker-copy.sh $^ $(HIGRESS_DOCKER_BUILD_TOP)/$@ && cd $(HIGRESS_DOCKER_BUILD_TOP)/$@ $(BUILD_PRE) && docker build $(BUILD_ARGS) --build-arg BASE_DISTRIBUTION=$(call normalize-tag,$(VARIANT)) -t $(HUB)/higress:$(TAG)$(call variant-tag,$(VARIANT)) -f Dockerfile.higress . ); )
IMG ?= higress
IMG_URL ?= $(HUB)/$(IMG):$(TAG)
HIGRESS_DOCKER_BUILDX_RULE ?= $(foreach VARIANT,$(DOCKER_BUILD_VARIANTS), time (mkdir -p $(HIGRESS_DOCKER_BUILD_TOP)/$@ && TARGET_ARCH=$(TARGET_ARCH) ./docker/docker-copy.sh $^ $(HIGRESS_DOCKER_BUILD_TOP)/$@ && cd $(HIGRESS_DOCKER_BUILD_TOP)/$@ $(BUILD_PRE) && docker buildx create --name higress --node higress0 --platform linux/amd64,linux/arm64 --use && docker buildx build --no-cache --platform linux/amd64,linux/arm64 $(BUILD_ARGS) --build-arg BASE_DISTRIBUTION=$(call normalize-tag,$(VARIANT)) -t $(IMG_URL)$(call variant-tag,$(VARIANT)) -f Dockerfile.higress . --push ); )
HIGRESS_DOCKER_RULE ?= $(foreach VARIANT,$(DOCKER_BUILD_VARIANTS), time (mkdir -p $(HIGRESS_DOCKER_BUILD_TOP)/$@ && TARGET_ARCH=$(TARGET_ARCH) ./docker/docker-copy.sh $^ $(HIGRESS_DOCKER_BUILD_TOP)/$@ && cd $(HIGRESS_DOCKER_BUILD_TOP)/$@ $(BUILD_PRE) && docker build $(BUILD_ARGS) --build-arg BASE_DISTRIBUTION=$(call normalize-tag,$(VARIANT)) -t $(IMG_URL)$(call variant-tag,$(VARIANT)) -f Dockerfile.higress . ); )

143
docs/architecture.md Normal file
View File

@@ -0,0 +1,143 @@
# Higress 核心组件和原理
Higress 是基于 Envoy 和 Istio 进行二次定制化开发构建和功能增强,同时利用 Envoy 和 Istio 一些插件机制,实现了一个轻量级的网关服务。其包括 3 个核心组件Higress Controller控制器、Higress Gateway网关和 Higress Console控制台
下图概况了其核心工作流程:
![img](./images/img_02_01.png)
本章将重点介绍 Higress 的两个核心组件Higress Controller 和 Higress Gateway。
## 1 Higress Console
Higress Console 是 Higress 网关的管理控制台,主要功能是管理 Higress 网关的路由配置、插件配置等。
### 1.1 Higress Admin SDK
Higress Admin SDK 脱胎于 Higress Console。起初它作为 Higress Console 的一部分,为前端界面提供实际的功能支持。后来考虑到对接外部系统等需求,将配置管理的部分剥离出来,形成一个独立的逻辑组件,便于和各个系统进行对接。目前支持服务来源管理、服务管理、路由管理、域名管理、证书管理、插件管理等功能。
Higress Admin SDK 现在只提供 Java 版本,且要求 JDK 版本不低于 17。具体如何集成请参考 Higress 官方 BLOG [如何使用 Higress Admin SDK 进行配置管理](https://higress.io/zh-cn/blog/admin-sdk-intro)。
## 2 Higress Controller
Higress Controller控制器 是 Higress 的核心组件,其功能主要是实现 Higress 网关的服务发现、动态配置管理以及动态下发配置给数据面。Higress Controller 内部包含两个子组件Discovery 和 Higress Core。
### 2.1 Discovery 组件
Discovery 组件Istio Pilot-Discovery是 Istio 的核心组件负责服务发现、配置管理、证书签发、控制面和数据面之间的通讯和配置下发等。Discovery 内部结构比较复杂,本文只介绍 Discovery 配置管理和服务发现的基本原理,其核心功能的详细介绍可以参考赵化冰老师的 BLOG [Istio Pilot 组件介绍](https://www.zhaohuabing.com/post/2019-10-21-pilot-discovery-code-analysis/)。
Discovery 将 Kubernetes Service、Gateway API 配置等转换成 Istio 配置,然后将所有 Istio 配置合并转成符合 xDS 接口规范的数据结构,通过 GRPC 下发到数据面的 Envoy。其工作原理如下图
![img](./images/img_02_02.png)
#### 2.1.1 Config Controller
Discovery 为了更好管理 Istio 配置来源,提供 `Config Controller` 用于管理各种配置来源,目前支持 4 种类型的 `Config Controller`
- Kubernetes使用 Kubernetes 作为配置信息来源,该方式的直接依赖 Kubernetes 强大的 CRD 机制来存储配置信息,简单方便,是 Istio 最开始使用的配置信息存储方案, 其中包括 `Kubernetes Controller``Gateway API Controller` 两个实现。
- MCPMesh Configuration Protocol使用 Kubernetes 存储配置数据导致了 Istio 和 Kubernetes 的耦合,限制了 Istio 在非 Kubernetes 环境下的运用。为了解决该耦合Istio 社区提出了 MCP。
- Memory一个基于内存的 Config Controller 实现,主要用于测试。
- File一个基于文件的 Config Controller 实现,主要用于测试。
1. Istio 配置
Istio 配置包括:`Gateway``VirtualService``DestinationRule``ServiceEntry``EnvoyFilter``WasmPlugin``WorkloadEntry``WorkloadGroup` 等,可以参考 Istio 官方文档[流量管理](https://istio.io/latest/zh/docs/reference/config/networking/)了解更多配置信息。
2. Gateway API 配置
Gateway API 配置包括:`GatewayClass``Gateway``HttpRoute``TCPRoute``GRPCRoute` 等, 可以参考 Gateway API 官方文档 [Gateway API](https://gateway-api.sigs.k8s.io/api-types/gateway/) 了解更多配置信息。
3. MCP over xDS
Discovery 作为 MCP Client任何实现了 MCP 协议的 Server 都可以通过 MCP 协议向 Discovery 下发配置信息,从而消除了 Istio 和 Kubernetes 之间的耦合, 同时使 Istio 的配置信息处理更加灵活和可扩展。
同时 MCP 是一种基于 xDS 协议的配置管理协议Higress Core 通过实现 MCP 协议,使 Higress Core 成为 Discovery 的 Istio 配置来源。
4. Config Controller 来源配置
`higress-system` 命名空间中,名为 `higress-config` 的 Configmap 中,`mesh` 配置项包含一个 `configSources` 属性用于配置来源。其 Configmap 部分配置项如下:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: higress-config
namespace: higress-system
data:
mesh: |-
accessLogEncoding: TEXT
...
configSources:
- address: xds://127.0.0.1:15051
- address: k8s://
...
meshNetworks: "networks: {}"
```
#### 2.1.2 Service Controller
`Service Controller` 用于管理各种 `Service Registry`,提供服务发现数据,目前 Istio 支持的 `Service Registry` 主要包括:
- Kubernetes对接 Kubernetes Registry可以将 Kubernetes 中定义的 Service 和 Endpoint 采集到 Istio 中。
- Memory一个基于内存的 Service Controller 实现,主要用于测试。
### 2.2 Higress Core 组件
Higress Core 核心逻辑如下图:
![img](./images/img_02_03.png)
Higress Core 内部包含两个核心子组件: Ingress Config 和 Cert Server。
#### 2.2.1 Ingress Config
Ingress Config 包含 6 个控制器,各自负责不同的功能:
- Ingress Controller监听 Ingress 资源,将 Ingress 转换为 Istio 的 Gateway、VirtualService、DestinationRule 等资源。
- Gateway Controller监听 Gateway、VirtualService、DestinationRule 等资源。
- McpBridge Controller根据 McpBridge 的配置,将来自 Nacos、Eureka、Consul、Zookeeper 等外部注册中心或 DNS 的服务信息转换成 Istio ServiceEntry 资源。
- Http2Rpc Controller监听 Http2Rpc 资源,实现 HTTP 协议到 RPC 协议的转换。用户可以通过配置协议转换,将 RPC 服务以 HTTP 接口的形式暴露,从而使用 HTTP 请求调用 RPC 接口。
- WasmPlugin Controller监听 WasmPlugin 资源,将 Higress WasmPlugin 转化为 Istio WasmPlugin。Higress WasmPlugin 在 Istio WasmPlugin 的基础上进行了扩展,支持全局、路由、域名、服务级别的配置。
- ConfigmapMgr监听 Higress 的全局配置 `higress-config` ConfigMap可以根据 tracing、gzip 等配置构造 EnvoyFilter。
#### 2.2.2 Cert Server
Cert Server 管理 Secret 资源和证书自动签发。
## 3 Higress Gateway
Higress Gateway 内部包含两个子组件Pilot Agent 和 Envoy。Pilot Agent 主要负责 Envoy 的启动和配置,同时代理 Envoy xDS 请求到 Discovery。 Envoy 作为数据面,负责接收控制面的配置下发,并代理请求到业务服务。 Pilot Agent 和 Envoy 之间通讯协议是使用 xDS 协议, 通过 Unix Domain SocketUDS进行通信。
Envoy 核心架构如下图:
![img](./images/img_02_04.png)
### 1 Envoy 核心组件
- 下游Downstream:
下游是 Envoy 的客户端,它们负责发起请求并接收 Envoy 的响应。下游通常是最终用户的设备或服务,它们通过 Envoy 代理与后端服务进行通信。
- 上游Upstream:
上游是 Envoy 的后端服务器,它们接收 Envoy 代理的连接和请求。上游提供服务或数据,对来自下游客户端的请求进行处理并返回响应。
- 监听器Listener:
监听器是可以接受来自下游客户端连接的网络地址(如 IP 地址和端口Unix Domain Socket 等。Envoy 支持在单个进程中配置任意数量的监听器。监听器可以通过 `Listener Discovery ServiceLDS`来动态发现和更新。
- 路由Router:
路由器是 Envoy 中连接下游和上游的桥梁。它负责决定如何将监听器接收到的请求路由到适当的集群。路由器根据配置的路由规则如路径、HTTP 标头 等,来确定请求的目标集群,从而实现精确的流量控制和路由。路由器可以通过 `Route Discovery ServiceRDS`来动态发现和更新。
- 集群Cluster:
集群是一组逻辑上相似的服务提供者的集合。集群成员的选择由负载均衡策略决定,确保请求能够均匀或按需分配到不同的服务实例。集群可以通过 `Cluster Discovery ServiceCDS`来动态发现和更新。
- 端点Endpoint:
端点是上游集群中的具体服务实例,可以是 IP 地址和端口号的组合。端点可以通过 `Endpoint Discovery ServiceEDS`来动态发现和更新。
- SSL/TLS:
Envoy 可以通过 `Secret Discovery Service (SDS)` 动态获取监听器和集群所需的 TLS 证书、私钥以及信任的根证书和撤销机制等配置信息。
通过这些组件的协同工作Envoy 能够高效地处理网络请求,提供流量管理、负载均衡、服务发现和动态路由等关键功能。
要详细了解 Envoy 的工作原理,可以参考[Envoy 官方文档](https://www.envoyproxy.io/docs/envoy/latest/intro/intro),最佳的方式可以通过一个请求通过 [Envoy 代理的生命周期](https://www.envoyproxy.io/docs/envoy/latest/intro/life_of_a_request)事件的过程来理解 Envoy 的工作原理。
## 参考
- [1] [Istio Pilot 组件介绍](https://www.zhaohuabing.com/post/2019-10-21-pilot-discovery-code-analysis/)
- [2] [Istio 服务注册插件机制代码解析](https://www.zhaohuabing.com/post/2019-02-18-pilot-service-registry-code-analysis/)
- [3] [Istio Pilot代码深度解析](https://www.zhaohuabing.com/post/2019-10-21-pilot-discovery-code-analysis/)
- [4] [Envoy 官方文档](https://www.envoyproxy.io/docs/envoy/latest/intro/intro)

BIN
docs/images/img_02_01.png Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

BIN
docs/images/img_02_02.png Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

BIN
docs/images/img_02_03.png Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

BIN
docs/images/img_02_04.png Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

45
go.mod
View File

@@ -1,8 +1,6 @@
module github.com/alibaba/higress
go 1.21.0
toolchain go1.22.2
go 1.22.2
replace github.com/spf13/viper => github.com/istio/viper v1.3.3-0.20190515210538-2789fed3109c
@@ -23,6 +21,7 @@ require (
github.com/dubbogo/go-zookeeper v1.0.4-0.20211212162352-f9d2183d89d5
github.com/dubbogo/gost v1.13.1
github.com/envoyproxy/go-control-plane v0.11.2-0.20230725211550-11bfe846bcd4
github.com/go-errors/errors v1.4.2
github.com/gogo/protobuf v1.3.2
github.com/golang/protobuf v1.5.3
github.com/google/go-cmp v0.6.0
@@ -40,7 +39,7 @@ require (
github.com/tidwall/gjson v1.17.0
go.uber.org/atomic v1.11.0
go.uber.org/zap v1.27.0
golang.org/x/net v0.27.0
golang.org/x/net v0.33.0
google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13
google.golang.org/grpc v1.59.0
google.golang.org/protobuf v1.33.0
@@ -72,7 +71,27 @@ require (
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/alecholmes/xfccparser v0.1.0 // indirect
github.com/alecthomas/participle v0.4.1 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704 // indirect
github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 // indirect
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
github.com/alibabacloud-go/darabonba-array v0.1.0 // indirect
github.com/alibabacloud-go/darabonba-encode-util v0.0.2 // indirect
github.com/alibabacloud-go/darabonba-map v0.0.2 // indirect
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 // indirect
github.com/alibabacloud-go/darabonba-signature-util v0.0.7 // indirect
github.com/alibabacloud-go/darabonba-string v1.0.2 // indirect
github.com/alibabacloud-go/debug v1.0.1 // indirect
github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect
github.com/alibabacloud-go/kms-20160120/v3 v3.2.3 // indirect
github.com/alibabacloud-go/openapi-util v0.1.0 // indirect
github.com/alibabacloud-go/tea v1.2.2 // indirect
github.com/alibabacloud-go/tea-utils v1.4.4 // indirect
github.com/alibabacloud-go/tea-utils/v2 v2.0.7 // indirect
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1800 // indirect
github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1 // indirect
github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8 // indirect
github.com/aliyun/aliyun-secretsmanager-client-go v1.1.5 // indirect
github.com/aliyun/credentials-go v1.4.3 // indirect
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect
github.com/armon/go-metrics v0.4.1 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
@@ -83,10 +102,12 @@ require (
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/clbanning/mxj v1.8.4 // indirect
github.com/clbanning/mxj/v2 v2.5.5 // indirect
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
github.com/coreos/go-oidc/v3 v3.6.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/deckarep/golang-set v1.7.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/docker/cli v24.0.7+incompatible // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
@@ -99,7 +120,6 @@ require (
github.com/fatih/color v1.15.0 // indirect
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect
github.com/go-jose/go-jose/v3 v3.0.0 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
@@ -167,6 +187,7 @@ require (
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
github.com/openshift/api v0.0.0-20230720094506-afcbe27aec7c // indirect
github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
@@ -184,6 +205,7 @@ require (
github.com/tetratelabs/wazero v1.7.3 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect
github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3 // indirect
github.com/vbatts/tar-split v0.11.3 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
@@ -199,14 +221,14 @@ require (
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/oauth2 v0.13.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/term v0.22.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/term v0.27.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
@@ -252,5 +274,6 @@ replace github.com/caddyserver/certmagic => github.com/2456868764/certmagic v1.0
replace (
github.com/dubbogo/gost => github.com/johnlanni/gost v1.11.23-0.20220713132522-0967a24036c6
github.com/nacos-group/nacos-sdk-go/v2 => github.com/luoxiner/nacos-sdk-go/v2 v2.2.9-60
golang.org/x/exp => golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1
)

144
go.sum
View File

@@ -683,9 +683,68 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alessio/shellescape v1.2.2/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30=
github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 h1:eIf+iGJxdU4U9ypaUfbtOWCsZSbTb8AUHvyPrxu6mAA=
github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6/go.mod h1:4EUIoxs/do24zMOGGqYVWgw0s9NtiylnJglOeEB5UJo=
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 h1:zE8vH9C7JiZLNJJQ5OwjU9mSi4T9ef9u3BURT6LCLC8=
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5/go.mod h1:tWnyE9AjF8J8qqLk645oUmVUnFybApTQWklQmi5tY6g=
github.com/alibabacloud-go/darabonba-array v0.1.0 h1:vR8s7b1fWAQIjEjWnuF0JiKsCvclSRTfDzZHTYqfufY=
github.com/alibabacloud-go/darabonba-array v0.1.0/go.mod h1:BLKxr0brnggqOJPqT09DFJ8g3fsDshapUD3C3aOEFaI=
github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC2NG0Ax+GpOM5gtupki31XE=
github.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F4PKuMgEUETNZasrDM6vqVr/Can7H8=
github.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc=
github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.9/go.mod h1:bb+Io8Sn2RuM3/Rpme6ll86jMyFSrD1bxeV/+v61KeU=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 h1:GEYkMApgpKEVDn6z12DcH1EGYpDYRB8JxsazM4Rywak=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10/go.mod h1:26a14FGhZVELuz2cc2AolvW4RHmIO3/HRwsdHhaIPDE=
github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=
github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ=
github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo=
github.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=
github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
github.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg=
github.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q=
github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
github.com/alibabacloud-go/kms-20160120/v3 v3.2.3 h1:vamGcYQFwXVqR6RWcrVTTqlIXZVsYjaA7pZbx+Xw6zw=
github.com/alibabacloud-go/kms-20160120/v3 v3.2.3/go.mod h1:3rIyughsFDLie1ut9gQJXkWkMg/NfXBCk+OtXnPu3lw=
github.com/alibabacloud-go/openapi-util v0.1.0 h1:0z75cIULkDrdEhkLWgi9tnLe+KhAFE/r5Pb3312/eAY=
github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=
github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg=
github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
github.com/alibabacloud-go/tea v1.2.1/go.mod h1:qbzof29bM/IFhLMtJPrgTGK3eauV5J2wSyEUo4OEmnA=
github.com/alibabacloud-go/tea v1.2.2 h1:aTsR6Rl3ANWPfqeQugPglfurloyBJY85eFy7Gc1+8oU=
github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
github.com/alibabacloud-go/tea-utils v1.4.4 h1:lxCDvNCdTo9FaXKKq45+4vGETQUKNOW/qKTcX9Sk53o=
github.com/alibabacloud-go/tea-utils v1.4.4/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw=
github.com/alibabacloud-go/tea-utils/v2 v2.0.3/go.mod h1:sj1PbjPodAVTqGTA3olprfeeqqmwD0A5OQz94o9EuXQ=
github.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4=
github.com/alibabacloud-go/tea-utils/v2 v2.0.6/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
github.com/alibabacloud-go/tea-utils/v2 v2.0.7 h1:WDx5qW3Xa5ZgJ1c8NfqJkF6w+AU5wB8835UdhPr6Ax0=
github.com/alibabacloud-go/tea-utils/v2 v2.0.7/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0=
github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.18/go.mod h1:v8ESoHo4SyHmuB4b1tJqDHxfTGEciD+yhvOU/5s1Rfk=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704 h1:PpfENOj/vPfhhy9N2OFRjpue0hjM5XqAp2thFmkXXIk=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1800 h1:ie/8RxBOfKZWcrbYSJi2Z8uX8TcOlSMwPlEJh83OeOw=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1800/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1 h1:nJYyoFP+aqGKgPs9JeZgS1rWQ4NndNR0Zfhh161ZltU=
github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1/go.mod h1:WzGOmFFTlUzXM03CJnHWMQ85UN6QGpOXZocCjwkiyOg=
github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8 h1:QeUdR7JF7iNCvO/81EhxEr3wDwxk4YBoYZOq6E0AjHI=
github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8/go.mod h1:xP0KIZry6i7oGPF24vhAPr1Q8vLZRcMcxtft5xDKwCU=
github.com/aliyun/aliyun-secretsmanager-client-go v1.1.5 h1:8S0mtD101RDYa0LXwdoqgN0RxdMmmJYjq8g2mk7/lQ4=
github.com/aliyun/aliyun-secretsmanager-client-go v1.1.5/go.mod h1:M19fxYz3gpm0ETnoKweYyYtqrtnVtrpKFpwsghbw+cQ=
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0=
github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM=
github.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
github.com/aliyun/credentials-go v1.4.3 h1:N3iHyvHRMyOwY1+0qBLSf3hb5JFiOujVSVuEpgeGttY=
github.com/aliyun/credentials-go v1.4.3/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
@@ -755,7 +814,6 @@ github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.11-0.20170329064859-445be9e134b2/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
@@ -765,6 +823,8 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I=
github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E=
github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
@@ -813,6 +873,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ=
github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
@@ -1162,8 +1224,9 @@ github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97Dwqy
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0=
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
@@ -1371,6 +1434,8 @@ github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhn
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=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/luoxiner/nacos-sdk-go/v2 v2.2.9-60 h1:FA/azfz2nSkMc1XR8LeqhcAiA/2/sOMcyBGYCTUc+Cs=
github.com/luoxiner/nacos-sdk-go/v2 v2.2.9-60/go.mod h1:9FKXl6FqOiVmm72i8kADtbeK71egyG9y3uRDBg41tpQ=
github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o=
github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk=
@@ -1460,8 +1525,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/nacos-group/nacos-sdk-go v1.0.8 h1:8pEm05Cdav9sQgJSv5kyvlgfz0SzFUUGI3pWX6SiSnM=
github.com/nacos-group/nacos-sdk-go v1.0.8/go.mod h1:hlAPn3UdzlxIlSILAyOXKxjFSvDJ9oLzTJ9hLAK1KzA=
github.com/nacos-group/nacos-sdk-go/v2 v2.1.2 h1:A8GV6j0rw80I6tTKSav/pTpEgNECYXeFvZCsiLBWGnQ=
github.com/nacos-group/nacos-sdk-go/v2 v2.1.2/go.mod h1:ys/1adWeKXXzbNWfRNbaFlX/t6HVLWdpsNDvmoWTw0g=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
@@ -1517,6 +1580,8 @@ github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJ
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.3.0/go.mod h1:4c3sLeE8xjNqehmF5RpAFLPLJxXscc0R4l6Zg0P1tTQ=
github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc h1:Ak86L+yDSOzKFa7WM5bf5itSOo1e3Xh8bm5YCMUXIjQ=
github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
@@ -1560,7 +1625,6 @@ github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3O
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
@@ -1593,7 +1657,6 @@ github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/prometheus/prometheus v0.45.0 h1:O/uG+Nw4kNxx/jDPxmjsSDd+9Ohql6E7ZSY1x5x/0KI=
@@ -1643,8 +1706,9 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0=
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
@@ -1713,6 +1777,9 @@ github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JT
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@@ -1746,6 +1813,7 @@ github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+Seva
github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
@@ -1832,7 +1900,6 @@ 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=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
@@ -1849,7 +1916,6 @@ go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
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.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -1868,9 +1934,12 @@ golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
@@ -1882,8 +1951,13 @@ golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw=
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
@@ -1970,6 +2044,7 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
@@ -2008,8 +2083,13 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -2059,8 +2139,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
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=
@@ -2107,6 +2187,7 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -2156,7 +2237,6 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -2181,8 +2261,13 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.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=
@@ -2195,8 +2280,13 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
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=
@@ -2214,8 +2304,11 @@ golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
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=
@@ -2225,7 +2318,6 @@ golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
@@ -2279,6 +2371,7 @@ golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjs
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
@@ -2646,6 +2739,7 @@ gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=

View File

@@ -1,13 +1,18 @@
apiVersion: v2
appVersion: 2.0.3
appVersion: 2.1.3
description: Helm chart for deploying higress gateways
icon: https://higress.io/img/higress_logo_small.png
home: http://higress.io/
keywords:
- higress
- gateways
- higress
- gateways
name: higress-core
sources:
- http://github.com/alibaba/higress
- http://github.com/alibaba/higress
dependencies:
- condition: global.enableRedis
name: redis
repository: "file://../redis"
version: 0.0.1
type: application
version: 2.0.3
version: 2.1.3

View File

@@ -2,4 +2,4 @@
Installs the core components of cloud-native gateway [Higress](http://higress.io/)
**Note:** It is highly recommended to install the whole package of Higress. Please visit https://higress.io/docs/user/quickstart/ for details.
**Note:** It is highly recommended to install the whole package of Higress. Please visit https://higress.io/docs/user/quickstart/ for details.

View File

@@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/

View File

@@ -0,0 +1,24 @@
apiVersion: v2
name: redis
description: A Helm chart for Kubernetes
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.0.1
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "7.4.0-v3"

View File

@@ -0,0 +1,34 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "redis.name" -}}
{{- .Values.redis.name | default "redis-stack-server" -}}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "redis.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "redis.labels" -}}
helm.sh/chart: {{ include "redis.chart" . }}
{{ include "redis.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "redis.selectorLabels" -}}
app.kubernetes.io/name: {{ include "redis.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

View File

@@ -0,0 +1,10 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "redis.name" . }}
namespace: {{ .Release.Namespace }}
data:
redis-stack.conf: |
{{- if .Values.redis.password }}
requirepass {{ .Values.redis.password }}
{{- end }}

View File

@@ -0,0 +1,16 @@
{{- if .Values.redis.persistence.enabled }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "redis.name" . }}
namespace: {{ .Release.Namespace }}
spec:
accessModes:
{{- range .Values.redis.persistence.accessModes }}
- {{ . | quote }}
{{- end }}
storageClassName: {{ .Values.redis.persistence.storageClass }}
resources:
requests:
storage: {{ .Values.redis.persistence.size | quote }}
{{- end }}

View File

@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "redis.name" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "redis.labels" . | nindent 4 }}
spec:
type: {{ .Values.redis.service.type }}
ports:
- port: {{ .Values.redis.service.port }}
targetPort: 6379
protocol: TCP
selector:
{{- include "redis.selectorLabels" . | nindent 4 }}

View File

@@ -0,0 +1,74 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: {{ include "redis.name" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "redis.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.redis.replicas }}
serviceName: {{ include "redis.name" . }}
selector:
matchLabels:
{{- include "redis.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "redis.selectorLabels" . | nindent 8 }}
spec:
terminationGracePeriodSeconds: 10
{{- with .Values.global.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.global.hub }}/{{ .Values.redis.image | default "redis-stack-server" }}:{{ .Values.redis.tag | default .Chart.AppVersion }}"
{{- if .Values.global.imagePullPolicy }}
imagePullPolicy: {{ .Values.global.imagePullPolicy }}
{{- end }}
ports:
- name: http
containerPort: 6379
protocol: TCP
livenessProbe:
tcpSocket:
port: 6379
initialDelaySeconds: 15
periodSeconds: 10
readinessProbe:
tcpSocket:
port: 6379
initialDelaySeconds: 15
periodSeconds: 10
resources:
{{- toYaml .Values.redis.resources | nindent 12 }}
volumeMounts:
- name: config
mountPath: /redis-stack.conf
subPath: redis-stack.conf
{{- if .Values.redis.persistence.enabled }}
- name: db
mountPath: /data
{{- end }}
{{- with .Values.redis.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.redis.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.redis.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
volumes:
- name: config
configMap:
name: {{ include "redis.name" . }}
{{- if .Values.redis.persistence.enabled }}
- name: db
persistentVolumeClaim:
claimName: {{ include "redis.name" . }}
{{- end }}

View File

@@ -0,0 +1,48 @@
# Default values for redis.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
global:
# -- Specify the image registry and pull policy
hub: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress
# -- Specify image pull policy if default behavior isn't desired.
# Default behavior: latest images will be Always else IfNotPresent.
imagePullPolicy: ""
# -- Specify the image pull secrets
imagePullSecrets: []
redis:
# -- Specify the name
name: redis-stack-server
# -- Specify the image
image: "redis-stack-server"
# -- Specify the tag
tag: "7.4.0-v3"
# -- Specify the number of replicas
replicas: 1
# -- Specify the password, if not set, no password is used
password: ""
# -- Service parameters
service:
# -- Exporter service type
type: ClusterIP
# -- Exporter service port
port: 6379
# -- Specify the resources
resources: {}
# -- NodeSelector Node labels for Redis
nodeSelector: {}
# -- Tolerations for Redis
tolerations: []
# -- Affinity for Redis
affinity: {}
persistence:
# -- Enable persistence on Redis
enabled: false
# -- If defined, storageClassName: <storageClass>
# -- If undefined (the default) or set to null, no storageClassName spec is set, choosing the default provisioner
storageClass: ""
# -- Persistent Volume access modes
accessModes:
- ReadWriteOnce
# -- Persistent Volume size
size: 1Gi

View File

@@ -7,9 +7,6 @@ Rendering the pod template of gateway component.
template:
metadata:
annotations:
{{- if .Values.global.enableHigressIstio }}
"enableHigressIstio": "true"
{{- end }}
{{- if .Values.gateway.podAnnotations }}
{{- toYaml .Values.gateway.podAnnotations | nindent 6 }}
{{- end }}
@@ -18,6 +15,9 @@ template:
{{- with .Values.gateway.revision }}
istio.io/rev: {{ . }}
{{- end }}
{{- with .Values.gateway.podLabels }}
{{- toYaml . | nindent 6 }}
{{- end }}
{{- include "gateway.selectorLabels" . | nindent 6 }}
spec:
{{- with .Values.gateway.imagePullSecrets }}
@@ -45,9 +45,9 @@ template:
- router
- --domain
- $(POD_NAMESPACE).svc.cluster.local
- --proxyLogLevel=warning
- --proxyComponentLogLevel=misc:error
- --log_output_level=all:info
- --proxyLogLevel={{- default "warning" .Values.global.proxy.logLevel }}
- --proxyComponentLogLevel={{- default "misc:error" .Values.global.proxy.componentLogLevel }}
- --log_output_level={{- default "default:info" .Values.global.logging.level }}
- --serviceCluster=higress-gateway
securityContext:
{{- if .Values.gateway.containerSecurityContext }}
@@ -131,7 +131,7 @@ template:
- name: ISTIO_META_REQUESTED_NETWORK_VIEW
value: "{{.}}"
{{- end }}
{{- range $key, $val := .Values.env }}
{{- range $key, $val := .Values.gateway.env }}
- name: {{ $key }}
value: {{ $val | quote }}
{{- end }}
@@ -268,11 +268,7 @@ template:
{{- end }}
- name: higress-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

View File

@@ -9,7 +9,7 @@
accessLogFile: "/dev/stdout"
{{- end }}
ingressControllerMode: "OFF"
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)%","response_code_details":"%RESPONSE_CODE_DETAILS%"}
accessLogFormat: '{"ai_log":"%FILTER_STATE(wasm.ai_log:PLAIN)%","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)%","response_code_details":"%RESPONSE_CODE_DETAILS%"}
'
dnsRefreshRate: 200s
@@ -20,11 +20,7 @@
# When processing a leaf namespace Istio will search for declarations in that namespace first
# and if none are found it will search in the root namespace. Any matching declaration found in the root namespace
# is processed as if it were declared in the leaf namespace.
{{- if .Values.global.enableHigressIstio }}
rootNamespace: {{ .Values.meshConfig.rootNamespace | default .Values.global.istioNamespace }}
{{- else }}
rootNamespace: {{ .Release.Namespace }}
{{- end }}
configSources:
- address: "xds://127.0.0.1:15051"
@@ -85,15 +81,11 @@
discoveryAddress: {{ printf "istiod.%s.svc" .Release.Namespace }}:15012
{{- end }}
{{- else }}
{{- if .Values.global.enableHigressIstio }}
discoveryAddress: {{ printf "istiod.%s.svc" .Values.global.istioNamespace }}:15012
{{- else }}
discoveryAddress: {{ include "controller.name" . }}.{{.Release.Namespace}}.svc:15012
{{- end }}
{{- end }}
proxyStatsMatcher:
inclusionRegexps:
- ".*"
{{ toYaml .Values.global.proxy.proxyStatsMatcher.inclusionRegexps | indent 8 }}
{{- end }}
{{/* We take the mesh config above, defined with individual values.yaml, and merge with .Values.meshConfig */}}

View File

@@ -19,6 +19,9 @@ spec:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- with .Values.controller.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- include "controller.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.controller.imagePullSecrets }}
@@ -96,7 +99,6 @@ spec:
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 }}"
{{- if .Values.global.imagePullPolicy }}
@@ -137,6 +139,14 @@ spec:
periodSeconds: 3
timeoutSeconds: 5
env:
{{- if .Values.global.watchNamespace }}
- name: ISTIO_WATCH_NAMESPACE
value: "{{ .Values.global.watchNamespace }}"
{{- end }}
- name: ENABLE_PUSH_ALL_MCP_CLUSTERS
value: "{{ .Values.global.enablePushAllMCPClusters }}"
- name: PILOT_ENABLE_LDS_CACHE
value: "{{ .Values.global.enableLDSCache }}"
- name: PILOT_ENABLE_QUIC_LISTENERS
value: "true"
- name: VALIDATION_WEBHOOK_CONFIG_NAME
@@ -229,10 +239,8 @@ spec:
value: "false"
- name: PILOT_ENABLE_GATEWAY_API_DEPLOYMENT_CONTROLLER
value: "false"
{{- if not .Values.global.enableHigressIstio }}
- name: CUSTOM_CA_CERT_NAME
value: "higress-ca-root-cert"
{{- end }}
{{- if not (or .Values.global.local .Values.global.kind) }}
resources:
{{- if .Values.pilot.resources }}
@@ -269,7 +277,6 @@ spec:
- name: extracacerts
mountPath: /cacerts
{{- end }}
{{- end }}
{{- with .Values.controller.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
@@ -285,7 +292,6 @@ spec:
volumes:
- name: log
emptyDir: {}
{{- if not .Values.global.enableHigressIstio }}
- name: config
configMap:
name: higress-config
@@ -317,4 +323,3 @@ spec:
configMap:
name: pilot-jwks-extra-cacerts{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}
{{- end }}
{{- end }}

View File

@@ -9,7 +9,6 @@ spec:
type: {{ .Values.controller.service.type }}
ports:
{{- toYaml .Values.controller.ports | nindent 4 }}
{{- if not .Values.global.enableHigressIstio }}
- port: 15010
name: grpc-xds # plaintext
protocol: TCP
@@ -23,6 +22,5 @@ spec:
- port: 15014
name: http-monitoring # prometheus stats
protocol: TCP
{{- end }}
selector:
{{- include "controller.selectorLabels" . | nindent 4 }}

View File

@@ -1,7 +1,8 @@
{{- if eq .Values.gateway.kind "DaemonSet" -}}
{{- $o11y := .Values.global.o11y }}
{{- $unprivilegedPortSupported := true }}
{{- range $index, $node := (lookup "v1" "Node" "default" "").items }}
{{- if eq .Values.gateway.unprivilegedPortSupported nil -}}
{{- $unprivilegedPortSupported := true }}
{{- range $index, $node := (lookup "v1" "Node" "default" "").items }}
{{- $kernelVersion := $node.status.nodeInfo.kernelVersion }}
{{- if $kernelVersion }}
{{- $kernelVersion = regexFind "^(\\d+\\.\\d+\\.\\d+)" $kernelVersion }}
@@ -9,8 +10,9 @@
{{- $unprivilegedPortSupported = false }}
{{- end }}
{{- end }}
{{- end -}}
{{- $_ := set .Values.gateway "unprivilegedPortSupported" $unprivilegedPortSupported -}}
{{- end -}}
{{- $_ := set .Values.gateway "unprivilegedPortSupported" $unprivilegedPortSupported -}}
apiVersion: apps/v1
kind: DaemonSet

View File

@@ -1,6 +1,7 @@
{{- if eq .Values.gateway.kind "Deployment" -}}
{{- $unprivilegedPortSupported := true }}
{{- range $index, $node := (lookup "v1" "Node" "default" "").items }}
{{- if eq .Values.gateway.unprivilegedPortSupported nil -}}
{{- $unprivilegedPortSupported := true }}
{{- range $index, $node := (lookup "v1" "Node" "default" "").items }}
{{- $kernelVersion := $node.status.nodeInfo.kernelVersion }}
{{- if $kernelVersion }}
{{- $kernelVersion = regexFind "^(\\d+\\.\\d+\\.\\d+)" $kernelVersion }}
@@ -8,8 +9,9 @@
{{- $unprivilegedPortSupported = false }}
{{- end }}
{{- end }}
{{- end -}}
{{- $_ := set .Values.gateway "unprivilegedPortSupported" $unprivilegedPortSupported -}}
{{- end -}}
{{- $_ := set .Values.gateway "unprivilegedPortSupported" $unprivilegedPortSupported -}}
apiVersion: apps/v1
kind: Deployment

View File

@@ -3,14 +3,18 @@ global:
enableH3: false
enableIPv6: false
enableProxyProtocol: false
liteMetrics: true
enableLDSCache: false
enablePushAllMCPClusters: true
liteMetrics: false
xdsMaxRecvMsgSize: "104857600"
defaultUpstreamConcurrencyThreshold: 10000
enableSRDS: true
# -- Whether to enable Redis(redis-stack-server) for Higress, default is false.
enableRedis: false
onDemandRDS: false
hostRDSMergeSubset: false
onlyPushRouteCluster: true
# IngressClass filters which ingress resources the higress controller watches.
# -- IngressClass filters which ingress resources the higress controller watches.
# The default ingress class is higress.
# There are some special cases for special ingress class.
# 1. When the ingress class is set as nginx, the higress controller will watch ingress
@@ -18,28 +22,38 @@ global:
# 2. When the ingress class is set empty, the higress controller will watch all ingress
# resources in the k8s cluster.
ingressClass: "higress"
# -- If not empty, Higress Controller will only watch resources in the specified namespace.
# When isolating different business systems using K8s namespace,
# if each namespace requires a standalone gateway instance,
# this parameter can be used to confine the Ingress watching of Higress within the given namespace.
watchNamespace: ""
# -- Whether to disable HTTP/2 in ALPN
disableAlpnH2: false
# -- If true, Higress Controller will update the status field of Ingress resources.
# When migrating from Nginx Ingress, in order to avoid status field of Ingress objects being overwritten,
# this parameter needs to be set to false,
# so Higress won't write the entry IP to the status field of the corresponding Ingress object.
enableStatus: true
# whether to use autoscaling/v2 template for HPA settings
# -- whether to use autoscaling/v2 template for HPA settings
# for internal usage only, not to be configured by users.
autoscalingv2API: true
local: false # When deploying to a local cluster (e.g.: kind cluster), set this to true.
# -- When deploying to a local cluster (e.g.: kind cluster), set this to true.
local: false
kind: false # Deprecated. Please use "global.local" instead. Will be removed later.
# -- If true, Higress Controller will monitor istio resources as well
enableIstioAPI: true
# -- If true, Higress Controller will monitor Gateway API resources as well
enableGatewayAPI: false
# Deprecated
enableHigressIstio: false
# Used to locate istiod.
# -- Used to locate istiod.
istioNamespace: istio-system
# enable pod disruption budget for the control plane, which is used to
# -- enable pod disruption budget for the control plane, which is used to
# ensure Istio control plane components are gradually upgraded or recovered.
defaultPodDisruptionBudget:
enabled: false
# The values aren't mutable due to a current PodDisruptionBudget limitation
# minAvailable: 1
# A minimal set of requested resources to applied to all deployments so that
# -- A minimal set of requested resources to applied to all deployments so that
# Horizontal Pod Autoscaler will be able to function (if set).
# Each component can overwrite these default values by adding its own resources
# block in the relevant section below and setting the desired resources values.
@@ -51,16 +65,16 @@ global:
# cpu: 100m
# memory: 128Mi
# Default hub for Istio images.
# -- Default hub for Istio images.
# Releases are published to docker hub under 'istio' project.
# Dev builds from prow are on gcr.io
hub: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress
# Specify image pull policy if default behavior isn't desired.
# -- Specify image pull policy if default behavior isn't desired.
# Default behavior: latest images will be Always else IfNotPresent.
imagePullPolicy: ""
# ImagePullSecrets for all ServiceAccount, list of secrets in the same namespace
# -- ImagePullSecrets for all ServiceAccount, list of secrets in the same namespace
# to use for pulling any images in pods that reference this ServiceAccount.
# For components that don't use ServiceAccounts (i.e. grafana, servicegraph, tracing)
# ImagePullSecrets will be added to the corresponding Deployment(StatefulSet) objects.
@@ -68,14 +82,14 @@ global:
imagePullSecrets: []
# - private-registry-key
# Enabled by default in master for maximising testing.
# -- Enabled by default in master for maximising testing.
istiod:
enableAnalysis: false
# To output all istio components logs in json format by adding --log_as_json argument to each container argument
# -- To output all istio components logs in json format by adding --log_as_json argument to each container argument
logAsJson: false
# Comma-separated minimum per-scope logging level of messages to output, in the form of <scope>:<level>,<scope>:<level>
# -- Comma-separated minimum per-scope logging level of messages to output, in the form of <scope>:<level>,<scope>:<level>
# The control plane has different scopes depending on component, but can configure default log level across all components
# If empty, default scope and level will be used as configured in code
logging:
@@ -83,11 +97,11 @@ global:
omitSidecarInjectorConfigMap: false
# Whether to restrict the applications namespace the controller manages;
# -- Whether to restrict the applications namespace the controller manages;
# If not set, controller watches all namespaces
oneNamespace: false
# Configure whether Operator manages webhook configurations. The current behavior
# -- Configure whether Operator manages webhook configurations. The current behavior
# of Istiod is to manage its own webhook configurations.
# When this option is set as true, Istio Operator, instead of webhooks, manages the
# webhook configurations. When this option is set as false, webhooks manage their
@@ -106,7 +120,7 @@ global:
#- global
#- "{{ valueOrDefault .DeploymentMeta.Namespace \"default\" }}.global"
# Kubernetes >=v1.11.0 will create two PriorityClass, including system-cluster-critical and
# -- Kubernetes >=v1.11.0 will create two PriorityClass, including system-cluster-critical and
# system-node-critical, it is better to configure this in order to make sure your Istio pods
# will not be killed because of low priority class.
# Refer to https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass
@@ -116,18 +130,18 @@ global:
proxy:
image: proxyv2
# This controls the 'policy' in the sidecar injector.
# -- This controls the 'policy' in the sidecar injector.
autoInject: enabled
# CAUTION: It is important to ensure that all Istio helm charts specify the same clusterDomain value
# -- CAUTION: It is important to ensure that all Istio helm charts specify the same clusterDomain value
# cluster domain. Default value is "cluster.local".
clusterDomain: "cluster.local"
# Per Component log level for proxy, applies to gateways and sidecars. If a component level is
# -- Per Component log level for proxy, applies to gateways and sidecars. If a component level is
# not set, then the global "logLevel" will be used.
componentLogLevel: "misc:error"
# If set, newly injected sidecars will have core dumps enabled.
# -- If set, newly injected sidecars will have core dumps enabled.
enableCoreDump: false
# istio ingress capture allowlist
@@ -136,7 +150,7 @@ global:
excludeInboundPorts: ""
includeInboundPorts: "*"
# istio egress capture allowlist
# -- istio egress capture allowlist
# https://istio.io/docs/tasks/traffic-management/egress.html#calling-external-services-directly
# example: includeIPRanges: "172.30.0.0/16,172.20.0.0/16"
# would only capture egress traffic on those two IP Ranges, all other outbound traffic would
@@ -146,29 +160,29 @@ global:
includeOutboundPorts: ""
excludeOutboundPorts: ""
# Log level for proxy, applies to gateways and sidecars.
# -- Log level for proxy, applies to gateways and sidecars.
# Expected values are: trace|debug|info|warning|error|critical|off
logLevel: warning
#If set to true, istio-proxy container will have privileged securityContext
# -- If set to true, istio-proxy container will have privileged securityContext
privileged: false
# The number of successive failed probes before indicating readiness failure.
# -- The number of successive failed probes before indicating readiness failure.
readinessFailureThreshold: 30
# The number of successive successed probes before indicating readiness success.
# -- The number of successive successed probes before indicating readiness success.
readinessSuccessThreshold: 30
# The initial delay for readiness probes in seconds.
# -- The initial delay for readiness probes in seconds.
readinessInitialDelaySeconds: 1
# The period between readiness probes.
# -- The period between readiness probes.
readinessPeriodSeconds: 2
# The readiness timeout seconds
# -- The readiness timeout seconds
readinessTimeoutSeconds: 3
# Resources for the sidecar.
# -- Resources for the sidecar.
resources:
requests:
cpu: 100m
@@ -177,18 +191,23 @@ global:
cpu: 2000m
memory: 1024Mi
# Default port for Pilot agent health checks. A value of 0 will disable health checking.
# -- Default port for Pilot agent health checks. A value of 0 will disable health checking.
statusPort: 15020
# Specify which tracer to use. One of: lightstep, datadog, stackdriver.
# -- Specify which tracer to use. One of: lightstep, datadog, stackdriver.
# If using stackdriver tracer outside GCP, set env GOOGLE_APPLICATION_CREDENTIALS to the GCP credential file.
tracer: ""
# Controls if sidecar is injected at the front of the container list and blocks the start of the other containers until the proxy is ready
# -- Controls if sidecar is injected at the front of the container list and blocks the start of the other containers until the proxy is ready
holdApplicationUntilProxyStarts: false
# -- Proxy stats name regexps matcher for inclusion
proxyStatsMatcher:
inclusionRegexps:
- ".*"
proxy_init:
# Base name for the proxy_init container, used to configure iptables.
# -- Base name for the proxy_init container, used to configure iptables.
image: proxyv2
resources:
limits:
@@ -198,7 +217,7 @@ global:
cpu: 10m
memory: 10Mi
# configure remote pilot and istiod service and endpoint
# -- configure remote pilot and istiod service and endpoint
remotePilotAddress: ""
##############################################################################################
@@ -206,20 +225,20 @@ global:
# make sure they are consistent across your Istio helm charts #
##############################################################################################
# The customized CA address to retrieve certificates for the pods in the cluster.
# -- The customized CA address to retrieve certificates for the pods in the cluster.
# CSR clients such as the Istio Agent and ingress gateways can use this to specify the CA endpoint.
# If not set explicitly, default to the Istio discovery address.
caAddress: ""
# Configure a remote cluster data plane controlled by an external istiod.
# -- Configure a remote cluster data plane controlled by an external istiod.
# When set to true, istiod is not deployed locally and only a subset of the other
# discovery charts are enabled.
externalIstiod: false
# Configure a remote cluster as the config cluster for an external istiod.
# -- Configure a remote cluster as the config cluster for an external istiod.
configCluster: false
# Configure the policy for validating JWT.
# -- Configure the policy for validating JWT.
# Currently, two options are supported: "third-party-jwt" and "first-party-jwt".
jwtPolicy: "third-party-jwt"
@@ -241,7 +260,7 @@ global:
# of migration TBD, and it may be a disruptive operation to change the Mesh
# ID post-install.
#
# If the mesh admin does not specify a value, Istio will use the value of the
# -- If the mesh admin does not specify a value, Istio will use the value of the
# mesh's Trust Domain. The best practice is to select a proper Trust Domain
# value.
meshID: ""
@@ -275,68 +294,69 @@ global:
#
meshNetworks: {}
# Use the user-specified, secret volume mounted key and certs for Pilot and workloads.
# -- Use the user-specified, secret volume mounted key and certs for Pilot and workloads.
mountMtlsCerts: false
multiCluster:
# Set to true to connect two kubernetes clusters via their respective
# -- Set to true to connect two kubernetes clusters via their respective
# ingressgateway services when pods in each cluster cannot directly
# talk to one another. All clusters should be using Istio mTLS and must
# have a shared root CA for this model to work.
enabled: true
# Should be set to the name of the cluster this installation will run in. This is required for sidecar injection
# -- Should be set to the name of the cluster this installation will run in. This is required for sidecar injection
# to properly label proxies
clusterName: ""
# Network defines the network this cluster belong to. This name
# -- Network defines the network this cluster belong to. This name
# corresponds to the networks in the map of mesh networks.
network: ""
# Configure the certificate provider for control plane communication.
# -- Configure the certificate provider for control plane communication.
# Currently, two providers are supported: "kubernetes" and "istiod".
# As some platforms may not have kubernetes signing APIs,
# Istiod is the default
pilotCertProvider: istiod
sds:
# The JWT token for SDS and the aud field of such JWT. See RFC 7519, section 4.1.3.
# -- The JWT token for SDS and the aud field of such JWT. See RFC 7519, section 4.1.3.
# When a CSR is sent from Istio Agent to the CA (e.g. Istiod), this aud is to make sure the
# JWT is intended for the CA.
token:
aud: istio-ca
sts:
# The service port used by Security Token Service (STS) server to handle token exchange requests.
# -- The service port used by Security Token Service (STS) server to handle token exchange requests.
# Setting this port to a non-zero value enables STS server.
servicePort: 0
# Configuration for each of the supported tracers
# -- Configuration for each of the supported tracers
tracer:
# Configuration for envoy to send trace data to LightStep.
# -- Configuration for envoy to send trace data to LightStep.
# Disabled by default.
# address: the <host>:<port> of the satellite pool
# accessToken: required for sending data to the pool
#
datadog:
# Host:Port for submitting traces to the Datadog agent.
# -- Host:Port for submitting traces to the Datadog agent.
address: "$(HOST_IP):8126"
lightstep:
address: "" # example: lightstep-satellite:443
accessToken: "" # example: abcdefg1234567
# -- example: lightstep-satellite:443
address: ""
# -- example: abcdefg1234567
accessToken: ""
stackdriver:
# enables trace output to stdout.
# -- enables trace output to stdout.
debug: false
# The global default max number of message events per span.
# -- The global default max number of message events per span.
maxNumberOfMessageEvents: 200
# The global default max number of annotation events per span.
# -- The global default max number of annotation events per span.
maxNumberOfAnnotations: 200
# The global default max number of attributes per span.
# -- The global default max number of attributes per span.
maxNumberOfAttributes: 200
# Use the Mesh Control Protocol (MCP) for configuring Istiod. Requires an MCP source.
# -- Use the Mesh Control Protocol (MCP) for configuring Istiod. Requires an MCP source.
useMCP: false
# Observability (o11y) configurations
# -- Observability (o11y) configurations
o11y:
enabled: false
promtail:
@@ -350,7 +370,7 @@ global:
memory: 2Gi
securityContext: {}
# The name of the CA for workload certificates.
# -- The name of the CA for workload certificates.
# For example, when caName=GkeWorkloadCertificate, GKE workload certificates
# will be used as the certificates for workloads.
# The default value is "" and when caName="", the CA will be configured by other
@@ -359,7 +379,7 @@ global:
hub: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress
clusterName: ""
# meshConfig defines runtime configuration of components, including Istiod and istio-agent behavior
# -- meshConfig defines runtime configuration of components, including Istiod and istio-agent behavior
# See https://istio.io/docs/reference/config/istio.mesh.v1alpha1/ for all available options
meshConfig:
enablePrometheusMerge: true
@@ -370,14 +390,13 @@ meshConfig:
# and gradual adoption by setting capture only on specific workloads. It also allows
# VMs to use other DNS options, like dnsmasq or unbound.
# The namespace to treat as the administrative root namespace for Istio configuration.
# -- The namespace to treat as the administrative root namespace for Istio configuration.
# When processing a leaf namespace Istio will search for declarations in that namespace first
# and if none are found it will search in the root namespace. Any matching declaration found in the root namespace
# is processed as if it were declared in the leaf namespace.
rootNamespace:
# The trust domain corresponds to the trust root of a system
# -- The trust domain corresponds to the trust root of a system
# Refer to https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md#21-trust-domain
trustDomain: "cluster.local"
@@ -391,56 +410,57 @@ meshConfig:
gateway:
name: "higress-gateway"
# -- Number of Higress Gateway pods
replicas: 2
image: gateway
# -- Use a `DaemonSet` or `Deployment`
kind: Deployment
# The number of successive failed probes before indicating readiness failure.
# -- The number of successive failed probes before indicating readiness failure.
readinessFailureThreshold: 30
# The number of successive successed probes before indicating readiness success.
# -- The number of successive successed probes before indicating readiness success.
readinessSuccessThreshold: 1
# The initial delay for readiness probes in seconds.
# -- The initial delay for readiness probes in seconds.
readinessInitialDelaySeconds: 1
# The period between readiness probes.
# -- The period between readiness probes.
readinessPeriodSeconds: 2
# The readiness timeout seconds
# -- The readiness timeout seconds
readinessTimeoutSeconds: 3
hub: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress
tag: ""
# revision declares which revision this gateway is a part of
# -- revision declares which revision this gateway is a part of
revision: ""
rbac:
# If enabled, roles will be created to enable accessing certificates from Gateways. This is not needed
# -- If enabled, roles will be created to enable accessing certificates from Gateways. This is not needed
# when using http://gateway-api.org/.
enabled: true
serviceAccount:
# If set, a service account will be created. Otherwise, the default is used
# -- If set, a service account will be created. Otherwise, the default is used
create: true
# Annotations to add to the service account
# -- Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# -- The name of the service account to use.
# If not set, the release name is used
name: ""
# Pod environment variables
# -- Pod environment variables
env: {}
httpPort: 80
httpsPort: 443
hostNetwork: false
# Labels to apply to all resources
# -- Labels to apply to all resources
labels: {}
# Annotations to apply to all resources
# -- Annotations to apply to all resources
annotations: {}
podAnnotations:
@@ -449,14 +469,18 @@ gateway:
prometheus.io/path: "/stats/prometheus"
sidecar.istio.io/inject: "false"
# Define the security context for the pod.
# -- Labels to apply to the pod
podLabels: {}
# -- Define the security context for the pod.
# If unset, this will be automatically set to the minimum privileges required to bind to port 80 and 443.
# On Kubernetes 1.22+, this only requires the `net.ipv4.ip_unprivileged_port_start` sysctl.
securityContext: ~
containerSecurityContext: ~
unprivilegedPortSupported: ~
service:
# Type of service. Set to "None" to disable the service entirely
# -- Type of service. Set to "None" to disable the service entirely
type: LoadBalancer
ports:
- name: http2
@@ -474,6 +498,7 @@ gateway:
externalTrafficPolicy: ""
rollingMaxSurge: 100%
# -- If global.local is true, the default value is 100%, otherwise it is 25%
rollingMaxUnavailable: 25%
resources:
@@ -496,28 +521,29 @@ gateway:
affinity: {}
# If specified, the gateway will act as a network gateway for the given network.
# -- If specified, the gateway will act as a network gateway for the given network.
networkGateway: ""
metrics:
# If true, create PodMonitor or VMPodScrape for gateway
# -- If true, create PodMonitor or VMPodScrape for gateway
enabled: false
# provider group name for CustomResourceDefinition, can be monitoring.coreos.com or operator.victoriametrics.com
# -- provider group name for CustomResourceDefinition, can be monitoring.coreos.com or operator.victoriametrics.com
provider: monitoring.coreos.com
interval: ""
scrapeTimeout: ""
honorLabels: false
# for monitoring.coreos.com/v1.PodMonitor
# -- for monitoring.coreos.com/v1.PodMonitor
metricRelabelings: []
relabelings: []
# for operator.victoriametrics.com/v1beta1.VMPodScrape
# -- for operator.victoriametrics.com/v1beta1.VMPodScrape
metricRelabelConfigs: []
relabelConfigs: []
# some more raw podMetricsEndpoints spec
# -- some more raw podMetricsEndpoints spec
rawSpec: {}
controller:
name: "higress-controller"
# -- Number of Higress Controller pods
replicas: 1
image: higress
@@ -528,12 +554,12 @@ controller:
labels: {}
probe:
{
httpGet: { path: /ready, port: 8888 },
initialDelaySeconds: 1,
periodSeconds: 3,
timeoutSeconds: 5,
}
httpGet:
path: /ready
port: 8888
initialDelaySeconds: 1
periodSeconds: 3
timeoutSeconds: 5
imagePullSecrets: []
@@ -541,31 +567,36 @@ controller:
create: true
serviceAccount:
# Specifies whether a service account should be created
# -- Specifies whether a service account should be created
create: true
# Annotations to add to the service account
# -- Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
# -- The name of the service account to use.
# -- If not set and create is true, a name is generated using the fullname template
name: ""
podAnnotations: {}
# -- Labels to apply to the pod
podLabels: {}
podSecurityContext:
{}
# fsGroup: 2000
# fsGroup: 2000
ports:
[
{ "name": "http", "protocol": "TCP", "port": 8888, "targetPort": 8888 },
{
"name": "http-solver",
"protocol": "TCP",
"port": 8889,
"targetPort": 8889,
},
{ "name": "grpc", "protocol": "TCP", "port": 15051, "targetPort": 15051 },
]
- name: http
protocol: TCP
port: 8888
targetPort: 8888
- name: http-solver
protocol: TCP
port: 8889
targetPort: 8889
- name: grpc
protocol: TCP
port: 15051
targetPort: 15051
service:
type: ClusterIP
@@ -575,9 +606,9 @@ controller:
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
resources:
requests:
@@ -602,7 +633,7 @@ controller:
enabled: true
email: ""
## Discovery Settings
## -- Discovery Settings
pilot:
autoscaleEnabled: false
autoscaleMin: 1
@@ -614,11 +645,11 @@ pilot:
hub: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress
tag: ""
# Can be a full hub/image:tag
# -- Can be a full hub/image:tag
image: pilot
traceSampling: 1.0
# Resources for a small pilot install
# -- Resources for a small pilot install
resources:
requests:
cpu: 500m
@@ -633,21 +664,21 @@ pilot:
cpu:
targetAverageUtilization: 80
# if protocol sniffing is enabled for outbound
# -- if protocol sniffing is enabled for outbound
enableProtocolSniffingForOutbound: true
# if protocol sniffing is enabled for inbound
# -- if protocol sniffing is enabled for inbound
enableProtocolSniffingForInbound: true
nodeSelector: {}
podAnnotations: {}
serviceAnnotations: {}
# You can use jwksResolverExtraRootCA to provide a root certificate
# -- You can use jwksResolverExtraRootCA to provide a root certificate
# in PEM format. This will then be trusted by pilot when resolving
# JWKS URIs.
jwksResolverExtraRootCA: ""
# This is used to set the source of configuration for
# -- This is used to set the source of configuration for
# the associated address in configSource, if nothing is specified
# the default MCP is assumed.
configSource:
@@ -655,21 +686,21 @@ pilot:
plugins: []
# The following is used to limit how long a sidecar can be connected
# -- The following is used to limit how long a sidecar can be connected
# to a pilot. It balances out load across pilot instances at the cost of
# increasing system churn.
keepaliveMaxServerConnectionAge: 30m
# Additional labels to apply to the deployment.
# -- Additional labels to apply to the deployment.
deploymentLabels: {}
## Mesh config settings
# Install the mesh config map, generated from values.yaml.
# -- Install the mesh config map, generated from values.yaml.
# If false, pilot wil use default values (by default) or user-supplied values.
configMap: true
# Additional labels to apply on the pod level for monitoring and logging configuration.
# -- Additional labels to apply on the pod level for monitoring and logging configuration.
podLabels: {}
# Tracing config settings
@@ -685,7 +716,7 @@ tracing:
# service: ""
# port: 9411
# Downstream config settings
# -- Downstream config settings
downstream:
idleTimeout: 180
maxRequestHeadersKb: 60
@@ -696,7 +727,44 @@ downstream:
initialConnectionWindowSize: 1048576
routeTimeout: 0
# Upstream config settings
# -- Upstream config settings
upstream:
idleTimeout: 10
connectionBufferLimits: 10485760
redis:
redis:
name: redis-stack-server
# -- Specify the image
image: "redis-stack-server"
# -- Specify the tag
tag: "7.4.0-v3"
# -- Specify the number of replicas
replicas: 1
# -- Specify the password, if not set, no password is used
password: ""
# -- Service parameters
service:
# -- Exporter service type
type: ClusterIP
# -- Exporter service port
port: 6379
# -- Specify the resources
resources: {}
# -- NodeSelector Node labels for Redis
nodeSelector: {}
# -- Tolerations for Redis
tolerations: []
# -- Affinity for Redis
affinity: {}
persistence:
# -- Enable persistence on Redis, default is false
enabled: false
# -- If defined, storageClassName: <storageClass>
# -- If undefined (the default) or set to null, no storageClassName spec is set, choosing the default provisioner
storageClass: ""
# -- Persistent Volume access modes
accessModes:
- ReadWriteOnce
# -- Persistent Volume size
size: 1Gi

View File

@@ -1,9 +1,9 @@
dependencies:
- name: higress-core
repository: file://../core
version: 2.0.3
version: 2.1.3
- name: higress-console
repository: https://higress.io/helm-charts/
version: 1.4.5
digest: sha256:74b772113264168483961f5d0424459fd7359adc509a4b50400229581d7cddbf
generated: "2024-11-08T14:06:51.871719+08:00"
version: 2.1.3
digest: sha256:c7307d5398c3c1178758c5372bd1aa4cb8dee7beeab3832d3e9ce0a04d1adc23
generated: "2025-05-09T15:29:50.616179+08:00"

View File

@@ -1,5 +1,5 @@
apiVersion: v2
appVersion: 2.0.3
appVersion: 2.1.3
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: 2.0.3
version: 2.1.3
- name: higress-console
repository: "https://higress.io/helm-charts/"
version: 1.4.5
version: 2.1.3
type: application
version: 2.0.3
version: 2.1.3

View File

@@ -1,57 +1,298 @@
# Higress Helm Chart
Installs the cloud-native gateway [Higress](http://higress.io/)
## Get Repo Info
```console
helm repo add higress.io https://higress.io/helm-charts
helm repo update
```
_See [helm repo](https://helm.sh/docs/helm/helm_repo/) for command documentation._
## Installing the Chart
To install the chart with the release name `higress`:
```console
helm install higress -n higress-system higress.io/higress --create-namespace --render-subchart-notes
```
## Uninstalling the Chart
To uninstall/delete the higress deployment:
```console
helm delete higress -n higress-system
```
The command removes all the Kubernetes components associated with the chart and deletes the release.
## Configuration
| **Parameter** | **Description** | **Default** |
|---|---|---|
| **Global Parameters** | | |
| global.local | Set to `true` if installing to a local K8s cluster (e.g.: Kind, Rancher Desktop, etc.) | false |
| global.ingressClass | [IngressClass](https://kubernetes.io/zh-cn/docs/concepts/services-networking/ingress/#ingress-class) which is used to filter Ingress resources Higress Controller watches.<br />If there are multiple gateway instances deployed in the cluster, this parameter can be used to distinguish the scope of each gateway instance.<br />There are some special cases for special IngressClass values:<br />1. If set to "nginx", Higress Controller will watch Ingress resources with the `nginx` IngressClass or without any Ingress class.<br />2. If set to empty, Higress Controller will watch all Ingress resources in the K8s cluster. | higress |
| global.watchNamespace | If not empty, Higress Controller will only watch resources in the specified namespace. When isolating different business systems using K8s namespace, if each namespace requires a standalone gateway instance, this parameter can be used to confine the Ingress watching of Higress within the given namespace. | "" |
| global.disableAlpnH2 | Whether to disable HTTP/2 in ALPN | true |
| global.enableStatus | If `true`, Higress Controller will update the `status` field of Ingress resources.<br />When migrating from Nginx Ingress, in order to avoid `status` field of Ingress objects being overwritten, this parameter needs to be set to false, so Higress won't write the entry IP to the `status` field of the corresponding Ingress object. | true |
| global.enableIstioAPI | If `true`, Higress Controller will monitor istio resources as well | false |
| global.enableGatewayAPI | If `true`, Higress Controller will monitor Gateway API resources as well | false |
| global.istioNamespace | The namespace istio is installed to | istio-system |
| **Core Paramters** | | |
| higress-core.gateway.replicas | Number of Higress Gateway pods | 2 |
| higress-core.controller.replicas | Number of Higress Controller pods | 1 |
| **Console Paramters** | | |
| higress-console.replicaCount | Number of Higress Console pods | 1 |
| higress-console.service.type | K8s service type used by Higress Console | ClusterIP |
| higress-console.domain | Domain used to access Higress Console | console.higress.io |
| higress-console.tlsSecretName | Name of Secret resource used by TLS connections. | "" |
| higress-console.web.login.prompt | Prompt message to be displayed on the login page | "" |
| higress-console.admin.password.value | If not empty, the admin password will be configured to the specified value. | "" |
| higress-console.admin.password.length | The length of random admin password generated during installation. Only works when `higress-console.admin.password.value` is not set. | 8 |
| higress-console.o11y.enabled | If `true`, o11y suite (Grafana + Promethues) will be installed. | false |
| higress-console.pvc.rwxSupported | Set to `false` when installing to a standard K8s cluster and the target cluster doesn't support the ReadWriteMany access mode of PersistentVolumeClaim. | true |
## Higress for Kubernetes
Higress is a cloud-native api gateway based on Alibaba's internal gateway practices.
Powered by Istio and 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.
## Setup Repo Info
```console
helm repo add higress.io https://higress.io/helm-charts
helm repo update
```
## Install
To install the chart with the release name `higress`:
```console
helm install higress -n higress-system higress.io/higress --create-namespace --render-subchart-notes
```
## Uninstall
To uninstall/delete the higress deployment:
```console
helm delete higress -n higress-system
```
The command removes all the Kubernetes components associated with the chart and deletes the release.
## Parameters
## Values
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| clusterName | string | `""` | |
| controller.affinity | object | `{}` | |
| controller.automaticHttps.email | string | `""` | |
| controller.automaticHttps.enabled | bool | `true` | |
| controller.autoscaling.enabled | bool | `false` | |
| controller.autoscaling.maxReplicas | int | `5` | |
| controller.autoscaling.minReplicas | int | `1` | |
| controller.autoscaling.targetCPUUtilizationPercentage | int | `80` | |
| controller.env | object | `{}` | |
| controller.hub | string | `"higress-registry.cn-hangzhou.cr.aliyuncs.com/higress"` | |
| controller.image | string | `"higress"` | |
| controller.imagePullSecrets | list | `[]` | |
| controller.labels | object | `{}` | |
| controller.name | string | `"higress-controller"` | |
| controller.nodeSelector | object | `{}` | |
| controller.podAnnotations | object | `{}` | |
| controller.podLabels | object | `{}` | Labels to apply to the pod |
| controller.podSecurityContext | object | `{}` | |
| controller.ports[0].name | string | `"http"` | |
| controller.ports[0].port | int | `8888` | |
| controller.ports[0].protocol | string | `"TCP"` | |
| controller.ports[0].targetPort | int | `8888` | |
| controller.ports[1].name | string | `"http-solver"` | |
| controller.ports[1].port | int | `8889` | |
| controller.ports[1].protocol | string | `"TCP"` | |
| controller.ports[1].targetPort | int | `8889` | |
| controller.ports[2].name | string | `"grpc"` | |
| controller.ports[2].port | int | `15051` | |
| controller.ports[2].protocol | string | `"TCP"` | |
| controller.ports[2].targetPort | int | `15051` | |
| controller.probe.httpGet.path | string | `"/ready"` | |
| controller.probe.httpGet.port | int | `8888` | |
| controller.probe.initialDelaySeconds | int | `1` | |
| controller.probe.periodSeconds | int | `3` | |
| controller.probe.timeoutSeconds | int | `5` | |
| controller.rbac.create | bool | `true` | |
| controller.replicas | int | `1` | Number of Higress Controller pods |
| controller.resources.limits.cpu | string | `"1000m"` | |
| controller.resources.limits.memory | string | `"2048Mi"` | |
| controller.resources.requests.cpu | string | `"500m"` | |
| controller.resources.requests.memory | string | `"2048Mi"` | |
| controller.securityContext | object | `{}` | |
| controller.service.type | string | `"ClusterIP"` | |
| controller.serviceAccount.annotations | object | `{}` | Annotations to add to the service account |
| controller.serviceAccount.create | bool | `true` | Specifies whether a service account should be created |
| controller.serviceAccount.name | string | `""` | If not set and create is true, a name is generated using the fullname template |
| controller.tag | string | `""` | |
| controller.tolerations | list | `[]` | |
| downstream | object | `{"connectionBufferLimits":32768,"http2":{"initialConnectionWindowSize":1048576,"initialStreamWindowSize":65535,"maxConcurrentStreams":100},"idleTimeout":180,"maxRequestHeadersKb":60,"routeTimeout":0}` | Downstream config settings |
| gateway.affinity | object | `{}` | |
| gateway.annotations | object | `{}` | Annotations to apply to all resources |
| gateway.autoscaling.enabled | bool | `false` | |
| gateway.autoscaling.maxReplicas | int | `5` | |
| gateway.autoscaling.minReplicas | int | `1` | |
| gateway.autoscaling.targetCPUUtilizationPercentage | int | `80` | |
| gateway.containerSecurityContext | string | `nil` | |
| gateway.env | object | `{}` | Pod environment variables |
| gateway.hostNetwork | bool | `false` | |
| gateway.httpPort | int | `80` | |
| gateway.httpsPort | int | `443` | |
| gateway.hub | string | `"higress-registry.cn-hangzhou.cr.aliyuncs.com/higress"` | |
| gateway.image | string | `"gateway"` | |
| gateway.kind | string | `"Deployment"` | Use a `DaemonSet` or `Deployment` |
| gateway.labels | object | `{}` | Labels to apply to all resources |
| gateway.metrics.enabled | bool | `false` | If true, create PodMonitor or VMPodScrape for gateway |
| gateway.metrics.honorLabels | bool | `false` | |
| gateway.metrics.interval | string | `""` | |
| gateway.metrics.metricRelabelConfigs | list | `[]` | for operator.victoriametrics.com/v1beta1.VMPodScrape |
| gateway.metrics.metricRelabelings | list | `[]` | for monitoring.coreos.com/v1.PodMonitor |
| gateway.metrics.provider | string | `"monitoring.coreos.com"` | provider group name for CustomResourceDefinition, can be monitoring.coreos.com or operator.victoriametrics.com |
| gateway.metrics.rawSpec | object | `{}` | some more raw podMetricsEndpoints spec |
| gateway.metrics.relabelConfigs | list | `[]` | |
| gateway.metrics.relabelings | list | `[]` | |
| gateway.metrics.scrapeTimeout | string | `""` | |
| gateway.name | string | `"higress-gateway"` | |
| gateway.networkGateway | string | `""` | If specified, the gateway will act as a network gateway for the given network. |
| gateway.nodeSelector | object | `{}` | |
| gateway.podAnnotations."prometheus.io/path" | string | `"/stats/prometheus"` | |
| gateway.podAnnotations."prometheus.io/port" | string | `"15020"` | |
| gateway.podAnnotations."prometheus.io/scrape" | string | `"true"` | |
| gateway.podAnnotations."sidecar.istio.io/inject" | string | `"false"` | |
| gateway.podLabels | object | `{}` | Labels to apply to the pod |
| gateway.rbac.enabled | bool | `true` | If enabled, roles will be created to enable accessing certificates from Gateways. This is not needed when using http://gateway-api.org/. |
| gateway.readinessFailureThreshold | int | `30` | The number of successive failed probes before indicating readiness failure. |
| gateway.readinessInitialDelaySeconds | int | `1` | The initial delay for readiness probes in seconds. |
| gateway.readinessPeriodSeconds | int | `2` | The period between readiness probes. |
| gateway.readinessSuccessThreshold | int | `1` | The number of successive successed probes before indicating readiness success. |
| gateway.readinessTimeoutSeconds | int | `3` | The readiness timeout seconds |
| gateway.replicas | int | `2` | Number of Higress Gateway pods |
| gateway.resources.limits.cpu | string | `"2000m"` | |
| gateway.resources.limits.memory | string | `"2048Mi"` | |
| gateway.resources.requests.cpu | string | `"2000m"` | |
| gateway.resources.requests.memory | string | `"2048Mi"` | |
| gateway.revision | string | `""` | revision declares which revision this gateway is a part of |
| gateway.rollingMaxSurge | string | `"100%"` | |
| gateway.rollingMaxUnavailable | string | `"25%"` | If global.local is true, the default value is 100%, otherwise it is 25% |
| gateway.securityContext | string | `nil` | Define the security context for the pod. If unset, this will be automatically set to the minimum privileges required to bind to port 80 and 443. On Kubernetes 1.22+, this only requires the `net.ipv4.ip_unprivileged_port_start` sysctl. |
| gateway.service.annotations | object | `{}` | |
| gateway.service.externalTrafficPolicy | string | `""` | |
| gateway.service.loadBalancerClass | string | `""` | |
| gateway.service.loadBalancerIP | string | `""` | |
| gateway.service.loadBalancerSourceRanges | list | `[]` | |
| gateway.service.ports[0].name | string | `"http2"` | |
| gateway.service.ports[0].port | int | `80` | |
| gateway.service.ports[0].protocol | string | `"TCP"` | |
| gateway.service.ports[0].targetPort | int | `80` | |
| gateway.service.ports[1].name | string | `"https"` | |
| gateway.service.ports[1].port | int | `443` | |
| gateway.service.ports[1].protocol | string | `"TCP"` | |
| gateway.service.ports[1].targetPort | int | `443` | |
| gateway.service.type | string | `"LoadBalancer"` | Type of service. Set to "None" to disable the service entirely |
| gateway.serviceAccount.annotations | object | `{}` | Annotations to add to the service account |
| gateway.serviceAccount.create | bool | `true` | If set, a service account will be created. Otherwise, the default is used |
| gateway.serviceAccount.name | string | `""` | The name of the service account to use. If not set, the release name is used |
| gateway.tag | string | `""` | |
| gateway.tolerations | list | `[]` | |
| gateway.unprivilegedPortSupported | string | `nil` | |
| global.autoscalingv2API | bool | `true` | whether to use autoscaling/v2 template for HPA settings for internal usage only, not to be configured by users. |
| global.caAddress | string | `""` | The customized CA address to retrieve certificates for the pods in the cluster. CSR clients such as the Istio Agent and ingress gateways can use this to specify the CA endpoint. If not set explicitly, default to the Istio discovery address. |
| global.caName | string | `""` | The name of the CA for workload certificates. For example, when caName=GkeWorkloadCertificate, GKE workload certificates will be used as the certificates for workloads. The default value is "" and when caName="", the CA will be configured by other mechanisms (e.g., environmental variable CA_PROVIDER). |
| global.configCluster | bool | `false` | Configure a remote cluster as the config cluster for an external istiod. |
| global.defaultPodDisruptionBudget | object | `{"enabled":false}` | enable pod disruption budget for the control plane, which is used to ensure Istio control plane components are gradually upgraded or recovered. |
| global.defaultResources | object | `{"requests":{"cpu":"10m"}}` | A minimal set of requested resources to applied to all deployments so that Horizontal Pod Autoscaler will be able to function (if set). Each component can overwrite these default values by adding its own resources block in the relevant section below and setting the desired resources values. |
| global.defaultUpstreamConcurrencyThreshold | int | `10000` | |
| global.disableAlpnH2 | bool | `false` | Whether to disable HTTP/2 in ALPN |
| global.enableGatewayAPI | bool | `false` | If true, Higress Controller will monitor Gateway API resources as well |
| global.enableH3 | bool | `false` | |
| global.enableIPv6 | bool | `false` | |
| global.enableIstioAPI | bool | `true` | If true, Higress Controller will monitor istio resources as well |
| global.enableLDSCache | bool | `false` | |
| global.enableProxyProtocol | bool | `false` | |
| global.enablePushAllMCPClusters | bool | `true` | |
| global.enableRedis | bool | `false` | Whether to enable Redis(redis-stack-server) for Higress, default is false. |
| global.enableSRDS | bool | `true` | |
| global.enableStatus | bool | `true` | If true, Higress Controller will update the status field of Ingress resources. When migrating from Nginx Ingress, in order to avoid status field of Ingress objects being overwritten, this parameter needs to be set to false, so Higress won't write the entry IP to the status field of the corresponding Ingress object. |
| global.externalIstiod | bool | `false` | Configure a remote cluster data plane controlled by an external istiod. When set to true, istiod is not deployed locally and only a subset of the other discovery charts are enabled. |
| global.hostRDSMergeSubset | bool | `false` | |
| global.hub | string | `"higress-registry.cn-hangzhou.cr.aliyuncs.com/higress"` | Default hub for Istio images. Releases are published to docker hub under 'istio' project. Dev builds from prow are on gcr.io |
| global.imagePullPolicy | string | `""` | Specify image pull policy if default behavior isn't desired. Default behavior: latest images will be Always else IfNotPresent. |
| global.imagePullSecrets | list | `[]` | ImagePullSecrets for all ServiceAccount, list of secrets in the same namespace to use for pulling any images in pods that reference this ServiceAccount. For components that don't use ServiceAccounts (i.e. grafana, servicegraph, tracing) ImagePullSecrets will be added to the corresponding Deployment(StatefulSet) objects. Must be set for any cluster configured with private docker registry. |
| global.ingressClass | string | `"higress"` | IngressClass filters which ingress resources the higress controller watches. The default ingress class is higress. There are some special cases for special ingress class. 1. When the ingress class is set as nginx, the higress controller will watch ingress resources with the nginx ingress class or without any ingress class. 2. When the ingress class is set empty, the higress controller will watch all ingress resources in the k8s cluster. |
| global.istioNamespace | string | `"istio-system"` | Used to locate istiod. |
| global.istiod | object | `{"enableAnalysis":false}` | Enabled by default in master for maximising testing. |
| global.jwtPolicy | string | `"third-party-jwt"` | Configure the policy for validating JWT. Currently, two options are supported: "third-party-jwt" and "first-party-jwt". |
| global.kind | bool | `false` | |
| global.liteMetrics | bool | `false` | |
| global.local | bool | `false` | When deploying to a local cluster (e.g.: kind cluster), set this to true. |
| global.logAsJson | bool | `false` | |
| global.logging | object | `{"level":"default:info"}` | Comma-separated minimum per-scope logging level of messages to output, in the form of <scope>:<level>,<scope>:<level> The control plane has different scopes depending on component, but can configure default log level across all components If empty, default scope and level will be used as configured in code |
| global.meshID | string | `""` | If the mesh admin does not specify a value, Istio will use the value of the mesh's Trust Domain. The best practice is to select a proper Trust Domain value. |
| global.meshNetworks | object | `{}` | |
| global.mountMtlsCerts | bool | `false` | Use the user-specified, secret volume mounted key and certs for Pilot and workloads. |
| global.multiCluster.clusterName | string | `""` | Should be set to the name of the cluster this installation will run in. This is required for sidecar injection to properly label proxies |
| global.multiCluster.enabled | bool | `true` | Set to true to connect two kubernetes clusters via their respective ingressgateway services when pods in each cluster cannot directly talk to one another. All clusters should be using Istio mTLS and must have a shared root CA for this model to work. |
| global.network | string | `""` | Network defines the network this cluster belong to. This name corresponds to the networks in the map of mesh networks. |
| global.o11y | object | `{"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":{}}}` | Observability (o11y) configurations |
| global.omitSidecarInjectorConfigMap | bool | `false` | |
| global.onDemandRDS | bool | `false` | |
| global.oneNamespace | bool | `false` | Whether to restrict the applications namespace the controller manages; If not set, controller watches all namespaces |
| global.onlyPushRouteCluster | bool | `true` | |
| global.operatorManageWebhooks | bool | `false` | Configure whether Operator manages webhook configurations. The current behavior of Istiod is to manage its own webhook configurations. When this option is set as true, Istio Operator, instead of webhooks, manages the webhook configurations. When this option is set as false, webhooks manage their own webhook configurations. |
| global.pilotCertProvider | string | `"istiod"` | Configure the certificate provider for control plane communication. Currently, two providers are supported: "kubernetes" and "istiod". As some platforms may not have kubernetes signing APIs, Istiod is the default |
| global.priorityClassName | string | `""` | Kubernetes >=v1.11.0 will create two PriorityClass, including system-cluster-critical and system-node-critical, it is better to configure this in order to make sure your Istio pods will not be killed because of low priority class. Refer to https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass for more detail. |
| global.proxy.autoInject | string | `"enabled"` | This controls the 'policy' in the sidecar injector. |
| global.proxy.clusterDomain | string | `"cluster.local"` | CAUTION: It is important to ensure that all Istio helm charts specify the same clusterDomain value cluster domain. Default value is "cluster.local". |
| global.proxy.componentLogLevel | string | `"misc:error"` | Per Component log level for proxy, applies to gateways and sidecars. If a component level is not set, then the global "logLevel" will be used. |
| global.proxy.enableCoreDump | bool | `false` | If set, newly injected sidecars will have core dumps enabled. |
| global.proxy.excludeIPRanges | string | `""` | |
| global.proxy.excludeInboundPorts | string | `""` | |
| global.proxy.excludeOutboundPorts | string | `""` | |
| global.proxy.holdApplicationUntilProxyStarts | bool | `false` | Controls if sidecar is injected at the front of the container list and blocks the start of the other containers until the proxy is ready |
| global.proxy.image | string | `"proxyv2"` | |
| global.proxy.includeIPRanges | string | `"*"` | istio egress capture allowlist https://istio.io/docs/tasks/traffic-management/egress.html#calling-external-services-directly example: includeIPRanges: "172.30.0.0/16,172.20.0.0/16" would only capture egress traffic on those two IP Ranges, all other outbound traffic would be allowed by the sidecar |
| global.proxy.includeInboundPorts | string | `"*"` | |
| global.proxy.includeOutboundPorts | string | `""` | |
| global.proxy.logLevel | string | `"warning"` | Log level for proxy, applies to gateways and sidecars. Expected values are: trace|debug|info|warning|error|critical|off |
| global.proxy.privileged | bool | `false` | If set to true, istio-proxy container will have privileged securityContext |
| global.proxy.proxyStatsMatcher | object | `{"inclusionRegexps":[".*"]}` | Proxy stats name regexps matcher for inclusion |
| global.proxy.readinessFailureThreshold | int | `30` | The number of successive failed probes before indicating readiness failure. |
| global.proxy.readinessInitialDelaySeconds | int | `1` | The initial delay for readiness probes in seconds. |
| global.proxy.readinessPeriodSeconds | int | `2` | The period between readiness probes. |
| global.proxy.readinessSuccessThreshold | int | `30` | The number of successive successed probes before indicating readiness success. |
| global.proxy.readinessTimeoutSeconds | int | `3` | The readiness timeout seconds |
| global.proxy.resources | object | `{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"100m","memory":"128Mi"}}` | Resources for the sidecar. |
| global.proxy.statusPort | int | `15020` | Default port for Pilot agent health checks. A value of 0 will disable health checking. |
| global.proxy.tracer | string | `""` | Specify which tracer to use. One of: lightstep, datadog, stackdriver. If using stackdriver tracer outside GCP, set env GOOGLE_APPLICATION_CREDENTIALS to the GCP credential file. |
| global.proxy_init.image | string | `"proxyv2"` | Base name for the proxy_init container, used to configure iptables. |
| global.proxy_init.resources.limits.cpu | string | `"2000m"` | |
| global.proxy_init.resources.limits.memory | string | `"1024Mi"` | |
| global.proxy_init.resources.requests.cpu | string | `"10m"` | |
| global.proxy_init.resources.requests.memory | string | `"10Mi"` | |
| global.remotePilotAddress | string | `""` | configure remote pilot and istiod service and endpoint |
| global.sds.token | object | `{"aud":"istio-ca"}` | The JWT token for SDS and the aud field of such JWT. See RFC 7519, section 4.1.3. When a CSR is sent from Istio Agent to the CA (e.g. Istiod), this aud is to make sure the JWT is intended for the CA. |
| global.sts.servicePort | int | `0` | The service port used by Security Token Service (STS) server to handle token exchange requests. Setting this port to a non-zero value enables STS server. |
| global.tracer | object | `{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":""},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200}}` | Configuration for each of the supported tracers |
| global.tracer.datadog | object | `{"address":"$(HOST_IP):8126"}` | Configuration for envoy to send trace data to LightStep. Disabled by default. address: the <host>:<port> of the satellite pool accessToken: required for sending data to the pool |
| global.tracer.datadog.address | string | `"$(HOST_IP):8126"` | Host:Port for submitting traces to the Datadog agent. |
| global.tracer.lightstep.accessToken | string | `""` | example: abcdefg1234567 |
| global.tracer.lightstep.address | string | `""` | example: lightstep-satellite:443 |
| global.tracer.stackdriver.debug | bool | `false` | enables trace output to stdout. |
| global.tracer.stackdriver.maxNumberOfAnnotations | int | `200` | The global default max number of annotation events per span. |
| global.tracer.stackdriver.maxNumberOfAttributes | int | `200` | The global default max number of attributes per span. |
| global.tracer.stackdriver.maxNumberOfMessageEvents | int | `200` | The global default max number of message events per span. |
| global.useMCP | bool | `false` | Use the Mesh Control Protocol (MCP) for configuring Istiod. Requires an MCP source. |
| global.watchNamespace | string | `""` | If not empty, Higress Controller will only watch resources in the specified namespace. When isolating different business systems using K8s namespace, if each namespace requires a standalone gateway instance, this parameter can be used to confine the Ingress watching of Higress within the given namespace. |
| global.xdsMaxRecvMsgSize | string | `"104857600"` | |
| hub | string | `"higress-registry.cn-hangzhou.cr.aliyuncs.com/higress"` | |
| meshConfig | object | `{"enablePrometheusMerge":true,"rootNamespace":null,"trustDomain":"cluster.local"}` | meshConfig defines runtime configuration of components, including Istiod and istio-agent behavior See https://istio.io/docs/reference/config/istio.mesh.v1alpha1/ for all available options |
| meshConfig.rootNamespace | string | `nil` | The namespace to treat as the administrative root namespace for Istio configuration. When processing a leaf namespace Istio will search for declarations in that namespace first and if none are found it will search in the root namespace. Any matching declaration found in the root namespace is processed as if it were declared in the leaf namespace. |
| meshConfig.trustDomain | string | `"cluster.local"` | The trust domain corresponds to the trust root of a system Refer to https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md#21-trust-domain |
| pilot.autoscaleEnabled | bool | `false` | |
| pilot.autoscaleMax | int | `5` | |
| pilot.autoscaleMin | int | `1` | |
| pilot.configMap | bool | `true` | Install the mesh config map, generated from values.yaml. If false, pilot wil use default values (by default) or user-supplied values. |
| pilot.configSource | object | `{"subscribedResources":[]}` | This is used to set the source of configuration for the associated address in configSource, if nothing is specified the default MCP is assumed. |
| pilot.cpu.targetAverageUtilization | int | `80` | |
| pilot.deploymentLabels | object | `{}` | Additional labels to apply to the deployment. |
| pilot.enableProtocolSniffingForInbound | bool | `true` | if protocol sniffing is enabled for inbound |
| pilot.enableProtocolSniffingForOutbound | bool | `true` | if protocol sniffing is enabled for outbound |
| pilot.env.PILOT_ENABLE_CROSS_CLUSTER_WORKLOAD_ENTRY | string | `"false"` | |
| pilot.env.PILOT_ENABLE_METADATA_EXCHANGE | string | `"false"` | |
| pilot.env.PILOT_SCOPE_GATEWAY_TO_NAMESPACE | string | `"false"` | |
| pilot.env.VALIDATION_ENABLED | string | `"false"` | |
| pilot.hub | string | `"higress-registry.cn-hangzhou.cr.aliyuncs.com/higress"` | |
| pilot.image | string | `"pilot"` | Can be a full hub/image:tag |
| pilot.jwksResolverExtraRootCA | string | `""` | You can use jwksResolverExtraRootCA to provide a root certificate in PEM format. This will then be trusted by pilot when resolving JWKS URIs. |
| pilot.keepaliveMaxServerConnectionAge | string | `"30m"` | The following is used to limit how long a sidecar can be connected to a pilot. It balances out load across pilot instances at the cost of increasing system churn. |
| pilot.nodeSelector | object | `{}` | |
| pilot.plugins | list | `[]` | |
| pilot.podAnnotations | object | `{}` | |
| pilot.podLabels | object | `{}` | Additional labels to apply on the pod level for monitoring and logging configuration. |
| pilot.replicaCount | int | `1` | |
| pilot.resources | object | `{"requests":{"cpu":"500m","memory":"2048Mi"}}` | Resources for a small pilot install |
| pilot.rollingMaxSurge | string | `"100%"` | |
| pilot.rollingMaxUnavailable | string | `"25%"` | |
| pilot.serviceAnnotations | object | `{}` | |
| pilot.tag | string | `""` | |
| pilot.traceSampling | float | `1` | |
| redis.redis.affinity | object | `{}` | Affinity for Redis |
| redis.redis.image | string | `"redis-stack-server"` | Specify the image |
| redis.redis.name | string | `"redis-stack-server"` | |
| redis.redis.nodeSelector | object | `{}` | NodeSelector Node labels for Redis |
| redis.redis.password | string | `""` | Specify the password, if not set, no password is used |
| redis.redis.persistence.accessModes | list | `["ReadWriteOnce"]` | Persistent Volume access modes |
| redis.redis.persistence.enabled | bool | `false` | Enable persistence on Redis, default is false |
| redis.redis.persistence.size | string | `"1Gi"` | Persistent Volume size |
| redis.redis.persistence.storageClass | string | `""` | If undefined (the default) or set to null, no storageClassName spec is set, choosing the default provisioner |
| redis.redis.replicas | int | `1` | Specify the number of replicas |
| redis.redis.resources | object | `{}` | Specify the resources |
| redis.redis.service | object | `{"port":6379,"type":"ClusterIP"}` | Service parameters |
| redis.redis.service.port | int | `6379` | Exporter service port |
| redis.redis.service.type | string | `"ClusterIP"` | Exporter service type |
| redis.redis.tag | string | `"7.4.0-v3"` | Specify the tag |
| redis.redis.tolerations | list | `[]` | Tolerations for Redis |
| revision | string | `""` | |
| tracing.enable | bool | `false` | |
| tracing.sampling | int | `100` | |
| tracing.skywalking.port | int | `11800` | |
| tracing.skywalking.service | string | `""` | |
| tracing.timeout | int | `500` | |
| upstream | object | `{"connectionBufferLimits":10485760,"idleTimeout":10}` | Upstream config settings |

View File

@@ -0,0 +1,34 @@
## Higress for Kubernetes
Higress is a cloud-native api gateway based on Alibaba's internal gateway practices.
Powered by Istio and 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.
## Setup Repo Info
```console
helm repo add higress.io https://higress.io/helm-charts
helm repo update
```
## Install
To install the chart with the release name `higress`:
```console
helm install higress -n higress-system higress.io/higress --create-namespace --render-subchart-notes
```
## Uninstall
To uninstall/delete the higress deployment:
```console
helm delete higress -n higress-system
```
The command removes all the Kubernetes components associated with the chart and deletes the release.
## Parameters
{{ template "chart.valuesSection" . }}

150
helm/higress/README.zh.md Normal file
View File

@@ -0,0 +1,150 @@
## Higress 适用于 Kubernetes
Higress 是基于阿里巴巴内部网关实践的云原生 API 网关。
通过 Istio 和 Envoy 的支持Higress 实现了流量网关、微服务网关和安全网关三种架构的融合,从而极大地减少了部署、运维的成本。
## 设置仓库信息
```console
helm repo add higress.io https://higress.io/helm-charts
helm repo update
```
## 安装
使用 Helm 安装名为 `higress` 的组件:
```console
helm install higress -n higress-system higress.io/higress --create-namespace --render-subchart-notes
```
## 卸载
删除名称为 higress 的安装:
```console
helm delete higress -n higress-system
```
该命令将删除与组件关联的所有 Kubernetes 组件并卸载该发行版。
## 参数
## Values
| 键 | 类型 | 默认值 | 描述 |
|----|------|---------|-------------|
| clusterName | string | `""` | 集群名 |
| controller.affinity | object | `{}` | 控制器亲和性设置 |
| controller.automaticHttps.email | string | `""` | 自动 HTTPS 所需的邮件 |
| controller.automaticHttps.enabled | bool | `true` | 是否启用自动 HTTPS 功能 |
| controller.autoscaling.enabled | bool | `false` | 是否启用控制器的自动扩展功能 |
| controller.autoscaling.maxReplicas | int | `5` | 最大副本数 |
| controller.autoscaling.minReplicas | int | `1` | 最小副本数 |
| controller.autoscaling.targetCPUUtilizationPercentage | int | `80` | 目标 CPU 使用率百分比 |
| controller.env | object | `{}` | 环境变量 |
| controller.hub | string | `"higress-registry.cn-hangzhou.cr.aliyuncs.com/higress"` | 图像库的基础地址 |
| controller.image | string | `"higress"` | 镜像名称 |
| controller.imagePullSecrets | list | `[]` | 拉取秘钥列表 |
| controller.labels | object | `{}` | 标签 |
| controller.name | string | `"higress-controller"` | 控制器名称 |
| controller.nodeSelector | object | `{}` | 节点选择器 |
| controller.podAnnotations | object | `{}` | Pod 注解 |
| controller.podLabels | object | `{}` | 应用到 Pod 上的标签 |
| controller.podSecurityContext | object | `{}` | Pod 安全上下文 |
| controller.ports[0].name | string | `"http"` | 端口名称 |
| controller.ports[0].port | int | `8888` | 端口编号 |
| controller.ports[0].protocol | string | `"TCP"` | 协议类型 |
| controller.ports[0].targetPort | int | `8888` | 目标端口 |
| controller.ports[1].name | string | `"http-solver"` | 端口名称 |
| controller.ports[1].port | int | `8889` | 端口编号 |
| controller.ports[1].protocol | string | `"TCP"` | 协议类型 |
| controller.ports[1].targetPort | int | `8889` | 目标端口 |
| controller.ports[2].name | string | `"grpc"` | 端口名称 |
| controller.ports[2].port | int | `15051` | 端口编号 |
| controller.ports[2].protocol | string | `"TCP"` | 协议类型 |
| controller.ports[2].targetPort | int | `15051` | 目标端口 |
| controller.probe.httpGet.path | string | `"/ready"` | 运行状况检查路径 |
| controller.probe.httpGet.port | int | `8888` | 端口运行状态检查 |
| controller.probe.initialDelaySeconds | int | `1` | 初始延迟秒数 |
| controller.probe.periodSeconds | int | `3` | 健康检查间隔秒数 |
| controller.probe.timeoutSeconds | int | `5` | 超时秒数 |
| controller.rbac.create | bool | `true` | 是否创建 RBAC 相关资源 |
| controller.replicas | int | `1` | Higress 控制器 Pod 的数量 |
| controller.resources.limits.cpu | string | `"1000m"` | CPU 上限 |
| controller.resources.limits.memory | string | `"2048Mi"` | 内存上限 |
| controller.resources.requests.cpu | string | `"500m"` | CPU 请求量 |
| controller.resources.requests.memory | string | `"2048Mi"` | 内存请求量 |
| controller.securityContext | object | `{}` | 安全上下文 |
| controller.service.type | string | `"ClusterIP"` | 服务类型 |
| controller.serviceAccount.annotations | object | `{}` | 添加到服务帐户的注解 |
| controller.serviceAccount.create | bool | `true` | 是否创建服务帐户 |
| controller.serviceAccount.name | string | `""` | 如果未设置且 create 为 true则从 fullname 模板生成名称 |
| controller.tag | string | `""` | 标记 |
| controller.tolerations | list | `[]` | 受容容忍度列表 |
| downstream.connectionBufferLimits | int | `32768` | 下游连接缓冲区限制(字节) |
| downstream.http2.initialConnectionWindowSize | int | `1048576` | HTTP/2 初始连接窗口大小 |
| downstream.http2.initialStreamWindowSize | int | `65535` | 流初始窗口大小 |
| downstream.http2.maxConcurrentStreams | int | `100` | 并发流最大数量 |
| downstream.idleTimeout | int | `180` | 空闲超时时间(秒) |
| downstream.maxRequestHeadersKb | int | `60` | 最大请求头大小KB |
| downstream.routeTimeout | int | `0` | 路由超时时间 |
| gateway.affinity | object | `{}` | 网关的节点亲和性 |
| gateway.annotations | object | `{}` | 应用于所有资源的注解 |
| gateway.autoscaling.enabled | bool | `false` | 启用网关的自动扩展功能 |
| gateway.autoscaling.maxReplicas | int | `5` | 最大副本数 |
| gateway.autoscaling.minReplicas | int | `1` | 最小副本数 |
| gateway.autoscaling.targetCPUUtilizationPercentage | int | `80` | CPU 使用率的目标百分比 |
| gateway.containerSecurityContext | string | `nil` | 网关容器的安全配置上下文 |
| gateway.env | object | `{}` | Pod 环境变量 |
| gateway.hostNetwork | bool | `false` | 是否使用主机网络 |
| gateway.httpPort | int | `80` | HTTP 服务端口 |
| gateway.httpsPort | int | `443` | HTTPS 服务端口 |
| gateway.hub | string | `"higress-registry.cn-hangzhou.cr.aliyuncs.com/higress"` | 网关镜像的基础域名 |
| gateway.image | string | `"gateway"` | |
| gateway.kind | string | `"Deployment"` | 部署类型 |
| gateway.labels | object | `{}` | 应用于所有资源的标签 |
| gateway.metrics.enabled | bool | `false` | 启用网关度量收集 |
| gateway.metrics.honorLabels | bool | `false` | 是否合并现有标签 |
| gateway.metrics.interval | string | `""` | 度量间隔时间 |
| gateway.metrics.provider | string | `"monitoring.coreos.com"` | 定义监控提供者 |
| gateway.metrics.rawSpec | object | `{}` | 额外的度量规范 |
| gateway.metrics.relabelConfigs | list | `[]` | 重新标签配置 |
| gateway.metrics.relabelings | list | `[]` | 重新标签项 |
| gateway.metrics.scrapeTimeout | string | `""` | 抓取的超时时间 |
| gateway.name | string | `"higress-gateway"` | 网关名称 |
| gateway.networkGateway | string | `""` | 网络网关指定 |
| gateway.nodeSelector | object | `{}` | 节点选择器 |
| gateway.replicas | int | `2` | Higress Gateway pod 的数量 |
| gateway.resources.limits.cpu | string | `"2000m"` | 容器资源限制的 CPU |
| gateway.resources.limits.memory | string | `"2048Mi"` | 容器资源限制的内存 |
| gateway.resources.requests.cpu | string | `"2000m"` | 容器资源请求的 CPU |
| gateway.resources.requests.memory | string | `"2048Mi"` | 容器资源请求的内存 |
| gateway.revision | string | `""` | 网关所属版本声明 |
| gateway.rollingMaxSurge | string | `"100%"` | 最大激增数目百分比 |
| gateway.rollingMaxUnavailable | string | `"25%"` | 最大不可用比例 |
| gateway.readinessFailureThreshold | int | `30` | 成功尝试之前连续失败的最大探测次数 |
| gateway.readinessInitialDelaySeconds | int | `1` | 初次检测推迟多少秒后开始探测存活状态 |
| gateway.readinessPeriodSeconds | int | `2` | 存活探测间隔秒数 |
| gateway.readinessSuccessThreshold | int | `1` | 认为成功之前连续成功最小探测次数 |
| gateway.readinessTimeoutSeconds | int | `3` | 存活探测超时秒数 |
| gateway.securityContext | string | `nil` | 客户豆荚的安全上下文 |
| gateway.service.annotations | object | `{}` | 应用于服务账户的注释 |
| gateway.service.externalTrafficPolicy | string | `""` | 外部路由策略 |
| gateway.service.loadBalancerClass | string | `""` | 负载均衡器类别 |
| gateway.service.loadBalancerIP | string | `""` | 负载均衡器 IP 地址 |
| gateway.service.loadBalancerSourceRanges | list | `[]` | 允许访问负载均衡器的 CIDR 范围 |
| gateway.service.ports[0].name | string | `"http2"` | 服务定义的端口名称 |
| gateway.service.ports[0].port | int | `80` | 服务端口 |
| gateway.service.ports[0].protocol | string | `"TCP"` | 协议 |
| gateway.service.ports[0].targetPort | int | `80` | 靶向端口 |
| gateway.service.ports[1].name | string | `"https"` | 服务定义的端口名称 |
| gateway.service.ports[1].port | int | `443` | 服务端口 |
| gateway.service.ports[1].protocol | string | `"TCP"` | 协议 |
| gateway.service.ports[1].targetPort | int | `443` | 靶向端口 |
| gateway.service.type | string | `"LoadBalancer"` | 服务类型 |
| global.disableAlpnH2 | bool | `false` | 设置是否禁用 ALPN 中的 http/2 |
| ... | ... | ... | ... |
由于内容较多,其他参数可以参考完整表。

View File

@@ -1,9 +1,8 @@
module github.com/alibaba/higress/hgctl
go 1.21.0
toolchain go1.22.2
go 1.22.2
toolchain go1.23.7
replace github.com/spf13/viper => github.com/istio/viper v1.3.3-0.20190515210538-2789fed3109c
@@ -243,15 +242,15 @@ require (
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.27.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/oauth2 v0.13.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/term v0.22.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/term v0.27.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
google.golang.org/appengine v1.6.8 // indirect

View File

@@ -1789,8 +1789,9 @@ golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw=
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
@@ -1909,8 +1910,9 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1961,8 +1963,9 @@ golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/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=
@@ -2069,8 +2072,9 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
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=
@@ -2086,8 +2090,9 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
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=
@@ -2108,8 +2113,9 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
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=

View File

@@ -41,11 +41,11 @@ import (
"istio.io/istio/pkg/config/schema/kind"
"istio.io/istio/pkg/keepalive"
istiokube "istio.io/istio/pkg/kube"
"istio.io/istio/pkg/log"
"istio.io/istio/pkg/security"
"istio.io/istio/security/pkg/server/ca/authenticate"
"istio.io/istio/security/pkg/server/ca/authenticate/kubeauth"
"istio.io/pkg/ledger"
"istio.io/pkg/log"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
@@ -235,7 +235,7 @@ func (s *Server) initConfigController() error {
options.ClusterId = ""
}
ingressConfig := translation.NewIngressTranslation(s.kubeClient, s.xdsServer, ns, options.ClusterId)
ingressConfig := translation.NewIngressTranslation(s.kubeClient, s.xdsServer, ns, options)
ingressConfig.AddLocalCluster(options)
s.configStores = append(s.configStores, ingressConfig)

View File

@@ -173,7 +173,7 @@ func (s *CertMgr) Reconcile(ctx context.Context, oldConfig *Config, newConfig *C
s.cache.Start()
// sync domains
s.configMgr.SetConfig(newConfig)
CertLog.Infof("certMgr start to manageSync domains:+v%", newDomains)
CertLog.Infof("certMgr start to manageSync domains: %+v", newDomains)
s.manageSync(context.Background(), newDomains)
CertLog.Infof("certMgr manageSync domains done")
} else {

View File

@@ -14,6 +14,6 @@
package cert
import "istio.io/pkg/log"
import "istio.io/istio/pkg/log"
var CertLog = log.RegisterScope("cert", "Higress Cert process.", 0)
var CertLog = log.RegisterScope("cert", "Higress Cert process.")

View File

@@ -25,7 +25,7 @@ import (
"istio.io/istio/pkg/config/constants"
"istio.io/istio/pkg/env"
"istio.io/istio/pkg/keepalive"
"istio.io/pkg/log"
"istio.io/istio/pkg/log"
)
var (

View File

@@ -22,5 +22,6 @@ var (
GatewayName = env.RegisterStringVar("GATEWAY_NAME", "higress-gateway", "").Get()
// Revision is the value of the Istio control plane revision, e.g. "canary",
// and is the value used by the "istio.io/rev" label.
Revision = env.Register("REVISION", "", "").Get()
Revision = env.Register("REVISION", "", "").Get()
McpServerWasmImageUrl = env.RegisterStringVar("MCP_SERVER_WASM_IMAGE_URL", "oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/mcp-server/all-in-one:1.0.0", "").Get()
)

View File

@@ -151,9 +151,38 @@ type IngressConfig struct {
clusterId cluster.ID
httpsConfigMgr *cert.ConfigMgr
commonOptions common.Options
// templateProcessor processes template variables in config
templateProcessor *TemplateProcessor
// secretConfigMgr manages secret dependencies
secretConfigMgr *SecretConfigMgr
}
func NewIngressConfig(localKubeClient kube.Client, xdsUpdater istiomodel.XDSUpdater, namespace string, clusterId cluster.ID) *IngressConfig {
// getSecretValue implements the getValue function for secret references
func (m *IngressConfig) getSecretValue(valueType, namespace, name, key string) (string, error) {
if valueType != "secret" {
return "", fmt.Errorf("unsupported value type: %s", valueType)
}
m.mutex.RLock()
defer m.mutex.RUnlock()
for _, controller := range m.remoteIngressControllers {
secret, err := controller.SecretLister().Secrets(namespace).Get(name)
if err == nil {
if value, exists := secret.Data[key]; exists {
return string(value), nil
}
return "", fmt.Errorf("key %s not found in secret %s/%s", key, namespace, name)
}
}
return "", fmt.Errorf("secret %s/%s not found", namespace, name)
}
func NewIngressConfig(localKubeClient kube.Client, xdsUpdater istiomodel.XDSUpdater, namespace string, options common.Options) *IngressConfig {
clusterId := options.ClusterId
if clusterId == "Kubernetes" {
clusterId = ""
}
@@ -169,18 +198,26 @@ func NewIngressConfig(localKubeClient kube.Client, xdsUpdater istiomodel.XDSUpda
namespace: namespace,
wasmPlugins: make(map[string]*extensions.WasmPlugin),
http2rpcs: make(map[string]*higressv1.Http2Rpc),
commonOptions: options,
}
mcpbridgeController := mcpbridge.NewController(localKubeClient, clusterId)
// Initialize secret config manager
config.secretConfigMgr = NewSecretConfigMgr(xdsUpdater)
// Initialize template processor with value getter function
config.templateProcessor = NewTemplateProcessor(config.getSecretValue, namespace, config.secretConfigMgr)
mcpbridgeController := mcpbridge.NewController(localKubeClient, options)
mcpbridgeController.AddEventHandler(config.AddOrUpdateMcpBridge, config.DeleteMcpBridge)
config.mcpbridgeController = mcpbridgeController
config.mcpbridgeLister = mcpbridgeController.Lister()
wasmPluginController := wasmplugin.NewController(localKubeClient, clusterId)
wasmPluginController := wasmplugin.NewController(localKubeClient, options)
wasmPluginController.AddEventHandler(config.AddOrUpdateWasmPlugin, config.DeleteWasmPlugin)
config.wasmPluginController = wasmPluginController
config.wasmPluginLister = wasmPluginController.Lister()
http2rpcController := http2rpc.NewController(localKubeClient, clusterId)
http2rpcController := http2rpc.NewController(localKubeClient, options)
http2rpcController.AddEventHandler(config.AddOrUpdateHttp2Rpc, config.DeleteHttp2Rpc)
config.http2rpcController = http2rpcController
config.http2rpcLister = http2rpcController.Lister()
@@ -225,8 +262,9 @@ func (m *IngressConfig) RegisterEventHandler(kind config.GroupVersionKind, f ist
}
func (m *IngressConfig) AddLocalCluster(options common.Options) {
secretController := secret.NewController(m.localKubeClient, options.ClusterId)
secretController := secret.NewController(m.localKubeClient, options)
secretController.AddEventHandler(m.ReflectSecretChanges)
secretController.AddEventHandler(m.secretConfigMgr.HandleSecretChange)
var ingressController common.IngressController
v1 := common.V1Available(m.localKubeClient)
@@ -253,10 +291,24 @@ func (m *IngressConfig) List(typ config.GroupVersionKind, namespace string) []co
var configs = make([]config.Config, 0)
if configsFromIngress := m.listFromIngressControllers(typ, namespace); configsFromIngress != nil {
// Process templates for ingress configs
for i := range configsFromIngress {
if err := m.templateProcessor.ProcessConfig(&configsFromIngress[i]); err != nil {
IngressLog.Errorf("Failed to process template for config %s/%s: %v",
configsFromIngress[i].Namespace, configsFromIngress[i].Name, err)
}
}
configs = append(configs, configsFromIngress...)
}
if configsFromGateway := m.listFromGatewayControllers(typ, namespace); configsFromGateway != nil {
// Process templates for gateway configs
for i := range configsFromGateway {
if err := m.templateProcessor.ProcessConfig(&configsFromGateway[i]); err != nil {
IngressLog.Errorf("Failed to process template for config %s/%s: %v",
configsFromGateway[i].Namespace, configsFromGateway[i].Name, err)
}
}
configs = append(configs, configsFromGateway...)
}
@@ -303,21 +355,21 @@ func (m *IngressConfig) listFromIngressControllers(typ config.GroupVersionKind,
common.SortIngressByCreationTime(configs)
wrapperConfigs := m.createWrapperConfigs(configs)
IngressLog.Infof("resource type %s, configs number %d", typ, len(wrapperConfigs))
var result []config.Config
switch typ {
case gvk.Gateway:
return m.convertGateways(wrapperConfigs)
result = m.convertGateways(wrapperConfigs)
case gvk.VirtualService:
return m.convertVirtualService(wrapperConfigs)
result = m.convertVirtualService(wrapperConfigs)
case gvk.DestinationRule:
return m.convertDestinationRule(wrapperConfigs)
result = m.convertDestinationRule(wrapperConfigs)
case gvk.ServiceEntry:
return m.convertServiceEntry(wrapperConfigs)
result = m.convertServiceEntry(wrapperConfigs)
case gvk.WasmPlugin:
return m.convertWasmPlugin(wrapperConfigs)
result = m.convertWasmPlugin(wrapperConfigs)
}
return nil
IngressLog.Infof("resource type %s, ingress number %d, convert configs number %d", typ, len(configs), len(result))
return result
}
func (m *IngressConfig) listFromGatewayControllers(typ config.GroupVersionKind, namespace string) []config.Config {
@@ -538,6 +590,13 @@ func (m *IngressConfig) convertVirtualService(configs []common.WrapperConfig) []
Spec: vs,
})
}
// add vs from naco3 for mcp server
if m.RegistryReconciler != nil {
allConfigsFromMcp := m.RegistryReconciler.GetAllConfigs(gvk.VirtualService)
for _, cfg := range allConfigsFromMcp {
out = append(out, *cfg)
}
}
// We generate some specific envoy filter here to avoid duplicated computation.
m.convertEnvoyFilter(&convertOptions)
@@ -624,6 +683,13 @@ func (m *IngressConfig) convertWasmPlugin([]common.WrapperConfig) []config.Confi
Spec: wasmPlugin,
})
}
// add wasm plugin from nacos for mcp server
if m.RegistryReconciler != nil {
wasmFromMcp := m.RegistryReconciler.GetAllConfigs(gvk.WasmPlugin)
for _, cfg := range wasmFromMcp {
out = append(out, *cfg)
}
}
return out
}
@@ -634,6 +700,7 @@ func (m *IngressConfig) convertServiceEntry([]common.WrapperConfig) []config.Con
serviceEntries := m.RegistryReconciler.GetAllServiceWrapper()
IngressLog.Infof("Found mcp serviceEntries %v", serviceEntries)
out := make([]config.Config, 0, len(serviceEntries))
hostSets := sets.Set[string]{}
for _, se := range serviceEntries {
out = append(out, config.Config{
Meta: config.Meta{
@@ -648,6 +715,15 @@ func (m *IngressConfig) convertServiceEntry([]common.WrapperConfig) []config.Con
},
Spec: se.ServiceEntry,
})
hostSets.Insert(se.ServiceEntry.Hosts[0])
}
// add service entry by host from nacos3 for mcp server
seFromMcp := m.RegistryReconciler.GetAllConfigs(gvk.ServiceEntry)
for _, cfg := range seFromMcp {
se := cfg.Spec.(*networking.ServiceEntry)
if !hostSets.Contains(se.Hosts[0]) {
out = append(out, *cfg)
}
}
return out
}
@@ -712,13 +788,16 @@ func (m *IngressConfig) convertDestinationRule(configs []common.WrapperConfig) [
if m.RegistryReconciler != nil {
drws := m.RegistryReconciler.GetAllDestinationRuleWrapper()
IngressLog.Infof("Found mcp destinationRules: %v", drws)
for _, destinationRuleWrapper := range drws {
serviceName := destinationRuleWrapper.ServiceKey.ServiceFQDN
dr, exist := destinationRules[serviceName]
if !exist {
destinationRules[serviceName] = destinationRuleWrapper
} else if dr.DestinationRule.TrafficPolicy != nil {
if dr.DestinationRule.TrafficPolicy.LoadBalancer == nil &&
destinationRuleWrapper.DestinationRule.TrafficPolicy.LoadBalancer != nil {
dr.DestinationRule.TrafficPolicy.LoadBalancer = destinationRuleWrapper.DestinationRule.TrafficPolicy.LoadBalancer
}
portTrafficPolicy := destinationRuleWrapper.DestinationRule.TrafficPolicy.PortLevelSettings[0]
portUpdated := false
for _, policy := range dr.DestinationRule.TrafficPolicy.PortLevelSettings {
@@ -855,7 +934,7 @@ func (m *IngressConfig) convertIstioWasmPlugin(obj *higressext.WasmPlugin) (*ext
result := &extensions.WasmPlugin{
Selector: &istiotype.WorkloadSelector{
MatchLabels: map[string]string{
"higress": m.namespace + "-higress-gateway",
m.commonOptions.GatewaySelectorKey: m.commonOptions.GatewaySelectorValue,
},
},
Url: obj.Url,
@@ -882,7 +961,7 @@ func (m *IngressConfig) convertIstioWasmPlugin(obj *higressext.WasmPlugin) (*ext
if result.PluginConfig != nil {
return result, nil
}
if !obj.DefaultConfigDisable {
if !isBoolValueTrue(obj.DefaultConfigDisable) {
result.PluginConfig = obj.DefaultConfig
}
hasValidRule := false
@@ -894,7 +973,7 @@ func (m *IngressConfig) convertIstioWasmPlugin(obj *higressext.WasmPlugin) (*ext
}
var ruleValues []*_struct.Value
for _, rule := range obj.MatchRules {
if rule.ConfigDisable {
if isBoolValueTrue(rule.ConfigDisable) {
continue
}
if rule.Config == nil {
@@ -906,6 +985,7 @@ func (m *IngressConfig) convertIstioWasmPlugin(obj *higressext.WasmPlugin) (*ext
StructValue: rule.Config,
}
validRule := false
var matchItems []*_struct.Value
// match ingress
for _, ing := range rule.Ingress {
@@ -916,6 +996,7 @@ func (m *IngressConfig) convertIstioWasmPlugin(obj *higressext.WasmPlugin) (*ext
})
}
if len(matchItems) > 0 {
validRule = true
v.StructValue.Fields["_match_route_"] = &_struct.Value{
Kind: &_struct.Value_ListValue{
ListValue: &_struct.ListValue{
@@ -923,12 +1004,9 @@ func (m *IngressConfig) convertIstioWasmPlugin(obj *higressext.WasmPlugin) (*ext
},
},
}
ruleValues = append(ruleValues, &_struct.Value{
Kind: v,
})
continue
}
// match service
matchItems = nil
for _, service := range rule.Service {
matchItems = append(matchItems, &_struct.Value{
Kind: &_struct.Value_StringValue{
@@ -937,6 +1015,7 @@ func (m *IngressConfig) convertIstioWasmPlugin(obj *higressext.WasmPlugin) (*ext
})
}
if len(matchItems) > 0 {
validRule = true
v.StructValue.Fields["_match_service_"] = &_struct.Value{
Kind: &_struct.Value_ListValue{
ListValue: &_struct.ListValue{
@@ -944,12 +1023,9 @@ func (m *IngressConfig) convertIstioWasmPlugin(obj *higressext.WasmPlugin) (*ext
},
},
}
ruleValues = append(ruleValues, &_struct.Value{
Kind: v,
})
continue
}
// match domain
matchItems = nil
for _, domain := range rule.Domain {
matchItems = append(matchItems, &_struct.Value{
Kind: &_struct.Value_StringValue{
@@ -957,19 +1033,23 @@ func (m *IngressConfig) convertIstioWasmPlugin(obj *higressext.WasmPlugin) (*ext
},
})
}
if len(matchItems) == 0 {
if len(matchItems) > 0 {
validRule = true
v.StructValue.Fields["_match_domain_"] = &_struct.Value{
Kind: &_struct.Value_ListValue{
ListValue: &_struct.ListValue{
Values: matchItems,
},
},
}
}
if validRule {
ruleValues = append(ruleValues, &_struct.Value{
Kind: v,
})
} else {
return nil, fmt.Errorf("invalid match rule has no match condition, rule:%v", rule)
}
v.StructValue.Fields["_match_domain_"] = &_struct.Value{
Kind: &_struct.Value_ListValue{
ListValue: &_struct.ListValue{
Values: matchItems,
},
},
}
ruleValues = append(ruleValues, &_struct.Value{
Kind: v,
})
}
if len(ruleValues) > 0 {
hasValidRule = true
@@ -982,11 +1062,14 @@ func (m *IngressConfig) convertIstioWasmPlugin(obj *higressext.WasmPlugin) (*ext
}
}
}
if !hasValidRule && obj.DefaultConfigDisable {
if !hasValidRule && isBoolValueTrue(obj.DefaultConfigDisable) {
return nil, nil
}
return result, nil
}
func isBoolValueTrue(b *wrappers.BoolValue) bool {
return b != nil && b.Value
}
func (m *IngressConfig) AddOrUpdateWasmPlugin(clusterNamespacedName util.ClusterNamespacedName) {
@@ -1082,6 +1165,28 @@ func (m *IngressConfig) AddOrUpdateMcpBridge(clusterNamespacedName util.ClusterN
// Set this label so that we do not compare configs and just push.
Labels: map[string]string{constants.AlwaysPushLabel: "true"},
}
vsMetadata := config.Meta{
Name: "mcpbridge-virtualservice",
Namespace: m.namespace,
GroupVersionKind: gvk.VirtualService,
// Set this label so that we do not compare configs and just push.
Labels: map[string]string{constants.AlwaysPushLabel: "true"},
}
wasmMetadata := config.Meta{
Name: "mcpbridge-wasmplugin",
Namespace: m.namespace,
GroupVersionKind: gvk.WasmPlugin,
// Set this label so that we do not compare configs and just push.
Labels: map[string]string{constants.AlwaysPushLabel: "true"},
}
efMetadata := config.Meta{
Name: "mcpbridge-envoyfilter",
Namespace: m.namespace,
GroupVersionKind: gvk.EnvoyFilter,
// Set this label so that we do not compare configs and just push.
Labels: map[string]string{constants.AlwaysPushLabel: "true"},
}
for _, f := range m.serviceEntryHandlers {
IngressLog.Debug("McpBridge triggerd serviceEntry update")
f(config.Config{Meta: seMetadata}, config.Config{Meta: seMetadata}, istiomodel.EventUpdate)
@@ -1090,9 +1195,22 @@ func (m *IngressConfig) AddOrUpdateMcpBridge(clusterNamespacedName util.ClusterN
IngressLog.Debug("McpBridge triggerd destinationRule update")
f(config.Config{Meta: drMetadata}, config.Config{Meta: drMetadata}, istiomodel.EventUpdate)
}
}, m.localKubeClient, m.namespace)
for _, f := range m.virtualServiceHandlers {
IngressLog.Debug("McpBridge triggerd virtualservice update")
f(config.Config{Meta: vsMetadata}, config.Config{Meta: vsMetadata}, istiomodel.EventUpdate)
}
for _, f := range m.wasmPluginHandlers {
IngressLog.Debug("McpBridge triggerd wasmplugin update")
f(config.Config{Meta: wasmMetadata}, config.Config{Meta: wasmMetadata}, istiomodel.EventUpdate)
}
for _, f := range m.envoyFilterHandlers {
IngressLog.Debug("McpBridge triggerd envoyfilter update")
f(config.Config{Meta: efMetadata}, config.Config{Meta: efMetadata}, istiomodel.EventUpdate)
}
}, m.localKubeClient, m.namespace, m.clusterId.String())
}
reconciler := m.RegistryReconciler
m.configmapMgr.SetMcpReconciler(m.RegistryReconciler)
err = reconciler.Reconcile(mcpbridge)
if err != nil {
IngressLog.Errorf("Mcpbridge reconcile failed, err:%v", err)

View File

@@ -127,7 +127,14 @@ func TestConvertGatewaysForIngress(t *testing.T) {
}
ingressV1Beta1Controller := controllerv1beta1.NewController(fake, fake, v1Beta1Options, nil)
ingressV1Controller := controllerv1.NewController(fake, fake, v1Options, nil)
m := NewIngressConfig(fake, nil, "wakanda", "gw-123-istio")
options := common.Options{
Enable: true,
ClusterId: "gw-123-istio",
RawClusterId: "gw-123-istio__",
GatewayHttpPort: 80,
GatewayHttpsPort: 443,
}
m := NewIngressConfig(fake, nil, "wakanda", options)
m.remoteIngressControllers = map[cluster.ID]common.IngressController{
"ingress-v1beta1": ingressV1Beta1Controller,
"ingress-v1": ingressV1Controller,

View File

@@ -0,0 +1,119 @@
// Copyright (c) 2022 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"encoding/json"
"fmt"
"regexp"
"strings"
. "github.com/alibaba/higress/pkg/ingress/log"
"google.golang.org/protobuf/proto"
"istio.io/istio/pkg/config"
)
// TemplateProcessor handles template substitution in configs
type TemplateProcessor struct {
// getValue is a function that retrieves values by type, namespace, name and key
getValue func(valueType, namespace, name, key string) (string, error)
namespace string
secretConfigMgr *SecretConfigMgr
}
// NewTemplateProcessor creates a new TemplateProcessor with the given value getter function
func NewTemplateProcessor(getValue func(valueType, namespace, name, key string) (string, error), namespace string, secretConfigMgr *SecretConfigMgr) *TemplateProcessor {
return &TemplateProcessor{
getValue: getValue,
namespace: namespace,
secretConfigMgr: secretConfigMgr,
}
}
// ProcessConfig processes a config and substitutes any template variables
func (p *TemplateProcessor) ProcessConfig(cfg *config.Config) error {
// Convert spec to JSON string to process substitutions
jsonBytes, err := json.Marshal(cfg.Spec)
if err != nil {
return fmt.Errorf("failed to marshal config spec: %v", err)
}
configStr := string(jsonBytes)
// Find all value references in format:
// ${type.name.key} or ${type.namespace/name.key}
valueRegex := regexp.MustCompile(`\$\{([^.}]+)\.(?:([^/]+)/)?([^.}]+)\.([^}]+)\}`)
matches := valueRegex.FindAllStringSubmatch(configStr, -1)
// If there are no value references, return immediately
if len(matches) == 0 {
if p.secretConfigMgr != nil {
if err := p.secretConfigMgr.DeleteConfig(cfg); err != nil {
IngressLog.Errorf("failed to delete secret dependency: %v", err)
}
}
return nil
}
foundSecretSource := false
IngressLog.Infof("start to apply config %s/%s with %d variables", cfg.Namespace, cfg.Name, len(matches))
for _, match := range matches {
valueType := match[1]
var namespace, name, key string
if match[2] != "" {
// Format: ${type.namespace/name.key}
namespace = match[2]
} else {
// Format: ${type.name.key} - use default namespace
namespace = p.namespace
}
name = match[3]
key = match[4]
// Get value using the provided getter function
value, err := p.getValue(valueType, namespace, name, key)
if err != nil {
return fmt.Errorf("failed to get %s value for %s/%s.%s: %v", valueType, namespace, name, key, err)
}
// Add secret dependency if this is a secret reference
if valueType == "secret" && p.secretConfigMgr != nil {
foundSecretSource = true
secretKey := fmt.Sprintf("%s/%s", namespace, name)
if err := p.secretConfigMgr.AddConfig(secretKey, cfg); err != nil {
IngressLog.Errorf("failed to add secret dependency: %v", err)
}
}
// Replace placeholder with actual value
configStr = strings.Replace(configStr, match[0], value, 1)
}
// Create a new instance of the same type as cfg.Spec
newSpec := proto.Clone(cfg.Spec.(proto.Message))
if err := json.Unmarshal([]byte(configStr), newSpec); err != nil {
return fmt.Errorf("failed to unmarshal substituted config: %v", err)
}
cfg.Spec = newSpec
// Delete secret dependency if no secret reference is found
if !foundSecretSource {
if p.secretConfigMgr != nil {
if err := p.secretConfigMgr.DeleteConfig(cfg); err != nil {
IngressLog.Errorf("failed to delete secret dependency: %v", err)
}
}
}
IngressLog.Infof("end to process config %s/%s", cfg.Namespace, cfg.Name)
return nil
}

View File

@@ -0,0 +1,166 @@
// Copyright (c) 2022 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"google.golang.org/protobuf/types/known/structpb"
extensions "istio.io/api/extensions/v1alpha1"
"istio.io/istio/pkg/config"
"istio.io/istio/pkg/config/schema/gvk"
)
func TestTemplateProcessor_ProcessConfig(t *testing.T) {
// Create test values map
values := map[string]string{
"secret.default/test-secret.api_key": "test-api-key",
"secret.default/test-secret.plugin_conf.timeout": "5000",
"secret.default/test-secret.plugin_conf.max_retries": "3",
"secret.higress-system/auth-secret.auth_config.type": "basic",
"secret.higress-system/auth-secret.auth_config.credentials": "base64-encoded",
}
// Mock value getter function
getValue := func(valueType, namespace, name, key string) (string, error) {
fullKey := fmt.Sprintf("%s.%s/%s.%s", valueType, namespace, name, key)
fmt.Printf("Getting value for %s", fullKey)
if value, exists := values[fullKey]; exists {
return value, nil
}
return "", fmt.Errorf("value not found for %s", fullKey)
}
// Create template processor
processor := NewTemplateProcessor(getValue, "higress-system", nil)
tests := []struct {
name string
wasmPlugin *extensions.WasmPlugin
expected *extensions.WasmPlugin
expectError bool
}{
{
name: "simple api key reference",
wasmPlugin: &extensions.WasmPlugin{
PluginName: "test-plugin",
PluginConfig: makeStructValue(t, map[string]interface{}{
"api_key": "${secret.default/test-secret.api_key}",
}),
},
expected: &extensions.WasmPlugin{
PluginName: "test-plugin",
PluginConfig: makeStructValue(t, map[string]interface{}{
"api_key": "test-api-key",
}),
},
expectError: false,
},
{
name: "config with multiple fields",
wasmPlugin: &extensions.WasmPlugin{
PluginName: "test-plugin",
PluginConfig: makeStructValue(t, map[string]interface{}{
"config": map[string]interface{}{
"timeout": "${secret.default/test-secret.plugin_conf.timeout}",
"max_retries": "${secret.default/test-secret.plugin_conf.max_retries}",
},
}),
},
expected: &extensions.WasmPlugin{
PluginName: "test-plugin",
PluginConfig: makeStructValue(t, map[string]interface{}{
"config": map[string]interface{}{
"timeout": "5000",
"max_retries": "3",
},
}),
},
expectError: false,
},
{
name: "auth config with default namespace",
wasmPlugin: &extensions.WasmPlugin{
PluginName: "test-plugin",
PluginConfig: makeStructValue(t, map[string]interface{}{
"auth": map[string]interface{}{
"type": "${secret.auth-secret.auth_config.type}",
"credentials": "${secret.auth-secret.auth_config.credentials}",
},
}),
},
expected: &extensions.WasmPlugin{
PluginName: "test-plugin",
PluginConfig: makeStructValue(t, map[string]interface{}{
"auth": map[string]interface{}{
"type": "basic",
"credentials": "base64-encoded",
},
}),
},
expectError: false,
},
{
name: "non-existent secret",
wasmPlugin: &extensions.WasmPlugin{
PluginName: "test-plugin",
PluginConfig: makeStructValue(t, map[string]interface{}{
"api_key": "${secret.default/non-existent.api_key}",
}),
},
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cfg := &config.Config{
Meta: config.Meta{
GroupVersionKind: gvk.WasmPlugin,
Name: "test-plugin",
Namespace: "default",
},
Spec: tt.wasmPlugin,
}
err := processor.ProcessConfig(cfg)
if tt.expectError {
assert.Error(t, err)
return
}
assert.NoError(t, err)
processedPlugin := cfg.Spec.(*extensions.WasmPlugin)
// Compare plugin name
assert.Equal(t, tt.expected.PluginName, processedPlugin.PluginName)
// Compare plugin configs
if tt.expected.PluginConfig != nil {
assert.NotNil(t, processedPlugin.PluginConfig)
assert.Equal(t, tt.expected.PluginConfig.AsMap(), processedPlugin.PluginConfig.AsMap())
}
})
}
}
// Helper function to create structpb.Struct from map
func makeStructValue(t *testing.T, m map[string]interface{}) *structpb.Struct {
s, err := structpb.NewStruct(m)
assert.NoError(t, err, "Failed to create struct value")
return s
}

View File

@@ -75,10 +75,11 @@ type KIngressConfig struct {
clusterId cluster.ID
}
func NewKIngressConfig(localKubeClient kube.Client, XDSUpdater istiomodel.XDSUpdater, namespace string, clusterId cluster.ID) *KIngressConfig {
func NewKIngressConfig(localKubeClient kube.Client, XDSUpdater istiomodel.XDSUpdater, namespace string, options common.Options) *KIngressConfig {
if localKubeClient.KIngressInformer() == nil {
return nil
}
clusterId := options.ClusterId
if clusterId == "Kubernetes" {
clusterId = ""
}
@@ -114,7 +115,7 @@ func (m *KIngressConfig) RegisterEventHandler(kind config.GroupVersionKind, f is
}
func (m *KIngressConfig) AddLocalCluster(options common.Options) common.KIngressController {
secretController := secret.NewController(m.localKubeClient, options.ClusterId)
secretController := secret.NewController(m.localKubeClient, options)
secretController.AddEventHandler(m.ReflectSecretChanges)
var ingressController common.KIngressController
@@ -493,7 +494,7 @@ func (m *KIngressConfig) HasSynced() bool {
defer m.mutex.RUnlock()
for _, remoteIngressController := range m.remoteIngressControllers {
IngressLog.Info("In Kingress Synced.", remoteIngressController)
IngressLog.Info("In Kingress Synced.")
if !remoteIngressController.HasSynced() {
return false
}

View File

@@ -118,7 +118,14 @@ func TestConvertGatewaysForKIngress(t *testing.T) {
RawClusterId: "kingress__",
}
kingressV1Controller := kcontrollerv1.NewController(fake, fake, v1Options, nil)
m := NewKIngressConfig(fake, nil, "wakanda", "gw-123-istio")
options := common.Options{
Enable: true,
ClusterId: "gw-123-istio",
RawClusterId: "gw-123-istio__",
GatewayHttpPort: 80,
GatewayHttpsPort: 443,
}
m := NewKIngressConfig(fake, nil, "wakanda", options)
m.remoteIngressControllers = map[cluster.ID]common.KIngressController{
"kingress": kingressV1Controller,
}

View File

@@ -0,0 +1,157 @@
// Copyright (c) 2022 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"fmt"
"sync"
"github.com/alibaba/higress/pkg/ingress/kube/util"
. "github.com/alibaba/higress/pkg/ingress/log"
istiomodel "istio.io/istio/pilot/pkg/model"
"istio.io/istio/pkg/config"
"istio.io/istio/pkg/config/schema/kind"
"istio.io/istio/pkg/util/sets"
)
// toConfigKey converts config.Config to istiomodel.ConfigKey
func toConfigKey(cfg *config.Config) (istiomodel.ConfigKey, error) {
return istiomodel.ConfigKey{
Kind: kind.MustFromGVK(cfg.GroupVersionKind),
Name: cfg.Name,
Namespace: cfg.Namespace,
}, nil
}
// SecretConfigMgr maintains the mapping between secrets and configs
type SecretConfigMgr struct {
mutex sync.RWMutex
// configSet tracks all configs that have been added
// key format: namespace/name
configSet sets.Set[string]
// secretToConfigs maps secret key to dependent configs
// key format: namespace/name
secretToConfigs map[string]sets.Set[istiomodel.ConfigKey]
// watchedSecrets tracks which secrets are being watched
watchedSecrets sets.Set[string]
// xdsUpdater is used to push config updates
xdsUpdater istiomodel.XDSUpdater
}
// NewSecretConfigMgr creates a new SecretConfigMgr
func NewSecretConfigMgr(xdsUpdater istiomodel.XDSUpdater) *SecretConfigMgr {
return &SecretConfigMgr{
secretToConfigs: make(map[string]sets.Set[istiomodel.ConfigKey]),
watchedSecrets: sets.New[string](),
configSet: sets.New[string](),
xdsUpdater: xdsUpdater,
}
}
// AddConfig adds a config and its secret dependencies
func (m *SecretConfigMgr) AddConfig(secretKey string, cfg *config.Config) error {
configKey, _ := toConfigKey(cfg)
m.mutex.Lock()
defer m.mutex.Unlock()
configId := fmt.Sprintf("%s/%s", cfg.Namespace, cfg.Name)
m.configSet.Insert(configId)
if configs, exists := m.secretToConfigs[secretKey]; exists {
configs.Insert(configKey)
} else {
m.secretToConfigs[secretKey] = sets.New(configKey)
}
// Add to watched secrets
m.watchedSecrets.Insert(secretKey)
return nil
}
// DeleteConfig removes a config from all secret dependencies
func (m *SecretConfigMgr) DeleteConfig(cfg *config.Config) error {
configKey, _ := toConfigKey(cfg)
m.mutex.Lock()
defer m.mutex.Unlock()
configId := fmt.Sprintf("%s/%s", cfg.Namespace, cfg.Name)
if !m.configSet.Contains(configId) {
return nil
}
removeKeys := make([]string, 0)
// Find and remove the config from all secrets
for secretKey, configs := range m.secretToConfigs {
if configs.Contains(configKey) {
configs.Delete(configKey)
// If no more configs depend on this secret, remove it
if configs.Len() == 0 {
removeKeys = append(removeKeys, secretKey)
}
}
}
// Remove the secrets from the secretToConfigs map
for _, secretKey := range removeKeys {
delete(m.secretToConfigs, secretKey)
m.watchedSecrets.Delete(secretKey)
}
// Remove the config from the config set
m.configSet.Delete(configId)
return nil
}
// GetConfigsForSecret returns all configs that depend on the given secret
func (m *SecretConfigMgr) GetConfigsForSecret(secretKey string) []istiomodel.ConfigKey {
m.mutex.RLock()
defer m.mutex.RUnlock()
if configs, exists := m.secretToConfigs[secretKey]; exists {
return configs.UnsortedList()
}
return nil
}
// IsSecretWatched checks if a secret is being watched
func (m *SecretConfigMgr) IsSecretWatched(secretKey string) bool {
m.mutex.RLock()
defer m.mutex.RUnlock()
return m.watchedSecrets.Contains(secretKey)
}
// HandleSecretChange handles secret changes and updates affected configs
func (m *SecretConfigMgr) HandleSecretChange(name util.ClusterNamespacedName) {
secretKey := fmt.Sprintf("%s/%s", name.Namespace, name.Name)
// Check if this secret is being watched
if !m.IsSecretWatched(secretKey) {
return
}
// Get affected configs
configKeys := m.GetConfigsForSecret(secretKey)
if len(configKeys) == 0 {
return
}
IngressLog.Infof("SecretConfigMgr Secret %s changed, updating %d dependent configs and push", secretKey, len(configKeys))
m.xdsUpdater.ConfigUpdate(&istiomodel.PushRequest{
Full: true,
Reason: istiomodel.NewReasonStats(istiomodel.SecretTrigger),
})
}

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 config
import (
"k8s.io/apimachinery/pkg/types"
"testing"
"github.com/alibaba/higress/pkg/ingress/kube/util"
"github.com/stretchr/testify/assert"
istiomodel "istio.io/istio/pilot/pkg/model"
"istio.io/istio/pkg/cluster"
"istio.io/istio/pkg/config"
"istio.io/istio/pkg/config/schema/gvk"
"istio.io/istio/pkg/config/schema/kind"
)
type mockXdsUpdater struct {
lastPushRequest *istiomodel.PushRequest
}
func (m *mockXdsUpdater) EDSUpdate(shard istiomodel.ShardKey, hostname string, namespace string, entry []*istiomodel.IstioEndpoint) {
//TODO implement me
panic("implement me")
}
func (m *mockXdsUpdater) EDSCacheUpdate(shard istiomodel.ShardKey, hostname string, namespace string, entry []*istiomodel.IstioEndpoint) {
//TODO implement me
panic("implement me")
}
func (m *mockXdsUpdater) SvcUpdate(shard istiomodel.ShardKey, hostname string, namespace string, event istiomodel.Event) {
//TODO implement me
panic("implement me")
}
func (m *mockXdsUpdater) ProxyUpdate(clusterID cluster.ID, ip string) {
//TODO implement me
panic("implement me")
}
func (m *mockXdsUpdater) RemoveShard(shardKey istiomodel.ShardKey) {
//TODO implement me
panic("implement me")
}
func (m *mockXdsUpdater) ConfigUpdate(req *istiomodel.PushRequest) {
m.lastPushRequest = req
}
func TestSecretConfigMgr(t *testing.T) {
updater := &mockXdsUpdater{}
mgr := NewSecretConfigMgr(updater)
// Test AddConfig
t.Run("AddConfig", func(t *testing.T) {
wasmPlugin := &config.Config{
Meta: config.Meta{
GroupVersionKind: gvk.WasmPlugin,
Name: "test-plugin",
Namespace: "default",
},
}
err := mgr.AddConfig("default/test-secret", wasmPlugin)
assert.NoError(t, err)
assert.True(t, mgr.IsSecretWatched("default/test-secret"))
configs := mgr.GetConfigsForSecret("default/test-secret")
assert.Len(t, configs, 1)
assert.Equal(t, kind.WasmPlugin, configs[0].Kind)
assert.Equal(t, "test-plugin", configs[0].Name)
assert.Equal(t, "default", configs[0].Namespace)
})
// Test DeleteConfig
t.Run("DeleteConfig", func(t *testing.T) {
wasmPlugin := &config.Config{
Meta: config.Meta{
GroupVersionKind: gvk.WasmPlugin,
Name: "test-plugin",
Namespace: "default",
},
}
err := mgr.DeleteConfig(wasmPlugin)
assert.NoError(t, err)
assert.False(t, mgr.IsSecretWatched("default/test-secret"))
assert.Empty(t, mgr.GetConfigsForSecret("default/test-secret"))
})
// Test HandleSecretChange
t.Run("HandleSecretChange", func(t *testing.T) {
// Add a config first
wasmPlugin := &config.Config{
Meta: config.Meta{
GroupVersionKind: gvk.WasmPlugin,
Name: "test-plugin",
Namespace: "default",
},
}
err := mgr.AddConfig("default/test-secret", wasmPlugin)
assert.NoError(t, err)
// Test secret change
secretName := util.ClusterNamespacedName{
NamespacedName: types.NamespacedName{
Name: "test-secret",
Namespace: "default",
},
}
mgr.HandleSecretChange(secretName)
assert.NotNil(t, updater.lastPushRequest)
assert.True(t, updater.lastPushRequest.Full)
})
// Test full push for secret update
t.Run("FullPushForSecretUpdate", func(t *testing.T) {
// Add a secret config
secretConfig := &config.Config{
Meta: config.Meta{
GroupVersionKind: gvk.Secret,
Name: "test-secret",
Namespace: "default",
},
}
err := mgr.AddConfig("default/test-secret", secretConfig)
assert.NoError(t, err)
// Update the secret
secretName := util.ClusterNamespacedName{
NamespacedName: types.NamespacedName{
Name: "test-secret",
Namespace: "default",
},
}
mgr.HandleSecretChange(secretName)
assert.NotNil(t, updater.lastPushRequest)
assert.True(t, updater.lastPushRequest.Full)
})
}

View File

@@ -15,12 +15,6 @@
package annotations
import (
"errors"
"sort"
"strings"
corev1 "k8s.io/api/core/v1"
"github.com/alibaba/higress/pkg/ingress/kube/util"
. "github.com/alibaba/higress/pkg/ingress/log"
)
@@ -57,101 +51,10 @@ func (a auth) Parse(annotations Annotations, config *Ingress, globalContext *Glo
if !needAuthConfig(annotations) {
return nil
}
authConfig := &AuthConfig{
AuthType: defaultAuthType,
}
// Check auth type
authType, err := annotations.ParseStringASAP(authType)
if err != nil {
IngressLog.Errorf("Parse auth type error %v within ingress %/%s", err, config.Namespace, config.Name)
return nil
}
if authType != defaultAuthType {
IngressLog.Errorf("Auth type %s within ingress %/%s is not supported yet.", authType, config.Namespace, config.Name)
return nil
}
secretName, _ := annotations.ParseStringASAP(authSecretAnn)
namespaced := util.SplitNamespacedName(secretName)
if namespaced.Name == "" {
IngressLog.Errorf("Auth secret name within ingress %s/%s is invalid", config.Namespace, config.Name)
return nil
}
if namespaced.Namespace == "" {
namespaced.Namespace = config.Namespace
}
configKey := util.ClusterNamespacedName{
NamespacedName: namespaced,
ClusterId: config.ClusterId,
}
authConfig.AuthSecret = configKey
// Subscribe secret
globalContext.WatchedSecrets.Insert(configKey.String())
secretType := authFileAuthSecretType
if rawSecretType, err := annotations.ParseStringASAP(authSecretTypeAnn); err == nil {
resultAuthSecretType := authSecretType(rawSecretType)
if resultAuthSecretType == authFileAuthSecretType || resultAuthSecretType == authMapAuthSecretType {
secretType = resultAuthSecretType
}
}
authConfig.AuthRealm, _ = annotations.ParseStringASAP(authRealm)
// Process credentials.
secretLister, exist := globalContext.ClusterSecretLister[config.ClusterId]
if !exist {
IngressLog.Errorf("secret lister of cluster %s doesn't exist", config.ClusterId)
return nil
}
authSecret, err := secretLister.Secrets(namespaced.Namespace).Get(namespaced.Name)
if err != nil {
IngressLog.Errorf("Secret %s within ingress %s/%s is not found",
namespaced.String(), config.Namespace, config.Name)
return nil
}
credentials, err := convertCredentials(secretType, authSecret)
if err != nil {
IngressLog.Errorf("Parse auth secret fail, err %v", err)
return nil
}
authConfig.Credentials = credentials
config.Auth = authConfig
IngressLog.Error("The annotation nginx.ingress.kubernetes.io/auth-type is no longer supported after version 2.0.0, please use the higress wasm plugin (e.g., basic-auth) as an alternative.")
return nil
}
func convertCredentials(secretType authSecretType, secret *corev1.Secret) ([]string, error) {
var result []string
switch secretType {
case authFileAuthSecretType:
users, exist := secret.Data[authFileKey]
if !exist {
return nil, errors.New("the auth file type must has auth key in secret data")
}
userList := strings.Split(string(users), "\n")
for _, item := range userList {
if !strings.Contains(item, ":") {
continue
}
result = append(result, item)
}
case authMapAuthSecretType:
for name, password := range secret.Data {
result = append(result, name+":"+string(password))
}
}
sort.SliceStable(result, func(i, j int) bool {
return result[i] < result[j]
})
return result, nil
}
func needAuthConfig(annotations Annotations) bool {
return annotations.HasASAP(authType) &&
annotations.HasASAP(authSecretAnn)

View File

@@ -1,197 +0,0 @@
// 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 annotations
import (
"context"
"reflect"
"testing"
"time"
"istio.io/istio/pkg/cluster"
"istio.io/istio/pkg/util/sets"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes/fake"
listerv1 "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/tools/cache"
"github.com/alibaba/higress/pkg/ingress/kube/util"
)
func TestAuthParse(t *testing.T) {
auth := auth{}
inputCases := []struct {
input map[string]string
secret *v1.Secret
expect *AuthConfig
watchedSecret string
}{
{
secret: &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "bar",
Namespace: "foo",
},
Data: map[string][]byte{
"auth": []byte("A:a\nB:b"),
},
},
},
{
input: map[string]string{
buildNginxAnnotationKey(authType): "digest",
},
expect: nil,
secret: &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "bar",
Namespace: "foo",
},
Data: map[string][]byte{
"auth": []byte("A:a\nB:b"),
},
},
},
{
input: map[string]string{
buildNginxAnnotationKey(authType): defaultAuthType,
buildHigressAnnotationKey(authSecretAnn): "foo/bar",
},
secret: &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "bar",
Namespace: "foo",
},
Data: map[string][]byte{
"auth": []byte("A:a\nB:b"),
},
},
expect: &AuthConfig{
AuthType: defaultAuthType,
AuthSecret: util.ClusterNamespacedName{
NamespacedName: types.NamespacedName{
Namespace: "foo",
Name: "bar",
},
ClusterId: "cluster",
},
Credentials: []string{"A:a", "B:b"},
},
watchedSecret: "cluster/foo/bar",
},
{
input: map[string]string{
buildNginxAnnotationKey(authType): defaultAuthType,
buildHigressAnnotationKey(authSecretAnn): "foo/bar",
buildNginxAnnotationKey(authSecretTypeAnn): string(authMapAuthSecretType),
},
secret: &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "bar",
Namespace: "foo",
},
Data: map[string][]byte{
"A": []byte("a"),
"B": []byte("b"),
},
},
expect: &AuthConfig{
AuthType: defaultAuthType,
AuthSecret: util.ClusterNamespacedName{
NamespacedName: types.NamespacedName{
Namespace: "foo",
Name: "bar",
},
ClusterId: "cluster",
},
Credentials: []string{"A:a", "B:b"},
},
watchedSecret: "cluster/foo/bar",
},
{
input: map[string]string{
buildNginxAnnotationKey(authType): defaultAuthType,
buildHigressAnnotationKey(authSecretAnn): "bar",
buildNginxAnnotationKey(authSecretTypeAnn): string(authFileAuthSecretType),
},
secret: &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "bar",
Namespace: "default",
},
Data: map[string][]byte{
"auth": []byte("A:a\nB:b"),
},
},
expect: &AuthConfig{
AuthType: defaultAuthType,
AuthSecret: util.ClusterNamespacedName{
NamespacedName: types.NamespacedName{
Namespace: "default",
Name: "bar",
},
ClusterId: "cluster",
},
Credentials: []string{"A:a", "B:b"},
},
watchedSecret: "cluster/default/bar",
},
}
for _, inputCase := range inputCases {
t.Run("", func(t *testing.T) {
config := &Ingress{
Meta: Meta{
Namespace: "default",
ClusterId: "cluster",
},
}
globalContext, cancel := initGlobalContext(inputCase.secret)
defer cancel()
_ = auth.Parse(inputCase.input, config, globalContext)
if !reflect.DeepEqual(inputCase.expect, config.Auth) {
t.Fatal("Should be equal")
}
if inputCase.watchedSecret != "" {
if !globalContext.WatchedSecrets.Contains(inputCase.watchedSecret) {
t.Fatalf("Should watch secret %s", inputCase.watchedSecret)
}
}
})
}
}
func initGlobalContext(secret *v1.Secret) (*GlobalContext, context.CancelFunc) {
ctx, cancel := context.WithCancel(context.Background())
client := fake.NewSimpleClientset(secret)
informerFactory := informers.NewSharedInformerFactory(client, time.Hour)
secretInformer := informerFactory.Core().V1().Secrets()
go secretInformer.Informer().Run(ctx.Done())
cache.WaitForCacheSync(ctx.Done(), secretInformer.Informer().HasSynced)
return &GlobalContext{
WatchedSecrets: sets.New[string](),
ClusterSecretLister: map[cluster.ID]listerv1.SecretLister{
"cluster": secretInformer.Lister(),
},
}, cancel
}

View File

@@ -15,6 +15,7 @@
package annotations
import (
"fmt"
"strings"
networking "istio.io/api/networking/v1alpha3"
@@ -27,9 +28,11 @@ import (
)
const (
authTLSSecret = "auth-tls-secret"
sslCipher = "ssl-cipher"
gatewaySdsCaSuffix = "-cacert"
authTLSSecret = "auth-tls-secret"
sslCipher = "ssl-cipher"
gatewaySdsCaSuffix = "-cacert"
annotationMinTLSVersion = "tls-min-protocol-version"
annotationMaxTLSVersion = "tls-max-protocol-version"
)
var (
@@ -41,6 +44,8 @@ type DownstreamTLSConfig struct {
CipherSuites []string
Mode networking.ServerTLSSettings_TLSmode
CASecretName types.NamespacedName
MinVersion string
MaxVersion string
}
type downstreamTLS struct{}
@@ -82,6 +87,14 @@ func (d downstreamTLS) Parse(annotations Annotations, config *Ingress, _ *Global
downstreamTLSConfig.CipherSuites = validCipherSuite
}
if minVersion, err := annotations.ParseStringASAP(annotationMinTLSVersion); err == nil {
downstreamTLSConfig.MinVersion = minVersion
}
if maxVersion, err := annotations.ParseStringASAP(annotationMaxTLSVersion); err == nil {
downstreamTLSConfig.MaxVersion = maxVersion
}
return nil
}
@@ -107,11 +120,44 @@ func (d downstreamTLS) ApplyGateway(gateway *networking.Gateway, config *Ingress
if len(downstreamTLSConfig.CipherSuites) != 0 {
server.Tls.CipherSuites = downstreamTLSConfig.CipherSuites
}
if downstreamTLSConfig.MinVersion != "" {
if version, err := convertTLSVersion(downstreamTLSConfig.MinVersion); err != nil {
IngressLog.Errorf("Invalid minimum TLS version: %v", err)
} else {
server.Tls.MinProtocolVersion = version
}
}
if downstreamTLSConfig.MaxVersion != "" {
if version, err := convertTLSVersion(downstreamTLSConfig.MaxVersion); err != nil {
IngressLog.Errorf("Invalid maximum TLS version: %v", err)
} else {
server.Tls.MaxProtocolVersion = version
}
}
}
}
}
func needDownstreamTLS(annotations Annotations) bool {
return annotations.HasASAP(sslCipher) ||
annotations.HasASAP(authTLSSecret)
annotations.HasASAP(authTLSSecret) ||
annotations.HasASAP(annotationMinTLSVersion) ||
annotations.HasASAP(annotationMaxTLSVersion)
}
func convertTLSVersion(version string) (networking.ServerTLSSettings_TLSProtocol, error) {
switch version {
case "TLSv1.0":
return networking.ServerTLSSettings_TLSV1_0, nil
case "TLSv1.1":
return networking.ServerTLSSettings_TLSV1_1, nil
case "TLSv1.2":
return networking.ServerTLSSettings_TLSV1_2, nil
case "TLSv1.3":
return networking.ServerTLSSettings_TLSV1_3, nil
}
return networking.ServerTLSSettings_TLS_AUTO, fmt.Errorf("invalid TLS version: %s. Valid values are: TLSv1.0, TLSv1.1, TLSv1.2, TLSv1.3", version)
}

View File

@@ -26,11 +26,15 @@ var parser = downstreamTLS{}
func TestParse(t *testing.T) {
testCases := []struct {
name string
input map[string]string
expect *DownstreamTLSConfig
}{
{},
{
name: "empty config",
},
{
name: "ssl cipher only",
input: map[string]string{
buildNginxAnnotationKey(sslCipher): "ECDHE-RSA-AES256-GCM-SHA384:AES128-SHA",
},
@@ -40,9 +44,24 @@ func TestParse(t *testing.T) {
},
},
{
name: "with TLS version config",
input: map[string]string{
buildNginxAnnotationKey(authTLSSecret): "test",
buildNginxAnnotationKey(sslCipher): "ECDHE-RSA-AES256-GCM-SHA384:AES128-SHA",
buildNginxAnnotationKey(annotationMinTLSVersion): "TLSv1.2",
buildNginxAnnotationKey(annotationMaxTLSVersion): "TLSv1.3",
},
expect: &DownstreamTLSConfig{
Mode: networking.ServerTLSSettings_SIMPLE,
MinVersion: "TLSv1.2",
MaxVersion: "TLSv1.3",
},
},
{
name: "complete config",
input: map[string]string{
buildNginxAnnotationKey(authTLSSecret): "test",
buildNginxAnnotationKey(sslCipher): "ECDHE-RSA-AES256-GCM-SHA384:AES128-SHA",
buildNginxAnnotationKey(annotationMinTLSVersion): "TLSv1.2",
buildNginxAnnotationKey(annotationMaxTLSVersion): "TLSv1.3",
},
expect: &DownstreamTLSConfig{
CASecretName: types.NamespacedName{
@@ -51,34 +70,79 @@ func TestParse(t *testing.T) {
},
Mode: networking.ServerTLSSettings_MUTUAL,
CipherSuites: []string{"ECDHE-RSA-AES256-GCM-SHA384", "AES128-SHA"},
},
},
{
input: map[string]string{
buildHigressAnnotationKey(authTLSSecret): "test/foo",
DefaultAnnotationsPrefix + "/" + sslCipher: "ECDHE-RSA-AES256-GCM-SHA384:AES128-SHA",
},
expect: &DownstreamTLSConfig{
CASecretName: types.NamespacedName{
Namespace: "test",
Name: "foo",
},
Mode: networking.ServerTLSSettings_MUTUAL,
CipherSuites: []string{"ECDHE-RSA-AES256-GCM-SHA384", "AES128-SHA"},
MinVersion: "TLSv1.2",
MaxVersion: "TLSv1.3",
},
},
}
for _, testCase := range testCases {
t.Run("", func(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
config := &Ingress{
Meta: Meta{
Namespace: "foo",
},
}
_ = parser.Parse(testCase.input, config, nil)
if !reflect.DeepEqual(testCase.expect, config.DownstreamTLS) {
t.Fatalf("Should be equal")
err := parser.Parse(tc.input, config, nil)
if err != nil {
t.Fatalf("Parse failed: %v", err)
}
if !reflect.DeepEqual(tc.expect, config.DownstreamTLS) {
t.Fatalf("Parse result mismatch:\nExpect: %+v\nGot: %+v", tc.expect, config.DownstreamTLS)
}
})
}
}
func TestConvertTLSVersion(t *testing.T) {
testCases := []struct {
name string
version string
expect networking.ServerTLSSettings_TLSProtocol
wantErr bool
}{
{
name: "TLS 1.0",
version: "TLSv1.0",
expect: networking.ServerTLSSettings_TLSV1_0,
},
{
name: "TLS 1.1",
version: "TLSv1.1",
expect: networking.ServerTLSSettings_TLSV1_1,
},
{
name: "TLS 1.2",
version: "TLSv1.2",
expect: networking.ServerTLSSettings_TLSV1_2,
},
{
name: "TLS 1.3",
version: "TLSv1.3",
expect: networking.ServerTLSSettings_TLSV1_3,
},
{
name: "invalid version",
version: "invalid",
expect: networking.ServerTLSSettings_TLS_AUTO,
wantErr: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result, err := convertTLSVersion(tc.version)
if tc.wantErr {
if err == nil {
t.Error("Expected error but got none")
}
} else {
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if result != tc.expect {
t.Errorf("Expected %v but got %v", tc.expect, result)
}
}
})
}
@@ -86,11 +150,13 @@ func TestParse(t *testing.T) {
func TestApplyGateway(t *testing.T) {
testCases := []struct {
name string
input *networking.Gateway
config *Ingress
expect *networking.Gateway
}{
{
name: "apply TLS version",
input: &networking.Gateway{
Servers: []*networking.Server{
{
@@ -105,7 +171,8 @@ func TestApplyGateway(t *testing.T) {
},
config: &Ingress{
DownstreamTLS: &DownstreamTLSConfig{
CipherSuites: []string{"ECDHE-RSA-AES256-GCM-SHA384"},
MinVersion: "TLSv1.2",
MaxVersion: "TLSv1.3",
},
},
expect: &networking.Gateway{
@@ -115,14 +182,16 @@ func TestApplyGateway(t *testing.T) {
Protocol: "HTTPS",
},
Tls: &networking.ServerTLSSettings{
Mode: networking.ServerTLSSettings_SIMPLE,
CipherSuites: []string{"ECDHE-RSA-AES256-GCM-SHA384"},
Mode: networking.ServerTLSSettings_SIMPLE,
MinProtocolVersion: networking.ServerTLSSettings_TLSV1_2,
MaxProtocolVersion: networking.ServerTLSSettings_TLSV1_3,
},
},
},
},
},
{
name: "complete config",
input: &networking.Gateway{
Servers: []*networking.Server{
{
@@ -144,24 +213,28 @@ func TestApplyGateway(t *testing.T) {
},
Mode: networking.ServerTLSSettings_MUTUAL,
CipherSuites: []string{"ECDHE-RSA-AES256-GCM-SHA384"},
MinVersion: "TLSv1.2",
MaxVersion: "TLSv1.3",
},
},
expect: &networking.Gateway{
Servers: []*networking.Server{
{
Port: &networking.Port{
Protocol: "HTTPS",
},
{Port: &networking.Port{
Protocol: "HTTPS",
},
Tls: &networking.ServerTLSSettings{
CredentialName: "kubernetes-ingress://cluster/foo/bar",
Mode: networking.ServerTLSSettings_MUTUAL,
CipherSuites: []string{"ECDHE-RSA-AES256-GCM-SHA384"},
CredentialName: "kubernetes-ingress://cluster/foo/bar",
Mode: networking.ServerTLSSettings_MUTUAL,
CipherSuites: []string{"ECDHE-RSA-AES256-GCM-SHA384"},
MinProtocolVersion: networking.ServerTLSSettings_TLSV1_2,
MaxProtocolVersion: networking.ServerTLSSettings_TLSV1_3,
},
},
},
},
},
{
name: "invalid TLS version",
input: &networking.Gateway{
Servers: []*networking.Server{
{
@@ -169,20 +242,15 @@ func TestApplyGateway(t *testing.T) {
Protocol: "HTTPS",
},
Tls: &networking.ServerTLSSettings{
Mode: networking.ServerTLSSettings_SIMPLE,
CredentialName: "kubernetes-ingress://cluster/foo/bar",
Mode: networking.ServerTLSSettings_SIMPLE,
},
},
},
},
config: &Ingress{
DownstreamTLS: &DownstreamTLSConfig{
CASecretName: types.NamespacedName{
Namespace: "foo",
Name: "bar-cacert",
},
Mode: networking.ServerTLSSettings_MUTUAL,
CipherSuites: []string{"ECDHE-RSA-AES256-GCM-SHA384"},
MinVersion: "invalid",
MaxVersion: "invalid",
},
},
expect: &networking.Gateway{
@@ -192,48 +260,10 @@ func TestApplyGateway(t *testing.T) {
Protocol: "HTTPS",
},
Tls: &networking.ServerTLSSettings{
CredentialName: "kubernetes-ingress://cluster/foo/bar",
Mode: networking.ServerTLSSettings_MUTUAL,
CipherSuites: []string{"ECDHE-RSA-AES256-GCM-SHA384"},
},
},
},
},
},
{
input: &networking.Gateway{
Servers: []*networking.Server{
{
Port: &networking.Port{
Protocol: "HTTPS",
},
Tls: &networking.ServerTLSSettings{
Mode: networking.ServerTLSSettings_SIMPLE,
CredentialName: "kubernetes-ingress://cluster/foo/bar",
},
},
},
},
config: &Ingress{
DownstreamTLS: &DownstreamTLSConfig{
CASecretName: types.NamespacedName{
Namespace: "bar",
Name: "foo",
},
Mode: networking.ServerTLSSettings_MUTUAL,
CipherSuites: []string{"ECDHE-RSA-AES256-GCM-SHA384"},
},
},
expect: &networking.Gateway{
Servers: []*networking.Server{
{
Port: &networking.Port{
Protocol: "HTTPS",
},
Tls: &networking.ServerTLSSettings{
CredentialName: "kubernetes-ingress://cluster/foo/bar",
Mode: networking.ServerTLSSettings_SIMPLE,
CipherSuites: []string{"ECDHE-RSA-AES256-GCM-SHA384"},
Mode: networking.ServerTLSSettings_SIMPLE,
// Invalid versions should default to TLS_AUTO
MinProtocolVersion: networking.ServerTLSSettings_TLS_AUTO,
MaxProtocolVersion: networking.ServerTLSSettings_TLS_AUTO,
},
},
},
@@ -241,11 +271,59 @@ func TestApplyGateway(t *testing.T) {
},
}
for _, testCase := range testCases {
t.Run("", func(t *testing.T) {
parser.ApplyGateway(testCase.input, testCase.config)
if !reflect.DeepEqual(testCase.input, testCase.expect) {
t.Fatalf("Should be equal")
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
parser.ApplyGateway(tc.input, tc.config)
if !reflect.DeepEqual(tc.input, tc.expect) {
t.Fatalf("ApplyGateway result mismatch for %s:\nExpect: %+v\nGot: %+v",
tc.name, tc.expect, tc.input)
}
})
}
}
func TestNeedDownstreamTLS(t *testing.T) {
testCases := []struct {
name string
annotations map[string]string
expect bool
}{
{
name: "empty annotations",
annotations: map[string]string{},
expect: false,
},
{
name: "with ssl cipher",
annotations: map[string]string{
buildNginxAnnotationKey(sslCipher): "ECDHE-RSA-AES256-GCM-SHA384",
},
expect: true,
},
{
name: "with TLS version",
annotations: map[string]string{
buildNginxAnnotationKey(annotationMinTLSVersion): "TLSv1.2",
},
expect: true,
},
{
name: "with multiple TLS configs",
annotations: map[string]string{
buildNginxAnnotationKey(sslCipher): "ECDHE-RSA-AES256-GCM-SHA384",
buildNginxAnnotationKey(annotationMinTLSVersion): "TLSv1.2",
buildNginxAnnotationKey(annotationMaxTLSVersion): "TLSv1.3",
},
expect: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := needDownstreamTLS(tc.annotations)
if result != tc.expect {
t.Errorf("needDownstreamTLS() for %s = %v, want %v",
tc.name, result, tc.expect)
}
})
}

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 common
import (
"testing"
"github.com/stretchr/testify/assert"
"istio.io/istio/pilot/pkg/model"
"istio.io/istio/pkg/config"
)
func TestIngressDomainCache(t *testing.T) {
cache := NewIngressDomainCache()
assert.NotNil(t, cache)
assert.NotNil(t, cache.Valid)
assert.Empty(t, cache.Invalid)
cache.Valid["example.com"] = &IngressDomainBuilder{
Host: "example.com",
Protocol: HTTP,
ClusterId: "cluster-1",
Ingress: &config.Config{
Meta: config.Meta{
Name: "test-ingress",
Namespace: "default",
},
},
}
cache.Invalid = append(cache.Invalid, model.IngressDomain{
Host: "invalid.com",
Error: "invalid domain",
})
result := cache.Extract()
assert.Equal(t, 1, len(result.Valid))
assert.Equal(t, "example.com", result.Valid[0].Host)
assert.Equal(t, string(HTTP), result.Valid[0].Protocol)
assert.Equal(t, 1, len(result.Invalid))
assert.Equal(t, "invalid.com", result.Invalid[0].Host)
}
func TestIngressDomainBuilder(t *testing.T) {
builder := &IngressDomainBuilder{
Host: "example.com",
Protocol: HTTP,
ClusterId: "cluster-1",
Ingress: &config.Config{
Meta: config.Meta{
Name: "test-ingress",
Namespace: "default",
},
},
}
domain := builder.Build()
assert.Equal(t, "example.com", domain.Host)
assert.Equal(t, string(HTTP), domain.Protocol)
builder.Event = MissingSecret
eventDomain := builder.Build()
assert.Contains(t, eventDomain.Error, "misses secret")
builder.Event = DuplicatedTls
builder.PreIngress = &config.Config{
Meta: config.Meta{
Name: "pre-ingress",
Namespace: "default",
},
}
builder.PreIngress.Meta.Annotations = map[string]string{
ClusterIdAnnotation: "pre-cluster",
}
dupDomain := builder.Build()
assert.Contains(t, dupDomain.Error, "conflicted with ingress")
builder.Protocol = HTTPS
builder.SecretName = "test-secret"
builder.Event = ""
httpsDomain := builder.Build()
assert.Equal(t, string(HTTPS), httpsDomain.Protocol)
assert.Equal(t, "test-secret", httpsDomain.SecretName)
}

View File

@@ -18,6 +18,7 @@ import (
"testing"
networking "istio.io/api/networking/v1alpha3"
"istio.io/istio/pilot/pkg/model"
"istio.io/istio/pkg/config"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -556,3 +557,514 @@ func TestSortHTTPRoutesWithMoreRules(t *testing.T) {
}
}
}
func TestValidateBackendResource(t *testing.T) {
groupStr := "networking.higress.io"
testCases := []struct {
name string
resource *v1.TypedLocalObjectReference
expected bool
}{
{
name: "nil resource",
resource: nil,
expected: false,
},
{
name: "nil APIGroup",
resource: &v1.TypedLocalObjectReference{
APIGroup: nil,
Kind: "McpBridge",
Name: "default",
},
expected: false,
},
{
name: "wrong APIGroup",
resource: &v1.TypedLocalObjectReference{
APIGroup: &groupStr,
Kind: "McpBridge",
Name: "wrong-name",
},
expected: false,
},
{
name: "wrong Kind",
resource: &v1.TypedLocalObjectReference{
APIGroup: &groupStr,
Kind: "WrongKind",
Name: "default",
},
expected: false,
},
{
name: "valid resource",
resource: &v1.TypedLocalObjectReference{
APIGroup: &groupStr,
Kind: "McpBridge",
Name: "default",
},
expected: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := ValidateBackendResource(tc.resource)
assert.Equal(t, tc.expected, result)
})
}
}
func TestCreateOrUpdateAnnotations(t *testing.T) {
testCases := []struct {
name string
annotations map[string]string
options Options
expected map[string]string
}{
{
name: "empty annotations",
annotations: map[string]string{},
options: Options{
ClusterId: "test-cluster",
RawClusterId: "raw-test-cluster",
},
expected: map[string]string{
ClusterIdAnnotation: "test-cluster",
RawClusterIdAnnotation: "raw-test-cluster",
},
},
{
name: "existing annotations",
annotations: map[string]string{
"key1": "value1",
"key2": "value2",
},
options: Options{
ClusterId: "test-cluster",
RawClusterId: "raw-test-cluster",
},
expected: map[string]string{
"key1": "value1",
"key2": "value2",
ClusterIdAnnotation: "test-cluster",
RawClusterIdAnnotation: "raw-test-cluster",
},
},
{
name: "overwrite existing cluster annotations",
annotations: map[string]string{
ClusterIdAnnotation: "old-cluster",
RawClusterIdAnnotation: "old-raw-cluster",
"key1": "value1",
},
options: Options{
ClusterId: "new-cluster",
RawClusterId: "new-raw-cluster",
},
expected: map[string]string{
ClusterIdAnnotation: "new-cluster",
RawClusterIdAnnotation: "new-raw-cluster",
"key1": "value1",
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := CreateOrUpdateAnnotations(tc.annotations, tc.options)
assert.Equal(t, tc.expected, result)
})
}
}
func TestGetClusterId(t *testing.T) {
testCases := []struct {
name string
annotations map[string]string
expected string
}{
{
name: "nil annotations",
annotations: nil,
expected: "",
},
{
name: "empty annotations",
annotations: map[string]string{},
expected: "",
},
{
name: "with cluster id",
annotations: map[string]string{
ClusterIdAnnotation: "test-cluster",
},
expected: "test-cluster",
},
{
name: "with other annotations",
annotations: map[string]string{
"key1": "value1",
"key2": "value2",
},
expected: "",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := GetClusterId(tc.annotations)
assert.Equal(t, tc.expected, string(result))
})
}
}
func TestConvertToDNSLabelValidAndCleanHost(t *testing.T) {
testCases := []struct {
name string
input string
}{
{
name: "simple host",
input: "example.com",
},
{
name: "wildcard host",
input: "*.example.com",
},
{
name: "long host",
input: "very-long-subdomain.example-service.my-namespace.svc.cluster.local",
},
{
name: "empty host",
input: "",
},
{
name: "ip address",
input: "192.168.1.1",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// Test internal convertToDNSLabelValid function (through CleanHost)
result := CleanHost(tc.input)
// Validate result
assert.NotEmpty(t, result)
assert.Equal(t, 16, len(result)) // MD5 hash format is fixed length of 16 bytes
// Consistency check - same input should produce same output
result2 := CleanHost(tc.input)
assert.Equal(t, result, result2)
})
}
}
func TestSplitServiceFQDN(t *testing.T) {
testCases := []struct {
name string
fqdn string
expectedSvc string
expectedNs string
expectedValid bool
}{
{
name: "simple fqdn",
fqdn: "service.namespace",
expectedSvc: "service",
expectedNs: "namespace",
expectedValid: true,
},
{
name: "full k8s fqdn",
fqdn: "service.namespace.svc.cluster.local",
expectedSvc: "service",
expectedNs: "namespace",
expectedValid: true,
},
{
name: "just service name",
fqdn: "service",
expectedSvc: "",
expectedNs: "",
expectedValid: false,
},
{
name: "empty string",
fqdn: "",
expectedSvc: "",
expectedNs: "",
expectedValid: false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
svc, ns, valid := SplitServiceFQDN(tc.fqdn)
assert.Equal(t, tc.expectedSvc, svc)
assert.Equal(t, tc.expectedNs, ns)
assert.Equal(t, tc.expectedValid, valid)
})
}
}
func TestConvertBackendService(t *testing.T) {
testCases := []struct {
name string
dest *networking.HTTPRouteDestination
expected model.BackendService
}{
{
name: "simple service",
dest: &networking.HTTPRouteDestination{
Destination: &networking.Destination{
Host: "service.namespace",
Port: &networking.PortSelector{
Number: 80,
},
},
Weight: 100,
},
expected: model.BackendService{
Name: "service",
Namespace: "namespace",
Port: 80,
Weight: 100,
},
},
{
name: "full k8s FQDN",
dest: &networking.HTTPRouteDestination{
Destination: &networking.Destination{
Host: "service.namespace.svc.cluster.local",
Port: &networking.PortSelector{
Number: 8080,
},
},
Weight: 50,
},
expected: model.BackendService{
Name: "service",
Namespace: "namespace",
Port: 8080,
Weight: 50,
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := ConvertBackendService(tc.dest)
assert.Equal(t, tc.expected.Name, result.Name)
assert.Equal(t, tc.expected.Namespace, result.Namespace)
assert.Equal(t, tc.expected.Port, result.Port)
assert.Equal(t, tc.expected.Weight, result.Weight)
})
}
}
func TestCreateConvertedName(t *testing.T) {
testCases := []struct {
name string
items []string
expected string
}{
{
name: "empty slice",
items: []string{},
expected: "",
},
{
name: "single item",
items: []string{"example"},
expected: "example",
},
{
name: "multiple items",
items: []string{"part1", "part2", "part3"},
expected: "part1-part2-part3",
},
{
name: "with empty strings",
items: []string{"part1", "", "part3"},
expected: "part1-part3",
},
{
name: "all empty strings",
items: []string{"", "", ""},
expected: "",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := CreateConvertedName(tc.items...)
assert.Equal(t, tc.expected, result)
})
}
}
func TestSortIngressByCreationTime(t *testing.T) {
configs := []config.Config{
{
Meta: config.Meta{
Name: "c-ingress",
Namespace: "ns1",
},
},
{
Meta: config.Meta{
Name: "a-ingress",
Namespace: "ns1",
},
},
{
Meta: config.Meta{
Name: "b-ingress",
Namespace: "ns1",
},
},
}
expected := []string{"a-ingress", "b-ingress", "c-ingress"}
SortIngressByCreationTime(configs)
var actual []string
for _, cfg := range configs {
actual = append(actual, cfg.Name)
}
assert.Equal(t, expected, actual, "When the timestamps are the same, the configuration should be sorted by name")
sameNamespaceConfigs := []config.Config{
{
Meta: config.Meta{
Name: "same-name",
Namespace: "c-ns",
},
},
{
Meta: config.Meta{
Name: "same-name",
Namespace: "a-ns",
},
},
{
Meta: config.Meta{
Name: "same-name",
Namespace: "b-ns",
},
},
}
expectedNamespace := []string{"a-ns", "b-ns", "c-ns"}
SortIngressByCreationTime(sameNamespaceConfigs)
var actualNamespace []string
for _, cfg := range sameNamespaceConfigs {
actualNamespace = append(actualNamespace, cfg.Namespace)
}
assert.Equal(t, expectedNamespace, actualNamespace, "When the names are the same, the configuration should be sorted by namespace")
}
func TestPartMd5(t *testing.T) {
testCases := []struct {
name string
input string
length int
}{
{
name: "empty string",
input: "",
length: 8,
},
{
name: "simple string",
input: "test",
length: 8,
},
{
name: "complex string",
input: "this-is-a-long-string-with-special-chars-!@#$%^&*()",
length: 8,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := partMd5(tc.input)
// Check result format
assert.Equal(t, tc.length, len(result), "MD5 hash excerpt should be 8 characters")
// Run twice to ensure deterministic output
result2 := partMd5(tc.input)
assert.Equal(t, result, result2, "partMd5 function should be deterministic")
})
}
}
func TestGetLbStatusListV1AndV1Beta1(t *testing.T) {
clusterPrefix = "gw-123-"
svcName := clusterPrefix
svcList := []*v1.Service{
{
ObjectMeta: metav1.ObjectMeta{
Name: svcName,
},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeLoadBalancer,
},
Status: v1.ServiceStatus{
LoadBalancer: v1.LoadBalancerStatus{
Ingress: []v1.LoadBalancerIngress{
{
IP: "2.2.2.2",
},
},
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: svcName,
},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeLoadBalancer,
},
Status: v1.ServiceStatus{
LoadBalancer: v1.LoadBalancerStatus{
Ingress: []v1.LoadBalancerIngress{
{
Hostname: "1.1.1.1" + SvcHostNameSuffix,
},
},
},
},
},
}
// Test the V1 version
t.Run("GetLbStatusListV1", func(t *testing.T) {
lbiList := GetLbStatusListV1(svcList)
assert.Equal(t, 2, len(lbiList), "There should be 2 entry points")
assert.Equal(t, "1.1.1.1", lbiList[0].IP, "The first IP should be 1.1.1.1")
assert.Equal(t, "2.2.2.2", lbiList[1].IP, "The second IP should be 2.2.2.2")
})
// Test the V1Beta1 version
t.Run("GetLbStatusListV1Beta1", func(t *testing.T) {
lbiList := GetLbStatusListV1Beta1(svcList)
assert.Equal(t, 2, len(lbiList), "There should be 2 entry points")
assert.Equal(t, "1.1.1.1", lbiList[0].IP, "The first IP should be 1.1.1.1")
assert.Equal(t, "2.2.2.2", lbiList[1].IP, "The second IP should be 2.2.2.2")
})
}

View File

@@ -40,6 +40,7 @@ type HigressConfig struct {
Upstream *Upstream `json:"upstream,omitempty"`
DisableXEnvoyHeaders bool `json:"disableXEnvoyHeaders,omitempty"`
AddXRealIpHeader bool `json:"addXRealIpHeader,omitempty"`
McpServer *McpServer `json:"mcpServer,omitempty"`
}
func NewDefaultHigressConfig() *HigressConfig {
@@ -51,6 +52,7 @@ func NewDefaultHigressConfig() *HigressConfig {
Upstream: globalOption.Upstream,
DisableXEnvoyHeaders: globalOption.DisableXEnvoyHeaders,
AddXRealIpHeader: globalOption.AddXRealIpHeader,
McpServer: NewDefaultMcpServer(),
}
return higressConfig
}

View File

@@ -18,6 +18,7 @@ import (
"reflect"
"sync/atomic"
"github.com/alibaba/higress/registry/reconcile"
"istio.io/istio/pilot/pkg/model"
"istio.io/istio/pkg/cluster"
"istio.io/istio/pkg/config"
@@ -58,6 +59,7 @@ type ItemController interface {
ValidHigressConfig(higressConfig *HigressConfig) error
ConstructEnvoyFilters() ([]*config.Config, error)
RegisterItemEventHandler(eventHandler ItemEventHandler)
RegisterMcpReconciler(reconciler *reconcile.Reconciler)
}
type ConfigmapMgr struct {
@@ -89,6 +91,9 @@ func NewConfigmapMgr(XDSUpdater model.XDSUpdater, namespace string, higressConfi
globalOptionController := NewGlobalOptionController(namespace)
configmapMgr.AddItemControllers(globalOptionController)
mcpServerController := NewMcpServerController(namespace)
configmapMgr.AddItemControllers(mcpServerController)
configmapMgr.initEventHandlers()
return configmapMgr
@@ -108,6 +113,12 @@ func (c *ConfigmapMgr) GetHigressConfig() *HigressConfig {
return nil
}
func (c *ConfigmapMgr) SetMcpReconciler(reconciler *reconcile.Reconciler) {
for _, itemController := range c.ItemControllers {
itemController.RegisterMcpReconciler(reconciler)
}
}
func (c *ConfigmapMgr) AddItemControllers(controllers ...ItemController) {
c.ItemControllers = append(c.ItemControllers, controllers...)
}

View File

@@ -21,6 +21,7 @@ import (
"github.com/alibaba/higress/pkg/ingress/kube/util"
. "github.com/alibaba/higress/pkg/ingress/log"
"github.com/alibaba/higress/registry/reconcile"
networking "istio.io/api/networking/v1alpha3"
"istio.io/istio/pkg/config"
"istio.io/istio/pkg/config/schema/gvk"
@@ -376,6 +377,9 @@ func (g *GlobalOptionController) RegisterItemEventHandler(eventHandler ItemEvent
g.eventHandler = eventHandler
}
func (g *GlobalOptionController) RegisterMcpReconciler(reconciler *reconcile.Reconciler) {
}
// generateDownstreamEnvoyFilter generates the downstream envoy filter.
func (g *GlobalOptionController) generateDownstreamEnvoyFilter(downstreamValueStruct string, bufferLimitStruct string, routeTimeoutStruct string, namespace string) []*networking.EnvoyFilter_EnvoyConfigObjectPatch {
var downstreamConfig []*networking.EnvoyFilter_EnvoyConfigObjectPatch

View File

@@ -23,6 +23,7 @@ import (
"github.com/alibaba/higress/pkg/ingress/kube/util"
. "github.com/alibaba/higress/pkg/ingress/log"
"github.com/alibaba/higress/registry/reconcile"
networking "istio.io/api/networking/v1alpha3"
"istio.io/istio/pkg/config"
"istio.io/istio/pkg/config/schema/gvk"
@@ -291,6 +292,9 @@ func (g *GzipController) RegisterItemEventHandler(eventHandler ItemEventHandler)
g.eventHandler = eventHandler
}
func (g *GzipController) RegisterMcpReconciler(reconciler *reconcile.Reconciler) {
}
func (g *GzipController) constructGzipStruct(gzip *Gzip, namespace string) string {
gzipConfig := ""
contentType := ""

View File

@@ -0,0 +1,545 @@
// Copyright (c) 2022 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package configmap
import (
"encoding/json"
"errors"
"fmt"
"reflect"
"strings"
"sync/atomic"
"github.com/alibaba/higress/pkg/ingress/kube/util"
. "github.com/alibaba/higress/pkg/ingress/log"
"github.com/alibaba/higress/registry/reconcile"
networking "istio.io/api/networking/v1alpha3"
"istio.io/istio/pkg/config"
"istio.io/istio/pkg/config/schema/gvk"
)
// RedisConfig defines the configuration for Redis connection
type RedisConfig struct {
// The address of Redis server in the format of "host:port"
Address string `json:"address,omitempty"`
// The username for Redis authentication
Username string `json:"username,omitempty"`
// The password for Redis authentication
Password string `json:"password,omitempty"`
// The database index to use
DB int `json:"db,omitempty"`
}
// MCPRatelimitConfig defines the configuration for rate limit
type MCPRatelimitConfig struct {
// The limit of the rate limit
Limit int64 `json:"limit,omitempty"`
// The window of the rate limit
Window int64 `json:"window,omitempty"`
// The white list of the rate limit
WhiteList []string `json:"white_list,omitempty"`
}
// SSEServer defines the configuration for Server-Sent Events (SSE) server
type SSEServer struct {
// The name of the SSE server
Name string `json:"name,omitempty"`
// The path where the SSE server will be mounted, the full path is (PATH + SSEPathSuffix)
Path string `json:"path,omitempty"`
// The type of the SSE server
Type string `json:"type,omitempty"`
// Additional Config parameters for the real MCP server implementation
Config map[string]interface{} `json:"config,omitempty"`
// The domain list of the SSE server
DomainList []string `json:"domain_list,omitempty"`
}
// MatchRule defines a rule for matching requests
type MatchRule struct {
// Domain pattern, supports wildcards
MatchRuleDomain string `json:"match_rule_domain,omitempty"`
// Path pattern to match
MatchRulePath string `json:"match_rule_path,omitempty"`
// Type of match rule: exact, prefix, suffix, contains, regex
MatchRuleType string `json:"match_rule_type,omitempty"`
// Type of upstream(s) matched by the rule: rest (default), sse
UpstreamType string `json:"upstream_type"`
// Enable request path rewrite for matched routes
EnablePathRewrite bool `json:"enable_path_rewrite"`
// Prefix the request path would be rewritten to.
PathRewritePrefix string `json:"path_rewrite_prefix"`
}
// McpServer defines the configuration for MCP (Model Context Protocol) server
type McpServer struct {
// Flag to control whether MCP server is enabled
Enable bool `json:"enable,omitempty"`
// Redis Config for MCP server
Redis *RedisConfig `json:"redis,omitempty"`
// The suffix to be appended to SSE paths, default is "/sse"
SSEPathSuffix string `json:"sse_path_suffix,omitempty"`
// List of SSE servers Configs
Servers []*SSEServer `json:"servers,omitempty"`
// List of match rules for filtering requests
MatchList []*MatchRule `json:"match_list,omitempty"`
// Flag to control whether user level server is enabled
EnableUserLevelServer bool `json:"enable_user_level_server,omitempty"`
// Rate limit config for MCP server
Ratelimit *MCPRatelimitConfig `json:"rate_limit,omitempty"`
}
func NewDefaultMcpServer() *McpServer {
return &McpServer{
Enable: false,
Servers: make([]*SSEServer, 0),
MatchList: make([]*MatchRule, 0),
EnableUserLevelServer: false,
}
}
const (
higressMcpServerEnvoyFilterName = "higress-config-mcp-server"
)
func validMcpServer(m *McpServer) error {
if m == nil {
return nil
}
if m.EnableUserLevelServer && m.Redis == nil {
return errors.New("redis config cannot be empty when user level server is enabled")
}
// Validate match rule types
if m.MatchList != nil {
validMatchRuleTypes := map[string]bool{
"exact": true,
"prefix": true,
"suffix": true,
"contains": true,
"regex": true,
}
validUpstreamTypes := map[string]bool{
"rest": true,
"sse": true,
"streamable": true,
}
for _, rule := range m.MatchList {
if rule.MatchRuleType == "" {
return errors.New("match_rule_type cannot be empty, must be one of: exact, prefix, suffix, contains, regex")
}
if !validMatchRuleTypes[rule.MatchRuleType] {
return fmt.Errorf("invalid match_rule_type: %s, must be one of: exact, prefix, suffix, contains, regex", rule.MatchRuleType)
}
if rule.UpstreamType != "" && !validUpstreamTypes[rule.UpstreamType] {
return fmt.Errorf("invalid upstream_type: %s, must be one of: rest, sse, streamable", rule.UpstreamType)
}
if rule.EnablePathRewrite && rule.UpstreamType != "sse" {
return errors.New("path rewrite is only supported for SSE upstream type")
}
}
}
return nil
}
func compareMcpServer(old *McpServer, new *McpServer) (Result, error) {
if old == nil && new == nil {
return ResultNothing, nil
}
if new == nil {
return ResultDelete, nil
}
if !reflect.DeepEqual(old, new) {
return ResultReplace, nil
}
return ResultNothing, nil
}
func deepCopyMcpServer(mcp *McpServer) (*McpServer, error) {
newMcp := NewDefaultMcpServer()
newMcp.Enable = mcp.Enable
if mcp.Redis != nil {
newMcp.Redis = &RedisConfig{
Address: mcp.Redis.Address,
Username: mcp.Redis.Username,
Password: mcp.Redis.Password,
DB: mcp.Redis.DB,
}
}
if mcp.Ratelimit != nil {
newMcp.Ratelimit = &MCPRatelimitConfig{
Limit: mcp.Ratelimit.Limit,
Window: mcp.Ratelimit.Window,
WhiteList: mcp.Ratelimit.WhiteList,
}
}
newMcp.SSEPathSuffix = mcp.SSEPathSuffix
newMcp.EnableUserLevelServer = mcp.EnableUserLevelServer
if len(mcp.Servers) > 0 {
newMcp.Servers = make([]*SSEServer, len(mcp.Servers))
for i, server := range mcp.Servers {
newServer := &SSEServer{
Name: server.Name,
Path: server.Path,
Type: server.Type,
DomainList: server.DomainList,
}
if server.Config != nil {
newServer.Config = make(map[string]interface{})
for k, v := range server.Config {
newServer.Config[k] = v
}
}
newMcp.Servers[i] = newServer
}
}
if len(mcp.MatchList) > 0 {
newMcp.MatchList = make([]*MatchRule, len(mcp.MatchList))
for i, rule := range mcp.MatchList {
newMcp.MatchList[i] = &MatchRule{
MatchRuleDomain: rule.MatchRuleDomain,
MatchRulePath: rule.MatchRulePath,
MatchRuleType: rule.MatchRuleType,
UpstreamType: rule.UpstreamType,
EnablePathRewrite: rule.EnablePathRewrite,
PathRewritePrefix: rule.PathRewritePrefix,
}
}
}
return newMcp, nil
}
type McpServerController struct {
Namespace string
mcpServer atomic.Value
Name string
eventHandler ItemEventHandler
reconciler *reconcile.Reconciler
}
func NewMcpServerController(namespace string) *McpServerController {
mcpController := &McpServerController{
Namespace: namespace,
mcpServer: atomic.Value{},
Name: "mcpServer",
}
mcpController.SetMcpServer(NewDefaultMcpServer())
return mcpController
}
func (m *McpServerController) GetName() string {
return m.Name
}
func (m *McpServerController) SetMcpServer(mcp *McpServer) {
m.mcpServer.Store(mcp)
}
func (m *McpServerController) GetMcpServer() *McpServer {
value := m.mcpServer.Load()
if value != nil {
if mcp, ok := value.(*McpServer); ok {
return mcp
}
}
return nil
}
func (m *McpServerController) AddOrUpdateHigressConfig(name util.ClusterNamespacedName, old *HigressConfig, new *HigressConfig) error {
if err := validMcpServer(new.McpServer); err != nil {
IngressLog.Errorf("data:%+v convert to mcp server, error: %+v", new.McpServer, err)
return nil
}
result, _ := compareMcpServer(old.McpServer, new.McpServer)
switch result {
case ResultReplace:
if newMcp, err := deepCopyMcpServer(new.McpServer); err != nil {
IngressLog.Infof("mcp server deepcopy error:%v", err)
} else {
m.SetMcpServer(newMcp)
IngressLog.Infof("AddOrUpdate Higress config mcp server")
m.eventHandler(higressMcpServerEnvoyFilterName)
IngressLog.Infof("send event with filter name:%s", higressMcpServerEnvoyFilterName)
}
case ResultDelete:
m.SetMcpServer(NewDefaultMcpServer())
IngressLog.Infof("Delete Higress config mcp server")
m.eventHandler(higressMcpServerEnvoyFilterName)
IngressLog.Infof("send event with filter name:%s", higressMcpServerEnvoyFilterName)
}
return nil
}
func (m *McpServerController) ValidHigressConfig(higressConfig *HigressConfig) error {
if higressConfig == nil {
return nil
}
if higressConfig.McpServer == nil {
return nil
}
return validMcpServer(higressConfig.McpServer)
}
func (m *McpServerController) RegisterItemEventHandler(eventHandler ItemEventHandler) {
m.eventHandler = eventHandler
}
func (m *McpServerController) RegisterMcpReconciler(reconciler *reconcile.Reconciler) {
m.reconciler = reconciler
}
func (m *McpServerController) ConstructEnvoyFilters() ([]*config.Config, error) {
configs := make([]*config.Config, 0)
mcpServer := m.GetMcpServer()
namespace := m.Namespace
if mcpServer == nil || !mcpServer.Enable {
return configs, nil
}
// mcp-session envoy filter
mcpSessionStruct := m.constructMcpSessionStruct(mcpServer)
if mcpSessionStruct != "" {
sessionConfig := &config.Config{
Meta: config.Meta{
GroupVersionKind: gvk.EnvoyFilter,
Name: higressMcpServerEnvoyFilterName,
Namespace: namespace,
},
Spec: &networking.EnvoyFilter{
ConfigPatches: []*networking.EnvoyFilter_EnvoyConfigObjectPatch{
{
ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_GATEWAY,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: "envoy.filters.network.http_connection_manager",
SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{
Name: "envoy.filters.http.cors",
},
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_INSERT_AFTER,
Value: util.BuildPatchStruct(mcpSessionStruct),
},
},
},
},
}
configs = append(configs, sessionConfig)
}
// mcp-server envoy filter
mcpServerStruct := m.constructMcpServerStruct(mcpServer)
if mcpServerStruct != "" {
serverConfig := &config.Config{
Meta: config.Meta{
GroupVersionKind: gvk.EnvoyFilter,
Name: higressMcpServerEnvoyFilterName + "-server",
Namespace: namespace,
},
Spec: &networking.EnvoyFilter{
ConfigPatches: []*networking.EnvoyFilter_EnvoyConfigObjectPatch{
{
ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_GATEWAY,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: "envoy.filters.network.http_connection_manager",
SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{
Name: "envoy.filters.http.router",
},
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_INSERT_BEFORE,
Value: util.BuildPatchStruct(mcpServerStruct),
},
},
},
},
}
configs = append(configs, serverConfig)
}
return configs, nil
}
func (m *McpServerController) constructMcpSessionStruct(mcp *McpServer) string {
// Build match_list configuration
matchList := "[]"
var matchConfigs []string
if len(mcp.MatchList) > 0 {
for _, rule := range mcp.MatchList {
matchConfigs = append(matchConfigs, fmt.Sprintf(`{
"match_rule_domain": "%s",
"match_rule_path": "%s",
"match_rule_type": "%s",
"upstream_type": "%s",
"enable_path_rewrite": %t,
"path_rewrite_prefix": "%s"
}`, rule.MatchRuleDomain, rule.MatchRulePath, rule.MatchRuleType, rule.UpstreamType, rule.EnablePathRewrite, rule.PathRewritePrefix))
}
}
if m.reconciler != nil {
vsFromMcp := m.reconciler.GetAllConfigs(gvk.VirtualService)
for _, c := range vsFromMcp {
vs := c.Spec.(*networking.VirtualService)
var host string
if len(vs.Hosts) > 1 {
host = fmt.Sprintf("(%s)", strings.Join(vs.Hosts, "|"))
} else {
host = vs.Hosts[0]
}
path := vs.Http[0].Match[0].Uri.GetPrefix()
matchConfigs = append(matchConfigs, fmt.Sprintf(`{
"match_rule_domain": "%s",
"match_rule_path": "%s",
"match_rule_type": "prefix"
}`, host, path))
}
}
matchList = fmt.Sprintf("[%s]", strings.Join(matchConfigs, ","))
// Build redis configuration
redisConfig := "null"
if mcp.Redis != nil {
redisConfig = fmt.Sprintf(`{
"address": "%s",
"username": "%s",
"password": "%s",
"db": %d
}`, mcp.Redis.Address, mcp.Redis.Username, mcp.Redis.Password, mcp.Redis.DB)
}
// Build rate limit configuration
rateLimitConfig := "null"
if mcp.Ratelimit != nil {
whiteList := "[]"
if len(mcp.Ratelimit.WhiteList) > 0 {
whiteList = fmt.Sprintf(`["%s"]`, strings.Join(mcp.Ratelimit.WhiteList, `","`))
}
rateLimitConfig = fmt.Sprintf(`{
"limit": %d,
"window": %d,
"white_list": %s
}`, mcp.Ratelimit.Limit, mcp.Ratelimit.Window, whiteList)
}
// Build complete configuration structure
return fmt.Sprintf(`{
"name": "envoy.filters.http.golang",
"typed_config": {
"@type": "type.googleapis.com/udpa.type.v1.TypedStruct",
"type_url": "type.googleapis.com/envoy.extensions.filters.http.golang.v3alpha.Config",
"value": {
"library_id": "mcp-session",
"library_path": "/var/lib/istio/envoy/golang-filter.so",
"plugin_name": "mcp-session",
"plugin_config": {
"@type": "type.googleapis.com/xds.type.v3.TypedStruct",
"value": {
"redis": %s,
"rate_limit": %s,
"sse_path_suffix": "%s",
"match_list": %s,
"enable_user_level_server": %t
}
}
}
}
}`,
redisConfig,
rateLimitConfig,
mcp.SSEPathSuffix,
matchList,
mcp.EnableUserLevelServer)
}
func (m *McpServerController) constructMcpServerStruct(mcp *McpServer) string {
// Build servers configuration
servers := "[]"
if len(mcp.Servers) > 0 {
serverConfigs := make([]string, len(mcp.Servers))
for i, server := range mcp.Servers {
serverConfig := fmt.Sprintf(`{
"name": "%s",
"path": "%s",
"type": "%s"`,
server.Name, server.Path, server.Type)
if len(server.DomainList) > 0 {
domainList := fmt.Sprintf(`["%s"]`, strings.Join(server.DomainList, `","`))
serverConfig += fmt.Sprintf(`,
"domain_list": %s`, domainList)
}
if len(server.Config) > 0 {
config, _ := json.Marshal(server.Config)
serverConfig += fmt.Sprintf(`,
"config": %s`, string(config))
}
serverConfig += "}"
serverConfigs[i] = serverConfig
}
servers = fmt.Sprintf("[%s]", strings.Join(serverConfigs, ","))
}
// Build complete configuration structure
return fmt.Sprintf(`{
"name": "envoy.filters.http.golang",
"typed_config": {
"@type": "type.googleapis.com/udpa.type.v1.TypedStruct",
"type_url": "type.googleapis.com/envoy.extensions.filters.http.golang.v3alpha.Config",
"value": {
"library_id": "mcp-server",
"library_path": "/var/lib/istio/envoy/golang-filter.so",
"plugin_name": "mcp-server",
"plugin_config": {
"@type": "type.googleapis.com/xds.type.v3.TypedStruct",
"value": {
"servers": %s
}
}
}
}
}`, servers)
}

View File

@@ -0,0 +1,819 @@
// Copyright (c) 2022 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package configmap
import (
"encoding/json"
"errors"
"testing"
"github.com/alibaba/higress/pkg/ingress/kube/util"
"github.com/stretchr/testify/assert"
)
func Test_validMcpServer(t *testing.T) {
tests := []struct {
name string
mcp *McpServer
wantErr error
}{
{
name: "default",
mcp: &McpServer{
Enable: false,
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
wantErr: nil,
},
{
name: "nil",
mcp: nil,
wantErr: nil,
},
{
name: "enabled but no redis config",
mcp: &McpServer{
Enable: true,
EnableUserLevelServer: false,
Redis: nil,
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
wantErr: nil,
},
{
name: "enabled but bad match_rule_type",
mcp: &McpServer{
Enable: true,
EnableUserLevelServer: false,
Redis: nil,
MatchList: []*MatchRule{
{
MatchRuleDomain: "*",
MatchRulePath: "/mcp",
MatchRuleType: "bad-type",
},
},
Servers: []*SSEServer{},
},
wantErr: errors.New("invalid match_rule_type: bad-type, must be one of: exact, prefix, suffix, contains, regex"),
},
{
name: "enabled but bad upstream_type",
mcp: &McpServer{
Enable: true,
EnableUserLevelServer: false,
Redis: nil,
MatchList: []*MatchRule{
{
MatchRuleDomain: "*",
MatchRulePath: "/mcp",
MatchRuleType: "prefix",
UpstreamType: "bad-type",
},
},
Servers: []*SSEServer{},
},
wantErr: errors.New("invalid upstream_type: bad-type, must be one of: rest, sse, streamable"),
},
{
name: "enabled but path rewrite with unsupported upstream type",
mcp: &McpServer{
Enable: true,
EnableUserLevelServer: false,
Redis: nil,
MatchList: []*MatchRule{
{
MatchRuleDomain: "*",
MatchRulePath: "/mcp",
MatchRuleType: "prefix",
UpstreamType: "rest",
EnablePathRewrite: true,
PathRewritePrefix: "/",
},
},
Servers: []*SSEServer{},
},
wantErr: errors.New("path rewrite is only supported for SSE upstream type"),
},
{
name: "enabled with user level server but no redis config",
mcp: &McpServer{
Enable: true,
EnableUserLevelServer: true,
Redis: nil,
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
wantErr: errors.New("redis config cannot be empty when user level server is enabled"),
},
{
name: "valid config with redis",
mcp: &McpServer{
Enable: true,
EnableUserLevelServer: true,
Redis: &RedisConfig{
Address: "localhost:6379",
Username: "default",
Password: "password",
DB: 0,
},
SSEPathSuffix: "/sse",
MatchList: []*MatchRule{
{
MatchRuleDomain: "*",
MatchRulePath: "*",
MatchRuleType: "exact",
},
},
Servers: []*SSEServer{
{
Name: "test-server",
Path: "/test",
Type: "test",
Config: map[string]interface{}{
"key": "value",
},
},
},
},
wantErr: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := validMcpServer(tt.mcp)
assert.Equal(t, tt.wantErr, err)
})
}
}
func Test_compareMcpServer(t *testing.T) {
tests := []struct {
name string
old *McpServer
new *McpServer
wantResult Result
wantErr error
}{
{
name: "compare both nil",
old: nil,
new: nil,
wantResult: ResultNothing,
wantErr: nil,
},
{
name: "compare result delete",
old: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "localhost:6379",
},
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
new: nil,
wantResult: ResultDelete,
wantErr: nil,
},
{
name: "compare result equal",
old: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "localhost:6379",
},
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
new: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "localhost:6379",
},
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
wantResult: ResultNothing,
wantErr: nil,
},
{
name: "compare result replace",
old: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "localhost:6379",
},
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
new: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "redis:6379",
},
MatchList: []*MatchRule{
{
MatchRuleDomain: "*",
MatchRulePath: "/test",
MatchRuleType: "exact",
},
},
Servers: []*SSEServer{},
},
wantResult: ResultReplace,
wantErr: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := compareMcpServer(tt.old, tt.new)
assert.Equal(t, tt.wantResult, result)
assert.Equal(t, tt.wantErr, err)
})
}
}
func Test_deepCopyMcpServer(t *testing.T) {
tests := []struct {
name string
mcp *McpServer
wantMcp *McpServer
wantErr error
}{
{
name: "deep copy with redis only",
mcp: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "localhost:6379",
Username: "default",
Password: "password",
DB: 0,
},
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
wantMcp: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "localhost:6379",
Username: "default",
Password: "password",
DB: 0,
},
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
wantErr: nil,
},
{
name: "deep copy with full config",
mcp: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "localhost:6379",
Username: "default",
Password: "password",
DB: 0,
},
SSEPathSuffix: "/sse",
MatchList: []*MatchRule{
{
MatchRuleDomain: "*",
MatchRulePath: "*",
MatchRuleType: "exact",
},
},
Servers: []*SSEServer{
{
Name: "test-server",
Path: "/test",
Type: "test",
Config: map[string]interface{}{
"key": "value",
},
},
},
},
wantMcp: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "localhost:6379",
Username: "default",
Password: "password",
DB: 0,
},
SSEPathSuffix: "/sse",
MatchList: []*MatchRule{
{
MatchRuleDomain: "*",
MatchRulePath: "*",
MatchRuleType: "exact",
},
},
Servers: []*SSEServer{
{
Name: "test-server",
Path: "/test",
Type: "test",
Config: map[string]interface{}{
"key": "value",
},
},
},
},
wantErr: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mcp, err := deepCopyMcpServer(tt.mcp)
assert.Equal(t, tt.wantMcp, mcp)
assert.Equal(t, tt.wantErr, err)
})
}
}
func TestMcpServerController_AddOrUpdateHigressConfig(t *testing.T) {
eventPush := "default"
defaultHandler := func(name string) {
eventPush = "push"
}
defaultName := util.ClusterNamespacedName{}
tests := []struct {
name string
old *HigressConfig
new *HigressConfig
wantErr error
wantEventPush string
wantMcp *McpServer
}{
{
name: "default",
old: &HigressConfig{
McpServer: NewDefaultMcpServer(),
},
new: &HigressConfig{
McpServer: NewDefaultMcpServer(),
},
wantErr: nil,
wantEventPush: "default",
wantMcp: NewDefaultMcpServer(),
},
{
name: "replace and push - enable mcp server",
old: &HigressConfig{
McpServer: NewDefaultMcpServer(),
},
new: &HigressConfig{
McpServer: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "localhost:6379",
Username: "default",
Password: "password",
DB: 0,
},
Servers: []*SSEServer{},
MatchList: []*MatchRule{},
},
},
wantErr: nil,
wantEventPush: "push",
wantMcp: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "localhost:6379",
Username: "default",
Password: "password",
DB: 0,
},
Servers: []*SSEServer{},
MatchList: []*MatchRule{},
},
},
{
name: "replace and push - update config",
old: &HigressConfig{
McpServer: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "localhost:6379",
},
Servers: []*SSEServer{},
MatchList: []*MatchRule{},
},
},
new: &HigressConfig{
McpServer: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "redis:6379",
},
Servers: []*SSEServer{},
MatchList: []*MatchRule{},
},
},
wantErr: nil,
wantEventPush: "push",
wantMcp: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "redis:6379",
},
Servers: []*SSEServer{},
MatchList: []*MatchRule{},
},
},
{
name: "delete and push",
old: &HigressConfig{
McpServer: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "localhost:6379",
},
Servers: []*SSEServer{},
MatchList: []*MatchRule{},
},
},
new: &HigressConfig{
McpServer: nil,
},
wantErr: nil,
wantEventPush: "push",
wantMcp: NewDefaultMcpServer(),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := NewMcpServerController("higress-system")
m.eventHandler = defaultHandler
eventPush = "default"
err := m.AddOrUpdateHigressConfig(defaultName, tt.old, tt.new)
assert.Equal(t, tt.wantEventPush, eventPush)
assert.Equal(t, tt.wantErr, err)
assert.Equal(t, tt.wantMcp, m.GetMcpServer())
})
}
}
func TestMcpServerController_ValidHigressConfig(t *testing.T) {
tests := []struct {
name string
higressConfig *HigressConfig
wantErr error
}{
{
name: "nil config",
higressConfig: nil,
wantErr: nil,
},
{
name: "nil mcp server",
higressConfig: &HigressConfig{
McpServer: nil,
},
wantErr: nil,
},
{
name: "valid config",
higressConfig: &HigressConfig{
McpServer: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "localhost:6379",
},
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
},
wantErr: nil,
},
{
name: "invalid config - user level server without redis",
higressConfig: &HigressConfig{
McpServer: &McpServer{
Enable: true,
EnableUserLevelServer: true,
Redis: nil,
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
},
wantErr: errors.New("redis config cannot be empty when user level server is enabled"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := NewMcpServerController("test-namespace")
err := m.ValidHigressConfig(tt.higressConfig)
assert.Equal(t, tt.wantErr, err)
})
}
}
func TestMcpServerController_ConstructEnvoyFilters(t *testing.T) {
tests := []struct {
name string
mcpServer *McpServer
wantConfigs int
wantErr error
}{
{
name: "nil mcp server",
mcpServer: nil,
wantConfigs: 0,
wantErr: nil,
},
{
name: "disabled mcp server",
mcpServer: &McpServer{
Enable: false,
},
wantConfigs: 0,
wantErr: nil,
},
{
name: "valid mcp server with redis",
mcpServer: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "localhost:6379",
},
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
wantConfigs: 2, // Both session and server filters
wantErr: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := NewMcpServerController("test-namespace")
m.mcpServer.Store(tt.mcpServer)
configs, err := m.ConstructEnvoyFilters()
assert.Equal(t, tt.wantErr, err)
assert.Equal(t, tt.wantConfigs, len(configs))
})
}
}
func TestMcpServerController_constructMcpSessionStruct(t *testing.T) {
tests := []struct {
name string
mcp *McpServer
wantJSON string
}{
{
name: "minimal config",
mcp: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "localhost:6379",
},
MatchList: []*MatchRule{},
Servers: []*SSEServer{},
},
wantJSON: `{
"name": "envoy.filters.http.golang",
"typed_config": {
"@type": "type.googleapis.com/udpa.type.v1.TypedStruct",
"type_url": "type.googleapis.com/envoy.extensions.filters.http.golang.v3alpha.Config",
"value": {
"library_id": "mcp-session",
"library_path": "/var/lib/istio/envoy/golang-filter.so",
"plugin_name": "mcp-session",
"plugin_config": {
"@type": "type.googleapis.com/xds.type.v3.TypedStruct",
"value": {
"redis": {
"address": "localhost:6379",
"username": "",
"password": "",
"db": 0
},
"rate_limit": null,
"sse_path_suffix": "",
"match_list": [],
"enable_user_level_server": false
}
}
}
}
}`,
},
{
name: "full config",
mcp: &McpServer{
Enable: true,
Redis: &RedisConfig{
Address: "localhost:6379",
Username: "user",
Password: "pass",
DB: 1,
},
SSEPathSuffix: "/sse",
MatchList: []*MatchRule{
{
MatchRuleDomain: "*",
MatchRulePath: "/test",
MatchRuleType: "exact",
},
{
MatchRuleDomain: "*",
MatchRulePath: "/sse-test-1",
MatchRuleType: "prefix",
UpstreamType: "sse",
},
{
MatchRuleDomain: "*",
MatchRulePath: "/sse-test-2",
MatchRuleType: "prefix",
UpstreamType: "sse",
EnablePathRewrite: true,
PathRewritePrefix: "/mcp",
},
},
EnableUserLevelServer: true,
Ratelimit: &MCPRatelimitConfig{
Limit: 100,
Window: 3600,
WhiteList: []string{"user1", "user2"},
},
},
wantJSON: `{
"name": "envoy.filters.http.golang",
"typed_config": {
"@type": "type.googleapis.com/udpa.type.v1.TypedStruct",
"type_url": "type.googleapis.com/envoy.extensions.filters.http.golang.v3alpha.Config",
"value": {
"library_id": "mcp-session",
"library_path": "/var/lib/istio/envoy/golang-filter.so",
"plugin_name": "mcp-session",
"plugin_config": {
"@type": "type.googleapis.com/xds.type.v3.TypedStruct",
"value": {
"redis": {
"address": "localhost:6379",
"username": "user",
"password": "pass",
"db": 1
},
"rate_limit": {
"limit": 100,
"window": 3600,
"white_list": ["user1","user2"]
},
"sse_path_suffix": "/sse",
"match_list": [{
"match_rule_domain": "*",
"match_rule_path": "/test",
"match_rule_type": "exact",
"upstream_type": "",
"enable_path_rewrite": false,
"path_rewrite_prefix": ""
},{
"match_rule_domain": "*",
"match_rule_path": "/sse-test-1",
"match_rule_type": "prefix",
"upstream_type": "sse",
"enable_path_rewrite": false,
"path_rewrite_prefix": ""
},{
"match_rule_domain": "*",
"match_rule_path": "/sse-test-2",
"match_rule_type": "prefix",
"upstream_type": "sse",
"enable_path_rewrite": true,
"path_rewrite_prefix": "/mcp"
}],
"enable_user_level_server": true
}
}
}
}
}`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := NewMcpServerController("test-namespace")
got := m.constructMcpSessionStruct(tt.mcp)
// Normalize JSON strings for comparison
var gotJSON, wantJSON interface{}
json.Unmarshal([]byte(got), &gotJSON)
json.Unmarshal([]byte(tt.wantJSON), &wantJSON)
assert.Equal(t, wantJSON, gotJSON)
})
}
}
func TestMcpServerController_constructMcpServerStruct(t *testing.T) {
tests := []struct {
name string
mcp *McpServer
wantJSON string
}{
{
name: "no servers",
mcp: &McpServer{
Servers: []*SSEServer{},
},
wantJSON: `{
"name": "envoy.filters.http.golang",
"typed_config": {
"@type": "type.googleapis.com/udpa.type.v1.TypedStruct",
"type_url": "type.googleapis.com/envoy.extensions.filters.http.golang.v3alpha.Config",
"value": {
"library_id": "mcp-server",
"library_path": "/var/lib/istio/envoy/golang-filter.so",
"plugin_name": "mcp-server",
"plugin_config": {
"@type": "type.googleapis.com/xds.type.v3.TypedStruct",
"value": {
"servers": []
}
}
}
}
}`,
},
{
name: "with servers",
mcp: &McpServer{
Servers: []*SSEServer{
{
Name: "test-server",
Path: "/test",
Type: "test",
Config: map[string]interface{}{
"key": "value",
},
DomainList: []string{"example.com"},
},
},
},
wantJSON: `{
"name": "envoy.filters.http.golang",
"typed_config": {
"@type": "type.googleapis.com/udpa.type.v1.TypedStruct",
"type_url": "type.googleapis.com/envoy.extensions.filters.http.golang.v3alpha.Config",
"value": {
"library_id": "mcp-server",
"library_path": "/var/lib/istio/envoy/golang-filter.so",
"plugin_name": "mcp-server",
"plugin_config": {
"@type": "type.googleapis.com/xds.type.v3.TypedStruct",
"value": {
"servers": [{
"name": "test-server",
"path": "/test",
"type": "test",
"domain_list": ["example.com"],
"config": {"key":"value"}
}]
}
}
}
}
}`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := NewMcpServerController("test-namespace")
got := m.constructMcpServerStruct(tt.mcp)
// Normalize JSON strings for comparison
var gotJSON, wantJSON interface{}
json.Unmarshal([]byte(got), &gotJSON)
json.Unmarshal([]byte(tt.wantJSON), &wantJSON)
assert.Equal(t, wantJSON, gotJSON)
})
}
}

View File

@@ -21,6 +21,7 @@ import (
"reflect"
"sync/atomic"
"github.com/alibaba/higress/registry/reconcile"
"istio.io/istio/pkg/config"
"istio.io/istio/pkg/config/schema/gvk"
@@ -237,6 +238,9 @@ func (t *TracingController) RegisterItemEventHandler(eventHandler ItemEventHandl
t.eventHandler = eventHandler
}
func (t *TracingController) RegisterMcpReconciler(reconciler *reconcile.Reconciler) {
}
func (t *TracingController) ConstructEnvoyFilters() ([]*config.Config, error) {
configs := make([]*config.Config, 0)
tracing := t.GetTracing()

View File

@@ -15,21 +15,33 @@
package http2rpc
import (
"istio.io/istio/pkg/cluster"
"time"
"istio.io/istio/pkg/kube/controllers"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/tools/cache"
v1 "github.com/alibaba/higress/client/pkg/apis/networking/v1"
"github.com/alibaba/higress/client/pkg/clientset/versioned"
informersv1 "github.com/alibaba/higress/client/pkg/informers/externalversions/networking/v1"
listersv1 "github.com/alibaba/higress/client/pkg/listers/networking/v1"
"github.com/alibaba/higress/pkg/ingress/kube/common"
"github.com/alibaba/higress/pkg/ingress/kube/controller"
kubeclient "github.com/alibaba/higress/pkg/kube"
)
type Http2RpcController controller.Controller[listersv1.Http2RpcLister]
func NewController(client kubeclient.Client, clusterId cluster.ID) Http2RpcController {
informer := client.HigressInformer().Networking().V1().Http2Rpcs().Informer()
return controller.NewCommonController("http2rpc", client.HigressInformer().Networking().V1().Http2Rpcs().Lister(),
informer, GetHttp2Rpc, clusterId)
func NewController(client kubeclient.Client, options common.Options) Http2RpcController {
var informer cache.SharedIndexInformer
if options.WatchNamespace == "" {
informer = client.HigressInformer().Networking().V1().Http2Rpcs().Informer()
} else {
informer = client.HigressInformer().InformerFor(&v1.Http2Rpc{}, func(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return informersv1.NewHttp2RpcInformer(client, options.WatchNamespace, resyncPeriod, nil)
})
}
return controller.NewCommonController("http2rpc", listersv1.NewHttp2RpcLister(informer.GetIndexer()), informer, GetHttp2Rpc, options.ClusterId)
}
func GetHttp2Rpc(lister listersv1.Http2RpcLister, namespacedName types.NamespacedName) (controllers.Object, error) {

View File

@@ -100,7 +100,7 @@ type controller struct {
// NewController creates a new Kubernetes controller
func NewController(localKubeClient, client kubeclient.Client, options common.Options,
secretController secret.SecretController) common.IngressController {
opts := ktypes.InformerOptions{}
opts := ktypes.InformerOptions{Namespace: options.WatchNamespace}
ingressInformer := util.GetInformerFiltered(client, opts, gvrIngressV1Beta1, &ingress.Ingress{},
func(options metav1.ListOptions) (runtime.Object, error) {
return client.Kube().NetworkingV1beta1().Ingresses(opts.Namespace).List(context.Background(), options)

View File

@@ -54,7 +54,7 @@ func TestIngressControllerApplies(t *testing.T) {
options := common.Options{IngressClass: "mse", ClusterId: ""}
secretController := secret.NewController(localKubeClient, options.ClusterId)
secretController := secret.NewController(localKubeClient, options)
ingressController := NewController(localKubeClient, client, options, secretController)
testcases := map[string]func(*testing.T, common.IngressController){
@@ -253,7 +253,7 @@ func TestIngressControllerConventions(t *testing.T) {
options := common.Options{IngressClass: "mse", ClusterId: "", EnableStatus: true}
secretController := secret.NewController(localKubeClient, options.ClusterId)
secretController := secret.NewController(localKubeClient, options)
ingressController := NewController(localKubeClient, client, options, secretController)
testcases := map[string]func(*testing.T, common.IngressController){
@@ -1142,7 +1142,7 @@ func TestIngressControllerProcessing(t *testing.T) {
options := common.Options{IngressClass: "mse", ClusterId: "", EnableStatus: true}
secretController := secret.NewController(localKubeClient, options.ClusterId)
secretController := secret.NewController(localKubeClient, options)
opts := ktypes.InformerOptions{}
ingressInformer := util.GetInformerFiltered(fakeClient, opts, gvrIngressV1Beta1, &ingress.Ingress{},

View File

@@ -81,8 +81,6 @@ func (s *statusSyncer) runUpdateStatus() error {
return err
}
IngressLog.Debugf("found number %d of svc", len(svcList))
lbStatusList := common.GetLbStatusListV1Beta1(svcList)
if len(lbStatusList) == 0 {
return nil

View File

@@ -92,7 +92,7 @@ type controller struct {
// NewController creates a new Kubernetes controller
func NewController(localKubeClient, client kubeclient.Client, options common.Options, secretController secret.SecretController) common.IngressController {
opts := ktypes.InformerOptions{}
opts := ktypes.InformerOptions{Namespace: options.WatchNamespace}
ingressInformer := schemakubeclient.GetInformerFilteredFromGVR(client, opts, gvr.Ingress)
ingressLister := networkinglister.NewIngressLister(ingressInformer.Informer.GetIndexer())
serviceInformer := schemakubeclient.GetInformerFilteredFromGVR(client, opts, gvr.Service)
@@ -162,6 +162,7 @@ func (c *controller) onEvent(namespacedName types.NamespacedName) error {
delete(c.ingresses, namespacedName.String())
c.mutex.Unlock()
} else {
IngressLog.Warnf("ingressLister Get failed, ingress: %s, err: %v", namespacedName, err)
return err
}
}
@@ -171,7 +172,7 @@ func (c *controller) onEvent(namespacedName types.NamespacedName) error {
return nil
}
IngressLog.Debugf("ingress: %s, event: %s", namespacedName, event)
IngressLog.Infof("ingress: %s, event: %s", namespacedName, event)
// we should check need process only when event is not delete,
// if it is delete event, and previously processed, we need to process too.
@@ -181,7 +182,7 @@ func (c *controller) onEvent(namespacedName types.NamespacedName) error {
return err
}
if !shouldProcess {
IngressLog.Infof("no need process, ingress %s", namespacedName)
IngressLog.Infof("no need process, ingress: %s", namespacedName)
return nil
}
}
@@ -279,10 +280,17 @@ func (c *controller) List() []config.Config {
for _, raw := range c.ingressInformer.Informer.GetStore().List() {
ing, ok := raw.(*ingress.Ingress)
if !ok {
IngressLog.Warnf("get ingress from informer failed: %v", raw)
continue
}
if should, err := c.shouldProcessIngress(ing); !should || err != nil {
should, err := c.shouldProcessIngress(ing)
if err != nil {
IngressLog.Warnf("check should process ingress failed: %v", err)
continue
}
if !should {
IngressLog.Debugf("no need process ingress: %s/%s", ing.Namespace, ing.Name)
continue
}

View File

@@ -81,8 +81,6 @@ func (s *statusSyncer) runUpdateStatus() error {
return err
}
IngressLog.Debugf("found number %d of svc", len(svcList))
lbStatusList := common.GetLbStatusListV1(svcList)
if len(lbStatusList) == 0 {
return nil

View File

@@ -21,6 +21,7 @@ import (
"sort"
"strings"
"sync"
"time"
"github.com/hashicorp/go-multierror"
networking "istio.io/api/networking/v1alpha3"
@@ -43,7 +44,9 @@ import (
listerv1 "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/tools/cache"
ingress "knative.dev/networking/pkg/apis/networking/v1alpha1"
networkingv1alpha1 "knative.dev/networking/pkg/client/listers/networking/v1alpha1"
"knative.dev/networking/pkg/client/clientset/versioned"
informernetworkingv1alpha1 "knative.dev/networking/pkg/client/informers/externalversions/networking/v1alpha1"
listernetworkingv1alpha1 "knative.dev/networking/pkg/client/listers/networking/v1alpha1"
"github.com/alibaba/higress/pkg/ingress/kube/annotations"
"github.com/alibaba/higress/pkg/ingress/kube/common"
@@ -76,7 +79,7 @@ type controller struct {
ingresses map[string]*ingress.Ingress
ingressInformer cache.SharedInformer
ingressLister networkingv1alpha1.IngressLister
ingressLister listernetworkingv1alpha1.IngressLister
serviceInformer informerfactory.StartableInformer
serviceLister listerv1.ServiceLister
secretController secret.SecretController
@@ -86,16 +89,23 @@ type controller struct {
// NewController creates a new Kubernetes controller
func NewController(localKubeClient, client kube.Client, options common.Options,
secretController secret.SecretController) common.KIngressController {
//var namespace string = "default"
ingressInformer := client.KIngressInformer().Networking().V1alpha1().Ingresses()
serviceInformer := schemakubeclient.GetInformerFilteredFromGVR(client, ktypes.InformerOptions{}, gvr.Service)
var ingressInformer cache.SharedIndexInformer
if options.WatchNamespace == "" {
ingressInformer = client.KIngressInformer().Networking().V1alpha1().Ingresses().Informer()
} else {
ingressInformer = client.KIngressInformer().InformerFor(&ingress.Ingress{}, func(c versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return informernetworkingv1alpha1.NewIngressInformer(c, options.WatchNamespace, resyncPeriod, nil)
})
}
ingressLister := listernetworkingv1alpha1.NewIngressLister(ingressInformer.GetIndexer())
serviceInformer := schemakubeclient.GetInformerFilteredFromGVR(client, ktypes.InformerOptions{Namespace: options.WatchNamespace}, gvr.Service)
serviceLister := listerv1.NewServiceLister(serviceInformer.Informer.GetIndexer())
c := &controller{
options: options,
ingresses: make(map[string]*ingress.Ingress),
ingressInformer: ingressInformer.Informer(),
ingressLister: ingressInformer.Lister(),
ingressInformer: ingressInformer,
ingressLister: ingressLister,
serviceInformer: serviceInformer,
serviceLister: serviceLister,
secretController: secretController,

View File

@@ -154,7 +154,7 @@ func TestKIngressControllerConventions(t *testing.T) {
options := common.Options{IngressClass: "mse", ClusterId: "", EnableStatus: true}
secretController := secret.NewController(localKubeClient, options.ClusterId)
secretController := secret.NewController(localKubeClient, options)
ingressController := NewController(localKubeClient, client, options, secretController)
testcases := map[string]func(*testing.T, common.KIngressController){

View File

@@ -77,7 +77,6 @@ func (s *statusSyncer) runUpdateStatus() error {
return err
}
IngressLog.Debugf("found number %d of svc", len(svcList))
lbStatusList := common2.GetLbStatusList(svcList)
return s.updateStatus(lbStatusList)
}

View File

@@ -15,21 +15,33 @@
package mcpbridge
import (
"istio.io/istio/pkg/cluster"
"time"
"istio.io/istio/pkg/kube/controllers"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/tools/cache"
v1 "github.com/alibaba/higress/client/pkg/apis/networking/v1"
"github.com/alibaba/higress/client/pkg/clientset/versioned"
informersv1 "github.com/alibaba/higress/client/pkg/informers/externalversions/networking/v1"
listersv1 "github.com/alibaba/higress/client/pkg/listers/networking/v1"
"github.com/alibaba/higress/pkg/ingress/kube/common"
"github.com/alibaba/higress/pkg/ingress/kube/controller"
kubeclient "github.com/alibaba/higress/pkg/kube"
)
type McpBridgeController controller.Controller[listersv1.McpBridgeLister]
func NewController(client kubeclient.Client, clusterId cluster.ID) McpBridgeController {
informer := client.HigressInformer().Networking().V1().McpBridges().Informer()
return controller.NewCommonController("mcpbridge", client.HigressInformer().Networking().V1().McpBridges().Lister(),
informer, GetMcpBridge, clusterId)
func NewController(client kubeclient.Client, options common.Options) McpBridgeController {
var informer cache.SharedIndexInformer
if options.WatchNamespace == "" {
informer = client.HigressInformer().Networking().V1().McpBridges().Informer()
} else {
informer = client.HigressInformer().InformerFor(&v1.McpBridge{}, func(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return informersv1.NewMcpBridgeInformer(client, options.WatchNamespace, resyncPeriod, nil)
})
}
return controller.NewCommonController("mcpbridge", listersv1.NewMcpBridgeLister(informer.GetIndexer()), informer, GetMcpBridge, options.ClusterId)
}
func GetMcpBridge(lister listersv1.McpBridgeLister, namespacedName types.NamespacedName) (controllers.Object, error) {

View File

@@ -15,15 +15,14 @@
package secret
import (
"github.com/alibaba/higress/pkg/ingress/kube/common"
"github.com/alibaba/higress/pkg/ingress/kube/controller"
"istio.io/istio/pkg/cluster"
"istio.io/istio/pkg/config/schema/gvr"
schemakubeclient "istio.io/istio/pkg/config/schema/kubeclient"
kubeclient "istio.io/istio/pkg/kube"
"istio.io/istio/pkg/kube/controllers"
ktypes "istio.io/istio/pkg/kube/kubetypes"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/types"
listersv1 "k8s.io/client-go/listers/core/v1"
@@ -31,17 +30,17 @@ import (
type SecretController controller.Controller[listersv1.SecretLister]
func NewController(client kubeclient.Client, clusterId cluster.ID) SecretController {
func NewController(client kubeclient.Client, options common.Options) SecretController {
opts := ktypes.InformerOptions{
Namespace: metav1.NamespaceAll,
Cluster: clusterId,
Namespace: options.WatchNamespace,
Cluster: options.ClusterId,
FieldSelector: fields.AndSelectors(
fields.OneTermNotEqualSelector("type", "helm.sh/release.v1"),
fields.OneTermNotEqualSelector("type", string(v1.SecretTypeServiceAccountToken)),
).String(),
}
informer := schemakubeclient.GetInformerFilteredFromGVR(client, opts, gvr.Secret)
return controller.NewCommonController("secret", listersv1.NewSecretLister(informer.Informer.GetIndexer()), informer.Informer, GetSecret, clusterId)
return controller.NewCommonController("secret", listersv1.NewSecretLister(informer.Informer.GetIndexer()), informer.Informer, GetSecret, options.ClusterId)
}
func GetSecret(lister listersv1.SecretLister, namespacedName types.NamespacedName) (controllers.Object, error) {

View File

@@ -16,6 +16,7 @@ package secret
import (
"context"
"github.com/alibaba/higress/pkg/ingress/kube/common"
"reflect"
"sync"
"testing"
@@ -43,7 +44,7 @@ var period = time.Second
func TestController(t *testing.T) {
client := kubeclient.NewFakeClient()
ctrl := NewController(client, "fake-cluster")
ctrl := NewController(client, common.Options{ClusterId: "fake-cluster"})
stop := make(chan struct{})
t.Cleanup(func() {

View File

@@ -15,21 +15,33 @@
package wasmplugin
import (
"istio.io/istio/pkg/cluster"
"time"
"istio.io/istio/pkg/kube/controllers"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/tools/cache"
v1 "github.com/alibaba/higress/client/pkg/apis/extensions/v1alpha1"
"github.com/alibaba/higress/client/pkg/clientset/versioned"
informersv1 "github.com/alibaba/higress/client/pkg/informers/externalversions/extensions/v1alpha1"
listersv1 "github.com/alibaba/higress/client/pkg/listers/extensions/v1alpha1"
"github.com/alibaba/higress/pkg/ingress/kube/common"
"github.com/alibaba/higress/pkg/ingress/kube/controller"
kubeclient "github.com/alibaba/higress/pkg/kube"
)
type WasmPluginController controller.Controller[listersv1.WasmPluginLister]
func NewController(client kubeclient.Client, clusterId cluster.ID) WasmPluginController {
informer := client.HigressInformer().Extensions().V1alpha1().WasmPlugins().Informer()
return controller.NewCommonController("wasmplugin", client.HigressInformer().Extensions().V1alpha1().WasmPlugins().Lister(),
informer, GetWasmPlugin, clusterId)
func NewController(client kubeclient.Client, options common.Options) WasmPluginController {
var informer cache.SharedIndexInformer
if options.WatchNamespace == "" {
informer = client.HigressInformer().Extensions().V1alpha1().WasmPlugins().Informer()
} else {
informer = client.HigressInformer().InformerFor(&v1.WasmPlugin{}, func(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return informersv1.NewWasmPluginInformer(client, options.WatchNamespace, resyncPeriod, nil)
})
}
return controller.NewCommonController("wasmplugin", listersv1.NewWasmPluginLister(informer.GetIndexer()), informer, GetWasmPlugin, options.ClusterId)
}
func GetWasmPlugin(lister listersv1.WasmPluginLister, namespacedName types.NamespacedName) (controllers.Object, error) {

View File

@@ -14,6 +14,6 @@
package log
import "istio.io/pkg/log"
import "istio.io/istio/pkg/log"
var IngressLog = log.RegisterScope("ingress", "Higress Ingress process.", 0)
var IngressLog = log.RegisterScope("ingress", "Higress Ingress process.")

View File

@@ -19,7 +19,6 @@ import (
"istio.io/istio/pilot/pkg/model"
istiomodel "istio.io/istio/pilot/pkg/model"
"istio.io/istio/pkg/cluster"
"istio.io/istio/pkg/config"
"istio.io/istio/pkg/config/schema/collection"
"istio.io/istio/pkg/config/schema/gvk"
@@ -45,13 +44,13 @@ type IngressTranslation struct {
higressDomainCache model.IngressDomainCollection
}
func NewIngressTranslation(localKubeClient kube.Client, xdsUpdater istiomodel.XDSUpdater, namespace string, clusterId cluster.ID) *IngressTranslation {
if clusterId == "Kubernetes" {
clusterId = ""
func NewIngressTranslation(localKubeClient kube.Client, xdsUpdater istiomodel.XDSUpdater, namespace string, options common.Options) *IngressTranslation {
if options.ClusterId == "Kubernetes" {
options.ClusterId = ""
}
Config := &IngressTranslation{
ingressConfig: ingressconfig.NewIngressConfig(localKubeClient, xdsUpdater, namespace, clusterId),
kingressConfig: ingressconfig.NewKIngressConfig(localKubeClient, xdsUpdater, namespace, clusterId),
ingressConfig: ingressconfig.NewIngressConfig(localKubeClient, xdsUpdater, namespace, options),
kingressConfig: ingressconfig.NewKIngressConfig(localKubeClient, xdsUpdater, namespace, options),
}
return Config
}

View File

@@ -0,0 +1,39 @@
FROM golang:1.22-bullseye AS golang-base
ARG GOPROXY
ARG GO_FILTER_NAME
ARG GOARCH
ENV GOFLAGS=-buildvcs=false
ENV GOPROXY=${GOPROXY}
ENV GOARCH=${GOARCH}
ENV CGO_ENABLED=1
# 根据目标架构安装对应的编译工具
RUN if [ "$GOARCH" = "arm64" ]; then \
echo "Installing ARM64 toolchain" && \
apt-get update && \
apt-get install -y gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu; \
else \
echo "Installing AMD64 toolchain" && \
apt-get update && \
apt-get install -y gcc binutils; \
fi
WORKDIR /workspace
COPY . .
WORKDIR /workspace
RUN go mod tidy
RUN if [ "$GOARCH" = "arm64" ]; then \
CC=aarch64-linux-gnu-gcc AS=aarch64-linux-gnu-as go build -o /$GO_FILTER_NAME.so -buildmode=c-shared .; \
else \
go build -o /$GO_FILTER_NAME.so -buildmode=c-shared .; \
fi
FROM scratch AS output
ARG GO_FILTER_NAME
ARG GOARCH
COPY --from=golang-base /${GO_FILTER_NAME}.so golang-filter_${GOARCH}.so

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