mirror of
https://github.com/alibaba/higress.git
synced 2026-02-26 05:30:50 +08:00
Compare commits
162 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26654aefc0 | ||
|
|
70176cde3e | ||
|
|
7b1f538d38 | ||
|
|
344035698a | ||
|
|
9136908354 | ||
|
|
de1dd3bfbc | ||
|
|
0c1db17de6 | ||
|
|
8cbe16f77c | ||
|
|
8ed4c5609a | ||
|
|
9ea1903ce6 | ||
|
|
6835486725 | ||
|
|
265df42456 | ||
|
|
3b1b621627 | ||
|
|
901ad9619d | ||
|
|
4a5127fedc | ||
|
|
4e44e7a1bb | ||
|
|
b54a2e7387 | ||
|
|
124caf8785 | ||
|
|
754ec71d6e | ||
|
|
d8e91851d9 | ||
|
|
86b223bc75 | ||
|
|
a18879bf86 | ||
|
|
970cfd44ee | ||
|
|
f685b0353a | ||
|
|
e135789c3e | ||
|
|
3e72d4b1f0 | ||
|
|
1ded5322a5 | ||
|
|
be8563765e | ||
|
|
45c4c80a66 | ||
|
|
d8c34bb863 | ||
|
|
4e392d1cf6 | ||
|
|
5b663ae412 | ||
|
|
fcf19535f9 | ||
|
|
14e43aa921 | ||
|
|
64ccbab29c | ||
|
|
945787f7dc | ||
|
|
792b9b0ee5 | ||
|
|
26ed9a6d93 | ||
|
|
ed36a4989f | ||
|
|
f23e26374f | ||
|
|
eb2934c084 | ||
|
|
2da1c62c69 | ||
|
|
fab734d39a | ||
|
|
2393af5c85 | ||
|
|
b142f51776 | ||
|
|
587267a733 | ||
|
|
a2078711f5 | ||
|
|
dc54c581f3 | ||
|
|
b47d74bce5 | ||
|
|
8d8ad6d624 | ||
|
|
8062625d75 | ||
|
|
54a8a906ae | ||
|
|
8659895a91 | ||
|
|
dc3e496aa0 | ||
|
|
8747e1ddad | ||
|
|
2b9e3a14c2 | ||
|
|
1051201e97 | ||
|
|
8b24a20651 | ||
|
|
02b98dc4d8 | ||
|
|
e96f9a078c | ||
|
|
8e7793c470 | ||
|
|
e224df6bb4 | ||
|
|
a6444af185 | ||
|
|
8e28ae781d | ||
|
|
d58e781900 | ||
|
|
6861a78bb1 | ||
|
|
c3789416d6 | ||
|
|
1913508f5e | ||
|
|
0eaa9389c9 | ||
|
|
8048436604 | ||
|
|
ec229e69ac | ||
|
|
f8f8b41fa2 | ||
|
|
c49c8f1ec2 | ||
|
|
49269b4303 | ||
|
|
35d5669b51 | ||
|
|
1f154c59f1 | ||
|
|
8c206a6456 | ||
|
|
d307d0e755 | ||
|
|
9b88c6bb40 | ||
|
|
e5105a4d71 | ||
|
|
564c7d8193 | ||
|
|
3700ada7e6 | ||
|
|
3b78a0eb62 | ||
|
|
0620346761 | ||
|
|
aa17e9598d | ||
|
|
fa834634b7 | ||
|
|
4ff311e0fc | ||
|
|
90b7f209e2 | ||
|
|
6e1dd5bbc8 | ||
|
|
a392d0cf34 | ||
|
|
43034d7d61 | ||
|
|
8c76ae26bb | ||
|
|
c1250aec2e | ||
|
|
02bc319eef | ||
|
|
28892cf3ae | ||
|
|
bee03a37a4 | ||
|
|
2a97921d2b | ||
|
|
d4dbaba760 | ||
|
|
d718870b65 | ||
|
|
b65446fa25 | ||
|
|
3fd37abab7 | ||
|
|
81e467b624 | ||
|
|
736eea6cf9 | ||
|
|
c32e1ab69b | ||
|
|
fc05a3b256 | ||
|
|
9fc2760b7d | ||
|
|
be88647752 | ||
|
|
a56172095a | ||
|
|
f3270123ba | ||
|
|
5e2d62406b | ||
|
|
39cab9d724 | ||
|
|
89865733f6 | ||
|
|
1ccf9195b2 | ||
|
|
7d2a05ef1c | ||
|
|
32c2acefda | ||
|
|
ea7b581e26 | ||
|
|
ac2f0a5545 | ||
|
|
51d7124454 | ||
|
|
ec6a185adc | ||
|
|
f9ffda288b | ||
|
|
2dbe41324a | ||
|
|
80d6ecfddb | ||
|
|
b23fae7a12 | ||
|
|
2c19d97252 | ||
|
|
efd7ccd5fe | ||
|
|
81fd0d6386 | ||
|
|
176ddc6963 | ||
|
|
44637c2449 | ||
|
|
3e68ae75d1 | ||
|
|
18ad817edb | ||
|
|
d48e0ce773 | ||
|
|
9734ffeb3e | ||
|
|
1421ce8667 | ||
|
|
625c06e58f | ||
|
|
e4a47dfb46 | ||
|
|
6b483189ac | ||
|
|
74ad9a555a | ||
|
|
f6e181ecb6 | ||
|
|
30a5b2ab2b | ||
|
|
91a23cc27e | ||
|
|
51e515d53e | ||
|
|
67274bfa0d | ||
|
|
4f24979579 | ||
|
|
1f4bf8e0b2 | ||
|
|
05608128e2 | ||
|
|
fbdc301f94 | ||
|
|
cf69234eff | ||
|
|
461f7ed675 | ||
|
|
7e358eb1db | ||
|
|
daffd18674 | ||
|
|
48978e5135 | ||
|
|
311d5c21c2 | ||
|
|
e2b4a52c9e | ||
|
|
51cd5e830e | ||
|
|
10d2b41ad5 | ||
|
|
4f16d6b70f | ||
|
|
8c41dbc376 | ||
|
|
e98788a75c | ||
|
|
3b5850a5ba | ||
|
|
df60dd4307 | ||
|
|
283432b6eb | ||
|
|
a9742bbae1 |
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Ask a question 💬
|
||||
url: https://github.com/alibaba/higress/discussions
|
||||
about: Ask a question or request support for using Higress.
|
||||
@@ -10,14 +10,6 @@ assignees: ''
|
||||
**If you are reporting *any* crash or *any* potential security issue, *do not*
|
||||
open an issue in this repo. Please report the issue via [ASRC](https://security.alibaba.com/)(Alibaba Security Response Center) where the issue will be triaged appropriately.**
|
||||
|
||||
|
||||
---
|
||||
name: Bug Report
|
||||
about: If you would like to report an issue to Higress, please use this template.
|
||||
|
||||
|
||||
---
|
||||
|
||||
- [ ] I have searched the [issues](https://github.com/alibaba/higress/issues) of this repository and believe that this is not a duplicate.
|
||||
|
||||
### Ⅰ. Issue Description
|
||||
|
||||
120
.github/workflows/build-and-test.yaml
vendored
120
.github/workflows/build-and-test.yaml
vendored
@@ -23,6 +23,27 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Golang Caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |-
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-go
|
||||
|
||||
- name: Setup Submodule Caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |-
|
||||
envoy
|
||||
istio
|
||||
.git/modules
|
||||
key: ${{ runner.os }}-submodules-new-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-submodules-new
|
||||
|
||||
- run: git stash # restore patch
|
||||
|
||||
# test
|
||||
- name: Run Coverage Tests
|
||||
run: GOPROXY="https://proxy.golang.org,direct" make go.test.coverage
|
||||
@@ -38,15 +59,36 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [lint,coverage-test]
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }}"
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: "Setup Go"
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.19
|
||||
|
||||
- name: "checkout ${{ github.ref }}"
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Golang Caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
path: |-
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-go
|
||||
|
||||
- name: Setup Submodule Caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |-
|
||||
envoy
|
||||
istio
|
||||
.git/modules
|
||||
key: ${{ runner.os }}-submodules-new-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-submodules-new
|
||||
|
||||
- run: git stash # restore patch
|
||||
|
||||
- name: "Build Higress Binary"
|
||||
run: GOPROXY="https://proxy.golang.org,direct" make build
|
||||
@@ -63,20 +105,84 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
ingress-conformance-test:
|
||||
higress-conformance-test:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: "Setup Go"
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.19
|
||||
|
||||
- name: Setup Golang Caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |-
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go
|
||||
|
||||
- name: Setup Submodule Caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |-
|
||||
envoy
|
||||
istio
|
||||
.git/modules
|
||||
key: ${{ runner.os }}-submodules-new-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-submodules-new
|
||||
|
||||
- run: git stash # restore patch
|
||||
|
||||
- name: "Run Higress E2E Conformance Tests"
|
||||
run: GOPROXY="https://proxy.golang.org,direct" make higress-conformance-test
|
||||
|
||||
higress-wasmplugin-test:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build]
|
||||
strategy:
|
||||
matrix:
|
||||
# TODO(Xunzhuo): Enable C WASM Filters in CI
|
||||
wasmPluginType: [ GO ]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: "Run Ingress Conformance Tests"
|
||||
run: GOPROXY="https://proxy.golang.org,direct" make ingress-conformance-test
|
||||
|
||||
- name: "Setup Go"
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.19
|
||||
|
||||
- name: Setup Golang Caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |-
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go
|
||||
|
||||
- name: Setup Submodule Caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |-
|
||||
envoy
|
||||
istio
|
||||
.git/modules
|
||||
key: ${{ runner.os }}-submodules-new-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-submodules-new
|
||||
|
||||
- run: git stash # restore patch
|
||||
|
||||
- name: "Run Ingress WasmPlugins Tests"
|
||||
run: GOPROXY="https://proxy.golang.org,direct" PLUGIN_TYPE=${{ matrix.wasmPluginType }} make higress-wasmplugin-test
|
||||
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ingress-conformance-test,gateway-conformance-test]
|
||||
needs: [higress-conformance-test,gateway-conformance-test,higress-wasmplugin-test]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
207
.github/workflows/build-image-and-push.yaml
vendored
Normal file
207
.github/workflows/build-image-and-push.yaml
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
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@v3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: "Setup Go"
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.19
|
||||
|
||||
- name: Setup Golang Caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |-
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-go
|
||||
|
||||
- name: Setup Submodule Caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |-
|
||||
envoy
|
||||
istio
|
||||
.git/modules
|
||||
key: ${{ runner.os }}-submodules-new-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-submodules-new
|
||||
|
||||
- name: Calculate Docker metadata
|
||||
id: docker-meta
|
||||
uses: docker/metadata-action@v4
|
||||
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@v2
|
||||
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@v3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: "Setup Go"
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.19
|
||||
|
||||
- name: Setup Golang Caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |-
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-go
|
||||
|
||||
- name: Setup Submodule Caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |-
|
||||
envoy
|
||||
istio
|
||||
.git/modules
|
||||
key: ${{ runner.os }}-submodules-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-submodules-new
|
||||
|
||||
- name: Calculate Docker metadata
|
||||
id: docker-meta
|
||||
uses: docker/metadata-action@v4
|
||||
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@v2
|
||||
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@v3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: "Setup Go"
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.19
|
||||
|
||||
- name: Setup Golang Caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |-
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-go
|
||||
|
||||
- name: Setup Submodule Caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |-
|
||||
envoy
|
||||
istio
|
||||
.git/modules
|
||||
key: ${{ runner.os }}-submodules-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-submodules-new
|
||||
|
||||
- name: Calculate Docker metadata
|
||||
id: docker-meta
|
||||
uses: docker/metadata-action@v4
|
||||
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@v2
|
||||
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
|
||||
37
.github/workflows/deploy-standalone-to-oss.yaml
vendored
Normal file
37
.github/workflows/deploy-standalone-to-oss.yaml
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
name: Deploy Standalone to OSS
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
workflow_dispatch: ~
|
||||
|
||||
jobs:
|
||||
deploy-to-oss:
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: oss
|
||||
steps:
|
||||
# Step 1
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
# Step 2
|
||||
- id: package
|
||||
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"
|
||||
echo -n "$VERSION" > ./artifact/VERSION
|
||||
echo "Version=$VERSION"
|
||||
# Step 3
|
||||
- name: Upload to OSS
|
||||
uses: doggycool/ossutil-github-action@master
|
||||
with:
|
||||
ossArgs: 'cp -r -u ./artifact/ oss://higress-website-cn-hongkong/standalone/'
|
||||
accessKey: ${{ secrets.ACCESS_KEYID }}
|
||||
accessSecret: ${{ secrets.ACCESS_KEYSECRET }}
|
||||
endpoint: oss-cn-hongkong.aliyuncs.com
|
||||
6
.github/workflows/deploy-to-oss.yaml
vendored
6
.github/workflows/deploy-to-oss.yaml
vendored
@@ -4,10 +4,13 @@ on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
workflow_dispatch: ~
|
||||
|
||||
jobs:
|
||||
deploy-to-oss:
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: oss
|
||||
steps:
|
||||
# Step 1
|
||||
- name: Checkout
|
||||
@@ -33,11 +36,14 @@ jobs:
|
||||
with:
|
||||
helmv3: 3.7.2
|
||||
command: |
|
||||
cp api/kubernetes/customresourcedefinitions.gen.yaml helm/core/crds
|
||||
helmv3 repo add higress.io https://higress.io/helm-charts
|
||||
helmv3 package helm/core --debug --app-version ${{steps.calc-version.outputs.version}} --version ${{steps.calc-version.outputs.version}} -d ./artifact
|
||||
helmv3 dependency build helm/higress
|
||||
helmv3 package helm/higress --debug --app-version ${{steps.calc-version.outputs.version}} --version ${{steps.calc-version.outputs.version}} -d ./artifact
|
||||
helmv3 repo index --url https://higress.io/helm-charts/ --merge ./artifact/index.yaml ./artifact
|
||||
cp ./artifact/index.yaml ./artifact/cn-index.yaml
|
||||
sed -i 's/higress\.io/higress\.cn/g' ./artifact/cn-index.yaml
|
||||
# Step 5
|
||||
- name: Upload to OSS
|
||||
uses: doggycool/ossutil-github-action@master
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -12,4 +12,6 @@ bazel-out
|
||||
bazel-testlogs
|
||||
bazel-wasm-cpp
|
||||
tools/bin/
|
||||
helm/**/charts/**.tgz
|
||||
helm/**/charts/**.tgz
|
||||
target/
|
||||
tools/hack/cluster.conf
|
||||
@@ -27,6 +27,7 @@ header:
|
||||
- 'tools/'
|
||||
- 'test/README.md'
|
||||
- 'pkg/cmd/hgctl/testdata/config'
|
||||
- 'pkg/cmd/hgctl/manifests'
|
||||
|
||||
comment: on-failure
|
||||
dependency:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/api @johnlanni
|
||||
/envoy @gengleilei @johnlanni @Lynskylate
|
||||
/istio @SpecialYang @johnlanni
|
||||
/pkg @SpecialYang @johnlanni @Charlie17Li
|
||||
/pkg @SpecialYang @johnlanni @Charlie17Li @Xunzhuo
|
||||
/plugins @johnlanni
|
||||
/registry @NameHaibinZhang @johnlanni
|
||||
/test @Xunzhuo
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
## 报告一般问题
|
||||
|
||||
老实说,我们把每一个 Higress 用户都视为非常善良的贡献者。在体验了 Higress 之后,您可能会对项目有一些反馈。然后随时通过 [NEW ISSUE](https://github. com/alibaba/higress/issues/new/choose)打开一个问题。
|
||||
老实说,我们把每一个 Higress 用户都视为非常善良的贡献者。在体验了 Higress 之后,您可能会对项目有一些反馈。然后随时通过 [NEW ISSUE](https://github.com/alibaba/higress/issues/new/choose)打开一个问题。
|
||||
|
||||
因为我们在一个分布式的方式合作项目Higress,我们欣赏写得很好的,详细的,准确的问题报告。为了让沟通更高效,我们希望每个人都可以搜索您的问题是否在搜索列表中。如果您发现它存在,请在现有问题下的评论中添加您的详细信息,而不是打开一个全新的问题。
|
||||
|
||||
|
||||
@@ -28,8 +28,7 @@ Security issues are always treated seriously. As our usual principle, we discour
|
||||
## Reporting general issues
|
||||
|
||||
To be honest, we regard every user of Higress as a very kind contributor. After experiencing Higress, you may have
|
||||
some feedback for the project. Then feel free to open an issue via [NEW ISSUE](https://github.
|
||||
com/alibaba/higress/issues/new/choose).
|
||||
some feedback for the project. Then feel free to open an issue via [NEW ISSUE](https://github.com/alibaba/higress/issues/new/choose).
|
||||
|
||||
Since we collaborate project Higress in a distributed way, we appreciate **WELL-WRITTEN**, **DETAILED**, **EXPLICIT** issue reports. To make the communication more efficient, we wish everyone could search if your issue is an existing one in the searching list. If you find it existing, please add your details in comments under the existing issue instead of opening a brand new one.
|
||||
|
||||
|
||||
107
Makefile.core.mk
107
Makefile.core.mk
@@ -17,6 +17,8 @@ GO ?= go
|
||||
|
||||
export GOPROXY ?= https://proxy.golang.com.cn,direct
|
||||
|
||||
TARGET_ARCH ?= amd64
|
||||
|
||||
GOARCH_LOCAL := $(TARGET_ARCH)
|
||||
GOOS_LOCAL := $(TARGET_OS)
|
||||
RELEASE_LDFLAGS='$(GO_LDFLAGS) -extldflags -static -s -w'
|
||||
@@ -24,6 +26,8 @@ RELEASE_LDFLAGS='$(GO_LDFLAGS) -extldflags -static -s -w'
|
||||
export OUT:=$(TARGET_OUT)
|
||||
export OUT_LINUX:=$(TARGET_OUT_LINUX)
|
||||
|
||||
BUILDX_PLATFORM ?=
|
||||
|
||||
# If tag not explicitly set in users' .istiorc.mk or command line, default to the git sha.
|
||||
TAG ?= $(shell git rev-parse --verify HEAD)
|
||||
ifeq ($(TAG),)
|
||||
@@ -49,6 +53,7 @@ $(OUT):
|
||||
submodule:
|
||||
git submodule update --init
|
||||
|
||||
.PHONY: prebuild
|
||||
prebuild: submodule
|
||||
./tools/hack/prebuild.sh
|
||||
|
||||
@@ -67,16 +72,22 @@ build: prebuild $(OUT)
|
||||
build-linux: prebuild $(OUT)
|
||||
GOPROXY=$(GOPROXY) GOOS=linux GOARCH=$(GOARCH_LOCAL) LDFLAGS=$(RELEASE_LDFLAGS) tools/hack/gobuild.sh $(OUT_LINUX)/ $(HIGRESS_BINARIES)
|
||||
|
||||
$(AMD64_OUT_LINUX)/higress:
|
||||
GOPROXY=$(GOPROXY) GOOS=linux GOARCH=amd64 LDFLAGS=$(RELEASE_LDFLAGS) tools/hack/gobuild.sh ./out/linux_amd64/ $(HIGRESS_BINARIES)
|
||||
|
||||
$(ARM64_OUT_LINUX)/higress:
|
||||
GOPROXY=$(GOPROXY) GOOS=linux GOARCH=arm64 LDFLAGS=$(RELEASE_LDFLAGS) tools/hack/gobuild.sh ./out/linux_arm64/ $(HIGRESS_BINARIES)
|
||||
|
||||
.PHONY: build-hgctl
|
||||
build-hgctl: $(OUT)
|
||||
build-hgctl: prebuild $(OUT)
|
||||
GOPROXY=$(GOPROXY) GOOS=$(GOOS_LOCAL) GOARCH=$(GOARCH_LOCAL) LDFLAGS=$(RELEASE_LDFLAGS) tools/hack/gobuild.sh $(OUT)/ $(HGCTL_BINARIES)
|
||||
|
||||
.PHONY: build-linux-hgctl
|
||||
build-linux-hgctl: $(OUT)
|
||||
build-linux-hgctl: prebuild $(OUT)
|
||||
GOPROXY=$(GOPROXY) GOOS=linux GOARCH=$(GOARCH_LOCAL) LDFLAGS=$(RELEASE_LDFLAGS) tools/hack/gobuild.sh $(OUT_LINUX)/ $(HGCTL_BINARIES)
|
||||
|
||||
.PHONY: build-hgctl-multiarch
|
||||
build-hgctl-multiarch: $(OUT)
|
||||
build-hgctl-multiarch: prebuild $(OUT)
|
||||
GOPROXY=$(GOPROXY) GOOS=linux GOARCH=amd64 LDFLAGS=$(RELEASE_LDFLAGS) tools/hack/gobuild.sh ./out/linux_amd64/ $(HGCTL_BINARIES)
|
||||
GOPROXY=$(GOPROXY) GOOS=linux GOARCH=arm64 LDFLAGS=$(RELEASE_LDFLAGS) tools/hack/gobuild.sh ./out/linux_arm64/ $(HGCTL_BINARIES)
|
||||
GOPROXY=$(GOPROXY) GOOS=darwin GOARCH=amd64 LDFLAGS=$(RELEASE_LDFLAGS) tools/hack/gobuild.sh ./out/darwin_amd64/ $(HGCTL_BINARIES)
|
||||
@@ -114,19 +125,45 @@ include docker/docker.mk
|
||||
|
||||
docker-build: docker.higress ## Build and push docker images to registry defined by $HUB and $TAG
|
||||
|
||||
docker-buildx-push: clean-env docker.higress-buildx
|
||||
|
||||
docker-build-base:
|
||||
docker buildx build --no-cache --platform linux/amd64,linux/arm64 -t ${HUB}/base:${BASE_VERSION} -f docker/Dockerfile.base . --push
|
||||
|
||||
export PARENT_GIT_TAG:=$(shell cat VERSION)
|
||||
export PARENT_GIT_REVISION:=$(TAG)
|
||||
|
||||
export ENVOY_TAR_PATH:=/home/package/envoy.tar.gz
|
||||
|
||||
external/package/envoy.tar.gz:
|
||||
cd external/proxy; BUILD_WITH_CONTAINER=1 make test_release
|
||||
external/package/envoy-amd64.tar.gz:
|
||||
# cd external/proxy; BUILD_WITH_CONTAINER=1 make test_release
|
||||
cd external/package; wget "https://github.com/alibaba/higress/releases/download/v1.2.0/envoy-amd64.tar.gz"
|
||||
|
||||
build-gateway: prebuild external/package/envoy.tar.gz
|
||||
cd external/istio; rm -rf out; GOOS_LOCAL=linux TARGET_OS=linux TARGET_ARCH=amd64 BUILD_WITH_CONTAINER=1 DOCKER_BUILD_VARIANTS=default DOCKER_TARGETS="docker.proxyv2" make docker
|
||||
external/package/envoy-arm64.tar.gz:
|
||||
# cd external/proxy; BUILD_WITH_CONTAINER=1 make test_release
|
||||
cd external/package; wget "https://github.com/alibaba/higress/releases/download/v1.2.0/envoy-arm64.tar.gz"
|
||||
|
||||
build-istio: prebuild
|
||||
cd external/istio; rm -rf out; GOOS_LOCAL=linux TARGET_OS=linux TARGET_ARCH=amd64 BUILD_WITH_CONTAINER=1 DOCKER_BUILD_VARIANTS=default DOCKER_TARGETS="docker.pilot" make docker
|
||||
build-pilot:
|
||||
cd external/istio; rm -rf out/linux_amd64; GOOS_LOCAL=linux TARGET_OS=linux TARGET_ARCH=amd64 BUILD_WITH_CONTAINER=1 make build-linux
|
||||
cd external/istio; rm -rf out/linux_arm64; GOOS_LOCAL=linux TARGET_OS=linux TARGET_ARCH=arm64 BUILD_WITH_CONTAINER=1 make build-linux
|
||||
|
||||
build-pilot-local:
|
||||
cd external/istio; rm -rf out/linux_${GOARCH_LOCAL}; GOOS_LOCAL=linux TARGET_OS=linux TARGET_ARCH=${GOARCH_LOCAL} BUILD_WITH_CONTAINER=1 make build-linux
|
||||
|
||||
build-gateway: prebuild external/package/envoy-amd64.tar.gz external/package/envoy-arm64.tar.gz build-pilot
|
||||
cd external/istio; BUILD_WITH_CONTAINER=1 BUILDX_PLATFORM=true DOCKER_BUILD_VARIANTS=default DOCKER_TARGETS="docker.proxyv2" make docker
|
||||
|
||||
build-gateway-local: prebuild external/package/envoy-amd64.tar.gz external/package/envoy-arm64.tar.gz build-pilot
|
||||
cd external/istio; rm -rf out/linux_${GOARCH_LOCAL}; GOOS_LOCAL=linux TARGET_OS=linux BUILD_WITH_CONTAINER=1 BUILDX_PLATFORM=false DOCKER_BUILD_VARIANTS=default DOCKER_TARGETS="docker.proxyv2" make docker
|
||||
|
||||
build-istio: prebuild build-pilot
|
||||
cd external/istio; BUILD_WITH_CONTAINER=1 BUILDX_PLATFORM=true DOCKER_BUILD_VARIANTS=default DOCKER_TARGETS="docker.pilot" make docker
|
||||
|
||||
build-istio-local: prebuild build-pilot-local
|
||||
cd external/istio; rm -rf out/linux_${GOARCH_LOCAL}; GOOS_LOCAL=linux TARGET_OS=linux BUILD_WITH_CONTAINER=1 BUILDX_PLATFORM=false DOCKER_BUILD_VARIANTS=default DOCKER_TARGETS="docker.pilot" make docker
|
||||
|
||||
build-wasmplugins:
|
||||
./tools/hack/build-wasm-plugins.sh
|
||||
|
||||
pre-install:
|
||||
cp api/kubernetes/customresourcedefinitions.gen.yaml helm/core/crds
|
||||
@@ -139,11 +176,13 @@ 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 ?= 1.0.0-rc
|
||||
ISTIO_LATEST_IMAGE_TAG ?= 1.0.0-rc
|
||||
ENVOY_LATEST_IMAGE_TAG ?= sha-6835486
|
||||
ISTIO_LATEST_IMAGE_TAG ?= sha-6835486
|
||||
|
||||
install-dev: pre-install
|
||||
helm install higress helm/core -n higress-system --create-namespace --set 'controller.tag=$(TAG)' --set 'gateway.replicas=1' --set 'gateway.tag=$(ENVOY_LATEST_IMAGE_TAG)' --set 'global.local=true'
|
||||
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'
|
||||
install-dev-wasmplugin: build-wasmplugins 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' --set 'global.volumeWasmPlugins=true'
|
||||
|
||||
uninstall:
|
||||
helm uninstall higress -n higress-system
|
||||
@@ -193,9 +232,13 @@ include tools/lint.mk
|
||||
.PHONY: gateway-conformance-test
|
||||
gateway-conformance-test:
|
||||
|
||||
# ingress-conformance-test runs ingress api conformance tests.
|
||||
.PHONY: ingress-conformance-test
|
||||
ingress-conformance-test: $(tools/kind) delete-cluster create-cluster docker-build kube-load-image install-dev run-ingress-e2e-test delete-cluster
|
||||
# higress-conformance-test runs ingress api conformance tests.
|
||||
.PHONY: higress-conformance-test
|
||||
higress-conformance-test: $(tools/kind) delete-cluster create-cluster docker-build kube-load-image install-dev run-higress-e2e-test delete-cluster
|
||||
|
||||
# higress-wasmplugin-test runs ingress wasmplugin tests.
|
||||
.PHONY: higress-wasmplugin-test
|
||||
higress-wasmplugin-test: $(tools/kind) delete-cluster create-cluster docker-build kube-load-image install-dev-wasmplugin run-higress-e2e-test-wasmplugin delete-cluster
|
||||
|
||||
# create-cluster creates a kube cluster with kind.
|
||||
.PHONY: create-cluster
|
||||
@@ -208,16 +251,40 @@ delete-cluster: $(tools/kind) ## Delete kind cluster.
|
||||
$(tools/kind) delete cluster --name higress
|
||||
|
||||
# kube-load-image loads a local built docker image into kube cluster.
|
||||
# dubbo-provider-demo和nacos-standlone-rc3的镜像已经上传到阿里云镜像库,第一次需要先拉到本地
|
||||
# docker pull registry.cn-hangzhou.aliyuncs.com/hinsteny/dubbo-provider-demo:0.0.1
|
||||
# docker pull registry.cn-hangzhou.aliyuncs.com/hinsteny/nacos-standlone-rc3:1.0.0-RC3
|
||||
.PHONY: kube-load-image
|
||||
kube-load-image: $(tools/kind) ## Install the Higress image to a kind cluster using the provided $IMAGE and $TAG.
|
||||
tools/hack/kind-load-image.sh higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/higress $(TAG)
|
||||
|
||||
# run-ingress-e2e-test starts to run ingress e2e tests.
|
||||
.PHONY: run-ingress-e2e-test
|
||||
run-ingress-e2e-test:
|
||||
tools/hack/docker-pull-image.sh docker.io/alihigress/dubbo-provider-demo 0.0.1
|
||||
tools/hack/docker-pull-image.sh docker.io/alihigress/nacos-standlone-rc3 1.0.0-RC3
|
||||
tools/hack/docker-pull-image.sh docker.io/hashicorp/consul 1.16.0
|
||||
tools/hack/docker-pull-image.sh docker.io/charlie1380/eureka-registry-provider v0.3.0
|
||||
tools/hack/docker-pull-image.sh docker.io/bitinit/eureka latest
|
||||
tools/hack/docker-pull-image.sh docker.io/alihigress/httpbin 1.0.2
|
||||
tools/hack/kind-load-image.sh docker.io/alihigress/dubbo-provider-demo 0.0.1
|
||||
tools/hack/kind-load-image.sh docker.io/alihigress/nacos-standlone-rc3 1.0.0-RC3
|
||||
tools/hack/kind-load-image.sh docker.io/hashicorp/consul 1.16.0
|
||||
tools/hack/kind-load-image.sh docker.io/alihigress/httpbin 1.0.2
|
||||
tools/hack/kind-load-image.sh docker.io/charlie1380/eureka-registry-provider v0.3.0
|
||||
tools/hack/kind-load-image.sh docker.io/bitinit/eureka latest
|
||||
# run-higress-e2e-test starts to run ingress e2e tests.
|
||||
.PHONY: run-higress-e2e-test
|
||||
run-higress-e2e-test:
|
||||
@echo -e "\n\033[36mRunning higress conformance tests...\033[0m"
|
||||
@echo -e "\n\033[36mWaiting higress-controller to be ready...\033[0m\n"
|
||||
kubectl wait --timeout=10m -n higress-system deployment/higress-controller --for=condition=Available
|
||||
@echo -e "\n\033[36mWaiting higress-gateway to be ready...\033[0m\n"
|
||||
kubectl wait --timeout=10m -n higress-system deployment/higress-gateway --for=condition=Available
|
||||
go test -v -tags conformance ./test/ingress/e2e_test.go --ingress-class=higress --debug=true
|
||||
go test -v -tags conformance ./test/e2e/e2e_test.go --ingress-class=higress --debug=true
|
||||
|
||||
# run-higress-e2e-test starts to run ingress e2e tests.
|
||||
.PHONY: run-higress-e2e-test-wasmplugin
|
||||
run-higress-e2e-test-wasmplugin:
|
||||
@echo -e "\n\033[36mRunning higress conformance tests...\033[0m"
|
||||
@echo -e "\n\033[36mWaiting higress-controller to be ready...\033[0m\n"
|
||||
kubectl wait --timeout=10m -n higress-system deployment/higress-controller --for=condition=Available
|
||||
@echo -e "\n\033[36mWaiting higress-gateway to be ready...\033[0m\n"
|
||||
kubectl wait --timeout=10m -n higress-system deployment/higress-gateway --for=condition=Available
|
||||
go test -v -tags conformance ./test/e2e/e2e_test.go -isWasmPluginTest=true -wasmPluginType=$(PLUGIN_TYPE) -wasmPluginName=$(PLUGIN_NAME) --ingress-class=higress --debug=true
|
||||
|
||||
51
README.md
51
README.md
@@ -8,9 +8,10 @@
|
||||
[](https://www.apache.org/licenses/LICENSE-2.0.html)
|
||||
|
||||
[**官网**](https://higress.io/) |
|
||||
[**文档**](https://higress.io/zh-cn/docs/overview/what-is-higress.html) |
|
||||
[**博客**](https://higress.io/zh-cn/blog/index.html) |
|
||||
[**开发指引**](https://higress.io/zh-cn/docs/dev/code.html)
|
||||
[**文档**](https://higress.io/zh-cn/docs/overview/what-is-higress) |
|
||||
[**博客**](https://higress.io/zh-cn/blog) |
|
||||
[**开发指引**](https://higress.io/zh-cn/docs/developers/developers_dev) |
|
||||
[**Higress 企业版**](https://www.aliyun.com/product/aliware/mse?spm=higress-website.topbar.0.0.0)
|
||||
|
||||
|
||||
<p>
|
||||
@@ -20,15 +21,17 @@
|
||||
|
||||
Higress 是基于阿里内部两年多的 Envoy Gateway 实践沉淀,以开源 [Istio](https://github.com/istio/istio) 与 [Envoy](https://github.com/envoyproxy/envoy) 为核心构建的下一代云原生网关。Higress 实现了安全防护网关、流量网关、微服务网关三层网关合一,可以显著降低网关的部署和运维成本。
|
||||
|
||||

|
||||

|
||||
|
||||
## Summary
|
||||
|
||||
|
||||
- [**功能展示**](#功能展示)
|
||||
- [**使用场景**](#使用场景)
|
||||
- [**核心优势**](#核心优势)
|
||||
- [**Quick Start**](https://higress.io/zh-cn/docs/user/quickstart)
|
||||
- [**社区**](#社区)
|
||||
|
||||
|
||||
## 使用场景
|
||||
|
||||
- **Kubernetes Ingress 网关**:
|
||||
@@ -73,6 +76,42 @@ Higress 是基于阿里内部两年多的 Envoy Gateway 实践沉淀,以开源
|
||||
|
||||
插件支持热更新,变更插件逻辑和配置都对流量无损。
|
||||
|
||||
## 功能展示
|
||||
|
||||
- **丰富的可观测**
|
||||
|
||||
提供开箱即用的可观测,Grafana&Prometheus 可以使用内置的也可对接自建的
|
||||
|
||||

|
||||
|
||||
|
||||
- **插件扩展机制**
|
||||
|
||||
官方提供了多种插件,用户也可以[开发](./plugins/wasm-go)自己的插件,构建成 docker/oci 镜像后在控制台配置,可以实时变更插件逻辑,对流量完全无损。
|
||||
|
||||

|
||||
|
||||
|
||||
- **多种服务发现**
|
||||
|
||||
默认提供 K8s Service 服务发现,通过配置可以对接 Nacos/ZooKeeper 等注册中心实现服务发现,也可以基于静态 IP 或者 DNS 来发现
|
||||
|
||||

|
||||
|
||||
|
||||
- **域名和证书**
|
||||
|
||||
可以创建管理 TLS 证书,并配置域名的 HTTP/HTTPS 行为,域名策略里支持对特定域名生效插件
|
||||
|
||||

|
||||
|
||||
|
||||
- **丰富的路由能力**
|
||||
|
||||
通过上面定义的服务发现机制,发现的服务会出现在服务列表中;创建路由时,选择域名,定义路由匹配机制,再选择目标服务进行路由;路由策略里支持对特定路由生效插件
|
||||
|
||||

|
||||
|
||||
|
||||
## 社区
|
||||
|
||||
@@ -86,7 +125,7 @@ Higress 是基于阿里内部两年多的 Envoy Gateway 实践沉淀,以开源
|
||||
|
||||
社区交流群:
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
开发者群:
|
||||
|
||||
17
README_EN.md
17
README_EN.md
@@ -4,6 +4,16 @@
|
||||
Next-generation Cloud Native Gateway
|
||||
</h1>
|
||||
|
||||
[](https://github.com/alibaba/higress/actions)
|
||||
[](https://www.apache.org/licenses/LICENSE-2.0.html)
|
||||
|
||||
[**Official Site**](https://higress.io/en-us/) |
|
||||
[**Docs**](https://higress.io/en-us/docs/overview/what-is-higress) |
|
||||
[**Blog**](https://higress.io/en-us/blog) |
|
||||
[**Developer**](https://higress.io/en-us/docs/developers/developers_dev) |
|
||||
[**Higress in Cloud**](https://www.alibabacloud.com/product/microservices-engine?spm=higress-website.topbar.0.0.0)
|
||||
|
||||
|
||||
<p>
|
||||
English | <a href="README.md">中文<a/>
|
||||
</p>
|
||||
@@ -13,7 +23,7 @@ Higress is a next-generation cloud-native gateway based on Alibaba's internal ga
|
||||
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/O1CN01vnNawh26mU5C9py9w_!!6000000007704-0-tps-1726-1366.jpg" alt="Higress Architecture">
|
||||
<img src="https://img.alicdn.com/imgextra/i1/O1CN01iO9ph825juHbOIg75_!!6000000007563-2-tps-2483-2024.png" alt="Higress Architecture">
|
||||
</h1>
|
||||
|
||||
|
||||
@@ -22,6 +32,7 @@ Powered by [Istio](https://github.com/istio/istio) and [Envoy](https://github.co
|
||||
- [**Use Cases**](#use-cases)
|
||||
- [**Higress Features**](#higress-features)
|
||||
- [**Quick Start**](https://higress.io/en-us/docs/user/quickstart)
|
||||
- [**Community**](#community)
|
||||
- [**Thanks**](#thanks)
|
||||
|
||||
## Use Cases
|
||||
@@ -64,6 +75,10 @@ Powered by [Istio](https://github.com/istio/istio) and [Envoy](https://github.co
|
||||
|
||||
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.
|
||||
|
||||
@@ -171,7 +171,7 @@ type WasmPlugin struct {
|
||||
DefaultConfig *types.Struct `protobuf:"bytes,101,opt,name=default_config,json=defaultConfig,proto3" json:"default_config,omitempty"`
|
||||
// Extended by Higress, matching rules take effect
|
||||
MatchRules []*MatchRule `protobuf:"bytes,102,rep,name=match_rules,json=matchRules,proto3" json:"match_rules,omitempty"`
|
||||
// diable the default config
|
||||
// disable the default config
|
||||
DefaultConfigDisable bool `protobuf:"varint,103,opt,name=default_config_disable,json=defaultConfigDisable,proto3" json:"default_config_disable,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
|
||||
@@ -104,7 +104,7 @@ message WasmPlugin {
|
||||
google.protobuf.Struct default_config = 101;
|
||||
// Extended by Higress, matching rules take effect
|
||||
repeated MatchRule match_rules = 102;
|
||||
// diable the default config
|
||||
// disable the default config
|
||||
bool default_config_disable = 103;
|
||||
}
|
||||
|
||||
|
||||
@@ -104,6 +104,88 @@ spec:
|
||||
subresources:
|
||||
status: {}
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
"helm.sh/resource-policy": keep
|
||||
name: http2rpcs.networking.higress.io
|
||||
spec:
|
||||
group: networking.higress.io
|
||||
names:
|
||||
categories:
|
||||
- higress-io
|
||||
kind: Http2Rpc
|
||||
listKind: Http2RpcList
|
||||
plural: http2rpcs
|
||||
singular: http2rpc
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
properties:
|
||||
spec:
|
||||
oneOf:
|
||||
- not:
|
||||
anyOf:
|
||||
- required:
|
||||
- dubbo
|
||||
- required:
|
||||
- grpc
|
||||
- required:
|
||||
- dubbo
|
||||
- required:
|
||||
- grpc
|
||||
properties:
|
||||
dubbo:
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
methods:
|
||||
items:
|
||||
properties:
|
||||
headersAttach:
|
||||
type: string
|
||||
httpMethods:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
httpPath:
|
||||
type: string
|
||||
params:
|
||||
items:
|
||||
properties:
|
||||
paramKey:
|
||||
type: string
|
||||
paramSource:
|
||||
type: string
|
||||
paramType:
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
serviceMethod:
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
service:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
type: object
|
||||
grpc:
|
||||
type: object
|
||||
type: object
|
||||
status:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
@@ -131,8 +213,17 @@ spec:
|
||||
registries:
|
||||
items:
|
||||
properties:
|
||||
authSecretName:
|
||||
type: string
|
||||
consulDatacenter:
|
||||
type: string
|
||||
consulNamespace:
|
||||
type: string
|
||||
consulRefreshInterval:
|
||||
format: int64
|
||||
type: integer
|
||||
consulServiceTag:
|
||||
type: string
|
||||
domain:
|
||||
type: string
|
||||
nacosAccessKey:
|
||||
|
||||
1666
api/networking/v1/http_2_rpc.pb.go
Normal file
1666
api/networking/v1/http_2_rpc.pb.go
Normal file
File diff suppressed because it is too large
Load Diff
74
api/networking/v1/http_2_rpc.proto
Normal file
74
api/networking/v1/http_2_rpc.proto
Normal file
@@ -0,0 +1,74 @@
|
||||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
import "google/api/field_behavior.proto";
|
||||
|
||||
// $schema: higress.networking.v1.Http2Rpc
|
||||
// $title: Http2Rpc
|
||||
// $description: Configuration affecting service discovery from multi registries
|
||||
// $mode: none
|
||||
|
||||
package higress.networking.v1;
|
||||
|
||||
option go_package = "github.com/alibaba/higress/api/networking/v1";
|
||||
|
||||
// <!-- crd generation tags
|
||||
// +cue-gen:Http2Rpc:groupName:networking.higress.io
|
||||
// +cue-gen:Http2Rpc:version:v1
|
||||
// +cue-gen:Http2Rpc:storageVersion
|
||||
// +cue-gen:Http2Rpc:annotations:helm.sh/resource-policy=keep
|
||||
// +cue-gen:Http2Rpc:subresource:status
|
||||
// +cue-gen:Http2Rpc:scope:Namespaced
|
||||
// +cue-gen:Http2Rpc:resource:categories=higress-io,plural=http2rpcs
|
||||
// +cue-gen:Http2Rpc:preserveUnknownFields:false
|
||||
// -->
|
||||
//
|
||||
// <!-- go code generation tags
|
||||
// +kubetype-gen
|
||||
// +kubetype-gen:groupVersion=networking.higress.io/v1
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen=true
|
||||
// -->
|
||||
message Http2Rpc {
|
||||
oneof destination {
|
||||
DubboService dubbo = 1;
|
||||
GrpcService grpc = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message DubboService {
|
||||
string service = 1 [(google.api.field_behavior) = REQUIRED];
|
||||
string version = 2 [(google.api.field_behavior) = REQUIRED];
|
||||
string group = 3 [(google.api.field_behavior) = OPTIONAL];
|
||||
repeated Method methods = 4 [(google.api.field_behavior) = REQUIRED];
|
||||
}
|
||||
|
||||
message Method {
|
||||
string service_method = 1 [(google.api.field_behavior) = REQUIRED];
|
||||
string headers_attach = 2 [(google.api.field_behavior) = OPTIONAL];
|
||||
string http_path = 3 [(google.api.field_behavior) = REQUIRED];
|
||||
repeated string http_methods = 4 [(google.api.field_behavior) = REQUIRED];
|
||||
repeated Param params = 5;
|
||||
}
|
||||
|
||||
message Param {
|
||||
string param_source = 1 [(google.api.field_behavior) = REQUIRED];
|
||||
string param_key = 2 [(google.api.field_behavior) = REQUIRED];
|
||||
string param_type = 3 [(google.api.field_behavior) = REQUIRED];
|
||||
}
|
||||
|
||||
message GrpcService {
|
||||
}
|
||||
121
api/networking/v1/http_2_rpc_deepcopy.gen.go
Normal file
121
api/networking/v1/http_2_rpc_deepcopy.gen.go
Normal file
@@ -0,0 +1,121 @@
|
||||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: networking/v1/http_2_rpc.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
_ "istio.io/gogo-genproto/googleapis/google/api"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// DeepCopyInto supports using Http2Rpc within kubernetes types, where deepcopy-gen is used.
|
||||
func (in *Http2Rpc) DeepCopyInto(out *Http2Rpc) {
|
||||
p := proto.Clone(in).(*Http2Rpc)
|
||||
*out = *p
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Http2Rpc. Required by controller-gen.
|
||||
func (in *Http2Rpc) DeepCopy() *Http2Rpc {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Http2Rpc)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new Http2Rpc. Required by controller-gen.
|
||||
func (in *Http2Rpc) DeepCopyInterface() interface{} {
|
||||
return in.DeepCopy()
|
||||
}
|
||||
|
||||
// DeepCopyInto supports using DubboService within kubernetes types, where deepcopy-gen is used.
|
||||
func (in *DubboService) DeepCopyInto(out *DubboService) {
|
||||
p := proto.Clone(in).(*DubboService)
|
||||
*out = *p
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DubboService. Required by controller-gen.
|
||||
func (in *DubboService) DeepCopy() *DubboService {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DubboService)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new DubboService. Required by controller-gen.
|
||||
func (in *DubboService) DeepCopyInterface() interface{} {
|
||||
return in.DeepCopy()
|
||||
}
|
||||
|
||||
// DeepCopyInto supports using Method within kubernetes types, where deepcopy-gen is used.
|
||||
func (in *Method) DeepCopyInto(out *Method) {
|
||||
p := proto.Clone(in).(*Method)
|
||||
*out = *p
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Method. Required by controller-gen.
|
||||
func (in *Method) DeepCopy() *Method {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Method)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new Method. Required by controller-gen.
|
||||
func (in *Method) DeepCopyInterface() interface{} {
|
||||
return in.DeepCopy()
|
||||
}
|
||||
|
||||
// DeepCopyInto supports using Param within kubernetes types, where deepcopy-gen is used.
|
||||
func (in *Param) DeepCopyInto(out *Param) {
|
||||
p := proto.Clone(in).(*Param)
|
||||
*out = *p
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Param. Required by controller-gen.
|
||||
func (in *Param) DeepCopy() *Param {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Param)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new Param. Required by controller-gen.
|
||||
func (in *Param) DeepCopyInterface() interface{} {
|
||||
return in.DeepCopy()
|
||||
}
|
||||
|
||||
// DeepCopyInto supports using GrpcService within kubernetes types, where deepcopy-gen is used.
|
||||
func (in *GrpcService) DeepCopyInto(out *GrpcService) {
|
||||
p := proto.Clone(in).(*GrpcService)
|
||||
*out = *p
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GrpcService. Required by controller-gen.
|
||||
func (in *GrpcService) DeepCopy() *GrpcService {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(GrpcService)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new GrpcService. Required by controller-gen.
|
||||
func (in *GrpcService) DeepCopyInterface() interface{} {
|
||||
return in.DeepCopy()
|
||||
}
|
||||
78
api/networking/v1/http_2_rpc_json.gen.go
Normal file
78
api/networking/v1/http_2_rpc_json.gen.go
Normal file
@@ -0,0 +1,78 @@
|
||||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: networking/v1/http_2_rpc.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
bytes "bytes"
|
||||
fmt "fmt"
|
||||
github_com_gogo_protobuf_jsonpb "github.com/gogo/protobuf/jsonpb"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
_ "istio.io/gogo-genproto/googleapis/google/api"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// MarshalJSON is a custom marshaler for Http2Rpc
|
||||
func (this *Http2Rpc) MarshalJSON() ([]byte, error) {
|
||||
str, err := Http_2RpcMarshaler.MarshalToString(this)
|
||||
return []byte(str), err
|
||||
}
|
||||
|
||||
// UnmarshalJSON is a custom unmarshaler for Http2Rpc
|
||||
func (this *Http2Rpc) UnmarshalJSON(b []byte) error {
|
||||
return Http_2RpcUnmarshaler.Unmarshal(bytes.NewReader(b), this)
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshaler for DubboService
|
||||
func (this *DubboService) MarshalJSON() ([]byte, error) {
|
||||
str, err := Http_2RpcMarshaler.MarshalToString(this)
|
||||
return []byte(str), err
|
||||
}
|
||||
|
||||
// UnmarshalJSON is a custom unmarshaler for DubboService
|
||||
func (this *DubboService) UnmarshalJSON(b []byte) error {
|
||||
return Http_2RpcUnmarshaler.Unmarshal(bytes.NewReader(b), this)
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshaler for Method
|
||||
func (this *Method) MarshalJSON() ([]byte, error) {
|
||||
str, err := Http_2RpcMarshaler.MarshalToString(this)
|
||||
return []byte(str), err
|
||||
}
|
||||
|
||||
// UnmarshalJSON is a custom unmarshaler for Method
|
||||
func (this *Method) UnmarshalJSON(b []byte) error {
|
||||
return Http_2RpcUnmarshaler.Unmarshal(bytes.NewReader(b), this)
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshaler for Param
|
||||
func (this *Param) MarshalJSON() ([]byte, error) {
|
||||
str, err := Http_2RpcMarshaler.MarshalToString(this)
|
||||
return []byte(str), err
|
||||
}
|
||||
|
||||
// UnmarshalJSON is a custom unmarshaler for Param
|
||||
func (this *Param) UnmarshalJSON(b []byte) error {
|
||||
return Http_2RpcUnmarshaler.Unmarshal(bytes.NewReader(b), this)
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshaler for GrpcService
|
||||
func (this *GrpcService) MarshalJSON() ([]byte, error) {
|
||||
str, err := Http_2RpcMarshaler.MarshalToString(this)
|
||||
return []byte(str), err
|
||||
}
|
||||
|
||||
// UnmarshalJSON is a custom unmarshaler for GrpcService
|
||||
func (this *GrpcService) UnmarshalJSON(b []byte) error {
|
||||
return Http_2RpcUnmarshaler.Unmarshal(bytes.NewReader(b), this)
|
||||
}
|
||||
|
||||
var (
|
||||
Http_2RpcMarshaler = &github_com_gogo_protobuf_jsonpb.Marshaler{}
|
||||
Http_2RpcUnmarshaler = &github_com_gogo_protobuf_jsonpb.Unmarshaler{AllowUnknownFields: true}
|
||||
)
|
||||
@@ -88,22 +88,26 @@ func (m *McpBridge) GetRegistries() []*RegistryConfig {
|
||||
}
|
||||
|
||||
type RegistryConfig struct {
|
||||
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"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
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"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *RegistryConfig) Reset() { *m = RegistryConfig{} }
|
||||
@@ -230,6 +234,34 @@ func (m *RegistryConfig) GetZkServicesPath() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *RegistryConfig) GetConsulDatacenter() string {
|
||||
if m != nil {
|
||||
return m.ConsulDatacenter
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *RegistryConfig) GetConsulServiceTag() string {
|
||||
if m != nil {
|
||||
return m.ConsulServiceTag
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *RegistryConfig) GetConsulRefreshInterval() int64 {
|
||||
if m != nil {
|
||||
return m.ConsulRefreshInterval
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *RegistryConfig) GetAuthSecretName() string {
|
||||
if m != nil {
|
||||
return m.AuthSecretName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*McpBridge)(nil), "higress.networking.v1.McpBridge")
|
||||
proto.RegisterType((*RegistryConfig)(nil), "higress.networking.v1.RegistryConfig")
|
||||
@@ -238,34 +270,37 @@ func init() {
|
||||
func init() { proto.RegisterFile("networking/v1/mcp_bridge.proto", fileDescriptor_3fcc59a15c34642d) }
|
||||
|
||||
var fileDescriptor_3fcc59a15c34642d = []byte{
|
||||
// 421 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x92, 0xd1, 0x8a, 0xd4, 0x30,
|
||||
0x14, 0x86, 0xc9, 0x76, 0x1c, 0x9d, 0x8c, 0xbb, 0x4a, 0x50, 0x08, 0x22, 0x63, 0x59, 0x50, 0x8a,
|
||||
0x48, 0xcb, 0xae, 0x77, 0xde, 0xed, 0x88, 0xc8, 0x22, 0x8a, 0x74, 0xef, 0xbc, 0x59, 0xd2, 0xf4,
|
||||
0x4c, 0x1a, 0xb6, 0x4d, 0x42, 0x92, 0xa9, 0x8c, 0x4f, 0xe8, 0xa5, 0x8f, 0x20, 0x7d, 0x04, 0x9f,
|
||||
0x40, 0x9a, 0x59, 0xbb, 0x9d, 0x71, 0xee, 0xda, 0xef, 0x7c, 0xf9, 0x73, 0x08, 0x3f, 0x5e, 0x28,
|
||||
0xf0, 0xdf, 0xb5, 0xbd, 0x91, 0x4a, 0x64, 0xed, 0x59, 0xd6, 0x70, 0x73, 0x5d, 0x58, 0x59, 0x0a,
|
||||
0x48, 0x8d, 0xd5, 0x5e, 0x93, 0xa7, 0x95, 0x14, 0x16, 0x9c, 0x4b, 0xef, 0xbc, 0xb4, 0x3d, 0x7b,
|
||||
0xf6, 0x42, 0x68, 0x2d, 0x6a, 0xc8, 0x98, 0x91, 0xd9, 0x4a, 0x42, 0x5d, 0x5e, 0x17, 0x50, 0xb1,
|
||||
0x56, 0x6a, 0xbb, 0x3d, 0x77, 0x9a, 0xe3, 0xd9, 0x67, 0x6e, 0x96, 0x21, 0x8a, 0x7c, 0xc0, 0xd8,
|
||||
0x82, 0x90, 0xce, 0x5b, 0x09, 0x8e, 0xa2, 0x38, 0x4a, 0xe6, 0xe7, 0x2f, 0xd3, 0x83, 0xc9, 0x69,
|
||||
0xbe, 0x15, 0x37, 0xef, 0xb5, 0x5a, 0x49, 0x91, 0x8f, 0x0e, 0x9e, 0xfe, 0x89, 0xf0, 0xc9, 0xee,
|
||||
0x98, 0x50, 0x3c, 0xf1, 0x1b, 0x03, 0x14, 0xc5, 0x28, 0x99, 0x2d, 0x27, 0xdd, 0x05, 0x3a, 0xca,
|
||||
0x03, 0x21, 0x04, 0x4f, 0x14, 0x6b, 0x80, 0x1e, 0xf5, 0x93, 0x3c, 0x7c, 0x93, 0xe7, 0x78, 0x5a,
|
||||
0xea, 0x86, 0x49, 0x45, 0xa3, 0x91, 0x7f, 0xcb, 0xfa, 0x2c, 0xa3, 0xad, 0xa7, 0x93, 0x18, 0x25,
|
||||
0xc7, 0xff, 0xb2, 0x7a, 0x42, 0x52, 0x4c, 0x14, 0xe3, 0xda, 0x5d, 0x94, 0x65, 0xbf, 0xf1, 0x15,
|
||||
0xd8, 0x16, 0x2c, 0xbd, 0x17, 0x92, 0x0f, 0x4c, 0xc8, 0x2b, 0x7c, 0xb2, 0xa5, 0x9c, 0x83, 0x73,
|
||||
0x9f, 0x60, 0x43, 0xa7, 0xc1, 0xdd, 0xa3, 0x83, 0x77, 0x05, 0xdc, 0x82, 0xef, 0xbd, 0xfb, 0x23,
|
||||
0x6f, 0xa0, 0xe4, 0x35, 0x7e, 0x1c, 0xc8, 0x17, 0xd6, 0x80, 0x33, 0x8c, 0xc3, 0x65, 0x49, 0x1f,
|
||||
0x04, 0xf3, 0x3f, 0x3e, 0x64, 0x0e, 0x8c, 0xce, 0x46, 0x99, 0x03, 0x25, 0x31, 0x9e, 0x07, 0xf2,
|
||||
0xd1, 0xea, 0xb5, 0x71, 0x14, 0xc7, 0x51, 0x32, 0xcb, 0xc7, 0x88, 0x9c, 0xe3, 0x27, 0xe1, 0x37,
|
||||
0x87, 0x95, 0x05, 0x57, 0x5d, 0x2a, 0x0f, 0xb6, 0x65, 0x35, 0x9d, 0xc7, 0x28, 0x89, 0xf2, 0x83,
|
||||
0x33, 0x92, 0xe0, 0x47, 0x5c, 0x2b, 0xb7, 0xae, 0xef, 0xae, 0x7f, 0x18, 0xae, 0xdf, 0xc7, 0xfd,
|
||||
0x9e, 0x3f, 0x6e, 0xfa, 0xf7, 0x92, 0x1c, 0xdc, 0x57, 0xe6, 0x2b, 0x7a, 0x1c, 0x56, 0xd8, 0xa3,
|
||||
0xcb, 0x77, 0x3f, 0xbb, 0x05, 0xfa, 0xd5, 0x2d, 0xd0, 0xef, 0x6e, 0x81, 0xbe, 0xbd, 0x11, 0xd2,
|
||||
0x57, 0xeb, 0x22, 0xe5, 0xba, 0xc9, 0x58, 0x2d, 0x0b, 0x56, 0xb0, 0xec, 0xb6, 0x47, 0xa1, 0x8b,
|
||||
0x3b, 0x6d, 0x2e, 0xa6, 0xa1, 0x8b, 0x6f, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xb9, 0x6f, 0xf7,
|
||||
0xf0, 0xe5, 0x02, 0x00, 0x00,
|
||||
// 477 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x93, 0xd1, 0x6e, 0xd3, 0x30,
|
||||
0x14, 0x86, 0x95, 0xb5, 0x2b, 0xd4, 0x65, 0xdd, 0xb0, 0x98, 0x64, 0x21, 0x54, 0xa2, 0x49, 0xa0,
|
||||
0x08, 0xa1, 0x44, 0x1b, 0x5c, 0x71, 0xb7, 0x02, 0x42, 0x13, 0x02, 0xa1, 0x8c, 0x2b, 0x6e, 0x26,
|
||||
0xc7, 0x39, 0x75, 0xac, 0x26, 0x71, 0x64, 0xbb, 0x41, 0xe5, 0x89, 0x78, 0x14, 0x2e, 0x79, 0x04,
|
||||
0xd4, 0x27, 0x41, 0x76, 0x4a, 0x9a, 0x86, 0xde, 0x25, 0xdf, 0xf9, 0xfd, 0x9f, 0xf3, 0x3b, 0x39,
|
||||
0x68, 0x56, 0x82, 0xf9, 0x2e, 0xd5, 0x52, 0x94, 0x3c, 0xaa, 0x2f, 0xa3, 0x82, 0x55, 0x77, 0x89,
|
||||
0x12, 0x29, 0x87, 0xb0, 0x52, 0xd2, 0x48, 0x7c, 0x9e, 0x09, 0xae, 0x40, 0xeb, 0x70, 0xa7, 0x0b,
|
||||
0xeb, 0xcb, 0xc7, 0x4f, 0xb9, 0x94, 0x3c, 0x87, 0x88, 0x56, 0x22, 0x5a, 0x08, 0xc8, 0xd3, 0xbb,
|
||||
0x04, 0x32, 0x5a, 0x0b, 0xa9, 0x9a, 0x73, 0x17, 0x31, 0x1a, 0x7f, 0x62, 0xd5, 0xdc, 0x59, 0xe1,
|
||||
0xf7, 0x08, 0x29, 0xe0, 0x42, 0x1b, 0x25, 0x40, 0x13, 0xcf, 0x1f, 0x04, 0x93, 0xab, 0x67, 0xe1,
|
||||
0x41, 0xe7, 0x30, 0x6e, 0x84, 0xeb, 0xb7, 0xb2, 0x5c, 0x08, 0x1e, 0x77, 0x0e, 0x5e, 0xfc, 0x3c,
|
||||
0x46, 0xd3, 0xfd, 0x32, 0x26, 0x68, 0x68, 0xd6, 0x15, 0x10, 0xcf, 0xf7, 0x82, 0xf1, 0x7c, 0xb8,
|
||||
0xb9, 0xf6, 0x8e, 0x62, 0x47, 0x30, 0x46, 0xc3, 0x92, 0x16, 0x40, 0x8e, 0x6c, 0x25, 0x76, 0xcf,
|
||||
0xf8, 0x09, 0x1a, 0xa5, 0xb2, 0xa0, 0xa2, 0x24, 0x83, 0x8e, 0x7e, 0xcb, 0xac, 0x57, 0x25, 0x95,
|
||||
0x21, 0x43, 0xdf, 0x0b, 0x4e, 0xfe, 0x79, 0x59, 0x82, 0x43, 0x84, 0x4b, 0xca, 0xa4, 0xbe, 0x4e,
|
||||
0x53, 0x3b, 0xf1, 0x2d, 0xa8, 0x1a, 0x14, 0x39, 0x76, 0xce, 0x07, 0x2a, 0xf8, 0x39, 0x9a, 0x36,
|
||||
0x94, 0x31, 0xd0, 0xfa, 0x23, 0xac, 0xc9, 0xc8, 0x69, 0x7b, 0xb4, 0xd5, 0xdd, 0x02, 0x53, 0x60,
|
||||
0xac, 0xee, 0x5e, 0x47, 0xd7, 0x52, 0xfc, 0x02, 0x9d, 0x39, 0xf2, 0x99, 0x16, 0xa0, 0x2b, 0xca,
|
||||
0xe0, 0x26, 0x25, 0xf7, 0x9d, 0xf2, 0x3f, 0xde, 0x7a, 0xb6, 0x8c, 0x8c, 0x3b, 0x9e, 0x2d, 0xc5,
|
||||
0x3e, 0x9a, 0x38, 0xf2, 0x41, 0xc9, 0x55, 0xa5, 0x09, 0xf2, 0x07, 0xc1, 0x38, 0xee, 0x22, 0x7c,
|
||||
0x85, 0x1e, 0xb9, 0xd7, 0x18, 0x16, 0x0a, 0x74, 0x76, 0x53, 0x1a, 0x50, 0x35, 0xcd, 0xc9, 0xc4,
|
||||
0xf7, 0x82, 0x41, 0x7c, 0xb0, 0x86, 0x03, 0x74, 0xca, 0x64, 0xa9, 0x57, 0xf9, 0xae, 0xfd, 0x03,
|
||||
0xd7, 0xbe, 0x8f, 0xed, 0x9c, 0x3f, 0x96, 0xf6, 0xbe, 0x04, 0x03, 0xfd, 0x85, 0x9a, 0x8c, 0x9c,
|
||||
0xb8, 0x11, 0x7a, 0xd4, 0x66, 0x6f, 0x8e, 0xbe, 0xa3, 0x86, 0x32, 0xb0, 0x8d, 0xc8, 0xb4, 0xc9,
|
||||
0xde, 0xe7, 0x3b, 0xed, 0xd6, 0xe1, 0x2b, 0xe5, 0xe4, 0xb4, 0xab, 0xdd, 0x71, 0xfc, 0x1a, 0x9d,
|
||||
0x37, 0xac, 0x1f, 0xef, 0xcc, 0xc5, 0x3b, 0x5c, 0xb4, 0x53, 0xd3, 0x95, 0xc9, 0x9a, 0x4f, 0x63,
|
||||
0xc3, 0x90, 0x87, 0xcd, 0xed, 0xee, 0xd3, 0xf9, 0x9b, 0x5f, 0x9b, 0x99, 0xf7, 0x7b, 0x33, 0xf3,
|
||||
0xfe, 0x6c, 0x66, 0xde, 0xb7, 0x97, 0x5c, 0x98, 0x6c, 0x95, 0x84, 0x4c, 0x16, 0x11, 0xcd, 0x45,
|
||||
0x42, 0x13, 0x1a, 0x6d, 0xff, 0x7e, 0xb7, 0x41, 0x7b, 0x3b, 0x98, 0x8c, 0xdc, 0x06, 0xbd, 0xfa,
|
||||
0x1b, 0x00, 0x00, 0xff, 0xff, 0x21, 0x2e, 0x82, 0x0a, 0x9b, 0x03, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *McpBridge) Marshal() (dAtA []byte, err error) {
|
||||
@@ -333,6 +368,36 @@ func (m *RegistryConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i -= len(m.XXX_unrecognized)
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
if len(m.AuthSecretName) > 0 {
|
||||
i -= len(m.AuthSecretName)
|
||||
copy(dAtA[i:], m.AuthSecretName)
|
||||
i = encodeVarintMcpBridge(dAtA, i, uint64(len(m.AuthSecretName)))
|
||||
i--
|
||||
dAtA[i] = 0x1
|
||||
i--
|
||||
dAtA[i] = 0x8a
|
||||
}
|
||||
if m.ConsulRefreshInterval != 0 {
|
||||
i = encodeVarintMcpBridge(dAtA, i, uint64(m.ConsulRefreshInterval))
|
||||
i--
|
||||
dAtA[i] = 0x1
|
||||
i--
|
||||
dAtA[i] = 0x80
|
||||
}
|
||||
if len(m.ConsulServiceTag) > 0 {
|
||||
i -= len(m.ConsulServiceTag)
|
||||
copy(dAtA[i:], m.ConsulServiceTag)
|
||||
i = encodeVarintMcpBridge(dAtA, i, uint64(len(m.ConsulServiceTag)))
|
||||
i--
|
||||
dAtA[i] = 0x7a
|
||||
}
|
||||
if len(m.ConsulDatacenter) > 0 {
|
||||
i -= len(m.ConsulDatacenter)
|
||||
copy(dAtA[i:], m.ConsulDatacenter)
|
||||
i = encodeVarintMcpBridge(dAtA, i, uint64(len(m.ConsulDatacenter)))
|
||||
i--
|
||||
dAtA[i] = 0x72
|
||||
}
|
||||
if len(m.ZkServicesPath) > 0 {
|
||||
for iNdEx := len(m.ZkServicesPath) - 1; iNdEx >= 0; iNdEx-- {
|
||||
i -= len(m.ZkServicesPath[iNdEx])
|
||||
@@ -516,6 +581,21 @@ func (m *RegistryConfig) Size() (n int) {
|
||||
n += 1 + l + sovMcpBridge(uint64(l))
|
||||
}
|
||||
}
|
||||
l = len(m.ConsulDatacenter)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovMcpBridge(uint64(l))
|
||||
}
|
||||
l = len(m.ConsulServiceTag)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovMcpBridge(uint64(l))
|
||||
}
|
||||
if m.ConsulRefreshInterval != 0 {
|
||||
n += 2 + sovMcpBridge(uint64(m.ConsulRefreshInterval))
|
||||
}
|
||||
l = len(m.AuthSecretName)
|
||||
if l > 0 {
|
||||
n += 2 + l + sovMcpBridge(uint64(l))
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
@@ -1032,6 +1112,121 @@ func (m *RegistryConfig) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
m.ZkServicesPath = append(m.ZkServicesPath, string(dAtA[iNdEx:postIndex]))
|
||||
iNdEx = postIndex
|
||||
case 14:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ConsulDatacenter", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowMcpBridge
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthMcpBridge
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthMcpBridge
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.ConsulDatacenter = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 15:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ConsulServiceTag", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowMcpBridge
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthMcpBridge
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthMcpBridge
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.ConsulServiceTag = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 16:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ConsulRefreshInterval", wireType)
|
||||
}
|
||||
m.ConsulRefreshInterval = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowMcpBridge
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.ConsulRefreshInterval |= int64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 17:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field AuthSecretName", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowMcpBridge
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthMcpBridge
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthMcpBridge
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.AuthSecretName = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipMcpBridge(dAtA[iNdEx:])
|
||||
|
||||
@@ -60,4 +60,8 @@ message RegistryConfig {
|
||||
int64 nacosRefreshInterval = 11;
|
||||
string consulNamespace = 12;
|
||||
repeated string zkServicesPath = 13;
|
||||
string consulDatacenter = 14;
|
||||
string consulServiceTag = 15;
|
||||
int64 consulRefreshInterval = 16;
|
||||
string authSecretName = 17;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ func Resource(resource string) schema.GroupResource {
|
||||
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&Http2Rpc{},
|
||||
&Http2RpcList{},
|
||||
&McpBridge{},
|
||||
&McpBridgeList{},
|
||||
)
|
||||
|
||||
@@ -25,6 +25,48 @@ import (
|
||||
// please upgrade the proto package
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// <!-- crd generation tags
|
||||
// +cue-gen:Http2Rpc:groupName:networking.higress.io
|
||||
// +cue-gen:Http2Rpc:version:v1
|
||||
// +cue-gen:Http2Rpc:storageVersion
|
||||
// +cue-gen:Http2Rpc:annotations:helm.sh/resource-policy=keep
|
||||
// +cue-gen:Http2Rpc:subresource:status
|
||||
// +cue-gen:Http2Rpc:scope:Namespaced
|
||||
// +cue-gen:Http2Rpc:resource:categories=higress-io,plural=http2rpcs
|
||||
// +cue-gen:Http2Rpc:preserveUnknownFields:false
|
||||
// -->
|
||||
//
|
||||
// <!-- go code generation tags
|
||||
// +kubetype-gen
|
||||
// +kubetype-gen:groupVersion=networking.higress.io/v1
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen=true
|
||||
// -->
|
||||
type Http2Rpc struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// +optional
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// Spec defines the implementation of this definition.
|
||||
// +optional
|
||||
Spec networkingv1.Http2Rpc `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
|
||||
|
||||
Status v1alpha1.IstioStatus `json:"status"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Http2RpcList is a collection of Http2Rpcs.
|
||||
type Http2RpcList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// +optional
|
||||
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
Items []Http2Rpc `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||
}
|
||||
|
||||
// please upgrade the proto package
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// <!-- crd generation tags
|
||||
// +cue-gen:McpBridge:groupName:networking.higress.io
|
||||
// +cue-gen:McpBridge:version:v1
|
||||
|
||||
@@ -23,6 +23,67 @@ import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Http2Rpc) DeepCopyInto(out *Http2Rpc) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Http2Rpc.
|
||||
func (in *Http2Rpc) DeepCopy() *Http2Rpc {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Http2Rpc)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Http2Rpc) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Http2RpcList) DeepCopyInto(out *Http2RpcList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Http2Rpc, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Http2RpcList.
|
||||
func (in *Http2RpcList) DeepCopy() *Http2RpcList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Http2RpcList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Http2RpcList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *McpBridge) DeepCopyInto(out *McpBridge) {
|
||||
*out = *in
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
networkingv1 "github.com/alibaba/higress/client/pkg/apis/networking/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// FakeHttp2Rpcs implements Http2RpcInterface
|
||||
type FakeHttp2Rpcs struct {
|
||||
Fake *FakeNetworkingV1
|
||||
ns string
|
||||
}
|
||||
|
||||
var http2rpcsResource = schema.GroupVersionResource{Group: "networking.higress.io", Version: "v1", Resource: "http2rpcs"}
|
||||
|
||||
var http2rpcsKind = schema.GroupVersionKind{Group: "networking.higress.io", Version: "v1", Kind: "Http2Rpc"}
|
||||
|
||||
// Get takes name of the http2Rpc, and returns the corresponding http2Rpc object, and an error if there is any.
|
||||
func (c *FakeHttp2Rpcs) Get(ctx context.Context, name string, options v1.GetOptions) (result *networkingv1.Http2Rpc, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewGetAction(http2rpcsResource, c.ns, name), &networkingv1.Http2Rpc{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*networkingv1.Http2Rpc), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of Http2Rpcs that match those selectors.
|
||||
func (c *FakeHttp2Rpcs) List(ctx context.Context, opts v1.ListOptions) (result *networkingv1.Http2RpcList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewListAction(http2rpcsResource, http2rpcsKind, c.ns, opts), &networkingv1.Http2RpcList{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &networkingv1.Http2RpcList{ListMeta: obj.(*networkingv1.Http2RpcList).ListMeta}
|
||||
for _, item := range obj.(*networkingv1.Http2RpcList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested http2Rpcs.
|
||||
func (c *FakeHttp2Rpcs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(http2rpcsResource, c.ns, opts))
|
||||
|
||||
}
|
||||
|
||||
// Create takes the representation of a http2Rpc and creates it. Returns the server's representation of the http2Rpc, and an error, if there is any.
|
||||
func (c *FakeHttp2Rpcs) Create(ctx context.Context, http2Rpc *networkingv1.Http2Rpc, opts v1.CreateOptions) (result *networkingv1.Http2Rpc, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewCreateAction(http2rpcsResource, c.ns, http2Rpc), &networkingv1.Http2Rpc{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*networkingv1.Http2Rpc), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a http2Rpc and updates it. Returns the server's representation of the http2Rpc, and an error, if there is any.
|
||||
func (c *FakeHttp2Rpcs) Update(ctx context.Context, http2Rpc *networkingv1.Http2Rpc, opts v1.UpdateOptions) (result *networkingv1.Http2Rpc, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateAction(http2rpcsResource, c.ns, http2Rpc), &networkingv1.Http2Rpc{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*networkingv1.Http2Rpc), err
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *FakeHttp2Rpcs) UpdateStatus(ctx context.Context, http2Rpc *networkingv1.Http2Rpc, opts v1.UpdateOptions) (*networkingv1.Http2Rpc, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateSubresourceAction(http2rpcsResource, "status", c.ns, http2Rpc), &networkingv1.Http2Rpc{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*networkingv1.Http2Rpc), err
|
||||
}
|
||||
|
||||
// Delete takes name of the http2Rpc and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeHttp2Rpcs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteAction(http2rpcsResource, c.ns, name), &networkingv1.Http2Rpc{})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeHttp2Rpcs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(http2rpcsResource, c.ns, listOpts)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &networkingv1.Http2RpcList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched http2Rpc.
|
||||
func (c *FakeHttp2Rpcs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *networkingv1.Http2Rpc, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(http2rpcsResource, c.ns, name, pt, data, subresources...), &networkingv1.Http2Rpc{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*networkingv1.Http2Rpc), err
|
||||
}
|
||||
@@ -26,6 +26,10 @@ type FakeNetworkingV1 struct {
|
||||
*testing.Fake
|
||||
}
|
||||
|
||||
func (c *FakeNetworkingV1) Http2Rpcs(namespace string) v1.Http2RpcInterface {
|
||||
return &FakeHttp2Rpcs{c, namespace}
|
||||
}
|
||||
|
||||
func (c *FakeNetworkingV1) McpBridges(namespace string) v1.McpBridgeInterface {
|
||||
return &FakeMcpBridges{c, namespace}
|
||||
}
|
||||
|
||||
@@ -16,4 +16,6 @@
|
||||
|
||||
package v1
|
||||
|
||||
type Http2RpcExpansion interface{}
|
||||
|
||||
type McpBridgeExpansion interface{}
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
v1 "github.com/alibaba/higress/client/pkg/apis/networking/v1"
|
||||
scheme "github.com/alibaba/higress/client/pkg/clientset/versioned/scheme"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// Http2RpcsGetter has a method to return a Http2RpcInterface.
|
||||
// A group's client should implement this interface.
|
||||
type Http2RpcsGetter interface {
|
||||
Http2Rpcs(namespace string) Http2RpcInterface
|
||||
}
|
||||
|
||||
// Http2RpcInterface has methods to work with Http2Rpc resources.
|
||||
type Http2RpcInterface interface {
|
||||
Create(ctx context.Context, http2Rpc *v1.Http2Rpc, opts metav1.CreateOptions) (*v1.Http2Rpc, error)
|
||||
Update(ctx context.Context, http2Rpc *v1.Http2Rpc, opts metav1.UpdateOptions) (*v1.Http2Rpc, error)
|
||||
UpdateStatus(ctx context.Context, http2Rpc *v1.Http2Rpc, opts metav1.UpdateOptions) (*v1.Http2Rpc, error)
|
||||
Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error
|
||||
DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
|
||||
Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Http2Rpc, error)
|
||||
List(ctx context.Context, opts metav1.ListOptions) (*v1.Http2RpcList, error)
|
||||
Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error)
|
||||
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Http2Rpc, err error)
|
||||
Http2RpcExpansion
|
||||
}
|
||||
|
||||
// http2Rpcs implements Http2RpcInterface
|
||||
type http2Rpcs struct {
|
||||
client rest.Interface
|
||||
ns string
|
||||
}
|
||||
|
||||
// newHttp2Rpcs returns a Http2Rpcs
|
||||
func newHttp2Rpcs(c *NetworkingV1Client, namespace string) *http2Rpcs {
|
||||
return &http2Rpcs{
|
||||
client: c.RESTClient(),
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the http2Rpc, and returns the corresponding http2Rpc object, and an error if there is any.
|
||||
func (c *http2Rpcs) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.Http2Rpc, err error) {
|
||||
result = &v1.Http2Rpc{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("http2rpcs").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of Http2Rpcs that match those selectors.
|
||||
func (c *http2Rpcs) List(ctx context.Context, opts metav1.ListOptions) (result *v1.Http2RpcList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
result = &v1.Http2RpcList{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("http2rpcs").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested http2Rpcs.
|
||||
func (c *http2Rpcs) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("http2rpcs").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch(ctx)
|
||||
}
|
||||
|
||||
// Create takes the representation of a http2Rpc and creates it. Returns the server's representation of the http2Rpc, and an error, if there is any.
|
||||
func (c *http2Rpcs) Create(ctx context.Context, http2Rpc *v1.Http2Rpc, opts metav1.CreateOptions) (result *v1.Http2Rpc, err error) {
|
||||
result = &v1.Http2Rpc{}
|
||||
err = c.client.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("http2rpcs").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(http2Rpc).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a http2Rpc and updates it. Returns the server's representation of the http2Rpc, and an error, if there is any.
|
||||
func (c *http2Rpcs) Update(ctx context.Context, http2Rpc *v1.Http2Rpc, opts metav1.UpdateOptions) (result *v1.Http2Rpc, err error) {
|
||||
result = &v1.Http2Rpc{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("http2rpcs").
|
||||
Name(http2Rpc.Name).
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(http2Rpc).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *http2Rpcs) UpdateStatus(ctx context.Context, http2Rpc *v1.Http2Rpc, opts metav1.UpdateOptions) (result *v1.Http2Rpc, err error) {
|
||||
result = &v1.Http2Rpc{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("http2rpcs").
|
||||
Name(http2Rpc.Name).
|
||||
SubResource("status").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(http2Rpc).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the http2Rpc and deletes it. Returns an error if one occurs.
|
||||
func (c *http2Rpcs) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("http2rpcs").
|
||||
Name(name).
|
||||
Body(&opts).
|
||||
Do(ctx).
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *http2Rpcs) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
|
||||
var timeout time.Duration
|
||||
if listOpts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("http2rpcs").
|
||||
VersionedParams(&listOpts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Body(&opts).
|
||||
Do(ctx).
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched http2Rpc.
|
||||
func (c *http2Rpcs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Http2Rpc, err error) {
|
||||
result = &v1.Http2Rpc{}
|
||||
err = c.client.Patch(pt).
|
||||
Namespace(c.ns).
|
||||
Resource("http2rpcs").
|
||||
Name(name).
|
||||
SubResource(subresources...).
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(data).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
|
||||
type NetworkingV1Interface interface {
|
||||
RESTClient() rest.Interface
|
||||
Http2RpcsGetter
|
||||
McpBridgesGetter
|
||||
}
|
||||
|
||||
@@ -32,6 +33,10 @@ type NetworkingV1Client struct {
|
||||
restClient rest.Interface
|
||||
}
|
||||
|
||||
func (c *NetworkingV1Client) Http2Rpcs(namespace string) Http2RpcInterface {
|
||||
return newHttp2Rpcs(c, namespace)
|
||||
}
|
||||
|
||||
func (c *NetworkingV1Client) McpBridges(namespace string) McpBridgeInterface {
|
||||
return newMcpBridges(c, namespace)
|
||||
}
|
||||
|
||||
@@ -56,6 +56,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Extensions().V1alpha1().WasmPlugins().Informer()}, nil
|
||||
|
||||
// Group=networking.higress.io, Version=v1
|
||||
case v1.SchemeGroupVersion.WithResource("http2rpcs"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Networking().V1().Http2Rpcs().Informer()}, nil
|
||||
case v1.SchemeGroupVersion.WithResource("mcpbridges"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Networking().V1().McpBridges().Informer()}, nil
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
time "time"
|
||||
|
||||
networkingv1 "github.com/alibaba/higress/client/pkg/apis/networking/v1"
|
||||
versioned "github.com/alibaba/higress/client/pkg/clientset/versioned"
|
||||
internalinterfaces "github.com/alibaba/higress/client/pkg/informers/externalversions/internalinterfaces"
|
||||
v1 "github.com/alibaba/higress/client/pkg/listers/networking/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// Http2RpcInformer provides access to a shared informer and lister for
|
||||
// Http2Rpcs.
|
||||
type Http2RpcInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1.Http2RpcLister
|
||||
}
|
||||
|
||||
type http2RpcInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewHttp2RpcInformer constructs a new informer for Http2Rpc type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewHttp2RpcInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredHttp2RpcInformer(client, namespace, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredHttp2RpcInformer constructs a new informer for Http2Rpc type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewFilteredHttp2RpcInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.NetworkingV1().Http2Rpcs(namespace).List(context.TODO(), options)
|
||||
},
|
||||
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.NetworkingV1().Http2Rpcs(namespace).Watch(context.TODO(), options)
|
||||
},
|
||||
},
|
||||
&networkingv1.Http2Rpc{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *http2RpcInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredHttp2RpcInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *http2RpcInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&networkingv1.Http2Rpc{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *http2RpcInformer) Lister() v1.Http2RpcLister {
|
||||
return v1.NewHttp2RpcLister(f.Informer().GetIndexer())
|
||||
}
|
||||
@@ -22,6 +22,8 @@ import (
|
||||
|
||||
// Interface provides access to all the informers in this group version.
|
||||
type Interface interface {
|
||||
// Http2Rpcs returns a Http2RpcInformer.
|
||||
Http2Rpcs() Http2RpcInformer
|
||||
// McpBridges returns a McpBridgeInformer.
|
||||
McpBridges() McpBridgeInformer
|
||||
}
|
||||
@@ -37,6 +39,11 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
|
||||
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
|
||||
}
|
||||
|
||||
// Http2Rpcs returns a Http2RpcInformer.
|
||||
func (v *version) Http2Rpcs() Http2RpcInformer {
|
||||
return &http2RpcInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
|
||||
// McpBridges returns a McpBridgeInformer.
|
||||
func (v *version) McpBridges() McpBridgeInformer {
|
||||
return &mcpBridgeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
|
||||
@@ -16,6 +16,14 @@
|
||||
|
||||
package v1
|
||||
|
||||
// Http2RpcListerExpansion allows custom methods to be added to
|
||||
// Http2RpcLister.
|
||||
type Http2RpcListerExpansion interface{}
|
||||
|
||||
// Http2RpcNamespaceListerExpansion allows custom methods to be added to
|
||||
// Http2RpcNamespaceLister.
|
||||
type Http2RpcNamespaceListerExpansion interface{}
|
||||
|
||||
// McpBridgeListerExpansion allows custom methods to be added to
|
||||
// McpBridgeLister.
|
||||
type McpBridgeListerExpansion interface{}
|
||||
|
||||
92
client/pkg/listers/networking/v1/http2rpc.gen.go
Normal file
92
client/pkg/listers/networking/v1/http2rpc.gen.go
Normal file
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
v1 "github.com/alibaba/higress/client/pkg/apis/networking/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// Http2RpcLister helps list Http2Rpcs.
|
||||
type Http2RpcLister interface {
|
||||
// List lists all Http2Rpcs in the indexer.
|
||||
List(selector labels.Selector) (ret []*v1.Http2Rpc, err error)
|
||||
// Http2Rpcs returns an object that can list and get Http2Rpcs.
|
||||
Http2Rpcs(namespace string) Http2RpcNamespaceLister
|
||||
Http2RpcListerExpansion
|
||||
}
|
||||
|
||||
// http2RpcLister implements the Http2RpcLister interface.
|
||||
type http2RpcLister struct {
|
||||
indexer cache.Indexer
|
||||
}
|
||||
|
||||
// NewHttp2RpcLister returns a new Http2RpcLister.
|
||||
func NewHttp2RpcLister(indexer cache.Indexer) Http2RpcLister {
|
||||
return &http2RpcLister{indexer: indexer}
|
||||
}
|
||||
|
||||
// List lists all Http2Rpcs in the indexer.
|
||||
func (s *http2RpcLister) List(selector labels.Selector) (ret []*v1.Http2Rpc, err error) {
|
||||
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1.Http2Rpc))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Http2Rpcs returns an object that can list and get Http2Rpcs.
|
||||
func (s *http2RpcLister) Http2Rpcs(namespace string) Http2RpcNamespaceLister {
|
||||
return http2RpcNamespaceLister{indexer: s.indexer, namespace: namespace}
|
||||
}
|
||||
|
||||
// Http2RpcNamespaceLister helps list and get Http2Rpcs.
|
||||
type Http2RpcNamespaceLister interface {
|
||||
// List lists all Http2Rpcs in the indexer for a given namespace.
|
||||
List(selector labels.Selector) (ret []*v1.Http2Rpc, err error)
|
||||
// Get retrieves the Http2Rpc from the indexer for a given namespace and name.
|
||||
Get(name string) (*v1.Http2Rpc, error)
|
||||
Http2RpcNamespaceListerExpansion
|
||||
}
|
||||
|
||||
// http2RpcNamespaceLister implements the Http2RpcNamespaceLister
|
||||
// interface.
|
||||
type http2RpcNamespaceLister struct {
|
||||
indexer cache.Indexer
|
||||
namespace string
|
||||
}
|
||||
|
||||
// List lists all Http2Rpcs in the indexer for a given namespace.
|
||||
func (s http2RpcNamespaceLister) List(selector labels.Selector) (ret []*v1.Http2Rpc, err error) {
|
||||
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1.Http2Rpc))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves the Http2Rpc from the indexer for a given namespace and name.
|
||||
func (s http2RpcNamespaceLister) Get(name string) (*v1.Http2Rpc, error) {
|
||||
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(v1.Resource("http2rpc"), name)
|
||||
}
|
||||
return obj.(*v1.Http2Rpc), nil
|
||||
}
|
||||
33
docker/Dockerfile.base
Normal file
33
docker/Dockerfile.base
Normal file
@@ -0,0 +1,33 @@
|
||||
FROM ubuntu:22.04
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Do not add more stuff to this list that isn't small or critically useful.
|
||||
# If you occasionally need something on the container do
|
||||
# sudo apt-get update && apt-get whichever
|
||||
|
||||
# hadolint ignore=DL3005,DL3008
|
||||
RUN apt-get update && \
|
||||
apt-get install --no-install-recommends -y \
|
||||
ca-certificates \
|
||||
curl \
|
||||
iptables \
|
||||
iproute2 \
|
||||
iputils-ping \
|
||||
knot-dnsutils \
|
||||
netcat \
|
||||
tcpdump \
|
||||
conntrack \
|
||||
bsdmainutils \
|
||||
net-tools \
|
||||
lsof \
|
||||
sudo \
|
||||
&& apt-get upgrade -y \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/log/*log /var/lib/apt/lists/* /var/log/apt/* /var/lib/dpkg/*-old /var/cache/debconf/*-old \
|
||||
&& update-alternatives --set iptables /usr/sbin/iptables-legacy \
|
||||
&& update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
|
||||
|
||||
# Sudoers used to allow tcpdump and other debug utilities.
|
||||
RUN useradd -m --uid 1337 istio-proxy && \
|
||||
echo "istio-proxy ALL=NOPASSWD: ALL" >> /etc/sudoers
|
||||
@@ -11,6 +11,7 @@ ARG HUB
|
||||
FROM ${HUB}/base:${BASE_VERSION}
|
||||
|
||||
ARG TARGETARCH
|
||||
|
||||
COPY ${TARGETARCH:-amd64}/higress /usr/local/bin/higress
|
||||
|
||||
USER 1337:1337
|
||||
|
||||
@@ -17,6 +17,12 @@ docker.higress: $(OUT_LINUX)/higress
|
||||
docker.higress: docker/Dockerfile.higress
|
||||
$(HIGRESS_DOCKER_RULE)
|
||||
|
||||
docker.higress-buildx: BUILD_ARGS=--build-arg BASE_VERSION=${BASE_VERSION} --build-arg HUB=${HUB}
|
||||
docker.higress-buildx: $(AMD64_OUT_LINUX)/higress
|
||||
docker.higress-buildx: $(ARM64_OUT_LINUX)/higress
|
||||
docker.higress-buildx: docker/Dockerfile.higress
|
||||
$(HIGRESS_DOCKER_BUILDX_RULE)
|
||||
|
||||
# DOCKER_BUILD_VARIANTS ?=debug distroless
|
||||
# Base images have two different forms:
|
||||
# * "debug", suffixed as -debug. This is a ubuntu based image with a bunch of debug tools
|
||||
@@ -28,4 +34,7 @@ DOCKER_ALL_VARIANTS ?= debug distroless
|
||||
# This can be done with DOCKER_BUILD_VARIANTS="default debug" as well, but at the expense of building twice vs building once and tagging twice
|
||||
INCLUDE_UNTAGGED_DEFAULT ?= false
|
||||
DEFAULT_DISTRIBUTION=debug
|
||||
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)/$(subst docker.,,$@):$(TAG)$(call variant-tag,$(VARIANT)) -f Dockerfile$(suffix $@) . ); )
|
||||
|
||||
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 . ); )
|
||||
|
||||
|
||||
BIN
docs/images/domain.gif
Normal file
BIN
docs/images/domain.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 MiB |
BIN
docs/images/monitor.gif
Normal file
BIN
docs/images/monitor.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.4 MiB |
BIN
docs/images/plugin.gif
Normal file
BIN
docs/images/plugin.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.2 MiB |
BIN
docs/images/route-service.gif
Normal file
BIN
docs/images/route-service.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 MiB |
BIN
docs/images/service-source.gif
Normal file
BIN
docs/images/service-source.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 MiB |
111
envoy/1.20/patches/envoy/20231008-fallback-origin-cluster.patch
Normal file
111
envoy/1.20/patches/envoy/20231008-fallback-origin-cluster.patch
Normal file
@@ -0,0 +1,111 @@
|
||||
diff -Naur envoy/contrib/custom_cluster_plugins/cluster_fallback/source/filter.cc envoy-new/contrib/custom_cluster_plugins/cluster_fallback/source/filter.cc
|
||||
--- envoy/contrib/custom_cluster_plugins/cluster_fallback/source/filter.cc 2023-10-08 15:01:21.960871500 +0800
|
||||
+++ envoy-new/contrib/custom_cluster_plugins/cluster_fallback/source/filter.cc 2023-09-27 17:03:41.613256338 +0800
|
||||
@@ -60,7 +60,7 @@
|
||||
|
||||
for (const auto& cluster_name : first_item->second) {
|
||||
if (hasHealthHost(cluster_name)) {
|
||||
- return base.clone(cluster_name);
|
||||
+ return base.clone(cluster_name, first_item->first);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,8 @@
|
||||
|
||||
auto search = clusters_config_.find(route_entry.clusterName());
|
||||
if (search == clusters_config_.end()) {
|
||||
- ENVOY_LOG(warn, "there is no fallback cluster config, the original routing cluster is returned");
|
||||
+ ENVOY_LOG(warn,
|
||||
+ "there is no fallback cluster config, the original routing cluster is returned");
|
||||
return cluster_entry.getRouteConstSharedPtr();
|
||||
}
|
||||
|
||||
@@ -87,7 +88,7 @@
|
||||
|
||||
for (const auto& cluster_name : search->second) {
|
||||
if (hasHealthHost(cluster_name)) {
|
||||
- return cluster_entry.clone(cluster_name);
|
||||
+ return cluster_entry.clone(cluster_name, search->first);
|
||||
}
|
||||
}
|
||||
|
||||
diff -Naur envoy/source/common/http/headers.h envoy-new/source/common/http/headers.h
|
||||
--- envoy/source/common/http/headers.h 2023-10-08 15:01:21.968871828 +0800
|
||||
+++ envoy-new/source/common/http/headers.h 2023-09-27 18:48:50.059419606 +0800
|
||||
@@ -124,6 +124,7 @@
|
||||
const LowerCaseString TriStartTime{"req-start-time"};
|
||||
const LowerCaseString TriRespStartTime{"resp-start-time"};
|
||||
const LowerCaseString EnvoyOriginalHost{"original-host"};
|
||||
+ const LowerCaseString HigressOriginalService{"x-higress-original-service"};
|
||||
} AliExtendedValues;
|
||||
#endif
|
||||
};
|
||||
diff -Naur envoy/source/common/router/config_impl.cc envoy-new/source/common/router/config_impl.cc
|
||||
--- envoy/source/common/router/config_impl.cc 2023-10-08 15:01:21.968871828 +0800
|
||||
+++ envoy-new/source/common/router/config_impl.cc 2023-09-27 18:49:18.656592237 +0800
|
||||
@@ -563,7 +563,6 @@
|
||||
route.name());
|
||||
}
|
||||
// End Added
|
||||
-
|
||||
}
|
||||
|
||||
bool RouteEntryImplBase::evaluateRuntimeMatch(const uint64_t random_value) const {
|
||||
@@ -662,6 +661,10 @@
|
||||
}
|
||||
|
||||
#if defined(ALIMESH)
|
||||
+ if (!origin_cluster_name_.empty()) {
|
||||
+ headers.addCopy(Http::CustomHeaders::get().AliExtendedValues.HigressOriginalService,
|
||||
+ origin_cluster_name_);
|
||||
+ }
|
||||
headers.setReferenceKey(Http::CustomHeaders::get().AliExtendedValues.EnvoyOriginalHost,
|
||||
headers.getHostValue());
|
||||
#endif
|
||||
diff -Naur envoy/source/common/router/config_impl.h envoy-new/source/common/router/config_impl.h
|
||||
--- envoy/source/common/router/config_impl.h 2023-10-08 15:01:21.968871828 +0800
|
||||
+++ envoy-new/source/common/router/config_impl.h 2023-09-27 18:59:11.196893507 +0800
|
||||
@@ -584,9 +584,13 @@
|
||||
return internal_active_redirect_policy_;
|
||||
}
|
||||
|
||||
- RouteConstSharedPtr clone(const std::string& name) const {
|
||||
- return std::make_shared<DynamicRouteEntry>(this, name);
|
||||
+ RouteConstSharedPtr clone(const std::string& name, const std::string& origin_cluster = "") const {
|
||||
+ auto entry = std::make_shared<DynamicRouteEntry>(this, name);
|
||||
+ entry->setOriginClusterName(origin_cluster);
|
||||
+ return entry;
|
||||
}
|
||||
+
|
||||
+ void setOriginClusterName(const std::string& name) const { origin_cluster_name_ = name; }
|
||||
#endif
|
||||
uint32_t retryShadowBufferLimit() const override { return retry_shadow_buffer_limit_; }
|
||||
const std::vector<ShadowPolicyPtr>& shadowPolicies() const override { return shadow_policies_; }
|
||||
@@ -787,11 +791,17 @@
|
||||
return parent_->internalActiveRedirectPolicy();
|
||||
}
|
||||
|
||||
- RouteConstSharedPtr clone(const std::string& name) const {
|
||||
- return std::make_shared<Envoy::Router::RouteEntryImplBase::DynamicRouteEntry>(parent_, name);
|
||||
+ RouteConstSharedPtr clone(const std::string& name,
|
||||
+ const std::string& origin_cluster = "") const {
|
||||
+ auto entry =
|
||||
+ std::make_shared<Envoy::Router::RouteEntryImplBase::DynamicRouteEntry>(parent_, name);
|
||||
+ entry->setOriginClusterName(origin_cluster);
|
||||
+ return entry;
|
||||
}
|
||||
|
||||
virtual RouteConstSharedPtr getRouteConstSharedPtr() const { return shared_from_this(); }
|
||||
+
|
||||
+ void setOriginClusterName(const std::string& name) { parent_->setOriginClusterName(name); }
|
||||
#endif
|
||||
|
||||
private:
|
||||
@@ -1039,6 +1049,7 @@
|
||||
|
||||
#if defined(ALIMESH)
|
||||
const InternalActiveRedirectPoliciesImpl internal_active_redirect_policy_;
|
||||
+ mutable std::string origin_cluster_name_;
|
||||
#endif
|
||||
};
|
||||
|
||||
248
go.mod
248
go.mod
@@ -10,47 +10,61 @@ replace github.com/chzyer/logex => github.com/chzyer/logex v1.1.11-0.20170329064
|
||||
// Avoid pulling in incompatible libraries
|
||||
replace github.com/docker/distribution => github.com/docker/distribution v0.0.0-20191216044856-a8371794149d
|
||||
|
||||
replace github.com/docker/docker => github.com/moby/moby v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible
|
||||
|
||||
// Client-go does not handle different versions of mergo due to some breaking changes - use the matching version
|
||||
replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.5
|
||||
|
||||
require (
|
||||
github.com/AlecAivazis/survey/v2 v2.3.6
|
||||
github.com/agiledragon/gomonkey/v2 v2.9.0
|
||||
github.com/avast/retry-go/v4 v4.3.4
|
||||
github.com/compose-spec/compose-go v1.8.2
|
||||
github.com/docker/cli v20.10.20+incompatible
|
||||
github.com/docker/compose/v2 v2.0.0-00010101000000-000000000000
|
||||
github.com/docker/docker v20.10.20+incompatible
|
||||
github.com/dubbogo/go-zookeeper v1.0.4-0.20211212162352-f9d2183d89d5
|
||||
github.com/dubbogo/gost v1.13.1
|
||||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1
|
||||
github.com/fatih/color v1.14.1
|
||||
github.com/fatih/structtag v1.2.0
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/google/go-cmp v0.5.8
|
||||
github.com/google/go-cmp v0.5.9
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
|
||||
github.com/hashicorp/consul/api v1.23.0
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/hudl/fargo v1.4.0
|
||||
github.com/iancoleman/orderedmap v0.3.0
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/nacos-group/nacos-sdk-go v1.0.8
|
||||
github.com/nacos-group/nacos-sdk-go/v2 v2.1.2
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/spf13/cobra v1.2.1
|
||||
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
|
||||
github.com/spf13/cobra v1.6.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/spf13/viper v1.8.1
|
||||
github.com/stretchr/testify v1.8.3
|
||||
go.uber.org/atomic v1.9.0
|
||||
google.golang.org/grpc v1.48.0
|
||||
google.golang.org/protobuf v1.28.0
|
||||
google.golang.org/protobuf v1.28.1
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
istio.io/api v0.0.0-20211122181927-8da52c66ff23
|
||||
istio.io/client-go v1.12.0-rc.1.0.20211118171212-b744b6f111e4
|
||||
istio.io/gogo-genproto v0.0.0-20211115195057-0e34bdd2be67
|
||||
istio.io/istio v0.0.0
|
||||
istio.io/pkg v0.0.0-20211115195056-e379f31ee62a
|
||||
k8s.io/api v0.22.2
|
||||
k8s.io/apimachinery v0.22.2
|
||||
k8s.io/api v0.24.1
|
||||
k8s.io/apimachinery v0.24.1
|
||||
k8s.io/cli-runtime v0.22.2
|
||||
k8s.io/client-go v0.22.2
|
||||
k8s.io/client-go v0.24.1
|
||||
k8s.io/kubectl v0.22.2
|
||||
sigs.k8s.io/controller-runtime v0.10.2
|
||||
sigs.k8s.io/yaml v1.3.0
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.97.0 // indirect
|
||||
cloud.google.com/go v0.98.0 // indirect
|
||||
cloud.google.com/go/logging v1.4.2 // indirect
|
||||
contrib.go.opencensus.io/exporter/prometheus v0.4.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
@@ -60,47 +74,69 @@ require (
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/BurntSushi/toml v0.3.1 // indirect
|
||||
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.1.1 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.2 // indirect
|
||||
github.com/Microsoft/go-winio v0.5.0 // indirect
|
||||
github.com/Microsoft/hcsshim v0.8.21 // indirect
|
||||
github.com/Masterminds/squirrel v1.5.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.5.2 // indirect
|
||||
github.com/Microsoft/hcsshim v0.9.6 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/RageCage64/multilinediff v0.2.0 // indirect
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704 // indirect
|
||||
github.com/aws/aws-sdk-go v1.41.7 // indirect
|
||||
github.com/armon/go-metrics v0.4.1 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect
|
||||
github.com/aws/aws-sdk-go v1.43.16 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bmatcuk/doublestar/v4 v4.6.0 // indirect
|
||||
github.com/braydonk/yaml v0.7.0 // indirect
|
||||
github.com/buger/goterm v1.0.4 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.1.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.1.2 // indirect
|
||||
github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect
|
||||
github.com/clbanning/mxj v1.8.4 // indirect
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20220520190051-1e77728a1eaa // indirect
|
||||
github.com/containerd/continuity v0.1.0 // indirect
|
||||
github.com/compose-spec/godotenv v1.1.1 // indirect
|
||||
github.com/containerd/cgroups v1.0.4 // indirect
|
||||
github.com/containerd/console v1.0.3 // indirect
|
||||
github.com/containerd/containerd v1.6.14 // indirect
|
||||
github.com/containerd/continuity v0.3.0 // indirect
|
||||
github.com/containerd/typeurl v1.0.2 // indirect
|
||||
github.com/coreos/go-oidc/v3 v3.1.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0 // indirect
|
||||
github.com/docker/cli v20.10.7+incompatible // indirect
|
||||
github.com/docker/distribution v2.7.1+incompatible // indirect
|
||||
github.com/docker/docker v20.10.7+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.6.3 // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/distribution/distribution/v3 v3.0.0-20221201083218-92d136e113cf // indirect
|
||||
github.com/docker/buildx v0.9.1 // indirect
|
||||
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.7.0 // indirect
|
||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-metrics v0.0.1 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0 // indirect
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
|
||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
|
||||
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/fvbommel/sortorder v1.0.1 // indirect
|
||||
github.com/fvbommel/sortorder v1.0.2 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-errors/errors v1.0.1 // indirect
|
||||
github.com/go-kit/log v0.1.0 // indirect
|
||||
github.com/go-logfmt/logfmt v0.5.0 // indirect
|
||||
github.com/go-logr/logr v0.4.0 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.5 // indirect
|
||||
github.com/go-openapi/swag v0.19.14 // indirect
|
||||
github.com/go-openapi/swag v0.19.15 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/goccy/go-json v0.4.8 // indirect
|
||||
github.com/gofrs/flock v0.8.0 // indirect
|
||||
github.com/gogo/googleapis v1.4.1 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
@@ -111,18 +147,35 @@ require (
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.1.1 // indirect
|
||||
github.com/googleapis/gnostic v0.5.5 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/gosuri/uitable v0.0.4 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-version v1.3.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-hclog v1.5.0 // indirect
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
||||
github.com/hashicorp/go-version v1.6.0 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/hashicorp/serf v0.10.1 // indirect
|
||||
github.com/huandu/xstrings v1.3.2 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/imdario/mergo v0.3.13 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||
github.com/jaguilar/vt100 v0.0.0-20150826170717-2703a27b14ea // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/jmoiron/sqlx v1.3.1 // indirect
|
||||
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/klauspost/compress v1.15.9 // indirect
|
||||
github.com/kr/pretty v0.3.0 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
|
||||
github.com/lestrrat-go/backoff/v2 v2.0.7 // indirect
|
||||
github.com/lestrrat-go/blackmagic v1.0.0 // indirect
|
||||
github.com/lestrrat-go/httpcc v1.0.0 // indirect
|
||||
@@ -131,66 +184,101 @@ require (
|
||||
github.com/lestrrat-go/option v1.0.0 // indirect
|
||||
github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f // indirect
|
||||
github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect
|
||||
github.com/lib/pq v1.10.0 // indirect
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.12 // indirect
|
||||
github.com/mattn/go-shellwords v1.0.12 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
|
||||
github.com/miekg/dns v1.1.43 // indirect
|
||||
github.com/miekg/pkcs11 v1.1.1 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/moby/buildkit v0.10.4 // indirect
|
||||
github.com/moby/locker v1.0.1 // indirect
|
||||
github.com/moby/spdystream v0.2.0 // indirect
|
||||
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 // indirect
|
||||
github.com/moby/sys/mount v0.3.0 // indirect
|
||||
github.com/moby/sys/mountinfo v0.6.0 // indirect
|
||||
github.com/moby/sys/signal v0.7.0 // indirect
|
||||
github.com/moby/sys/symlink v0.2.0 // indirect
|
||||
github.com/moby/term v0.0.0-20221128092401-c43b287e0e0f // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/natefinch/lumberjack v2.0.0+incompatible // indirect
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.1 // indirect
|
||||
github.com/opencontainers/runc v1.0.2 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0-rc2 // indirect
|
||||
github.com/opencontainers/runc v1.1.3 // indirect
|
||||
github.com/openshift/api v0.0.0-20200713203337-b2494ecb17dd // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_golang v1.12.2 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.32.1 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/prometheus/statsd_exporter v0.21.0 // indirect
|
||||
github.com/russross/blackfriday v1.5.2 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.6.1 // indirect
|
||||
github.com/rubenv/sql-migrate v0.0.0-20210614095031-55d5740dbbcc // indirect
|
||||
github.com/russross/blackfriday v1.6.0 // indirect
|
||||
github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/spf13/afero v1.2.2 // indirect
|
||||
github.com/spf13/cast v1.3.1 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/theupdateframework/notary v0.7.0 // indirect
|
||||
github.com/tonistiigi/fsutil v0.0.0-20220930225714-4638ad635be5 // indirect
|
||||
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
|
||||
github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect
|
||||
github.com/yl2chen/cidranger v1.0.2 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.7.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.12.0 // indirect
|
||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
|
||||
go.uber.org/multierr v1.7.0 // indirect
|
||||
go.uber.org/zap v1.21.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/crypto v0.11.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
|
||||
golang.org/x/net v0.12.0 // indirect
|
||||
golang.org/x/oauth2 v0.6.0 // indirect
|
||||
golang.org/x/sync v0.2.0 // indirect
|
||||
golang.org/x/sys v0.10.0 // indirect
|
||||
golang.org/x/term v0.10.0 // indirect
|
||||
golang.org/x/text v0.11.0 // indirect
|
||||
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
|
||||
gomodules.xyz/jsonpatch/v3 v3.0.1 // indirect
|
||||
gomodules.xyz/orderedmap v0.1.0 // indirect
|
||||
google.golang.org/api v0.59.0 // indirect
|
||||
google.golang.org/api v0.61.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20211020151524-b7c3a969101a // indirect
|
||||
google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 // indirect
|
||||
gopkg.in/gcfg.v1 v1.2.3 // indirect
|
||||
gopkg.in/gorp.v1 v1.7.2 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.66.2 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.22.2 // indirect
|
||||
k8s.io/component-base v0.22.2 // indirect
|
||||
k8s.io/klog/v2 v2.10.0 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20211020163157-7327e2aaee2b // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
k8s.io/apiserver v0.22.5 // indirect
|
||||
k8s.io/component-base v0.22.5 // indirect
|
||||
k8s.io/klog/v2 v2.60.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c // indirect
|
||||
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect
|
||||
oras.land/oras-go v0.4.0 // indirect
|
||||
sigs.k8s.io/gateway-api v0.4.0 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.8.11 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.11.0 // indirect
|
||||
@@ -209,3 +297,59 @@ replace istio.io/pkg => ./external/pkg
|
||||
replace istio.io/client-go => ./external/client-go
|
||||
|
||||
replace istio.io/istio => ./external/istio
|
||||
|
||||
require (
|
||||
github.com/evanphx/json-patch/v5 v5.6.0
|
||||
github.com/google/yamlfmt v0.10.0
|
||||
github.com/kylelemons/godebug v1.1.0
|
||||
helm.sh/helm/v3 v3.7.1
|
||||
k8s.io/apiextensions-apiserver v0.25.4
|
||||
knative.dev/networking v0.0.0-20220302134042-e8b2eb995165
|
||||
knative.dev/pkg v0.0.0-20220301181942-2fdd5f232e77
|
||||
)
|
||||
|
||||
replace (
|
||||
github.com/Sirupsen/logrus => github.com/sirupsen/logrus v1.9.3
|
||||
github.com/go-logr/logr => github.com/go-logr/logr v0.4.0
|
||||
|
||||
k8s.io/api => k8s.io/api v0.22.2
|
||||
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.22.2
|
||||
k8s.io/apimachinery => k8s.io/apimachinery v0.22.2
|
||||
k8s.io/cli-runtime => k8s.io/cli-runtime v0.22.2
|
||||
k8s.io/client-go => k8s.io/client-go v0.22.2
|
||||
k8s.io/code-generator => k8s.io/code-generator v0.22.2
|
||||
k8s.io/component-base => k8s.io/component-base v0.22.2
|
||||
k8s.io/component-helpers => k8s.io/component-helpers v0.22.2
|
||||
k8s.io/klog/v2 => k8s.io/klog/v2 v2.10.0
|
||||
k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e
|
||||
k8s.io/kubectl => k8s.io/kubectl v0.22.2
|
||||
k8s.io/metrics => k8s.io/metrics v0.22.2
|
||||
|
||||
k8s.io/utils => k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect
|
||||
sigs.k8s.io/kustomize/api => sigs.k8s.io/kustomize/api v0.8.11 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml => sigs.k8s.io/kustomize/kyaml v0.11.0 // indirect
|
||||
)
|
||||
|
||||
// for pkg/cmd/hgctl/docker/compose.go
|
||||
// TODO(WeixinX): Wait for the dependency library to upgrade, such as github.com/go-logr/logr from v0.4.0 to v1.2+
|
||||
// replace (
|
||||
// github.com/compose-spec/compose-go => github.com/compose-spec/compose-go v1.8.2
|
||||
// github.com/cucumber/godog => github.com/laurazard/godog v0.0.0-20220922095256-4c4b17abdae7
|
||||
// github.com/docker/buildx => github.com/docker/buildx v0.9.1
|
||||
// github.com/docker/cli => github.com/docker/cli v20.10.3-0.20221013132413-1d6c6e2367e2+incompatible
|
||||
// github.com/docker/compose/v2 => github.com/docker/compose/v2 v2.15.1
|
||||
// github.com/docker/docker => github.com/moby/moby v20.10.3-0.20221021173910-5aac513617f0+incompatible
|
||||
// github.com/moby/buildkit => github.com/moby/buildkit v0.10.1-0.20220816171719-55ba9d14360a
|
||||
// )
|
||||
|
||||
replace (
|
||||
github.com/compose-spec/compose-go => github.com/compose-spec/compose-go v1.0.8
|
||||
github.com/docker/buildx => github.com/docker/buildx v0.5.2-0.20210422185057-908a856079fc
|
||||
github.com/docker/cli => github.com/docker/cli v20.10.7+incompatible
|
||||
github.com/docker/compose/v2 => github.com/docker/compose/v2 v2.2.0
|
||||
github.com/docker/docker => github.com/docker/docker v20.10.3+incompatible
|
||||
github.com/jaguilar/vt100 => github.com/tonistiigi/vt100 v0.0.0-20190402012908-ad4c4a574305
|
||||
github.com/moby/buildkit => github.com/moby/buildkit v0.8.2-0.20210401015549-df49b648c8bf
|
||||
github.com/tonistiigi/fsutil => github.com/tonistiigi/fsutil v0.0.0-20201103201449-0834f99b7b85
|
||||
sigs.k8s.io/gateway-api => github.com/johnlanni/gateway-api v0.0.0-20231031082632-72137664e7c7
|
||||
)
|
||||
|
||||
1
helm/core/.helmignore
Normal file
1
helm/core/.helmignore
Normal file
@@ -0,0 +1 @@
|
||||
crds/customresourcedefinitions.gen_lt1.16.yaml
|
||||
@@ -1,7 +1,8 @@
|
||||
apiVersion: v2
|
||||
appVersion: 1.0.0-rc
|
||||
appVersion: 1.3.0
|
||||
description: Helm chart for deploying higress gateways
|
||||
icon: https://higress.io/img/higress_logo_small.png
|
||||
home: http://higress.io/
|
||||
keywords:
|
||||
- higress
|
||||
- gateways
|
||||
@@ -9,4 +10,4 @@ name: higress-core
|
||||
sources:
|
||||
- http://github.com/alibaba/higress
|
||||
type: application
|
||||
version: 1.0.0-rc
|
||||
version: 1.3.0
|
||||
|
||||
407
helm/core/LICENSE
Normal file
407
helm/core/LICENSE
Normal file
@@ -0,0 +1,407 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
|
||||
========================================================================
|
||||
Higress Subcomponents:
|
||||
|
||||
The Higress project contains subcomponents with separate copyright
|
||||
notices and license terms. Your use of the source code for the these
|
||||
subcomponents is subject to the terms and conditions of the following
|
||||
licenses.
|
||||
========================================================================
|
||||
Apache-2.0 licenses
|
||||
========================================================================
|
||||
|
||||
cloud.google.com/go v0.97.0 Apache-2.0
|
||||
cloud.google.com/go/logging v1.4.2 Apache-2.0
|
||||
contrib.go.opencensus.io/exporter/prometheus v0.4.0 Apache-2.0
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible Apache-2.0
|
||||
github.com/Azure/go-autorest/autorest v0.11.20 Apache-2.0
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.15 Apache-2.0
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 Apache-2.0
|
||||
github.com/Azure/go-autorest/logger v0.2.1 Apache-2.0
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 Apache-2.0
|
||||
github.com/Masterminds/goutils v1.1.1 Apache-2.0
|
||||
github.com/aws/aws-sdk-go v1.41.7 Apache-2.0
|
||||
github.com/census-instrumentation/opencensus-proto v0.3.0 Apache-2.0
|
||||
github.com/cncf/xds/go v0.0.0-20220520190051-1e77728a1eaa Apache-2.0
|
||||
github.com/containerd/continuity v0.1.0 Apache-2.0
|
||||
github.com/docker/cli v20.10.7+incompatible Apache-2.0
|
||||
github.com/docker/distribution v0.0.0-20191216044856-a8371794149d Apache-2.0
|
||||
github.com/docker/go-units v0.4.0 Apache-2.0
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0 Apache-2.0
|
||||
github.com/go-logr/logr v0.4.0 Apache-2.0
|
||||
github.com/go-openapi/jsonpointer v0.19.5 Apache-2.0
|
||||
github.com/go-openapi/jsonreference v0.19.5 Apache-2.0
|
||||
github.com/go-openapi/swag v0.19.14 Apache-2.0
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da Apache-2.0
|
||||
github.com/google/btree v1.0.1 Apache-2.0
|
||||
github.com/google/go-containerregistry v0.6.0 Apache-2.0
|
||||
github.com/google/gofuzz v1.2.0 Apache-2.0
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 Apache-2.0
|
||||
github.com/googleapis/gnostic v0.5.5 Apache-2.0
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 Apache-2.0
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 Apache-2.0
|
||||
github.com/inconshreveable/mousetrap v1.0.0 Apache-2.0
|
||||
github.com/jmespath/go-jmespath v0.4.0 Apache-2.0
|
||||
github.com/jonboulle/clockwork v0.2.2 Apache-2.0
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 Apache-2.0
|
||||
github.com/moby/moby v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible Apache-2.0
|
||||
github.com/moby/spdystream v0.2.0 Apache-2.0
|
||||
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 Apache-2.0
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd Apache-2.0
|
||||
github.com/modern-go/reflect2 v1.0.1 Apache-2.0
|
||||
github.com/opencontainers/go-digest v1.0.0 Apache-2.0
|
||||
github.com/opencontainers/image-spec v1.0.1 Apache-2.0
|
||||
github.com/opencontainers/runc v1.0.2 Apache-2.0
|
||||
github.com/openshift/api v0.0.0-20200713203337-b2494ecb17dd Apache-2.0
|
||||
github.com/prometheus/client_golang v1.11.0 Apache-2.0
|
||||
github.com/prometheus/client_model v0.2.0 Apache-2.0
|
||||
github.com/prometheus/common v0.32.1 Apache-2.0
|
||||
github.com/prometheus/procfs v0.6.0 Apache-2.0
|
||||
github.com/prometheus/statsd_exporter v0.21.0 Apache-2.0
|
||||
github.com/spf13/cobra v1.2.1 Apache-2.0
|
||||
go.opencensus.io v0.23.0 Apache-2.0
|
||||
go.opentelemetry.io/proto/otlp v0.7.0 Apache-2.0
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0 Apache-2.0
|
||||
gomodules.xyz/jsonpatch/v3 v3.0.1 Apache-2.0
|
||||
google.golang.org/appengine v1.6.7 Apache-2.0
|
||||
google.golang.org/genproto v0.0.0-20211020151524-b7c3a969101a Apache-2.0
|
||||
google.golang.org/grpc v1.42.0 Apache-2.0
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 Apache-2.0
|
||||
gopkg.in/yaml.v2 v2.4.0 Apache-2.0
|
||||
istio.io/gogo-genproto v0.0.0-20211115195057-0e34bdd2be67 Apache-2.0
|
||||
k8s.io/api v0.22.2 Apache-2.0
|
||||
k8s.io/apiextensions-apiserver v0.22.2 Apache-2.0
|
||||
k8s.io/apimachinery v0.22.2 Apache-2.0
|
||||
k8s.io/cli-runtime v0.22.2 Apache-2.0
|
||||
k8s.io/client-go v0.22.2 Apache-2.0
|
||||
k8s.io/component-base v0.22.2 Apache-2.0
|
||||
k8s.io/klog/v2 v2.10.0 Apache-2.0
|
||||
k8s.io/kube-openapi v0.0.0-20211020163157-7327e2aaee2b Apache-2.0
|
||||
k8s.io/kubectl v0.22.2 Apache-2.0
|
||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b Apache-2.0
|
||||
sigs.k8s.io/controller-runtime v0.10.2 Apache-2.0
|
||||
sigs.k8s.io/gateway-api v0.4.0 Apache-2.0
|
||||
sigs.k8s.io/kustomize/api v0.8.11 Apache-2.0
|
||||
sigs.k8s.io/kustomize/kyaml v0.11.0 Apache-2.0
|
||||
sigs.k8s.io/mcs-api v0.1.0 Apache-2.0
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 Apache-2.0
|
||||
|
||||
========================================================================
|
||||
BSD-2-Clause licenses
|
||||
========================================================================
|
||||
|
||||
github.com/pkg/errors v0.9.1 BSD-2-Clause
|
||||
github.com/russross/blackfriday v1.5.2 BSD-2-Clause
|
||||
|
||||
========================================================================
|
||||
BSD-3-Clause licenses
|
||||
========================================================================
|
||||
|
||||
github.com/PuerkitoBio/purell v1.1.1 BSD-3-Clause
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 BSD-3-Clause
|
||||
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 BSD-3-Clause
|
||||
github.com/evanphx/json-patch v4.11.0+incompatible BSD-3-Clause
|
||||
github.com/evanphx/json-patch/v5 v5.6.0 BSD-3-Clause
|
||||
github.com/fsnotify/fsnotify v1.5.1 BSD-3-Clause
|
||||
github.com/gogo/protobuf v1.3.2 BSD-3-Clause
|
||||
github.com/golang/protobuf v1.5.2 BSD-3-Clause
|
||||
github.com/google/go-cmp v0.5.6 BSD-3-Clause
|
||||
github.com/google/uuid v1.3.0 BSD-3-Clause
|
||||
github.com/googleapis/gax-go/v2 v2.1.1 BSD-3-Clause
|
||||
github.com/imdario/mergo v0.3.5 BSD-3-Clause
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de BSD-3-Clause
|
||||
github.com/pmezard/go-difflib v1.0.0 BSD-3-Clause
|
||||
github.com/spaolacci/murmur3 v1.1.0 BSD-3-Clause
|
||||
github.com/spf13/pflag v1.0.5 BSD-3-Clause
|
||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 BSD-3-Clause
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 BSD-3-Clause
|
||||
golang.org/x/net v0.0.0-20211020060615-d418f374d309 BSD-3-Clause
|
||||
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1 BSD-3-Clause
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c BSD-3-Clause
|
||||
golang.org/x/sys v0.0.0-20211020174200-9d6173849985 BSD-3-Clause
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d BSD-3-Clause
|
||||
golang.org/x/text v0.3.6 BSD-3-Clause
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac BSD-3-Clause
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 BSD-3-Clause
|
||||
google.golang.org/api v0.59.0 BSD-3-Clause
|
||||
google.golang.org/protobuf v1.27.1 BSD-3-Clause
|
||||
gopkg.in/inf.v0 v0.9.1 BSD-3-Clause
|
||||
|
||||
========================================================================
|
||||
ISC licenses
|
||||
========================================================================
|
||||
|
||||
github.com/davecgh/go-spew v1.1.1 ISC
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0 ISC
|
||||
|
||||
========================================================================
|
||||
MIT licenses
|
||||
========================================================================
|
||||
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 MIT
|
||||
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd MIT
|
||||
github.com/Masterminds/semver/v3 v3.1.1 MIT
|
||||
github.com/Masterminds/sprig/v3 v3.2.2 MIT
|
||||
github.com/Microsoft/go-winio v0.5.0 MIT
|
||||
github.com/Microsoft/hcsshim v0.8.21 MIT
|
||||
github.com/beorn7/perks v1.0.1 MIT
|
||||
github.com/cenkalti/backoff/v4 v4.1.1 MIT
|
||||
github.com/cespare/xxhash/v2 v2.1.1 MIT
|
||||
github.com/docker/docker-credential-helpers v0.6.3 MIT
|
||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d MIT
|
||||
github.com/fvbommel/sortorder v1.0.1 MIT
|
||||
github.com/go-errors/errors v1.0.1 MIT
|
||||
github.com/go-kit/log v0.1.0 MIT
|
||||
github.com/go-logfmt/logfmt v0.5.0 MIT
|
||||
github.com/goccy/go-json v0.4.8 MIT
|
||||
github.com/golang-jwt/jwt/v4 v4.0.0 MIT
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 MIT
|
||||
github.com/huandu/xstrings v1.3.2 MIT
|
||||
github.com/josharian/intern v1.0.0 MIT
|
||||
github.com/json-iterator/go v1.1.11 MIT
|
||||
github.com/lestrrat-go/backoff/v2 v2.0.7 MIT
|
||||
github.com/lestrrat-go/blackmagic v1.0.0 MIT
|
||||
github.com/lestrrat-go/httpcc v1.0.0 MIT
|
||||
github.com/lestrrat-go/iter v1.0.1 MIT
|
||||
github.com/lestrrat-go/jwx v1.2.0 MIT
|
||||
github.com/lestrrat-go/option v1.0.0 MIT
|
||||
github.com/mailru/easyjson v0.7.6 MIT
|
||||
github.com/mitchellh/copystructure v1.2.0 MIT
|
||||
github.com/mitchellh/go-wordwrap v1.0.0 MIT
|
||||
github.com/mitchellh/reflectwalk v1.0.2 MIT
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 MIT
|
||||
github.com/natefinch/lumberjack v2.0.0+incompatible MIT
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible MIT
|
||||
github.com/shopspring/decimal v1.2.0 MIT
|
||||
github.com/sirupsen/logrus v1.8.1 MIT
|
||||
github.com/spf13/cast v1.3.1 MIT
|
||||
github.com/stretchr/testify v1.7.0 MIT
|
||||
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca MIT
|
||||
github.com/yl2chen/cidranger v1.0.2 MIT
|
||||
go.uber.org/atomic v1.9.0 MIT
|
||||
go.uber.org/multierr v1.7.0 MIT
|
||||
go.uber.org/zap v1.19.1 MIT
|
||||
gomodules.xyz/orderedmap v0.1.0 MIT
|
||||
|
||||
========================================================================
|
||||
MIT and Apache-2.0 licenses
|
||||
========================================================================
|
||||
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b MIT and Apache-2.0
|
||||
|
||||
========================================================================
|
||||
MIT and BSD-3-Clause licenses
|
||||
========================================================================
|
||||
|
||||
github.com/ghodss/yaml v1.0.0 MIT and BSD-3-Clause
|
||||
sigs.k8s.io/yaml v1.3.0 MIT and BSD-3-Clause
|
||||
|
||||
========================================================================
|
||||
MPL-2.0 licenses
|
||||
========================================================================
|
||||
|
||||
github.com/hashicorp/errwrap v1.0.0 MPL-2.0
|
||||
github.com/hashicorp/go-multierror v1.1.1 MPL-2.0
|
||||
github.com/hashicorp/go-version v1.3.0 MPL-2.0
|
||||
github.com/hashicorp/golang-lru v0.5.4 MPL-2.0
|
||||
5
helm/core/README.md
Normal file
5
helm/core/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Higress Core Helm Chart
|
||||
|
||||
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.
|
||||
@@ -104,6 +104,88 @@ spec:
|
||||
subresources:
|
||||
status: {}
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
"helm.sh/resource-policy": keep
|
||||
name: http2rpcs.networking.higress.io
|
||||
spec:
|
||||
group: networking.higress.io
|
||||
names:
|
||||
categories:
|
||||
- higress-io
|
||||
kind: Http2Rpc
|
||||
listKind: Http2RpcList
|
||||
plural: http2rpcs
|
||||
singular: http2rpc
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
properties:
|
||||
spec:
|
||||
oneOf:
|
||||
- not:
|
||||
anyOf:
|
||||
- required:
|
||||
- dubbo
|
||||
- required:
|
||||
- grpc
|
||||
- required:
|
||||
- dubbo
|
||||
- required:
|
||||
- grpc
|
||||
properties:
|
||||
dubbo:
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
methods:
|
||||
items:
|
||||
properties:
|
||||
headersAttach:
|
||||
type: string
|
||||
httpMethods:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
httpPath:
|
||||
type: string
|
||||
params:
|
||||
items:
|
||||
properties:
|
||||
paramKey:
|
||||
type: string
|
||||
paramSource:
|
||||
type: string
|
||||
paramType:
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
serviceMethod:
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
service:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
type: object
|
||||
grpc:
|
||||
type: object
|
||||
type: object
|
||||
status:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
@@ -131,8 +213,17 @@ spec:
|
||||
registries:
|
||||
items:
|
||||
properties:
|
||||
authSecretName:
|
||||
type: string
|
||||
consulDatacenter:
|
||||
type: string
|
||||
consulNamespace:
|
||||
type: string
|
||||
consulRefreshInterval:
|
||||
format: int64
|
||||
type: integer
|
||||
consulServiceTag:
|
||||
type: string
|
||||
domain:
|
||||
type: string
|
||||
nacosAccessKey:
|
||||
|
||||
176
helm/core/crds/customresourcedefinitions.gen_lt1.16.yaml
Normal file
176
helm/core/crds/customresourcedefinitions.gen_lt1.16.yaml
Normal file
@@ -0,0 +1,176 @@
|
||||
# DO NOT EDIT - Generated by Cue OpenAPI generator based on Istio APIs.
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
"helm.sh/resource-policy": keep
|
||||
name: wasmplugins.extensions.higress.io
|
||||
spec:
|
||||
group: extensions.higress.io
|
||||
names:
|
||||
categories:
|
||||
- higress-io
|
||||
- extensions-higress-io
|
||||
kind: WasmPlugin
|
||||
listKind: WasmPluginList
|
||||
plural: wasmplugins
|
||||
singular: wasmplugin
|
||||
scope: Namespaced
|
||||
additionalPrinterColumns:
|
||||
- description: 'CreationTimestamp is a timestamp representing the server time
|
||||
when this object was created. It is not guaranteed to be set in happens-before
|
||||
order across separate operations. Clients may not set this value. It is represented
|
||||
in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
|
||||
lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
|
||||
JSONPath: .metadata.creationTimestamp
|
||||
name: Age
|
||||
type: date
|
||||
versions:
|
||||
- name: v1alpha1
|
||||
served: true
|
||||
storage: true
|
||||
version: v1alpha1
|
||||
validation:
|
||||
openAPIV3Schema:
|
||||
properties:
|
||||
spec:
|
||||
properties:
|
||||
defaultConfig:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
defaultConfigDisable:
|
||||
type: boolean
|
||||
imagePullPolicy:
|
||||
description: The pull behaviour to be applied when fetching an OCI
|
||||
image.
|
||||
enum:
|
||||
- UNSPECIFIED_POLICY
|
||||
- IfNotPresent
|
||||
- Always
|
||||
type: string
|
||||
imagePullSecret:
|
||||
description: Credentials to use for OCI image pulling.
|
||||
type: string
|
||||
matchRules:
|
||||
items:
|
||||
properties:
|
||||
config:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
configDisable:
|
||||
type: boolean
|
||||
domain:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
ingress:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
type: array
|
||||
phase:
|
||||
description: Determines where in the filter chain this `WasmPlugin`
|
||||
is to be injected.
|
||||
enum:
|
||||
- UNSPECIFIED_PHASE
|
||||
- AUTHN
|
||||
- AUTHZ
|
||||
- STATS
|
||||
type: string
|
||||
pluginConfig:
|
||||
description: The configuration that will be passed on to the plugin.
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
pluginName:
|
||||
type: string
|
||||
priority:
|
||||
description: Determines ordering of `WasmPlugins` in the same `phase`.
|
||||
nullable: true
|
||||
type: integer
|
||||
sha256:
|
||||
description: SHA256 checksum that will be used to verify Wasm module
|
||||
or OCI container.
|
||||
type: string
|
||||
url:
|
||||
description: URL of a Wasm module or OCI container.
|
||||
type: string
|
||||
verificationKey:
|
||||
type: string
|
||||
type: object
|
||||
status:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
subresources:
|
||||
status: {}
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
"helm.sh/resource-policy": keep
|
||||
name: mcpbridges.networking.higress.io
|
||||
spec:
|
||||
group: networking.higress.io
|
||||
names:
|
||||
categories:
|
||||
- higress-io
|
||||
kind: McpBridge
|
||||
listKind: McpBridgeList
|
||||
plural: mcpbridges
|
||||
singular: mcpbridge
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1
|
||||
served: true
|
||||
storage: true
|
||||
version: v1
|
||||
validation:
|
||||
openAPIV3Schema:
|
||||
properties:
|
||||
spec:
|
||||
properties:
|
||||
registries:
|
||||
items:
|
||||
properties:
|
||||
consulNamespace:
|
||||
type: string
|
||||
domain:
|
||||
type: string
|
||||
nacosAccessKey:
|
||||
type: string
|
||||
nacosAddressServer:
|
||||
type: string
|
||||
nacosGroups:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
nacosNamespace:
|
||||
type: string
|
||||
nacosNamespaceId:
|
||||
type: string
|
||||
nacosRefreshInterval:
|
||||
format: int64
|
||||
type: integer
|
||||
nacosSecretKey:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
port:
|
||||
type: integer
|
||||
type:
|
||||
type: string
|
||||
zkServicesPath:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
subresources:
|
||||
status: {}
|
||||
---
|
||||
@@ -95,3 +95,9 @@ higress: {{ include "controller.name" . }}
|
||||
{{- print "first-party-jwt" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "skywalking.enabled" -}}
|
||||
{{- if and .Values.skywalking.enabled .Values.skywalking.service.address }}
|
||||
true
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
configSources:
|
||||
- address: "xds://127.0.0.1:15051"
|
||||
{{- if .Values.global.enableIstioAPI }}
|
||||
{{- if or .Values.global.enableIstioAPI .Values.global.enableGatewayAPI }}
|
||||
- address: "k8s://"
|
||||
{{- end }}
|
||||
|
||||
@@ -122,7 +122,7 @@ data:
|
||||
{{- include "mesh" . }}
|
||||
{{- end }}
|
||||
---
|
||||
{{- if .Values.enableSkywalking }}
|
||||
{{- if include "skywalking.enabled" . }}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
@@ -154,7 +154,6 @@ data:
|
||||
"type": "LOGICAL_DNS",
|
||||
"connect_timeout": "5s",
|
||||
"http2_protocol_options": {
|
||||
|
||||
},
|
||||
"dns_lookup_family": "V4_ONLY",
|
||||
"lb_policy": "ROUND_ROBIN",
|
||||
@@ -167,8 +166,8 @@ data:
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socket_address": {
|
||||
"address": "{{ .Values.Skywalking.address }}",
|
||||
"port_value": "{{ .Values.Skywalking.port }}"
|
||||
"address": "{{ .Values.skywalking.service.address }}",
|
||||
"port_value": "{{ .Values.skywalking.service.port }}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,10 @@ rules:
|
||||
resources: ["wasmplugins"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
|
||||
- apiGroups: ["networking.higress.io"]
|
||||
resources: ["http2rpcs"]
|
||||
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||
|
||||
- apiGroups: [""]
|
||||
resources: ["services"]
|
||||
verbs: ["get", "watch", "list", "update", "patch", "create", "delete"]
|
||||
@@ -113,3 +117,10 @@ rules:
|
||||
- apiGroups: ["config.istio.io", "security.istio.io", "networking.istio.io", "authentication.istio.io", "rbac.istio.io", "telemetry.istio.io", "extensions.istio.io"]
|
||||
verbs: ["get", "watch", "list"]
|
||||
resources: ["*"]
|
||||
# knative KIngress configuration
|
||||
- apiGroups: ["networking.internal.knative.dev"]
|
||||
verbs: ["get","list","watch"]
|
||||
resources: ["ingresses"]
|
||||
- apiGroups: ["networking.internal.knative.dev"]
|
||||
resources: ["ingresses/status"]
|
||||
verbs: ["get","patch","update"]
|
||||
@@ -2,6 +2,7 @@ apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "controller.name" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "controller.labels" . | nindent 4 }}
|
||||
spec:
|
||||
@@ -33,7 +34,7 @@ spec:
|
||||
{{- if contains "/" .Values.pilot.image }}
|
||||
image: "{{ .Values.pilot.image }}"
|
||||
{{- else }}
|
||||
image: "{{ .Values.pilot.hub | default .Values.global.hub }}/{{ .Values.pilot.image | default "pilot" }}:{{ .Values.pilot.tag | default .Values.global.tag }}"
|
||||
image: "{{ .Values.pilot.hub | default .Values.global.hub }}/{{ .Values.pilot.image | default "pilot" }}:{{ .Values.pilot.tag | default .Chart.AppVersion }}"
|
||||
{{- end }}
|
||||
{{- if .Values.global.imagePullPolicy }}
|
||||
imagePullPolicy: {{ .Values.global.imagePullPolicy }}
|
||||
@@ -73,6 +74,8 @@ spec:
|
||||
periodSeconds: 3
|
||||
timeoutSeconds: 5
|
||||
env:
|
||||
- name: PILOT_FILTER_GATEWAY_CLUSTER_CONFIG
|
||||
value: "true"
|
||||
- name: HIGRESS_CONTROLLER_SVC
|
||||
value: "127.0.0.1"
|
||||
- name: HIGRESS_CONTROLLER_PORT
|
||||
@@ -100,6 +103,10 @@ spec:
|
||||
fieldPath: spec.serviceAccountName
|
||||
- name: KUBECONFIG
|
||||
value: /var/run/secrets/remote/config
|
||||
- name: PRIORITIZED_LEADER_ELECTION
|
||||
value: "false"
|
||||
- name: INJECT_ENABLED
|
||||
value: "false"
|
||||
{{- if .Values.pilot.env }}
|
||||
{{- range $key, $val := .Values.pilot.env }}
|
||||
- name: {{ $key }}
|
||||
@@ -120,10 +127,19 @@ spec:
|
||||
value: "{{ .Values.global.istiod.enableAnalysis }}"
|
||||
- name: CLUSTER_ID
|
||||
value: "{{ $.Values.global.multiCluster.clusterName | default `Kubernetes` }}"
|
||||
# HIGRESS_ENABLE_ISTIO_API is only used to restart the controller pod after the config change
|
||||
{{- if .Values.global.enableIstioAPI }}
|
||||
- name: HIGRESS_ENABLE_ISTIO_API
|
||||
value: "true"
|
||||
{{- end }}
|
||||
{{- if .Values.global.enableGatewayAPI }}
|
||||
- name: PILOT_ENABLE_GATEWAY_API
|
||||
value: "true"
|
||||
- name: PILOT_ENABLE_GATEWAY_API_STATUS
|
||||
value: "true"
|
||||
- name: PILOT_ENABLE_GATEWAY_API_DEPLOYMENT_CONTROLLER
|
||||
value: "false"
|
||||
{{- end }}
|
||||
{{- if not .Values.global.enableHigressIstio }}
|
||||
- name: CUSTOM_CA_CERT_NAME
|
||||
value: "higress-ca-root-cert"
|
||||
@@ -196,6 +212,8 @@ spec:
|
||||
fieldRef:
|
||||
apiVersion: v1
|
||||
fieldPath: spec.serviceAccountName
|
||||
- name: DOMAIN_SUFFIX
|
||||
value: {{ .Values.global.proxy.clusterDomain }}
|
||||
{{- if .Values.controller.env }}
|
||||
{{- range $key, $val := .Values.controller.env }}
|
||||
- name: {{ $key }}
|
||||
|
||||
@@ -2,6 +2,7 @@ apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "controller.name" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "controller.labels" . | nindent 4 }}
|
||||
spec:
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
{{- $unprivilegedPortSupported := true }}
|
||||
{{- range $index, $node := (lookup "v1" "Node" "default" "").items }}
|
||||
{{- $kernelVersion := $node.status.nodeInfo.kernelVersion }}
|
||||
{{- if $kernelVersion }}
|
||||
{{- $kernelVersion = regexFind "^(\\d+\\.\\d+\\.\\d+)" $kernelVersion }}
|
||||
{{- if and $kernelVersion (semverCompare "<4.11.0" $kernelVersion) }}
|
||||
{{- $unprivilegedPortSupported = false }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@@ -50,7 +60,7 @@ spec:
|
||||
securityContext:
|
||||
{{- if .Values.gateway.securityContext }}
|
||||
{{- toYaml .Values.gateway.securityContext | nindent 8 }}
|
||||
{{- else if and (not .Values.gateway.hostNetwork) (semverCompare ">=1.22-0" .Capabilities.KubeVersion.GitVersion) }}
|
||||
{{- else if and $unprivilegedPortSupported (and (not .Values.gateway.hostNetwork) (semverCompare ">=1.22-0" .Capabilities.KubeVersion.GitVersion)) }}
|
||||
# Safe since 1.22: https://github.com/kubernetes/kubernetes/pull/103326
|
||||
sysctls:
|
||||
- name: net.ipv4.ip_unprivileged_port_start
|
||||
@@ -71,7 +81,7 @@ spec:
|
||||
securityContext:
|
||||
{{- if .Values.gateway.containerSecurityContext }}
|
||||
{{- toYaml .Values.gateway.containerSecurityContext | nindent 12 }}
|
||||
{{- else if and (not .Values.gateway.hostNetwork) (semverCompare ">=1.22-0" .Capabilities.KubeVersion.GitVersion) }}
|
||||
{{- else if and $unprivilegedPortSupported (and (not .Values.gateway.hostNetwork) (semverCompare ">=1.22-0" .Capabilities.KubeVersion.GitVersion)) }}
|
||||
# Safe since 1.22: https://github.com/kubernetes/kubernetes/pull/103326
|
||||
capabilities:
|
||||
drop:
|
||||
@@ -136,7 +146,7 @@ spec:
|
||||
value: "{{ $.Values.clusterName | default `Kubernetes` }}"
|
||||
- name: INSTANCE_NAME
|
||||
value: "higress-gateway"
|
||||
{{- if .Values.enableSkywalking }}
|
||||
{{- if include "skywalking.enabled" . }}
|
||||
- name: ISTIO_BOOTSTRAP_OVERRIDE
|
||||
value: /etc/istio/custom-bootstrap/custom_bootstrap.json
|
||||
{{- end }}
|
||||
@@ -192,10 +202,14 @@ spec:
|
||||
mountPath: /etc/istio/pod
|
||||
- name: proxy-socket
|
||||
mountPath: /etc/istio/proxy
|
||||
{{- if .Values.enableSkywalking }}
|
||||
{{- if include "skywalking.enabled" . }}
|
||||
- mountPath: /etc/istio/custom-bootstrap
|
||||
name: custom-bootstrap-volume
|
||||
{{- end }}
|
||||
{{- if .Values.global.volumeWasmPlugins }}
|
||||
- mountPath: /opt/plugins
|
||||
name: local-wasmplugins-volume
|
||||
{{- end }}
|
||||
{{- if .Values.gateway.hostNetwork }}
|
||||
hostNetwork: {{ .Values.gateway.hostNetwork }}
|
||||
dnsPolicy: ClusterFirstWithHostNet
|
||||
@@ -232,7 +246,7 @@ spec:
|
||||
- name: config
|
||||
configMap:
|
||||
name: higress-config
|
||||
{{- if .Values.enableSkywalking }}
|
||||
{{- if include "skywalking.enabled" . }}
|
||||
- configMap:
|
||||
defaultMode: 420
|
||||
name: higress-custom-bootstrap
|
||||
@@ -264,3 +278,9 @@ spec:
|
||||
containerName: higress-gateway
|
||||
divisor: 1m
|
||||
resource: limits.cpu
|
||||
{{- if .Values.global.volumeWasmPlugins }}
|
||||
- name: local-wasmplugins-volume
|
||||
hostPath:
|
||||
path: /opt/plugins
|
||||
type: Directory
|
||||
{{- end }}
|
||||
|
||||
@@ -17,6 +17,7 @@ global:
|
||||
local: false # When deploying to a local cluster (e.g.: kind cluster), set this to true.
|
||||
kind: false # Deprecated. Please use "global.local" instead. Will be removed later.
|
||||
enableIstioAPI: false
|
||||
enableGatewayAPI: false
|
||||
# Deprecated
|
||||
enableHigressIstio: false
|
||||
# Used to locate istiod.
|
||||
@@ -44,8 +45,6 @@ global:
|
||||
# Releases are published to docker hub under 'istio' project.
|
||||
# Dev builds from prow are on gcr.io
|
||||
hub: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress
|
||||
# Default tag for Istio images.
|
||||
tag: 1.0.0-rc
|
||||
|
||||
# Specify image pull policy if default behavior isn't desired.
|
||||
# Default behavior: latest images will be Always else IfNotPresent.
|
||||
@@ -369,7 +368,7 @@ gateway:
|
||||
name: "higress-gateway"
|
||||
replicas: 2
|
||||
image: gateway
|
||||
tag: "1.0.0-rc"
|
||||
tag: ""
|
||||
# revision declares which revision this gateway is a part of
|
||||
revision: ""
|
||||
|
||||
@@ -457,7 +456,7 @@ controller:
|
||||
name: "higress-controller"
|
||||
replicas: 1
|
||||
image: higress
|
||||
tag: "1.0.0-rc"
|
||||
tag: ""
|
||||
env: {}
|
||||
|
||||
labels: {}
|
||||
@@ -547,7 +546,7 @@ pilot:
|
||||
rollingMaxUnavailable: 25%
|
||||
|
||||
hub: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress
|
||||
tag: 1.0.0-rc
|
||||
tag: ""
|
||||
|
||||
# Can be a full hub/image:tag
|
||||
image: pilot
|
||||
@@ -560,7 +559,7 @@ pilot:
|
||||
memory: 2048Mi
|
||||
|
||||
env:
|
||||
PILOT_SCOPE_GATEWAY_TO_NAMESPACE: "true"
|
||||
PILOT_SCOPE_GATEWAY_TO_NAMESPACE: "false"
|
||||
PILOT_ENABLE_METADATA_EXCHANGE: "false"
|
||||
PILOT_ENABLE_CROSS_CLUSTER_WORKLOAD_ENTRY: "false"
|
||||
VALIDATION_ENABLED: "false"
|
||||
@@ -583,7 +582,7 @@ pilot:
|
||||
jwksResolverExtraRootCA: ""
|
||||
|
||||
# This is used to set the source of configuration for
|
||||
# the associated address in configSource, if nothing is specificed
|
||||
# the associated address in configSource, if nothing is specified
|
||||
# the default MCP is assumed.
|
||||
configSource:
|
||||
subscribedResources: []
|
||||
@@ -610,7 +609,8 @@ pilot:
|
||||
|
||||
|
||||
# Skywalking config settings
|
||||
enableSkywalking: false
|
||||
Skywalking:
|
||||
address: "skywalking-oap.higress-system.svc"
|
||||
port: 11800
|
||||
skywalking:
|
||||
enabled: false
|
||||
service:
|
||||
address: ~
|
||||
port: 11800
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
dependencies:
|
||||
- name: higress-core
|
||||
repository: file://../core
|
||||
version: 1.0.0-rc
|
||||
version: 1.3.0
|
||||
- name: higress-console
|
||||
repository: https://higress.io/helm-charts/
|
||||
version: 0.2.0
|
||||
digest: sha256:0a34765ab2125ccf397e81566b4d81a8dc0742a2477d225aad77d9450e4add94
|
||||
generated: "2023-04-08T23:17:37.193119+08:00"
|
||||
version: 1.3.0
|
||||
digest: sha256:3efc59ad8cd92ab4c3c87abeed8e2fc0288bb3ecc2805888ba6eaaf265ba6a10
|
||||
generated: "2023-11-02T11:45:56.011629+08:00"
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
apiVersion: v2
|
||||
appVersion: 1.0.0-rc
|
||||
description: Helm chart for deploying higress gateways
|
||||
appVersion: 1.3.0
|
||||
description: Helm chart for deploying Higress gateways
|
||||
icon: https://higress.io/img/higress_logo_small.png
|
||||
home: http://higress.io/
|
||||
keywords:
|
||||
- higress
|
||||
- gateways
|
||||
@@ -11,9 +12,9 @@ sources:
|
||||
dependencies:
|
||||
- name: higress-core
|
||||
repository: "file://../core"
|
||||
version: 1.0.0-rc
|
||||
version: 1.3.0
|
||||
- name: higress-console
|
||||
repository: "https://higress.io/helm-charts/"
|
||||
version: 0.2.0
|
||||
version: 1.3.0
|
||||
type: application
|
||||
version: 1.0.0-rc
|
||||
version: 1.3.0
|
||||
|
||||
407
helm/higress/LICENSE
Normal file
407
helm/higress/LICENSE
Normal file
@@ -0,0 +1,407 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
|
||||
========================================================================
|
||||
Higress Subcomponents:
|
||||
|
||||
The Higress project contains subcomponents with separate copyright
|
||||
notices and license terms. Your use of the source code for the these
|
||||
subcomponents is subject to the terms and conditions of the following
|
||||
licenses.
|
||||
========================================================================
|
||||
Apache-2.0 licenses
|
||||
========================================================================
|
||||
|
||||
cloud.google.com/go v0.97.0 Apache-2.0
|
||||
cloud.google.com/go/logging v1.4.2 Apache-2.0
|
||||
contrib.go.opencensus.io/exporter/prometheus v0.4.0 Apache-2.0
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible Apache-2.0
|
||||
github.com/Azure/go-autorest/autorest v0.11.20 Apache-2.0
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.15 Apache-2.0
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 Apache-2.0
|
||||
github.com/Azure/go-autorest/logger v0.2.1 Apache-2.0
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 Apache-2.0
|
||||
github.com/Masterminds/goutils v1.1.1 Apache-2.0
|
||||
github.com/aws/aws-sdk-go v1.41.7 Apache-2.0
|
||||
github.com/census-instrumentation/opencensus-proto v0.3.0 Apache-2.0
|
||||
github.com/cncf/xds/go v0.0.0-20220520190051-1e77728a1eaa Apache-2.0
|
||||
github.com/containerd/continuity v0.1.0 Apache-2.0
|
||||
github.com/docker/cli v20.10.7+incompatible Apache-2.0
|
||||
github.com/docker/distribution v0.0.0-20191216044856-a8371794149d Apache-2.0
|
||||
github.com/docker/go-units v0.4.0 Apache-2.0
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0 Apache-2.0
|
||||
github.com/go-logr/logr v0.4.0 Apache-2.0
|
||||
github.com/go-openapi/jsonpointer v0.19.5 Apache-2.0
|
||||
github.com/go-openapi/jsonreference v0.19.5 Apache-2.0
|
||||
github.com/go-openapi/swag v0.19.14 Apache-2.0
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da Apache-2.0
|
||||
github.com/google/btree v1.0.1 Apache-2.0
|
||||
github.com/google/go-containerregistry v0.6.0 Apache-2.0
|
||||
github.com/google/gofuzz v1.2.0 Apache-2.0
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 Apache-2.0
|
||||
github.com/googleapis/gnostic v0.5.5 Apache-2.0
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 Apache-2.0
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 Apache-2.0
|
||||
github.com/inconshreveable/mousetrap v1.0.0 Apache-2.0
|
||||
github.com/jmespath/go-jmespath v0.4.0 Apache-2.0
|
||||
github.com/jonboulle/clockwork v0.2.2 Apache-2.0
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 Apache-2.0
|
||||
github.com/moby/moby v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible Apache-2.0
|
||||
github.com/moby/spdystream v0.2.0 Apache-2.0
|
||||
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 Apache-2.0
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd Apache-2.0
|
||||
github.com/modern-go/reflect2 v1.0.1 Apache-2.0
|
||||
github.com/opencontainers/go-digest v1.0.0 Apache-2.0
|
||||
github.com/opencontainers/image-spec v1.0.1 Apache-2.0
|
||||
github.com/opencontainers/runc v1.0.2 Apache-2.0
|
||||
github.com/openshift/api v0.0.0-20200713203337-b2494ecb17dd Apache-2.0
|
||||
github.com/prometheus/client_golang v1.11.0 Apache-2.0
|
||||
github.com/prometheus/client_model v0.2.0 Apache-2.0
|
||||
github.com/prometheus/common v0.32.1 Apache-2.0
|
||||
github.com/prometheus/procfs v0.6.0 Apache-2.0
|
||||
github.com/prometheus/statsd_exporter v0.21.0 Apache-2.0
|
||||
github.com/spf13/cobra v1.2.1 Apache-2.0
|
||||
go.opencensus.io v0.23.0 Apache-2.0
|
||||
go.opentelemetry.io/proto/otlp v0.7.0 Apache-2.0
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0 Apache-2.0
|
||||
gomodules.xyz/jsonpatch/v3 v3.0.1 Apache-2.0
|
||||
google.golang.org/appengine v1.6.7 Apache-2.0
|
||||
google.golang.org/genproto v0.0.0-20211020151524-b7c3a969101a Apache-2.0
|
||||
google.golang.org/grpc v1.42.0 Apache-2.0
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 Apache-2.0
|
||||
gopkg.in/yaml.v2 v2.4.0 Apache-2.0
|
||||
istio.io/gogo-genproto v0.0.0-20211115195057-0e34bdd2be67 Apache-2.0
|
||||
k8s.io/api v0.22.2 Apache-2.0
|
||||
k8s.io/apiextensions-apiserver v0.22.2 Apache-2.0
|
||||
k8s.io/apimachinery v0.22.2 Apache-2.0
|
||||
k8s.io/cli-runtime v0.22.2 Apache-2.0
|
||||
k8s.io/client-go v0.22.2 Apache-2.0
|
||||
k8s.io/component-base v0.22.2 Apache-2.0
|
||||
k8s.io/klog/v2 v2.10.0 Apache-2.0
|
||||
k8s.io/kube-openapi v0.0.0-20211020163157-7327e2aaee2b Apache-2.0
|
||||
k8s.io/kubectl v0.22.2 Apache-2.0
|
||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b Apache-2.0
|
||||
sigs.k8s.io/controller-runtime v0.10.2 Apache-2.0
|
||||
sigs.k8s.io/gateway-api v0.4.0 Apache-2.0
|
||||
sigs.k8s.io/kustomize/api v0.8.11 Apache-2.0
|
||||
sigs.k8s.io/kustomize/kyaml v0.11.0 Apache-2.0
|
||||
sigs.k8s.io/mcs-api v0.1.0 Apache-2.0
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 Apache-2.0
|
||||
|
||||
========================================================================
|
||||
BSD-2-Clause licenses
|
||||
========================================================================
|
||||
|
||||
github.com/pkg/errors v0.9.1 BSD-2-Clause
|
||||
github.com/russross/blackfriday v1.5.2 BSD-2-Clause
|
||||
|
||||
========================================================================
|
||||
BSD-3-Clause licenses
|
||||
========================================================================
|
||||
|
||||
github.com/PuerkitoBio/purell v1.1.1 BSD-3-Clause
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 BSD-3-Clause
|
||||
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 BSD-3-Clause
|
||||
github.com/evanphx/json-patch v4.11.0+incompatible BSD-3-Clause
|
||||
github.com/evanphx/json-patch/v5 v5.6.0 BSD-3-Clause
|
||||
github.com/fsnotify/fsnotify v1.5.1 BSD-3-Clause
|
||||
github.com/gogo/protobuf v1.3.2 BSD-3-Clause
|
||||
github.com/golang/protobuf v1.5.2 BSD-3-Clause
|
||||
github.com/google/go-cmp v0.5.6 BSD-3-Clause
|
||||
github.com/google/uuid v1.3.0 BSD-3-Clause
|
||||
github.com/googleapis/gax-go/v2 v2.1.1 BSD-3-Clause
|
||||
github.com/imdario/mergo v0.3.5 BSD-3-Clause
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de BSD-3-Clause
|
||||
github.com/pmezard/go-difflib v1.0.0 BSD-3-Clause
|
||||
github.com/spaolacci/murmur3 v1.1.0 BSD-3-Clause
|
||||
github.com/spf13/pflag v1.0.5 BSD-3-Clause
|
||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 BSD-3-Clause
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 BSD-3-Clause
|
||||
golang.org/x/net v0.0.0-20211020060615-d418f374d309 BSD-3-Clause
|
||||
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1 BSD-3-Clause
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c BSD-3-Clause
|
||||
golang.org/x/sys v0.0.0-20211020174200-9d6173849985 BSD-3-Clause
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d BSD-3-Clause
|
||||
golang.org/x/text v0.3.6 BSD-3-Clause
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac BSD-3-Clause
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 BSD-3-Clause
|
||||
google.golang.org/api v0.59.0 BSD-3-Clause
|
||||
google.golang.org/protobuf v1.27.1 BSD-3-Clause
|
||||
gopkg.in/inf.v0 v0.9.1 BSD-3-Clause
|
||||
|
||||
========================================================================
|
||||
ISC licenses
|
||||
========================================================================
|
||||
|
||||
github.com/davecgh/go-spew v1.1.1 ISC
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0 ISC
|
||||
|
||||
========================================================================
|
||||
MIT licenses
|
||||
========================================================================
|
||||
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 MIT
|
||||
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd MIT
|
||||
github.com/Masterminds/semver/v3 v3.1.1 MIT
|
||||
github.com/Masterminds/sprig/v3 v3.2.2 MIT
|
||||
github.com/Microsoft/go-winio v0.5.0 MIT
|
||||
github.com/Microsoft/hcsshim v0.8.21 MIT
|
||||
github.com/beorn7/perks v1.0.1 MIT
|
||||
github.com/cenkalti/backoff/v4 v4.1.1 MIT
|
||||
github.com/cespare/xxhash/v2 v2.1.1 MIT
|
||||
github.com/docker/docker-credential-helpers v0.6.3 MIT
|
||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d MIT
|
||||
github.com/fvbommel/sortorder v1.0.1 MIT
|
||||
github.com/go-errors/errors v1.0.1 MIT
|
||||
github.com/go-kit/log v0.1.0 MIT
|
||||
github.com/go-logfmt/logfmt v0.5.0 MIT
|
||||
github.com/goccy/go-json v0.4.8 MIT
|
||||
github.com/golang-jwt/jwt/v4 v4.0.0 MIT
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 MIT
|
||||
github.com/huandu/xstrings v1.3.2 MIT
|
||||
github.com/josharian/intern v1.0.0 MIT
|
||||
github.com/json-iterator/go v1.1.11 MIT
|
||||
github.com/lestrrat-go/backoff/v2 v2.0.7 MIT
|
||||
github.com/lestrrat-go/blackmagic v1.0.0 MIT
|
||||
github.com/lestrrat-go/httpcc v1.0.0 MIT
|
||||
github.com/lestrrat-go/iter v1.0.1 MIT
|
||||
github.com/lestrrat-go/jwx v1.2.0 MIT
|
||||
github.com/lestrrat-go/option v1.0.0 MIT
|
||||
github.com/mailru/easyjson v0.7.6 MIT
|
||||
github.com/mitchellh/copystructure v1.2.0 MIT
|
||||
github.com/mitchellh/go-wordwrap v1.0.0 MIT
|
||||
github.com/mitchellh/reflectwalk v1.0.2 MIT
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 MIT
|
||||
github.com/natefinch/lumberjack v2.0.0+incompatible MIT
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible MIT
|
||||
github.com/shopspring/decimal v1.2.0 MIT
|
||||
github.com/sirupsen/logrus v1.8.1 MIT
|
||||
github.com/spf13/cast v1.3.1 MIT
|
||||
github.com/stretchr/testify v1.7.0 MIT
|
||||
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca MIT
|
||||
github.com/yl2chen/cidranger v1.0.2 MIT
|
||||
go.uber.org/atomic v1.9.0 MIT
|
||||
go.uber.org/multierr v1.7.0 MIT
|
||||
go.uber.org/zap v1.19.1 MIT
|
||||
gomodules.xyz/orderedmap v0.1.0 MIT
|
||||
|
||||
========================================================================
|
||||
MIT and Apache-2.0 licenses
|
||||
========================================================================
|
||||
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b MIT and Apache-2.0
|
||||
|
||||
========================================================================
|
||||
MIT and BSD-3-Clause licenses
|
||||
========================================================================
|
||||
|
||||
github.com/ghodss/yaml v1.0.0 MIT and BSD-3-Clause
|
||||
sigs.k8s.io/yaml v1.3.0 MIT and BSD-3-Clause
|
||||
|
||||
========================================================================
|
||||
MPL-2.0 licenses
|
||||
========================================================================
|
||||
|
||||
github.com/hashicorp/errwrap v1.0.0 MPL-2.0
|
||||
github.com/hashicorp/go-multierror v1.1.1 MPL-2.0
|
||||
github.com/hashicorp/go-version v1.3.0 MPL-2.0
|
||||
github.com/hashicorp/golang-lru v0.5.4 MPL-2.0
|
||||
57
helm/higress/README.md
Normal file
57
helm/higress/README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# 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 |
|
||||
@@ -140,7 +140,7 @@ index 25479439b7..bd34442260 100755
|
||||
|
||||
# This script builds and version stamps the output
|
||||
|
||||
+export GOPROXY="https://proxy.golang.com.cn,direct"
|
||||
+export GOPROXY=${GOPROXY:-"https://proxy.golang.com.cn,direct"}
|
||||
+
|
||||
VERBOSE=${VERBOSE:-"0"}
|
||||
V=""
|
||||
@@ -215,10 +215,11 @@ index 271fe77a2d..c9e625efdc 100755
|
||||
--init \
|
||||
--sig-proxy=true \
|
||||
${DOCKER_SOCKET_MOUNT:--v /var/run/docker.sock:/var/run/docker.sock} \
|
||||
@@ -55,7 +59,15 @@ read -ra DOCKER_RUN_OPTIONS <<< "${DOCKER_RUN_OPTIONS:-}"
|
||||
@@ -55,7 +59,16 @@ read -ra DOCKER_RUN_OPTIONS <<< "${DOCKER_RUN_OPTIONS:-}"
|
||||
--env-file <(env | grep -v ${ENV_BLOCKLIST}) \
|
||||
-e IN_BUILD_CONTAINER=1 \
|
||||
-e TZ="${TIMEZONE:-$TZ}" \
|
||||
+ -e GOPROXY="${GOPROXY}" \
|
||||
+ -e HUB="${HUB}" \
|
||||
+ -e ENVOY_TAR_PATH="${ENVOY_TAR_PATH}" \
|
||||
+ --mount "type=bind,source=${MOUNT_PACKAGE_SOURCE},destination=/home/package" \
|
||||
|
||||
30
istio/1.12/patches/istio/20230618-debug-api-anonymous.patch
Normal file
30
istio/1.12/patches/istio/20230618-debug-api-anonymous.patch
Normal file
@@ -0,0 +1,30 @@
|
||||
diff --color -Naur istio/pilot/pkg/features/pilot.go istio_new/pilot/pkg/features/pilot.go
|
||||
--- istio/pilot/pkg/features/pilot.go 2023-06-18 20:13:57.715044832 +0800
|
||||
+++ istio_new/pilot/pkg/features/pilot.go 2023-06-18 20:11:40.310406690 +0800
|
||||
@@ -359,6 +359,9 @@
|
||||
EnableUnsafeAdminEndpoints = env.RegisterBoolVar("UNSAFE_ENABLE_ADMIN_ENDPOINTS", false,
|
||||
"If this is set to true, dangerous admin endpoints will be exposed on the debug interface. Not recommended for production.").Get()
|
||||
|
||||
+ DebugAuth = env.RegisterBoolVar("DEBUG_AUTH", true,
|
||||
+ "If this is set to false, the debug interface will allow all anonymous request from any remote host, which is not recommended for production").Get()
|
||||
+
|
||||
XDSAuth = env.RegisterBoolVar("XDS_AUTH", true,
|
||||
"If true, will authenticate XDS clients.").Get()
|
||||
|
||||
diff --color -Naur istio/pilot/pkg/xds/debug.go istio_new/pilot/pkg/xds/debug.go
|
||||
--- istio/pilot/pkg/xds/debug.go 2023-06-18 20:13:57.695044739 +0800
|
||||
+++ istio_new/pilot/pkg/xds/debug.go 2023-06-18 20:11:40.286406579 +0800
|
||||
@@ -218,8 +218,12 @@
|
||||
if internalMux != nil {
|
||||
internalMux.HandleFunc(path, handler)
|
||||
}
|
||||
+ handlerFunc := http.HandlerFunc(handler)
|
||||
+ if features.DebugAuth {
|
||||
+ handlerFunc = s.allowAuthenticatedOrLocalhost(handlerFunc)
|
||||
+ }
|
||||
// Add handler with auth; this is expose on an HTTP server
|
||||
- mux.HandleFunc(path, s.allowAuthenticatedOrLocalhost(http.HandlerFunc(handler)))
|
||||
+ mux.HandleFunc(path, handlerFunc)
|
||||
}
|
||||
|
||||
func (s *DiscoveryServer) allowAuthenticatedOrLocalhost(next http.Handler) http.HandlerFunc {
|
||||
15
istio/1.12/patches/istio/20230627-debug-fix-configz.patch
Normal file
15
istio/1.12/patches/istio/20230627-debug-fix-configz.patch
Normal file
@@ -0,0 +1,15 @@
|
||||
diff -Naur istio/pilot/pkg/xds/debug.go istio-new/pilot/pkg/xds/debug.go
|
||||
--- istio/pilot/pkg/xds/debug.go 2023-06-27 14:08:00.000000000 +0800
|
||||
+++ istio-new/pilot/pkg/xds/debug.go 2023-06-27 14:07:04.000000000 +0800
|
||||
@@ -469,6 +469,11 @@
|
||||
s.Env.IstioConfigStore.Schemas().ForEach(func(schema collection.Schema) bool {
|
||||
cfg, _ := s.Env.IstioConfigStore.List(schema.Resource().GroupVersionKind(), "")
|
||||
// Added by ingress
|
||||
+ copied := make([]config.Config, len(cfg))
|
||||
+ for i := range copied {
|
||||
+ copied[i] = cfg[i].DeepCopy()
|
||||
+ }
|
||||
+ cfg = copied
|
||||
switch schema.Resource().GroupVersionKind().String() {
|
||||
case gvk.Gateway.String():
|
||||
cfg = model.GatewayFilter(cfg)
|
||||
124
istio/1.12/patches/istio/20230815-multi-arch.patch
Normal file
124
istio/1.12/patches/istio/20230815-multi-arch.patch
Normal file
@@ -0,0 +1,124 @@
|
||||
diff -Naur istio/bin/init.sh istio-new/bin/init.sh
|
||||
--- istio/bin/init.sh 2023-08-15 21:01:53.601636573 +0800
|
||||
+++ istio-new/bin/init.sh 2023-08-15 21:04:56.144783484 +0800
|
||||
@@ -151,7 +151,8 @@
|
||||
# download_envoy_if_necessary "${ISTIO_ENVOY_LINUX_RELEASE_URL}" "$ISTIO_ENVOY_LINUX_RELEASE_PATH" "${SIDECAR}"
|
||||
# download_envoy_if_necessary "${ISTIO_ENVOY_CENTOS_RELEASE_URL}" "$ISTIO_ENVOY_CENTOS_LINUX_RELEASE_PATH" "${SIDECAR}-centos"
|
||||
|
||||
-untar_envoy_if_necessary "${ENVOY_TAR_PATH}" "$ISTIO_ENVOY_LINUX_RELEASE_PATH" "${SIDECAR}"
|
||||
+untar_envoy_if_necessary "${ENVOY_TAR_DIR}/envoy-arm64.tar.gz" "$ISTIO_ENVOY_LINUX_ARM64_RELEASE_PATH" "${SIDECAR}"
|
||||
+untar_envoy_if_necessary "${ENVOY_TAR_DIR}/envoy-amd64.tar.gz" "$ISTIO_ENVOY_LINUX_AMD64_RELEASE_PATH" "${SIDECAR}"
|
||||
|
||||
if [[ "$GOOS_LOCAL" == "darwin" ]]; then
|
||||
# Download and extract the Envoy macOS release binary
|
||||
diff -Naur istio/common/scripts/run.sh istio-new/common/scripts/run.sh
|
||||
--- istio/common/scripts/run.sh 2023-08-15 21:01:53.601636573 +0800
|
||||
+++ istio-new/common/scripts/run.sh 2023-08-15 17:37:57.754600731 +0800
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
HUB="${HUB:-istio}"
|
||||
MOUNT_SOURCE="${MOUNT_SOURCE:-${PWD}}"
|
||||
-ENVOY_TAR_PATH="${ENVOY_TAR_PATH:-/home/package/envoy.tar.gz}"
|
||||
+ENVOY_TAR_DIR="${ENVOY_TAR_DIR:-/home/package}"
|
||||
MOUNT_DEST="${MOUNT_DEST:-/work}"
|
||||
MOUNT_ROOT_SOURCE="${MOUNT_ROOT_SOURCE:-`cd $MOUNT_SOURCE/..;pwd`}"
|
||||
MOUNT_PACKAGE_SOURCE="${MOUNT_PACKAGE_SOURCE:-`cd $MOUNT_SOURCE/../package;pwd`}"
|
||||
@@ -61,7 +61,7 @@
|
||||
-e TZ="${TIMEZONE:-$TZ}" \
|
||||
-e GOPROXY="${GOPROXY}" \
|
||||
-e HUB="${HUB}" \
|
||||
- -e ENVOY_TAR_PATH="${ENVOY_TAR_PATH}" \
|
||||
+ -e ENVOY_TAR_DIR="${ENVOY_TAR_DIR}" \
|
||||
--mount "type=bind,source=${MOUNT_PACKAGE_SOURCE},destination=/home/package" \
|
||||
--mount "type=bind,source=${MOUNT_SOURCE},destination=/work" \
|
||||
--mount "type=bind,source=${MOUNT_ROOT_SOURCE}/..,destination=/parent" \
|
||||
diff -Naur istio/common/scripts/setup_env.sh istio-new/common/scripts/setup_env.sh
|
||||
--- istio/common/scripts/setup_env.sh 2023-08-15 21:01:53.601636573 +0800
|
||||
+++ istio-new/common/scripts/setup_env.sh 2023-08-15 20:15:23.292391629 +0800
|
||||
@@ -81,6 +81,9 @@
|
||||
export TARGET_OUT="${TARGET_OUT:-$(pwd)/out/${TARGET_OS}_${TARGET_ARCH}}"
|
||||
export TARGET_OUT_LINUX="${TARGET_OUT_LINUX:-$(pwd)/out/linux_${TARGET_ARCH}}"
|
||||
|
||||
+export ARM64_OUT_LINUX=/work/out/linux_arm64
|
||||
+export AMD64_OUT_LINUX=/work/out/linux_amd64
|
||||
+
|
||||
export CONTAINER_TARGET_OUT="${CONTAINER_TARGET_OUT:-/work/out/${TARGET_OS}_${TARGET_ARCH}}"
|
||||
export CONTAINER_TARGET_OUT_LINUX="${CONTAINER_TARGET_OUT_LINUX:-/work/out/linux_${TARGET_ARCH}}"
|
||||
|
||||
diff -Naur istio/Makefile.core.mk istio-new/Makefile.core.mk
|
||||
--- istio/Makefile.core.mk 2023-08-15 21:01:53.601636573 +0800
|
||||
+++ istio-new/Makefile.core.mk 2023-08-15 20:03:25.384280274 +0800
|
||||
@@ -150,6 +150,11 @@
|
||||
export ISTIO_ENVOY_CENTOS_LINUX_RELEASE_NAME ?= envoy-centos-${ISTIO_ENVOY_LINUX_VERSION}
|
||||
export ISTIO_ENVOY_CENTOS_LINUX_RELEASE_PATH ?= ${ISTIO_ENVOY_LINUX_RELEASE_DIR}/${ISTIO_ENVOY_CENTOS_LINUX_RELEASE_NAME}
|
||||
|
||||
+export ISTIO_ENVOY_LINUX_ARM64_RELEASE_DIR ?= ${ARM64_OUT_LINUX}/release
|
||||
+export ISTIO_ENVOY_LINUX_ARM64_RELEASE_PATH ?= ${ISTIO_ENVOY_LINUX_ARM64_RELEASE_DIR}/${ISTIO_ENVOY_LINUX_RELEASE_NAME}
|
||||
+export ISTIO_ENVOY_LINUX_AMD64_RELEASE_DIR ?= ${AMD64_OUT_LINUX}/release
|
||||
+export ISTIO_ENVOY_LINUX_AMD64_RELEASE_PATH ?= ${ISTIO_ENVOY_LINUX_AMD64_RELEASE_DIR}/${ISTIO_ENVOY_LINUX_RELEASE_NAME}
|
||||
+
|
||||
# Envoy macOS vars.
|
||||
# TODO Change url when official envoy release for macOS is available
|
||||
export ISTIO_ENVOY_MACOS_VERSION ?= 1.0.2
|
||||
@@ -240,6 +245,8 @@
|
||||
${ISTIO_ENVOY_LINUX_DEBUG_PATH}: init
|
||||
${ISTIO_ENVOY_LINUX_RELEASE_PATH}: init
|
||||
${ISTIO_ENVOY_MACOS_RELEASE_PATH}: init
|
||||
+${ISTIO_ENVOY_LINUX_ARM64_RELEASE_PATH}: init
|
||||
+${ISTIO_ENVOY_LINUX_AMD64_RELEASE_PATH}: init
|
||||
|
||||
# Pull dependencies, based on the checked in Gopkg.lock file.
|
||||
# Developers must manually run `dep ensure` if adding new deps
|
||||
@@ -312,8 +319,8 @@
|
||||
# various platform images.
|
||||
.PHONY: build-linux
|
||||
build-linux: depend
|
||||
- GOOS=linux GOARCH=$(GOARCH_LOCAL) LDFLAGS=$(RELEASE_LDFLAGS) common/scripts/gobuild.sh $(ISTIO_OUT_LINUX)/ $(STANDARD_BINARIES)
|
||||
- GOOS=linux GOARCH=$(GOARCH_LOCAL) LDFLAGS=$(RELEASE_LDFLAGS) common/scripts/gobuild.sh $(ISTIO_OUT_LINUX)/ -tags=agent $(AGENT_BINARIES)
|
||||
+ GOOS=linux GOARCH=$(GOARCH_LOCAL) LDFLAGS=$(RELEASE_LDFLAGS) GOBUILDFLAGS='-buildvcs=false' common/scripts/gobuild.sh $(ISTIO_OUT_LINUX)/ $(STANDARD_BINARIES)
|
||||
+ GOOS=linux GOARCH=$(GOARCH_LOCAL) LDFLAGS=$(RELEASE_LDFLAGS) GOBUILDFLAGS='-buildvcs=false' common/scripts/gobuild.sh $(ISTIO_OUT_LINUX)/ -tags=agent $(AGENT_BINARIES)
|
||||
|
||||
# Create targets for ISTIO_OUT_LINUX/binary
|
||||
# There are two use cases here:
|
||||
diff -Naur istio/tools/istio-docker.mk istio-new/tools/istio-docker.mk
|
||||
--- istio/tools/istio-docker.mk 2023-08-15 21:01:53.621637356 +0800
|
||||
+++ istio-new/tools/istio-docker.mk 2023-08-15 20:02:11.881402098 +0800
|
||||
@@ -77,6 +77,14 @@
|
||||
${ISTIO_ENVOY_BOOTSTRAP_CONFIG_DIR}/envoy_bootstrap.json: ${ISTIO_ENVOY_BOOTSTRAP_CONFIG_PATH}
|
||||
cp ${ISTIO_ENVOY_BOOTSTRAP_CONFIG_PATH} ${ISTIO_ENVOY_BOOTSTRAP_CONFIG_DIR}/envoy_bootstrap.json
|
||||
|
||||
+${ISTIO_ENVOY_LINUX_ARM64_RELEASE_DIR}/${SIDECAR}: ${ISTIO_ENVOY_LINUX_ARM64_RELEASE_PATH}
|
||||
+ mkdir -p $(DOCKER_BUILD_TOP)/proxyv2
|
||||
+ cp ${ISTIO_ENVOY_LINUX_ARM64_RELEASE_PATH} ${ISTIO_ENVOY_LINUX_ARM64_RELEASE_DIR}/${SIDECAR}
|
||||
+
|
||||
+${ISTIO_ENVOY_LINUX_AMD64_RELEASE_DIR}/${SIDECAR}: ${ISTIO_ENVOY_LINUX_AMD64_RELEASE_PATH}
|
||||
+ mkdir -p $(DOCKER_BUILD_TOP)/proxyv2
|
||||
+ cp ${ISTIO_ENVOY_LINUX_AMD64_RELEASE_PATH} ${ISTIO_ENVOY_LINUX_AMD64_RELEASE_DIR}/${SIDECAR}
|
||||
+
|
||||
# rule for wasm extensions.
|
||||
$(ISTIO_ENVOY_LINUX_RELEASE_DIR)/stats-filter.wasm: init
|
||||
$(ISTIO_ENVOY_LINUX_RELEASE_DIR)/stats-filter.compiled.wasm: init
|
||||
@@ -88,7 +96,8 @@
|
||||
docker.proxyv2: BUILD_ARGS=--build-arg proxy_version=istio-proxy:${PROXY_REPO_SHA} --build-arg istio_version=${VERSION} --build-arg BASE_VERSION=${BASE_VERSION} --build-arg SIDECAR=${SIDECAR} --build-arg HUB=${HUB}
|
||||
docker.proxyv2: ${ISTIO_ENVOY_BOOTSTRAP_CONFIG_DIR}/envoy_bootstrap.json
|
||||
docker.proxyv2: ${ISTIO_ENVOY_BOOTSTRAP_CONFIG_DIR}/gcp_envoy_bootstrap.json
|
||||
-docker.proxyv2: $(ISTIO_ENVOY_LINUX_RELEASE_DIR)/${SIDECAR}
|
||||
+docker.proxyv2: ${ISTIO_ENVOY_LINUX_ARM64_RELEASE_DIR}/${SIDECAR}
|
||||
+docker.proxyv2: ${ISTIO_ENVOY_LINUX_AMD64_RELEASE_DIR}/${SIDECAR}
|
||||
docker.proxyv2: $(ISTIO_OUT_LINUX)/pilot-agent
|
||||
docker.proxyv2: pilot/docker/Dockerfile.proxyv2
|
||||
# docker.proxyv2: $(ISTIO_ENVOY_LINUX_RELEASE_DIR)/stats-filter.wasm
|
||||
@@ -324,7 +333,13 @@
|
||||
# This can be done with DOCKER_BUILD_VARIANTS="default debug" as well, but at the expense of building twice vs building once and tagging twice
|
||||
INCLUDE_UNTAGGED_DEFAULT ?= false
|
||||
DEFAULT_DISTRIBUTION=debug
|
||||
+
|
||||
+
|
||||
+ifeq ($(BUILDX_PLATFORM), true)
|
||||
+DOCKER_RULE ?= $(foreach VARIANT,$(DOCKER_BUILD_VARIANTS), time (mkdir -p $(DOCKER_BUILD_TOP)/$@ && TARGET_ARCH=$(TARGET_ARCH) ./tools/docker-copy.sh $^ $(DOCKER_BUILD_TOP)/$@ && cd $(DOCKER_BUILD_TOP)/$@ $(BUILD_PRE) && docker buildx create --use && docker buildx build --no-cache --platform linux/amd64,linux/arm64 $(BUILD_ARGS) --build-arg BASE_DISTRIBUTION=$(call normalize-tag,$(VARIANT)) -t $(HUB)/$(subst docker.,,$@):$(TAG)$(call variant-tag,$(VARIANT)) -f Dockerfile$(suffix $@) . --push ); )
|
||||
+else
|
||||
DOCKER_RULE ?= $(foreach VARIANT,$(DOCKER_BUILD_VARIANTS), time (mkdir -p $(DOCKER_BUILD_TOP)/$@ && TARGET_ARCH=$(TARGET_ARCH) ./tools/docker-copy.sh $^ $(DOCKER_BUILD_TOP)/$@ && cd $(DOCKER_BUILD_TOP)/$@ $(BUILD_PRE) && docker build $(BUILD_ARGS) --build-arg BASE_DISTRIBUTION=$(call normalize-tag,$(VARIANT)) -t $(HUB)/$(subst docker.,,$@):$(TAG)$(call variant-tag,$(VARIANT)) -f Dockerfile$(suffix $@) . ); )
|
||||
+endif
|
||||
RENAME_TEMPLATE ?= mkdir -p $(DOCKER_BUILD_TOP)/$@ && cp $(ECHO_DOCKER)/$(VM_OS_DOCKERFILE_TEMPLATE) $(DOCKER_BUILD_TOP)/$@/Dockerfile$(suffix $@)
|
||||
|
||||
# This target will package all docker images used in test and release, without re-building
|
||||
14
istio/1.12/patches/istio/20230922-gateway-class.patch
Normal file
14
istio/1.12/patches/istio/20230922-gateway-class.patch
Normal file
@@ -0,0 +1,14 @@
|
||||
diff -Naur istio/pilot/pkg/config/kube/gateway/conversion.go istio_new/pilot/pkg/config/kube/gateway/conversion.go
|
||||
--- istio/pilot/pkg/config/kube/gateway/conversion.go 2023-09-22 11:06:50.400535200 +0800
|
||||
+++ istio_new/pilot/pkg/config/kube/gateway/conversion.go 2023-09-22 11:07:52.954982700 +0800
|
||||
@@ -37,8 +37,8 @@
|
||||
)
|
||||
|
||||
const (
|
||||
- DefaultClassName = "istio"
|
||||
- ControllerName = "istio.io/gateway-controller"
|
||||
+ DefaultClassName = "higress"
|
||||
+ ControllerName = "higress.io/gateway-controller"
|
||||
)
|
||||
|
||||
// KubernetesResources stores all inputs to our conversion
|
||||
71
istio/1.12/patches/istio/20230925-gateway-httproute.patch
Normal file
71
istio/1.12/patches/istio/20230925-gateway-httproute.patch
Normal file
@@ -0,0 +1,71 @@
|
||||
diff -Naur istio/pilot/pkg/config/kube/gateway/conversion.go istio-new/pilot/pkg/config/kube/gateway/conversion.go
|
||||
--- istio/pilot/pkg/config/kube/gateway/conversion.go 2023-09-25 17:26:32.000000000 +0800
|
||||
+++ istio-new/pilot/pkg/config/kube/gateway/conversion.go 2023-09-25 17:25:27.000000000 +0800
|
||||
@@ -656,6 +656,16 @@
|
||||
Port: &istio.PortSelector{Number: uint32(*to.Port)},
|
||||
}, nil
|
||||
}
|
||||
+ if equal((*string)(to.Group), "networking.higress.io") && nilOrEqual((*string)(to.Kind), "Service") {
|
||||
+ var port *istio.PortSelector
|
||||
+ if to.Port != nil {
|
||||
+ port = &istio.PortSelector{Number: uint32(*to.Port)}
|
||||
+ }
|
||||
+ return &istio.Destination{
|
||||
+ Host: string(to.Name),
|
||||
+ Port: port,
|
||||
+ }, nil
|
||||
+ }
|
||||
return nil, &ConfigError{
|
||||
Reason: InvalidDestination,
|
||||
Message: fmt.Sprintf("referencing unsupported backendRef: group %q kind %q", emptyIfNil((*string)(to.Group)), emptyIfNil((*string)(to.Kind))),
|
||||
@@ -912,7 +922,7 @@
|
||||
ObservedGeneration: obj.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(k8s.GatewayClassConditionStatusAccepted),
|
||||
- Message: "Handled by Istio controller",
|
||||
+ Message: "Handled by Higress controller",
|
||||
})
|
||||
return gcs
|
||||
})
|
||||
@@ -1371,6 +1381,10 @@
|
||||
return d
|
||||
}
|
||||
|
||||
+func equal(have *string, expected string) bool {
|
||||
+ return have != nil && *have == expected
|
||||
+}
|
||||
+
|
||||
func nilOrEqual(have *string, expected string) bool {
|
||||
return have == nil || *have == expected
|
||||
}
|
||||
diff -Naur istio/pilot/pkg/leaderelection/leaderelection.go istio-new/pilot/pkg/leaderelection/leaderelection.go
|
||||
--- istio/pilot/pkg/leaderelection/leaderelection.go 2023-09-25 17:26:31.000000000 +0800
|
||||
+++ istio-new/pilot/pkg/leaderelection/leaderelection.go 2023-09-25 14:59:39.000000000 +0800
|
||||
@@ -35,20 +35,20 @@
|
||||
|
||||
// Various locks used throughout the code
|
||||
const (
|
||||
- NamespaceController = "istio-namespace-controller-election"
|
||||
- ServiceExportController = "istio-serviceexport-controller-election"
|
||||
+ NamespaceController = "higress-namespace-controller-election"
|
||||
+ ServiceExportController = "higress-serviceexport-controller-election"
|
||||
// This holds the legacy name to not conflict with older control plane deployments which are just
|
||||
// doing the ingress syncing.
|
||||
- IngressController = "istio-leader"
|
||||
+ IngressController = "higress-leader"
|
||||
// GatewayStatusController controls the status of gateway.networking.k8s.io objects. For the v1alpha1
|
||||
// this was formally "istio-gateway-leader"; because they are a different API group we need a different
|
||||
// election to ensure we do not only handle one or the other.
|
||||
- GatewayStatusController = "istio-gateway-status-leader"
|
||||
+ GatewayStatusController = "higress-gateway-status-leader"
|
||||
// GatewayDeploymentController controls the Deployment/Service generation from Gateways. This is
|
||||
// separate from GatewayStatusController to allow running in a separate process (for low priv).
|
||||
- GatewayDeploymentController = "istio-gateway-deployment-leader"
|
||||
- StatusController = "istio-status-leader"
|
||||
- AnalyzeController = "istio-analyze-leader"
|
||||
+ GatewayDeploymentController = "higress-gateway-deployment-leader"
|
||||
+ StatusController = "higress-status-leader"
|
||||
+ AnalyzeController = "higress-analyze-leader"
|
||||
)
|
||||
|
||||
var ClusterScopedNamespaceController = NamespaceController
|
||||
90
istio/1.12/patches/istio/20231008-gateway-fallback.patch
Normal file
90
istio/1.12/patches/istio/20231008-gateway-fallback.patch
Normal file
@@ -0,0 +1,90 @@
|
||||
diff -Naur istio/pilot/pkg/config/kube/gateway/conversion.go istio-new/pilot/pkg/config/kube/gateway/conversion.go
|
||||
--- istio/pilot/pkg/config/kube/gateway/conversion.go 2023-10-08 19:54:47.000000000 +0800
|
||||
+++ istio-new/pilot/pkg/config/kube/gateway/conversion.go 2023-09-27 16:10:42.000000000 +0800
|
||||
@@ -18,6 +18,7 @@
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
+ "strconv"
|
||||
"strings"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
@@ -176,7 +177,9 @@
|
||||
hosts := hostnameToStringList(route.Hostnames)
|
||||
for _, r := range route.Rules {
|
||||
// TODO: implement rewrite, timeout, mirror, corspolicy, retries
|
||||
- vs := &istio.HTTPRoute{}
|
||||
+ vs := &istio.HTTPRoute{
|
||||
+ Name: obj.Name,
|
||||
+ }
|
||||
for _, match := range r.Matches {
|
||||
uri, err := createURIMatch(match)
|
||||
if err != nil {
|
||||
@@ -246,7 +249,9 @@
|
||||
}}
|
||||
}
|
||||
|
||||
- route, err := buildHTTPDestination(r.BackendRefs, obj.Namespace, domain, zero)
|
||||
+ fallbackCluster := obj.Annotations["higress.io/fallback-service"]
|
||||
+
|
||||
+ route, err := buildHTTPDestination(r.BackendRefs, obj.Namespace, domain, zero, fallbackCluster)
|
||||
if err != nil {
|
||||
reportError(err)
|
||||
return nil
|
||||
@@ -581,11 +586,33 @@
|
||||
return r
|
||||
}
|
||||
|
||||
-func buildHTTPDestination(forwardTo []k8s.HTTPBackendRef, ns string, domain string, totalZero bool) ([]*istio.HTTPRouteDestination, *ConfigError) {
|
||||
+func buildHTTPDestination(forwardTo []k8s.HTTPBackendRef, ns string, domain string, totalZero bool, fallbackCluster string) ([]*istio.HTTPRouteDestination, *ConfigError) {
|
||||
if forwardTo == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
+ var fallbackDest *istio.Destination
|
||||
+ if fallbackCluster != "" {
|
||||
+ var port uint64
|
||||
+ host := fallbackCluster
|
||||
+ colon := strings.LastIndex(fallbackCluster, ":")
|
||||
+ if colon != -1 {
|
||||
+ var err error
|
||||
+ port, err = strconv.ParseUint(fallbackCluster[colon+1:], 10, 32)
|
||||
+ if err == nil && port > 0 && port < 65536 {
|
||||
+ host = fallbackCluster[:colon]
|
||||
+ }
|
||||
+ }
|
||||
+ fallbackDest = &istio.Destination{
|
||||
+ Host: host,
|
||||
+ }
|
||||
+ if port > 0 {
|
||||
+ fallbackDest.Port = &istio.PortSelector{
|
||||
+ Number: uint32(port),
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
weights := []int{}
|
||||
action := []k8s.HTTPBackendRef{}
|
||||
for i, w := range forwardTo {
|
||||
@@ -612,6 +639,9 @@
|
||||
Destination: dst,
|
||||
Weight: int32(weights[i]),
|
||||
}
|
||||
+ if fallbackDest != nil {
|
||||
+ rd.FallbackClusters = append(rd.FallbackClusters, fallbackDest)
|
||||
+ }
|
||||
for _, filter := range fwd.Filters {
|
||||
switch filter.Type {
|
||||
case k8s.HTTPRouteFilterRequestHeaderModifier:
|
||||
diff -Naur istio/pilot/pkg/networking/core/v1alpha3/route/route.go istio-new/pilot/pkg/networking/core/v1alpha3/route/route.go
|
||||
--- istio/pilot/pkg/networking/core/v1alpha3/route/route.go 2023-10-08 19:54:46.000000000 +0800
|
||||
+++ istio-new/pilot/pkg/networking/core/v1alpha3/route/route.go 2023-09-27 16:18:16.000000000 +0800
|
||||
@@ -669,7 +669,7 @@
|
||||
}
|
||||
var singleClusterConfig *fallback.ClusterFallbackConfig
|
||||
var weightedClusterConfig *fallback.ClusterFallbackConfig
|
||||
- isSupportFallback := supportFallback(node)
|
||||
+ isSupportFallback := true
|
||||
// Added by ingress
|
||||
if len(in.Route) == 1 {
|
||||
route := in.Route[0]
|
||||
13
istio/1.12/patches/istio/20231024-cds-add-fallback.patch
Normal file
13
istio/1.12/patches/istio/20231024-cds-add-fallback.patch
Normal file
@@ -0,0 +1,13 @@
|
||||
diff -Naur istio/pilot/pkg/model/push_context.go istio-new/pilot/pkg/model/push_context.go
|
||||
--- istio/pilot/pkg/model/push_context.go 2023-10-24 10:55:51.000000000 +0800
|
||||
+++ istio-new/pilot/pkg/model/push_context.go 2023-10-20 17:00:06.000000000 +0800
|
||||
@@ -704,6 +704,9 @@
|
||||
if r.Destination != nil {
|
||||
out = append(out, r.Destination.Host)
|
||||
}
|
||||
+ for _, d := range r.FallbackClusters {
|
||||
+ out = append(out, d.Host)
|
||||
+ }
|
||||
}
|
||||
if h.Mirror != nil {
|
||||
out = append(out, h.Mirror.Host)
|
||||
2202
istio/1.12/patches/istio/20231031-gatewayapi-v1beta1.patch
Normal file
2202
istio/1.12/patches/istio/20231031-gatewayapi-v1beta1.patch
Normal file
File diff suppressed because it is too large
Load Diff
377
istio/1.12/patches/istio/20231103-gatewayapi-sort.patch
Normal file
377
istio/1.12/patches/istio/20231103-gatewayapi-sort.patch
Normal file
@@ -0,0 +1,377 @@
|
||||
diff -Naur istio/pilot/pkg/config/kube/gateway/conversion.go istio-new/pilot/pkg/config/kube/gateway/conversion.go
|
||||
--- istio/pilot/pkg/config/kube/gateway/conversion.go 2023-11-03 17:18:56.000000000 +0800
|
||||
+++ istio-new/pilot/pkg/config/kube/gateway/conversion.go 2023-11-03 17:14:50.000000000 +0800
|
||||
@@ -151,15 +151,113 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ // for gateway routes, build one VS per gateway+host
|
||||
+ gatewayRoutes := make(map[string]map[string]*config.Config)
|
||||
+
|
||||
for _, obj := range r.HTTPRoute {
|
||||
- if vsConfig := buildHTTPVirtualServices(obj, gatewayMap, r.Domain); vsConfig != nil {
|
||||
+ buildHTTPVirtualServices(r, obj, gatewayMap, gatewayRoutes, r.Domain)
|
||||
+ }
|
||||
+ for _, vsByHost := range gatewayRoutes {
|
||||
+ for _, vsConfig := range vsByHost {
|
||||
result = append(result, *vsConfig)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
-func buildHTTPVirtualServices(obj config.Config, gateways map[parentKey]map[gatewayapiV1beta1.SectionName]*parentInfo, domain string) *config.Config {
|
||||
+// getURIRank ranks a URI match type. Exact > Prefix > Regex
|
||||
+func getURIRank(match *istio.HTTPMatchRequest) int {
|
||||
+ if match.Uri == nil {
|
||||
+ return -1
|
||||
+ }
|
||||
+ switch match.Uri.MatchType.(type) {
|
||||
+ case *istio.StringMatch_Exact:
|
||||
+ return 3
|
||||
+ case *istio.StringMatch_Prefix:
|
||||
+ return 2
|
||||
+ case *istio.StringMatch_Regex:
|
||||
+ // TODO optimize in new verison envoy
|
||||
+ if strings.HasSuffix(match.Uri.GetRegex(), prefixMatchRegex) &&
|
||||
+ !strings.ContainsAny(strings.TrimSuffix(match.Uri.GetRegex(), prefixMatchRegex), `\.+*?()|[]{}^$`) {
|
||||
+ return 2
|
||||
+ }
|
||||
+ return 1
|
||||
+ }
|
||||
+ // should not happen
|
||||
+ return -1
|
||||
+}
|
||||
+
|
||||
+func getURILength(match *istio.HTTPMatchRequest) int {
|
||||
+ if match.Uri == nil {
|
||||
+ return 0
|
||||
+ }
|
||||
+ switch match.Uri.MatchType.(type) {
|
||||
+ case *istio.StringMatch_Prefix:
|
||||
+ return len(match.Uri.GetPrefix())
|
||||
+ case *istio.StringMatch_Exact:
|
||||
+ return len(match.Uri.GetExact())
|
||||
+ case *istio.StringMatch_Regex:
|
||||
+ return len(match.Uri.GetRegex())
|
||||
+ }
|
||||
+ // should not happen
|
||||
+ return -1
|
||||
+}
|
||||
+
|
||||
+// sortHTTPRoutes sorts generated vs routes to meet gateway-api requirements
|
||||
+// see https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1alpha2.HTTPRouteRule
|
||||
+func sortHTTPRoutes(routes []*istio.HTTPRoute) {
|
||||
+ sort.SliceStable(routes, func(i, j int) bool {
|
||||
+ if len(routes[i].Match) == 0 {
|
||||
+ return false
|
||||
+ } else if len(routes[j].Match) == 0 {
|
||||
+ return true
|
||||
+ }
|
||||
+ // Only look at match[0], we always generate only one match
|
||||
+ m1, m2 := routes[i].Match[0], routes[j].Match[0]
|
||||
+ r1, r2 := getURIRank(m1), getURIRank(m2)
|
||||
+ len1, len2 := getURILength(m1), getURILength(m2)
|
||||
+ switch {
|
||||
+ // 1: Exact/Prefix/Regex
|
||||
+ case r1 != r2:
|
||||
+ return r1 > r2
|
||||
+ case len1 != len2:
|
||||
+ return len1 > len2
|
||||
+ // 2: method math
|
||||
+ case (m1.Method == nil) != (m2.Method == nil):
|
||||
+ return m1.Method != nil
|
||||
+ // 3: number of header matches
|
||||
+ case len(m1.Headers) != len(m2.Headers):
|
||||
+ return len(m1.Headers) > len(m2.Headers)
|
||||
+ // 4: number of query matches
|
||||
+ default:
|
||||
+ return len(m1.QueryParams) > len(m2.QueryParams)
|
||||
+ }
|
||||
+ })
|
||||
+}
|
||||
+
|
||||
+func routeMeta(obj config.Config) map[string]string {
|
||||
+ m := parentMeta(obj, nil)
|
||||
+ m[constants.InternalRouteSemantics] = constants.RouteSemanticsGateway
|
||||
+ return m
|
||||
+}
|
||||
+
|
||||
+func filteredReferences(parents []routeParentReference) []routeParentReference {
|
||||
+ ret := make([]routeParentReference, 0, len(parents))
|
||||
+ for _, p := range parents {
|
||||
+ if p.DeniedReason != nil {
|
||||
+ // We should filter this out
|
||||
+ continue
|
||||
+ }
|
||||
+ ret = append(ret, p)
|
||||
+ }
|
||||
+ // To ensure deterministic order, sort them
|
||||
+ sort.Slice(ret, func(i, j int) bool {
|
||||
+ return ret[i].InternalName < ret[j].InternalName
|
||||
+ })
|
||||
+ return ret
|
||||
+}
|
||||
+
|
||||
+func buildHTTPVirtualServices(ctx *KubernetesResources, obj config.Config, gateways map[parentKey]map[gatewayapiV1beta1.SectionName]*parentInfo, gatewayRoutes map[string]map[string]*config.Config, domain string) {
|
||||
route := obj.Spec.(*gatewayapiV1beta1.HTTPRouteSpec)
|
||||
|
||||
parentRefs := extractParentReferenceInfo(gateways, route.ParentRefs, route.Hostnames, gvk.HTTPRoute, obj.Namespace)
|
||||
@@ -172,10 +270,7 @@
|
||||
})
|
||||
}
|
||||
|
||||
- name := fmt.Sprintf("%s-%s", obj.Name, constants.KubernetesGatewayName)
|
||||
-
|
||||
httproutes := []*istio.HTTPRoute{}
|
||||
- hosts := hostnameToStringList(route.Hostnames)
|
||||
for _, r := range route.Rules {
|
||||
// TODO: implement rewrite, timeout, mirror, corspolicy, retries
|
||||
vs := &istio.HTTPRoute{
|
||||
@@ -185,22 +280,22 @@
|
||||
uri, err := createURIMatch(match)
|
||||
if err != nil {
|
||||
reportError(err)
|
||||
- return nil
|
||||
+ return
|
||||
}
|
||||
headers, err := createHeadersMatch(match)
|
||||
if err != nil {
|
||||
reportError(err)
|
||||
- return nil
|
||||
+ return
|
||||
}
|
||||
qp, err := createQueryParamsMatch(match)
|
||||
if err != nil {
|
||||
reportError(err)
|
||||
- return nil
|
||||
+ return
|
||||
}
|
||||
method, err := createMethodMatch(match)
|
||||
if err != nil {
|
||||
reportError(err)
|
||||
- return nil
|
||||
+ return
|
||||
}
|
||||
vs.Match = append(vs.Match, &istio.HTTPMatchRequest{
|
||||
Uri: uri,
|
||||
@@ -219,7 +314,7 @@
|
||||
mirror, err := createMirrorFilter(filter.RequestMirror, obj.Namespace, domain)
|
||||
if err != nil {
|
||||
reportError(err)
|
||||
- return nil
|
||||
+ return
|
||||
}
|
||||
vs.Mirror = mirror
|
||||
default:
|
||||
@@ -227,7 +322,7 @@
|
||||
Reason: InvalidFilter,
|
||||
Message: fmt.Sprintf("unsupported filter type %q", filter.Type),
|
||||
})
|
||||
- return nil
|
||||
+ return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,33 +350,65 @@
|
||||
route, err := buildHTTPDestination(r.BackendRefs, obj.Namespace, domain, zero, fallbackCluster)
|
||||
if err != nil {
|
||||
reportError(err)
|
||||
- return nil
|
||||
+ return
|
||||
}
|
||||
vs.Route = route
|
||||
|
||||
httproutes = append(httproutes, vs)
|
||||
}
|
||||
reportError(nil)
|
||||
- gatewayNames := referencesToInternalNames(parentRefs)
|
||||
- if len(gatewayNames) == 0 {
|
||||
- return nil
|
||||
+
|
||||
+ count := 0
|
||||
+ for _, parent := range filteredReferences(parentRefs) {
|
||||
+ // for gateway routes, build one VS per gateway+host
|
||||
+ routeMap := gatewayRoutes
|
||||
+ routeKey := parent.InternalName
|
||||
+ vsHosts := hostnameToStringList(route.Hostnames)
|
||||
+ routes := httproutes
|
||||
+ if len(routes) == 0 {
|
||||
+ continue
|
||||
+ }
|
||||
+ if _, f := routeMap[routeKey]; !f {
|
||||
+ routeMap[routeKey] = make(map[string]*config.Config)
|
||||
+ }
|
||||
+
|
||||
+ // Create one VS per hostname with a single hostname.
|
||||
+ // This ensures we can treat each hostname independently, as the spec requires
|
||||
+ for _, h := range vsHosts {
|
||||
+ if cfg := routeMap[routeKey][h]; cfg != nil {
|
||||
+ // merge http routes
|
||||
+ vs := cfg.Spec.(*istio.VirtualService)
|
||||
+ vs.Http = append(vs.Http, routes...)
|
||||
+ // append parents
|
||||
+ cfg.Annotations[constants.InternalParentNames] = fmt.Sprintf("%s,%s/%s.%s",
|
||||
+ cfg.Annotations[constants.InternalParentNames], obj.GroupVersionKind.Kind, obj.Name, obj.Namespace)
|
||||
+ } else {
|
||||
+ name := fmt.Sprintf("%s-%d-%s", obj.Name, count, constants.KubernetesGatewayName)
|
||||
+ routeMap[routeKey][h] = &config.Config{
|
||||
+ Meta: config.Meta{
|
||||
+ CreationTimestamp: obj.CreationTimestamp,
|
||||
+ GroupVersionKind: gvk.VirtualService,
|
||||
+ Name: name,
|
||||
+ Annotations: routeMeta(obj),
|
||||
+ Namespace: obj.Namespace,
|
||||
+ Domain: ctx.Domain,
|
||||
+ },
|
||||
+ Spec: &istio.VirtualService{
|
||||
+ Hosts: []string{h},
|
||||
+ Gateways: []string{parent.InternalName},
|
||||
+ Http: routes,
|
||||
+ },
|
||||
+ }
|
||||
+ count++
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
- vsConfig := config.Config{
|
||||
- Meta: config.Meta{
|
||||
- CreationTimestamp: obj.CreationTimestamp,
|
||||
- GroupVersionKind: gvk.VirtualService,
|
||||
- Name: name,
|
||||
- Annotations: parentMeta(obj, nil),
|
||||
- Namespace: obj.Namespace,
|
||||
- Domain: domain,
|
||||
- },
|
||||
- Spec: &istio.VirtualService{
|
||||
- Hosts: hosts,
|
||||
- Gateways: gatewayNames,
|
||||
- Http: httproutes,
|
||||
- },
|
||||
+ for _, vsByHost := range gatewayRoutes {
|
||||
+ for _, cfg := range vsByHost {
|
||||
+ vs := cfg.Spec.(*istio.VirtualService)
|
||||
+ sortHTTPRoutes(vs.Http)
|
||||
+ }
|
||||
}
|
||||
- return &vsConfig
|
||||
}
|
||||
|
||||
func parentMeta(obj config.Config, sectionName *gatewayapiV1beta1.SectionName) map[string]string {
|
||||
@@ -1155,9 +1282,11 @@
|
||||
}
|
||||
gs.Addresses = make([]gatewayapiV1beta1.GatewayAddress, 0, len(addressesToReport))
|
||||
for _, addr := range addressesToReport {
|
||||
+ addrPairs := strings.Split(addr, ":")
|
||||
gs.Addresses = append(gs.Addresses, gatewayapiV1beta1.GatewayAddress{
|
||||
- Type: &addrType,
|
||||
- Value: addr,
|
||||
+ Type: &addrType,
|
||||
+ // strip the port
|
||||
+ Value: addrPairs[0],
|
||||
})
|
||||
}
|
||||
return gs
|
||||
diff -Naur istio/pilot/pkg/model/push_context.go istio-new/pilot/pkg/model/push_context.go
|
||||
--- istio/pilot/pkg/model/push_context.go 2023-11-03 17:18:56.000000000 +0800
|
||||
+++ istio-new/pilot/pkg/model/push_context.go 2023-11-03 17:05:47.000000000 +0800
|
||||
@@ -841,7 +841,19 @@
|
||||
func (ps *PushContext) VirtualServicesForGateway(proxy *Proxy, gateway string) []config.Config {
|
||||
res := ps.virtualServiceIndex.privateByNamespaceAndGateway[proxy.ConfigNamespace][gateway]
|
||||
res = append(res, ps.virtualServiceIndex.exportedToNamespaceByGateway[proxy.ConfigNamespace][gateway]...)
|
||||
- res = append(res, ps.virtualServiceIndex.publicByGateway[gateway]...)
|
||||
+
|
||||
+ // Favor same-namespace Gateway routes, to give the "consumer override" preference.
|
||||
+ // We do 2 iterations here to avoid extra allocations.
|
||||
+ for _, vs := range ps.virtualServiceIndex.publicByGateway[gateway] {
|
||||
+ if UseGatewaySemantics(vs) && vs.Namespace == proxy.ConfigNamespace {
|
||||
+ res = append(res, vs)
|
||||
+ }
|
||||
+ }
|
||||
+ for _, vs := range ps.virtualServiceIndex.publicByGateway[gateway] {
|
||||
+ if !(UseGatewaySemantics(vs) && vs.Namespace == proxy.ConfigNamespace) {
|
||||
+ res = append(res, vs)
|
||||
+ }
|
||||
+ }
|
||||
return res
|
||||
}
|
||||
|
||||
diff -Naur istio/pilot/pkg/model/virtualservice.go istio-new/pilot/pkg/model/virtualservice.go
|
||||
--- istio/pilot/pkg/model/virtualservice.go 2023-11-03 17:18:55.000000000 +0800
|
||||
+++ istio-new/pilot/pkg/model/virtualservice.go 2023-11-03 15:19:08.000000000 +0800
|
||||
@@ -76,6 +76,11 @@
|
||||
}
|
||||
|
||||
func resolveVirtualServiceShortnames(rule *networking.VirtualService, meta config.Meta) {
|
||||
+ // Kubernetes Gateway API semantics support shortnames
|
||||
+ // if UseGatewaySemantics(config.Config{Meta: meta}) {
|
||||
+ // return
|
||||
+ // }
|
||||
+
|
||||
// resolve top level hosts
|
||||
for i, h := range rule.Hosts {
|
||||
rule.Hosts[i] = string(ResolveShortnameToFQDN(h, meta))
|
||||
@@ -524,3 +529,10 @@
|
||||
}
|
||||
return false
|
||||
}
|
||||
+
|
||||
+// UseGatewaySemantics determines which logic we should use for VirtualService
|
||||
+// This allows gateway-api and VS to both be represented by VirtualService, but have different
|
||||
+// semantics.
|
||||
+func UseGatewaySemantics(cfg config.Config) bool {
|
||||
+ return cfg.Annotations[constants.InternalRouteSemantics] == constants.RouteSemanticsGateway
|
||||
+}
|
||||
diff -Naur istio/pilot/pkg/networking/core/v1alpha3/route/route.go istio-new/pilot/pkg/networking/core/v1alpha3/route/route.go
|
||||
--- istio/pilot/pkg/networking/core/v1alpha3/route/route.go 2023-11-03 17:18:56.000000000 +0800
|
||||
+++ istio-new/pilot/pkg/networking/core/v1alpha3/route/route.go 2023-11-03 17:05:55.000000000 +0800
|
||||
@@ -408,7 +408,6 @@
|
||||
break
|
||||
}
|
||||
}
|
||||
-
|
||||
if len(out) == 0 {
|
||||
return nil, fmt.Errorf("no routes matched")
|
||||
}
|
||||
@@ -493,6 +492,14 @@
|
||||
},
|
||||
}
|
||||
|
||||
+ if model.UseGatewaySemantics(virtualService) {
|
||||
+ if uri, isPrefixReplace := cutPrefix(redirect.Uri, "%PREFIX()%"); isPrefixReplace {
|
||||
+ action.Redirect.PathRewriteSpecifier = &route.RedirectAction_PrefixRewrite{
|
||||
+ PrefixRewrite: uri,
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if redirect.Scheme != "" {
|
||||
action.Redirect.SchemeRewriteSpecifier = &route.RedirectAction_SchemeRedirect{SchemeRedirect: redirect.Scheme}
|
||||
}
|
||||
@@ -1616,3 +1623,10 @@
|
||||
isSupport = curVersion.GreaterThan(notSupportFallback)
|
||||
return
|
||||
}
|
||||
+
|
||||
+func cutPrefix(s, prefix string) (after string, found bool) {
|
||||
+ if !strings.HasPrefix(s, prefix) {
|
||||
+ return s, false
|
||||
+ }
|
||||
+ return s[len(prefix):], true
|
||||
+}
|
||||
diff -Naur istio/pkg/config/constants/constants.go istio-new/pkg/config/constants/constants.go
|
||||
--- istio/pkg/config/constants/constants.go 2023-11-03 17:18:54.000000000 +0800
|
||||
+++ istio-new/pkg/config/constants/constants.go 2023-11-03 14:29:27.000000000 +0800
|
||||
@@ -15,6 +15,12 @@
|
||||
package constants
|
||||
|
||||
const (
|
||||
+ InternalParentNames = "internal.istio.io/parents"
|
||||
+
|
||||
+ InternalRouteSemantics = "internal.istio.io/route-semantics"
|
||||
+
|
||||
+ RouteSemanticsGateway = "gateway"
|
||||
+
|
||||
// UnspecifiedIP constant for empty IP address
|
||||
UnspecifiedIP = "0.0.0.0"
|
||||
|
||||
50
istio/1.12/patches/istio/20231104-gatewayapi-catchall.patch
Normal file
50
istio/1.12/patches/istio/20231104-gatewayapi-catchall.patch
Normal file
@@ -0,0 +1,50 @@
|
||||
diff -Naur istio/pilot/pkg/config/kube/gateway/conversion.go istio-new/pilot/pkg/config/kube/gateway/conversion.go
|
||||
--- istio/pilot/pkg/config/kube/gateway/conversion.go 2023-11-03 20:09:38.000000000 +0800
|
||||
+++ istio-new/pilot/pkg/config/kube/gateway/conversion.go 2023-11-03 20:02:26.000000000 +0800
|
||||
@@ -165,6 +165,34 @@
|
||||
return result
|
||||
}
|
||||
|
||||
+// isCatchAll returns true if HTTPMatchRequest is a catchall match otherwise
|
||||
+// false. Note - this may not be exactly "catch all" as we don't know the full
|
||||
+// class of possible inputs As such, this is used only for optimization.
|
||||
+func isCatchAllMatch(m *istio.HTTPMatchRequest) bool {
|
||||
+ catchall := false
|
||||
+ if m.Uri != nil {
|
||||
+ switch m := m.Uri.MatchType.(type) {
|
||||
+ case *istio.StringMatch_Prefix:
|
||||
+ catchall = m.Prefix == "/"
|
||||
+ case *istio.StringMatch_Regex:
|
||||
+ catchall = m.Regex == "*"
|
||||
+ }
|
||||
+ }
|
||||
+ // A Match is catch all if and only if it has no match set
|
||||
+ // and URI has a prefix / or regex *.
|
||||
+ return catchall &&
|
||||
+ len(m.Headers) == 0 &&
|
||||
+ len(m.QueryParams) == 0 &&
|
||||
+ len(m.SourceLabels) == 0 &&
|
||||
+ len(m.WithoutHeaders) == 0 &&
|
||||
+ len(m.Gateways) == 0 &&
|
||||
+ m.Method == nil &&
|
||||
+ m.Scheme == nil &&
|
||||
+ m.Port == 0 &&
|
||||
+ m.Authority == nil &&
|
||||
+ m.SourceNamespace == ""
|
||||
+}
|
||||
+
|
||||
// getURIRank ranks a URI match type. Exact > Prefix > Regex
|
||||
func getURIRank(match *istio.HTTPMatchRequest) int {
|
||||
if match.Uri == nil {
|
||||
@@ -212,6 +240,11 @@
|
||||
} else if len(routes[j].Match) == 0 {
|
||||
return true
|
||||
}
|
||||
+ if isCatchAllMatch(routes[i].Match[0]) {
|
||||
+ return false
|
||||
+ } else if isCatchAllMatch(routes[j].Match[0]) {
|
||||
+ return true
|
||||
+ }
|
||||
// Only look at match[0], we always generate only one match
|
||||
m1, m2 := routes[i].Match[0], routes[j].Match[0]
|
||||
r1, r2 := getURIRank(m1), getURIRank(m2)
|
||||
@@ -20,6 +20,10 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/alibaba/higress/pkg/ingress/kube/common"
|
||||
"github.com/alibaba/higress/pkg/ingress/mcp"
|
||||
"github.com/alibaba/higress/pkg/ingress/translation"
|
||||
higresskube "github.com/alibaba/higress/pkg/kube"
|
||||
prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/reflection"
|
||||
@@ -46,11 +50,6 @@ import (
|
||||
"istio.io/pkg/log"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
|
||||
ingressconfig "github.com/alibaba/higress/pkg/ingress/config"
|
||||
"github.com/alibaba/higress/pkg/ingress/kube/common"
|
||||
"github.com/alibaba/higress/pkg/ingress/mcp"
|
||||
higresskube "github.com/alibaba/higress/pkg/kube"
|
||||
)
|
||||
|
||||
type XdsOptions struct {
|
||||
@@ -225,9 +224,12 @@ func (s *Server) initConfigController() error {
|
||||
if options.ClusterId == "Kubernetes" {
|
||||
options.ClusterId = ""
|
||||
}
|
||||
ingressConfig := ingressconfig.NewIngressConfig(s.kubeClient, s.xdsServer, ns, options.ClusterId)
|
||||
ingressController := ingressConfig.AddLocalCluster(options)
|
||||
|
||||
ingressConfig := translation.NewIngressTranslation(s.kubeClient, s.xdsServer, ns, options.ClusterId)
|
||||
ingressController, kingressController := ingressConfig.AddLocalCluster(options)
|
||||
|
||||
s.configStores = append(s.configStores, ingressConfig)
|
||||
|
||||
// Wrap the config controller with a cache.
|
||||
aggregateConfigController, err := configaggregate.MakeCache(s.configStores)
|
||||
if err != nil {
|
||||
@@ -242,7 +244,7 @@ func (s *Server) initConfigController() error {
|
||||
|
||||
// Defer starting the controller until after the service is created.
|
||||
s.server.RunComponent(func(stop <-chan struct{}) error {
|
||||
if err := ingressConfig.InitializeCluster(ingressController, stop); err != nil {
|
||||
if err := ingressConfig.InitializeCluster(ingressController, kingressController, stop); err != nil {
|
||||
return err
|
||||
}
|
||||
go s.configController.Run(stop)
|
||||
|
||||
@@ -12,8 +12,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package kubernetes
|
||||
package hgctl
|
||||
|
||||
import (
|
||||
_ "github.com/alibaba/higress/test/ingress/conformance/utils/flags"
|
||||
const (
|
||||
yamlOutput = "yaml"
|
||||
jsonOutput = "json"
|
||||
flagsOutput = "flags"
|
||||
)
|
||||
@@ -33,8 +33,8 @@ var (
|
||||
)
|
||||
|
||||
const (
|
||||
adminPort = 15000
|
||||
containerName = "envoy"
|
||||
defaultProxyAdminPort = 15000
|
||||
containerName = "envoy"
|
||||
)
|
||||
|
||||
func retrieveConfigDump(args []string, includeEds bool) ([]byte, error) {
|
||||
@@ -96,7 +96,7 @@ func portForwarder(nn types.NamespacedName) (kubernetes.PortForwarder, error) {
|
||||
return nil, fmt.Errorf("pod %s is not running", nn)
|
||||
}
|
||||
|
||||
fw, err := kubernetes.NewLocalPortForwarder(c, nn, 0, adminPort)
|
||||
fw, err := kubernetes.NewLocalPortForwarder(c, nn, 0, defaultProxyAdminPort)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -34,6 +34,7 @@ type fakePortForwarder struct {
|
||||
localPort int
|
||||
l net.Listener
|
||||
mux *http.ServeMux
|
||||
stopCh chan struct{}
|
||||
}
|
||||
|
||||
func newFakePortForwarder(b []byte) (kubernetes.PortForwarder, error) {
|
||||
@@ -46,6 +47,7 @@ func newFakePortForwarder(b []byte) (kubernetes.PortForwarder, error) {
|
||||
responseBody: b,
|
||||
localPort: p,
|
||||
mux: http.NewServeMux(),
|
||||
stopCh: make(chan struct{}),
|
||||
}
|
||||
fw.mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = w.Write(fw.responseBody)
|
||||
@@ -54,6 +56,10 @@ func newFakePortForwarder(b []byte) (kubernetes.PortForwarder, error) {
|
||||
return fw, nil
|
||||
}
|
||||
|
||||
func (fw *fakePortForwarder) WaitForStop() {
|
||||
<-fw.stopCh
|
||||
}
|
||||
|
||||
func (fw *fakePortForwarder) Start() error {
|
||||
l, err := net.Listen("tcp", fw.Address())
|
||||
if err != nil {
|
||||
|
||||
387
pkg/cmd/hgctl/dashboard.go
Normal file
387
pkg/cmd/hgctl/dashboard.go
Normal file
@@ -0,0 +1,387 @@
|
||||
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package hgctl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/kubernetes"
|
||||
"github.com/alibaba/higress/pkg/cmd/options"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
var (
|
||||
listenPort = 0
|
||||
promPort = 0
|
||||
grafanaPort = 0
|
||||
consolePort = 0
|
||||
controllerPort = 0
|
||||
|
||||
bindAddress = "localhost"
|
||||
|
||||
// open browser or not, default is true
|
||||
browser = true
|
||||
|
||||
// label selector
|
||||
labelSelector = ""
|
||||
|
||||
addonNamespace = ""
|
||||
|
||||
envoyDashNs = ""
|
||||
|
||||
proxyAdminPort int
|
||||
)
|
||||
|
||||
const (
|
||||
defaultPrometheusPort = 9090
|
||||
defaultGrafanaPort = 3000
|
||||
defaultConsolePort = 8080
|
||||
defaultControllerPort = 8888
|
||||
)
|
||||
|
||||
func newDashboardCmd() *cobra.Command {
|
||||
dashboardCmd := &cobra.Command{
|
||||
Use: "dashboard",
|
||||
Aliases: []string{"dash", "d"},
|
||||
Short: "Access to Higress web UIs",
|
||||
Args: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 0 {
|
||||
return fmt.Errorf("unknown dashboard %q", args[0])
|
||||
}
|
||||
return nil
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cmd.HelpFunc()(cmd, args)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
dashboardCmd.PersistentFlags().IntVarP(&listenPort, "port", "p", 0, "Local port to listen to")
|
||||
dashboardCmd.PersistentFlags().BoolVar(&browser, "browser", true,
|
||||
"When --browser is supplied as false, hgctl dashboard will not open the browser. "+
|
||||
"Default is true which means hgctl dashboard will always open a browser to view the dashboard.")
|
||||
dashboardCmd.PersistentFlags().StringVarP(&addonNamespace, "namespace", "n", "higress-system",
|
||||
"Namespace where the addon is running, if not specified, higress-system would be used")
|
||||
|
||||
prom := promDashCmd()
|
||||
prom.PersistentFlags().IntVar(&promPort, "ui-port", defaultPrometheusPort, "The component dashboard UI port.")
|
||||
dashboardCmd.AddCommand(prom)
|
||||
|
||||
graf := grafanaDashCmd()
|
||||
graf.PersistentFlags().IntVar(&grafanaPort, "ui-port", defaultGrafanaPort, "The component dashboard UI port.")
|
||||
dashboardCmd.AddCommand(graf)
|
||||
|
||||
envoy := envoyDashCmd()
|
||||
envoy.PersistentFlags().StringVarP(&labelSelector, "selector", "l", "app=higress-gateway", "Label selector")
|
||||
envoy.PersistentFlags().StringVarP(&envoyDashNs, "namespace", "n", "",
|
||||
"Namespace where the addon is running, if not specified, higress-system would be used")
|
||||
envoy.PersistentFlags().IntVar(&proxyAdminPort, "ui-port", defaultProxyAdminPort, "The component dashboard UI port.")
|
||||
dashboardCmd.AddCommand(envoy)
|
||||
|
||||
consoleCmd := consoleDashCmd()
|
||||
consoleCmd.PersistentFlags().IntVar(&consolePort, "ui-port", defaultConsolePort, "The component dashboard UI port.")
|
||||
dashboardCmd.AddCommand(consoleCmd)
|
||||
|
||||
controllerDebugCmd := controllerDebugCmd()
|
||||
controllerDebugCmd.PersistentFlags().IntVar(&controllerPort, "ui-port", defaultControllerPort, "The component dashboard UI port.")
|
||||
dashboardCmd.AddCommand(controllerDebugCmd)
|
||||
flags := dashboardCmd.PersistentFlags()
|
||||
options.AddKubeConfigFlags(flags)
|
||||
return dashboardCmd
|
||||
}
|
||||
|
||||
// port-forward to Higress System Prometheus; open browser
|
||||
func promDashCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "prometheus",
|
||||
Short: "Open Prometheus web UI",
|
||||
Long: `Open Higress's Prometheus dashboard`,
|
||||
Example: ` hgctl dashboard prometheus
|
||||
|
||||
# with short syntax
|
||||
hgctl dash prometheus
|
||||
hgctl d prometheus`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
client, err := kubernetes.NewCLIClient(options.DefaultConfigFlags.ToRawKubeConfigLoader())
|
||||
if err != nil {
|
||||
return fmt.Errorf("build CLI client fail: %w", err)
|
||||
}
|
||||
|
||||
pl, err := client.PodsForSelector(addonNamespace, "app=higress-console-prometheus")
|
||||
if err != nil {
|
||||
return fmt.Errorf("not able to locate Prometheus pod: %v", err)
|
||||
}
|
||||
|
||||
if len(pl.Items) < 1 {
|
||||
return errors.New("no Prometheus pods found")
|
||||
}
|
||||
|
||||
// only use the first pod in the list
|
||||
return portForward(pl.Items[0].Name, addonNamespace, "Prometheus",
|
||||
"http://%s", bindAddress, promPort, client, cmd.OutOrStdout(), browser)
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// port-forward to Higress System Console; open browser
|
||||
func consoleDashCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "console",
|
||||
Short: "Open Console web UI",
|
||||
Long: `Open Higress Console`,
|
||||
Example: ` hgctl dashboard console
|
||||
|
||||
# with short syntax
|
||||
hgctl dash console
|
||||
hgctl d console`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
client, err := kubernetes.NewCLIClient(options.DefaultConfigFlags.ToRawKubeConfigLoader())
|
||||
if err != nil {
|
||||
return fmt.Errorf("build CLI client fail: %w", err)
|
||||
}
|
||||
|
||||
pl, err := client.PodsForSelector(addonNamespace, "app.kubernetes.io/name=higress-console")
|
||||
if err != nil {
|
||||
return fmt.Errorf("not able to locate console pod: %v", err)
|
||||
}
|
||||
|
||||
if len(pl.Items) < 1 {
|
||||
return errors.New("no higress console pods found")
|
||||
}
|
||||
|
||||
// only use the first pod in the list
|
||||
return portForward(pl.Items[0].Name, addonNamespace, "Console",
|
||||
"http://%s", bindAddress, consolePort, client, cmd.OutOrStdout(), browser)
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// port-forward to Higress System Grafana; open browser
|
||||
func grafanaDashCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "grafana",
|
||||
Short: "Open Grafana web UI",
|
||||
Long: `Open Higress's Grafana dashboard`,
|
||||
Example: ` hgctl dashboard grafana
|
||||
|
||||
# with short syntax
|
||||
hgctl dash grafana
|
||||
hgctl d grafana`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
client, err := kubernetes.NewCLIClient(options.DefaultConfigFlags.ToRawKubeConfigLoader())
|
||||
if err != nil {
|
||||
return fmt.Errorf("build CLI client fail: %w", err)
|
||||
}
|
||||
pl, err := client.PodsForSelector(addonNamespace, "app=higress-console-grafana")
|
||||
if err != nil {
|
||||
return fmt.Errorf("not able to locate Grafana pod: %v", err)
|
||||
}
|
||||
|
||||
if len(pl.Items) < 1 {
|
||||
return errors.New("no Grafana pods found")
|
||||
}
|
||||
|
||||
// only use the first pod in the list
|
||||
return portForward(pl.Items[0].Name, addonNamespace, "Grafana",
|
||||
"http://%s", bindAddress, grafanaPort, client, cmd.OutOrStdout(), browser)
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// port-forward to sidecar Envoy admin port; open browser
|
||||
func envoyDashCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "envoy [<type>/]<name>[.<namespace>]",
|
||||
Short: "Open Envoy admin web UI",
|
||||
Long: `Open the Envoy admin dashboard for a higress gateway`,
|
||||
Example: ` # Open Envoy dashboard for the higress-gateway-56f9b9797-b9nnc
|
||||
hgctl dashboard envoy higress-gateway-56f9b9797-b9nnc
|
||||
|
||||
# with short syntax
|
||||
hgctl dash envoy
|
||||
hgctl d envoy
|
||||
`,
|
||||
RunE: func(c *cobra.Command, args []string) error {
|
||||
kubeClient, err := kubernetes.NewCLIClient(options.DefaultConfigFlags.ToRawKubeConfigLoader())
|
||||
if err != nil {
|
||||
return fmt.Errorf("build CLI client fail: %w", err)
|
||||
}
|
||||
|
||||
if labelSelector == "" && len(args) < 1 {
|
||||
c.Println(c.UsageString())
|
||||
return fmt.Errorf("specify a pod or --selector")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create k8s client: %v", err)
|
||||
}
|
||||
|
||||
var podName, ns string
|
||||
if labelSelector != "" {
|
||||
pl, err := kubeClient.PodsForSelector(envoyDashNs, labelSelector)
|
||||
if err != nil {
|
||||
return fmt.Errorf("not able to locate pod with selector %s: %v", labelSelector, err)
|
||||
}
|
||||
|
||||
if len(pl.Items) < 1 {
|
||||
return errors.New("no pods found")
|
||||
}
|
||||
// only use the first pod in the list
|
||||
podName = pl.Items[0].Name
|
||||
ns = pl.Items[0].Namespace
|
||||
} else if len(args) > 0 {
|
||||
po, err := kubeClient.Pod(types.NamespacedName{Name: args[0], Namespace: envoyDashNs})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
podName = po.Name
|
||||
ns = po.Namespace
|
||||
}
|
||||
|
||||
return portForward(podName, ns, fmt.Sprintf("Envoy sidecar %s", podName),
|
||||
"http://%s", bindAddress, proxyAdminPort, kubeClient, c.OutOrStdout(), browser)
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// port-forward to Higress System Console; open browser
|
||||
func controllerDebugCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "controller",
|
||||
Short: "Open Controller debug web UI",
|
||||
Long: `Open Higress Controller`,
|
||||
Example: ` hgctl dashboard controller
|
||||
|
||||
# with short syntax
|
||||
hgctl dash controller
|
||||
hgctl d controller`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
client, err := kubernetes.NewCLIClient(options.DefaultConfigFlags.ToRawKubeConfigLoader())
|
||||
if err != nil {
|
||||
return fmt.Errorf("build CLI client fail: %w", err)
|
||||
}
|
||||
|
||||
pl, err := client.PodsForSelector(addonNamespace, "app=higress-controller")
|
||||
if err != nil {
|
||||
return fmt.Errorf("not able to locate controller pod: %v", err)
|
||||
}
|
||||
|
||||
if len(pl.Items) < 1 {
|
||||
return errors.New("no higress controller pods found")
|
||||
}
|
||||
|
||||
// only use the first pod in the list
|
||||
return portForward(pl.Items[0].Name, addonNamespace, "Controller",
|
||||
"http://%s/debug", bindAddress, controllerPort, client, cmd.OutOrStdout(), browser)
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// portForward first tries to forward localhost:remotePort to podName:remotePort, falls back to dynamic local port
|
||||
func portForward(podName, namespace, flavor, urlFormat, localAddress string, remotePort int,
|
||||
client kubernetes.CLIClient, writer io.Writer, browser bool,
|
||||
) error {
|
||||
// port preference:
|
||||
// - If --listenPort is specified, use it
|
||||
// - without --listenPort, prefer the remotePort but fall back to a random port
|
||||
var portPrefs []int
|
||||
if listenPort != 0 {
|
||||
portPrefs = []int{listenPort}
|
||||
} else {
|
||||
portPrefs = []int{remotePort}
|
||||
}
|
||||
|
||||
var err error
|
||||
for _, localPort := range portPrefs {
|
||||
var fw kubernetes.PortForwarder
|
||||
fw, err = kubernetes.NewLocalPortForwarder(client, types.NamespacedName{Namespace: namespace, Name: podName}, localPort, remotePort)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not build port forwarder for %s: %v", flavor, err)
|
||||
}
|
||||
|
||||
if err := fw.Start(); err != nil {
|
||||
fw.Stop()
|
||||
// Try the next port
|
||||
continue
|
||||
}
|
||||
|
||||
// Close the port forwarder when the command is terminated.
|
||||
ClosePortForwarderOnInterrupt(fw)
|
||||
|
||||
openBrowser(fmt.Sprintf(urlFormat, fw.Address()), writer, browser)
|
||||
|
||||
// Wait for stop
|
||||
fw.WaitForStop()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failure running port forward process: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ClosePortForwarderOnInterrupt(fw kubernetes.PortForwarder) {
|
||||
go func() {
|
||||
signals := make(chan os.Signal, 1)
|
||||
signal.Notify(signals, os.Interrupt)
|
||||
defer signal.Stop(signals)
|
||||
<-signals
|
||||
fw.Stop()
|
||||
}()
|
||||
}
|
||||
|
||||
func openBrowser(url string, writer io.Writer, browser bool) {
|
||||
var err error
|
||||
|
||||
fmt.Fprintf(writer, "%s\n", url)
|
||||
|
||||
if !browser {
|
||||
fmt.Fprint(writer, "skipping opening a browser")
|
||||
return
|
||||
}
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
err = exec.Command("xdg-open", url).Start()
|
||||
case "windows":
|
||||
err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
|
||||
case "darwin":
|
||||
err = exec.Command("open", url).Start()
|
||||
default:
|
||||
fmt.Fprintf(writer, "Unsupported platform %q; open %s in your browser.\n", runtime.GOOS, url)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintf(writer, "Failed to open browser; open %s in your browser.\nError: %s\n", url, err.Error())
|
||||
}
|
||||
}
|
||||
111
pkg/cmd/hgctl/docker/compose.go
Normal file
111
pkg/cmd/hgctl/docker/compose.go
Normal file
@@ -0,0 +1,111 @@
|
||||
// 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 docker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/flags"
|
||||
"github.com/docker/compose/v2/cmd/formatter"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/compose"
|
||||
)
|
||||
|
||||
type Compose struct {
|
||||
client *api.ServiceProxy
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
func NewCompose(w io.Writer) (*Compose, error) {
|
||||
c := &Compose{w: w}
|
||||
|
||||
dockerCli, err := command.NewDockerCli(
|
||||
command.WithCombinedStreams(c.w),
|
||||
// command.WithDefaultContextStoreConfig(), Deprecated, set during NewDockerCli
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
opts := flags.NewClientOptions()
|
||||
err = dockerCli.Initialize(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.client = api.NewServiceProxy().WithService(compose.NewComposeService(dockerCli.Client(), dockerCli.ConfigFile()))
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c Compose) Up(ctx context.Context, name string, configs []string, source string, detach bool) error {
|
||||
pOpts, err := cli.NewProjectOptions(
|
||||
configs,
|
||||
cli.WithWorkingDirectory(source),
|
||||
cli.WithDefaultConfigPath,
|
||||
cli.WithName(name),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
project, err := cli.ProjectFromOptions(pOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i, s := range project.Services {
|
||||
// TODO(WeixinX): Change from `Label` to `CustomLabels` after upgrading the dependency library github.com/compose-spec/compose-go
|
||||
s.Labels = map[string]string{
|
||||
api.ProjectLabel: project.Name,
|
||||
api.ServiceLabel: s.Name,
|
||||
api.VersionLabel: api.ComposeVersion,
|
||||
api.WorkingDirLabel: project.WorkingDir,
|
||||
api.ConfigFilesLabel: strings.Join(project.ComposeFiles, ","),
|
||||
api.OneoffLabel: "False",
|
||||
}
|
||||
project.Services[i] = s
|
||||
}
|
||||
project.WithoutUnnecessaryResources()
|
||||
|
||||
// for log
|
||||
var consumer api.LogConsumer
|
||||
if !detach {
|
||||
// TODO(WeixinX): Change to `formatter.NewLogConsumer(ctx, c.w, c.w, true, true, false)` after upgrading the dependency library github.com/compose-spec/compose-go
|
||||
consumer = formatter.NewLogConsumer(ctx, c.w, true, true)
|
||||
}
|
||||
attachTo := make([]string, 0)
|
||||
for _, svc := range project.Services {
|
||||
attachTo = append(attachTo, svc.Name)
|
||||
}
|
||||
|
||||
return c.client.Up(ctx, project, api.UpOptions{
|
||||
Start: api.StartOptions{
|
||||
Attach: consumer,
|
||||
AttachTo: attachTo,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (c Compose) List(ctx context.Context) ([]api.Stack, error) {
|
||||
return c.client.List(ctx, api.ListOptions{})
|
||||
}
|
||||
|
||||
func (c Compose) Down(ctx context.Context, name string) error {
|
||||
return c.client.Down(ctx, name, api.DownOptions{})
|
||||
}
|
||||
327
pkg/cmd/hgctl/helm/common.go
Normal file
327
pkg/cmd/hgctl/helm/common.go
Normal file
@@ -0,0 +1,327 @@
|
||||
// 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 helm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/helm/tpath"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/util"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// GetProfileFromFlags get profile name from flags.
|
||||
func GetProfileFromFlags(setFlags []string) (string, error) {
|
||||
profileName := DefaultProfileName
|
||||
// The profile coming from --set flag has the highest precedence.
|
||||
psf := GetValueForSetFlag(setFlags, "profile")
|
||||
if psf != "" {
|
||||
profileName = psf
|
||||
}
|
||||
return profileName, nil
|
||||
}
|
||||
|
||||
func GetValuesOverylayFromFiles(inFilenames []string) (string, error) {
|
||||
// Convert layeredYamls under values node in profile file to support helm values
|
||||
overLayYamls := ""
|
||||
// Get Overlays from files
|
||||
if len(inFilenames) > 0 {
|
||||
layeredYamls, err := ReadLayeredYAMLs(inFilenames)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
vals := make(map[string]any)
|
||||
if err := yaml.Unmarshal([]byte(layeredYamls), &vals); err != nil {
|
||||
return "", fmt.Errorf("%s:\n\nYAML:\n%s", err, layeredYamls)
|
||||
}
|
||||
values := make(map[string]any)
|
||||
values["values"] = vals
|
||||
out, err := yaml.Marshal(values)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
overLayYamls = string(out)
|
||||
}
|
||||
|
||||
return overLayYamls, nil
|
||||
}
|
||||
|
||||
func GetUninstallProfileName() string {
|
||||
return DefaultUninstallProfileName
|
||||
}
|
||||
|
||||
func ReadLayeredYAMLs(filenames []string) (string, error) {
|
||||
return readLayeredYAMLs(filenames, os.Stdin)
|
||||
}
|
||||
|
||||
func readLayeredYAMLs(filenames []string, stdinReader io.Reader) (string, error) {
|
||||
var ly string
|
||||
var stdin bool
|
||||
for _, fn := range filenames {
|
||||
var b []byte
|
||||
var err error
|
||||
if fn == "-" {
|
||||
if stdin {
|
||||
continue
|
||||
}
|
||||
stdin = true
|
||||
b, err = io.ReadAll(stdinReader)
|
||||
} else {
|
||||
b, err = os.ReadFile(strings.TrimSpace(fn))
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
ly, err = util.OverlayYAML(ly, string(b))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return ly, nil
|
||||
}
|
||||
|
||||
// GetValueForSetFlag parses the passed set flags which have format key=value and if any set the given path,
|
||||
// returns the corresponding value, otherwise returns the empty string. setFlags must have valid format.
|
||||
func GetValueForSetFlag(setFlags []string, path string) string {
|
||||
ret := ""
|
||||
for _, sf := range setFlags {
|
||||
p, v := getPV(sf)
|
||||
if p == path {
|
||||
ret = v
|
||||
}
|
||||
// if set multiple times, return last set value
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// getPV returns the path and value components for the given set flag string, which must be in path=value format.
|
||||
func getPV(setFlag string) (path string, value string) {
|
||||
pv := strings.Split(setFlag, "=")
|
||||
if len(pv) != 2 {
|
||||
return setFlag, ""
|
||||
}
|
||||
path, value = strings.TrimSpace(pv[0]), strings.TrimSpace(pv[1])
|
||||
return
|
||||
}
|
||||
|
||||
func GenerateConfig(inFilenames []string, setFlags []string) (string, *Profile, string, error) {
|
||||
if err := validateSetFlags(setFlags); err != nil {
|
||||
return "", nil, "", err
|
||||
}
|
||||
|
||||
profileName, err := GetProfileFromFlags(setFlags)
|
||||
if err != nil {
|
||||
return "", nil, "", err
|
||||
}
|
||||
|
||||
valuesOverlay, err := GetValuesOverylayFromFiles(inFilenames)
|
||||
if err != nil {
|
||||
return "", nil, "", err
|
||||
}
|
||||
|
||||
profileString, profile, err := GenProfile(profileName, valuesOverlay, setFlags)
|
||||
|
||||
if err != nil {
|
||||
return "", nil, "", err
|
||||
}
|
||||
|
||||
return profileString, profile, profileName, nil
|
||||
}
|
||||
|
||||
// validateSetFlags validates that setFlags all have path=value format.
|
||||
func validateSetFlags(setFlags []string) error {
|
||||
for _, sf := range setFlags {
|
||||
pv := strings.Split(sf, "=")
|
||||
if len(pv) != 2 {
|
||||
return fmt.Errorf("set flag %s has incorrect format, must be path=value", sf)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func overlaySetFlagValues(iopYAML string, setFlags []string) (string, error) {
|
||||
iop := make(map[string]any)
|
||||
if err := yaml.Unmarshal([]byte(iopYAML), &iop); err != nil {
|
||||
return "", err
|
||||
}
|
||||
// Unmarshal returns nil for empty manifests but we need something to insert into.
|
||||
if iop == nil {
|
||||
iop = make(map[string]any)
|
||||
}
|
||||
|
||||
for _, sf := range setFlags {
|
||||
p, v := getPV(sf)
|
||||
inc, _, err := tpath.GetPathContext(iop, util.PathFromString(p), true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// input value type is always string, transform it to correct type before setting.
|
||||
if err := tpath.WritePathContext(inc, util.ParseValue(v), false); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
out, err := yaml.Marshal(iop)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(out), nil
|
||||
}
|
||||
|
||||
// getInstallPackagePath returns the installPackagePath in the given IstioOperator YAML string.
|
||||
func getInstallPackagePath(profileYAML string) (string, error) {
|
||||
profile, err := UnmarshalProfile(profileYAML)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if profile == nil {
|
||||
return "", nil
|
||||
}
|
||||
return profile.InstallPackagePath, nil
|
||||
}
|
||||
|
||||
// GetProfileYAML returns the YAML for the given profile name, using the given profileOrPath string, which may be either
|
||||
// a profile label or a file path.
|
||||
func GetProfileYAML(installPackagePath, profileOrPath string) (string, error) {
|
||||
if profileOrPath == "" {
|
||||
profileOrPath = DefaultProfileFilename
|
||||
}
|
||||
profiles, err := readProfiles(installPackagePath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to read profiles: %v", err)
|
||||
}
|
||||
// If charts are a file path and profile is a name like default, transform it to the file path.
|
||||
if profiles[profileOrPath] && installPackagePath != "" {
|
||||
profileOrPath = filepath.Join(installPackagePath, "profiles", profileOrPath+".yaml")
|
||||
}
|
||||
// This contains the IstioOperator CR.
|
||||
baseCRYAML, err := ReadProfileYAML(profileOrPath, installPackagePath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
//if !IsDefaultProfile(profileOrPath) {
|
||||
// // Profile definitions are relative to the default profileOrPath, so read that first.
|
||||
// dfn := DefaultFilenameForProfile(profileOrPath)
|
||||
// defaultYAML, err := ReadProfileYAML(dfn, installPackagePath)
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
// baseCRYAML, err = util.OverlayYAML(defaultYAML, baseCRYAML)
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
//}
|
||||
return baseCRYAML, nil
|
||||
}
|
||||
|
||||
// IsDefaultProfile reports whether the given profile is the default profile.
|
||||
func IsDefaultProfile(profile string) bool {
|
||||
return profile == "" || profile == DefaultProfileName || filepath.Base(profile) == DefaultProfileFilename
|
||||
}
|
||||
|
||||
// DefaultFilenameForProfile returns the profile name of the default profile for the given profile.
|
||||
func DefaultFilenameForProfile(profile string) string {
|
||||
switch {
|
||||
case util.IsFilePath(profile):
|
||||
return filepath.Join(filepath.Dir(profile), DefaultProfileFilename)
|
||||
default:
|
||||
return DefaultProfileName
|
||||
}
|
||||
}
|
||||
|
||||
// ReadProfileYAML reads the YAML values associated with the given profile. It uses an appropriate reader for the
|
||||
// profile format (compiled-in, file, HTTP, etc.).
|
||||
func ReadProfileYAML(profile, manifestsPath string) (string, error) {
|
||||
var err error
|
||||
var globalValues string
|
||||
|
||||
// Get global values from profile.
|
||||
switch {
|
||||
case util.IsFilePath(profile):
|
||||
if globalValues, err = readFile(profile); err != nil {
|
||||
return "", err
|
||||
}
|
||||
default:
|
||||
if globalValues, err = LoadValues(profile, manifestsPath); err != nil {
|
||||
return "", fmt.Errorf("failed to read profile %v from %v: %v", profile, manifestsPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
return globalValues, nil
|
||||
}
|
||||
|
||||
func readFile(path string) (string, error) {
|
||||
b, err := os.ReadFile(path)
|
||||
return string(b), err
|
||||
}
|
||||
|
||||
// UnmarshalProfile unmarshals a string containing Profile as YAML.
|
||||
func UnmarshalProfile(profileYAML string) (*Profile, error) {
|
||||
profile := &Profile{}
|
||||
if err := yaml.Unmarshal([]byte(profileYAML), profile); err != nil {
|
||||
return nil, fmt.Errorf("%s:\n\nYAML:\n%s", err, profileYAML)
|
||||
}
|
||||
return profile, nil
|
||||
}
|
||||
|
||||
// GenProfile generates an Profile from the given profile name or path, and overlay YAMLs from user
|
||||
// files and the --set flag. If successful, it returns an Profile string and struct.
|
||||
func GenProfile(profileOrPath, fileOverlayYAML string, setFlags []string) (string, *Profile, error) {
|
||||
installPackagePath, err := getInstallPackagePath(fileOverlayYAML)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if sfp := GetValueForSetFlag(setFlags, "installPackagePath"); sfp != "" {
|
||||
// set flag installPackagePath has the highest precedence, if set.
|
||||
installPackagePath = sfp
|
||||
}
|
||||
|
||||
// To generate the base profileOrPath for overlaying with user values, we need the installPackagePath where the profiles
|
||||
// can be found, and the selected profileOrPath. Both of these can come from either the user overlay file or --set flag.
|
||||
outYAML, err := GetProfileYAML(installPackagePath, profileOrPath)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
// Combine file and --set overlays and translate any K8s settings in values to Profile format
|
||||
overlayYAML, err := overlaySetFlagValues(fileOverlayYAML, setFlags)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
// Merge user file and --set flags.
|
||||
outYAML, err = util.OverlayYAML(outYAML, overlayYAML)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("could not overlay user config over base: %s", err)
|
||||
}
|
||||
|
||||
finalProfile, err := UnmarshalProfile(outYAML)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
finalProfile.InstallPackagePath = installPackagePath
|
||||
|
||||
if finalProfile.Profile == "" {
|
||||
finalProfile.Profile = DefaultProfileName
|
||||
}
|
||||
return util.ToYAML(finalProfile), finalProfile, nil
|
||||
}
|
||||
63
pkg/cmd/hgctl/helm/name/name.go
Normal file
63
pkg/cmd/hgctl/helm/name/name.go
Normal file
@@ -0,0 +1,63 @@
|
||||
// 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 name
|
||||
|
||||
// Kubernetes Kind strings.
|
||||
const (
|
||||
CRDStr = "CustomResourceDefinition"
|
||||
ClusterRoleStr = "ClusterRole"
|
||||
ClusterRoleBindingStr = "ClusterRoleBinding"
|
||||
CMStr = "ConfigMap"
|
||||
DaemonSetStr = "DaemonSet"
|
||||
DeploymentStr = "Deployment"
|
||||
EndpointStr = "Endpoints"
|
||||
HPAStr = "HorizontalPodAutoscaler"
|
||||
IngressStr = "Ingress"
|
||||
IstioOperator = "IstioOperator"
|
||||
MutatingWebhookConfigurationStr = "MutatingWebhookConfiguration"
|
||||
NamespaceStr = "Namespace"
|
||||
PVCStr = "PersistentVolumeClaim"
|
||||
PodStr = "Pod"
|
||||
PDBStr = "PodDisruptionBudget"
|
||||
ReplicationControllerStr = "ReplicationController"
|
||||
ReplicaSetStr = "ReplicaSet"
|
||||
RoleStr = "Role"
|
||||
RoleBindingStr = "RoleBinding"
|
||||
SAStr = "ServiceAccount"
|
||||
ServiceStr = "Service"
|
||||
SecretStr = "Secret"
|
||||
StatefulSetStr = "StatefulSet"
|
||||
ValidatingWebhookConfigurationStr = "ValidatingWebhookConfiguration"
|
||||
)
|
||||
|
||||
// Istio Kind strings
|
||||
const (
|
||||
EnvoyFilterStr = "EnvoyFilter"
|
||||
GatewayStr = "Gateway"
|
||||
DestinationRuleStr = "DestinationRule"
|
||||
MeshPolicyStr = "MeshPolicy"
|
||||
PeerAuthenticationStr = "PeerAuthentication"
|
||||
VirtualServiceStr = "VirtualService"
|
||||
IstioOperatorStr = "IstioOperator"
|
||||
)
|
||||
|
||||
// Istio API Group Names
|
||||
const (
|
||||
AuthenticationAPIGroupName = "authentication.istio.io"
|
||||
ConfigAPIGroupName = "config.istio.io"
|
||||
NetworkingAPIGroupName = "networking.istio.io"
|
||||
OperatorAPIGroupName = "operator.istio.io"
|
||||
SecurityAPIGroupName = "security.istio.io"
|
||||
)
|
||||
573
pkg/cmd/hgctl/helm/object/objects.go
Normal file
573
pkg/cmd/hgctl/helm/object/objects.go
Normal file
@@ -0,0 +1,573 @@
|
||||
// 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 object
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
names "github.com/alibaba/higress/pkg/cmd/hgctl/helm/name"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/helm/tpath"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/util"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
k8syaml "k8s.io/apimachinery/pkg/util/yaml"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
const (
|
||||
// YAMLSeparator is a separator for multi-document YAML files.
|
||||
YAMLSeparator = "\n---\n"
|
||||
)
|
||||
|
||||
// K8sObject is an in-memory representation of a k8s object, used for moving between different representations
|
||||
// (Unstructured, JSON, YAML) with cached rendering.
|
||||
type K8sObject struct {
|
||||
object *unstructured.Unstructured
|
||||
|
||||
Group string
|
||||
Kind string
|
||||
Name string
|
||||
Namespace string
|
||||
|
||||
json []byte
|
||||
yaml []byte
|
||||
}
|
||||
|
||||
// NewK8sObject creates a new K8sObject and returns a ptr to it.
|
||||
func NewK8sObject(u *unstructured.Unstructured, json, yaml []byte) *K8sObject {
|
||||
o := &K8sObject{
|
||||
object: u,
|
||||
json: json,
|
||||
yaml: yaml,
|
||||
}
|
||||
|
||||
gvk := u.GetObjectKind().GroupVersionKind()
|
||||
o.Group = gvk.Group
|
||||
o.Kind = gvk.Kind
|
||||
o.Name = u.GetName()
|
||||
o.Namespace = u.GetNamespace()
|
||||
|
||||
return o
|
||||
}
|
||||
|
||||
// Hash returns a unique, insecure hash based on kind, namespace and name.
|
||||
func Hash(kind, namespace, name string) string {
|
||||
switch kind {
|
||||
case names.ClusterRoleStr, names.ClusterRoleBindingStr, names.MeshPolicyStr:
|
||||
namespace = ""
|
||||
}
|
||||
return strings.Join([]string{kind, namespace, name}, ":")
|
||||
}
|
||||
|
||||
// FromHash parses kind, namespace and name from a hash.
|
||||
func FromHash(hash string) (kind, namespace, name string) {
|
||||
hv := strings.Split(hash, ":")
|
||||
if len(hv) != 3 {
|
||||
return "Bad hash string: " + hash, "", ""
|
||||
}
|
||||
kind, namespace, name = hv[0], hv[1], hv[2]
|
||||
return
|
||||
}
|
||||
|
||||
// HashNameKind returns a unique, insecure hash based on kind and name.
|
||||
func HashNameKind(kind, name string) string {
|
||||
return strings.Join([]string{kind, name}, ":")
|
||||
}
|
||||
|
||||
// ParseJSONToK8sObject parses JSON to an K8sObject.
|
||||
func ParseJSONToK8sObject(json []byte) (*K8sObject, error) {
|
||||
o, _, err := unstructured.UnstructuredJSONScheme.Decode(json, nil, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing json into unstructured object: %v", err)
|
||||
}
|
||||
|
||||
u, ok := o.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("parsed unexpected type %T", o)
|
||||
}
|
||||
|
||||
return NewK8sObject(u, json, nil), nil
|
||||
}
|
||||
|
||||
// ParseYAMLToK8sObject parses YAML to an Object.
|
||||
func ParseYAMLToK8sObject(yaml []byte) (*K8sObject, error) {
|
||||
r := bytes.NewReader(yaml)
|
||||
decoder := k8syaml.NewYAMLOrJSONDecoder(r, 1024)
|
||||
|
||||
out := &unstructured.Unstructured{}
|
||||
err := decoder.Decode(out)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding object %v: %v", string(yaml), err)
|
||||
}
|
||||
return NewK8sObject(out, nil, yaml), nil
|
||||
}
|
||||
|
||||
// UnstructuredObject exposes the raw object, primarily for testing
|
||||
func (o *K8sObject) UnstructuredObject() *unstructured.Unstructured {
|
||||
return o.object
|
||||
}
|
||||
|
||||
// ResolveK8sConflict - This method resolves k8s object possible
|
||||
// conflicting settings. Which K8sObjects may need such method
|
||||
// depends on the type of the K8sObject.
|
||||
func (o *K8sObject) ResolveK8sConflict() *K8sObject {
|
||||
if o.Kind == names.PDBStr {
|
||||
return resolvePDBConflict(o)
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
// Unstructured exposes the raw object content, primarily for testing
|
||||
func (o *K8sObject) Unstructured() map[string]any {
|
||||
return o.UnstructuredObject().UnstructuredContent()
|
||||
}
|
||||
|
||||
// Container returns a container subtree for Deployment objects if one is found, or nil otherwise.
|
||||
func (o *K8sObject) Container(name string) map[string]any {
|
||||
u := o.Unstructured()
|
||||
path := fmt.Sprintf("spec.template.spec.containers.[name:%s]", name)
|
||||
node, f, err := tpath.GetPathContext(u, util.PathFromString(path), false)
|
||||
if err == nil && f {
|
||||
// Must be the type from the schema.
|
||||
return node.Node.(map[string]any)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GroupVersionKind returns the GroupVersionKind for the K8sObject
|
||||
func (o *K8sObject) GroupVersionKind() schema.GroupVersionKind {
|
||||
return o.object.GroupVersionKind()
|
||||
}
|
||||
|
||||
// Version returns the APIVersion of the K8sObject
|
||||
func (o *K8sObject) Version() string {
|
||||
return o.object.GetAPIVersion()
|
||||
}
|
||||
|
||||
// Hash returns a unique hash for the K8sObject
|
||||
func (o *K8sObject) Hash() string {
|
||||
return Hash(o.Kind, o.Namespace, o.Name)
|
||||
}
|
||||
|
||||
// HashNameKind returns a hash for the K8sObject based on the name and kind only.
|
||||
func (o *K8sObject) HashNameKind() string {
|
||||
return HashNameKind(o.Kind, o.Name)
|
||||
}
|
||||
|
||||
// JSON returns a JSON representation of the K8sObject, using an internal cache.
|
||||
func (o *K8sObject) JSON() ([]byte, error) {
|
||||
if o.json != nil {
|
||||
return o.json, nil
|
||||
}
|
||||
|
||||
b, err := o.object.MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// YAML returns a YAML representation of the K8sObject, using an internal cache.
|
||||
func (o *K8sObject) YAML() ([]byte, error) {
|
||||
if o == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if o.yaml != nil {
|
||||
return o.yaml, nil
|
||||
}
|
||||
oj, err := o.JSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
o.json = oj
|
||||
y, err := yaml.JSONToYAML(oj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
o.yaml = y
|
||||
return y, nil
|
||||
}
|
||||
|
||||
// YAMLDebugString returns a YAML representation of the K8sObject, or an error string if the K8sObject cannot be rendered to YAML.
|
||||
func (o *K8sObject) YAMLDebugString() string {
|
||||
y, err := o.YAML()
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return string(y)
|
||||
}
|
||||
|
||||
// K8sObjects holds a collection of k8s objects, so that we can filter / sequence them
|
||||
type K8sObjects []*K8sObject
|
||||
|
||||
// String implements the Stringer interface.
|
||||
func (os K8sObjects) String() string {
|
||||
var out []string
|
||||
for _, oo := range os {
|
||||
out = append(out, oo.YAMLDebugString())
|
||||
}
|
||||
return strings.Join(out, YAMLSeparator)
|
||||
}
|
||||
|
||||
// Keys returns a slice with the keys of os.
|
||||
func (os K8sObjects) Keys() []string {
|
||||
var out []string
|
||||
for _, oo := range os {
|
||||
out = append(out, oo.Hash())
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// UnstructuredItems returns the list of items of unstructured.Unstructured.
|
||||
func (os K8sObjects) UnstructuredItems() []unstructured.Unstructured {
|
||||
var usList []unstructured.Unstructured
|
||||
for _, obj := range os {
|
||||
usList = append(usList, *obj.UnstructuredObject())
|
||||
}
|
||||
return usList
|
||||
}
|
||||
|
||||
// ParseK8sObjectsFromYAMLManifest returns a K8sObjects representation of manifest.
|
||||
func ParseK8sObjectsFromYAMLManifest(manifest string) (K8sObjects, error) {
|
||||
return ParseK8sObjectsFromYAMLManifestFailOption(manifest, true)
|
||||
}
|
||||
|
||||
// ParseK8sObjectsFromYAMLManifestFailOption returns a K8sObjects representation of manifest. Continues parsing when a bad object
|
||||
// is found if failOnError is set to false.
|
||||
func ParseK8sObjectsFromYAMLManifestFailOption(manifest string, failOnError bool) (K8sObjects, error) {
|
||||
var b bytes.Buffer
|
||||
|
||||
var yamls []string
|
||||
scanner := bufio.NewScanner(strings.NewReader(manifest))
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.HasPrefix(line, "---") {
|
||||
// yaml separator
|
||||
yamls = append(yamls, b.String())
|
||||
b.Reset()
|
||||
} else {
|
||||
if _, err := b.WriteString(line); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := b.WriteString("\n"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
yamls = append(yamls, b.String())
|
||||
|
||||
var objects K8sObjects
|
||||
|
||||
for _, yaml := range yamls {
|
||||
yaml = removeNonYAMLLines(yaml)
|
||||
if yaml == "" {
|
||||
continue
|
||||
}
|
||||
o, err := ParseYAMLToK8sObject([]byte(yaml))
|
||||
if err != nil {
|
||||
e := fmt.Errorf("failed to parse YAML to a k8s object: %s", err)
|
||||
if failOnError {
|
||||
return nil, e
|
||||
}
|
||||
continue
|
||||
}
|
||||
if o.Valid() {
|
||||
objects = append(objects, o)
|
||||
}
|
||||
}
|
||||
|
||||
return objects, nil
|
||||
}
|
||||
|
||||
func removeNonYAMLLines(yms string) string {
|
||||
var b strings.Builder
|
||||
for _, s := range strings.Split(yms, "\n") {
|
||||
if strings.HasPrefix(s, "#") {
|
||||
continue
|
||||
}
|
||||
b.WriteString(s)
|
||||
b.WriteString("\n")
|
||||
}
|
||||
|
||||
// helm charts sometimes emits blank objects with just a "disabled" comment.
|
||||
return strings.TrimSpace(b.String())
|
||||
}
|
||||
|
||||
// YAMLManifest returns a YAML representation of K8sObjects os.
|
||||
func (os K8sObjects) YAMLManifest() (string, error) {
|
||||
var b bytes.Buffer
|
||||
|
||||
for i, item := range os {
|
||||
if i != 0 {
|
||||
if _, err := b.WriteString("\n\n"); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
ym, err := item.YAML()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error building yaml: %v", err)
|
||||
}
|
||||
if _, err := b.Write(ym); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if _, err := b.Write([]byte(YAMLSeparator)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return b.String(), nil
|
||||
}
|
||||
|
||||
// Sort will order the items in K8sObjects in order of score, group, kind, name. The intent is to
|
||||
// have a deterministic ordering in which K8sObjects are applied.
|
||||
func (os K8sObjects) Sort(score func(o *K8sObject) int) {
|
||||
sort.Slice(os, func(i, j int) bool {
|
||||
iScore := score(os[i])
|
||||
jScore := score(os[j])
|
||||
return iScore < jScore ||
|
||||
(iScore == jScore &&
|
||||
os[i].Group < os[j].Group) ||
|
||||
(iScore == jScore &&
|
||||
os[i].Group == os[j].Group &&
|
||||
os[i].Kind < os[j].Kind) ||
|
||||
(iScore == jScore &&
|
||||
os[i].Group == os[j].Group &&
|
||||
os[i].Kind == os[j].Kind &&
|
||||
os[i].Name < os[j].Name)
|
||||
})
|
||||
}
|
||||
|
||||
// ToMap returns a map of K8sObject hash to K8sObject.
|
||||
func (os K8sObjects) ToMap() map[string]*K8sObject {
|
||||
ret := make(map[string]*K8sObject)
|
||||
for _, oo := range os {
|
||||
if oo.Valid() {
|
||||
ret[oo.Hash()] = oo
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// ToNameKindMap returns a map of K8sObject name/kind hash to K8sObject.
|
||||
func (os K8sObjects) ToNameKindMap() map[string]*K8sObject {
|
||||
ret := make(map[string]*K8sObject)
|
||||
for _, oo := range os {
|
||||
if oo.Valid() {
|
||||
ret[oo.HashNameKind()] = oo
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Valid checks returns true if Kind of K8sObject is not empty.
|
||||
func (o *K8sObject) Valid() bool {
|
||||
return o.Kind != ""
|
||||
}
|
||||
|
||||
// FullName returns namespace/name of K8s object
|
||||
func (o *K8sObject) FullName() string {
|
||||
return fmt.Sprintf("%s/%s", o.Namespace, o.Name)
|
||||
}
|
||||
|
||||
// Equal returns true if o and other are both valid and equal to each other.
|
||||
func (o *K8sObject) Equal(other *K8sObject) bool {
|
||||
if o == nil {
|
||||
return other == nil
|
||||
}
|
||||
if other == nil {
|
||||
return o == nil
|
||||
}
|
||||
|
||||
ay, err := o.YAML()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
by, err := other.YAML()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return util.IsYAMLEqual(string(ay), string(by))
|
||||
}
|
||||
|
||||
func istioCustomResources(group string) bool {
|
||||
switch group {
|
||||
case names.ConfigAPIGroupName,
|
||||
names.SecurityAPIGroupName,
|
||||
names.AuthenticationAPIGroupName,
|
||||
names.NetworkingAPIGroupName:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// DefaultObjectOrder is default sorting function used to sort k8s objects.
|
||||
func DefaultObjectOrder() func(o *K8sObject) int {
|
||||
return func(o *K8sObject) int {
|
||||
gk := o.Group + "/" + o.Kind
|
||||
switch {
|
||||
// Create CRDs asap - both because they are slow and because we will likely create instances of them soon
|
||||
case gk == "apiextensions.k8s.io/CustomResourceDefinition":
|
||||
return -1000
|
||||
|
||||
// We need to create ServiceAccounts, Roles before we bind them with a RoleBinding
|
||||
case gk == "/ServiceAccount" || gk == "rbac.authorization.k8s.io/ClusterRole":
|
||||
return 1
|
||||
case gk == "rbac.authorization.k8s.io/ClusterRoleBinding":
|
||||
return 2
|
||||
|
||||
// validatingwebhookconfiguration is configured to FAIL-OPEN in the default install. For the
|
||||
// re-install case we want to apply the validatingwebhookconfiguration first to reset any
|
||||
// orphaned validatingwebhookconfiguration that is FAIL-CLOSE.
|
||||
case gk == "admissionregistration.k8s.io/ValidatingWebhookConfiguration":
|
||||
return 3
|
||||
|
||||
case istioCustomResources(o.Group):
|
||||
return 4
|
||||
|
||||
// Pods might need configmap or secrets - avoid backoff by creating them first
|
||||
case gk == "/ConfigMap" || gk == "/Secrets":
|
||||
return 100
|
||||
|
||||
// Create the pods after we've created other things they might be waiting for
|
||||
case gk == "extensions/Deployment" || gk == "app/Deployment":
|
||||
return 1000
|
||||
|
||||
// Autoscalers typically act on a deployment
|
||||
case gk == "autoscaling/HorizontalPodAutoscaler":
|
||||
return 1001
|
||||
|
||||
// Create services late - after pods have been started
|
||||
case gk == "/Service":
|
||||
return 10000
|
||||
|
||||
default:
|
||||
return 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ObjectsNotInLists(objects K8sObjects, lists ...K8sObjects) K8sObjects {
|
||||
var ret K8sObjects
|
||||
|
||||
filterMap := make(map[*K8sObject]bool)
|
||||
for _, list := range lists {
|
||||
for _, object := range list {
|
||||
filterMap[object] = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, o := range objects {
|
||||
if !filterMap[o] {
|
||||
ret = append(ret, o)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// KindObjects returns the subset of objs with the given kind.
|
||||
func KindObjects(objs K8sObjects, kind string) K8sObjects {
|
||||
var ret K8sObjects
|
||||
for _, o := range objs {
|
||||
if o.Kind == kind {
|
||||
ret = append(ret, o)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
//// ParseK8SYAMLToIstioOperator parses a IstioOperator CustomResource YAML string and unmarshals in into
|
||||
//// an IstioOperatorSpec object. It returns the object and an API group/version with it.
|
||||
//func ParseK8SYAMLToIstioOperator(yml string) (*v1alpha1.HigressOperator, *schema.GroupVersionKind, error) {
|
||||
// o, err := ParseYAMLToK8sObject([]byte(yml))
|
||||
// if err != nil {
|
||||
// return nil, nil, err
|
||||
// }
|
||||
// iop := &v1alpha1.HigressOperator{}
|
||||
// if err := yaml.UnmarshalStrict([]byte(yml), iop); err != nil {
|
||||
// return nil, nil, err
|
||||
// }
|
||||
// gvk := o.GroupVersionKind()
|
||||
// //v1alpha1.SetNamespace(iop.Spec, o.Namespace)
|
||||
// return iop, &gvk, nil
|
||||
//}
|
||||
|
||||
// AllObjectHashes returns a map with object hashes of all the objects contained in cmm as the keys.
|
||||
func AllObjectHashes(m string) map[string]bool {
|
||||
ret := make(map[string]bool)
|
||||
objs, err := ParseK8sObjectsFromYAMLManifest(m)
|
||||
if err != nil {
|
||||
}
|
||||
for _, o := range objs {
|
||||
ret[o.Hash()] = true
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// resolvePDBConflict When user uses both minAvailable and
|
||||
// maxUnavailable to configure istio instances, these two
|
||||
// parameters are mutually exclusive, care must be taken
|
||||
// to resolve the issue
|
||||
func resolvePDBConflict(o *K8sObject) *K8sObject {
|
||||
if o.json == nil {
|
||||
return o
|
||||
}
|
||||
if o.object.Object["spec"] == nil {
|
||||
return o
|
||||
}
|
||||
spec := o.object.Object["spec"].(map[string]any)
|
||||
isDefault := func(item any) bool {
|
||||
var ii intstr.IntOrString
|
||||
switch item := item.(type) {
|
||||
case int:
|
||||
ii = intstr.FromInt(item)
|
||||
case int64:
|
||||
ii = intstr.FromInt(int(item))
|
||||
case string:
|
||||
ii = intstr.FromString(item)
|
||||
default:
|
||||
ii = intstr.FromInt(0)
|
||||
}
|
||||
intVal, err := intstr.GetScaledValueFromIntOrPercent(&ii, 100, false)
|
||||
if err != nil || intVal == 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
if spec["maxUnavailable"] != nil && spec["minAvailable"] != nil {
|
||||
// When both maxUnavailable and minAvailable present and
|
||||
// neither has value 0, this is considered a conflict,
|
||||
// then maxUnavailale will take precedence.
|
||||
if !isDefault(spec["maxUnavailable"]) && !isDefault(spec["minAvailable"]) {
|
||||
delete(spec, "minAvailable")
|
||||
// Make sure that the json and yaml representation of the object
|
||||
// is consistent with the changed object
|
||||
o.json = nil
|
||||
o.json, _ = o.JSON()
|
||||
if o.yaml != nil {
|
||||
o.yaml = nil
|
||||
o.yaml, _ = o.YAML()
|
||||
}
|
||||
}
|
||||
}
|
||||
return o
|
||||
}
|
||||
713
pkg/cmd/hgctl/helm/object/objects_test.go
Normal file
713
pkg/cmd/hgctl/helm/object/objects_test.go
Normal file
@@ -0,0 +1,713 @@
|
||||
// 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 object
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/util"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func TestHash(t *testing.T) {
|
||||
hashTests := []struct {
|
||||
desc string
|
||||
kind string
|
||||
namespace string
|
||||
name string
|
||||
want string
|
||||
}{
|
||||
{"CalculateHashForObjectWithNormalCharacter", "Service", "default", "ingressgateway", "Service:default:ingressgateway"},
|
||||
{"CalculateHashForObjectWithDash", "Deployment", "istio-system", "istio-pilot", "Deployment:istio-system:istio-pilot"},
|
||||
{"CalculateHashForObjectWithDot", "ConfigMap", "istio-system", "my.config", "ConfigMap:istio-system:my.config"},
|
||||
}
|
||||
|
||||
for _, tt := range hashTests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
got := Hash(tt.kind, tt.namespace, tt.name)
|
||||
if got != tt.want {
|
||||
t.Errorf("Hash(%s): got %s for kind %s, namespace %s, name %s, want %s", tt.desc, got, tt.kind, tt.namespace, tt.name, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromHash(t *testing.T) {
|
||||
hashTests := []struct {
|
||||
desc string
|
||||
hash string
|
||||
kind string
|
||||
namespace string
|
||||
name string
|
||||
}{
|
||||
{"ParseHashWithNormalCharacter", "Service:default:ingressgateway", "Service", "default", "ingressgateway"},
|
||||
{"ParseHashForObjectWithDash", "Deployment:istio-system:istio-pilot", "Deployment", "istio-system", "istio-pilot"},
|
||||
{"ParseHashForObjectWithDot", "ConfigMap:istio-system:my.config", "ConfigMap", "istio-system", "my.config"},
|
||||
{"InvalidHash", "test", "Bad hash string: test", "", ""},
|
||||
}
|
||||
|
||||
for _, tt := range hashTests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
k, ns, name := FromHash(tt.hash)
|
||||
if k != tt.kind || ns != tt.namespace || name != tt.name {
|
||||
t.Errorf("FromHash(%s): got kind %s, namespace %s, name %s, want kind %s, namespace %s, name %s", tt.desc, k, ns, name, tt.kind, tt.namespace, tt.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHashNameKind(t *testing.T) {
|
||||
hashNameKindTests := []struct {
|
||||
desc string
|
||||
kind string
|
||||
name string
|
||||
want string
|
||||
}{
|
||||
{"CalculateHashNameKindForObjectWithNormalCharacter", "Service", "ingressgateway", "Service:ingressgateway"},
|
||||
{"CalculateHashNameKindForObjectWithDash", "Deployment", "istio-pilot", "Deployment:istio-pilot"},
|
||||
{"CalculateHashNameKindForObjectWithDot", "ConfigMap", "my.config", "ConfigMap:my.config"},
|
||||
}
|
||||
|
||||
for _, tt := range hashNameKindTests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
got := HashNameKind(tt.kind, tt.name)
|
||||
if got != tt.want {
|
||||
t.Errorf("HashNameKind(%s): got %s for kind %s, name %s, want %s", tt.desc, got, tt.kind, tt.name, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseJSONToK8sObject(t *testing.T) {
|
||||
testDeploymentJSON := `{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": {
|
||||
"name": "istio-citadel",
|
||||
"namespace": "istio-system",
|
||||
"labels": {
|
||||
"istio": "citadel"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"replicas": 1,
|
||||
"selector": {
|
||||
"matchLabels": {
|
||||
"istio": "citadel"
|
||||
}
|
||||
},
|
||||
"template": {
|
||||
"metadata": {
|
||||
"labels": {
|
||||
"istio": "citadel"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "citadel",
|
||||
"image": "docker.io/istio/citadel:1.1.8",
|
||||
"args": [
|
||||
"--append-dns-names=true",
|
||||
"--grpc-port=8060",
|
||||
"--grpc-hostname=citadel",
|
||||
"--citadel-storage-namespace=istio-system",
|
||||
"--custom-dns-names=istio-pilot-service-account.istio-system:istio-pilot.istio-system",
|
||||
"--monitoring-port=15014",
|
||||
"--self-signed-ca=true"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
testPodJSON := `{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Pod",
|
||||
"metadata": {
|
||||
"name": "istio-galley-75bcd59768-hpt5t",
|
||||
"namespace": "istio-system",
|
||||
"labels": {
|
||||
"istio": "galley"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "galley",
|
||||
"image": "docker.io/istio/galley:1.1.8",
|
||||
"command": [
|
||||
"/usr/local/bin/galley",
|
||||
"server",
|
||||
"--meshConfigFile=/etc/mesh-config/mesh",
|
||||
"--livenessProbeInterval=1s",
|
||||
"--livenessProbePath=/healthliveness",
|
||||
"--readinessProbePath=/healthready",
|
||||
"--readinessProbeInterval=1s",
|
||||
"--deployment-namespace=istio-system",
|
||||
"--insecure=true",
|
||||
"--validation-webhook-config-file",
|
||||
"/etc/config/validatingwebhookconfiguration.yaml",
|
||||
"--monitoringPort=15014",
|
||||
"--log_output_level=default:info"
|
||||
],
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": 443,
|
||||
"protocol": "TCP"
|
||||
},
|
||||
{
|
||||
"containerPort": 15014,
|
||||
"protocol": "TCP"
|
||||
},
|
||||
{
|
||||
"containerPort": 9901,
|
||||
"protocol": "TCP"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}`
|
||||
testServiceJSON := `{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Service",
|
||||
"metadata": {
|
||||
"labels": {
|
||||
"app": "pilot"
|
||||
},
|
||||
"name": "istio-pilot",
|
||||
"namespace": "istio-system"
|
||||
},
|
||||
"spec": {
|
||||
"clusterIP": "10.102.230.31",
|
||||
"ports": [
|
||||
{
|
||||
"name": "grpc-xds",
|
||||
"port": 15010,
|
||||
"protocol": "TCP",
|
||||
"targetPort": 15010
|
||||
},
|
||||
{
|
||||
"name": "https-xds",
|
||||
"port": 15011,
|
||||
"protocol": "TCP",
|
||||
"targetPort": 15011
|
||||
},
|
||||
{
|
||||
"name": "http-legacy-discovery",
|
||||
"port": 8080,
|
||||
"protocol": "TCP",
|
||||
"targetPort": 8080
|
||||
},
|
||||
{
|
||||
"name": "http-monitoring",
|
||||
"port": 15014,
|
||||
"protocol": "TCP",
|
||||
"targetPort": 15014
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"istio": "pilot"
|
||||
},
|
||||
"sessionAffinity": "None",
|
||||
"type": "ClusterIP"
|
||||
}
|
||||
}`
|
||||
|
||||
testInvalidJSON := `invalid json`
|
||||
|
||||
parseJSONToK8sObjectTests := []struct {
|
||||
desc string
|
||||
objString string
|
||||
wantGroup string
|
||||
wantKind string
|
||||
wantName string
|
||||
wantNamespace string
|
||||
wantErr bool
|
||||
}{
|
||||
{"ParseJsonToK8sDeployment", testDeploymentJSON, "apps", "Deployment", "istio-citadel", "istio-system", false},
|
||||
{"ParseJsonToK8sPod", testPodJSON, "", "Pod", "istio-galley-75bcd59768-hpt5t", "istio-system", false},
|
||||
{"ParseJsonToK8sService", testServiceJSON, "", "Service", "istio-pilot", "istio-system", false},
|
||||
{"ParseJsonError", testInvalidJSON, "", "", "", "", true},
|
||||
}
|
||||
|
||||
for _, tt := range parseJSONToK8sObjectTests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
k8sObj, err := ParseJSONToK8sObject([]byte(tt.objString))
|
||||
if err == nil {
|
||||
if tt.wantErr {
|
||||
t.Errorf("ParseJsonToK8sObject(%s): should be error", tt.desc)
|
||||
}
|
||||
k8sObjStr := k8sObj.YAMLDebugString()
|
||||
if k8sObj.Group != tt.wantGroup {
|
||||
t.Errorf("ParseJsonToK8sObject(%s): got group %s for k8s object %s, want %s", tt.desc, k8sObj.Group, k8sObjStr, tt.wantGroup)
|
||||
}
|
||||
if k8sObj.Kind != tt.wantKind {
|
||||
t.Errorf("ParseJsonToK8sObject(%s): got kind %s for k8s object %s, want %s", tt.desc, k8sObj.Kind, k8sObjStr, tt.wantKind)
|
||||
}
|
||||
if k8sObj.Name != tt.wantName {
|
||||
t.Errorf("ParseJsonToK8sObject(%s): got name %s for k8s object %s, want %s", tt.desc, k8sObj.Name, k8sObjStr, tt.wantName)
|
||||
}
|
||||
if k8sObj.Namespace != tt.wantNamespace {
|
||||
t.Errorf("ParseJsonToK8sObject(%s): got group %s for k8s object %s, want %s", tt.desc, k8sObj.Namespace, k8sObjStr, tt.wantNamespace)
|
||||
}
|
||||
} else if !tt.wantErr {
|
||||
t.Errorf("ParseJsonToK8sObject(%s): got unexpected error: %v", tt.desc, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseYAMLToK8sObject(t *testing.T) {
|
||||
testDeploymentYaml := `apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: istio-citadel
|
||||
namespace: istio-system
|
||||
labels:
|
||||
istio: citadel
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
istio: citadel
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
istio: citadel
|
||||
spec:
|
||||
containers:
|
||||
- name: citadel
|
||||
image: docker.io/istio/citadel:1.1.8
|
||||
args:
|
||||
- "--append-dns-names=true"
|
||||
- "--grpc-port=8060"
|
||||
- "--grpc-hostname=citadel"
|
||||
- "--citadel-storage-namespace=istio-system"
|
||||
- "--custom-dns-names=istio-pilot-service-account.istio-system:istio-pilot.istio-system"
|
||||
- "--monitoring-port=15014"
|
||||
- "--self-signed-ca=true"`
|
||||
|
||||
testPodYaml := `apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: istio-galley-75bcd59768-hpt5t
|
||||
namespace: istio-system
|
||||
labels:
|
||||
istio: galley
|
||||
spec:
|
||||
containers:
|
||||
- name: galley
|
||||
image: docker.io/istio/galley:1.1.8
|
||||
command:
|
||||
- "/usr/local/bin/galley"
|
||||
- server
|
||||
- "--meshConfigFile=/etc/mesh-config/mesh"
|
||||
- "--livenessProbeInterval=1s"
|
||||
- "--livenessProbePath=/healthliveness"
|
||||
- "--readinessProbePath=/healthready"
|
||||
- "--readinessProbeInterval=1s"
|
||||
- "--deployment-namespace=istio-system"
|
||||
- "--insecure=true"
|
||||
- "--validation-webhook-config-file"
|
||||
- "/etc/config/validatingwebhookconfiguration.yaml"
|
||||
- "--monitoringPort=15014"
|
||||
- "--log_output_level=default:info"
|
||||
ports:
|
||||
- containerPort: 443
|
||||
protocol: TCP
|
||||
- containerPort: 15014
|
||||
protocol: TCP
|
||||
- containerPort: 9901
|
||||
protocol: TCP`
|
||||
|
||||
testServiceYaml := `apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: pilot
|
||||
name: istio-pilot
|
||||
namespace: istio-system
|
||||
spec:
|
||||
clusterIP: 10.102.230.31
|
||||
ports:
|
||||
- name: grpc-xds
|
||||
port: 15010
|
||||
protocol: TCP
|
||||
targetPort: 15010
|
||||
- name: https-xds
|
||||
port: 15011
|
||||
protocol: TCP
|
||||
targetPort: 15011
|
||||
- name: http-legacy-discovery
|
||||
port: 8080
|
||||
protocol: TCP
|
||||
targetPort: 8080
|
||||
- name: http-monitoring
|
||||
port: 15014
|
||||
protocol: TCP
|
||||
targetPort: 15014
|
||||
selector:
|
||||
istio: pilot
|
||||
sessionAffinity: None
|
||||
type: ClusterIP`
|
||||
|
||||
parseYAMLToK8sObjectTests := []struct {
|
||||
desc string
|
||||
objString string
|
||||
wantGroup string
|
||||
wantKind string
|
||||
wantName string
|
||||
wantNamespace string
|
||||
}{
|
||||
{"ParseYamlToK8sDeployment", testDeploymentYaml, "apps", "Deployment", "istio-citadel", "istio-system"},
|
||||
{"ParseYamlToK8sPod", testPodYaml, "", "Pod", "istio-galley-75bcd59768-hpt5t", "istio-system"},
|
||||
{"ParseYamlToK8sService", testServiceYaml, "", "Service", "istio-pilot", "istio-system"},
|
||||
}
|
||||
|
||||
for _, tt := range parseYAMLToK8sObjectTests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
k8sObj, err := ParseYAMLToK8sObject([]byte(tt.objString))
|
||||
if err != nil {
|
||||
k8sObjStr := k8sObj.YAMLDebugString()
|
||||
if k8sObj.Group != tt.wantGroup {
|
||||
t.Errorf("ParseYAMLToK8sObject(%s): got group %s for k8s object %s, want %s", tt.desc, k8sObj.Group, k8sObjStr, tt.wantGroup)
|
||||
}
|
||||
if k8sObj.Group != tt.wantGroup {
|
||||
t.Errorf("ParseYAMLToK8sObject(%s): got kind %s for k8s object %s, want %s", tt.desc, k8sObj.Kind, k8sObjStr, tt.wantKind)
|
||||
}
|
||||
if k8sObj.Name != tt.wantName {
|
||||
t.Errorf("ParseYAMLToK8sObject(%s): got name %s for k8s object %s, want %s", tt.desc, k8sObj.Name, k8sObjStr, tt.wantName)
|
||||
}
|
||||
if k8sObj.Namespace != tt.wantNamespace {
|
||||
t.Errorf("ParseYAMLToK8sObject(%s): got group %s for k8s object %s, want %s", tt.desc, k8sObj.Namespace, k8sObjStr, tt.wantNamespace)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseK8sObjectsFromYAMLManifest(t *testing.T) {
|
||||
testDeploymentYaml := `apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: istio-citadel
|
||||
namespace: istio-system
|
||||
labels:
|
||||
istio: citadel
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
istio: citadel
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
istio: citadel
|
||||
spec:
|
||||
containers:
|
||||
- name: citadel
|
||||
image: docker.io/istio/citadel:1.1.8
|
||||
args:
|
||||
- "--append-dns-names=true"
|
||||
- "--grpc-port=8060"
|
||||
- "--grpc-hostname=citadel"
|
||||
- "--citadel-storage-namespace=istio-system"
|
||||
- "--custom-dns-names=istio-pilot-service-account.istio-system:istio-pilot.istio-system"
|
||||
- "--monitoring-port=15014"
|
||||
- "--self-signed-ca=true"`
|
||||
|
||||
testPodYaml := `apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: istio-galley-75bcd59768-hpt5t
|
||||
namespace: istio-system
|
||||
labels:
|
||||
istio: galley
|
||||
spec:
|
||||
containers:
|
||||
- name: galley
|
||||
image: docker.io/istio/galley:1.1.8
|
||||
command:
|
||||
- "/usr/local/bin/galley"
|
||||
- server
|
||||
- "--meshConfigFile=/etc/mesh-config/mesh"
|
||||
- "--livenessProbeInterval=1s"
|
||||
- "--livenessProbePath=/healthliveness"
|
||||
- "--readinessProbePath=/healthready"
|
||||
- "--readinessProbeInterval=1s"
|
||||
- "--deployment-namespace=istio-system"
|
||||
- "--insecure=true"
|
||||
- "--validation-webhook-config-file"
|
||||
- "/etc/config/validatingwebhookconfiguration.yaml"
|
||||
- "--monitoringPort=15014"
|
||||
- "--log_output_level=default:info"
|
||||
ports:
|
||||
- containerPort: 443
|
||||
protocol: TCP
|
||||
- containerPort: 15014
|
||||
protocol: TCP
|
||||
- containerPort: 9901
|
||||
protocol: TCP`
|
||||
|
||||
testServiceYaml := `apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: pilot
|
||||
name: istio-pilot
|
||||
namespace: istio-system
|
||||
spec:
|
||||
clusterIP: 10.102.230.31
|
||||
ports:
|
||||
- name: grpc-xds
|
||||
port: 15010
|
||||
protocol: TCP
|
||||
targetPort: 15010
|
||||
- name: https-xds
|
||||
port: 15011
|
||||
protocol: TCP
|
||||
targetPort: 15011
|
||||
- name: http-legacy-discovery
|
||||
port: 8080
|
||||
protocol: TCP
|
||||
targetPort: 8080
|
||||
- name: http-monitoring
|
||||
port: 15014
|
||||
protocol: TCP
|
||||
targetPort: 15014
|
||||
selector:
|
||||
istio: pilot
|
||||
sessionAffinity: None
|
||||
type: ClusterIP`
|
||||
|
||||
parseK8sObjectsFromYAMLManifestTests := []struct {
|
||||
desc string
|
||||
objsMap map[string]string
|
||||
}{
|
||||
{
|
||||
"FromHybridYAMLManifest",
|
||||
map[string]string{
|
||||
"Deployment:istio-system:istio-citadel": testDeploymentYaml,
|
||||
"Pod:istio-system:istio-galley-75bcd59768-hpt5t": testPodYaml,
|
||||
"Service:istio-system:istio-pilot": testServiceYaml,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range parseK8sObjectsFromYAMLManifestTests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
testManifestYaml := strings.Join([]string{testDeploymentYaml, testPodYaml, testServiceYaml}, YAMLSeparator)
|
||||
gotK8sObjs, err := ParseK8sObjectsFromYAMLManifest(testManifestYaml)
|
||||
if err != nil {
|
||||
gotK8sObjsMap := gotK8sObjs.ToMap()
|
||||
for objHash, want := range tt.objsMap {
|
||||
if gotObj, ok := gotK8sObjsMap[objHash]; ok {
|
||||
gotObjYaml := gotObj.YAMLDebugString()
|
||||
if !util.IsYAMLEqual(gotObjYaml, want) {
|
||||
t.Errorf("ParseK8sObjectsFromYAMLManifest(%s): got:\n%s\n\nwant:\n%s\nDiff:\n%s\n", tt.desc, gotObjYaml, want, util.YAMLDiff(gotObjYaml, want))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestK8sObject_Equal(t *testing.T) {
|
||||
obj1 := K8sObject{
|
||||
object: &unstructured.Unstructured{Object: map[string]any{
|
||||
"key": "value1",
|
||||
}},
|
||||
}
|
||||
obj2 := K8sObject{
|
||||
object: &unstructured.Unstructured{Object: map[string]any{
|
||||
"key": "value2",
|
||||
}},
|
||||
}
|
||||
cases := []struct {
|
||||
desc string
|
||||
o1 *K8sObject
|
||||
o2 *K8sObject
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
desc: "Equals",
|
||||
o1: &obj1,
|
||||
o2: &obj1,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
desc: "NotEquals",
|
||||
o1: &obj1,
|
||||
o2: &obj2,
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
desc: "NilSource",
|
||||
o1: nil,
|
||||
o2: &obj2,
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
desc: "NilDest",
|
||||
o1: &obj1,
|
||||
o2: nil,
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
desc: "TwoNils",
|
||||
o1: nil,
|
||||
o2: nil,
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range cases {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
res := tt.o1.Equal(tt.o2)
|
||||
if res != tt.want {
|
||||
t.Errorf("got %v, want: %v", res, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestK8sObject_ResolveK8sConflict(t *testing.T) {
|
||||
getK8sObject := func(ystr string) *K8sObject {
|
||||
o, err := ParseYAMLToK8sObject([]byte(ystr))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Ensure that json data is in sync.
|
||||
// Since the object was created using yaml, json is empty.
|
||||
// make sure the object json is set correctly.
|
||||
o.json, _ = o.JSON()
|
||||
return o
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
o1 *K8sObject
|
||||
o2 *K8sObject
|
||||
}{
|
||||
{
|
||||
desc: "not applicable kind",
|
||||
o1: getK8sObject(`
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: pilot
|
||||
name: istio-pilot
|
||||
namespace: istio-system
|
||||
spec:
|
||||
clusterIP: 10.102.230.31`),
|
||||
o2: getK8sObject(`
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: pilot
|
||||
name: istio-pilot
|
||||
namespace: istio-system
|
||||
spec:
|
||||
clusterIP: 10.102.230.31`),
|
||||
},
|
||||
{
|
||||
desc: "only minAvailable is set",
|
||||
o1: getK8sObject(`
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: zk-pdb
|
||||
spec:
|
||||
minAvailable: 2`),
|
||||
o2: getK8sObject(`
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: zk-pdb
|
||||
spec:
|
||||
minAvailable: 2`),
|
||||
},
|
||||
{
|
||||
desc: "only maxUnavailable is set",
|
||||
o1: getK8sObject(`
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: istio
|
||||
spec:
|
||||
maxUnavailable: 3`),
|
||||
o2: getK8sObject(`
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: istio
|
||||
spec:
|
||||
maxUnavailable: 3`),
|
||||
},
|
||||
{
|
||||
desc: "minAvailable and maxUnavailable are set to none zero values",
|
||||
o1: getK8sObject(`
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: istio
|
||||
spec:
|
||||
maxUnavailable: 50%
|
||||
minAvailable: 3`),
|
||||
o2: getK8sObject(`
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: istio
|
||||
spec:
|
||||
maxUnavailable: 50%`),
|
||||
},
|
||||
{
|
||||
desc: "both minAvailable and maxUnavailable are set default",
|
||||
o1: getK8sObject(`
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: istio
|
||||
spec:
|
||||
minAvailable: 0
|
||||
maxUnavailable: 0`),
|
||||
o2: getK8sObject(`
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: istio
|
||||
spec:
|
||||
maxUnavailable: 0
|
||||
minAvailable: 0`),
|
||||
},
|
||||
}
|
||||
for _, tt := range cases {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
newObj := tt.o1.ResolveK8sConflict()
|
||||
if !newObj.Equal(tt.o2) {
|
||||
newObjjson, _ := newObj.JSON()
|
||||
wantedObjjson, _ := tt.o2.JSON()
|
||||
t.Errorf("Got: %s, want: %s", string(newObjjson), string(wantedObjjson))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
344
pkg/cmd/hgctl/helm/profile.go
Normal file
344
pkg/cmd/hgctl/helm/profile.go
Normal file
@@ -0,0 +1,344 @@
|
||||
// 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 helm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"istio.io/istio/operator/pkg/util"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
type InstallMode string
|
||||
|
||||
const (
|
||||
InstallK8s InstallMode = "k8s"
|
||||
InstallLocalK8s InstallMode = "local-k8s"
|
||||
InstallLocalDocker InstallMode = "local-docker"
|
||||
InstallLocal InstallMode = "local"
|
||||
)
|
||||
|
||||
type Profile struct {
|
||||
Profile string `json:"profile,omitempty"`
|
||||
InstallPackagePath string `json:"installPackagePath,omitempty"`
|
||||
Global ProfileGlobal `json:"global,omitempty"`
|
||||
Console ProfileConsole `json:"console,omitempty"`
|
||||
Gateway ProfileGateway `json:"gateway,omitempty"`
|
||||
Controller ProfileController `json:"controller,omitempty"`
|
||||
Storage ProfileStorage `json:"storage,omitempty"`
|
||||
Values map[string]any `json:"values,omitempty"`
|
||||
Charts ProfileCharts `json:"charts,omitempty"`
|
||||
}
|
||||
|
||||
type ProfileGlobal struct {
|
||||
Install InstallMode `json:"install,omitempty"`
|
||||
IngressClass string `json:"ingressClass,omitempty"`
|
||||
EnableIstioAPI bool `json:"enableIstioAPI,omitempty"`
|
||||
EnableGatewayAPI bool `json:"enableGatewayAPI,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
func (p ProfileGlobal) SetFlags(install InstallMode) ([]string, error) {
|
||||
sets := make([]string, 0)
|
||||
if install == InstallK8s || install == InstallLocalK8s {
|
||||
sets = append(sets, fmt.Sprintf("global.ingressClass=%s", p.IngressClass))
|
||||
sets = append(sets, fmt.Sprintf("global.enableIstioAPI=%t", p.EnableIstioAPI))
|
||||
sets = append(sets, fmt.Sprintf("global.enableGatewayAPI=%t", p.EnableGatewayAPI))
|
||||
if install == InstallLocalK8s {
|
||||
sets = append(sets, fmt.Sprintf("global.local=%t", true))
|
||||
}
|
||||
}
|
||||
return sets, nil
|
||||
}
|
||||
|
||||
func (p ProfileGlobal) Validate(install InstallMode) []error {
|
||||
errs := make([]error, 0)
|
||||
// now only support k8s, local-k8s, local-docker installation mode
|
||||
if install != InstallK8s && install != InstallLocalK8s && install != InstallLocalDocker {
|
||||
errs = append(errs, errors.New("global.install only can be set to k8s, local-k8s or local-docker"))
|
||||
}
|
||||
if install == InstallK8s || install == InstallLocalK8s {
|
||||
if len(p.IngressClass) == 0 {
|
||||
errs = append(errs, errors.New("global.ingressClass can't be empty"))
|
||||
}
|
||||
if len(p.Namespace) == 0 {
|
||||
errs = append(errs, errors.New("global.namespace can't be empty"))
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
type ProfileConsole struct {
|
||||
Port uint32 `json:"port,omitempty"`
|
||||
Replicas uint32 `json:"replicas,omitempty"`
|
||||
O11yEnabled bool `json:"o11YEnabled,omitempty"`
|
||||
}
|
||||
|
||||
func (p ProfileConsole) SetFlags(install InstallMode) ([]string, error) {
|
||||
sets := make([]string, 0)
|
||||
if install == InstallK8s || install == InstallLocalK8s {
|
||||
sets = append(sets, fmt.Sprintf("higress-console.replicaCount=%d", p.Replicas))
|
||||
sets = append(sets, fmt.Sprintf("higress-console.o11y.enabled=%t", p.O11yEnabled))
|
||||
}
|
||||
return sets, nil
|
||||
}
|
||||
|
||||
func (p ProfileConsole) Validate(install InstallMode) []error {
|
||||
errs := make([]error, 0)
|
||||
if install == InstallK8s || install == InstallLocalK8s {
|
||||
if p.Replicas <= 0 {
|
||||
errs = append(errs, errors.New("console.replica need be large than zero"))
|
||||
}
|
||||
}
|
||||
|
||||
if install == InstallLocalDocker {
|
||||
if p.Port <= 0 {
|
||||
errs = append(errs, errors.New("console.port need be large than zero"))
|
||||
}
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
type ProfileGateway struct {
|
||||
Replicas uint32 `json:"replicas,omitempty"`
|
||||
HttpPort uint32 `json:"httpPort,omitempty"`
|
||||
HttpsPort uint32 `json:"httpsPort,omitempty"`
|
||||
MetricsPort uint32 `json:"metricsPort,omitempty"`
|
||||
}
|
||||
|
||||
func (p ProfileGateway) SetFlags(install InstallMode) ([]string, error) {
|
||||
sets := make([]string, 0)
|
||||
if install == InstallK8s || install == InstallLocalK8s {
|
||||
sets = append(sets, fmt.Sprintf("higress-core.gateway.replicas=%d", p.Replicas))
|
||||
}
|
||||
return sets, nil
|
||||
}
|
||||
|
||||
func (p ProfileGateway) Validate(install InstallMode) []error {
|
||||
errs := make([]error, 0)
|
||||
if install == InstallK8s || install == InstallLocalK8s {
|
||||
if p.Replicas <= 0 {
|
||||
errs = append(errs, errors.New("gateway.replica need be large than zero"))
|
||||
}
|
||||
}
|
||||
|
||||
if install == InstallLocalDocker {
|
||||
if p.HttpPort <= 0 {
|
||||
errs = append(errs, errors.New("gateway.httpPort need be large than zero"))
|
||||
}
|
||||
if p.HttpsPort <= 0 {
|
||||
errs = append(errs, errors.New("gateway.httpsPort need be large than zero"))
|
||||
}
|
||||
if p.MetricsPort <= 0 {
|
||||
errs = append(errs, errors.New("gateway.MetricsPort need be large than zero"))
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
type ProfileController struct {
|
||||
Replicas uint32 `json:"replicas,omitempty"`
|
||||
}
|
||||
|
||||
func (p ProfileController) SetFlags(install InstallMode) ([]string, error) {
|
||||
sets := make([]string, 0)
|
||||
if install == InstallK8s || install == InstallLocalK8s {
|
||||
sets = append(sets, fmt.Sprintf("higress-core.controller.replicas=%d", p.Replicas))
|
||||
}
|
||||
return sets, nil
|
||||
}
|
||||
|
||||
func (p ProfileController) Validate(install InstallMode) []error {
|
||||
errs := make([]error, 0)
|
||||
if install == InstallK8s || install == InstallLocalK8s {
|
||||
if p.Replicas <= 0 {
|
||||
errs = append(errs, errors.New("controller.replica need be large than zero"))
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
type ProfileStorage struct {
|
||||
Url string `json:"url,omitempty"`
|
||||
Ns string `json:"ns,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
DataEncKey string `json:"DataEncKey,omitempty"`
|
||||
}
|
||||
|
||||
func (p ProfileStorage) Validate(install InstallMode) []error {
|
||||
errs := make([]error, 0)
|
||||
if install == InstallLocalDocker {
|
||||
if len(p.Url) == 0 {
|
||||
errs = append(errs, errors.New("storage.url can't be empty"))
|
||||
}
|
||||
if len(p.Ns) == 0 {
|
||||
errs = append(errs, errors.New("storage.ns can't be empty"))
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(p.Url, "nacos://") && !strings.HasPrefix(p.Url, "file://") {
|
||||
errs = append(errs, fmt.Errorf("invalid storage url: %s", p.Url))
|
||||
} else {
|
||||
// check localhost or 127.0.0.0
|
||||
if strings.Contains(p.Url, "localhost") || strings.Contains(p.Url, "/127.") {
|
||||
errs = append(errs, errors.New("localhost or loopback addresses in nacos url won't work"))
|
||||
}
|
||||
}
|
||||
|
||||
if len(p.DataEncKey) > 0 && len(p.DataEncKey) != 32 {
|
||||
errs = append(errs, fmt.Errorf("expecting 32 characters for dataEncKey, but got %d length", len(p.DataEncKey)))
|
||||
}
|
||||
|
||||
if len(p.Username) > 0 && len(p.Password) == 0 || len(p.Username) == 0 && len(p.Password) > 0 {
|
||||
errs = append(errs, errors.New("both nacos username and password should be provided"))
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
type Chart struct {
|
||||
Url string `json:"url,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
type ProfileCharts struct {
|
||||
Higress Chart `json:"higress,omitempty"`
|
||||
Standalone Chart `json:"standalone,omitempty"`
|
||||
}
|
||||
|
||||
func (p ProfileCharts) Validate(install InstallMode) []error {
|
||||
errs := make([]error, 0)
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
func (p *Profile) ValuesYaml() (string, error) {
|
||||
setFlags := make([]string, 0)
|
||||
// Get global setting
|
||||
globalFlags, _ := p.Global.SetFlags(p.Global.Install)
|
||||
setFlags = append(setFlags, globalFlags...)
|
||||
|
||||
// Get console setting
|
||||
consoleFlags, _ := p.Console.SetFlags(p.Global.Install)
|
||||
setFlags = append(setFlags, consoleFlags...)
|
||||
|
||||
// Get gateway setting
|
||||
gatewayFlags, _ := p.Gateway.SetFlags(p.Global.Install)
|
||||
setFlags = append(setFlags, gatewayFlags...)
|
||||
|
||||
// Get controller setting
|
||||
controllerFlags, _ := p.Controller.SetFlags(p.Global.Install)
|
||||
setFlags = append(setFlags, controllerFlags...)
|
||||
|
||||
valueOverlayYAML := ""
|
||||
if p.Values != nil {
|
||||
out, err := yaml.Marshal(p.Values)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
valueOverlayYAML = string(out)
|
||||
}
|
||||
|
||||
flagsYAML, err := overlaySetFlagValues("", setFlags)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// merge values and setFlags
|
||||
overlayYAML, err := util.OverlayYAML(flagsYAML, valueOverlayYAML)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return overlayYAML, nil
|
||||
}
|
||||
|
||||
func (p *Profile) IstioEnabled() bool {
|
||||
if (p.Global.Install == InstallK8s || p.Global.Install == InstallLocalK8s) && p.Global.EnableIstioAPI {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *Profile) GatewayAPIEnabled() bool {
|
||||
if (p.Global.Install == InstallK8s || p.Global.Install == InstallLocalK8s) && p.Global.EnableGatewayAPI {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *Profile) GetIstioNamespace() string {
|
||||
if valuesGlobal, ok1 := p.Values["global"]; ok1 {
|
||||
if global, ok2 := valuesGlobal.(map[string]any); ok2 {
|
||||
if istioNamespace, ok3 := global["istioNamespace"]; ok3 {
|
||||
if namespace, ok4 := istioNamespace.(string); ok4 {
|
||||
return namespace
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *Profile) Validate() error {
|
||||
errs := make([]error, 0)
|
||||
errsGlobal := p.Global.Validate(p.Global.Install)
|
||||
if len(errsGlobal) > 0 {
|
||||
errs = append(errs, errsGlobal...)
|
||||
}
|
||||
errsConsole := p.Console.Validate(p.Global.Install)
|
||||
if len(errsConsole) > 0 {
|
||||
errs = append(errs, errsConsole...)
|
||||
}
|
||||
errsGateway := p.Gateway.Validate(p.Global.Install)
|
||||
if len(errsGateway) > 0 {
|
||||
errs = append(errs, errsGateway...)
|
||||
}
|
||||
errsController := p.Controller.Validate(p.Global.Install)
|
||||
if len(errsController) > 0 {
|
||||
errs = append(errs, errsController...)
|
||||
}
|
||||
errsStorage := p.Storage.Validate(p.Global.Install)
|
||||
if len(errsStorage) > 0 {
|
||||
errs = append(errs, errsStorage...)
|
||||
}
|
||||
errsCharts := p.Charts.Validate(p.Global.Install)
|
||||
if len(errsCharts) > 0 {
|
||||
errs = append(errs, errsCharts...)
|
||||
}
|
||||
|
||||
if len(errs) == 0 {
|
||||
return nil
|
||||
}
|
||||
return errors.New(ToString(errs, "\n"))
|
||||
}
|
||||
|
||||
// ToString returns a string representation of errors, with elements separated by separator string. Any nil errors in the
|
||||
// slice are skipped.
|
||||
func ToString(errors []error, separator string) string {
|
||||
var out string
|
||||
for i, e := range errors {
|
||||
if e == nil {
|
||||
continue
|
||||
}
|
||||
if i != 0 {
|
||||
out += separator
|
||||
}
|
||||
out += e.Error()
|
||||
}
|
||||
return out
|
||||
}
|
||||
663
pkg/cmd/hgctl/helm/render.go
Normal file
663
pkg/cmd/hgctl/helm/render.go
Normal file
@@ -0,0 +1,663 @@
|
||||
// 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 helm
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/manifests"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/util"
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
"helm.sh/helm/v3/pkg/chartutil"
|
||||
"helm.sh/helm/v3/pkg/cli"
|
||||
"helm.sh/helm/v3/pkg/downloader"
|
||||
"helm.sh/helm/v3/pkg/engine"
|
||||
"helm.sh/helm/v3/pkg/getter"
|
||||
"helm.sh/helm/v3/pkg/repo"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultProfileName is the name of the default profile for installation.
|
||||
DefaultProfileName = "local-k8s"
|
||||
// DefaultProfileFilename is the name of the default profile yaml file for installation.
|
||||
DefaultProfileFilename = "local-k8s.yaml"
|
||||
// DefaultUninstallProfileName is the name of the default profile yaml file for uninstallation.
|
||||
DefaultUninstallProfileName = "local-k8s"
|
||||
|
||||
// ChartsSubdirName = "charts"
|
||||
profilesRoot = "profiles"
|
||||
|
||||
RepoLatestVersion = "latest"
|
||||
RepoChartIndexYamlHigressIndex = "higress"
|
||||
|
||||
YAMLSeparator = "\n---\n"
|
||||
NotesFileNameSuffix = ".txt"
|
||||
)
|
||||
|
||||
func LoadValues(profileName string, chartsDir string) (string, error) {
|
||||
path := strings.Join([]string{profilesRoot, builtinProfileToFilename(profileName)}, "/")
|
||||
by, err := fs.ReadFile(manifests.BuiltinOrDir(chartsDir), path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(by), nil
|
||||
}
|
||||
|
||||
func readProfiles(chartsDir string) (map[string]bool, error) {
|
||||
profiles := map[string]bool{}
|
||||
f := manifests.BuiltinOrDir(chartsDir)
|
||||
dir, err := fs.ReadDir(f, profilesRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, f := range dir {
|
||||
if f.Name() == "_all.yaml" {
|
||||
continue
|
||||
}
|
||||
trimmedString := strings.TrimSuffix(f.Name(), ".yaml")
|
||||
if f.Name() != trimmedString {
|
||||
profiles[trimmedString] = true
|
||||
}
|
||||
}
|
||||
return profiles, nil
|
||||
}
|
||||
|
||||
func builtinProfileToFilename(name string) string {
|
||||
if name == "" {
|
||||
return DefaultProfileFilename
|
||||
}
|
||||
return name + ".yaml"
|
||||
}
|
||||
|
||||
// stripPrefix removes the given prefix from prefix.
|
||||
func stripPrefix(path, prefix string) string {
|
||||
pl := len(strings.Split(prefix, "/"))
|
||||
pv := strings.Split(path, "/")
|
||||
return strings.Join(pv[pl:], "/")
|
||||
}
|
||||
|
||||
// ListProfiles list all the profiles.
|
||||
func ListProfiles(charts string) ([]string, error) {
|
||||
profiles, err := readProfiles(charts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return util.StringBoolMapToSlice(profiles), nil
|
||||
}
|
||||
|
||||
var DefaultFilters = []util.FilterFunc{
|
||||
util.LicenseFilter,
|
||||
util.FormatterFilter,
|
||||
util.SpaceFilter,
|
||||
}
|
||||
|
||||
// Renderer is responsible for rendering helm chart with new values.
|
||||
type Renderer interface {
|
||||
Init() error
|
||||
RenderManifest(valsYaml string) (string, error)
|
||||
SetVersion(version string)
|
||||
}
|
||||
|
||||
type RendererOptions struct {
|
||||
Name string
|
||||
Namespace string
|
||||
|
||||
// fields for LocalChartRenderer and LocalFileRenderer
|
||||
FS fs.FS
|
||||
Dir string
|
||||
|
||||
// fields for RemoteRenderer
|
||||
Version string
|
||||
RepoURL string
|
||||
}
|
||||
|
||||
type RendererOption func(*RendererOptions)
|
||||
|
||||
func WithName(name string) RendererOption {
|
||||
return func(opts *RendererOptions) {
|
||||
opts.Name = name
|
||||
}
|
||||
}
|
||||
|
||||
func WithNamespace(ns string) RendererOption {
|
||||
return func(opts *RendererOptions) {
|
||||
opts.Namespace = ns
|
||||
}
|
||||
}
|
||||
|
||||
func WithFS(f fs.FS) RendererOption {
|
||||
return func(opts *RendererOptions) {
|
||||
opts.FS = f
|
||||
}
|
||||
}
|
||||
|
||||
func WithDir(dir string) RendererOption {
|
||||
return func(opts *RendererOptions) {
|
||||
opts.Dir = dir
|
||||
}
|
||||
}
|
||||
|
||||
func WithVersion(version string) RendererOption {
|
||||
return func(opts *RendererOptions) {
|
||||
opts.Version = version
|
||||
}
|
||||
}
|
||||
|
||||
func WithRepoURL(repo string) RendererOption {
|
||||
return func(opts *RendererOptions) {
|
||||
opts.RepoURL = repo
|
||||
}
|
||||
}
|
||||
|
||||
// LocalFileRenderer load yaml files from local file system
|
||||
type LocalFileRenderer struct {
|
||||
Opts *RendererOptions
|
||||
filesMap map[string]string
|
||||
Started bool
|
||||
}
|
||||
|
||||
func NewLocalFileRenderer(opts ...RendererOption) (Renderer, error) {
|
||||
newOpts := &RendererOptions{}
|
||||
for _, opt := range opts {
|
||||
opt(newOpts)
|
||||
}
|
||||
|
||||
return &LocalFileRenderer{
|
||||
Opts: newOpts,
|
||||
filesMap: make(map[string]string),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (l *LocalFileRenderer) Init() error {
|
||||
fileNames, err := getFileNames(l.Opts.FS, l.Opts.Dir)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return fmt.Errorf("chart of component %s doesn't exist", l.Opts.Name)
|
||||
}
|
||||
return fmt.Errorf("getFileNames err: %s", err)
|
||||
}
|
||||
for _, fileName := range fileNames {
|
||||
data, err := fs.ReadFile(l.Opts.FS, fileName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ReadFile %s err: %s", fileName, err)
|
||||
}
|
||||
|
||||
l.filesMap[fileName] = string(data)
|
||||
}
|
||||
l.Started = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *LocalFileRenderer) RenderManifest(valsYaml string) (string, error) {
|
||||
if !l.Started {
|
||||
return "", errors.New("LocalFileRenderer has not been init")
|
||||
}
|
||||
keys := make([]string, 0, len(l.filesMap))
|
||||
for key := range l.filesMap {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
// to ensure that every manifest rendered by same values are the same
|
||||
sort.Strings(keys)
|
||||
|
||||
var builder strings.Builder
|
||||
for i := 0; i < len(keys); i++ {
|
||||
file := l.filesMap[keys[i]]
|
||||
file = util.ApplyFilters(file, DefaultFilters...)
|
||||
// ignore empty manifest
|
||||
if file == "" {
|
||||
continue
|
||||
}
|
||||
if !strings.HasSuffix(file, YAMLSeparator) {
|
||||
file += YAMLSeparator
|
||||
}
|
||||
builder.WriteString(file)
|
||||
}
|
||||
return builder.String(), nil
|
||||
}
|
||||
|
||||
func (l *LocalFileRenderer) SetVersion(version string) {
|
||||
l.Opts.Version = version
|
||||
}
|
||||
|
||||
// LocalChartRenderer load chart from local file system
|
||||
type LocalChartRenderer struct {
|
||||
Opts *RendererOptions
|
||||
Chart *chart.Chart
|
||||
Started bool
|
||||
}
|
||||
|
||||
func (lr *LocalChartRenderer) Init() error {
|
||||
fileNames, err := getFileNames(lr.Opts.FS, lr.Opts.Dir)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return fmt.Errorf("chart of component %s doesn't exist", lr.Opts.Name)
|
||||
}
|
||||
return fmt.Errorf("getFileNames err: %s", err)
|
||||
}
|
||||
var files []*loader.BufferedFile
|
||||
for _, fileName := range fileNames {
|
||||
data, err := fs.ReadFile(lr.Opts.FS, fileName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ReadFile %s err: %s", fileName, err)
|
||||
}
|
||||
// todo:// explain why we need to do this
|
||||
name := util.StripPrefix(fileName, lr.Opts.Dir)
|
||||
file := &loader.BufferedFile{
|
||||
Name: name,
|
||||
Data: data,
|
||||
}
|
||||
files = append(files, file)
|
||||
}
|
||||
newChart, err := loader.LoadFiles(files)
|
||||
if err != nil {
|
||||
return fmt.Errorf("load chart of component %s err: %s", lr.Opts.Name, err)
|
||||
}
|
||||
lr.Chart = newChart
|
||||
lr.Started = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (lr *LocalChartRenderer) RenderManifest(valsYaml string) (string, error) {
|
||||
if !lr.Started {
|
||||
return "", errors.New("LocalChartRenderer has not been init")
|
||||
}
|
||||
return renderManifest(valsYaml, lr.Chart, true, lr.Opts, DefaultFilters...)
|
||||
}
|
||||
|
||||
func (lr *LocalChartRenderer) SetVersion(version string) {
|
||||
lr.Opts.Version = version
|
||||
}
|
||||
|
||||
func NewLocalChartRenderer(opts ...RendererOption) (Renderer, error) {
|
||||
newOpts := &RendererOptions{}
|
||||
for _, opt := range opts {
|
||||
opt(newOpts)
|
||||
}
|
||||
|
||||
if err := verifyRendererOptions(newOpts); err != nil {
|
||||
return nil, fmt.Errorf("verify err: %s", err)
|
||||
}
|
||||
return &LocalChartRenderer{
|
||||
Opts: newOpts,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type RemoteRenderer struct {
|
||||
Opts *RendererOptions
|
||||
Chart *chart.Chart
|
||||
Started bool
|
||||
}
|
||||
|
||||
func (rr *RemoteRenderer) initChartPathOptions() *action.ChartPathOptions {
|
||||
return &action.ChartPathOptions{
|
||||
RepoURL: rr.Opts.RepoURL,
|
||||
Version: rr.Opts.Version,
|
||||
}
|
||||
}
|
||||
|
||||
func (rr *RemoteRenderer) Init() error {
|
||||
cpOpts := rr.initChartPathOptions()
|
||||
settings := cli.New()
|
||||
// using release name as chart name by default
|
||||
cp, err := locateChart(cpOpts, rr.Opts.Name, settings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check chart dependencies to make sure all are present in /charts
|
||||
chartRequested, err := loader.Load(cp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := verifyInstallable(chartRequested); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rr.Chart = chartRequested
|
||||
rr.Started = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rr *RemoteRenderer) SetVersion(version string) {
|
||||
rr.Opts.Version = version
|
||||
}
|
||||
|
||||
func (rr *RemoteRenderer) RenderManifest(valsYaml string) (string, error) {
|
||||
if !rr.Started {
|
||||
return "", errors.New("RemoteRenderer has not been init")
|
||||
}
|
||||
return renderManifest(valsYaml, rr.Chart, false, rr.Opts, DefaultFilters...)
|
||||
}
|
||||
|
||||
func NewRemoteRenderer(opts ...RendererOption) (Renderer, error) {
|
||||
newOpts := &RendererOptions{}
|
||||
for _, opt := range opts {
|
||||
opt(newOpts)
|
||||
}
|
||||
|
||||
return &RemoteRenderer{
|
||||
Opts: newOpts,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func verifyRendererOptions(opts *RendererOptions) error {
|
||||
if opts.Name == "" {
|
||||
return errors.New("missing component name for Renderer")
|
||||
}
|
||||
if opts.Namespace == "" {
|
||||
return errors.New("missing component namespace for Renderer")
|
||||
}
|
||||
if opts.FS == nil {
|
||||
return errors.New("missing chart FS for Renderer")
|
||||
}
|
||||
if opts.Dir == "" {
|
||||
return errors.New("missing chart dir for Renderer")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// read all files recursively under root path from a certain local file system
|
||||
func getFileNames(f fs.FS, root string) ([]string, error) {
|
||||
var fileNames []string
|
||||
if err := fs.WalkDir(f, root, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
fileNames = append(fileNames, path)
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fileNames, nil
|
||||
}
|
||||
|
||||
func verifyInstallable(cht *chart.Chart) error {
|
||||
typ := cht.Metadata.Type
|
||||
if typ == "" || typ == "application" {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("%s chart %s is not installable", typ, cht.Name())
|
||||
}
|
||||
|
||||
func renderManifest(valsYaml string, cht *chart.Chart, builtIn bool, opts *RendererOptions, filters ...util.FilterFunc) (string, error) {
|
||||
valsMap := make(map[string]any)
|
||||
if err := yaml.Unmarshal([]byte(valsYaml), &valsMap); err != nil {
|
||||
return "", fmt.Errorf("unmarshal failed err: %s", err)
|
||||
}
|
||||
RelOpts := chartutil.ReleaseOptions{
|
||||
Name: opts.Name,
|
||||
Namespace: opts.Namespace,
|
||||
}
|
||||
// TODO need to specify k8s version
|
||||
caps := chartutil.DefaultCapabilities
|
||||
// maybe we need a configuration to change this caps
|
||||
resVals, err := chartutil.ToRenderValues(cht, valsMap, RelOpts, caps)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("ToRenderValues failed err: %s", err)
|
||||
}
|
||||
if builtIn {
|
||||
resVals["Values"].(chartutil.Values)["enabled"] = true
|
||||
}
|
||||
filesMap, err := engine.Render(cht, resVals)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Render chart failed err: %s", err)
|
||||
}
|
||||
keys := make([]string, 0, len(filesMap))
|
||||
for key := range filesMap {
|
||||
// remove notation files such as Notes.txt
|
||||
if strings.HasSuffix(key, NotesFileNameSuffix) {
|
||||
continue
|
||||
}
|
||||
keys = append(keys, key)
|
||||
}
|
||||
// to ensure that every manifest rendered by same values are the same
|
||||
sort.Strings(keys)
|
||||
|
||||
var builder strings.Builder
|
||||
for i := 0; i < len(keys); i++ {
|
||||
file := filesMap[keys[i]]
|
||||
file = util.ApplyFilters(file, filters...)
|
||||
// ignore empty manifest
|
||||
if file == "" {
|
||||
continue
|
||||
}
|
||||
if !strings.HasSuffix(file, YAMLSeparator) {
|
||||
file += YAMLSeparator
|
||||
}
|
||||
builder.WriteString(file)
|
||||
}
|
||||
|
||||
// render CRD
|
||||
crdFiles := cht.CRDObjects()
|
||||
// Sort crd files by name to ensure stable manifest output
|
||||
sort.Slice(crdFiles, func(i, j int) bool { return crdFiles[i].Name < crdFiles[j].Name })
|
||||
for _, crdFile := range crdFiles {
|
||||
f := string(crdFile.File.Data)
|
||||
// add yaml separator if the rendered file doesn't have one at the end
|
||||
f = strings.TrimSpace(f) + "\n"
|
||||
if !strings.HasSuffix(f, YAMLSeparator) {
|
||||
f += YAMLSeparator
|
||||
}
|
||||
builder.WriteString(f)
|
||||
}
|
||||
|
||||
return builder.String(), nil
|
||||
}
|
||||
|
||||
// locateChart locate the target chart path by sequential orders:
|
||||
// 1. find local helm repository using "name-version.tgz" format
|
||||
// 2. using downloader to pull remote chart
|
||||
func locateChart(cpOpts *action.ChartPathOptions, name string, settings *cli.EnvSettings) (string, error) {
|
||||
name = strings.TrimSpace(name)
|
||||
version := strings.TrimSpace(cpOpts.Version)
|
||||
|
||||
// check if it's in Helm's chart cache
|
||||
// cacheName is hardcoded as format of helm. eg: grafana-6.31.1.tgz
|
||||
cacheName := name + "-" + cpOpts.Version + ".tgz"
|
||||
cachePath := path.Join(settings.RepositoryCache, cacheName)
|
||||
if _, err := os.Stat(cachePath); err == nil {
|
||||
abs, err := filepath.Abs(cachePath)
|
||||
if err != nil {
|
||||
return abs, err
|
||||
}
|
||||
if cpOpts.Verify {
|
||||
if _, err := downloader.VerifyChart(abs, cpOpts.Keyring); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return abs, nil
|
||||
}
|
||||
|
||||
dl := downloader.ChartDownloader{
|
||||
Out: os.Stdout,
|
||||
Keyring: cpOpts.Keyring,
|
||||
Getters: getter.All(settings),
|
||||
Options: []getter.Option{
|
||||
getter.WithPassCredentialsAll(cpOpts.PassCredentialsAll),
|
||||
getter.WithTLSClientConfig(cpOpts.CertFile, cpOpts.KeyFile, cpOpts.CaFile),
|
||||
getter.WithInsecureSkipVerifyTLS(cpOpts.InsecureSkipTLSverify),
|
||||
},
|
||||
RepositoryConfig: settings.RepositoryConfig,
|
||||
RepositoryCache: settings.RepositoryCache,
|
||||
}
|
||||
|
||||
if cpOpts.Verify {
|
||||
dl.Verify = downloader.VerifyAlways
|
||||
}
|
||||
if cpOpts.RepoURL != "" {
|
||||
chartURL, err := repo.FindChartInAuthAndTLSAndPassRepoURL(cpOpts.RepoURL, cpOpts.Username, cpOpts.Password, name, version,
|
||||
cpOpts.CertFile, cpOpts.KeyFile, cpOpts.CaFile, cpOpts.InsecureSkipTLSverify, cpOpts.PassCredentialsAll, getter.All(settings))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
name = chartURL
|
||||
|
||||
// Only pass the user/pass on when the user has said to or when the
|
||||
// location of the chart repo and the chart are the same domain.
|
||||
u1, err := url.Parse(cpOpts.RepoURL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
u2, err := url.Parse(chartURL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Host on URL (returned from url.Parse) contains the port if present.
|
||||
// This check ensures credentials are not passed between different
|
||||
// services on different ports.
|
||||
if cpOpts.PassCredentialsAll || (u1.Scheme == u2.Scheme && u1.Host == u2.Host) {
|
||||
dl.Options = append(dl.Options, getter.WithBasicAuth(cpOpts.Username, cpOpts.Password))
|
||||
} else {
|
||||
dl.Options = append(dl.Options, getter.WithBasicAuth("", ""))
|
||||
}
|
||||
} else {
|
||||
dl.Options = append(dl.Options, getter.WithBasicAuth(cpOpts.Username, cpOpts.Password))
|
||||
}
|
||||
|
||||
// if RepositoryCache doesn't exist, create it
|
||||
if err := os.MkdirAll(settings.RepositoryCache, 0o755); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
filename, _, err := dl.DownloadTo(name, version, settings.RepositoryCache)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
fileAbsPath, err := filepath.Abs(filename)
|
||||
if err != nil {
|
||||
return filename, err
|
||||
}
|
||||
return fileAbsPath, nil
|
||||
}
|
||||
|
||||
func ParseLatestVersion(repoUrl string, version string) (string, error) {
|
||||
|
||||
cpOpts := &action.ChartPathOptions{
|
||||
RepoURL: repoUrl,
|
||||
Version: version,
|
||||
}
|
||||
settings := cli.New()
|
||||
|
||||
indexURL, err := repo.ResolveReferenceURL(repoUrl, "index.yaml")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
u, err := url.Parse(repoUrl)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid chart URL format: %s", repoUrl)
|
||||
}
|
||||
|
||||
client, err := getter.All(settings).ByScheme(u.Scheme)
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("could not find protocol handler for: %s", u.Scheme)
|
||||
}
|
||||
|
||||
resp, err := client.Get(indexURL,
|
||||
getter.WithURL(cpOpts.RepoURL),
|
||||
getter.WithInsecureSkipVerifyTLS(cpOpts.InsecureSkipTLSverify),
|
||||
getter.WithTLSClientConfig(cpOpts.CertFile, cpOpts.KeyFile, cpOpts.CaFile),
|
||||
getter.WithBasicAuth(cpOpts.Username, cpOpts.Password),
|
||||
getter.WithPassCredentialsAll(cpOpts.PassCredentialsAll),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
index, err := io.ReadAll(resp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
indexFile, err := loadIndex(index)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// get higress helm chart latest version
|
||||
if entries, ok := indexFile.Entries[RepoChartIndexYamlHigressIndex]; ok {
|
||||
return entries[0].AppVersion, nil
|
||||
}
|
||||
|
||||
return "", errors.New("can't find higress latest version")
|
||||
}
|
||||
|
||||
// loadIndex loads an index file and does minimal validity checking.
|
||||
//
|
||||
// The source parameter is only used for logging.
|
||||
// This will fail if API Version is not set (ErrNoAPIVersion) or if the unmarshal fails.
|
||||
func loadIndex(data []byte) (*repo.IndexFile, error) {
|
||||
i := &repo.IndexFile{}
|
||||
if len(data) == 0 {
|
||||
return i, errors.New("empty index.yaml file")
|
||||
}
|
||||
if err := jsonOrYamlUnmarshal(data, i); err != nil {
|
||||
return i, err
|
||||
}
|
||||
for _, cvs := range i.Entries {
|
||||
for idx := len(cvs) - 1; idx >= 0; idx-- {
|
||||
if cvs[idx] == nil {
|
||||
continue
|
||||
}
|
||||
if cvs[idx].APIVersion == "" {
|
||||
cvs[idx].APIVersion = chart.APIVersionV1
|
||||
}
|
||||
if err := cvs[idx].Validate(); err != nil {
|
||||
cvs = append(cvs[:idx], cvs[idx+1:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
i.SortEntries()
|
||||
if i.APIVersion == "" {
|
||||
return i, errors.New("no API version specified")
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
// jsonOrYamlUnmarshal unmarshals the given byte slice containing JSON or YAML
|
||||
// into the provided interface.
|
||||
//
|
||||
// It automatically detects whether the data is in JSON or YAML format by
|
||||
// checking its validity as JSON. If the data is valid JSON, it will use the
|
||||
// `encoding/json` package to unmarshal it. Otherwise, it will use the
|
||||
// `sigs.k8s.io/yaml` package to unmarshal the YAML data.
|
||||
func jsonOrYamlUnmarshal(b []byte, i interface{}) error {
|
||||
if json.Valid(b) {
|
||||
return json.Unmarshal(b, i)
|
||||
}
|
||||
return yaml.UnmarshalStrict(b, i)
|
||||
}
|
||||
548
pkg/cmd/hgctl/helm/tpath/tree.go
Normal file
548
pkg/cmd/hgctl/helm/tpath/tree.go
Normal file
@@ -0,0 +1,548 @@
|
||||
// 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 tpath
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/util"
|
||||
"gopkg.in/yaml.v2"
|
||||
yaml2 "sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// PathContext provides a means for traversing a tree towards the root.
|
||||
type PathContext struct {
|
||||
// Parent in the Parent of this PathContext.
|
||||
Parent *PathContext
|
||||
// KeyToChild is the key required to reach the child.
|
||||
KeyToChild any
|
||||
// Node is the actual Node in the data tree.
|
||||
Node any
|
||||
}
|
||||
|
||||
// String implements the Stringer interface.
|
||||
func (nc *PathContext) String() string {
|
||||
ret := "\n--------------- NodeContext ------------------\n"
|
||||
if nc.Parent != nil {
|
||||
ret += fmt.Sprintf("Parent.Node=\n%s\n", nc.Parent.Node)
|
||||
ret += fmt.Sprintf("KeyToChild=%v\n", nc.Parent.KeyToChild)
|
||||
}
|
||||
|
||||
ret += fmt.Sprintf("Node=\n%s\n", nc.Node)
|
||||
ret += "----------------------------------------------\n"
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// GetPathContext returns the PathContext for the Node which has the given path from root.
|
||||
// It returns false and no error if the given path is not found, or an error code in other error situations, like
|
||||
// a malformed path.
|
||||
// It also creates a tree of PathContexts during the traversal so that Parent nodes can be updated if required. This is
|
||||
// required when (say) appending to a list, where the parent list itself must be updated.
|
||||
func GetPathContext(root any, path util.Path, createMissing bool) (*PathContext, bool, error) {
|
||||
return getPathContext(&PathContext{Node: root}, path, path, createMissing)
|
||||
}
|
||||
|
||||
// WritePathContext writes the given value to the Node in the given PathContext.
|
||||
func WritePathContext(nc *PathContext, value any, merge bool) error {
|
||||
|
||||
if !util.IsValueNil(value) {
|
||||
return setPathContext(nc, value, merge)
|
||||
}
|
||||
|
||||
if nc.Parent == nil {
|
||||
return errors.New("cannot delete root element")
|
||||
}
|
||||
|
||||
switch {
|
||||
case isSliceOrPtrInterface(nc.Parent.Node):
|
||||
if err := util.DeleteFromSlicePtr(nc.Parent.Node, nc.Parent.KeyToChild.(int)); err != nil {
|
||||
return err
|
||||
}
|
||||
if isMapOrInterface(nc.Parent.Parent.Node) {
|
||||
return util.InsertIntoMap(nc.Parent.Parent.Node, nc.Parent.Parent.KeyToChild, nc.Parent.Node)
|
||||
}
|
||||
// TODO: The case of deleting a list.list.node element is not currently supported.
|
||||
return fmt.Errorf("cannot delete path: unsupported parent.parent type %T for delete", nc.Parent.Parent.Node)
|
||||
case util.IsMap(nc.Parent.Node):
|
||||
return util.DeleteFromMap(nc.Parent.Node, nc.Parent.KeyToChild)
|
||||
default:
|
||||
}
|
||||
return fmt.Errorf("cannot delete path: unsupported parent type %T for delete", nc.Parent.Node)
|
||||
}
|
||||
|
||||
// WriteNode writes value to the tree in root at the given path, creating any required missing internal nodes in path.
|
||||
func WriteNode(root any, path util.Path, value any) error {
|
||||
pc, _, err := getPathContext(&PathContext{Node: root}, path, path, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return WritePathContext(pc, value, false)
|
||||
}
|
||||
|
||||
// MergeNode merges value to the tree in root at the given path, creating any required missing internal nodes in path.
|
||||
func MergeNode(root any, path util.Path, value any) error {
|
||||
pc, _, err := getPathContext(&PathContext{Node: root}, path, path, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return WritePathContext(pc, value, true)
|
||||
}
|
||||
|
||||
// Find returns the value at path from the given tree, or false if the path does not exist.
|
||||
// It behaves differently from GetPathContext in that it never creates map entries at the leaf and does not provide
|
||||
// a way to mutate the parent of the found node.
|
||||
func Find(inputTree map[string]any, path util.Path) (any, bool, error) {
|
||||
if len(path) == 0 {
|
||||
return nil, false, fmt.Errorf("path is empty")
|
||||
}
|
||||
node, found := find(inputTree, path)
|
||||
return node, found, nil
|
||||
}
|
||||
|
||||
// Delete sets value at path of input untyped tree to nil
|
||||
func Delete(root map[string]any, path util.Path) (bool, error) {
|
||||
pc, _, err := getPathContext(&PathContext{Node: root}, path, path, false)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, WritePathContext(pc, nil, false)
|
||||
}
|
||||
|
||||
// getPathContext is the internal implementation of GetPathContext.
|
||||
// If createMissing is true, it creates any missing map (but NOT list) path entries in root.
|
||||
func getPathContext(nc *PathContext, fullPath, remainPath util.Path, createMissing bool) (*PathContext, bool, error) {
|
||||
if len(remainPath) == 0 {
|
||||
return nc, true, nil
|
||||
}
|
||||
pe := remainPath[0]
|
||||
|
||||
if nc.Node == nil {
|
||||
if !createMissing {
|
||||
return nil, false, fmt.Errorf("node %s is zero", pe)
|
||||
}
|
||||
if util.IsNPathElement(pe) || util.IsKVPathElement(pe) {
|
||||
nc.Node = []any{}
|
||||
} else {
|
||||
nc.Node = make(map[string]any)
|
||||
}
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(nc.Node)
|
||||
if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
|
||||
v = v.Elem()
|
||||
}
|
||||
ncNode := v.Interface()
|
||||
|
||||
// For list types, we need a key to identify the selected list item. This can be either a value key of the
|
||||
// form :matching_value in the case of a leaf list, or a matching key:value in the case of a non-leaf list.
|
||||
if lst, ok := ncNode.([]any); ok {
|
||||
// If the path element has the form [N], a list element is being selected by index. Return the element at index
|
||||
// N if it exists.
|
||||
if util.IsNPathElement(pe) {
|
||||
idx, err := util.PathN(pe)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("path %s, index %s: %s", fullPath, pe, err)
|
||||
}
|
||||
var foundNode any
|
||||
if idx >= len(lst) || idx < 0 {
|
||||
if !createMissing {
|
||||
return nil, false, fmt.Errorf("index %d exceeds list length %d at path %s", idx, len(lst), remainPath)
|
||||
}
|
||||
idx = len(lst)
|
||||
foundNode = make(map[string]any)
|
||||
} else {
|
||||
foundNode = lst[idx]
|
||||
}
|
||||
nn := &PathContext{
|
||||
Parent: nc,
|
||||
Node: foundNode,
|
||||
}
|
||||
nc.KeyToChild = idx
|
||||
return getPathContext(nn, fullPath, remainPath[1:], createMissing)
|
||||
}
|
||||
|
||||
// Otherwise the path element must have form [key:value]. In this case, go through all list elements, which
|
||||
// must have map type, and try to find one which has a matching key:value.
|
||||
for idx, le := range lst {
|
||||
// non-leaf list, expect to match item by key:value.
|
||||
if lm, ok := le.(map[any]any); ok {
|
||||
k, v, err := util.PathKV(pe)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("path %s: %s", fullPath, err)
|
||||
}
|
||||
if stringsEqual(lm[k], v) {
|
||||
nn := &PathContext{
|
||||
Parent: nc,
|
||||
Node: lm,
|
||||
}
|
||||
nc.KeyToChild = idx
|
||||
nn.KeyToChild = k
|
||||
if len(remainPath) == 1 {
|
||||
return nn, true, nil
|
||||
}
|
||||
return getPathContext(nn, fullPath, remainPath[1:], createMissing)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// repeat of the block above for the case where tree unmarshals to map[string]interface{}. There doesn't
|
||||
// seem to be a way to merge this case into the above block.
|
||||
if lm, ok := le.(map[string]any); ok {
|
||||
k, v, err := util.PathKV(pe)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("path %s: %s", fullPath, err)
|
||||
}
|
||||
if stringsEqual(lm[k], v) {
|
||||
nn := &PathContext{
|
||||
Parent: nc,
|
||||
Node: lm,
|
||||
}
|
||||
nc.KeyToChild = idx
|
||||
nn.KeyToChild = k
|
||||
if len(remainPath) == 1 {
|
||||
return nn, true, nil
|
||||
}
|
||||
return getPathContext(nn, fullPath, remainPath[1:], createMissing)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// leaf list, expect path element [V], match based on value V.
|
||||
v, err := util.PathV(pe)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("path %s: %s", fullPath, err)
|
||||
}
|
||||
if matchesRegex(v, le) {
|
||||
nn := &PathContext{
|
||||
Parent: nc,
|
||||
Node: le,
|
||||
}
|
||||
nc.KeyToChild = idx
|
||||
return getPathContext(nn, fullPath, remainPath[1:], createMissing)
|
||||
}
|
||||
}
|
||||
return nil, false, fmt.Errorf("path %s: element %s not found", fullPath, pe)
|
||||
}
|
||||
|
||||
if util.IsMap(ncNode) {
|
||||
var nn any
|
||||
if m, ok := ncNode.(map[any]any); ok {
|
||||
nn, ok = m[pe]
|
||||
if !ok {
|
||||
// remainPath == 1 means the patch is creation of a new leaf.
|
||||
if createMissing || len(remainPath) == 1 {
|
||||
m[pe] = make(map[any]any)
|
||||
nn = m[pe]
|
||||
} else {
|
||||
return nil, false, fmt.Errorf("path not found at element %s in path %s", pe, fullPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
if reflect.ValueOf(ncNode).IsNil() {
|
||||
ncNode = make(map[string]any)
|
||||
nc.Node = ncNode
|
||||
}
|
||||
if m, ok := ncNode.(map[string]any); ok {
|
||||
nn, ok = m[pe]
|
||||
if !ok {
|
||||
// remainPath == 1 means the patch is creation of a new leaf.
|
||||
if createMissing || len(remainPath) == 1 {
|
||||
nextElementNPath := len(remainPath) > 1 && util.IsNPathElement(remainPath[1])
|
||||
if nextElementNPath {
|
||||
m[pe] = make([]any, 0)
|
||||
} else {
|
||||
m[pe] = make(map[string]any)
|
||||
}
|
||||
nn = m[pe]
|
||||
} else {
|
||||
return nil, false, fmt.Errorf("path not found at element %s in path %s", pe, fullPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
npc := &PathContext{
|
||||
Parent: nc,
|
||||
Node: nn,
|
||||
}
|
||||
// for slices, use the address so that the slice can be mutated.
|
||||
if util.IsSlice(nn) {
|
||||
npc.Node = &nn
|
||||
}
|
||||
nc.KeyToChild = pe
|
||||
return getPathContext(npc, fullPath, remainPath[1:], createMissing)
|
||||
}
|
||||
|
||||
return nil, false, fmt.Errorf("leaf type %T in non-leaf Node %s", nc.Node, remainPath)
|
||||
}
|
||||
|
||||
// setPathContext writes the given value to the Node in the given PathContext,
|
||||
// enlarging all PathContext lists to ensure all indexes are valid.
|
||||
func setPathContext(nc *PathContext, value any, merge bool) error {
|
||||
processParent, err := setValueContext(nc, value, merge)
|
||||
if err != nil || !processParent {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the path included insertions, process them now
|
||||
if nc.Parent.Parent == nil {
|
||||
return nil
|
||||
}
|
||||
return setPathContext(nc.Parent, nc.Parent.Node, false) // note: tail recursive
|
||||
}
|
||||
|
||||
// setValueContext writes the given value to the Node in the given PathContext.
|
||||
// If setting the value requires growing the final slice, grows it.
|
||||
func setValueContext(nc *PathContext, value any, merge bool) (bool, error) {
|
||||
if nc.Parent == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
vv, mapFromString := tryToUnmarshalStringToYAML(value)
|
||||
|
||||
switch parentNode := nc.Parent.Node.(type) {
|
||||
case *any:
|
||||
switch vParentNode := (*parentNode).(type) {
|
||||
case []any:
|
||||
idx := nc.Parent.KeyToChild.(int)
|
||||
if idx == -1 {
|
||||
// Treat -1 as insert-at-end of list
|
||||
idx = len(vParentNode)
|
||||
}
|
||||
|
||||
if idx >= len(vParentNode) {
|
||||
newElements := make([]any, idx-len(vParentNode)+1)
|
||||
vParentNode = append(vParentNode, newElements...)
|
||||
*parentNode = vParentNode
|
||||
}
|
||||
|
||||
merged, err := mergeConditional(vv, nc.Node, merge)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
vParentNode[idx] = merged
|
||||
nc.Node = merged
|
||||
default:
|
||||
return false, fmt.Errorf("don't know about vtype %T", vParentNode)
|
||||
}
|
||||
case map[string]any:
|
||||
key := nc.Parent.KeyToChild.(string)
|
||||
|
||||
// Update is treated differently depending on whether the value is a scalar or map type. If scalar,
|
||||
// insert a new element into the terminal node, otherwise replace the terminal node with the new subtree.
|
||||
if ncNode, ok := nc.Node.(*any); ok && !mapFromString {
|
||||
switch vNcNode := (*ncNode).(type) {
|
||||
case []any:
|
||||
switch vv.(type) {
|
||||
case map[string]any:
|
||||
// the vv is a map, and the node is a slice
|
||||
mergedValue := append(vNcNode, vv)
|
||||
parentNode[key] = mergedValue
|
||||
case *any:
|
||||
merged, err := mergeConditional(vv, vNcNode, merge)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
parentNode[key] = merged
|
||||
nc.Node = merged
|
||||
default:
|
||||
// the vv is an basic JSON type (int, float, string, bool)
|
||||
vv = append(vNcNode, vv)
|
||||
parentNode[key] = vv
|
||||
nc.Node = vv
|
||||
}
|
||||
default:
|
||||
return false, fmt.Errorf("don't know about vnc type %T", vNcNode)
|
||||
}
|
||||
} else {
|
||||
// For map passed as string type, the root is the new key.
|
||||
if mapFromString {
|
||||
if err := util.DeleteFromMap(nc.Parent.Node, nc.Parent.KeyToChild); err != nil {
|
||||
return false, err
|
||||
}
|
||||
vm := vv.(map[string]any)
|
||||
newKey := getTreeRoot(vm)
|
||||
return false, util.InsertIntoMap(nc.Parent.Node, newKey, vm[newKey])
|
||||
}
|
||||
parentNode[key] = vv
|
||||
nc.Node = vv
|
||||
}
|
||||
// TODO `map[interface{}]interface{}` is used by tests in operator/cmd/mesh, we should add our own tests
|
||||
case map[any]any:
|
||||
key := nc.Parent.KeyToChild.(string)
|
||||
parentNode[key] = vv
|
||||
nc.Node = vv
|
||||
default:
|
||||
return false, fmt.Errorf("don't know about type %T", parentNode)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// mergeConditional returns a merge of newVal and originalVal if merge is true, otherwise it returns newVal.
|
||||
func mergeConditional(newVal, originalVal any, merge bool) (any, error) {
|
||||
if !merge || util.IsValueNilOrDefault(originalVal) {
|
||||
return newVal, nil
|
||||
}
|
||||
newS, err := yaml.Marshal(newVal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if util.IsYAMLEmpty(string(newS)) {
|
||||
return originalVal, nil
|
||||
}
|
||||
originalS, err := yaml.Marshal(originalVal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if util.IsYAMLEmpty(string(originalS)) {
|
||||
return newVal, nil
|
||||
}
|
||||
|
||||
mergedS, err := util.OverlayYAML(string(originalS), string(newS))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if util.IsMap(originalVal) {
|
||||
// For JSON compatibility
|
||||
out := make(map[string]any)
|
||||
if err := yaml.Unmarshal([]byte(mergedS), &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
// For scalars and slices, copy the type
|
||||
out := originalVal
|
||||
if err := yaml.Unmarshal([]byte(mergedS), &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// find returns the value at path from the given tree, or false if the path does not exist.
|
||||
func find(treeNode any, path util.Path) (any, bool) {
|
||||
if len(path) == 0 || treeNode == nil {
|
||||
return nil, false
|
||||
}
|
||||
switch nt := treeNode.(type) {
|
||||
case map[any]any:
|
||||
val := nt[path[0]]
|
||||
if val == nil {
|
||||
return nil, false
|
||||
}
|
||||
if len(path) == 1 {
|
||||
return val, true
|
||||
}
|
||||
return find(val, path[1:])
|
||||
case map[string]any:
|
||||
val := nt[path[0]]
|
||||
if val == nil {
|
||||
return nil, false
|
||||
}
|
||||
if len(path) == 1 {
|
||||
return val, true
|
||||
}
|
||||
return find(val, path[1:])
|
||||
case []any:
|
||||
idx, err := strconv.Atoi(path[0])
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
if idx >= len(nt) {
|
||||
return nil, false
|
||||
}
|
||||
val := nt[idx]
|
||||
return find(val, path[1:])
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
// stringsEqual reports whether the string representations of a and b are equal. a and b may have different types.
|
||||
func stringsEqual(a, b any) bool {
|
||||
return fmt.Sprint(a) == fmt.Sprint(b)
|
||||
}
|
||||
|
||||
// matchesRegex reports whether str regex matches pattern.
|
||||
func matchesRegex(pattern, str any) bool {
|
||||
match, err := regexp.MatchString(fmt.Sprint(pattern), fmt.Sprint(str))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return match
|
||||
}
|
||||
|
||||
// isSliceOrPtrInterface reports whether v is a slice, a ptr to slice or interface to slice.
|
||||
func isSliceOrPtrInterface(v any) bool {
|
||||
vv := reflect.ValueOf(v)
|
||||
if vv.Kind() == reflect.Ptr {
|
||||
vv = vv.Elem()
|
||||
}
|
||||
if vv.Kind() == reflect.Interface {
|
||||
vv = vv.Elem()
|
||||
}
|
||||
return vv.Kind() == reflect.Slice
|
||||
}
|
||||
|
||||
// isMapOrInterface reports whether v is a map, or interface to a map.
|
||||
func isMapOrInterface(v any) bool {
|
||||
vv := reflect.ValueOf(v)
|
||||
if vv.Kind() == reflect.Interface {
|
||||
vv = vv.Elem()
|
||||
}
|
||||
return vv.Kind() == reflect.Map
|
||||
}
|
||||
|
||||
// tryToUnmarshalStringToYAML tries to unmarshal something that may be a YAML list or map into a structure. If not
|
||||
// possible, returns original scalar value.
|
||||
func tryToUnmarshalStringToYAML(s any) (any, bool) {
|
||||
// If value type is a string it could either be a literal string or a map type passed as a string. Try to unmarshal
|
||||
// to discover it's the latter.
|
||||
vv := s
|
||||
|
||||
if reflect.TypeOf(vv).Kind() == reflect.String {
|
||||
sv := strings.Split(vv.(string), "\n")
|
||||
// Need to be careful not to transform string literals into maps unless they really are maps, since scalar handling
|
||||
// is different for inserts.
|
||||
if len(sv) == 1 && strings.Contains(s.(string), ": ") ||
|
||||
len(sv) > 1 && strings.Contains(s.(string), ":") {
|
||||
nv := make(map[string]any)
|
||||
if err := json.Unmarshal([]byte(vv.(string)), &nv); err == nil {
|
||||
// treat JSON as string
|
||||
return vv, false
|
||||
}
|
||||
if err := yaml2.Unmarshal([]byte(vv.(string)), &nv); err == nil {
|
||||
return nv, true
|
||||
}
|
||||
}
|
||||
}
|
||||
// looks like a literal or failed unmarshal, return original type.
|
||||
return vv, false
|
||||
}
|
||||
|
||||
// getTreeRoot returns the first key found in m. It assumes a single root tree.
|
||||
func getTreeRoot(m map[string]any) string {
|
||||
for k := range m {
|
||||
return k
|
||||
}
|
||||
return ""
|
||||
}
|
||||
843
pkg/cmd/hgctl/helm/tpath/tree_test.go
Normal file
843
pkg/cmd/hgctl/helm/tpath/tree_test.go
Normal file
@@ -0,0 +1,843 @@
|
||||
// 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 tpath
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/util"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
func TestWritePathContext(t *testing.T) {
|
||||
rootYAML := `
|
||||
a:
|
||||
b:
|
||||
- name: n1
|
||||
value: v1
|
||||
- name: n2
|
||||
list:
|
||||
- v1
|
||||
- v2
|
||||
- v3_regex
|
||||
`
|
||||
tests := []struct {
|
||||
desc string
|
||||
path string
|
||||
value any
|
||||
want string
|
||||
wantFound bool
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
desc: "AddListEntry",
|
||||
path: `a.b.[name:n2].list`,
|
||||
value: `foo`,
|
||||
wantFound: true,
|
||||
want: `
|
||||
a:
|
||||
b:
|
||||
- name: n1
|
||||
value: v1
|
||||
- name: n2
|
||||
list:
|
||||
- v1
|
||||
- v2
|
||||
- v3_regex
|
||||
- foo
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "ModifyListEntryValue",
|
||||
path: `a.b.[name:n1].value`,
|
||||
value: `v2`,
|
||||
wantFound: true,
|
||||
want: `
|
||||
a:
|
||||
b:
|
||||
- name: n1
|
||||
value: v2
|
||||
- list:
|
||||
- v1
|
||||
- v2
|
||||
- v3_regex
|
||||
name: n2
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "ModifyListEntryValueQuoted",
|
||||
path: `a.b.[name:n1].value`,
|
||||
value: `v2`,
|
||||
wantFound: true,
|
||||
want: `
|
||||
a:
|
||||
b:
|
||||
- name: "n1"
|
||||
value: v2
|
||||
- list:
|
||||
- v1
|
||||
- v2
|
||||
- v3_regex
|
||||
name: n2
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "ModifyListEntry",
|
||||
path: `a.b.[name:n2].list.[:v2]`,
|
||||
value: `v3`,
|
||||
wantFound: true,
|
||||
want: `
|
||||
a:
|
||||
b:
|
||||
- name: n1
|
||||
value: v1
|
||||
- list:
|
||||
- v1
|
||||
- v3
|
||||
- v3_regex
|
||||
name: n2
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "ModifyListEntryMapValue",
|
||||
path: `a.b.[name:n2]`,
|
||||
value: `name: n2
|
||||
list:
|
||||
- nk1: nv1
|
||||
- nk2: nv2`,
|
||||
wantFound: true,
|
||||
want: `
|
||||
a:
|
||||
b:
|
||||
- name: n1
|
||||
value: v1
|
||||
- name: n2
|
||||
list:
|
||||
- nk1: nv1
|
||||
- nk2: nv2
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "ModifyNthListEntry",
|
||||
path: `a.b.[1].list.[:v2]`,
|
||||
value: `v-the-second`,
|
||||
wantFound: true,
|
||||
want: `
|
||||
a:
|
||||
b:
|
||||
- name: n1
|
||||
value: v1
|
||||
- list:
|
||||
- v1
|
||||
- v-the-second
|
||||
- v3_regex
|
||||
name: n2
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "ModifyNthLeafListEntry",
|
||||
path: `a.b.[1].list.[2]`,
|
||||
value: `v-the-third`,
|
||||
wantFound: true,
|
||||
want: `
|
||||
a:
|
||||
b:
|
||||
- name: n1
|
||||
value: v1
|
||||
- list:
|
||||
- v1
|
||||
- v2
|
||||
- v-the-third
|
||||
name: n2
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "ModifyListEntryValueDotless",
|
||||
path: `a.b[name:n1].value`,
|
||||
value: `v2`,
|
||||
wantFound: true,
|
||||
want: `
|
||||
a:
|
||||
b:
|
||||
- name: n1
|
||||
value: v2
|
||||
- list:
|
||||
- v1
|
||||
- v2
|
||||
- v3_regex
|
||||
name: n2
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "DeleteListEntry",
|
||||
path: `a.b.[name:n1]`,
|
||||
wantFound: true,
|
||||
want: `
|
||||
a:
|
||||
b:
|
||||
- list:
|
||||
- v1
|
||||
- v2
|
||||
- v3_regex
|
||||
name: n2
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "DeleteListEntryValue",
|
||||
path: `a.b.[name:n2].list.[:v2]`,
|
||||
wantFound: true,
|
||||
want: `
|
||||
a:
|
||||
b:
|
||||
- name: n1
|
||||
value: v1
|
||||
- list:
|
||||
- v1
|
||||
- v3_regex
|
||||
name: n2
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "DeleteListEntryIndex",
|
||||
path: `a.b.[name:n2].list.[1]`,
|
||||
wantFound: true,
|
||||
want: `
|
||||
a:
|
||||
b:
|
||||
- name: n1
|
||||
value: v1
|
||||
- list:
|
||||
- v1
|
||||
- v3_regex
|
||||
name: n2
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "DeleteListEntryValueRegex",
|
||||
path: `a.b.[name:n2].list.[:v3]`,
|
||||
wantFound: true,
|
||||
want: `
|
||||
a:
|
||||
b:
|
||||
- name: n1
|
||||
value: v1
|
||||
- list:
|
||||
- v1
|
||||
- v2
|
||||
name: n2
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "DeleteListLeafEntryBogusIndex",
|
||||
path: `a.b.[name:n2].list.[-200]`,
|
||||
wantFound: false,
|
||||
wantErr: `path a.b.[name:n2].list.[-200]: element [-200] not found`,
|
||||
},
|
||||
{
|
||||
desc: "DeleteListEntryBogusIndex",
|
||||
path: `a.b.[1000000].list.[:v2]`,
|
||||
wantFound: false,
|
||||
wantErr: `index 1000000 exceeds list length 2 at path [1000000].list.[:v2]`,
|
||||
},
|
||||
{
|
||||
desc: "AddMapEntry",
|
||||
path: `a.new_key`,
|
||||
value: `new_val`,
|
||||
wantFound: true,
|
||||
want: `
|
||||
a:
|
||||
b:
|
||||
- name: n1
|
||||
value: v1
|
||||
- name: n2
|
||||
list:
|
||||
- v1
|
||||
- v2
|
||||
- v3_regex
|
||||
new_key: new_val
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "AddMapEntryMapValue",
|
||||
path: `a.new_key`,
|
||||
value: `new_key:
|
||||
nk1:
|
||||
nk2: nv2`,
|
||||
wantFound: true,
|
||||
want: `
|
||||
a:
|
||||
b:
|
||||
- name: n1
|
||||
value: v1
|
||||
- name: n2
|
||||
list:
|
||||
- v1
|
||||
- v2
|
||||
- v3_regex
|
||||
new_key:
|
||||
nk1:
|
||||
nk2: nv2
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "ModifyMapEntryMapValue",
|
||||
path: `a.b`,
|
||||
value: `nk1:
|
||||
nk2: nv2`,
|
||||
wantFound: true,
|
||||
want: `
|
||||
a:
|
||||
nk1:
|
||||
nk2: nv2
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "DeleteMapEntry",
|
||||
path: `a.b`,
|
||||
wantFound: true,
|
||||
want: `
|
||||
a: {}
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "path not found",
|
||||
path: `a.c.[name:n2].list.[:v3]`,
|
||||
wantFound: false,
|
||||
wantErr: `path not found at element c in path a.c.[name:n2].list.[:v3]`,
|
||||
},
|
||||
{
|
||||
desc: "error key",
|
||||
path: `a.b.[].list`,
|
||||
wantFound: false,
|
||||
wantErr: `path a.b.[].list: [] is not a valid key:value path element`,
|
||||
},
|
||||
{
|
||||
desc: "invalid index",
|
||||
path: `a.c.[n2].list.[:v3]`,
|
||||
wantFound: false,
|
||||
wantErr: `path not found at element c in path a.c.[n2].list.[:v3]`,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
root := make(map[string]any)
|
||||
if err := yaml.Unmarshal([]byte(rootYAML), &root); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pc, gotFound, gotErr := GetPathContext(root, util.PathFromString(tt.path), false)
|
||||
if gotErr, wantErr := errToString(gotErr), tt.wantErr; gotErr != wantErr {
|
||||
t.Fatalf("GetPathContext(%s): gotErr:%s, wantErr:%s", tt.desc, gotErr, wantErr)
|
||||
}
|
||||
if gotFound != tt.wantFound {
|
||||
t.Fatalf("GetPathContext(%s): gotFound:%v, wantFound:%v", tt.desc, gotFound, tt.wantFound)
|
||||
}
|
||||
if tt.wantErr != "" || !tt.wantFound {
|
||||
if tt.want != "" {
|
||||
t.Error("tt.want is set but never checked")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
err := WritePathContext(pc, tt.value, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
gotYAML := util.ToYAML(root)
|
||||
diff := util.YAMLDiff(gotYAML, tt.want)
|
||||
if diff != "" {
|
||||
t.Errorf("%s: (got:-, want:+):\n%s\n", tt.desc, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteNode(t *testing.T) {
|
||||
testTreeYAML := `
|
||||
a:
|
||||
b:
|
||||
c: val1
|
||||
list1:
|
||||
- i1: val1
|
||||
- i2: val2
|
||||
- i3a: key1
|
||||
i3b:
|
||||
list2:
|
||||
- i1: val1
|
||||
- i2: val2
|
||||
- i3a: key1
|
||||
i3b:
|
||||
i1: va11
|
||||
`
|
||||
tests := []struct {
|
||||
desc string
|
||||
baseYAML string
|
||||
path string
|
||||
value string
|
||||
want string
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
desc: "insert empty",
|
||||
path: "a.b.c",
|
||||
value: "val1",
|
||||
want: `
|
||||
a:
|
||||
b:
|
||||
c: val1
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "overwrite",
|
||||
baseYAML: testTreeYAML,
|
||||
path: "a.b.c",
|
||||
value: "val2",
|
||||
want: `
|
||||
a:
|
||||
b:
|
||||
c: val2
|
||||
list1:
|
||||
- i1: val1
|
||||
- i2: val2
|
||||
- i3a: key1
|
||||
i3b:
|
||||
list2:
|
||||
- i1: val1
|
||||
- i2: val2
|
||||
- i3a: key1
|
||||
i3b:
|
||||
i1: va11
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "partial create",
|
||||
baseYAML: testTreeYAML,
|
||||
path: "a.b.d",
|
||||
value: "val3",
|
||||
want: `
|
||||
a:
|
||||
b:
|
||||
c: val1
|
||||
d: val3
|
||||
list1:
|
||||
- i1: val1
|
||||
- i2: val2
|
||||
- i3a: key1
|
||||
i3b:
|
||||
list2:
|
||||
- i1: val1
|
||||
- i2: val2
|
||||
- i3a: key1
|
||||
i3b:
|
||||
i1: va11
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "list keys",
|
||||
baseYAML: testTreeYAML,
|
||||
path: "a.b.list1.[i3a:key1].i3b.list2.[i3a:key1].i3b.i1",
|
||||
value: "val2",
|
||||
want: `
|
||||
a:
|
||||
b:
|
||||
c: val1
|
||||
list1:
|
||||
- i1: val1
|
||||
- i2: val2
|
||||
- i3a: key1
|
||||
i3b:
|
||||
list2:
|
||||
- i1: val1
|
||||
- i2: val2
|
||||
- i3a: key1
|
||||
i3b:
|
||||
i1: val2
|
||||
`,
|
||||
},
|
||||
// For https://github.com/istio/istio/issues/20950
|
||||
{
|
||||
desc: "with initial list",
|
||||
baseYAML: `
|
||||
components:
|
||||
ingressGateways:
|
||||
- enabled: true
|
||||
`,
|
||||
path: "components.ingressGateways[0].enabled",
|
||||
value: "false",
|
||||
want: `
|
||||
components:
|
||||
ingressGateways:
|
||||
- enabled: "false"
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "no initial list",
|
||||
baseYAML: "",
|
||||
path: "components.ingressGateways[0].enabled",
|
||||
value: "false",
|
||||
want: `
|
||||
components:
|
||||
ingressGateways:
|
||||
- enabled: "false"
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "no initial list for entry",
|
||||
baseYAML: `
|
||||
a: {}
|
||||
`,
|
||||
path: "a.list.[0]",
|
||||
value: "v1",
|
||||
want: `
|
||||
a:
|
||||
list:
|
||||
- v1
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "ExtendNthLeafListEntry",
|
||||
baseYAML: `
|
||||
a:
|
||||
list:
|
||||
- v1
|
||||
`,
|
||||
path: `a.list.[1]`,
|
||||
value: `v2`,
|
||||
want: `
|
||||
a:
|
||||
list:
|
||||
- v1
|
||||
- v2
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "ExtendLeafListEntryLargeIndex",
|
||||
baseYAML: `
|
||||
a:
|
||||
list:
|
||||
- v1
|
||||
`,
|
||||
path: `a.list.[999]`,
|
||||
value: `v2`,
|
||||
want: `
|
||||
a:
|
||||
list:
|
||||
- v1
|
||||
- v2
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "ExtendLeafListEntryNegativeIndex",
|
||||
baseYAML: `
|
||||
a:
|
||||
list:
|
||||
- v1
|
||||
`,
|
||||
path: `a.list.[-1]`,
|
||||
value: `v2`,
|
||||
want: `
|
||||
a:
|
||||
list:
|
||||
- v1
|
||||
- v2
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "ExtendNthListEntry",
|
||||
baseYAML: `
|
||||
a:
|
||||
list:
|
||||
- name: foo
|
||||
`,
|
||||
path: `a.list.[1].name`,
|
||||
value: `bar`,
|
||||
want: `
|
||||
a:
|
||||
list:
|
||||
- name: foo
|
||||
- name: bar
|
||||
`,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
root := make(map[string]any)
|
||||
if tt.baseYAML != "" {
|
||||
if err := yaml.Unmarshal([]byte(tt.baseYAML), &root); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
p := util.PathFromString(tt.path)
|
||||
err := WriteNode(root, p, tt.value)
|
||||
if gotErr, wantErr := errToString(err), tt.wantErr; gotErr != wantErr {
|
||||
t.Errorf("%s: gotErr:%s, wantErr:%s", tt.desc, gotErr, wantErr)
|
||||
return
|
||||
}
|
||||
if got, want := util.ToYAML(root), tt.want; err == nil && util.YAMLDiff(got, want) != "" {
|
||||
t.Errorf("%s: got:\n%s\nwant:\n%s\ndiff:\n%s\n", tt.desc, got, want, util.YAMLDiff(got, want))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergeNode(t *testing.T) {
|
||||
testTreeYAML := `
|
||||
a:
|
||||
b:
|
||||
c: val1
|
||||
list1:
|
||||
- i1: val1
|
||||
- i2: val2
|
||||
`
|
||||
tests := []struct {
|
||||
desc string
|
||||
baseYAML string
|
||||
path string
|
||||
value string
|
||||
want string
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
desc: "merge list entry",
|
||||
baseYAML: testTreeYAML,
|
||||
path: "a.b.list1.[i1:val1]",
|
||||
value: `
|
||||
i2b: val2`,
|
||||
want: `
|
||||
a:
|
||||
b:
|
||||
c: val1
|
||||
list1:
|
||||
- i1: val1
|
||||
i2b: val2
|
||||
- i2: val2
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "merge list 2",
|
||||
baseYAML: testTreeYAML,
|
||||
path: "a.b.list1",
|
||||
value: `
|
||||
i3:
|
||||
a: val3
|
||||
`,
|
||||
want: `
|
||||
a:
|
||||
b:
|
||||
c: val1
|
||||
list1:
|
||||
- i1: val1
|
||||
- i2: val2
|
||||
- i3:
|
||||
a: val3
|
||||
`,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
root := make(map[string]any)
|
||||
if tt.baseYAML != "" {
|
||||
if err := yaml.Unmarshal([]byte(tt.baseYAML), &root); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
p := util.PathFromString(tt.path)
|
||||
iv := make(map[string]any)
|
||||
err := yaml.Unmarshal([]byte(tt.value), &iv)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = MergeNode(root, p, iv)
|
||||
if gotErr, wantErr := errToString(err), tt.wantErr; gotErr != wantErr {
|
||||
t.Errorf("%s: gotErr:%s, wantErr:%s", tt.desc, gotErr, wantErr)
|
||||
return
|
||||
}
|
||||
if got, want := util.ToYAML(root), tt.want; err == nil && util.YAMLDiff(got, want) != "" {
|
||||
t.Errorf("%s: got:\n%s\nwant:\n%s\ndiff:\n%s\n", tt.desc, got, want, util.YAMLDiff(got, want))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// errToString returns the string representation of err and the empty string if
|
||||
// err is nil.
|
||||
func errToString(err error) string {
|
||||
if err == nil {
|
||||
return ""
|
||||
}
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
// TestSecretVolumes simulates https://github.com/istio/istio/issues/20381
|
||||
func TestSecretVolumes(t *testing.T) {
|
||||
rootYAML := `
|
||||
values:
|
||||
gateways:
|
||||
istio-egressgateway:
|
||||
secretVolumes: []
|
||||
`
|
||||
root := make(map[string]any)
|
||||
if err := yaml.Unmarshal([]byte(rootYAML), &root); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
overrides := []struct {
|
||||
path string
|
||||
value any
|
||||
}{
|
||||
{
|
||||
path: "values.gateways.istio-egressgateway.secretVolumes[0].name",
|
||||
value: "egressgateway-certs",
|
||||
},
|
||||
{
|
||||
path: "values.gateways.istio-egressgateway.secretVolumes[0].secretName",
|
||||
value: "istio-egressgateway-certs",
|
||||
},
|
||||
{
|
||||
path: "values.gateways.istio-egressgateway.secretVolumes[0].mountPath",
|
||||
value: "/etc/istio/egressgateway-certs",
|
||||
},
|
||||
{
|
||||
path: "values.gateways.istio-egressgateway.secretVolumes[1].name",
|
||||
value: "egressgateway-ca-certs",
|
||||
},
|
||||
{
|
||||
path: "values.gateways.istio-egressgateway.secretVolumes[1].secretName",
|
||||
value: "istio-egressgateway-ca-certs",
|
||||
},
|
||||
{
|
||||
path: "values.gateways.istio-egressgateway.secretVolumes[1].mountPath",
|
||||
value: "/etc/istio/egressgateway-ca-certs",
|
||||
},
|
||||
{
|
||||
path: "values.gateways.istio-egressgateway.secretVolumes[2].name",
|
||||
value: "nginx-client-certs",
|
||||
},
|
||||
{
|
||||
path: "values.gateways.istio-egressgateway.secretVolumes[2].secretName",
|
||||
value: "nginx-client-certs",
|
||||
},
|
||||
{
|
||||
path: "values.gateways.istio-egressgateway.secretVolumes[2].mountPath",
|
||||
value: "/etc/istio/nginx-client-certs",
|
||||
},
|
||||
{
|
||||
path: "values.gateways.istio-egressgateway.secretVolumes[3].name",
|
||||
value: "nginx-ca-certs",
|
||||
},
|
||||
{
|
||||
path: "values.gateways.istio-egressgateway.secretVolumes[3].secretName",
|
||||
value: "nginx-ca-certs",
|
||||
},
|
||||
{
|
||||
path: "values.gateways.istio-egressgateway.secretVolumes[3].mountPath",
|
||||
value: "/etc/istio/nginx-ca-certs",
|
||||
},
|
||||
}
|
||||
|
||||
for _, override := range overrides {
|
||||
|
||||
pc, _, err := GetPathContext(root, util.PathFromString(override.path), true)
|
||||
if err != nil {
|
||||
t.Fatalf("GetPathContext(%q): %v", override.path, err)
|
||||
}
|
||||
err = WritePathContext(pc, override.value, false)
|
||||
if err != nil {
|
||||
t.Fatalf("WritePathContext(%q): %v", override.path, err)
|
||||
}
|
||||
}
|
||||
|
||||
want := `
|
||||
values:
|
||||
gateways:
|
||||
istio-egressgateway:
|
||||
secretVolumes:
|
||||
- mountPath: /etc/istio/egressgateway-certs
|
||||
name: egressgateway-certs
|
||||
secretName: istio-egressgateway-certs
|
||||
- mountPath: /etc/istio/egressgateway-ca-certs
|
||||
name: egressgateway-ca-certs
|
||||
secretName: istio-egressgateway-ca-certs
|
||||
- mountPath: /etc/istio/nginx-client-certs
|
||||
name: nginx-client-certs
|
||||
secretName: nginx-client-certs
|
||||
- mountPath: /etc/istio/nginx-ca-certs
|
||||
name: nginx-ca-certs
|
||||
secretName: nginx-ca-certs
|
||||
`
|
||||
gotYAML := util.ToYAML(root)
|
||||
diff := util.YAMLDiff(gotYAML, want)
|
||||
if diff != "" {
|
||||
t.Errorf("TestSecretVolumes: diff:\n%s\n", diff)
|
||||
}
|
||||
}
|
||||
|
||||
// Simulates https://github.com/istio/istio/issues/19196
|
||||
func TestWriteEscapedPathContext(t *testing.T) {
|
||||
rootYAML := `
|
||||
values:
|
||||
sidecarInjectorWebhook:
|
||||
injectedAnnotations: {}
|
||||
`
|
||||
tests := []struct {
|
||||
desc string
|
||||
path string
|
||||
value any
|
||||
want string
|
||||
wantFound bool
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
desc: "ModifyEscapedPathValue",
|
||||
path: `values.sidecarInjectorWebhook.injectedAnnotations.container\.apparmor\.security\.beta\.kubernetes\.io/istio-proxy`,
|
||||
value: `runtime/default`,
|
||||
wantFound: true,
|
||||
want: `
|
||||
values:
|
||||
sidecarInjectorWebhook:
|
||||
injectedAnnotations:
|
||||
container.apparmor.security.beta.kubernetes.io/istio-proxy: runtime/default
|
||||
`,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
root := make(map[string]any)
|
||||
if err := yaml.Unmarshal([]byte(rootYAML), &root); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pc, gotFound, gotErr := GetPathContext(root, util.PathFromString(tt.path), false)
|
||||
if gotErr, wantErr := errToString(gotErr), tt.wantErr; gotErr != wantErr {
|
||||
t.Fatalf("GetPathContext(%s): gotErr:%s, wantErr:%s", tt.desc, gotErr, wantErr)
|
||||
}
|
||||
if gotFound != tt.wantFound {
|
||||
t.Fatalf("GetPathContext(%s): gotFound:%v, wantFound:%v", tt.desc, gotFound, tt.wantFound)
|
||||
}
|
||||
if tt.wantErr != "" || !tt.wantFound {
|
||||
return
|
||||
}
|
||||
|
||||
err := WritePathContext(pc, tt.value, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
gotYAML := util.ToYAML(root)
|
||||
diff := util.YAMLDiff(gotYAML, tt.want)
|
||||
if diff != "" {
|
||||
t.Errorf("%s: diff:\n%s\n", tt.desc, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
58
pkg/cmd/hgctl/helm/tpath/util.go
Normal file
58
pkg/cmd/hgctl/helm/tpath/util.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// 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 tpath
|
||||
|
||||
import (
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/util"
|
||||
"gopkg.in/yaml.v2"
|
||||
yaml2 "sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// AddSpecRoot adds a root node called "spec" to the given tree and returns the resulting tree.
|
||||
func AddSpecRoot(tree string) (string, error) {
|
||||
t, nt := make(map[string]any), make(map[string]any)
|
||||
if err := yaml.Unmarshal([]byte(tree), &t); err != nil {
|
||||
return "", err
|
||||
}
|
||||
nt["spec"] = t
|
||||
out, err := yaml.Marshal(nt)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(out), nil
|
||||
}
|
||||
|
||||
// GetSpecSubtree returns the subtree under "spec".
|
||||
func GetSpecSubtree(yml string) (string, error) {
|
||||
return GetConfigSubtree(yml, "spec")
|
||||
}
|
||||
|
||||
// GetConfigSubtree returns the subtree at the given path.
|
||||
func GetConfigSubtree(manifest, path string) (string, error) {
|
||||
root := make(map[string]any)
|
||||
if err := yaml2.Unmarshal([]byte(manifest), &root); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
nc, _, err := GetPathContext(root, util.PathFromString(path), false)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
out, err := yaml2.Marshal(nc.Node)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(out), nil
|
||||
}
|
||||
122
pkg/cmd/hgctl/helm/tpath/util_test.go
Normal file
122
pkg/cmd/hgctl/helm/tpath/util_test.go
Normal file
@@ -0,0 +1,122 @@
|
||||
// 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 tpath
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAddSpecRoot(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
in string
|
||||
expect string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "empty",
|
||||
in: ``,
|
||||
expect: `spec: {}
|
||||
`,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "add-root",
|
||||
in: `
|
||||
a: va
|
||||
b: foo`,
|
||||
expect: `spec:
|
||||
a: va
|
||||
b: foo
|
||||
`,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "err",
|
||||
in: `i can't be yaml, can I?`,
|
||||
expect: ``,
|
||||
err: errors.New(""),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
if got, err := AddSpecRoot(tt.in); got != tt.expect ||
|
||||
((err != nil && tt.err == nil) || (err == nil && tt.err != nil)) {
|
||||
t.Errorf("%s AddSpecRoot(%s) => %s, want %s", tt.desc, tt.in, got, tt.expect)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetConfigSubtree(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
manifest string
|
||||
path string
|
||||
expect string
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
desc: "empty",
|
||||
manifest: ``,
|
||||
path: ``,
|
||||
expect: `{}
|
||||
`,
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
desc: "subtree",
|
||||
manifest: `
|
||||
a:
|
||||
b:
|
||||
- name: n1
|
||||
value: v2
|
||||
- list:
|
||||
- v1
|
||||
- v2
|
||||
- v3_regex
|
||||
name: n2
|
||||
`,
|
||||
path: `a`,
|
||||
expect: `b:
|
||||
- name: n1
|
||||
value: v2
|
||||
- list:
|
||||
- v1
|
||||
- v2
|
||||
- v3_regex
|
||||
name: n2
|
||||
`,
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
desc: "err",
|
||||
manifest: "not-yaml",
|
||||
path: "not-subnode",
|
||||
expect: ``,
|
||||
err: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
if got, err := GetConfigSubtree(tt.manifest, tt.path); got != tt.expect || (err == nil) == tt.err {
|
||||
t.Errorf("%s GetConfigSubtree(%s, %s) => %s, want %s", tt.desc, tt.manifest, tt.path, got, tt.expect)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
200
pkg/cmd/hgctl/install.go
Normal file
200
pkg/cmd/hgctl/install.go
Normal file
@@ -0,0 +1,200 @@
|
||||
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package hgctl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/helm"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/installer"
|
||||
"github.com/alibaba/higress/pkg/cmd/options"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
setFlagHelpStr = `Override an higress profile value, e.g. to choose a profile
|
||||
(--set profile=local-k8s), or override profile values (--set gateway.replicas=2), or override helm values (--set values.global.proxy.resources.requsts.cpu=500m).`
|
||||
// manifestsFlagHelpStr is the command line description for --manifests
|
||||
manifestsFlagHelpStr = `Specify a path to a directory of profiles
|
||||
(e.g. ~/Downloads/higress/manifests).`
|
||||
filenameFlagHelpStr = "Path to file containing helm custom values"
|
||||
outputHelpstr = "Specify a file to write profile yaml"
|
||||
|
||||
profileNameK8s = "k8s"
|
||||
profileNameLocalK8s = "local-k8s"
|
||||
profileNameLocalDocker = "local-docker"
|
||||
)
|
||||
|
||||
type InstallArgs struct {
|
||||
// InFilenames is a filename to helm custom values
|
||||
InFilenames []string
|
||||
// KubeConfigPath is the path to kube config file.
|
||||
KubeConfigPath string
|
||||
// Context is the cluster context in the kube config
|
||||
Context string
|
||||
// Set is a string with element format "path=value" where path is an profile path and the value is a
|
||||
// value to set the node at that path to.
|
||||
Set []string
|
||||
// ManifestsPath is a path to a ManifestsPath and profiles directory in the local filesystem with a release tgz.
|
||||
ManifestsPath string
|
||||
}
|
||||
|
||||
func (a *InstallArgs) String() string {
|
||||
var b strings.Builder
|
||||
b.WriteString("KubeConfigPath: " + a.KubeConfigPath + "\n")
|
||||
b.WriteString("Context: " + a.Context + "\n")
|
||||
b.WriteString("Set: " + fmt.Sprint(a.Set) + "\n")
|
||||
b.WriteString("ManifestsPath: " + a.ManifestsPath + "\n")
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func addInstallFlags(cmd *cobra.Command, args *InstallArgs) {
|
||||
cmd.PersistentFlags().StringSliceVarP(&args.InFilenames, "filename", "f", nil, filenameFlagHelpStr)
|
||||
cmd.PersistentFlags().StringArrayVarP(&args.Set, "set", "s", nil, setFlagHelpStr)
|
||||
cmd.PersistentFlags().StringVarP(&args.ManifestsPath, "manifests", "d", "", manifestsFlagHelpStr)
|
||||
}
|
||||
|
||||
// --manifests is an alias for --set installPackagePath=
|
||||
func applyFlagAliases(flags []string, manifestsPath string) []string {
|
||||
if manifestsPath != "" {
|
||||
flags = append(flags, fmt.Sprintf("installPackagePath=%s", manifestsPath))
|
||||
}
|
||||
return flags
|
||||
}
|
||||
|
||||
// newInstallCmd generates a higress install manifest and applies it to a cluster
|
||||
func newInstallCmd() *cobra.Command {
|
||||
iArgs := &InstallArgs{}
|
||||
installCmd := &cobra.Command{
|
||||
Use: "install",
|
||||
Short: "Applies an higress manifest, installing or reconfiguring higress on a cluster.",
|
||||
Long: "The install command generates an higress install manifest and applies it to a cluster.",
|
||||
// nolint: lll
|
||||
Example: ` # Apply a default higress installation
|
||||
hgctl install
|
||||
|
||||
# Install higress on local kubernetes cluster
|
||||
hgctl install --set profile=local-k8s
|
||||
|
||||
# Install higress on local docker environment with specific gateway port
|
||||
hgctl install --set profile=local-docker --set gateway.httpPort=80 --set gateway.httpsPort=443
|
||||
|
||||
# To override profile setting
|
||||
hgctl install --set profile=local-k8s --set global.enableIstioAPI=true --set gateway.replicas=2"
|
||||
|
||||
# To override helm setting
|
||||
hgctl install --set profile=local-k8s --set values.global.proxy.resources.requsts.cpu=500m"
|
||||
|
||||
|
||||
`,
|
||||
Args: cobra.ExactArgs(0),
|
||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return install(cmd.OutOrStdout(), iArgs)
|
||||
},
|
||||
}
|
||||
addInstallFlags(installCmd, iArgs)
|
||||
flags := installCmd.Flags()
|
||||
options.AddKubeConfigFlags(flags)
|
||||
return installCmd
|
||||
}
|
||||
|
||||
func install(writer io.Writer, iArgs *InstallArgs) error {
|
||||
setFlags := applyFlagAliases(iArgs.Set, iArgs.ManifestsPath)
|
||||
|
||||
// check profileName
|
||||
psf := helm.GetValueForSetFlag(setFlags, "profile")
|
||||
if len(psf) == 0 {
|
||||
psf = promptProfileName(writer)
|
||||
setFlags = append(setFlags, fmt.Sprintf("profile=%s", psf))
|
||||
}
|
||||
|
||||
if !promptInstall(writer, psf) {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, profile, profileName, err := helm.GenerateConfig(iArgs.InFilenames, setFlags)
|
||||
if err != nil {
|
||||
return fmt.Errorf("generate config: %v", err)
|
||||
}
|
||||
|
||||
fmt.Fprintf(writer, "🧐 Validating Profile: \"%s\" \n", profileName)
|
||||
err = profile.Validate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = installManifests(profile, writer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to install manifests: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func promptInstall(writer io.Writer, profileName string) bool {
|
||||
answer := ""
|
||||
for {
|
||||
fmt.Fprintf(writer, "\nThis will install Higress \"%s\" profile into the cluster. \nProceed? (y/N)", profileName)
|
||||
fmt.Scanln(&answer)
|
||||
if strings.TrimSpace(answer) == "y" {
|
||||
fmt.Fprintf(writer, "\n")
|
||||
return true
|
||||
}
|
||||
if strings.TrimSpace(answer) == "N" {
|
||||
fmt.Fprintf(writer, "Cancelled.\n")
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func promptProfileName(writer io.Writer) string {
|
||||
answer := ""
|
||||
fmt.Fprintf(writer, "\nPlease select higress install configration profile:\n")
|
||||
fmt.Fprintf(writer, "\n1.Install higress to local kubernetes cluster like kind etc.\n")
|
||||
fmt.Fprintf(writer, "\n2.Install higress to kubernetes cluster\n")
|
||||
fmt.Fprintf(writer, "\n3.Install higress to local docker environment\n")
|
||||
for {
|
||||
fmt.Fprintf(writer, "\nPlease input 1, 2 or 3 to select, input your selection:")
|
||||
fmt.Scanln(&answer)
|
||||
if strings.TrimSpace(answer) == "1" {
|
||||
return profileNameLocalK8s
|
||||
}
|
||||
if strings.TrimSpace(answer) == "2" {
|
||||
return profileNameK8s
|
||||
}
|
||||
if strings.TrimSpace(answer) == "3" {
|
||||
return profileNameLocalDocker
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func installManifests(profile *helm.Profile, writer io.Writer) error {
|
||||
installer, err := installer.NewInstaller(profile, writer, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = installer.Install()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
112
pkg/cmd/hgctl/installer/component.go
Normal file
112
pkg/cmd/hgctl/installer/component.go
Normal file
@@ -0,0 +1,112 @@
|
||||
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package installer
|
||||
|
||||
import (
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/helm"
|
||||
"github.com/alibaba/higress/pkg/cmd/hgctl/util"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
type ComponentName string
|
||||
|
||||
var ComponentMap = map[ComponentName]struct{}{
|
||||
Higress: {},
|
||||
Istio: {},
|
||||
}
|
||||
|
||||
type Component interface {
|
||||
// ComponentName returns the name of the component.
|
||||
ComponentName() ComponentName
|
||||
// Namespace returns the namespace for the component.
|
||||
Namespace() string
|
||||
// Enabled reports whether the component is enabled.
|
||||
Enabled() bool
|
||||
// Run starts the component. Must be called before the component is used.
|
||||
Run() error
|
||||
RenderManifest() (string, error)
|
||||
}
|
||||
|
||||
type ComponentOptions struct {
|
||||
Name string
|
||||
Namespace string
|
||||
// local
|
||||
ChartPath string
|
||||
// remote
|
||||
RepoURL string
|
||||
ChartName string
|
||||
Version string
|
||||
Quiet bool
|
||||
}
|
||||
|
||||
type ComponentOption func(*ComponentOptions)
|
||||
|
||||
func WithComponentNamespace(namespace string) ComponentOption {
|
||||
return func(opts *ComponentOptions) {
|
||||
opts.Namespace = namespace
|
||||
}
|
||||
}
|
||||
|
||||
func WithComponentChartPath(path string) ComponentOption {
|
||||
return func(opts *ComponentOptions) {
|
||||
opts.ChartPath = path
|
||||
}
|
||||
}
|
||||
|
||||
func WithComponentChartName(chartName string) ComponentOption {
|
||||
return func(opts *ComponentOptions) {
|
||||
opts.ChartName = chartName
|
||||
}
|
||||
}
|
||||
|
||||
func WithComponentRepoURL(url string) ComponentOption {
|
||||
return func(opts *ComponentOptions) {
|
||||
opts.RepoURL = url
|
||||
}
|
||||
}
|
||||
|
||||
func WithComponentVersion(version string) ComponentOption {
|
||||
return func(opts *ComponentOptions) {
|
||||
opts.Version = version
|
||||
}
|
||||
}
|
||||
|
||||
func WithQuiet() ComponentOption {
|
||||
return func(opts *ComponentOptions) {
|
||||
opts.Quiet = true
|
||||
}
|
||||
}
|
||||
|
||||
func renderComponentManifest(spec any, renderer helm.Renderer, addOn bool, name ComponentName, namespace string) (string, error) {
|
||||
var valsBytes []byte
|
||||
var valsYaml string
|
||||
var err error
|
||||
if yamlString, ok := spec.(string); ok {
|
||||
valsYaml = yamlString
|
||||
} else {
|
||||
if !util.IsValueNil(spec) {
|
||||
valsBytes, err = yaml.Marshal(spec)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
valsYaml = string(valsBytes)
|
||||
}
|
||||
}
|
||||
final, err := renderer.RenderManifest(valsYaml)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return final, nil
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user