mirror of
https://github.com/kubevela/kubevela.git
synced 2026-03-03 02:01:05 +00:00
Compare commits
47 Commits
dependabot
...
v1.10.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef9b6f3cc1 | ||
|
|
144e96df31 | ||
|
|
5ee9c8b38c | ||
|
|
d3ce7ad118 | ||
|
|
a1145f21fe | ||
|
|
edf3be272e | ||
|
|
b4f9db4af8 | ||
|
|
78c0b2c04e | ||
|
|
5d42a3b507 | ||
|
|
1588736b4e | ||
|
|
27965fb8aa | ||
|
|
262daacb63 | ||
|
|
fb17af5e75 | ||
|
|
5122eb575b | ||
|
|
d93e292142 | ||
|
|
f9e15c55ad | ||
|
|
af7f623cba | ||
|
|
d487012468 | ||
|
|
fc8888cb4d | ||
|
|
9558cb8491 | ||
|
|
bde50df3e5 | ||
|
|
dba2676cd9 | ||
|
|
8ee02c6506 | ||
|
|
0751c15ee5 | ||
|
|
1a16e52e36 | ||
|
|
853a077107 | ||
|
|
c5d9f69c9c | ||
|
|
e0f162e47d | ||
|
|
d9fcebb9e8 | ||
|
|
c48ded1994 | ||
|
|
424e433963 | ||
|
|
b51957ef9f | ||
|
|
cd0b0988f9 | ||
|
|
ead624e553 | ||
|
|
f5aed7aefd | ||
|
|
30249d5297 | ||
|
|
472e1f1e59 | ||
|
|
33cd16d425 | ||
|
|
793ba55455 | ||
|
|
711c9f0053 | ||
|
|
bc15e5b359 | ||
|
|
d0d7beb700 | ||
|
|
e63d8c33ec | ||
|
|
3779f828ae | ||
|
|
4d744a35d4 | ||
|
|
9f09436359 | ||
|
|
c6765c6ff0 |
30
.github/CODEOWNERS
vendored
30
.github/CODEOWNERS
vendored
@@ -1,35 +1,35 @@
|
||||
# This file is a github code protect rule follow the codeowners https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-code-owners#example-of-a-codeowners-file
|
||||
|
||||
* @barnettZQG @wonderflow @leejanee @Somefive @jefree-cat @FogDong @wangyikewxgm @chivalryq @anoop2811 @dhiguero
|
||||
design/ @barnettZQG @leejanee @wonderflow @Somefive @jefree-cat @FogDong @anoop2811 @dhiguero
|
||||
* @barnettZQG @wonderflow @leejanee @Somefive @jefree-cat @FogDong @wangyikewxgm @chivalryq @anoop2811
|
||||
design/ @barnettZQG @leejanee @wonderflow @Somefive @jefree-cat @FogDong @anoop2811
|
||||
|
||||
# Owner of Core Controllers
|
||||
pkg/controller/core.oam.dev @Somefive @FogDong @barnettZQG @wonderflow @wangyikewxgm @chivalryq @anoop2811 @dhiguero
|
||||
pkg/controller/core.oam.dev @Somefive @FogDong @barnettZQG @wonderflow @wangyikewxgm @chivalryq @anoop2811
|
||||
|
||||
# Owner of Standard Controllers
|
||||
pkg/controller/standard.oam.dev @wangyikewxgm @barnettZQG @wonderflow @Somefive @anoop2811 @dhiguero @FogDong
|
||||
pkg/controller/standard.oam.dev @wangyikewxgm @barnettZQG @wonderflow @Somefive @anoop2811 @FogDong
|
||||
|
||||
# Owner of CUE
|
||||
pkg/cue @leejanee @FogDong @Somefive @anoop2811 @dhiguero
|
||||
pkg/stdlib @leejanee @FogDong @Somefive @anoop2811 @dhiguero
|
||||
pkg/cue @leejanee @FogDong @Somefive @anoop2811
|
||||
pkg/stdlib @leejanee @FogDong @Somefive @anoop2811
|
||||
|
||||
# Owner of Workflow
|
||||
pkg/workflow @leejanee @FogDong @Somefive @wangyikewxgm @chivalryq @anoop2811 @dhiguero
|
||||
pkg/workflow @leejanee @FogDong @Somefive @wangyikewxgm @chivalryq @anoop2811
|
||||
|
||||
# Owner of vela templates
|
||||
vela-templates/ @Somefive @barnettZQG @wonderflow @FogDong @wangyikewxgm @chivalryq @anoop2811 @dhiguero
|
||||
vela-templates/ @Somefive @barnettZQG @wonderflow @FogDong @wangyikewxgm @chivalryq @anoop2811
|
||||
|
||||
# Owner of vela CLI
|
||||
references/cli/ @Somefive @StevenLeiZhang @charlie0129 @wangyikewxgm @chivalryq @anoop2811 @dhiguero @FogDong
|
||||
references/cli/ @Somefive @StevenLeiZhang @charlie0129 @wangyikewxgm @chivalryq @anoop2811 @FogDong
|
||||
|
||||
# Owner of vela addon framework
|
||||
pkg/addon/ @wangyikewxgm @wonderflow @charlie0129 @anoop2811 @dhiguero @FogDong
|
||||
pkg/addon/ @wangyikewxgm @wonderflow @charlie0129 @anoop2811 @FogDong
|
||||
|
||||
# Owner of resource keeper and tracker
|
||||
pkg/resourcekeeper @Somefive @FogDong @chivalryq @anoop2811 @dhiguero
|
||||
pkg/resourcetracker @Somefive @FogDong @chivalryq @anoop2811 @dhiguero
|
||||
pkg/resourcekeeper @Somefive @FogDong @chivalryq @anoop2811
|
||||
pkg/resourcetracker @Somefive @FogDong @chivalryq @anoop2811
|
||||
|
||||
.github/ @chivalryq @wonderflow @Somefive @FogDong @wangyikewxgm @anoop2811 @dhiguero
|
||||
makefiles @chivalryq @wonderflow @Somefive @FogDong @wangyikewxgm @anoop2811 @dhiguero
|
||||
go.* @chivalryq @wonderflow @Somefive @FogDong @wangyikewxgm @anoop2811 @dhiguero
|
||||
.github/ @chivalryq @wonderflow @Somefive @FogDong @wangyikewxgm @anoop2811
|
||||
makefiles @chivalryq @wonderflow @Somefive @FogDong @wangyikewxgm @anoop2811
|
||||
go.* @chivalryq @wonderflow @Somefive @FogDong @wangyikewxgm @anoop2811
|
||||
|
||||
|
||||
6
.github/workflows/codeql-analysis.yml
vendored
6
.github/workflows/codeql-analysis.yml
vendored
@@ -26,12 +26,12 @@ jobs:
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # v2.1.37
|
||||
uses: github/codeql-action/init@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # v2.1.37
|
||||
uses: github/codeql-action/autobuild@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # v2.1.37
|
||||
uses: github/codeql-action/analyze@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
|
||||
|
||||
6
.github/workflows/core-api-test.yml
vendored
6
.github/workflows/core-api-test.yml
vendored
@@ -16,10 +16,10 @@ jobs:
|
||||
core-api-test:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Set up Go 1.22
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
|
||||
- name: Set up Go 1.23.8
|
||||
uses: actions/setup-go@v5
|
||||
env:
|
||||
GO_VERSION: '1.22'
|
||||
GO_VERSION: '1.23.8'
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
id: go
|
||||
|
||||
2
.github/workflows/definition-lint.yml
vendored
2
.github/workflows/definition-lint.yml
vendored
@@ -16,7 +16,7 @@ permissions:
|
||||
|
||||
env:
|
||||
# Common versions
|
||||
GO_VERSION: '1.22'
|
||||
GO_VERSION: '1.23.8'
|
||||
|
||||
jobs:
|
||||
definition-doc:
|
||||
|
||||
4
.github/workflows/e2e-multicluster-test.yml
vendored
4
.github/workflows/e2e-multicluster-test.yml
vendored
@@ -18,7 +18,7 @@ permissions:
|
||||
|
||||
env:
|
||||
# Common versions
|
||||
GO_VERSION: '1.22'
|
||||
GO_VERSION: '1.23.8'
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
continue-on-error: true
|
||||
|
||||
e2e-multi-cluster-tests:
|
||||
runs-on: self-hosted
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [ detect-noop ]
|
||||
if: needs.detect-noop.outputs.noop != 'true'
|
||||
strategy:
|
||||
|
||||
4
.github/workflows/e2e-test.yml
vendored
4
.github/workflows/e2e-test.yml
vendored
@@ -18,7 +18,7 @@ permissions:
|
||||
|
||||
env:
|
||||
# Common versions
|
||||
GO_VERSION: '1.22'
|
||||
GO_VERSION: '1.23.8'
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
continue-on-error: true
|
||||
|
||||
e2e-tests:
|
||||
runs-on: self-hosted
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [ detect-noop ]
|
||||
if: needs.detect-noop.outputs.noop != 'true'
|
||||
strategy:
|
||||
|
||||
35
.github/workflows/go.yml
vendored
35
.github/workflows/go.yml
vendored
@@ -11,16 +11,15 @@ on:
|
||||
- master
|
||||
- release-*
|
||||
|
||||
permissions: # added using https://github.com/step-security/secure-workflows
|
||||
permissions: # added using https://github.com/step-security/secure-workflows
|
||||
contents: read
|
||||
|
||||
env:
|
||||
# Common versions
|
||||
GO_VERSION: '1.22'
|
||||
GOLANGCI_VERSION: 'v1.54.2'
|
||||
GO_VERSION: "1.23.8"
|
||||
GOLANGCI_VERSION: "v1.60.1"
|
||||
|
||||
jobs:
|
||||
|
||||
detect-noop:
|
||||
runs-on: ubuntu-22.04
|
||||
outputs:
|
||||
@@ -64,8 +63,8 @@ jobs:
|
||||
needs: detect-noop
|
||||
if: needs.detect-noop.outputs.noop != 'true'
|
||||
permissions:
|
||||
contents: read # for actions/checkout to fetch code
|
||||
pull-requests: read # for golangci/golangci-lint-action to fetch pull requests
|
||||
contents: read # for actions/checkout to fetch code
|
||||
pull-requests: read # for golangci/golangci-lint-action to fetch pull requests
|
||||
|
||||
steps:
|
||||
- name: Setup Go
|
||||
@@ -83,7 +82,7 @@ jobs:
|
||||
# version, but we prefer this action because it leaves 'annotations' (i.e.
|
||||
# it comments on PRs to point out linter violations).
|
||||
- name: Lint
|
||||
uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1
|
||||
uses: golangci/golangci-lint-action@v6
|
||||
with:
|
||||
version: ${{ env.GOLANGCI_VERSION }}
|
||||
|
||||
@@ -106,10 +105,10 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b
|
||||
with:
|
||||
node-version: '14'
|
||||
node-version: "14"
|
||||
|
||||
- name: Cache Go Dependencies
|
||||
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .work/pkg
|
||||
key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }}
|
||||
@@ -128,7 +127,7 @@ jobs:
|
||||
run: |
|
||||
export PATH=$(pwd)/bin/:$PATH
|
||||
make check-diff
|
||||
|
||||
|
||||
- name: Cleanup binary
|
||||
run: make build-cleanup
|
||||
|
||||
@@ -149,7 +148,7 @@ jobs:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Cache Go Dependencies
|
||||
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .work/pkg
|
||||
key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }}
|
||||
@@ -174,11 +173,11 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
|
||||
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
|
||||
- name: Build Test for vela core
|
||||
uses: docker/build-push-action@1a162644f9a7e87d8f4b053101d1d9a712edc18c # v6.3.0
|
||||
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile
|
||||
@@ -194,11 +193,11 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
|
||||
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
|
||||
- name: Build Test for CLI
|
||||
uses: docker/build-push-action@1a162644f9a7e87d8f4b053101d1d9a712edc18c # v6.3.0
|
||||
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile.cli
|
||||
file: Dockerfile.cli
|
||||
6
.github/workflows/issue-commands.yml
vendored
6
.github/workflows/issue-commands.yml
vendored
@@ -25,15 +25,15 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b
|
||||
with:
|
||||
node-version: '14'
|
||||
cache: 'npm'
|
||||
node-version: "14"
|
||||
cache: "npm"
|
||||
cache-dependency-path: ./actions/package-lock.json
|
||||
- name: Install Dependencies
|
||||
run: npm ci --production --prefix ./actions
|
||||
- name: Run Commands
|
||||
uses: ./actions/commands
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
token: ${{ secrets.GH_KUBEVELA_COMMAND_WORKFLOW }}
|
||||
configPath: issue-commands
|
||||
|
||||
backport:
|
||||
|
||||
198
.github/workflows/registry.yml
vendored
198
.github/workflows/registry.yml
vendored
@@ -1,23 +1,45 @@
|
||||
name: Registry
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
tags:
|
||||
- "v*"
|
||||
- 'v*'
|
||||
workflow_dispatch: {}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
publish-core-images:
|
||||
publish-vela-images:
|
||||
name: Build and Push Vela Images
|
||||
permissions:
|
||||
packages: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
contents: write
|
||||
runs-on: ubuntu-22.04
|
||||
outputs:
|
||||
vela_core_image: ${{ steps.meta-vela-core.outputs.image }}
|
||||
vela_core_digest: ${{ steps.meta-vela-core.outputs.digest }}
|
||||
vela_core_dockerhub_image: ${{ steps.meta-vela-core.outputs.dockerhub_image }}
|
||||
vela_cli_image: ${{ steps.meta-vela-cli.outputs.image }}
|
||||
vela_cli_digest: ${{ steps.meta-vela-cli.outputs.digest }}
|
||||
vela_cli_dockerhub_image: ${{ steps.meta-vela-cli.outputs.dockerhub_image }}
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
- name: Get the version
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.1
|
||||
|
||||
- name: Install Crane
|
||||
uses: imjasonh/setup-crane@00c9e93efa4e1138c9a7a5c594acd6c75a2fbf0c # v0.1
|
||||
|
||||
- name: Install Cosign
|
||||
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # main
|
||||
with:
|
||||
cosign-release: 'v2.5.0'
|
||||
|
||||
- name: Get the image version
|
||||
id: get_version
|
||||
run: |
|
||||
VERSION=${GITHUB_REF#refs/tags/}
|
||||
@@ -25,34 +47,41 @@ jobs:
|
||||
VERSION=latest
|
||||
fi
|
||||
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Get git revision
|
||||
id: vars
|
||||
shell: bash
|
||||
run: |
|
||||
echo "git_revision=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||
- name: Login ghcr.io
|
||||
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
|
||||
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Login docker.io
|
||||
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
with:
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0
|
||||
- uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
|
||||
|
||||
- name: Setup QEMU
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
|
||||
|
||||
- name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
|
||||
with:
|
||||
driver-opts: image=moby/buildkit:master
|
||||
|
||||
- uses: docker/build-push-action@1a162644f9a7e87d8f4b053101d1d9a712edc18c # v6.3.0
|
||||
name: Build & Pushing vela-core for Dockerhub, GHCR
|
||||
- name: Build & Push Vela Core for Dockerhub, GHCR
|
||||
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile
|
||||
labels: |-
|
||||
labels: |
|
||||
org.opencontainers.image.source=https://github.com/${{ github.repository }}
|
||||
org.opencontainers.image.revision=${{ github.sha }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
@@ -61,16 +90,55 @@ jobs:
|
||||
GITVERSION=git-${{ steps.vars.outputs.git_revision }}
|
||||
VERSION=${{ steps.get_version.outputs.VERSION }}
|
||||
GOPROXY=https://proxy.golang.org
|
||||
tags: |-
|
||||
tags: |
|
||||
docker.io/oamdev/vela-core:${{ steps.get_version.outputs.VERSION }}
|
||||
ghcr.io/${{ github.repository_owner }}/oamdev/vela-core:${{ steps.get_version.outputs.VERSION }}
|
||||
|
||||
- uses: docker/build-push-action@1a162644f9a7e87d8f4b053101d1d9a712edc18c # v6.3.0
|
||||
name: Build & Pushing CLI for Dockerhub, GHCR
|
||||
- name: Get Vela Core Image Digest
|
||||
id: meta-vela-core
|
||||
run: |
|
||||
GHCR_IMAGE=ghcr.io/${{ github.repository_owner }}/oamdev/vela-core
|
||||
DOCKER_IMAGE=docker.io/oamdev/vela-core
|
||||
TAG=${{ steps.get_version.outputs.VERSION }}
|
||||
|
||||
DIGEST=$(crane digest $GHCR_IMAGE:$TAG)
|
||||
|
||||
echo "image=$GHCR_IMAGE" >> $GITHUB_OUTPUT
|
||||
echo "dockerhub_image=$DOCKER_IMAGE" >> $GITHUB_OUTPUT
|
||||
echo "digest=$DIGEST" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Generate SBOM for Vela Core Image
|
||||
id: generate_vela_core_sbom
|
||||
uses: anchore/sbom-action@v0.17.0
|
||||
with:
|
||||
image: ghcr.io/${{ github.repository_owner }}/oamdev/vela-core:${{ steps.get_version.outputs.VERSION }}
|
||||
registry-username: ${{ github.actor }}
|
||||
registry-password: ${{ secrets.GITHUB_TOKEN }}
|
||||
format: spdx-json
|
||||
artifact-name: sbom-vela-core.spdx.json
|
||||
output-file: ${{ github.workspace }}/sbom-vela-core.spdx.json
|
||||
|
||||
- name: Sign Vela Core Image and Attest SBOM
|
||||
env:
|
||||
COSIGN_EXPERIMENTAL: 'true'
|
||||
run: |
|
||||
echo "signing vela core images..."
|
||||
cosign sign --yes ghcr.io/${{ github.repository_owner }}/oamdev/vela-core@${{ steps.meta-vela-core.outputs.digest }}
|
||||
cosign sign --yes docker.io/oamdev/vela-core@${{ steps.meta-vela-core.outputs.digest }}
|
||||
|
||||
echo "attesting SBOM against the vela core image..."
|
||||
cosign attest --yes --predicate ${{ github.workspace }}/sbom-vela-core.spdx.json --type spdx \
|
||||
ghcr.io/${{ github.repository_owner }}/oamdev/vela-core@${{ steps.meta-vela-core.outputs.digest }}
|
||||
|
||||
cosign attest --yes --predicate ${{ github.workspace }}/sbom-vela-core.spdx.json --type spdx \
|
||||
docker.io/oamdev/vela-core@${{ steps.meta-vela-core.outputs.digest }}
|
||||
|
||||
- name: Build & Push Vela CLI for Dockerhub, GHCR
|
||||
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile.cli
|
||||
labels: |-
|
||||
labels: |
|
||||
org.opencontainers.image.source=https://github.com/${{ github.repository }}
|
||||
org.opencontainers.image.revision=${{ github.sha }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
@@ -79,6 +147,100 @@ jobs:
|
||||
GITVERSION=git-${{ steps.vars.outputs.git_revision }}
|
||||
VERSION=${{ steps.get_version.outputs.VERSION }}
|
||||
GOPROXY=https://proxy.golang.org
|
||||
tags: |-
|
||||
tags: |
|
||||
docker.io/oamdev/vela-cli:${{ steps.get_version.outputs.VERSION }}
|
||||
ghcr.io/${{ github.repository_owner }}/oamdev/vela-cli:${{ steps.get_version.outputs.VERSION }}
|
||||
|
||||
- name: Get Vela CLI Image Digest
|
||||
id: meta-vela-cli
|
||||
run: |
|
||||
GHCR_IMAGE=ghcr.io/${{ github.repository_owner }}/oamdev/vela-cli
|
||||
DOCKER_IMAGE=docker.io/oamdev/vela-cli
|
||||
TAG=${{ steps.get_version.outputs.VERSION }}
|
||||
|
||||
DIGEST=$(crane digest $GHCR_IMAGE:$TAG)
|
||||
|
||||
echo "image=$GHCR_IMAGE" >> $GITHUB_OUTPUT
|
||||
echo "dockerhub_image=$DOCKER_IMAGE" >> $GITHUB_OUTPUT
|
||||
echo "digest=$DIGEST" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Generate SBOM for Vela CLI Image
|
||||
id: generate_sbom
|
||||
uses: anchore/sbom-action@v0.17.0
|
||||
with:
|
||||
image: ghcr.io/${{ github.repository_owner }}/oamdev/vela-cli:${{ steps.get_version.outputs.VERSION }}
|
||||
registry-username: ${{ github.actor }}
|
||||
registry-password: ${{ secrets.GITHUB_TOKEN }}
|
||||
format: spdx-json
|
||||
artifact-name: sbom-vela-cli.spdx.json
|
||||
output-file: ${{ github.workspace }}/sbom-vela-cli.spdx.json
|
||||
|
||||
- name: Sign Vela CLI Image and Attest SBOM
|
||||
env:
|
||||
COSIGN_EXPERIMENTAL: 'true'
|
||||
run: |
|
||||
echo "signing vela CLI images..."
|
||||
cosign sign --yes ghcr.io/${{ github.repository_owner }}/oamdev/vela-cli@${{ steps.meta-vela-cli.outputs.digest }}
|
||||
cosign sign --yes docker.io/oamdev/vela-cli@${{ steps.meta-vela-cli.outputs.digest }}
|
||||
|
||||
echo "attesting SBOM against the vela cli image..."
|
||||
cosign attest --yes --predicate ${{ github.workspace }}/sbom-vela-cli.spdx.json --type spdx \
|
||||
ghcr.io/${{ github.repository_owner }}/oamdev/vela-cli@${{ steps.meta-vela-cli.outputs.digest }}
|
||||
|
||||
cosign attest --yes --predicate ${{ github.workspace }}/sbom-vela-cli.spdx.json --type spdx \
|
||||
docker.io/oamdev/vela-cli@${{ steps.meta-vela-cli.outputs.digest }}
|
||||
|
||||
- name: Publish SBOMs as release artifacts
|
||||
uses: anchore/sbom-action/publish-sbom@v0.17.0
|
||||
|
||||
provenance-ghcr:
|
||||
name: Generate and Push Provenance to GCHR
|
||||
needs: publish-vela-images
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- name: 'Vela Core Image'
|
||||
image: ${{ needs.publish-vela-images.outputs.vela_core_image }}
|
||||
digest: ${{ needs.publish-vela-images.outputs.vela_core_digest }}
|
||||
- name: 'Vela CLI Image'
|
||||
image: ${{ needs.publish-vela-images.outputs.vela_cli_image }}
|
||||
digest: ${{ needs.publish-vela-images.outputs.vela_cli_digest }}
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: write
|
||||
actions: read
|
||||
packages: write
|
||||
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.1.0 # has to be sem var
|
||||
with:
|
||||
image: ${{ matrix.image }}
|
||||
digest: ${{ matrix.digest }}
|
||||
registry-username: ${{ github.actor }}
|
||||
secrets:
|
||||
registry-password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
provenance-dockerhub:
|
||||
name: Generate and Push Provenance to DockerHub
|
||||
needs: publish-vela-images
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- name: 'Vela Core Image'
|
||||
image: ${{ needs.publish-vela-images.outputs.vela_core_dockerhub_image }}
|
||||
digest: ${{ needs.publish-vela-images.outputs.vela_core_digest }}
|
||||
- name: 'Vela CLI Image'
|
||||
image: ${{ needs.publish-vela-images.outputs.vela_cli_dockerhub_image }}
|
||||
digest: ${{ needs.publish-vela-images.outputs.vela_cli_digest }}
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: write
|
||||
packages: write
|
||||
actions: read
|
||||
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.1.0
|
||||
with:
|
||||
image: ${{ matrix.image }}
|
||||
digest: ${{ matrix.digest }}
|
||||
registry-username: oamdev
|
||||
secrets:
|
||||
registry-password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
62
.github/workflows/release.yml
vendored
62
.github/workflows/release.yml
vendored
@@ -3,14 +3,16 @@ name: Release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
workflow_dispatch: { }
|
||||
- 'v*'
|
||||
workflow_dispatch: {}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
goreleaser:
|
||||
name: goreleaser
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
contents: write
|
||||
actions: read
|
||||
@@ -20,27 +22,54 @@ jobs:
|
||||
pull-requests: read
|
||||
repository-projects: read
|
||||
statuses: read
|
||||
runs-on: ubuntu-22.04
|
||||
name: goreleaser
|
||||
id-token: write
|
||||
outputs:
|
||||
hashes: ${{ steps.hash.outputs.hashes }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: git fetch --force --tags
|
||||
|
||||
- name: Get Git tags
|
||||
run: git fetch --force --tags
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
|
||||
with:
|
||||
go-version: 1.22
|
||||
go-version: 1.23.8
|
||||
cache: true
|
||||
- uses: goreleaser/goreleaser-action@7ec5c2b0c6cdda6e8bbb49444bc797dd33d74dd8 # v5.0.0
|
||||
|
||||
- name: Install Cosign
|
||||
uses: sigstore/cosign-installer@main
|
||||
with:
|
||||
cosign-release: 'v2.5.0'
|
||||
|
||||
- name: Install syft
|
||||
uses: anchore/sbom-action/download-syft@f325610c9f50a54015d37c8d16cb3b0e2c8f4de0 # v0.18.0
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # v6.3.0
|
||||
with:
|
||||
distribution: goreleaser
|
||||
version: 1.14.1
|
||||
args: release --rm-dist --timeout 60m
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Generate hashes
|
||||
id: hash
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
run: |
|
||||
set -euo pipefail
|
||||
HASHES=$(find dist -type f -exec sha256sum {} \; | base64 -w0)
|
||||
echo "hashes=$HASHES" >> "$GITHUB_OUTPUT"
|
||||
|
||||
upload-plugin-homebrew:
|
||||
name: upload-sha256sums
|
||||
needs: goreleaser
|
||||
runs-on: ubuntu-22.04
|
||||
if: ${{ !contains(github.ref, 'alpha') && !contains(github.ref, 'beta') && !contains(github.ref, 'rc') }}
|
||||
permissions:
|
||||
contents: write
|
||||
actions: read
|
||||
@@ -50,10 +79,6 @@ jobs:
|
||||
pull-requests: read
|
||||
repository-projects: read
|
||||
statuses: read
|
||||
needs: build
|
||||
runs-on: ubuntu-22.04
|
||||
if: ${{ !contains(github.ref, 'alpha') && !contains(github.ref, 'beta') && !contains(github.ref, 'rc') }}
|
||||
name: upload-sha256sums
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
@@ -67,3 +92,16 @@ jobs:
|
||||
tag: ${{ github.ref }}
|
||||
revision: ${{ github.sha }}
|
||||
force: false
|
||||
|
||||
provenance-vela-bins:
|
||||
name: generate provenance for binaries
|
||||
needs: [goreleaser]
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: write
|
||||
actions: read
|
||||
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0 # has to be sem var
|
||||
with:
|
||||
base64-subjects: '${{ needs.goreleaser.outputs.hashes }}'
|
||||
upload-assets: true
|
||||
|
||||
6
.github/workflows/scorecards.yml
vendored
6
.github/workflows/scorecards.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # tag=v2.3.1
|
||||
uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # tag=v2.4.1
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
||||
uses: actions/upload-artifact@134dcf33c0b9454c4b17a936843d7e21dccdc335 # v4.3.6
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
@@ -55,6 +55,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # v2.1.37
|
||||
uses: github/codeql-action/upload-sarif@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
4
.github/workflows/sdk-test.yml
vendored
4
.github/workflows/sdk-test.yml
vendored
@@ -18,8 +18,8 @@ permissions:
|
||||
|
||||
env:
|
||||
# Common versions
|
||||
GO_VERSION: '1.22'
|
||||
GOLANGCI_VERSION: 'v1.54.2'
|
||||
GO_VERSION: '1.23.8'
|
||||
GOLANGCI_VERSION: 'v1.60.1'
|
||||
|
||||
jobs:
|
||||
sdk-tests:
|
||||
|
||||
2
.github/workflows/sync-api.yml
vendored
2
.github/workflows/sync-api.yml
vendored
@@ -11,7 +11,7 @@ permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.22'
|
||||
GO_VERSION: '1.23.8'
|
||||
|
||||
jobs:
|
||||
sync-core-api:
|
||||
|
||||
2
.github/workflows/sync-sdk.yaml
vendored
2
.github/workflows/sync-sdk.yaml
vendored
@@ -15,7 +15,7 @@ permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.22'
|
||||
GO_VERSION: '1.23.8'
|
||||
|
||||
jobs:
|
||||
sync_sdk:
|
||||
|
||||
2
.github/workflows/trivy-scan.yml
vendored
2
.github/workflows/trivy-scan.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
||||
output: 'trivy-results.sarif'
|
||||
|
||||
- name: Upload Trivy scan results to GitHub Security tab
|
||||
uses: github/codeql-action/upload-sarif@366883a76d75dcee5428da5c3ae7abf9386e35ac # v2.26.2
|
||||
uses: github/codeql-action/upload-sarif@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
|
||||
if: always()
|
||||
with:
|
||||
sarif_file: 'trivy-results.sarif'
|
||||
9
.github/workflows/unit-test.yml
vendored
9
.github/workflows/unit-test.yml
vendored
@@ -5,7 +5,7 @@ on:
|
||||
branches:
|
||||
- master
|
||||
- release-*
|
||||
workflow_dispatch: { }
|
||||
workflow_dispatch: {}
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
@@ -16,13 +16,12 @@ permissions:
|
||||
|
||||
env:
|
||||
# Common versions
|
||||
GO_VERSION: '1.22'
|
||||
GO_VERSION: "1.23.8"
|
||||
|
||||
jobs:
|
||||
|
||||
detect-noop:
|
||||
permissions:
|
||||
actions: write # for fkirc/skip-duplicate-actions to skip or stop workflow runs
|
||||
actions: write # for fkirc/skip-duplicate-actions to skip or stop workflow runs
|
||||
runs-on: ubuntu-22.04
|
||||
outputs:
|
||||
noop: ${{ steps.noop.outputs.should_skip }}
|
||||
@@ -53,7 +52,7 @@ jobs:
|
||||
submodules: true
|
||||
|
||||
- name: Cache Go Dependencies
|
||||
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .work/pkg
|
||||
key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }}
|
||||
|
||||
@@ -1,18 +1,6 @@
|
||||
run:
|
||||
timeout: 10m
|
||||
|
||||
skip-files:
|
||||
- "zz_generated\\..+\\.go$"
|
||||
- ".*_test.go$"
|
||||
|
||||
skip-dirs:
|
||||
- "hack"
|
||||
- "e2e"
|
||||
|
||||
output:
|
||||
# colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number"
|
||||
format: colored-line-number
|
||||
|
||||
linters-settings:
|
||||
errcheck:
|
||||
# report about not checking of errors in type assetions: `a := b.(MyStruct)`;
|
||||
@@ -23,24 +11,12 @@ linters-settings:
|
||||
# default is false: such cases aren't reported by default.
|
||||
check-blank: false
|
||||
|
||||
# [deprecated] comma-separated list of pairs of the form pkg:regex
|
||||
# the regex is used to ignore names within pkg. (default "fmt:.*").
|
||||
# see https://github.com/kisielk/errcheck#the-deprecated-method for details
|
||||
ignore: fmt:.*,io/ioutil:^Read.*
|
||||
|
||||
exhaustive:
|
||||
# indicates that switch statements are to be considered exhaustive if a
|
||||
# 'default' case is present, even if all enum members aren't listed in the
|
||||
# switch
|
||||
default-signifies-exhaustive: true
|
||||
|
||||
govet:
|
||||
# report about shadowed variables
|
||||
check-shadowing: false
|
||||
|
||||
revive:
|
||||
# minimal confidence for issues, default is 0.8
|
||||
min-confidence: 0.8
|
||||
|
||||
gofmt:
|
||||
# simplify code: gofmt with `-s` option, true by default
|
||||
@@ -55,9 +31,6 @@ linters-settings:
|
||||
# minimal code complexity to report, 30 by default (but we recommend 10-20)
|
||||
min-complexity: 30
|
||||
|
||||
maligned:
|
||||
# print struct with more effective memory layout or not, false by default
|
||||
suggest-new: true
|
||||
|
||||
dupl:
|
||||
# tokens count to trigger issue, 150 by default
|
||||
@@ -73,13 +46,6 @@ linters-settings:
|
||||
# tab width in spaces. Default to 1.
|
||||
tab-width: 1
|
||||
|
||||
unused:
|
||||
# treat code as a program (not a library) and report unused exported identifiers; default is false.
|
||||
# XXX: if you enable this setting, unused will report a lot of false-positives in text editors:
|
||||
# if it's called for subdir of a project it can't find funcs usages. All text editor integrations
|
||||
# with golangci-lint call it on a directory with the changed file.
|
||||
check-exported: false
|
||||
|
||||
unparam:
|
||||
# Inspect exported functions, default is false. Set to true if no external program/library imports your code.
|
||||
# XXX: if you enable this setting, unparam will report a lot of false-positives in text editors:
|
||||
@@ -107,9 +73,13 @@ linters-settings:
|
||||
# Allow only slices initialized with a length of zero. Default is false.
|
||||
always: false
|
||||
|
||||
revive:
|
||||
rules:
|
||||
- name: unused-parameter
|
||||
disabled: true
|
||||
|
||||
linters:
|
||||
enable:
|
||||
- megacheck
|
||||
- govet
|
||||
- gocyclo
|
||||
- gocritic
|
||||
@@ -121,11 +91,10 @@ linters:
|
||||
- misspell
|
||||
- nakedret
|
||||
- exportloopref
|
||||
- unused
|
||||
- gosimple
|
||||
- staticcheck
|
||||
disable:
|
||||
- deadcode
|
||||
- scopelint
|
||||
- structcheck
|
||||
- varcheck
|
||||
- rowserrcheck
|
||||
- sqlclosecheck
|
||||
- errchkjson
|
||||
@@ -137,8 +106,28 @@ linters:
|
||||
|
||||
|
||||
issues:
|
||||
|
||||
exclude-files:
|
||||
- "zz_generated\\..+\\.go$"
|
||||
- ".*_test.go$"
|
||||
|
||||
exclude-dirs:
|
||||
- "hack"
|
||||
- "e2e"
|
||||
|
||||
# Excluding configuration per-path and per-linter
|
||||
exclude-rules:
|
||||
- path: .*\.go
|
||||
linters:
|
||||
- errcheck
|
||||
text: "fmt\\."
|
||||
|
||||
# Ignore unchecked errors from io/ioutil functions starting with Read
|
||||
- path: .*\.go
|
||||
linters:
|
||||
- errcheck
|
||||
text: "io/ioutil.*Read"
|
||||
|
||||
# Exclude some linters from running on tests files.
|
||||
- path: _test(ing)?\.go
|
||||
linters:
|
||||
@@ -227,7 +216,7 @@ issues:
|
||||
new: false
|
||||
|
||||
# Maximum issues count per one linter. Set to 0 to disable. Default is 50.
|
||||
max-per-linter: 0
|
||||
max-issues-per-linter: 0
|
||||
|
||||
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
|
||||
max-same-issues: 0
|
||||
max-same-issues: 0
|
||||
@@ -31,6 +31,28 @@ builds:
|
||||
ldflags:
|
||||
- -s -w -X github.com/oam-dev/kubevela/version.VelaVersion={{ .Version }} -X github.com/oam-dev/kubevela/version.GitRevision=git-{{.ShortCommit}}
|
||||
|
||||
sboms:
|
||||
- id: kubevela-binaries-sboms
|
||||
artifacts: binary
|
||||
documents:
|
||||
- "${artifact}-{{ .Version }}-{{ .Os }}-{{ .Arch }}.spdx.sbom.json"
|
||||
|
||||
signs:
|
||||
- id: kubevela-cosign-keyless
|
||||
artifacts: checksum # sign the checksum file over individual artifacts
|
||||
signature: "${artifact}-keyless.sig"
|
||||
certificate: "${artifact}-keyless.pem"
|
||||
cmd: cosign
|
||||
args:
|
||||
- "sign-blob"
|
||||
- "--yes"
|
||||
- "--output-signature"
|
||||
- "${artifact}-keyless.sig"
|
||||
- "--output-certificate"
|
||||
- "${artifact}-keyless.pem"
|
||||
- "${artifact}"
|
||||
output: true
|
||||
|
||||
archives:
|
||||
- format: tar.gz
|
||||
id: vela-cli-tgz
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
ARG BASE_IMAGE
|
||||
# Build the manager binary
|
||||
FROM golang:1.22-alpine3.18 as builder
|
||||
FROM golang:1.23.8-alpine@sha256:b7486658b87d34ecf95125e5b97e8dfe86c21f712aa36fc0c702e5dc41dc63e1 AS builder
|
||||
|
||||
WORKDIR /workspace
|
||||
# Copy the Go Modules manifests
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
ARG BASE_IMAGE
|
||||
# Build the cli binary
|
||||
FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.22-alpine@sha256:d1a601b64de09e2fa38c95e55838961811d5ca11062a8f4230a5c434b3ae2a34 as builder
|
||||
FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.23.8-alpine@sha256:b7486658b87d34ecf95125e5b97e8dfe86c21f712aa36fc0c702e5dc41dc63e1 AS builder
|
||||
ARG GOPROXY
|
||||
ENV GOPROXY=${GOPROXY:-https://proxy.golang.org}
|
||||
WORKDIR /workspace
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
ARG BASE_IMAGE
|
||||
# Build the manager binary
|
||||
FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.22-alpine@sha256:d1a601b64de09e2fa38c95e55838961811d5ca11062a8f4230a5c434b3ae2a34 as builder
|
||||
FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.23.8-alpine@sha256:b7486658b87d34ecf95125e5b97e8dfe86c21f712aa36fc0c702e5dc41dc63e1 AS builder
|
||||
|
||||
WORKDIR /workspace
|
||||
# Copy the Go Modules manifests
|
||||
|
||||
2
Makefile
2
Makefile
@@ -61,7 +61,7 @@ staticcheck: staticchecktool
|
||||
## lint: Run the golangci-lint
|
||||
lint: golangci
|
||||
@$(INFO) lint
|
||||
@$(GOLANGCILINT) run --fix --verbose --skip-dirs 'scaffold'
|
||||
@$(GOLANGCILINT) run --fix --verbose --exclude-dirs 'scaffold'
|
||||
|
||||
## reviewable: Run the reviewable
|
||||
reviewable: manifests fmt vet lint staticcheck helm-doc-gen sdk_fmt
|
||||
|
||||
@@ -59,6 +59,14 @@ and share the large growing community [addons](https://kubevela.net/docs/referen
|
||||
* [Installation](https://kubevela.io/docs/install)
|
||||
* [Deploy Your Application](https://kubevela.io/docs/quick-start)
|
||||
|
||||
### Get Your Own Demo with Alibaba Cloud
|
||||
|
||||
- install KubeVela on a Serverless K8S cluster in 3 minutes, try:
|
||||
|
||||
<a href="https://acs.console.aliyun.com/quick-deploy?repo=kubevela/kubevela&branch=master" target="_blank">
|
||||
<img src="https://img.alicdn.com/imgextra/i1/O1CN01aiPSuA1Wiz7wkgF5u_!!6000000002823-55-tps-399-70.svg" width="200" alt="Deploy on Alibaba Cloud">
|
||||
</a>
|
||||
|
||||
## Documentation
|
||||
|
||||
Full documentation is available on the [KubeVela website](https://kubevela.io/).
|
||||
|
||||
@@ -102,16 +102,16 @@ func (in *GarbageCollectPolicySpec) FindStrategy(manifest *unstructured.Unstruct
|
||||
}
|
||||
|
||||
// FindDeleteOption find delete option for target resource
|
||||
func (in *GarbageCollectPolicySpec) FindDeleteOption(manifest *unstructured.Unstructured) []client.DeleteOption {
|
||||
func (in *GarbageCollectPolicySpec) FindDeleteOption(manifest *unstructured.Unstructured) (bool, []client.DeleteOption) {
|
||||
for _, rule := range in.Rules {
|
||||
if rule.Selector.Match(manifest) && rule.Propagation != nil {
|
||||
switch *rule.Propagation {
|
||||
case GarbageCollectPropagationOrphan:
|
||||
return []client.DeleteOption{client.PropagationPolicy(metav1.DeletePropagationOrphan)}
|
||||
return true, []client.DeleteOption{client.PropagationPolicy(metav1.DeletePropagationOrphan)}
|
||||
case GarbageCollectPropagationCascading:
|
||||
return []client.DeleteOption{client.PropagationPolicy(metav1.DeletePropagationBackground)}
|
||||
return false, []client.DeleteOption{client.PropagationPolicy(metav1.DeletePropagationBackground)}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return false, nil
|
||||
}
|
||||
|
||||
@@ -27,6 +27,9 @@ import (
|
||||
|
||||
// ComponentDefinitionSpec defines the desired state of ComponentDefinition
|
||||
type ComponentDefinitionSpec struct {
|
||||
// +optional
|
||||
Version string `json:"version,omitempty"`
|
||||
|
||||
// Workload is a workload type descriptor
|
||||
Workload common.WorkloadTypeDescriptor `json:"workload"`
|
||||
|
||||
|
||||
@@ -164,6 +164,9 @@ type TraitDefinitionSpec struct {
|
||||
// pre-process and post-process respectively.
|
||||
// +optional
|
||||
Stage StageType `json:"stage,omitempty"`
|
||||
|
||||
// +optional
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
// StageType describes how the manifests should be dispatched.
|
||||
|
||||
@@ -37,6 +37,9 @@ type PolicyDefinitionSpec struct {
|
||||
// ManageHealthCheck means the policy will handle health checking and skip application controller
|
||||
// built-in health checking.
|
||||
ManageHealthCheck bool `json:"manageHealthCheck,omitempty"`
|
||||
|
||||
//+optional
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
// PolicyDefinitionStatus is the status of PolicyDefinition
|
||||
|
||||
@@ -33,6 +33,9 @@ type WorkflowStepDefinitionSpec struct {
|
||||
// Only CUE schematic is supported for now.
|
||||
// +optional
|
||||
Schematic *common.Schematic `json:"schematic,omitempty"`
|
||||
|
||||
// +optional
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
// WorkflowStepDefinitionStatus is the status of WorkflowStepDefinition
|
||||
|
||||
@@ -102,23 +102,25 @@ helm install --create-namespace -n vela-system kubevela kubevela/vela-core --wai
|
||||
|
||||
### MultiCluster parameters
|
||||
|
||||
| Name | Description | Value |
|
||||
| ----------------------------------------------------------- | ------------------------------------------------------------------------------------------- | -------------------------------- |
|
||||
| `multicluster.enabled` | Whether to enable multi-cluster | `true` |
|
||||
| `multicluster.metrics.enabled` | Whether to enable multi-cluster metrics collect | `false` |
|
||||
| `multicluster.clusterGateway.direct` | controller will connect to ClusterGateway directly instead of going to Kubernetes APIServer | `true` |
|
||||
| `multicluster.clusterGateway.replicaCount` | ClusterGateway replica count | `1` |
|
||||
| `multicluster.clusterGateway.port` | ClusterGateway port | `9443` |
|
||||
| `multicluster.clusterGateway.image.repository` | ClusterGateway image repository | `oamdev/cluster-gateway` |
|
||||
| `multicluster.clusterGateway.image.tag` | ClusterGateway image tag | `v1.9.0-alpha.2` |
|
||||
| `multicluster.clusterGateway.image.pullPolicy` | ClusterGateway image pull policy | `IfNotPresent` |
|
||||
| `multicluster.clusterGateway.resources.requests.cpu` | ClusterGateway cpu request | `50m` |
|
||||
| `multicluster.clusterGateway.resources.requests.memory` | ClusterGateway memory request | `20Mi` |
|
||||
| `multicluster.clusterGateway.resources.limits.cpu` | ClusterGateway cpu limit | `500m` |
|
||||
| `multicluster.clusterGateway.resources.limits.memory` | ClusterGateway memory limit | `200Mi` |
|
||||
| `multicluster.clusterGateway.secureTLS.enabled` | Whether to enable secure TLS | `true` |
|
||||
| `multicluster.clusterGateway.secureTLS.certPath` | Path to the certificate file | `/etc/k8s-cluster-gateway-certs` |
|
||||
| `multicluster.clusterGateway.secureTLS.certManager.enabled` | Whether to enable cert-manager | `false` |
|
||||
| Name | Description | Value |
|
||||
| ------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | -------------------------------- |
|
||||
| `multicluster.enabled` | Whether to enable multi-cluster | `true` |
|
||||
| `multicluster.metrics.enabled` | Whether to enable multi-cluster metrics collect | `false` |
|
||||
| `multicluster.clusterGateway.direct` | controller will connect to ClusterGateway directly instead of going to Kubernetes APIServer | `true` |
|
||||
| `multicluster.clusterGateway.replicaCount` | ClusterGateway replica count | `1` |
|
||||
| `multicluster.clusterGateway.port` | ClusterGateway port | `9443` |
|
||||
| `multicluster.clusterGateway.image.repository` | ClusterGateway image repository | `oamdev/cluster-gateway` |
|
||||
| `multicluster.clusterGateway.image.tag` | ClusterGateway image tag | `v1.9.0-alpha.2` |
|
||||
| `multicluster.clusterGateway.image.pullPolicy` | ClusterGateway image pull policy | `IfNotPresent` |
|
||||
| `multicluster.clusterGateway.resources.requests.cpu` | ClusterGateway cpu request | `50m` |
|
||||
| `multicluster.clusterGateway.resources.requests.memory` | ClusterGateway memory request | `20Mi` |
|
||||
| `multicluster.clusterGateway.resources.limits.cpu` | ClusterGateway cpu limit | `500m` |
|
||||
| `multicluster.clusterGateway.resources.limits.memory` | ClusterGateway memory limit | `200Mi` |
|
||||
| `multicluster.clusterGateway.secureTLS.enabled` | Whether to enable secure TLS | `true` |
|
||||
| `multicluster.clusterGateway.secureTLS.certPath` | Path to the certificate file | `/etc/k8s-cluster-gateway-certs` |
|
||||
| `multicluster.clusterGateway.secureTLS.certManager.enabled` | Whether to enable cert-manager | `false` |
|
||||
| `multicluster.clusterGateway.serviceMonitor.enabled` | Whether to enable service monitor | `false` |
|
||||
| `multicluster.clusterGateway.serviceMonitor.additionalLabels` | Additional labels for service monitor | `{}` |
|
||||
|
||||
### Test parameters
|
||||
|
||||
@@ -131,29 +133,32 @@ helm install --create-namespace -n vela-system kubevela kubevela/vela-core --wai
|
||||
|
||||
### Common parameters
|
||||
|
||||
| Name | Description | Value |
|
||||
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------- |
|
||||
| `imagePullSecrets` | Image pull secrets | `[]` |
|
||||
| `nameOverride` | Override name | `""` |
|
||||
| `fullnameOverride` | Fullname override | `""` |
|
||||
| `serviceAccount.create` | Specifies whether a service account should be created | `true` |
|
||||
| `serviceAccount.annotations` | Annotations to add to the service account | `{}` |
|
||||
| `serviceAccount.name` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | `nil` |
|
||||
| `nodeSelector` | Node selector | `{}` |
|
||||
| `tolerations` | Tolerations | `[]` |
|
||||
| `affinity` | Affinity | `{}` |
|
||||
| `rbac.create` | Specifies whether a RBAC role should be created | `true` |
|
||||
| `logDebug` | Enable debug logs for development purpose | `false` |
|
||||
| `logFilePath` | If non-empty, write log files in this path | `""` |
|
||||
| `logFileMaxSize` | Defines the maximum size a log file can grow to. Unit is megabytes. If the value is 0, the maximum file size is unlimited. | `1024` |
|
||||
| `kubeClient.qps` | The qps for reconcile clients | `400` |
|
||||
| `kubeClient.burst` | The burst for reconcile clients | `600` |
|
||||
| `authentication.enabled` | Enable authentication for application | `false` |
|
||||
| `authentication.withUser` | Application authentication will impersonate as the request User | `true` |
|
||||
| `authentication.defaultUser` | Application authentication will impersonate as the User if no user provided in Application | `kubevela:vela-core` |
|
||||
| `authentication.groupPattern` | Application authentication will impersonate as the request Group that matches the pattern | `kubevela:*` |
|
||||
| `sharding.enabled` | When sharding enabled, the controller will run as master mode. Refer to https://github.com/kubevela/kubevela/blob/master/design/vela-core/sharding.md for details. | `false` |
|
||||
| `sharding.schedulableShards` | The shards available for scheduling. If empty, dynamic discovery will be used. | `""` |
|
||||
| Name | Description | Value |
|
||||
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------- |
|
||||
| `imagePullSecrets` | Image pull secrets | `[]` |
|
||||
| `nameOverride` | Override name | `""` |
|
||||
| `fullnameOverride` | Fullname override | `""` |
|
||||
| `serviceAccount.create` | Specifies whether a service account should be created | `true` |
|
||||
| `serviceAccount.annotations` | Annotations to add to the service account | `{}` |
|
||||
| `serviceAccount.name` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | `nil` |
|
||||
| `nodeSelector` | Node selector | `{}` |
|
||||
| `tolerations` | Tolerations | `[]` |
|
||||
| `affinity` | Affinity | `{}` |
|
||||
| `rbac.create` | Specifies whether a RBAC role should be created | `true` |
|
||||
| `logDebug` | Enable debug logs for development purpose | `false` |
|
||||
| `logFilePath` | If non-empty, write log files in this path | `""` |
|
||||
| `logFileMaxSize` | Defines the maximum size a log file can grow to. Unit is megabytes. If the value is 0, the maximum file size is unlimited. | `1024` |
|
||||
| `kubeClient.qps` | The qps for reconcile clients | `400` |
|
||||
| `kubeClient.burst` | The burst for reconcile clients | `600` |
|
||||
| `authentication.enabled` | Enable authentication for application | `false` |
|
||||
| `authentication.withUser` | Application authentication will impersonate as the request User | `true` |
|
||||
| `authentication.defaultUser` | Application authentication will impersonate as the User if no user provided in Application | `kubevela:vela-core` |
|
||||
| `authentication.groupPattern` | Application authentication will impersonate as the request Group that matches the pattern | `kubevela:*` |
|
||||
| `sharding.enabled` | When sharding enabled, the controller will run as master mode. Refer to https://github.com/kubevela/kubevela/blob/master/design/vela-core/sharding.md for details. | `false` |
|
||||
| `sharding.schedulableShards` | The shards available for scheduling. If empty, dynamic discovery will be used. | `""` |
|
||||
| `core.metrics.enabled` | Enable metrics for vela-core | `false` |
|
||||
| `core.metrics.serviceMonitor.enabled` | Enable service monitor for metrics | `false` |
|
||||
| `core.metrics.serviceMonitor.additionalLabels` | Additional labels for service monitor | `{}` |
|
||||
|
||||
|
||||
## Uninstallation
|
||||
|
||||
@@ -1053,6 +1053,8 @@ spec:
|
||||
for the abstraction
|
||||
type: string
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
workload:
|
||||
description: Workload is a workload type descriptor
|
||||
properties:
|
||||
@@ -1356,6 +1358,8 @@ spec:
|
||||
- configuration
|
||||
type: object
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
type: object
|
||||
status:
|
||||
description: PolicyDefinitionStatus is the status of PolicyDefinition
|
||||
@@ -1651,6 +1655,8 @@ spec:
|
||||
for the abstraction
|
||||
type: string
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
workloadRefPath:
|
||||
description: WorkloadRefPath indicates where/if a trait
|
||||
accepts a workloadRef object
|
||||
@@ -2059,6 +2065,8 @@ spec:
|
||||
- configuration
|
||||
type: object
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
type: object
|
||||
status:
|
||||
description: WorkflowStepDefinitionStatus is the status of WorkflowStepDefinition
|
||||
|
||||
@@ -195,6 +195,8 @@ spec:
|
||||
the abstraction
|
||||
type: string
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
workload:
|
||||
description: Workload is a workload type descriptor
|
||||
properties:
|
||||
|
||||
@@ -241,6 +241,8 @@ spec:
|
||||
for the abstraction
|
||||
type: string
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
workload:
|
||||
description: Workload is a workload type descriptor
|
||||
properties:
|
||||
@@ -489,6 +491,8 @@ spec:
|
||||
- configuration
|
||||
type: object
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
type: object
|
||||
status:
|
||||
description: PolicyDefinitionStatus is the status of PolicyDefinition
|
||||
@@ -774,6 +778,8 @@ spec:
|
||||
for the abstraction
|
||||
type: string
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
workloadRefPath:
|
||||
description: WorkloadRefPath indicates where/if a trait accepts
|
||||
a workloadRef object
|
||||
@@ -992,6 +998,8 @@ spec:
|
||||
- configuration
|
||||
type: object
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
type: object
|
||||
status:
|
||||
description: WorkflowStepDefinitionStatus is the status of WorkflowStepDefinition
|
||||
|
||||
@@ -156,6 +156,8 @@ spec:
|
||||
- configuration
|
||||
type: object
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
type: object
|
||||
status:
|
||||
description: PolicyDefinitionStatus is the status of PolicyDefinition
|
||||
|
||||
@@ -225,6 +225,8 @@ spec:
|
||||
the abstraction
|
||||
type: string
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
workloadRefPath:
|
||||
description: WorkloadRefPath indicates where/if a trait accepts a
|
||||
workloadRef object
|
||||
|
||||
@@ -152,6 +152,8 @@ spec:
|
||||
- configuration
|
||||
type: object
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
type: object
|
||||
status:
|
||||
description: WorkflowStepDefinitionStatus is the status of WorkflowStepDefinition
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ template "kubevela.fullname" . }}-admission-create
|
||||
name: {{ template "kubevela.fullname" . }}-admission-create
|
||||
namespace: {{ .Release.Namespace }}
|
||||
annotations:
|
||||
"helm.sh/hook": pre-install,pre-upgrade
|
||||
@@ -17,7 +17,7 @@ spec:
|
||||
{{- end }}
|
||||
template:
|
||||
metadata:
|
||||
name: {{ template "kubevela.fullname" . }}-admission-create
|
||||
name: {{ template "kubevela.fullname" . }}-admission-create
|
||||
labels:
|
||||
app: {{ template "kubevela.name" . }}-admission-create
|
||||
{{- include "kubevela.labels" . | nindent 8 }}
|
||||
@@ -39,17 +39,26 @@ spec:
|
||||
- --cert-name=tls.crt
|
||||
restartPolicy: OnFailure
|
||||
serviceAccountName: {{ template "kubevela.fullname" . }}-admission
|
||||
{{- with .Values.admissionWebhooks.patch.nodeSelector }}
|
||||
{{- if .Values.admissionWebhooks.patch.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- toYaml .Values.admissionWebhooks.patch.nodeSelector | nindent 8 }}
|
||||
{{- else if .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml .Values.nodeSelector | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.admissionWebhooks.patch.affinity }}
|
||||
{{- if .Values.admissionWebhooks.patch.affinity }}
|
||||
affinity:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- toYaml .Values.admissionWebhooks.patch.affinity | nindent 8 }}
|
||||
{{- else if .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml .Values.affinity | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.admissionWebhooks.patch.tolerations }}
|
||||
{{- if .Values.admissionWebhooks.patch.tolerations }}
|
||||
tolerations:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- toYaml .Values.admissionWebhooks.patch.tolerations | nindent 8 }}
|
||||
{{- else if .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml .Values.tolerations | nindent 8 }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
runAsGroup: 2000
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ template "kubevela.fullname" . }}-admission-patch
|
||||
name: {{ template "kubevela.fullname" . }}-admission-patch
|
||||
namespace: {{ .Release.Namespace }}
|
||||
annotations:
|
||||
"helm.sh/hook": post-install,post-upgrade
|
||||
@@ -17,7 +17,7 @@ spec:
|
||||
{{- end }}
|
||||
template:
|
||||
metadata:
|
||||
name: {{ template "kubevela.fullname" . }}-admission-patch
|
||||
name: {{ template "kubevela.fullname" . }}-admission-patch
|
||||
labels:
|
||||
app: {{ template "kubevela.name" . }}-admission-patch
|
||||
{{- include "kubevela.labels" . | nindent 8 }}
|
||||
@@ -41,13 +41,26 @@ spec:
|
||||
{{- end }}
|
||||
restartPolicy: OnFailure
|
||||
serviceAccountName: {{ template "kubevela.fullname" . }}-admission
|
||||
{{- with .Values.admissionWebhooks.patch.affinity }}
|
||||
affinity:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- if .Values.admissionWebhooks.patch.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml .Values.admissionWebhooks.patch.nodeSelector | nindent 8 }}
|
||||
{{- else if .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml .Values.nodeSelector | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.admissionWebhooks.patch.tolerations }}
|
||||
{{- if .Values.admissionWebhooks.patch.affinity }}
|
||||
affinity:
|
||||
{{- toYaml .Values.admissionWebhooks.patch.affinity | nindent 8 }}
|
||||
{{- else if .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml .Values.affinity | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.admissionWebhooks.patch.tolerations }}
|
||||
tolerations:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- toYaml .Values.admissionWebhooks.patch.tolerations | nindent 8 }}
|
||||
{{- else if .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml .Values.tolerations | nindent 8 }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
runAsGroup: 2000
|
||||
|
||||
@@ -14,13 +14,13 @@ webhooks:
|
||||
service:
|
||||
name: {{ template "kubevela.name" . }}-webhook
|
||||
namespace: {{ .Release.Namespace }}
|
||||
path: /validating-core-oam-dev-v1alpha2-traitdefinitions
|
||||
path: /validating-core-oam-dev-v1beta1-traitdefinitions
|
||||
{{- if .Values.admissionWebhooks.patch.enabled }}
|
||||
failurePolicy: Ignore
|
||||
{{- else }}
|
||||
failurePolicy: {{ .Values.admissionWebhooks.failurePolicy }}
|
||||
{{- end }}
|
||||
name: validating.core.oam.dev.v1alpha2.traitdefinitions
|
||||
name: validating.core.oam.dev.v1beta1.traitdefinitions
|
||||
sideEffects: None
|
||||
admissionReviewVersions:
|
||||
- v1beta1
|
||||
@@ -35,7 +35,6 @@ webhooks:
|
||||
- UPDATE
|
||||
resources:
|
||||
- traitdefinitions
|
||||
scope: Cluster
|
||||
timeoutSeconds: 5
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
|
||||
@@ -124,6 +124,7 @@ spec:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.multicluster.clusterGateway.port }}
|
||||
targetPort: {{ .Values.multicluster.clusterGateway.port }}
|
||||
name: default
|
||||
---
|
||||
# 1. Check whether APIService ""v1alpha1.cluster.core.oam.dev" is already present in the cluster
|
||||
# 2.a If the APIService doesn't exist, create it.
|
||||
@@ -189,4 +190,4 @@ subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "kubevela.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
@@ -95,6 +95,18 @@ spec:
|
||||
runAsGroup: 2000
|
||||
runAsNonRoot: true
|
||||
runAsUser: 2000
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
@@ -138,4 +150,16 @@ spec:
|
||||
runAsGroup: 2000
|
||||
runAsNonRoot: true
|
||||
runAsUser: 2000
|
||||
{{ end }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{ end }}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/podsecuritycontext.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Adds security context to the pod spec in path 'spec.template.spec.securityContext'.
|
||||
name: podsecuritycontext
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
patch: spec: template: spec: securityContext: {
|
||||
if parameter.appArmorProfile != _|_ {
|
||||
appArmorProfile: parameter.appArmorProfile
|
||||
}
|
||||
if parameter.fsGroup != _|_ {
|
||||
fsGroup: parameter.fsGroup
|
||||
}
|
||||
if parameter.runAsGroup != _|_ {
|
||||
runAsGroup: parameter.runAsGroup
|
||||
}
|
||||
if parameter.runAsUser != _|_ {
|
||||
runAsUser: parameter.runAsUser
|
||||
}
|
||||
if parameter.seccompProfile != _|_ {
|
||||
seccompProfile: parameter.seccompProfile
|
||||
}
|
||||
runAsNonRoot: parameter.runAsNonRoot
|
||||
}
|
||||
|
||||
parameter: {
|
||||
// +usage=Specify the AppArmor profile for the pod
|
||||
appArmorProfile?: {
|
||||
type: "RuntimeDefault" | "Unconfined" | "Localhost"
|
||||
// +usage: localhostProfile is required when type is 'Localhost'
|
||||
localhostProfile?: string
|
||||
}
|
||||
fsGroup?: int
|
||||
runAsGroup?: int
|
||||
// +usage=Specify the UID to run the entrypoint of the container process
|
||||
runAsUser?: int
|
||||
// +usage=Specify if the container runs as a non-root user
|
||||
runAsNonRoot: *true | bool
|
||||
// +usage=Specify the seccomp profile for the pod
|
||||
seccompProfile?: {
|
||||
type: "RuntimeDefault" | "Unconfined" | "Localhost"
|
||||
// +usage: localhostProfile is required when type is 'Localhost'
|
||||
localhostProfile?: string
|
||||
}
|
||||
}
|
||||
|
||||
107
charts/vela-core/templates/defwithtemplate/securitycontext.yaml
Normal file
107
charts/vela-core/templates/defwithtemplate/securitycontext.yaml
Normal file
@@ -0,0 +1,107 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/securitycontext.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Adds security context to the container spec in path 'spec.template.spec.containers.[].securityContext'.
|
||||
name: securitycontext
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
#PatchParams: {
|
||||
// +usage=Specify the name of the target container, if not set, use the component name
|
||||
containerName: *"" | string
|
||||
addCapabilities?: [...string]
|
||||
allowPrivilegeEscalation: *false | bool
|
||||
dropCapabilities?: [...string]
|
||||
privileged: *false | bool
|
||||
readOnlyRootFilesystem: *false | bool
|
||||
runAsNonRoot: *true | bool
|
||||
runAsUser?: int
|
||||
runAsGroup?: int
|
||||
}
|
||||
|
||||
PatchContainer: {
|
||||
_params: #PatchParams
|
||||
name: _params.containerName
|
||||
_baseContainers: context.output.spec.template.spec.containers
|
||||
_matchContainers_: [for _container_ in _baseContainers if _container_.name == name {_container_}]
|
||||
_baseContainer: *_|_ | {...}
|
||||
if len(_matchContainers_) == 0 {
|
||||
err: "container \(name) not found"
|
||||
}
|
||||
if len(_matchContainers_) > 0 {
|
||||
securityContext: {
|
||||
capabilities: {
|
||||
if _params.addCapabilities != _|_ {
|
||||
add: _params.addCapabilities
|
||||
}
|
||||
if _params.dropCapabilities != _|_ {
|
||||
drop: _params.dropCapabilities
|
||||
}
|
||||
}
|
||||
if _params.runAsUser != _|_ {
|
||||
runAsUser: _params.runAsUser
|
||||
}
|
||||
if _params.runAsGroup != _|_ {
|
||||
runAsGroup: _params.runAsGroup
|
||||
}
|
||||
allowPrivilegeEscalation: _params.allowPrivilegeEscalation
|
||||
readOnlyRootFilesystem: _params.readOnlyRootFilesystem
|
||||
privileged: _params.privileged
|
||||
runAsNonRoot: _params.runAsNonRoot
|
||||
}
|
||||
}
|
||||
}
|
||||
patch: spec: template: spec: {
|
||||
if parameter.containers == _|_ {
|
||||
// +patchKey=name
|
||||
containers: [{
|
||||
PatchContainer & {_params: {
|
||||
if parameter.containerName == "" {
|
||||
containerName: context.name
|
||||
}
|
||||
if parameter.containerName != "" {
|
||||
containerName: parameter.containerName
|
||||
}
|
||||
allowPrivilegeEscalation: parameter.allowPrivilegeEscalation
|
||||
readOnlyRootFilesystem: parameter.readOnlyRootFilesystem
|
||||
privileged: parameter.privileged
|
||||
runAsNonRoot: parameter.runAsNonRoot
|
||||
runAsUser: parameter.runAsUser
|
||||
runAsGroup: parameter.runAsGroup
|
||||
addCapabilities: parameter.addCapabilities
|
||||
dropCapabilities: parameter.dropCapabilities
|
||||
}}
|
||||
}]
|
||||
}
|
||||
|
||||
if parameter.containers != _|_ {
|
||||
// +patchKey=name
|
||||
containers: [for c in parameter.containers {
|
||||
if c.containerName == "" {
|
||||
err: "containerName must be set for containers"
|
||||
}
|
||||
if c.containerName != "" {
|
||||
PatchContainer & {_params: c}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
parameter: #PatchParams | close({
|
||||
// +usage=Specify the container image for multiple containers
|
||||
containers: [...#PatchParams]
|
||||
})
|
||||
|
||||
errs: [for c in patch.spec.template.spec.containers if c.err != _|_ {c.err}]
|
||||
|
||||
@@ -98,9 +98,6 @@ spec:
|
||||
if _params.periodSeconds != _|_ {
|
||||
periodSeconds: _params.periodSeconds
|
||||
}
|
||||
if _params.tcpSocket != _|_ {
|
||||
tcpSocket: _params.tcpSocket
|
||||
}
|
||||
if _params.timeoutSeconds != _|_ {
|
||||
timeoutSeconds: _params.timeoutSeconds
|
||||
}
|
||||
|
||||
605
charts/vela-core/templates/defwithtemplate/statefulset.yaml
Normal file
605
charts/vela-core/templates/defwithtemplate/statefulset.yaml
Normal file
@@ -0,0 +1,605 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/statefulset.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Describes long-running, scalable, containerized services used to manage stateful application, like database.
|
||||
name: statefulset
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
mountsArray: [
|
||||
if parameter.volumeMounts != _|_ if parameter.volumeMounts.pvc != _|_ for v in parameter.volumeMounts.pvc {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
|
||||
if parameter.volumeMounts != _|_ if parameter.volumeMounts.configMap != _|_ for v in parameter.volumeMounts.configMap {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
|
||||
if parameter.volumeMounts != _|_ if parameter.volumeMounts.secret != _|_ for v in parameter.volumeMounts.secret {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
|
||||
if parameter.volumeMounts != _|_ if parameter.volumeMounts.emptyDir != _|_ for v in parameter.volumeMounts.emptyDir {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
|
||||
if parameter.volumeMounts != _|_ if parameter.volumeMounts.hostPath != _|_ for v in parameter.volumeMounts.hostPath {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
volumesList: [
|
||||
if parameter.volumeMounts != _|_ if parameter.volumeMounts.pvc != _|_ for v in parameter.volumeMounts.pvc {
|
||||
{
|
||||
name: v.name
|
||||
persistentVolumeClaim: claimName: v.claimName
|
||||
}
|
||||
},
|
||||
|
||||
if parameter.volumeMounts != _|_ if parameter.volumeMounts.configMap != _|_ for v in parameter.volumeMounts.configMap {
|
||||
{
|
||||
name: v.name
|
||||
configMap: {
|
||||
defaultMode: v.defaultMode
|
||||
name: v.cmName
|
||||
if v.items != _|_ {
|
||||
items: v.items
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
if parameter.volumeMounts != _|_ if parameter.volumeMounts.secret != _|_ for v in parameter.volumeMounts.secret {
|
||||
{
|
||||
name: v.name
|
||||
secret: {
|
||||
defaultMode: v.defaultMode
|
||||
secretName: v.secretName
|
||||
if v.items != _|_ {
|
||||
items: v.items
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
if parameter.volumeMounts != _|_ if parameter.volumeMounts.emptyDir != _|_ for v in parameter.volumeMounts.emptyDir {
|
||||
{
|
||||
name: v.name
|
||||
emptyDir: medium: v.medium
|
||||
}
|
||||
},
|
||||
|
||||
if parameter.volumeMounts != _|_ if parameter.volumeMounts.hostPath != _|_ for v in parameter.volumeMounts.hostPath {
|
||||
{
|
||||
name: v.name
|
||||
hostPath: path: v.path
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
deDupVolumesArray: [
|
||||
for val in [
|
||||
for i, vi in volumesList {
|
||||
for j, vj in volumesList if j < i && vi.name == vj.name {
|
||||
_ignore: true
|
||||
}
|
||||
vi
|
||||
},
|
||||
] if val._ignore == _|_ {
|
||||
val
|
||||
},
|
||||
]
|
||||
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "StatefulSet"
|
||||
spec: {
|
||||
selector: matchLabels: "app.oam.dev/component": context.name
|
||||
|
||||
template: {
|
||||
metadata: {
|
||||
labels: {
|
||||
if parameter.labels != _|_ {
|
||||
parameter.labels
|
||||
}
|
||||
if parameter.addRevisionLabel {
|
||||
"app.oam.dev/revision": context.revision
|
||||
}
|
||||
"app.oam.dev/name": context.appName
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
if parameter.annotations != _|_ {
|
||||
annotations: parameter.annotations
|
||||
}
|
||||
}
|
||||
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
if parameter["port"] != _|_ if parameter["ports"] == _|_ {
|
||||
ports: [{
|
||||
containerPort: parameter.port
|
||||
}]
|
||||
}
|
||||
if parameter["ports"] != _|_ {
|
||||
ports: [for v in parameter.ports {
|
||||
{
|
||||
containerPort: {
|
||||
if v.containerPort != _|_ {v.containerPort}
|
||||
if v.containerPort == _|_ {v.port}
|
||||
}
|
||||
protocol: v.protocol
|
||||
if v.name != _|_ {
|
||||
name: v.name
|
||||
}
|
||||
if v.name == _|_ {
|
||||
_name: {
|
||||
if v.containerPort != _|_ {"port-" + strconv.FormatInt(v.containerPort, 10)}
|
||||
if v.containerPort == _|_ {"port-" + strconv.FormatInt(v.port, 10)}
|
||||
}
|
||||
name: *_name | string
|
||||
if v.protocol != "TCP" {
|
||||
name: _name + "-" + strings.ToLower(v.protocol)
|
||||
}
|
||||
}
|
||||
}}]
|
||||
}
|
||||
|
||||
if parameter["imagePullPolicy"] != _|_ {
|
||||
imagePullPolicy: parameter.imagePullPolicy
|
||||
}
|
||||
|
||||
if parameter["cmd"] != _|_ {
|
||||
command: parameter.cmd
|
||||
}
|
||||
|
||||
if parameter["args"] != _|_ {
|
||||
args: parameter.args
|
||||
}
|
||||
|
||||
if parameter["env"] != _|_ {
|
||||
env: parameter.env
|
||||
}
|
||||
|
||||
if context["config"] != _|_ {
|
||||
env: context.config
|
||||
}
|
||||
|
||||
if parameter["cpu"] != _|_ {
|
||||
resources: {
|
||||
limits: cpu: parameter.cpu
|
||||
requests: cpu: parameter.cpu
|
||||
}
|
||||
}
|
||||
|
||||
if parameter["memory"] != _|_ {
|
||||
resources: {
|
||||
limits: memory: parameter.memory
|
||||
requests: memory: parameter.memory
|
||||
}
|
||||
}
|
||||
|
||||
if parameter["volumes"] != _|_ if parameter["volumeMounts"] == _|_ {
|
||||
volumeMounts: [for v in parameter.volumes {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
}}]
|
||||
}
|
||||
|
||||
if parameter["volumeMounts"] != _|_ {
|
||||
volumeMounts: mountsArray
|
||||
}
|
||||
|
||||
if parameter["livenessProbe"] != _|_ {
|
||||
livenessProbe: parameter.livenessProbe
|
||||
}
|
||||
|
||||
if parameter["readinessProbe"] != _|_ {
|
||||
readinessProbe: parameter.readinessProbe
|
||||
}
|
||||
|
||||
}]
|
||||
|
||||
if parameter["hostAliases"] != _|_ {
|
||||
// +patchKey=ip
|
||||
hostAliases: parameter.hostAliases
|
||||
}
|
||||
|
||||
if parameter["imagePullSecrets"] != _|_ {
|
||||
imagePullSecrets: [for v in parameter.imagePullSecrets {
|
||||
name: v
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
if parameter["volumes"] != _|_ if parameter["volumeMounts"] == _|_ {
|
||||
volumes: [for v in parameter.volumes {
|
||||
{
|
||||
name: v.name
|
||||
if v.type == "pvc" {
|
||||
persistentVolumeClaim: claimName: v.claimName
|
||||
}
|
||||
if v.type == "configMap" {
|
||||
configMap: {
|
||||
defaultMode: v.defaultMode
|
||||
name: v.cmName
|
||||
if v.items != _|_ {
|
||||
items: v.items
|
||||
}
|
||||
}
|
||||
}
|
||||
if v.type == "secret" {
|
||||
secret: {
|
||||
defaultMode: v.defaultMode
|
||||
secretName: v.secretName
|
||||
if v.items != _|_ {
|
||||
items: v.items
|
||||
}
|
||||
}
|
||||
}
|
||||
if v.type == "emptyDir" {
|
||||
emptyDir: medium: v.medium
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
if parameter["volumeMounts"] != _|_ {
|
||||
volumes: deDupVolumesArray
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exposePorts: [
|
||||
if parameter.ports != _|_ for v in parameter.ports if v.expose == true {
|
||||
port: v.port
|
||||
if v.containerPort != _|_ {targetPort: v.containerPort}
|
||||
if v.containerPort == _|_ {targetPort: v.port}
|
||||
if v.name != _|_ {name: v.name}
|
||||
if v.name == _|_ {
|
||||
_name: {
|
||||
if v.containerPort != _|_ {
|
||||
"port-" + strconv.FormatInt(v.containerPort, 10)
|
||||
}
|
||||
if v.containerPort == _|_ {
|
||||
"port-" + strconv.FormatInt(v.port, 10)
|
||||
}
|
||||
}
|
||||
name: *_name | string
|
||||
if v.protocol != "TCP" {
|
||||
name: _name + "-" + strings.ToLower(v.protocol)
|
||||
}
|
||||
}
|
||||
if v.nodePort != _|_ if parameter.exposeType == "NodePort" {
|
||||
nodePort: v.nodePort
|
||||
}
|
||||
if v.protocol != _|_ {
|
||||
protocol: v.protocol
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
outputs: {
|
||||
if len(exposePorts) != 0 {
|
||||
statefulsetsExpose: {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
metadata: name: context.name
|
||||
spec: {
|
||||
selector: "app.oam.dev/component": context.name
|
||||
ports: exposePorts
|
||||
type: parameter.exposeType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parameter: {
|
||||
// +usage=Specify the labels in the workload
|
||||
labels?: [string]: string
|
||||
|
||||
// +usage=Specify the annotations in the workload
|
||||
annotations?: [string]: string
|
||||
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
|
||||
// +usage=Specify image pull policy for your service
|
||||
imagePullPolicy?: "Always" | "Never" | "IfNotPresent"
|
||||
|
||||
// +usage=Specify image pull secrets for your service
|
||||
imagePullSecrets?: [...string]
|
||||
|
||||
// +ignore
|
||||
// +usage=Deprecated field, please use ports instead
|
||||
// +short=p
|
||||
port?: int
|
||||
|
||||
// +usage=Which ports do you want customer traffic sent to, defaults to 80
|
||||
ports?: [...{
|
||||
// +usage=Number of port to expose on the pod's IP address
|
||||
port: int
|
||||
// +usage=Number of container port to connect to, defaults to port
|
||||
containerPort?: int
|
||||
// +usage=Name of the port
|
||||
name?: string
|
||||
// +usage=Protocol for port. Must be UDP, TCP, or SCTP
|
||||
protocol: *"TCP" | "UDP" | "SCTP"
|
||||
// +usage=Specify if the port should be exposed
|
||||
expose: *false | bool
|
||||
// +usage=exposed node port. Only Valid when exposeType is NodePort
|
||||
nodePort?: int
|
||||
}]
|
||||
|
||||
// +ignore
|
||||
// +usage=Specify what kind of Service you want. options: "ClusterIP", "NodePort", "LoadBalancer"
|
||||
exposeType: *"ClusterIP" | "NodePort" | "LoadBalancer"
|
||||
|
||||
// +ignore
|
||||
// +usage=If addRevisionLabel is true, the revision label will be added to the underlying pods
|
||||
addRevisionLabel: *false | bool
|
||||
|
||||
// +usage=Commands to run in the container
|
||||
cmd?: [...string]
|
||||
|
||||
// +usage=Arguments to the entrypoint
|
||||
args?: [...string]
|
||||
|
||||
// +usage=Define arguments by using environment variables
|
||||
env?: [...{
|
||||
// +usage=Environment variable name
|
||||
name: string
|
||||
// +usage=The value of the environment variable
|
||||
value?: string
|
||||
// +usage=Specifies a source the value of this var should come from
|
||||
valueFrom?: {
|
||||
// +usage=Selects a key of a secret in the pod's namespace
|
||||
secretKeyRef?: {
|
||||
// +usage=The name of the secret in the pod's namespace to select from
|
||||
name: string
|
||||
// +usage=The key of the secret to select from. Must be a valid secret key
|
||||
key: string
|
||||
}
|
||||
// +usage=Selects a key of a config map in the pod's namespace
|
||||
configMapKeyRef?: {
|
||||
// +usage=The name of the config map in the pod's namespace to select from
|
||||
name: string
|
||||
// +usage=The key of the config map to select from. Must be a valid secret key
|
||||
key: string
|
||||
}
|
||||
}
|
||||
}]
|
||||
|
||||
// +usage=Number of CPU units for the service, like `0.5` (0.5 CPU core), `1` (1 CPU core)
|
||||
cpu?: string
|
||||
|
||||
// +usage=Specifies the attributes of the memory resource required for the container.
|
||||
memory?: string
|
||||
|
||||
volumeMounts?: {
|
||||
// +usage=Mount PVC type volume
|
||||
pvc?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
// +usage=The name of the PVC
|
||||
claimName: string
|
||||
}]
|
||||
// +usage=Mount ConfigMap type volume
|
||||
configMap?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
defaultMode: *420 | int
|
||||
cmName: string
|
||||
items?: [...{
|
||||
key: string
|
||||
path: string
|
||||
mode: *511 | int
|
||||
}]
|
||||
}]
|
||||
// +usage=Mount Secret type volume
|
||||
secret?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
defaultMode: *420 | int
|
||||
secretName: string
|
||||
items?: [...{
|
||||
key: string
|
||||
path: string
|
||||
mode: *511 | int
|
||||
}]
|
||||
}]
|
||||
// +usage=Mount EmptyDir type volume
|
||||
emptyDir?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
medium: *"" | "Memory"
|
||||
}]
|
||||
// +usage=Mount HostPath type volume
|
||||
hostPath?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
path: string
|
||||
}]
|
||||
}
|
||||
|
||||
// +usage=Deprecated field, use volumeMounts instead.
|
||||
volumes?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
// +usage=Specify volume type, options: "pvc","configMap","secret","emptyDir", default to emptyDir
|
||||
type: *"emptyDir" | "pvc" | "configMap" | "secret"
|
||||
if type == "pvc" {
|
||||
claimName: string
|
||||
}
|
||||
if type == "configMap" {
|
||||
defaultMode: *420 | int
|
||||
cmName: string
|
||||
items?: [...{
|
||||
key: string
|
||||
path: string
|
||||
mode: *511 | int
|
||||
}]
|
||||
}
|
||||
if type == "secret" {
|
||||
defaultMode: *420 | int
|
||||
secretName: string
|
||||
items?: [...{
|
||||
key: string
|
||||
path: string
|
||||
mode: *511 | int
|
||||
}]
|
||||
}
|
||||
if type == "emptyDir" {
|
||||
medium: *"" | "Memory"
|
||||
}
|
||||
}]
|
||||
|
||||
// +usage=Instructions for assessing whether the container is alive.
|
||||
livenessProbe?: #HealthProbe
|
||||
|
||||
// +usage=Instructions for assessing whether the container is in a suitable state to serve traffic.
|
||||
readinessProbe?: #HealthProbe
|
||||
|
||||
// +usage=Specify the hostAliases to add
|
||||
hostAliases?: [...{
|
||||
ip: string
|
||||
hostnames: [...string]
|
||||
}]
|
||||
}
|
||||
|
||||
#HealthProbe: {
|
||||
|
||||
// +usage=Instructions for assessing container health by executing a command. Either this attribute or the httpGet attribute or the tcpSocket attribute MUST be specified. This attribute is mutually exclusive with both the httpGet attribute and the tcpSocket attribute.
|
||||
exec?: {
|
||||
// +usage=A command to be executed inside the container to assess its health. Each space delimited token of the command is a separate array element. Commands exiting 0 are considered to be successful probes, whilst all other exit codes are considered failures.
|
||||
command: [...string]
|
||||
}
|
||||
|
||||
// +usage=Instructions for assessing container health by executing an HTTP GET request. Either this attribute or the exec attribute or the tcpSocket attribute MUST be specified. This attribute is mutually exclusive with both the exec attribute and the tcpSocket attribute.
|
||||
httpGet?: {
|
||||
// +usage=The endpoint, relative to the port, to which the HTTP GET request should be directed.
|
||||
path: string
|
||||
// +usage=The TCP socket within the container to which the HTTP GET request should be directed.
|
||||
port: int
|
||||
host?: string
|
||||
scheme?: *"HTTP" | string
|
||||
httpHeaders?: [...{
|
||||
name: string
|
||||
value: string
|
||||
}]
|
||||
}
|
||||
|
||||
// +usage=Instructions for assessing container health by probing a TCP socket. Either this attribute or the exec attribute or the httpGet attribute MUST be specified. This attribute is mutually exclusive with both the exec attribute and the httpGet attribute.
|
||||
tcpSocket?: {
|
||||
// +usage=The TCP socket within the container that should be probed to assess container health.
|
||||
port: int
|
||||
}
|
||||
|
||||
// +usage=Number of seconds after the container is started before the first probe is initiated.
|
||||
initialDelaySeconds: *0 | int
|
||||
|
||||
// +usage=How often, in seconds, to execute the probe.
|
||||
periodSeconds: *10 | int
|
||||
|
||||
// +usage=Number of seconds after which the probe times out.
|
||||
timeoutSeconds: *1 | int
|
||||
|
||||
// +usage=Minimum consecutive successes for the probe to be considered successful after having failed.
|
||||
successThreshold: *1 | int
|
||||
|
||||
// +usage=Number of consecutive failures required to determine the container is not alive (liveness probe) or not ready (readiness probe).
|
||||
failureThreshold: *3 | int
|
||||
}
|
||||
status:
|
||||
customStatus: |-
|
||||
ready: {
|
||||
readyReplicas: *0 | int
|
||||
} & {
|
||||
if context.output.status.readyReplicas != _|_ {
|
||||
readyReplicas: context.output.status.readyReplicas
|
||||
}
|
||||
}
|
||||
message: "Ready:\(ready.readyReplicas)/\(context.output.spec.replicas)"
|
||||
healthPolicy: |-
|
||||
ready: {
|
||||
updatedReplicas: *0 | int
|
||||
readyReplicas: *0 | int
|
||||
replicas: *0 | int
|
||||
observedGeneration: *0 | int
|
||||
} & {
|
||||
if context.output.status.updatedReplicas != _|_ {
|
||||
updatedReplicas: context.output.status.updatedReplicas
|
||||
}
|
||||
if context.output.status.readyReplicas != _|_ {
|
||||
readyReplicas: context.output.status.readyReplicas
|
||||
}
|
||||
if context.output.status.replicas != _|_ {
|
||||
replicas: context.output.status.replicas
|
||||
}
|
||||
if context.output.status.observedGeneration != _|_ {
|
||||
observedGeneration: context.output.status.observedGeneration
|
||||
}
|
||||
}
|
||||
_isHealth: (context.output.spec.replicas == ready.readyReplicas) && (context.output.spec.replicas == ready.updatedReplicas) && (context.output.spec.replicas == ready.replicas) && (ready.observedGeneration == context.output.metadata.generation || ready.observedGeneration > context.output.metadata.generation)
|
||||
isHealth: *_isHealth | bool
|
||||
if context.output.metadata.annotations != _|_ {
|
||||
if context.output.metadata.annotations["app.oam.dev/disable-health-check"] != _|_ {
|
||||
isHealth: true
|
||||
}
|
||||
}
|
||||
workload:
|
||||
definition:
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
type: statefulsets.apps
|
||||
|
||||
@@ -14,6 +14,7 @@ spec:
|
||||
output: {
|
||||
apiVersion: "batch/v1"
|
||||
kind: "Job"
|
||||
metadata: name: "\(context.appName)-\(context.name)"
|
||||
spec: {
|
||||
parallelism: parameter.count
|
||||
completions: parameter.count
|
||||
|
||||
@@ -207,16 +207,32 @@ spec:
|
||||
}
|
||||
|
||||
if parameter["cpu"] != _|_ {
|
||||
resources: {
|
||||
limits: cpu: parameter.cpu
|
||||
requests: cpu: parameter.cpu
|
||||
if (parameter.limit.cpu != _|_) {
|
||||
resources: {
|
||||
requests: cpu: parameter.cpu
|
||||
limits: cpu: parameter.limit.cpu
|
||||
}
|
||||
}
|
||||
if (parameter.limit.cpu == _|_) {
|
||||
resources: {
|
||||
limits: cpu: parameter.cpu
|
||||
requests: cpu: parameter.cpu
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if parameter["memory"] != _|_ {
|
||||
resources: {
|
||||
limits: memory: parameter.memory
|
||||
requests: memory: parameter.memory
|
||||
if (parameter.limit.memory != _|_) {
|
||||
resources: {
|
||||
limits: memory: parameter.limit.memory
|
||||
requests: memory: parameter.memory
|
||||
}
|
||||
}
|
||||
if (parameter.limit.memory == _|_) {
|
||||
resources: {
|
||||
limits: memory: parameter.memory
|
||||
requests: memory: parameter.memory
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -421,6 +437,11 @@ spec:
|
||||
// +usage=Specifies the attributes of the memory resource required for the container.
|
||||
memory?: string
|
||||
|
||||
limit?: {
|
||||
cpu?: string
|
||||
memory?: string
|
||||
}
|
||||
|
||||
volumeMounts?: {
|
||||
// +usage=Mount PVC type volume
|
||||
pvc?: [...{
|
||||
|
||||
@@ -399,3 +399,82 @@ spec:
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
|
||||
|
||||
{{- if and (.Capabilities.APIVersions.Has "monitoring.coreos.com/v1") .Values.core.metrics.enabled }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "kubevela.fullname" . }}-metrics
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
component: vela-core-controller
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
protocol: TCP
|
||||
port: 9443
|
||||
targetPort: 9443
|
||||
- name: metrics
|
||||
protocol: TCP
|
||||
port: 8080
|
||||
targetPort: 8080
|
||||
selector:
|
||||
{{- include "kubevela.selectorLabels" . | nindent 4 }}
|
||||
{{ if .Values.sharding.enabled }}
|
||||
controller.core.oam.dev/shard-id: master
|
||||
{{ end }}
|
||||
{{- end -}}
|
||||
|
||||
{{- if and (.Capabilities.APIVersions.Has "monitoring.coreos.com/v1") .Values.core.metrics.enabled .Values.core.metrics.serviceMonitor.enabled }}
|
||||
---
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: {{ include "kubevela.fullname" . }}-metrics
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- with .Values.core.metrics.serviceMonitor.additionalLabels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
endpoints:
|
||||
- honorLabels: true
|
||||
interval: 10s
|
||||
path: /metrics
|
||||
port: metrics
|
||||
scheme: http
|
||||
namespaceSelector:
|
||||
matchNames:
|
||||
- {{ .Release.Namespace }}
|
||||
selector:
|
||||
matchLabels:
|
||||
component: vela-core-controller
|
||||
{{- end -}}
|
||||
|
||||
{{- if and (.Capabilities.APIVersions.Has "monitoring.coreos.com/v1") .Values.multicluster.metrics.enabled .Values.multicluster.clusterGateway.serviceMonitor.enabled }}
|
||||
---
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: {{ include "kubevela.fullname" . }}-cluster-gateway-metrics
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- with .Values.multicluster.clusterGateway.serviceMonitor.additionalLabels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
endpoints:
|
||||
- honorLabels: true
|
||||
interval: 10s
|
||||
path: /metrics
|
||||
port: default
|
||||
scheme: http
|
||||
namespaceSelector:
|
||||
matchNames:
|
||||
- {{ .Release.Namespace }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "kubevela-cluster-gateway.selectorLabels" . | nindent 4 }}
|
||||
{{- end -}}
|
||||
|
||||
@@ -48,3 +48,15 @@ spec:
|
||||
|
||||
echo "Application and its components are created"
|
||||
restartPolicy: Never
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
|
||||
@@ -158,12 +158,17 @@ featureGates:
|
||||
## @param multicluster.clusterGateway.secureTLS.enabled Whether to enable secure TLS
|
||||
## @param multicluster.clusterGateway.secureTLS.certPath Path to the certificate file
|
||||
## @param multicluster.clusterGateway.secureTLS.certManager.enabled Whether to enable cert-manager
|
||||
## @param multicluster.clusterGateway.serviceMonitor.enabled Whether to enable service monitor
|
||||
## @param multicluster.clusterGateway.serviceMonitor.additionalLabels Additional labels for service monitor
|
||||
multicluster:
|
||||
enabled: true
|
||||
metrics:
|
||||
enabled: false
|
||||
clusterGateway:
|
||||
direct: true
|
||||
serviceMonitor:
|
||||
enabled: false
|
||||
additionalLabels: { }
|
||||
replicaCount: 1
|
||||
port: 9443
|
||||
image:
|
||||
@@ -296,4 +301,14 @@ authentication:
|
||||
## @param sharding.schedulableShards The shards available for scheduling. If empty, dynamic discovery will be used.
|
||||
sharding:
|
||||
enabled: false
|
||||
schedulableShards: ""
|
||||
schedulableShards: ""
|
||||
|
||||
## @param core.metrics.enabled Enable metrics for vela-core
|
||||
## @param core.metrics.serviceMonitor.enabled Enable service monitor for metrics
|
||||
## @param core.metrics.serviceMonitor.additionalLabels Additional labels for service monitor
|
||||
core:
|
||||
metrics:
|
||||
enabled: false
|
||||
serviceMonitor:
|
||||
enabled: false
|
||||
additionalLabels: {}
|
||||
@@ -20,6 +20,8 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/kubevela/pkg/cue/cuex"
|
||||
|
||||
pkgclient "github.com/kubevela/pkg/controller/client"
|
||||
ctrlrec "github.com/kubevela/pkg/controller/reconciler"
|
||||
"github.com/kubevela/pkg/controller/sharding"
|
||||
@@ -35,7 +37,6 @@ import (
|
||||
oamcontroller "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/resourcekeeper"
|
||||
"github.com/oam-dev/kubevela/pkg/workflow/providers"
|
||||
)
|
||||
|
||||
// CoreOptions contains everything necessary to create and run vela-core
|
||||
@@ -129,8 +130,8 @@ func (s *CoreOptions) Flags() cliflag.NamedFlagSets {
|
||||
gfs.BoolVar(&s.EnableClusterGateway, "enable-cluster-gateway", s.EnableClusterGateway, "Enable cluster-gateway to use multicluster, disabled by default.")
|
||||
gfs.BoolVar(&s.EnableClusterMetrics, "enable-cluster-metrics", s.EnableClusterMetrics, "Enable cluster-metrics-management to collect metrics from clusters with cluster-gateway, disabled by default. When this param is enabled, enable-cluster-gateway should be enabled")
|
||||
gfs.DurationVar(&s.ClusterMetricsInterval, "cluster-metrics-interval", s.ClusterMetricsInterval, "The interval that ClusterMetricsMgr will collect metrics from clusters, default value is 15 seconds.")
|
||||
gfs.BoolVar(&providers.EnableExternalPackageForDefaultCompiler, "enable-external-package-for-default-compiler", providers.EnableExternalPackageForDefaultCompiler, "Enable external package for default compiler")
|
||||
gfs.BoolVar(&providers.EnableExternalPackageWatchForDefaultCompiler, "enable-external-package-watch-for-default-compiler", providers.EnableExternalPackageWatchForDefaultCompiler, "Enable external package watch for default compiler")
|
||||
gfs.BoolVar(&cuex.EnableExternalPackageForDefaultCompiler, "enable-external-package-for-default-compiler", cuex.EnableExternalPackageForDefaultCompiler, "Enable external package for default compiler")
|
||||
gfs.BoolVar(&cuex.EnableExternalPackageWatchForDefaultCompiler, "enable-external-package-watch-for-default-compiler", cuex.EnableExternalPackageWatchForDefaultCompiler, "Enable external package watch for default compiler")
|
||||
|
||||
s.ControllerArgs.AddFlags(fss.FlagSet("controllerArgs"), s.ControllerArgs)
|
||||
|
||||
|
||||
@@ -21,7 +21,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/kubevela/pkg/cue/cuex"
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
oamcontroller "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev"
|
||||
)
|
||||
@@ -96,3 +98,26 @@ func TestCoreOptions_Flags(t *testing.T) {
|
||||
t.Errorf("Flags() diff: %v", cmp.Diff(opt, expected, cmp.AllowUnexported(CoreOptions{})))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCuexOptions_Flags(t *testing.T) {
|
||||
pflag.NewFlagSet("test", pflag.ContinueOnError)
|
||||
cuex.EnableExternalPackageForDefaultCompiler = false
|
||||
cuex.EnableExternalPackageWatchForDefaultCompiler = false
|
||||
|
||||
opts := &CoreOptions{
|
||||
ControllerArgs: &oamcontroller.Args{},
|
||||
}
|
||||
fss := opts.Flags()
|
||||
|
||||
args := []string{
|
||||
"--enable-external-package-for-default-compiler=true",
|
||||
"--enable-external-package-watch-for-default-compiler=true",
|
||||
}
|
||||
err := fss.FlagSet("generic").Parse(args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
assert.True(t, cuex.EnableExternalPackageForDefaultCompiler, "The --enable-external-package-for-default-compiler flag should be enabled")
|
||||
assert.True(t, cuex.EnableExternalPackageWatchForDefaultCompiler, "The --enable-external-package-watch-for-default-compiler flag should be enabled")
|
||||
}
|
||||
|
||||
321
design/vela-core/definition-versioning.md
Normal file
321
design/vela-core/definition-versioning.md
Normal file
@@ -0,0 +1,321 @@
|
||||
# Versioning Support for KubeVela Definitions
|
||||
|
||||
<!-- toc -->
|
||||
- [Versioning Support for KubeVela Definitions](#versioning-support-for-kubevela-definitions)
|
||||
- [Summary](#summary)
|
||||
- [Scope](#scope)
|
||||
- [Motivation](#motivation)
|
||||
- [Goals](#goals)
|
||||
- [Non-Goals](#non-goals)
|
||||
- [Acceptance Criteria](#acceptance-criteria)
|
||||
- [Current Implementation](#current-implementation)
|
||||
- [Versioning](#versioning)
|
||||
- [Auto Upgrade](#auto-upgrade)
|
||||
- [Reference:](#reference)
|
||||
- [Proposal](#proposal)
|
||||
- [Details](#details)
|
||||
- [Issues](#issues)
|
||||
- [Examples](#examples)
|
||||
<!-- /toc -->
|
||||
|
||||
## Summary
|
||||
|
||||
Support Semantic versioning for KubeVela Components and a way to allow fine control over auto-upgrades of KubeVela Applications to new versions of a Component. The implementation should include support for consistent versioning across environments/clusters, meaning specific Revisions/Versions of a Component should have consistent behaviour.
|
||||
|
||||
## Scope
|
||||
|
||||
Although, this document limits the scope of discussion to ComponentDefinition Revisions/Versions, due to the current implementation, the changes will most likely apply to all [`Definition`](https://kubevela.io/docs/getting-started/definition/) types. These changes are planned to be explored and validated as part of the implementation.
|
||||
|
||||
## Motivation
|
||||
|
||||
OAM/KubeVela Definitions (referred to as ComponentDefinitions of Components in the rest
|
||||
of the document) are the basic building blocks of the KubeVela platform. They
|
||||
expose a contract similar to an API contract, which evolves from minor to major
|
||||
versions. Applications are composed of Components that the KubeVela engine stitches
|
||||
together.
|
||||
|
||||
KubeVela creates a `DefinitionRevision` for all changes in a Component `spec`.
|
||||
Currently, Applications can refer to a particular Revision of a Component.
|
||||
But, this versioning scheme has the following issues:
|
||||
|
||||
- The `DefinitionRevision` does not denote the type of the change (patch/bug, minor or major). This hinders automation of automatic upgrades.
|
||||
- The current scheme also doesn't allow much control over automatic upgrades to new Component Revisions. KubeVela automatically upgrades/reconciles the Application to the
|
||||
latest when no Component Revision is specified.
|
||||
> While we don't ideally want Application developers to bother with such details, there are use cases where
|
||||
> an automatic upgrade to the latest Component version is not desired.
|
||||
|
||||
|
||||
### Goals
|
||||
|
||||
- Support Component versioning with Semantic Versions.
|
||||
- Allow pinning specific and non-specific versions of a Component in the
|
||||
KubeVela Application.
|
||||
|
||||
### Non-Goals
|
||||
|
||||
- Support for version range in Application. For eg. "type: my-component@>1.2.0"
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
**User Story: Component version specification**
|
||||
|
||||
>**AS A** Component author\
|
||||
>**I SHOULD** be able to publish every version of my Component with the Semantic Versioning scheme\
|
||||
>**SO THAT** an Application developer can use a specific version of the Component.
|
||||
|
||||
**BDD Acceptance Criteria**
|
||||
|
||||
>**GIVEN** an updated ComponentDefinition Specification \
|
||||
>**AND** a version denoted by the ComponentDefinition is set to V\
|
||||
>**WHEN** the Component is applied to KubeVela\
|
||||
>**THEN** `V` should be listed as one of the many versions in the DefinitionRevision list
|
||||
|
||||
**User Story: Application Component version specification**
|
||||
|
||||
>**AS AN** Application developer\
|
||||
>**I SHOULD** be able to specify a version (complete or partial) for every Component used\
|
||||
>**SO THAT** I can control which version are deployed.
|
||||
|
||||
**BDD Acceptance Criteria**
|
||||
|
||||
>Scenario 1: Use the version specified in the Application manifest when deploying the service\
|
||||
>**GIVEN** a Component A with versions 1.2.2 | 1.2.3\
|
||||
>**AND** a Component B with versions 4.4.2 | 4.5.6\
|
||||
>**AND** an Application composed of A 1.2.2 and B 4.4.2\
|
||||
>**WHEN** the Application is deployed\
|
||||
>**THEN** it uses Component A 1.2.2 and B 4.4.2
|
||||
>
|
||||
>**Variant:** Use the latest version for the part of the SemVer that is not specified.\
|
||||
>**GIVEN** component A latest version is 1.2.3
|
||||
>**AND** Component B latest version is 4.5.6
|
||||
>**AND** an Application composed of A 1.2 and B 4\
|
||||
>**WHEN** the Application is deployed\
|
||||
>**THEN** it uses Component A 1.2.3 and B 4.5.6
|
||||
|
||||
> Scenario 2: Behaviour when auto-upgrade is disabled \
|
||||
> **GIVEN** a component A with version 1.2.3\
|
||||
> **AND** an Application composed of A-1.2.3\
|
||||
> **IF** Auto-upgrade is disabled\
|
||||
> **WHEN** a new version of Component A (A-1.2.5) is released\
|
||||
> **THEN** the Application should continue to use A-1.2.3
|
||||
>
|
||||
> **Variant** Behaviour when auto-upgrade is disabled and exact version is unavailable.\
|
||||
> **GIVEN** a component A with version 1.2.3\
|
||||
> **AND** a new Application composed of A-1.2.2\
|
||||
> **IF** Auto-upgrade is disabled\
|
||||
> **WHEN** the Application is applied\
|
||||
> **THEN** the Application deployment should fail.
|
||||
>
|
||||
> **Variant** Behaviour when auto-upgrade is disabled and exact version is unavailable.\
|
||||
> **GIVEN** a component A with version 1.2.3\
|
||||
> **AND** a new Application composed of A-1.2\
|
||||
> **IF** Auto-upgrade is disabled\
|
||||
> **WHEN** the Application is applied\
|
||||
> **THEN** the Application deployment should fail.
|
||||
|
||||
> Scenario 3: Behaviour when auto-upgrade is enabled \
|
||||
> **GIVEN** a component A with version 1.2.3\
|
||||
> **AND** an Application composed of A-1.2\
|
||||
> **IF** Auto-upgrade is enabled\
|
||||
> **THEN** the Application should use A-1.2.3
|
||||
> **AND WHEN** a new version of Component A (A-1.2.5) is released\
|
||||
> **THEN** the Application should update to use A-1.2.5
|
||||
>
|
||||
> **Variant** Behaviour when auto-upgrade is enabled and exact version is unavailable \
|
||||
> **GIVEN** a component A with version 1.2.3\
|
||||
> **AND** a new Application composed of A-1.2.2\
|
||||
> **IF** Auto-upgrade is enabled\
|
||||
> **WHEN** the Application is applied\
|
||||
> **THEN** the Application deployment should fail.
|
||||
>
|
||||
> **Variant** Behaviour when auto-upgrade is enabled and exact version is unavailable \
|
||||
> **GIVEN** a component A with version 1.2.3\
|
||||
> **AND** a new Application composed of A-1.2\
|
||||
> **IF** Auto-upgrade is enabled\
|
||||
> **WHEN** the Application is applied\
|
||||
> **THEN** the Application deployment should use A-1.2.3.
|
||||
|
||||
> Scenario 4: Expectations of consistent versioning across Environments/Clusters. \
|
||||
> **GIVEN** a component A with versions 1.2.1|1.2.2|2.2.1\
|
||||
> **AND** an Application composed of A-1.2.2\
|
||||
> **IF** the Application needs to be deployed across Environments (Dev, Prod etc)\
|
||||
> **OR** the Application needs to be deployed in multiple clusters managed independently\
|
||||
> **WHEN** the Application is deployed across Environments/Clusters \
|
||||
> **THEN** The Application should behave consistently, as in all the clusters A-1.2.2 map to the same ComponentDefinition changes.
|
||||
|
||||
## Current Implementation
|
||||
|
||||
### Versioning
|
||||
|
||||
Currently, KubeVela has some support for controlling Definition versions based on K8s annotations and DefinitionRevisions. The annotation `definitionrevision.oam.dev/name` can be used to version the ComponentDefinition. For example if the following annotation is added to a ComponentDefinition, it produces a new DefinitionRevision and names the ComponentDefinition as `component-name-v4.4` .
|
||||
|
||||
> definitionrevision.oam.dev/name: "4.4"
|
||||
|
||||
This Component can then be referred in the Application as follows:
|
||||
|
||||
>"component-name@v4.4" - `NamedDefinitionRevision`
|
||||
|
||||
Alternatively, since DefinitionRevisions are maintained even if a **"named"** Revision is not specified via the annotation `definitionrevision.oam.dev/name`, Applications can still refer to a particular Revision of a Component via the auto-incrementing Revision numbers.
|
||||
|
||||
>"component-name@v2" - `DefinitionRevision`
|
||||
|
||||

|
||||
|
||||
This versioning scheme, although convenient, has the following issues:
|
||||
|
||||
- Applications which do not explicitly specify a target Revision of a ComponentDefinition, the "latest" applied revision of the ComponentDefinition is used. In scenarios where a cluster has to be replicated or re-created, this means that the sequence in which revisions of a ComponentDefinition are applied becomes important. Implicitly, this also means that the Component maintainers need to keep all Revisions of a ComponentDefinition in their deployment pipeline.\
|
||||
If `definitionrevision.oam.dev/name` annotation is not added to ComponentDefinitions, even if the Applications are explicit about a Component Revision, there is currently no guarantee that the Application behaviour will be consistent across Environments/Clusters. For example, a `Dev` environment will typically have more churn in Revisions than a `Prod` one and a reference to Component Revision `v3` in an Application will not be the same in both environments.
|
||||
|
||||
|
||||
### Auto Upgrade
|
||||
KubeVela utilises the annotation `app.oam.dev/autoUpdate` for automatic upgrade.
|
||||
|
||||
Application reconciliation behaviour when the `app.oam.dev/autoUpdate` annotation is specified in the Application:
|
||||
- If a ComponentDefinition Revision is not specified, the Application will always use the latest available Revision.
|
||||
- If a ComponentDefinition Revision is specified and a new Revision is released after the Application was created, the latest changes will not reflect in the Application.
|
||||
|
||||
Note: This feature is not documented in KubeVela documentation.
|
||||
|
||||
#### Reference:
|
||||
|
||||
- https://kubevela.io/docs/platform-engineers/x-def-version/
|
||||
- [Auto Upgrade PR](https://github.com/kubevela/kubevela/pull/3217)
|
||||
|
||||
|
||||
## Proposal
|
||||
|
||||
### Introduce `spec.version` as an optional field in the Definition
|
||||
|
||||
- Add an optional field `version` in the Definition `spec` and use it to generate the ComponentDefinition Revisions.
|
||||
|
||||
- Update the auto-upgrade behaviour to also allow limiting upgrades for an Application within a specified Definition version range. The existing annotation `app.oam.dev/autoUpdate` for enabling automatic updates will be used for this new behaviour and will maintain backward compatibility.
|
||||
|
||||
- Implement Validating webhook to:
|
||||
- Ensure that the values of the annotation `definitionrevision.oam.dev/version`, `definitionrevision.oam.dev/name` or `spec.version` field adhere to semantic versioning.
|
||||
- Ensure that the `definitionrevision.oam.dev/name` annotation and the `spec.version` field are not present together in the ComponentDefinition to avoid conflicts.
|
||||
- Ensure that `app.oam.dev/publishVersion` and `app.oam.dev/autoUpdate` both annotation are not present in Application to avoid conflicts.
|
||||
|
||||
### Issues
|
||||
|
||||
The following issues assume adherence to strict backward compatibility, meaning the `definitionrevision.oam.dev/name` annotation should continue to work as is.
|
||||
|
||||
- It does not resolve inconsistent versioning behaviour across Environments/Clusters when explicit versions are not specified or named DefinitionRevisions are not used.
|
||||
|
||||
## Examples
|
||||
1. Create a `configmap-component` ComponentDefinition with `1.2.5` version
|
||||
```
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
name: configmap-component
|
||||
namespace: vela-system
|
||||
spec:
|
||||
version: 1.2.5
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata: {
|
||||
name: "comptest"
|
||||
}
|
||||
data: {
|
||||
version: "125"
|
||||
}
|
||||
}
|
||||
|
||||
workload:
|
||||
definition:
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
```
|
||||
|
||||
2. Create a `configmap-component` ComponentDefinition with `2.0.5` version
|
||||
```apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
name: configmap-component
|
||||
namespace: vela-system
|
||||
spec:
|
||||
version: 2.5.0
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata: {
|
||||
name: "comptest"
|
||||
}
|
||||
data: {
|
||||
version: "250"
|
||||
}
|
||||
}
|
||||
|
||||
workload:
|
||||
definition:
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
```
|
||||
3. List DefinitionRevisions
|
||||
```
|
||||
kubectl get definitionrevision -n vela-system | grep -i my-component
|
||||
my-component-v1.2.5 1 1a4f3ac77e4fcfef Component
|
||||
my-component-v2.5.0 2 e61e9b5e55b01c2b Component
|
||||
```
|
||||
|
||||
4. Create Application using `configmap-component@v1.2` version and enable the Auto Update using `app.oam.dev/autoUpdate` annotation.
|
||||
```apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: test-app
|
||||
namespace: test
|
||||
annotations:
|
||||
app.oam.dev/autoUpdate: "true"
|
||||
spec:
|
||||
components:
|
||||
- name: test
|
||||
type: my-component@v1
|
||||
```
|
||||
|
||||
Expected Behavior:
|
||||
- Application will use `configmap-component@v1.2.5`, as `1.2.5` is highest version in specified range(`1`).
|
||||
|
||||
5. Create a `configmap-component` ComponentDefinition with `1.2.7` version
|
||||
```
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
name: configmap-component
|
||||
namespace: vela-system
|
||||
spec:
|
||||
version: 1.2.7
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata: {
|
||||
name: "comptest"
|
||||
}
|
||||
data: {
|
||||
version: "127"
|
||||
}
|
||||
}
|
||||
|
||||
workload:
|
||||
definition:
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
```
|
||||
|
||||
Expected Behavior:
|
||||
- After the Application is reconciled, it will use `configmap-component@v1.2.7`, as `1.2.7` is the latest version within the specified range (1).
|
||||
|
||||
6. List Definitionrevision
|
||||
```kubectl get definitionrevision -n vela-system | grep -i my-component
|
||||
my-component-v1.2.5 1 1a4f3ac77e4fcfef Component
|
||||
my-component-v1.2.7 3 86d7fb1a36566dea Component
|
||||
my-component-v2.5.0 2 e61e9b5e55b01c2b Component```
|
||||
@@ -1,4 +1,10 @@
|
||||
# How to use
|
||||
The Kubevela platform out of the box provides supported and complete `StatefulSet` component and `Storage` trait. This example is just provided for education.
|
||||
|
||||
Please check also the online documentation:
|
||||
* [Trait Definition](https://kubevela.io/docs/platform-engineers/traits/customize-trait/)
|
||||
* [Component Definition](https://kubevela.io/docs/platform-engineers/components/custom-component/)
|
||||
|
||||
# Yet another example defining a custom component and custom trait
|
||||
|
||||
1. define a stateful component with StatefulSet as output
|
||||
|
||||
|
||||
@@ -15,6 +15,6 @@ spec:
|
||||
properties:
|
||||
volumeClaimTemplates:
|
||||
- name: test
|
||||
requests: 10Gi
|
||||
storageClassName: cbs
|
||||
requests: 1Gi
|
||||
storageClassName: local-path
|
||||
mountPath: /usr/share/nginx/html
|
||||
249
e2e/application/application_auto_update_test.go
Normal file
249
e2e/application/application_auto_update_test.go
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
Copyright 2024 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package e2e
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
oamcommon "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/e2e"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
)
|
||||
|
||||
var _ = Describe("Application Auto update", Ordered, func() {
|
||||
ctx := context.Background()
|
||||
var k8sClient client.Client
|
||||
var namespace string
|
||||
var ns corev1.Namespace
|
||||
var err error
|
||||
var velaCommandPrefix string
|
||||
|
||||
BeforeEach(func() {
|
||||
k8sClient, err = common.NewK8sClient()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Create namespace for app-autoupdate-e2e-test")
|
||||
namespace = randomNamespaceName("app-autoupdate-e2e-test")
|
||||
ns = corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}
|
||||
k8sClient.Create(ctx, &ns)
|
||||
velaCommandPrefix = fmt.Sprintf("vela -n %s", namespace)
|
||||
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
By("Clean up resources after a test")
|
||||
k8sClient.DeleteAllOf(ctx, &v1beta1.Application{}, client.InNamespace(namespace))
|
||||
k8sClient.DeleteAllOf(ctx, &v1beta1.ComponentDefinition{}, client.InNamespace(namespace))
|
||||
k8sClient.DeleteAllOf(ctx, &v1beta1.DefinitionRevision{}, client.InNamespace(namespace))
|
||||
Expect(k8sClient.Delete(ctx, &ns)).Should(BeNil())
|
||||
})
|
||||
|
||||
It("dry-run command", func() {
|
||||
By("Create configmap-component with 1.2.0 version")
|
||||
component := configMapComponent.DeepCopy()
|
||||
component.SetNamespace(namespace)
|
||||
Expect(k8sClient.Create(ctx, component)).Should(Succeed())
|
||||
|
||||
By("Execute a dry-run for application having configmap-component@v1 component")
|
||||
output, err := e2e.Exec(fmt.Sprintf("%s dry-run -f data/app.yaml", velaCommandPrefix))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(ContainSubstring(fmt.Sprintf(dryRunResult1, namespace)))
|
||||
|
||||
By("Create application using configmap-component@v1 component")
|
||||
_, err = e2e.Exec(fmt.Sprintf("%s up -f data/app.yaml", velaCommandPrefix))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Create configmap-component with 1.4.0 version")
|
||||
updatedComponent := new(v1beta1.ComponentDefinition)
|
||||
updatedComponentVersion := "1.4.0"
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: "configmap-component", Namespace: namespace}, updatedComponent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatedComponent.Spec.Schematic.CUE.Template = strings.Replace(configMapOutputTemplate, updatedComponent.Spec.Version, updatedComponentVersion, 1)
|
||||
updatedComponent.Spec.Version = updatedComponentVersion
|
||||
return k8sClient.Update(ctx, updatedComponent)
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
|
||||
By("Execute a dry-run for application having configmap-component@v1 component")
|
||||
output, err = e2e.Exec(fmt.Sprintf("%s dry-run -f data/app.yaml", velaCommandPrefix))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(ContainSubstring(fmt.Sprintf(dryRunResult2, namespace, namespace)))
|
||||
})
|
||||
|
||||
It("live-diff between application file and revision", func() {
|
||||
By("Create configmap-component with 1.2.0 version")
|
||||
component := configMapComponent.DeepCopy()
|
||||
component.SetNamespace(namespace)
|
||||
Expect(k8sClient.Create(ctx, component)).Should(Succeed())
|
||||
|
||||
By("Create application using configmap-component@v1 component")
|
||||
_, err = e2e.Exec(fmt.Sprintf("%s up -f data/app.yaml", velaCommandPrefix))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Create configmap-component with 1.4.0 version")
|
||||
updatedComponent := new(v1beta1.ComponentDefinition)
|
||||
updatedComponentVersion := "1.4.0"
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: "configmap-component", Namespace: namespace}, updatedComponent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatedComponent.Spec.Schematic.CUE.Template = strings.Replace(configMapOutputTemplate, updatedComponent.Spec.Version, updatedComponentVersion, 1)
|
||||
updatedComponent.Spec.Version = updatedComponentVersion
|
||||
return k8sClient.Update(ctx, updatedComponent)
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
|
||||
By("Execute a live-diff command for application file and previous application")
|
||||
output, err := e2e.Exec(fmt.Sprintf("%s live-diff -f data/app.yaml -r app-with-auto-update-v1", velaCommandPrefix))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(ContainSubstring(liveDiffResult))
|
||||
})
|
||||
|
||||
It("live-diff between revisions", func() {
|
||||
By("Create configmap-component with 1.2.0 version")
|
||||
component := configMapComponent.DeepCopy()
|
||||
component.SetNamespace(namespace)
|
||||
Expect(k8sClient.Create(ctx, component)).Should(Succeed())
|
||||
|
||||
By("Create application using configmap-component@v1 component")
|
||||
_, err = e2e.Exec(fmt.Sprintf("%s up -f data/app.yaml", velaCommandPrefix))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Create configmap-component with 1.4.0 version")
|
||||
updatedComponent := new(v1beta1.ComponentDefinition)
|
||||
updatedComponentVersion := "1.4.0"
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: "configmap-component", Namespace: namespace}, updatedComponent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatedComponent.Spec.Schematic.CUE.Template = strings.Replace(configMapOutputTemplate, updatedComponent.Spec.Version, updatedComponentVersion, 1)
|
||||
updatedComponent.Spec.Version = updatedComponentVersion
|
||||
return k8sClient.Update(ctx, updatedComponent)
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
|
||||
By("Create application using configmap-component@v1 component")
|
||||
_, err = e2e.Exec(fmt.Sprintf("%s up -f data/app.yaml", velaCommandPrefix))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Execute a live-diff command for previous two application versions")
|
||||
output, err := e2e.Exec(fmt.Sprintf("%s live-diff --revision app-with-auto-update-v2,app-with-auto-update-v1", velaCommandPrefix))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(ContainSubstring("Application (app-with-auto-update) has no change"))
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
var configMapComponent = &v1beta1.ComponentDefinition{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ComponentDefinition",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "configmap-component",
|
||||
},
|
||||
Spec: v1beta1.ComponentDefinitionSpec{
|
||||
Version: "1.2.0",
|
||||
Schematic: &oamcommon.Schematic{
|
||||
CUE: &oamcommon.CUE{
|
||||
Template: configMapOutputTemplate,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var configMapOutputTemplate = `output: {
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata: name: "comptest"
|
||||
data: {
|
||||
expectedVersion: "1.2.0"
|
||||
}
|
||||
}`
|
||||
|
||||
func randomNamespaceName(basic string) string {
|
||||
return fmt.Sprintf("%s-%s", basic, strconv.FormatInt(rand.Int63(), 16))
|
||||
}
|
||||
|
||||
var dryRunResult1 = `---
|
||||
# Application(app-with-auto-update) -- Component(test)
|
||||
---
|
||||
|
||||
apiVersion: v1
|
||||
data:
|
||||
expectedVersion: 1.2.0
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
annotations:
|
||||
app.oam.dev/autoUpdate: "true"
|
||||
labels:
|
||||
app.oam.dev/appRevision: ""
|
||||
app.oam.dev/component: test
|
||||
app.oam.dev/name: app-with-auto-update
|
||||
app.oam.dev/namespace: %[1]s
|
||||
app.oam.dev/resourceType: WORKLOAD
|
||||
workload.oam.dev/type: configmap-component-v1
|
||||
name: comptest
|
||||
namespace: %[1]s
|
||||
|
||||
---`
|
||||
|
||||
var dryRunResult2 = `---
|
||||
# Application(app-with-auto-update) -- Component(test)
|
||||
---
|
||||
|
||||
apiVersion: v1
|
||||
data:
|
||||
expectedVersion: 1.4.0
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
annotations:
|
||||
app.oam.dev/autoUpdate: "true"
|
||||
labels:
|
||||
app.oam.dev/appRevision: ""
|
||||
app.oam.dev/component: test
|
||||
app.oam.dev/name: app-with-auto-update
|
||||
app.oam.dev/namespace: %[1]s
|
||||
app.oam.dev/resourceType: WORKLOAD
|
||||
workload.oam.dev/type: configmap-component-v1
|
||||
name: comptest
|
||||
namespace: %[1]s
|
||||
|
||||
---
|
||||
|
||||
|
||||
`
|
||||
|
||||
var liveDiffResult = `
|
||||
- expectedVersion: 1.2.0
|
||||
+ expectedVersion: 1.4.0
|
||||
`
|
||||
@@ -128,6 +128,15 @@ var ApplicationExecContext = func(context string, appName string) bool {
|
||||
|
||||
var ApplicationPortForwardContext = func(context string, appName string) bool {
|
||||
return ginkgo.It(context+": should get output of port-forward successfully", func() {
|
||||
ginkgo.By(fmt.Sprintf("waiting for the application [%s] to reach the desired status", appName))
|
||||
gomega.Eventually(func() string {
|
||||
cli := fmt.Sprintf("vela status %s", appName)
|
||||
output, err := e2e.Exec(cli)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
return output
|
||||
}, 90*time.Second, 1*time.Second).Should(gomega.ContainSubstring("running"))
|
||||
|
||||
ginkgo.By("executing port-forward")
|
||||
cli := fmt.Sprintf("vela port-forward %s 8080:80 ", appName)
|
||||
output, err := e2e.ExecAndTerminate(cli)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
@@ -184,8 +193,10 @@ var ApplicationInitIntercativeCliContext = func(context string, appName string,
|
||||
})
|
||||
}
|
||||
|
||||
// debug test
|
||||
var ApplicationDeleteWithWaitOptions = func(context string, appName string) bool {
|
||||
return ginkgo.It(context+": should print successful deletion information", func() {
|
||||
return ginkgo.It(context+": should print successful deletion information ", func() {
|
||||
time.Sleep(1 * time.Minute)
|
||||
cli := fmt.Sprintf("vela delete %s --wait -y", appName)
|
||||
output, err := e2e.LongTimeExec(cli, 10*time.Second)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
|
||||
10
e2e/application/data/app.yaml
Normal file
10
e2e/application/data/app.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: app-with-auto-update
|
||||
annotations:
|
||||
app.oam.dev/autoUpdate: "true"
|
||||
spec:
|
||||
components:
|
||||
- name: test
|
||||
type: configmap-component@v1
|
||||
@@ -56,7 +56,7 @@ func ExecAndTerminate(cli string) (string, error) {
|
||||
if err != nil {
|
||||
return string(output), err
|
||||
}
|
||||
time.Sleep(3 * time.Second)
|
||||
time.Sleep(10 * time.Second)
|
||||
s := session.Terminate()
|
||||
return string(s.Out.Contents()) + string(s.Err.Contents()), nil
|
||||
}
|
||||
|
||||
@@ -462,24 +462,26 @@ spec:
|
||||
- backend
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
kube:
|
||||
template:
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: my-service
|
||||
spec:
|
||||
ports:
|
||||
- protocol: TCP
|
||||
cue:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
metadata: {
|
||||
name: "my-service"
|
||||
}
|
||||
spec:{
|
||||
ports: [{
|
||||
protocol: "TCP"
|
||||
port: 80
|
||||
targetPort: 9376
|
||||
parameters:
|
||||
- name: targetPort
|
||||
required: true
|
||||
type: number
|
||||
fieldPaths:
|
||||
- "spec.template.spec.ports[0].targetPort"
|
||||
description: "target port num for service provider."
|
||||
targetPort: parameters.targetPort
|
||||
}]
|
||||
}
|
||||
parameters:{
|
||||
//+usage=target port num for service provider
|
||||
targetPort: *9376 | int
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
var componentWithDeepCue = `
|
||||
|
||||
82
go.mod
82
go.mod
@@ -1,11 +1,12 @@
|
||||
module github.com/oam-dev/kubevela
|
||||
|
||||
go 1.22.0
|
||||
go 1.23.8
|
||||
|
||||
require (
|
||||
cuelang.org/go v0.9.2
|
||||
github.com/AlecAivazis/survey/v2 v2.1.1
|
||||
github.com/FogDong/uitable v0.0.5
|
||||
github.com/Masterminds/semver v1.5.0
|
||||
github.com/Masterminds/semver/v3 v3.2.1
|
||||
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8
|
||||
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b
|
||||
@@ -20,15 +21,15 @@ require (
|
||||
github.com/ettle/strcase v0.2.0
|
||||
github.com/fatih/color v1.16.0
|
||||
github.com/fluxcd/helm-controller/api v0.32.2
|
||||
github.com/fluxcd/source-controller/api v0.24.4
|
||||
github.com/fluxcd/source-controller/api v0.30.0
|
||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible
|
||||
github.com/gdamore/tcell/v2 v2.6.0
|
||||
github.com/getkin/kin-openapi v0.118.0
|
||||
github.com/go-git/go-git/v5 v5.8.1
|
||||
github.com/go-logr/logr v1.4.1
|
||||
github.com/go-git/go-git/v5 v5.16.0
|
||||
github.com/go-logr/logr v1.4.2
|
||||
github.com/go-resty/resty/v2 v2.8.0
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/google/go-cmp v0.6.0
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/google/go-containerregistry v0.18.0
|
||||
github.com/google/go-github/v32 v32.1.0
|
||||
github.com/gosuri/uitable v0.0.4
|
||||
@@ -36,8 +37,9 @@ require (
|
||||
github.com/hashicorp/hcl/v2 v2.18.0
|
||||
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174
|
||||
github.com/imdario/mergo v0.3.16
|
||||
github.com/jeremywohl/flatten/v2 v2.0.0-20211013061545-07e4a09fb8e4
|
||||
github.com/kubevela/pkg v1.9.3-0.20241203070234-2cf98778c0a9
|
||||
github.com/kubevela/workflow v0.6.1-0.20241210074645-d8a85b26c862
|
||||
github.com/kubevela/workflow v0.6.2
|
||||
github.com/kyokomi/emoji v2.2.4+incompatible
|
||||
github.com/magiconair/properties v1.8.7
|
||||
github.com/mattn/go-runewidth v0.0.15
|
||||
@@ -48,8 +50,8 @@ require (
|
||||
github.com/oam-dev/terraform-config-inspect v0.0.0-20210418082552-fc72d929aa28
|
||||
github.com/oam-dev/terraform-controller v0.8.0
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/onsi/ginkgo/v2 v2.14.0
|
||||
github.com/onsi/gomega v1.30.0
|
||||
github.com/onsi/ginkgo/v2 v2.19.0
|
||||
github.com/onsi/gomega v1.34.1
|
||||
github.com/openkruise/kruise-api v1.4.0
|
||||
github.com/openkruise/rollouts v0.3.0
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
@@ -60,19 +62,19 @@ require (
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/tidwall/gjson v1.14.4
|
||||
github.com/wercker/stern v0.0.0-20190705090245-4fa46dd6987f
|
||||
github.com/xanzy/go-gitlab v0.91.1
|
||||
github.com/xlab/treeprint v1.2.0
|
||||
gitlab.com/gitlab-org/api/client-go v0.127.0
|
||||
go.uber.org/multierr v1.11.0
|
||||
golang.org/x/crypto v0.25.0
|
||||
golang.org/x/mod v0.17.0
|
||||
golang.org/x/oauth2 v0.20.0
|
||||
golang.org/x/sync v0.7.0
|
||||
golang.org/x/term v0.22.0
|
||||
golang.org/x/text v0.16.0
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d
|
||||
golang.org/x/crypto v0.37.0
|
||||
golang.org/x/mod v0.21.0
|
||||
golang.org/x/oauth2 v0.29.0
|
||||
golang.org/x/sync v0.13.0
|
||||
golang.org/x/term v0.31.0
|
||||
golang.org/x/text v0.24.0
|
||||
golang.org/x/tools v0.26.0
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
helm.sh/helm/v3 v3.14.4
|
||||
@@ -105,15 +107,13 @@ require (
|
||||
github.com/BurntSushi/toml v1.3.2 // indirect
|
||||
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||
github.com/Masterminds/squirrel v1.5.4 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/Microsoft/hcsshim v0.12.2 // indirect
|
||||
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 // indirect
|
||||
github.com/acomagu/bufpipe v1.0.4 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.6 // indirect
|
||||
github.com/agext/levenshtein v1.2.3 // indirect
|
||||
github.com/alessio/shellescape v1.4.1 // indirect
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704 // indirect
|
||||
@@ -127,9 +127,9 @@ require (
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||
github.com/cloudflare/circl v1.3.7 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/cockroachdb/apd/v3 v3.2.1 // indirect
|
||||
github.com/containerd/containerd v1.7.24 // indirect
|
||||
github.com/containerd/containerd v1.7.27 // indirect
|
||||
github.com/containerd/errdefs v0.3.0 // indirect
|
||||
github.com/containerd/platforms v0.2.1 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect
|
||||
@@ -137,15 +137,14 @@ require (
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
||||
github.com/creack/pty v1.1.18 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/docker/cli v26.0.0+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker v26.0.0+incompatible // indirect
|
||||
github.com/docker/docker v28.0.4+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.8.1 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-metrics v0.0.1 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.0 // indirect
|
||||
github.com/emicklei/proto v1.10.0 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
@@ -154,7 +153,7 @@ require (
|
||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
|
||||
github.com/fatih/camelcase v1.0.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fluxcd/pkg/apis/acl v0.0.3 // indirect
|
||||
github.com/fluxcd/pkg/apis/acl v0.1.0 // indirect
|
||||
github.com/fluxcd/pkg/apis/kustomize v1.0.0 // indirect
|
||||
github.com/fluxcd/pkg/apis/meta v1.0.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
@@ -163,7 +162,7 @@ require (
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-errors/errors v1.5.1 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.4.1 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-logr/zapr v1.3.0 // indirect
|
||||
@@ -171,18 +170,18 @@ require (
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-stack/stack v1.8.1 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/gobuffalo/flect v1.0.2 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/cel-go v0.17.7 // indirect
|
||||
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20240117000934-35fc243c5815 // indirect
|
||||
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect
|
||||
github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
@@ -194,7 +193,7 @@ require (
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/huandu/xstrings v1.4.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
@@ -230,7 +229,6 @@ require (
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
@@ -238,19 +236,19 @@ require (
|
||||
github.com/openshift/library-go v0.0.0-20230327085348-8477ec72b725 // indirect
|
||||
github.com/perimeterx/marshmallow v1.1.4 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/common v0.45.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/protocolbuffers/txtpbfmt v0.0.0-20230328191034-3462fbc510c0 // indirect
|
||||
github.com/rivo/uniseg v0.4.3 // indirect
|
||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
github.com/rubenv/sql-migrate v1.5.2 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sergi/go-diff v1.1.0 // indirect
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
github.com/skeema/knownhosts v1.2.0 // indirect
|
||||
github.com/skeema/knownhosts v1.3.1 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/stoewer/go-strcase v1.2.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
@@ -276,15 +274,15 @@ require (
|
||||
go.starlark.net v0.0.0-20240329153429-e6e8e7ce1b7a // indirect
|
||||
go.uber.org/automaxprocs v1.5.3 // indirect
|
||||
go.uber.org/zap v1.26.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/net v0.39.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/time v0.10.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect
|
||||
google.golang.org/grpc v1.63.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
google.golang.org/protobuf v1.35.2 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/evanphx/json-patch.v5 v5.9.0 // indirect
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
|
||||
@@ -309,7 +307,7 @@ require (
|
||||
replace (
|
||||
cloud.google.com/go => cloud.google.com/go v0.100.2
|
||||
github.com/docker/cli => github.com/docker/cli v24.0.9+incompatible
|
||||
github.com/docker/docker => github.com/docker/docker v24.0.9+incompatible
|
||||
github.com/docker/docker => github.com/docker/docker v25.0.6+incompatible
|
||||
github.com/docker/docker-credential-helpers => github.com/docker/docker-credential-helpers v0.7.0
|
||||
github.com/wercker/stern => github.com/oam-dev/stern v1.13.2
|
||||
k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00
|
||||
|
||||
180
go.sum
180
go.sum
@@ -63,14 +63,12 @@ github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMo
|
||||
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw=
|
||||
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 h1:KLq8BE0KwCL+mmXnjLWEAOYO+2l2AE4YMmqG1ZpZHBs=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
|
||||
github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs=
|
||||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
|
||||
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
|
||||
github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
|
||||
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
||||
github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
||||
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
|
||||
@@ -136,7 +134,6 @@ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembj
|
||||
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
|
||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o=
|
||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||
github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||
@@ -157,9 +154,8 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
||||
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
@@ -178,10 +174,10 @@ github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u9
|
||||
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
|
||||
github.com/containerd/cgroups/v3 v3.0.2 h1:f5WFqIVSgo5IZmtTT3qVBo6TzI1ON6sycSBKkymb9L0=
|
||||
github.com/containerd/cgroups/v3 v3.0.2/go.mod h1:JUgITrzdFqp42uI2ryGA+ge0ap/nxzYgkGmIcetmErE=
|
||||
github.com/containerd/containerd v1.7.24 h1:zxszGrGjrra1yYJW/6rhm9cJ1ZQ8rkKBR48brqsa7nA=
|
||||
github.com/containerd/containerd v1.7.24/go.mod h1:7QUzfURqZWCZV7RLNEn1XjUCQLEf0bkaK4GjUaZehxw=
|
||||
github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM=
|
||||
github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
|
||||
github.com/containerd/containerd v1.7.27 h1:yFyEyojddO3MIGVER2xJLWoCIn+Up4GaHFquP7hsFII=
|
||||
github.com/containerd/containerd v1.7.27/go.mod h1:xZmPnl75Vc+BLGt4MIfu6bp+fy03gdHAn9bz+FreFR0=
|
||||
github.com/containerd/continuity v0.4.4 h1:/fNVfTJ7wIl/YPMHjf+5H32uFhl63JucB34PlCpMKII=
|
||||
github.com/containerd/continuity v0.4.4/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=
|
||||
github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4=
|
||||
github.com/containerd/errdefs v0.3.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
@@ -215,8 +211,8 @@ github.com/crossplane/crossplane-runtime v1.16.0 h1:lz+l0wEB3qowdTmN7t0PZkfuNSvf
|
||||
github.com/crossplane/crossplane-runtime v1.16.0/go.mod h1:Pz2tdGVMF6KDGzHZOkvKro0nKc8EzK0sb/nSA7pH4Dc=
|
||||
github.com/cue-exp/kubevelafix v0.0.0-20220922150317-aead819d979d h1:VNJA1nSKA8Xna5wjUIMItHlWmEej8Bb9fZ3vCNtIAX0=
|
||||
github.com/cue-exp/kubevelafix v0.0.0-20220922150317-aead819d979d/go.mod h1:SyTryzw/zYJIogw3H2IRcYdV5gsSoVMJiKGElcQK09I=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
|
||||
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||
github.com/dave/jennifer v1.6.1 h1:T4T/67t6RAA5AIV6+NP8Uk/BIsXgDoqEowgycdQQLuk=
|
||||
github.com/dave/jennifer v1.6.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -232,8 +228,8 @@ github.com/docker/cli v24.0.9+incompatible h1:OxbimnP/z+qVjDLpq9wbeFU3Nc30XhSe+L
|
||||
github.com/docker/cli v24.0.9+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0=
|
||||
github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v25.0.6+incompatible h1:5cPwbwriIcsua2REJe8HqQV+6WlWc1byg2QSXzBxBGg=
|
||||
github.com/docker/docker v25.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
|
||||
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
@@ -242,8 +238,6 @@ github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ
|
||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
|
||||
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
|
||||
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
@@ -251,8 +245,8 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 h1:RIB4cRk+lBqKK3Oy0r2gRX4ui7tuhiZq2SuTtTCi0/0=
|
||||
github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
|
||||
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
|
||||
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
@@ -297,14 +291,14 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fluxcd/helm-controller/api v0.32.2 h1:ETkZmMEHY/qu6a9AjP6en35WrpN7NnVmhOe7IvOB7jE=
|
||||
github.com/fluxcd/helm-controller/api v0.32.2/go.mod h1:xzQgNoaPOg77zFUqvnaX0Fn3lPA3iGDLoz8q4wiEyLA=
|
||||
github.com/fluxcd/pkg/apis/acl v0.0.3 h1:Lw0ZHdpnO4G7Zy9KjrzwwBmDZQuy4qEjaU/RvA6k1lc=
|
||||
github.com/fluxcd/pkg/apis/acl v0.0.3/go.mod h1:XPts6lRJ9C9fIF9xVWofmQwftvhY25n1ps7W9xw0XLU=
|
||||
github.com/fluxcd/pkg/apis/acl v0.1.0 h1:EoAl377hDQYL3WqanWCdifauXqXbMyFuK82NnX6pH4Q=
|
||||
github.com/fluxcd/pkg/apis/acl v0.1.0/go.mod h1:zfEZzz169Oap034EsDhmCAGgnWlcWmIObZjYMusoXS8=
|
||||
github.com/fluxcd/pkg/apis/kustomize v1.0.0 h1:5T2b/mRZiGWtP7fvSU8gZOApIc06H6SdLX3MlsE6LRo=
|
||||
github.com/fluxcd/pkg/apis/kustomize v1.0.0/go.mod h1:XaDYlKxrf9D2zZWcZ0BnSIqGtcm8mdNtJGzZWYjCnQo=
|
||||
github.com/fluxcd/pkg/apis/meta v1.0.0 h1:i9IGHd/VNEZELX7mepkiYFbJxs2J5znaB4cN9z2nPm8=
|
||||
github.com/fluxcd/pkg/apis/meta v1.0.0/go.mod h1:04ZdpZYm1x+aL93K4daNHW1UX6E8K7Gyf5za9OhrE+U=
|
||||
github.com/fluxcd/source-controller/api v0.24.4 h1:m54sS1rJlgJf5j9qDRgKLhbPJAnJ9dY+VrstPKj0aQo=
|
||||
github.com/fluxcd/source-controller/api v0.24.4/go.mod h1:b0MmMPGE8gcpgSyGXe5m7see77tBW26eZrvGkkPstUs=
|
||||
github.com/fluxcd/source-controller/api v0.30.0 h1:rPVPpwXcYG2n0DTRcRagfGDiccvCib5S09K5iMjlpRU=
|
||||
github.com/fluxcd/source-controller/api v0.30.0/go.mod h1:UkjAqQ6QAXNNesNQDTArTeiTp+UuhOUIA+JyFhGP/+Q=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible h1:/l4kBbb4/vGSsdtB5nUe8L7B9mImVMaBPw9L/0TBHU8=
|
||||
@@ -330,18 +324,18 @@ github.com/getkin/kin-openapi v0.118.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BH
|
||||
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
|
||||
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
|
||||
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
||||
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
||||
github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
|
||||
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||
github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4=
|
||||
github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo=
|
||||
github.com/go-git/go-git/v5 v5.8.1 h1:Zo79E4p7TRk0xoRgMq0RShiTHGKcKI4+DI6BfJc/Q+A=
|
||||
github.com/go-git/go-git/v5 v5.8.1/go.mod h1:FHFuoD6yGz5OSKEBK+aWN9Oah0q54Jxl0abmj6GnqAo=
|
||||
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
|
||||
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.16.0 h1:k3kuOEpkc0DeY7xlL6NaaNg39xdgQbtH5mwCafHO9AQ=
|
||||
github.com/go-git/go-git/v5 v5.16.0/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=
|
||||
github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
|
||||
@@ -359,8 +353,8 @@ github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTg
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro=
|
||||
@@ -393,8 +387,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
|
||||
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
|
||||
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
|
||||
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
@@ -423,8 +417,9 @@ github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68=
|
||||
github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
@@ -476,8 +471,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/go-containerregistry v0.18.0 h1:ShE7erKNPqRh5ue6Z9DUOlk04WsnFWPO6YGr3OxnfoQ=
|
||||
github.com/google/go-containerregistry v0.18.0/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ=
|
||||
github.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II=
|
||||
@@ -491,8 +486,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20240117000934-35fc243c5815 h1:WzfWbQz/Ze8v6l++GGbGNFZnUShVpP/0xffCPLL+ax8=
|
||||
github.com/google/pprof v0.0.0-20240117000934-35fc243c5815/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
|
||||
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
|
||||
github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI=
|
||||
github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
@@ -539,15 +534,15 @@ github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
|
||||
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
|
||||
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
@@ -593,6 +588,8 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jellydator/ttlcache/v3 v3.0.1 h1:cHgCSMS7TdQcoprXnWUptJZzyFsqs18Lt8VVhRuZYVU=
|
||||
github.com/jellydator/ttlcache/v3 v3.0.1/go.mod h1:WwTaEmcXQ3MTjOm4bsZoDFiCu/hMvNWLO1w67RXz6h4=
|
||||
github.com/jeremywohl/flatten/v2 v2.0.0-20211013061545-07e4a09fb8e4 h1:eA9wi6ZzpIRobvXkn/S2Lyw1hr2pc71zxzOPl7Xjs4w=
|
||||
github.com/jeremywohl/flatten/v2 v2.0.0-20211013061545-07e4a09fb8e4/go.mod h1:s9g9Dfls+aEgucKXKW+i8MRZuLXT2MrD/WjYpMnWfOw=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
@@ -650,8 +647,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kubevela/pkg v1.9.3-0.20241203070234-2cf98778c0a9 h1:VgW3WgcQ5jZcWUvKULfnV7w8vfp86yGp6Es4NFJpiCg=
|
||||
github.com/kubevela/pkg v1.9.3-0.20241203070234-2cf98778c0a9/go.mod h1:mb14wKSzUVKsSupXEjnci2vCd8DTkN4mBYdz9wvS7Vk=
|
||||
github.com/kubevela/workflow v0.6.1-0.20241210074645-d8a85b26c862 h1:EaXO5m/4ewOBa1CAHqFt9RqN/+oh566YKKpQJ6a1MBU=
|
||||
github.com/kubevela/workflow v0.6.1-0.20241210074645-d8a85b26c862/go.mod h1:nJIoAw1SHthfLhJqFFKX2dwwoDy6vF2DZrBdlAJNSXU=
|
||||
github.com/kubevela/workflow v0.6.2 h1:zmsjQStemSSAJVACsf9c39WTIJqdn1YQlb5jltOfSwU=
|
||||
github.com/kubevela/workflow v0.6.2/go.mod h1:nJIoAw1SHthfLhJqFFKX2dwwoDy6vF2DZrBdlAJNSXU=
|
||||
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
@@ -683,8 +680,6 @@ github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY
|
||||
github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI=
|
||||
github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI=
|
||||
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
|
||||
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
|
||||
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
@@ -761,8 +756,6 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
@@ -803,8 +796,8 @@ github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8Ay
|
||||
github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo=
|
||||
github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw=
|
||||
github.com/onsi/ginkgo/v2 v2.6.0/go.mod h1:63DOGlLAH8+REH8jUGdL3YpCpu7JODesutUjdENfUAc=
|
||||
github.com/onsi/ginkgo/v2 v2.14.0 h1:vSmGj2Z5YPb9JwCWT6z6ihcUvDhuXLc3sJiqd3jMKAY=
|
||||
github.com/onsi/ginkgo/v2 v2.14.0/go.mod h1:JkUdW7JkN0V6rFvsHcJ478egV3XH9NxpD27Hal/PhZw=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
@@ -815,8 +808,8 @@ github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ
|
||||
github.com/onsi/gomega v1.23.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
|
||||
github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
|
||||
github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM=
|
||||
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
|
||||
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
|
||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||
@@ -841,8 +834,8 @@ github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+v
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
|
||||
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
||||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
||||
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
||||
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
|
||||
github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
@@ -909,8 +902,8 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/rubenv/sql-migrate v1.5.2 h1:bMDqOnrJVV/6JQgQ/MxOpU+AdO8uzYYA/TxFUBzFtS0=
|
||||
github.com/rubenv/sql-migrate v1.5.2/go.mod h1:H38GW8Vqf8F0Su5XignRyaRcbXbJunSWxs+kmzlg0Is=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
@@ -919,8 +912,8 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
@@ -932,8 +925,8 @@ github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM=
|
||||
github.com/skeema/knownhosts v1.2.0/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo=
|
||||
github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
|
||||
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
@@ -980,8 +973,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
|
||||
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
@@ -1000,8 +993,6 @@ github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95
|
||||
github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts=
|
||||
github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk=
|
||||
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||
github.com/xanzy/go-gitlab v0.91.1 h1:gnV57IPGYywWer32oXKBcdmc8dVxeKl3AauV8Bu17rw=
|
||||
github.com/xanzy/go-gitlab v0.91.1/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw=
|
||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
@@ -1030,6 +1021,8 @@ github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go
|
||||
github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
|
||||
github.com/zclconf/go-cty v1.13.0 h1:It5dfKTTZHe9aeppbNOda3mN7Ag7sg6QkBNm6TkyFa0=
|
||||
github.com/zclconf/go-cty v1.13.0/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0=
|
||||
gitlab.com/gitlab-org/api/client-go v0.127.0 h1:8xnxcNKGF2gDazEoMs+hOZfOspSSw8D0vAoWhQk9U+U=
|
||||
gitlab.com/gitlab-org/api/client-go v0.127.0/go.mod h1:bYC6fPORKSmtuPRyD9Z2rtbAjE7UeNatu2VWHRf4/LE=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||
go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0=
|
||||
@@ -1159,16 +1152,14 @@ golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
||||
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o=
|
||||
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -1189,8 +1180,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91
|
||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -1238,11 +1229,10 @@ golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -1254,8 +1244,8 @@ golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo=
|
||||
golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
|
||||
golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -1268,8 +1258,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1341,8 +1331,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
@@ -1352,11 +1342,10 @@ golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
|
||||
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
|
||||
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
|
||||
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -1366,18 +1355,17 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
|
||||
golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -1408,8 +1396,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
||||
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1501,8 +1489,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
|
||||
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
|
||||
@@ -18,7 +18,6 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
@@ -69,23 +68,23 @@ func GenMarkdownTreeForIndex(cmd *cobra.Command, dir string) error {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if _, err = io.WriteString(f, "---\ntitle: CLI Commands\n---\n\n\n"); err != nil {
|
||||
if _, err = f.WriteString("---\ntitle: CLI Commands\n---\n\n\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, tp := range []string{types.TypeStart, types.TypeApp, types.TypeCD, types.TypeExtension, types.TypeSystem} {
|
||||
// write header of type
|
||||
_, err = io.WriteString(f, "## "+tp+"\n\n")
|
||||
_, err = f.WriteString("## " + tp + "\n\n")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
str := PrintCLIByTag(cmd, cmd.Commands(), tp)
|
||||
// write header of type
|
||||
_, err = io.WriteString(f, str)
|
||||
_, err = f.WriteString(str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = io.WriteString(f, "###### Auto generated by [script in KubeVela](https://github.com/kubevela/kubevela/tree/master/hack/docgen).")
|
||||
_, err = f.WriteString("###### Auto generated by [script in KubeVela](https://github.com/kubevela/kubevela/tree/master/hack/docgen).")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
LOCALBIN ?= $(shell pwd)/bin
|
||||
$(LOCALBIN):
|
||||
mkdir -p $(LOCALBIN)
|
||||
GOLANGCILINT_VERSION ?= 1.54.2
|
||||
GOLANGCILINT_VERSION ?= 1.60.1
|
||||
GLOBAL_GOLANGCILINT := $(shell which golangci-lint)
|
||||
GOBIN_GOLANGCILINT:= $(shell which $(GOBIN)/golangci-lint)
|
||||
ENVTEST_K8S_VERSION = 1.29.0
|
||||
@@ -31,7 +31,7 @@ ifeq (, $(shell which staticcheck))
|
||||
@{ \
|
||||
set -e ;\
|
||||
echo 'installing honnef.co/go/tools/cmd/staticcheck ' ;\
|
||||
go install honnef.co/go/tools/cmd/staticcheck@v0.4.7 ;\
|
||||
go install honnef.co/go/tools/cmd/staticcheck@v0.5.1 ;\
|
||||
}
|
||||
STATICCHECK=$(GOBIN)/staticcheck
|
||||
else
|
||||
|
||||
@@ -24,13 +24,15 @@ e2e-setup-core-wo-auth:
|
||||
--namespace vela-system \
|
||||
--set image.pullPolicy=IfNotPresent \
|
||||
--set image.repository=vela-core-test \
|
||||
--set applicationRevisionLimit=5 \
|
||||
--set applicationRevisionLimit=5 \
|
||||
--set controllerArgs.reSyncPeriod=1m \
|
||||
--set optimize.disableComponentRevision=false \
|
||||
--set image.tag=$(GIT_COMMIT) \
|
||||
--set multicluster.clusterGateway.image.repository=ghcr.io/oam-dev/cluster-gateway \
|
||||
--set admissionWebhooks.patch.image.repository=ghcr.io/oam-dev/kube-webhook-certgen/kube-webhook-certgen \
|
||||
--set multicluster.clusterGateway.image.repository=ghcr.io/oam-dev/cluster-gateway \
|
||||
--set admissionWebhooks.patch.image.repository=ghcr.io/oam-dev/kube-webhook-certgen/kube-webhook-certgen \
|
||||
--set featureGates.enableCueValidation=true \
|
||||
--wait kubevela ./charts/vela-core \
|
||||
--debug
|
||||
--debug
|
||||
|
||||
.PHONY: e2e-setup-core-w-auth
|
||||
e2e-setup-core-w-auth:
|
||||
@@ -109,4 +111,4 @@ end-e2e-core-shards: end-e2e-core
|
||||
|
||||
.PHONY: end-e2e
|
||||
end-e2e:
|
||||
sh ./hack/e2e/end_e2e.sh
|
||||
sh ./hack/e2e/end_e2e.sh
|
||||
|
||||
@@ -38,7 +38,7 @@ import (
|
||||
"github.com/google/go-github/v32/github"
|
||||
"github.com/imdario/mergo"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/xanzy/go-gitlab"
|
||||
gitlab "gitlab.com/gitlab-org/api/client-go"
|
||||
"go.uber.org/multierr"
|
||||
"golang.org/x/oauth2"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
@@ -1368,7 +1368,7 @@ func getDependencyArgs(ctx context.Context, k8sClient client.Client, depName str
|
||||
_, depErr := FetchAddonRelatedApp(ctx, k8sClient, depName)
|
||||
if depErr != nil {
|
||||
if !apierrors.IsNotFound(depErr) {
|
||||
return nil, err
|
||||
return nil, depErr
|
||||
}
|
||||
depArgs := map[string]interface{}{}
|
||||
if addonClusters != nil {
|
||||
@@ -1626,8 +1626,8 @@ func (h *Installer) renderNotes(addon *InstallPackage) (string, error) {
|
||||
}
|
||||
notesFile := contextFile + "\n" + addon.Notes.Data
|
||||
val := cuecontext.New().CompileString(notesFile)
|
||||
if val.Err() != nil {
|
||||
return "", errors.Wrap(err, "build values for NOTES.cue")
|
||||
if valErr := val.Err(); valErr != nil {
|
||||
return "", errors.Wrap(valErr, "build values for NOTES.cue")
|
||||
}
|
||||
notes := val.LookupPath(cue.ParsePath(KeyWordNotes))
|
||||
if !notes.Exists() {
|
||||
|
||||
@@ -378,7 +378,8 @@ func TestGetAddonStatus(t *testing.T) {
|
||||
})
|
||||
|
||||
cli := test.MockClient{
|
||||
MockGet: getFunc,
|
||||
MockGet: getFunc,
|
||||
MockList: listFunc,
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
@@ -410,6 +411,10 @@ func TestGetAddonStatus(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func listFunc(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestGetAddonVersionMeetSystemRequirement(t *testing.T) {
|
||||
server := httptest.NewServer(helmHandler)
|
||||
defer server.Close()
|
||||
|
||||
@@ -123,6 +123,14 @@ func EnableAddonByLocalDir(ctx context.Context, name string, dir string, cli cli
|
||||
// GetAddonStatus is general func for cli and apiServer get addon status
|
||||
func GetAddonStatus(ctx context.Context, cli client.Client, name string) (Status, error) {
|
||||
var addonStatus Status
|
||||
joinedClusters, err := multicluster.NewClusterClient(cli).List(ctx)
|
||||
if err != nil {
|
||||
return addonStatus, errors.Wrap(err, "failed to list registered clusters")
|
||||
}
|
||||
var joinedClusterMap = make(map[string]bool)
|
||||
for _, joinedCluster := range joinedClusters.Items {
|
||||
joinedClusterMap[joinedCluster.Name] = true
|
||||
}
|
||||
|
||||
app, err := FetchAddonRelatedApp(ctx, cli, name)
|
||||
if err != nil {
|
||||
@@ -143,8 +151,12 @@ func GetAddonStatus(ctx context.Context, cli client.Client, name string) (Status
|
||||
r.Cluster = multicluster.ClusterLocalName
|
||||
}
|
||||
// TODO(wonderflow): we should collect all the necessary information as observability, currently we only collect cluster name
|
||||
clusters[r.Cluster] = make(map[string]interface{})
|
||||
// If cluster is not registered in KubeVela then skip it.
|
||||
if joinedClusterMap[r.Cluster] {
|
||||
clusters[r.Cluster] = make(map[string]interface{})
|
||||
}
|
||||
}
|
||||
|
||||
addonStatus.Clusters = clusters
|
||||
|
||||
if app.Status.Workflow != nil && app.Status.Workflow.Suspend {
|
||||
|
||||
@@ -158,7 +158,7 @@ func (p *PushCmd) Push(ctx context.Context) error {
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(os.Stderr, "Pushing %s to %s... ",
|
||||
color.New(color.Bold).Sprintf(filepath.Base(chartPackagePath)),
|
||||
color.New(color.Bold).Sprintf("%s", filepath.Base(chartPackagePath)),
|
||||
formatRepoNameAndURL(p.RepoName, repo.Config.URL),
|
||||
)
|
||||
|
||||
@@ -294,7 +294,7 @@ func formatRepoNameAndURL(name, url string) string {
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s(%s)",
|
||||
color.New(color.Bold).Sprintf(name),
|
||||
color.New(color.Bold).Sprintf("%s", name),
|
||||
color.BlueString(url),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ package addon
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/xanzy/go-gitlab"
|
||||
gitlab "gitlab.com/gitlab-org/api/client-go"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
)
|
||||
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/xanzy/go-gitlab"
|
||||
gitlab "gitlab.com/gitlab-org/api/client-go"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
)
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/xanzy/go-gitlab"
|
||||
gitlab "gitlab.com/gitlab-org/api/client-go"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
)
|
||||
|
||||
@@ -37,6 +37,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/appfile"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
oamutil "github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
)
|
||||
|
||||
// NewLiveDiffOption creates a live-diff option
|
||||
@@ -118,9 +119,11 @@ func (l *LiveDiffOption) RenderlessDiff(ctx context.Context, base, comparor Live
|
||||
switch {
|
||||
case obj.Application != nil:
|
||||
app = obj.Application.DeepCopy()
|
||||
ctx = context.WithValue(ctx, oamutil.AppDefinitionNamespace, app.Namespace)
|
||||
af, err = l.Parser.GenerateAppFileFromApp(ctx, obj.Application)
|
||||
case obj.ApplicationRevision != nil:
|
||||
app = obj.ApplicationRevision.Spec.Application.DeepCopy()
|
||||
ctx = context.WithValue(ctx, oamutil.AppDefinitionNamespace, app.Namespace)
|
||||
af, err = l.Parser.GenerateAppFileFromRevision(obj.ApplicationRevision)
|
||||
default:
|
||||
err = errors.Errorf("either application or application revision should be set for LiveDiffObject")
|
||||
|
||||
@@ -109,9 +109,15 @@ func (d *Option) ValidateApp(ctx context.Context, filename string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(app.GetNamespace()) == 0 {
|
||||
|
||||
namespace := oamutil.GetDefinitionNamespaceWithCtx(ctx)
|
||||
|
||||
if namespace != "" {
|
||||
app.SetNamespace(namespace)
|
||||
} else if len(app.GetNamespace()) == 0 {
|
||||
app.SetNamespace(corev1.NamespaceDefault)
|
||||
}
|
||||
|
||||
app2 := app.DeepCopy()
|
||||
|
||||
err = d.Client.Get(ctx, client.ObjectKey{Namespace: app.GetNamespace(), Name: app.GetName()}, app2)
|
||||
|
||||
@@ -52,11 +52,11 @@ import (
|
||||
)
|
||||
|
||||
// TemplateLoaderFn load template of a capability definition
|
||||
type TemplateLoaderFn func(context.Context, client.Client, string, types.CapType) (*Template, error)
|
||||
type TemplateLoaderFn func(context.Context, client.Client, string, types.CapType, map[string]string) (*Template, error)
|
||||
|
||||
// LoadTemplate load template of a capability definition
|
||||
func (fn TemplateLoaderFn) LoadTemplate(ctx context.Context, c client.Client, capName string, capType types.CapType) (*Template, error) {
|
||||
return fn(ctx, c, capName, capType)
|
||||
func (fn TemplateLoaderFn) LoadTemplate(ctx context.Context, c client.Client, capName string, capType types.CapType, annotations map[string]string) (*Template, error) {
|
||||
return fn(ctx, c, capName, capType, annotations)
|
||||
}
|
||||
|
||||
// Parser is an application parser
|
||||
@@ -104,7 +104,7 @@ func (p *Parser) GenerateAppFileFromApp(ctx context.Context, app *v1beta1.Applic
|
||||
|
||||
for idx := range app.Spec.Policies {
|
||||
if app.Spec.Policies[idx].Name == "" {
|
||||
app.Spec.Policies[idx].Name = fmt.Sprintf("%s:auto-gen:%d", app.Spec.Policies[idx].Type, idx)
|
||||
app.Spec.Policies[idx].Name = fmt.Sprintf("%s-auto-gen-%d", app.Spec.Policies[idx].Type, idx)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,7 +253,8 @@ func (p *Parser) parseWorkflowStepsForLegacyRevision(ctx context.Context, af *Ap
|
||||
continue
|
||||
}
|
||||
def := &v1beta1.WorkflowStepDefinition{}
|
||||
if err := util.GetCapabilityDefinition(ctx, p.client, def, workflowStep.Type); err != nil {
|
||||
|
||||
if err := util.GetCapabilityDefinition(ctx, p.client, def, workflowStep.Type, af.app.Annotations); err != nil {
|
||||
return errors.Wrapf(err, "failed to get workflow step definition %s", workflowStep.Type)
|
||||
}
|
||||
af.RelatedWorkflowStepDefinitions[workflowStep.Type] = def
|
||||
@@ -383,7 +384,7 @@ func (p *Parser) parsePolicies(ctx context.Context, af *Appfile) (err error) {
|
||||
af.RelatedTraitDefinitions[def.Name] = def
|
||||
}
|
||||
default:
|
||||
w, err := p.makeComponent(ctx, policy.Name, policy.Type, types.TypePolicy, policy.Properties)
|
||||
w, err := p.makeComponent(ctx, policy.Name, policy.Type, types.TypePolicy, policy.Properties, af.app.Annotations)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -471,15 +472,15 @@ func (p *Parser) fetchAndSetWorkflowStepDefinition(ctx context.Context, af *Appf
|
||||
return nil
|
||||
}
|
||||
def := &v1beta1.WorkflowStepDefinition{}
|
||||
if err := util.GetCapabilityDefinition(ctx, p.client, def, workflowStepType); err != nil {
|
||||
if err := util.GetCapabilityDefinition(ctx, p.client, def, workflowStepType, af.AppAnnotations); err != nil {
|
||||
return errors.Wrapf(err, "failed to get workflow step definition %s", workflowStepType)
|
||||
}
|
||||
af.RelatedWorkflowStepDefinitions[workflowStepType] = def
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Parser) makeComponent(ctx context.Context, name, typ string, capType types.CapType, props *runtime.RawExtension) (*Component, error) {
|
||||
templ, err := p.tmplLoader.LoadTemplate(ctx, p.client, typ, capType)
|
||||
func (p *Parser) makeComponent(ctx context.Context, name, typ string, capType types.CapType, props *runtime.RawExtension, annotations map[string]string) (*Component, error) {
|
||||
templ, err := p.tmplLoader.LoadTemplate(ctx, p.client, typ, capType, annotations)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessagef(err, "fetch component/policy type of %s", name)
|
||||
}
|
||||
@@ -519,7 +520,7 @@ func (p *Parser) convertTemplate2Component(name, typ string, props *runtime.RawE
|
||||
func (p *Parser) parseComponents(ctx context.Context, af *Appfile) error {
|
||||
var comps []*Component
|
||||
for _, c := range af.app.Spec.Components {
|
||||
comp, err := p.parseComponent(ctx, c)
|
||||
comp, err := p.parseComponent(ctx, c, af.app.Annotations)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -568,25 +569,25 @@ func setComponentDefinitionsFromRevision(af *Appfile) {
|
||||
|
||||
// parseComponent resolve an ApplicationComponent and generate a Component
|
||||
// containing ALL information required by an Appfile.
|
||||
func (p *Parser) parseComponent(ctx context.Context, comp common.ApplicationComponent) (*Component, error) {
|
||||
workload, err := p.makeComponent(ctx, comp.Name, comp.Type, types.TypeComponentDefinition, comp.Properties)
|
||||
func (p *Parser) parseComponent(ctx context.Context, comp common.ApplicationComponent, annotations map[string]string) (*Component, error) {
|
||||
workload, err := p.makeComponent(ctx, comp.Name, comp.Type, types.TypeComponentDefinition, comp.Properties, annotations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = p.parseTraits(ctx, workload, comp); err != nil {
|
||||
if err = p.parseTraits(ctx, workload, comp, annotations); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return workload, nil
|
||||
}
|
||||
|
||||
func (p *Parser) parseTraits(ctx context.Context, workload *Component, comp common.ApplicationComponent) error {
|
||||
func (p *Parser) parseTraits(ctx context.Context, workload *Component, comp common.ApplicationComponent, annotations map[string]string) error {
|
||||
for _, traitValue := range comp.Traits {
|
||||
properties, err := util.RawExtension2Map(traitValue.Properties)
|
||||
if err != nil {
|
||||
return errors.Errorf("fail to parse properties of %s for %s", traitValue.Type, comp.Name)
|
||||
}
|
||||
trait, err := p.parseTrait(ctx, traitValue.Type, properties)
|
||||
trait, err := p.parseTrait(ctx, traitValue.Type, properties, annotations)
|
||||
if err != nil {
|
||||
return errors.WithMessagef(err, "component(%s) parse trait(%s)", comp.Name, traitValue.Type)
|
||||
}
|
||||
@@ -649,7 +650,7 @@ func (p *Parser) parseTraitsFromRevision(comp common.ApplicationComponent, appRe
|
||||
func (p *Parser) ParseComponentFromRevisionAndClient(ctx context.Context, c common.ApplicationComponent, appRev *v1beta1.ApplicationRevision) (*Component, error) {
|
||||
comp, err := p.makeComponentFromRevision(c.Name, c.Type, types.TypeComponentDefinition, c.Properties, appRev)
|
||||
if IsNotFoundInAppRevision(err) {
|
||||
comp, err = p.makeComponent(ctx, c.Name, c.Type, types.TypeComponentDefinition, c.Properties)
|
||||
comp, err = p.makeComponent(ctx, c.Name, c.Type, types.TypeComponentDefinition, c.Properties, appRev.Annotations)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -662,7 +663,7 @@ func (p *Parser) ParseComponentFromRevisionAndClient(ctx context.Context, c comm
|
||||
}
|
||||
trait, err := p.parseTraitFromRevision(traitValue.Type, properties, appRev)
|
||||
if IsNotFoundInAppRevision(err) {
|
||||
trait, err = p.parseTrait(ctx, traitValue.Type, properties)
|
||||
trait, err = p.parseTrait(ctx, traitValue.Type, properties, appRev.Annotations)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.WithMessagef(err, "component(%s) parse trait(%s)", c.Name, traitValue.Type)
|
||||
@@ -674,8 +675,8 @@ func (p *Parser) ParseComponentFromRevisionAndClient(ctx context.Context, c comm
|
||||
return comp, nil
|
||||
}
|
||||
|
||||
func (p *Parser) parseTrait(ctx context.Context, name string, properties map[string]interface{}) (*Trait, error) {
|
||||
templ, err := p.tmplLoader.LoadTemplate(ctx, p.client, name, types.TypeTrait)
|
||||
func (p *Parser) parseTrait(ctx context.Context, name string, properties map[string]interface{}, annotations map[string]string) (*Trait, error) {
|
||||
templ, err := p.tmplLoader.LoadTemplate(ctx, p.client, name, types.TypeTrait, annotations)
|
||||
if kerrors.IsNotFound(err) {
|
||||
return nil, errors.Errorf("trait definition of %s not found", name)
|
||||
}
|
||||
|
||||
@@ -559,7 +559,7 @@ func TestParser_parseTraits(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
mockTemplateLoaderFn: func(context.Context, client.Client, string, types.CapType) (*Template, error) {
|
||||
mockTemplateLoaderFn: func(context.Context, client.Client, string, types.CapType, map[string]string) (*Template, error) {
|
||||
return nil, fmt.Errorf("unsupported key not found")
|
||||
},
|
||||
wantErr: assert.Error,
|
||||
@@ -580,7 +580,7 @@ func TestParser_parseTraits(t *testing.T) {
|
||||
workload: &Component{},
|
||||
},
|
||||
wantErr: assert.NoError,
|
||||
mockTemplateLoaderFn: func(ctx context.Context, reader client.Client, s string, capType types.CapType) (*Template, error) {
|
||||
mockTemplateLoaderFn: func(ctx context.Context, reader client.Client, s string, capType types.CapType, annotations map[string]string) (*Template, error) {
|
||||
return &Template{
|
||||
TemplateStr: "template",
|
||||
CapabilityCategory: "network",
|
||||
@@ -598,7 +598,8 @@ func TestParser_parseTraits(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
p.tmplLoader = tt.mockTemplateLoaderFn
|
||||
err := p.parseTraits(context.Background(), tt.args.workload, tt.args.comp)
|
||||
annotations := make(map[string]string)
|
||||
err := p.parseTraits(context.Background(), tt.args.workload, tt.args.comp, annotations)
|
||||
tt.wantErr(t, err, fmt.Sprintf("parseTraits(%v, %v)", tt.args.workload, tt.args.comp))
|
||||
if tt.validateFunc != nil {
|
||||
assert.True(t, tt.validateFunc(tt.args.workload))
|
||||
|
||||
@@ -66,13 +66,13 @@ type Template struct {
|
||||
// LoadTemplate gets the capability definition from cluster and resolve it.
|
||||
// It returns a helper struct, Template, which will be used for further
|
||||
// processing.
|
||||
func LoadTemplate(ctx context.Context, cli client.Client, capName string, capType types.CapType) (*Template, error) {
|
||||
func LoadTemplate(ctx context.Context, cli client.Client, capName string, capType types.CapType, annotations map[string]string) (*Template, error) {
|
||||
ctx = multicluster.WithCluster(ctx, multicluster.Local)
|
||||
// Application Controller only loads template from ComponentDefinition and TraitDefinition
|
||||
switch capType {
|
||||
case types.TypeComponentDefinition, types.TypeWorkload:
|
||||
cd := new(v1beta1.ComponentDefinition)
|
||||
err := oamutil.GetCapabilityDefinition(ctx, cli, cd, capName)
|
||||
err := oamutil.GetCapabilityDefinition(ctx, cli, cd, capName, annotations)
|
||||
if err != nil {
|
||||
if kerrors.IsNotFound(err) {
|
||||
wd := new(v1beta1.WorkloadDefinition)
|
||||
@@ -108,7 +108,7 @@ func LoadTemplate(ctx context.Context, cli client.Client, capName string, capTyp
|
||||
|
||||
case types.TypeTrait:
|
||||
td := new(v1beta1.TraitDefinition)
|
||||
err := oamutil.GetCapabilityDefinition(ctx, cli, td, capName)
|
||||
err := oamutil.GetCapabilityDefinition(ctx, cli, td, capName, annotations)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessagef(err, "load template from trait definition [%s] ", capName)
|
||||
}
|
||||
@@ -119,7 +119,7 @@ func LoadTemplate(ctx context.Context, cli client.Client, capName string, capTyp
|
||||
return tmpl, nil
|
||||
case types.TypePolicy:
|
||||
d := new(v1beta1.PolicyDefinition)
|
||||
err := oamutil.GetCapabilityDefinition(ctx, cli, d, capName)
|
||||
err := oamutil.GetCapabilityDefinition(ctx, cli, d, capName, annotations)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessagef(err, "load template from policy definition [%s] ", capName)
|
||||
}
|
||||
@@ -130,7 +130,7 @@ func LoadTemplate(ctx context.Context, cli client.Client, capName string, capTyp
|
||||
return tmpl, nil
|
||||
case types.TypeWorkflowStep:
|
||||
d := new(v1beta1.WorkflowStepDefinition)
|
||||
err := oamutil.GetCapabilityDefinition(ctx, cli, d, capName)
|
||||
err := oamutil.GetCapabilityDefinition(ctx, cli, d, capName, annotations)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessagef(err, "load template from workflow step definition [%s] ", capName)
|
||||
}
|
||||
@@ -252,7 +252,7 @@ func verifyRevisionName(capName string, capType types.CapType, apprev *v1beta1.A
|
||||
// LoadTemplate, but load template from provided ones before loading from
|
||||
// cluster through LoadTemplate
|
||||
func DryRunTemplateLoader(defs []*unstructured.Unstructured) TemplateLoaderFn {
|
||||
return func(ctx context.Context, r client.Client, capName string, capType types.CapType) (*Template, error) {
|
||||
return func(ctx context.Context, r client.Client, capName string, capType types.CapType, annotations map[string]string) (*Template, error) {
|
||||
// retrieve provided cap definitions
|
||||
for _, def := range defs {
|
||||
if def.GetKind() == v1beta1.ComponentDefinitionKind &&
|
||||
@@ -282,7 +282,7 @@ func DryRunTemplateLoader(defs []*unstructured.Unstructured) TemplateLoaderFn {
|
||||
}
|
||||
// not found in provided cap definitions
|
||||
// then try to retrieve from cluster
|
||||
tmpl, err := LoadTemplate(ctx, r, capName, capType)
|
||||
tmpl, err := LoadTemplate(ctx, r, capName, capType, annotations)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessagef(err, "cannot load template %q from cluster and provided ones", capName)
|
||||
}
|
||||
|
||||
@@ -111,8 +111,8 @@ spec:
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
temp, err := LoadTemplate(context.TODO(), &tclient, "worker", types.TypeComponentDefinition)
|
||||
var annotations = make(map[string]string)
|
||||
temp, err := LoadTemplate(context.TODO(), &tclient, "worker", types.TypeComponentDefinition, annotations)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -219,8 +219,8 @@ spec:
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
temp, err := LoadTemplate(context.TODO(), &tclient, "ingress", types.TypeTrait)
|
||||
var annotations = make(map[string]string)
|
||||
temp, err := LoadTemplate(context.TODO(), &tclient, "ingress", types.TypeTrait, annotations)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -362,8 +362,9 @@ spec:
|
||||
TraitDefinition: traitDef,
|
||||
}
|
||||
|
||||
var annotations = make(map[string]string)
|
||||
dryRunLoadTemplate := DryRunTemplateLoader([]*unstructured.Unstructured{unstrctCompDef, unstrctTraitDef})
|
||||
compTmpl, err := dryRunLoadTemplate(nil, nil, "myworker", types.TypeComponentDefinition)
|
||||
compTmpl, err := dryRunLoadTemplate(nil, nil, "myworker", types.TypeComponentDefinition, annotations)
|
||||
if err != nil {
|
||||
t.Error("failed load template of component defintion", err)
|
||||
}
|
||||
@@ -371,7 +372,7 @@ spec:
|
||||
t.Fatal("failed load template of component defintion", diff)
|
||||
}
|
||||
|
||||
traitTmpl, err := dryRunLoadTemplate(nil, nil, "myingress", types.TypeTrait)
|
||||
traitTmpl, err := dryRunLoadTemplate(nil, nil, "myingress", types.TypeTrait, annotations)
|
||||
if err != nil {
|
||||
t.Error("failed load template of component defintion", err)
|
||||
}
|
||||
|
||||
@@ -17,7 +17,17 @@ limitations under the License.
|
||||
package appfile
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"cuelang.org/go/cue"
|
||||
"github.com/jeremywohl/flatten/v2"
|
||||
"github.com/kubevela/pkg/cue/cuex"
|
||||
"github.com/kubevela/workflow/pkg/cue/model/value"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/features"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
@@ -36,11 +46,20 @@ func (p *Parser) ValidateCUESchematicAppfile(a *Appfile) error {
|
||||
if wl.CapabilityCategory != types.CUECategory || wl.Type == v1alpha1.RefObjectsComponentType {
|
||||
continue
|
||||
}
|
||||
|
||||
ctxData := GenerateContextDataFromAppFile(a, wl.Name)
|
||||
if utilfeature.DefaultMutableFeatureGate.Enabled(features.EnableCueValidation) {
|
||||
err := p.ValidateComponentParams(ctxData, wl, a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
pCtx, err := newValidationProcessContext(wl, ctxData)
|
||||
if err != nil {
|
||||
return errors.WithMessagef(err, "cannot create the validation process context of app=%s in namespace=%s", a.Name, a.Namespace)
|
||||
}
|
||||
|
||||
for _, tr := range wl.Traits {
|
||||
if tr.CapabilityCategory != types.CUECategory {
|
||||
continue
|
||||
@@ -53,6 +72,225 @@ func (p *Parser) ValidateCUESchematicAppfile(a *Appfile) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateComponentParams performs CUE‑level validation for a Component’s
|
||||
// parameters and emits helpful, context‑rich errors.
|
||||
//
|
||||
// Flow
|
||||
// 1. Assemble a synthetic CUE document (template + params + app context).
|
||||
// 2. Compile it; if compilation fails, return the compiler error.
|
||||
// 3. When the EnableCueValidation gate is on, ensure *all* non‑optional,
|
||||
// non‑defaulted parameters are provided—either in the Component.Params
|
||||
// block or as workflow‑step inputs.
|
||||
// 4. Run cue.Value.Validate to enforce user‑supplied values against
|
||||
// template constraints.
|
||||
func (p *Parser) ValidateComponentParams(ctxData velaprocess.ContextData, wl *Component, app *Appfile) error {
|
||||
// ---------------------------------------------------------------------
|
||||
// 1. Build synthetic CUE source
|
||||
// ---------------------------------------------------------------------
|
||||
ctx := velaprocess.NewContext(ctxData)
|
||||
baseCtx, err := ctx.BaseContextFile()
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
paramSnippet, err := cueParamBlock(wl.Params)
|
||||
if err != nil {
|
||||
return errors.WithMessagef(err, "component %q: invalid params", wl.Name)
|
||||
}
|
||||
|
||||
cueSrc := strings.Join([]string{
|
||||
renderTemplate(wl.FullTemplate.TemplateStr),
|
||||
paramSnippet,
|
||||
baseCtx,
|
||||
}, "\n")
|
||||
|
||||
val, err := cuex.DefaultCompiler.Get().CompileString(ctx.GetCtx(), cueSrc)
|
||||
if err != nil {
|
||||
return errors.WithMessagef(err, "component %q: CUE compile error", wl.Name)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 2. Strict required‑field enforcement (feature‑gated)
|
||||
// ---------------------------------------------------------------------
|
||||
if err := enforceRequiredParams(val, wl.Params, app); err != nil {
|
||||
return errors.WithMessagef(err, "component %q", wl.Name)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 3. Validate concrete values
|
||||
// ---------------------------------------------------------------------
|
||||
paramVal := val.LookupPath(value.FieldPath(velaprocess.ParameterFieldName))
|
||||
if err := paramVal.Validate(cue.Concrete(false)); err != nil {
|
||||
return errors.WithMessagef(err, "component %q: parameter constraint violation", wl.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// cueParamBlock marshals the Params map into a `parameter:` block suitable
|
||||
// for inclusion in a CUE document.
|
||||
func cueParamBlock(params map[string]any) (string, error) {
|
||||
if len(params) == 0 {
|
||||
return velaprocess.ParameterFieldName + ": {}", nil
|
||||
}
|
||||
b, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("%s: %s", velaprocess.ParameterFieldName, string(b)), nil
|
||||
}
|
||||
|
||||
// enforceRequiredParams checks that every required field declared in the
|
||||
// template’s `parameter:` stanza is satisfied either directly (Params) or
|
||||
// indirectly (workflow‑step inputs). It returns an error describing any
|
||||
// missing keys.
|
||||
func enforceRequiredParams(root cue.Value, params map[string]any, app *Appfile) error {
|
||||
requiredParams, err := requiredFields(root.LookupPath(value.FieldPath(velaprocess.ParameterFieldName)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// filter out params that are initialized directly
|
||||
requiredParams, err = filterMissing(requiredParams, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if there are still required params not initialized
|
||||
if len(requiredParams) > 0 {
|
||||
// collect params that are initialized in workflow steps
|
||||
wfInitParams := make(map[string]bool)
|
||||
for _, step := range app.WorkflowSteps {
|
||||
for _, in := range step.Inputs {
|
||||
wfInitParams[in.ParameterKey] = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range app.Policies {
|
||||
if p.Type != "override" {
|
||||
continue
|
||||
}
|
||||
|
||||
var spec overrideSpec
|
||||
if err := json.Unmarshal(p.Properties.Raw, &spec); err != nil {
|
||||
return fmt.Errorf("override policy %q: parse properties: %w", p.Name, err)
|
||||
}
|
||||
|
||||
for _, c := range spec.Components {
|
||||
if len(c.Properties) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
flat, err := flatten.Flatten(c.Properties, "", flatten.DotStyle)
|
||||
if err != nil {
|
||||
return fmt.Errorf("override policy %q: flatten properties: %w", p.Name, err)
|
||||
}
|
||||
|
||||
for k := range flat {
|
||||
wfInitParams[k] = true // idempotent set-style insert
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// collect required params that were not initialized even in workflow steps
|
||||
var missingParams []string
|
||||
for _, key := range requiredParams {
|
||||
if !wfInitParams[key] {
|
||||
missingParams = append(missingParams, key)
|
||||
}
|
||||
}
|
||||
|
||||
if len(missingParams) > 0 {
|
||||
return fmt.Errorf("missing parameters: %v", strings.Join(missingParams, ","))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type overrideSpec struct {
|
||||
Components []struct {
|
||||
Properties map[string]any `json:"properties"`
|
||||
} `json:"components"`
|
||||
}
|
||||
|
||||
// requiredFields returns the list of "parameter" fields that must be supplied
|
||||
// by the caller. Nested struct leaves are returned as dot-separated paths.
|
||||
//
|
||||
// Rules:
|
||||
// - A field with a trailing '?' is optional -> ignore
|
||||
// - A field that has a default (*value | …) is optional -> ignore
|
||||
// - Everything else is required.
|
||||
// - Traverses arbitrarily deep into structs.
|
||||
func requiredFields(v cue.Value) ([]string, error) {
|
||||
var out []string
|
||||
err := collect("", v, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func collect(prefix string, v cue.Value, out *[]string) error {
|
||||
// Only structs can contain nested required fields.
|
||||
if v.Kind() != cue.StructKind {
|
||||
return nil
|
||||
}
|
||||
it, err := v.Fields(
|
||||
cue.Optional(false),
|
||||
cue.Definitions(false),
|
||||
cue.Hidden(false),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for it.Next() {
|
||||
// Skip fields that provide a default (*").
|
||||
if _, hasDef := it.Value().Default(); hasDef {
|
||||
continue
|
||||
}
|
||||
|
||||
label := it.Selector().Unquoted()
|
||||
path := label
|
||||
if prefix != "" {
|
||||
path = prefix + "." + label
|
||||
}
|
||||
|
||||
// Recurse if the value itself is a struct; otherwise record the leaf.
|
||||
if it.Value().Kind() == cue.StructKind {
|
||||
if err := collect(path, it.Value(), out); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
*out = append(*out, path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// filterMissing removes every key that is already present in the provided map.
|
||||
//
|
||||
// It re‑uses the original slice’s backing array to avoid allocations.
|
||||
func filterMissing(keys []string, provided map[string]any) ([]string, error) {
|
||||
flattenProvided, err := flatten.Flatten(provided, "", flatten.DotStyle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := keys[:0]
|
||||
for _, k := range keys {
|
||||
if _, ok := flattenProvided[k]; !ok {
|
||||
out = append(out, k)
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// renderTemplate appends the placeholders expected by KubeVela’s template
|
||||
// compiler so that the generated snippet is always syntactically complete.
|
||||
func renderTemplate(tmpl string) string {
|
||||
return tmpl + `
|
||||
context: _
|
||||
parameter: _
|
||||
`
|
||||
}
|
||||
|
||||
func newValidationProcessContext(c *Component, ctxData velaprocess.ContextData) (process.Context, error) {
|
||||
baseHooks := []process.BaseHook{
|
||||
// add more hook funcs here to validate CUE base
|
||||
|
||||
@@ -151,3 +151,114 @@ var _ = Describe("Test validate CUE schematic Appfile", func() {
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
var _ = Describe("Test ValidateComponentParams", func() {
|
||||
type ParamTestCase struct {
|
||||
name string
|
||||
template string
|
||||
params map[string]interface{}
|
||||
wantErr string
|
||||
}
|
||||
|
||||
DescribeTable("ValidateComponentParams cases", func(tc ParamTestCase) {
|
||||
wl := &Component{
|
||||
Name: tc.name,
|
||||
Type: "worker",
|
||||
FullTemplate: &Template{TemplateStr: tc.template},
|
||||
Params: tc.params,
|
||||
}
|
||||
app := &Appfile{
|
||||
Name: "myapp",
|
||||
Namespace: "test-ns",
|
||||
}
|
||||
ctxData := GenerateContextDataFromAppFile(app, wl.Name)
|
||||
parser := &Parser{}
|
||||
err := parser.ValidateComponentParams(ctxData, wl, app)
|
||||
if tc.wantErr == "" {
|
||||
Expect(err).To(BeNil())
|
||||
} else {
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring(tc.wantErr))
|
||||
}
|
||||
},
|
||||
Entry("valid params and template", ParamTestCase{
|
||||
name: "valid",
|
||||
template: `
|
||||
parameter: {
|
||||
replicas: int | *1
|
||||
}
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
}
|
||||
`,
|
||||
params: map[string]interface{}{
|
||||
"replicas": 2,
|
||||
},
|
||||
wantErr: "",
|
||||
}),
|
||||
Entry("invalid CUE in template", ParamTestCase{
|
||||
name: "invalid-cue",
|
||||
template: `
|
||||
parameter: {
|
||||
replicas: int | *1
|
||||
}
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
invalidField: {
|
||||
}
|
||||
`,
|
||||
params: map[string]interface{}{
|
||||
"replicas": 2,
|
||||
},
|
||||
wantErr: "CUE compile error",
|
||||
}),
|
||||
Entry("missing required parameter", ParamTestCase{
|
||||
name: "missing-required",
|
||||
template: `
|
||||
parameter: {
|
||||
replicas: int
|
||||
}
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
}
|
||||
`,
|
||||
params: map[string]interface{}{},
|
||||
wantErr: "component \"missing-required\": missing parameters: replicas",
|
||||
}),
|
||||
Entry("parameter constraint violation", ParamTestCase{
|
||||
name: "constraint-violation",
|
||||
template: `
|
||||
parameter: {
|
||||
replicas: int & >0
|
||||
}
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
}
|
||||
`,
|
||||
params: map[string]interface{}{
|
||||
"replicas": -1,
|
||||
},
|
||||
wantErr: "parameter constraint violation",
|
||||
}),
|
||||
Entry("invalid parameter block", ParamTestCase{
|
||||
name: "invalid-param-block",
|
||||
template: `
|
||||
parameter: {
|
||||
replicas: int | *1
|
||||
}
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
}
|
||||
`,
|
||||
params: map[string]interface{}{
|
||||
"replicas": "not-an-int",
|
||||
},
|
||||
wantErr: "parameter constraint violation",
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
@@ -58,17 +58,17 @@ var _ = Describe("Test dispatch stage", func() {
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
stage, err := getTraitDispatchStage(k8sClient, "kruise-rollout", &appRev)
|
||||
var annotations = make(map[string]string)
|
||||
stage, err := getTraitDispatchStage(k8sClient, "kruise-rollout", &appRev, annotations)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(stage).Should(BeEquivalentTo(PreDispatch))
|
||||
stage, err = getTraitDispatchStage(k8sClient, "gateway", &appRev)
|
||||
stage, err = getTraitDispatchStage(k8sClient, "gateway", &appRev, annotations)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(stage).Should(BeEquivalentTo(PostDispatch))
|
||||
stage, err = getTraitDispatchStage(k8sClient, "hpa", &appRev)
|
||||
stage, err = getTraitDispatchStage(k8sClient, "hpa", &appRev, annotations)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(stage).Should(BeEquivalentTo(DefaultDispatch))
|
||||
stage, err = getTraitDispatchStage(k8sClient, "not-exist", &appRev)
|
||||
stage, err = getTraitDispatchStage(k8sClient, "not-exist", &appRev, annotations)
|
||||
Expect(err).ShouldNot(BeNil())
|
||||
Expect(stage).Should(BeEquivalentTo(DefaultDispatch))
|
||||
})
|
||||
|
||||
@@ -112,7 +112,7 @@ type manifestDispatcher struct {
|
||||
healthCheck func(ctx context.Context, c *appfile.Component, appRev *v1beta1.ApplicationRevision) (bool, error)
|
||||
}
|
||||
|
||||
func (h *AppHandler) generateDispatcher(appRev *v1beta1.ApplicationRevision, readyWorkload *unstructured.Unstructured, readyTraits []*unstructured.Unstructured, overrideNamespace string) ([]*manifestDispatcher, error) {
|
||||
func (h *AppHandler) generateDispatcher(appRev *v1beta1.ApplicationRevision, readyWorkload *unstructured.Unstructured, readyTraits []*unstructured.Unstructured, overrideNamespace string, annotations map[string]string) ([]*manifestDispatcher, error) {
|
||||
dispatcherGenerator := func(options DispatchOptions) *manifestDispatcher {
|
||||
assembleManifestFn := func(skipApplyWorkload bool) (bool, []*unstructured.Unstructured) {
|
||||
manifests := options.Traits
|
||||
@@ -138,7 +138,13 @@ func (h *AppHandler) generateDispatcher(appRev *v1beta1.ApplicationRevision, rea
|
||||
}
|
||||
dispatcher.run = func(ctx context.Context, comp *appfile.Component, appRev *v1beta1.ApplicationRevision, clusterName string) (bool, error) {
|
||||
skipWorkload, dispatchManifests := assembleManifestFn(comp.SkipApplyWorkload)
|
||||
if isHealth, err := dispatcher.healthCheck(ctx, comp, appRev); !isHealth || err != nil {
|
||||
|
||||
var isAutoUpdateEnabled bool
|
||||
if annotations[oam.AnnotationAutoUpdate] == "true" {
|
||||
isAutoUpdateEnabled = true
|
||||
}
|
||||
|
||||
if isHealth, err := dispatcher.healthCheck(ctx, comp, appRev); !isHealth || err != nil || (!comp.SkipApplyWorkload && isAutoUpdateEnabled) {
|
||||
if err := h.Dispatch(ctx, h.Client, clusterName, common.WorkflowResourceCreator, dispatchManifests...); err != nil {
|
||||
return false, errors.WithMessage(err, "Dispatch")
|
||||
}
|
||||
@@ -179,7 +185,7 @@ func (h *AppHandler) generateDispatcher(appRev *v1beta1.ApplicationRevision, rea
|
||||
traitType = splitName
|
||||
}
|
||||
}
|
||||
stageType, err = getTraitDispatchStage(h.Client, traitType, appRev)
|
||||
stageType, err = getTraitDispatchStage(h.Client, traitType, appRev, annotations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -210,11 +216,11 @@ func (h *AppHandler) generateDispatcher(appRev *v1beta1.ApplicationRevision, rea
|
||||
return manifestDispatchers, nil
|
||||
}
|
||||
|
||||
func getTraitDispatchStage(client client.Client, traitType string, appRev *v1beta1.ApplicationRevision) (StageType, error) {
|
||||
func getTraitDispatchStage(client client.Client, traitType string, appRev *v1beta1.ApplicationRevision, annotations map[string]string) (StageType, error) {
|
||||
trait, ok := appRev.Spec.TraitDefinitions[traitType]
|
||||
if !ok {
|
||||
trait = &v1beta1.TraitDefinition{}
|
||||
err := oamutil.GetCapabilityDefinition(context.Background(), client, trait, traitType)
|
||||
err := oamutil.GetCapabilityDefinition(context.Background(), client, trait, traitType, annotations)
|
||||
if err != nil {
|
||||
return DefaultDispatch, err
|
||||
}
|
||||
|
||||
@@ -372,7 +372,7 @@ func (h *AppHandler) applyComponentFunc(appParser *appfile.Parser, af *appfile.A
|
||||
|
||||
isHealth := true
|
||||
if utilfeature.DefaultMutableFeatureGate.Enabled(features.MultiStageComponentApply) {
|
||||
manifestDispatchers, err := h.generateDispatcher(appRev, readyWorkload, readyTraits, overrideNamespace)
|
||||
manifestDispatchers, err := h.generateDispatcher(appRev, readyWorkload, readyTraits, overrideNamespace, af.AppAnnotations)
|
||||
if err != nil {
|
||||
return nil, nil, false, errors.WithMessage(err, "generateDispatcher")
|
||||
}
|
||||
|
||||
@@ -194,6 +194,18 @@ var _ = Describe("Test DefinitionRevision created by ComponentDefinition", func(
|
||||
Expect(defRev1.Spec.RevisionHash).Should(Equal(defRev2.Spec.RevisionHash))
|
||||
})
|
||||
|
||||
It("Test ComponentDefinition with name specified in spec.version, Should create definitaion with specified name", func() {
|
||||
cd := cdWithNoTemplate.DeepCopy()
|
||||
cd.Name = "test-cd-with-custom-version"
|
||||
cd.Spec.Version = "1.3.0"
|
||||
cd.Spec.Schematic.CUE.Template = fmt.Sprintf(cdTemplate, "test-defrev")
|
||||
|
||||
defRev, _, err := coredef.GenerateDefinitionRevision(ctx, r.Client, cd)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(defRev.Name).Should(Equal("test-cd-with-custom-version-v1.3.0"))
|
||||
|
||||
})
|
||||
|
||||
It("Test only update ComponentDefinition Labels, Shouldn't create new revision", func() {
|
||||
cd := cdWithNoTemplate.DeepCopy()
|
||||
cdName := "test-cd"
|
||||
@@ -258,6 +270,29 @@ var _ = Describe("Test DefinitionRevision created by ComponentDefinition", func(
|
||||
By("check the DefinitionRevision's RevisionNum")
|
||||
Expect(cdRev.Spec.Revision).Should(Equal(int64(1)))
|
||||
})
|
||||
|
||||
It("Test specified DefinitionRevision name in spec.version", func() {
|
||||
cdName := "test-specified-defrev1-name"
|
||||
req := reconcile.Request{NamespacedName: client.ObjectKey{Name: cdName, Namespace: namespace}}
|
||||
|
||||
cd := cdWithNoTemplate.DeepCopy()
|
||||
cd.Name = cdName
|
||||
cd.Spec.Schematic.CUE.Template = fmt.Sprintf(cdTemplate, "test")
|
||||
cd.Spec.Version = "1.1.3"
|
||||
By("create componentDefinition")
|
||||
Expect(k8sClient.Create(ctx, cd)).Should(SatisfyAll(BeNil()))
|
||||
testutil.ReconcileRetry(&r, req)
|
||||
|
||||
By("check whether DefinitionRevision is created")
|
||||
cdRevName := fmt.Sprintf("%s-v1.1.3", cdName)
|
||||
var cdRev v1beta1.DefinitionRevision
|
||||
Eventually(func() error {
|
||||
return k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: cdRevName}, &cdRev)
|
||||
}, 10*time.Second, time.Second).Should(BeNil())
|
||||
|
||||
By("check the DefinitionRevision's RevisionNum")
|
||||
Expect(cdRev.Spec.Revision).Should(Equal(int64(1)))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Test ComponentDefinition Controller clean up", func() {
|
||||
@@ -381,7 +416,7 @@ var _ = Describe("Test DefinitionRevision created by ComponentDefinition", func(
|
||||
}, time.Second*30, time.Microsecond*300).Should(BeNil())
|
||||
})
|
||||
|
||||
It("Test clean up definitionRevision contains definitionRevision with custom name", func() {
|
||||
It("Test clean up definitionRevision contains definitionRevision with custom name using annotation", func() {
|
||||
var revKey client.ObjectKey
|
||||
var defRev v1beta1.DefinitionRevision
|
||||
revisionNames := []string{"1.3.1", "", "1.3.3", "", "prod"}
|
||||
@@ -32,6 +32,7 @@ import (
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
coredef "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1beta1/core"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/testutil"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
@@ -128,6 +129,17 @@ var _ = Describe("Test DefinitionRevision created by PolicyDefinition", func() {
|
||||
newRevKey := client.ObjectKey{Namespace: namespace, Name: newDefRevName}
|
||||
Expect(k8sClient.Get(ctx, newRevKey, &defRev)).Should(HaveOccurred())
|
||||
})
|
||||
It("Test Policy Definition with name specified in spec.version, Should create definitaion with specified name", func() {
|
||||
def := defWithNoTemplate.DeepCopy()
|
||||
def.Name = "test-policy-def-custom-version"
|
||||
def.Spec.Version = "1.3.0"
|
||||
def.Spec.Schematic.CUE.Template = fmt.Sprintf(defTemplate, "test-defrev")
|
||||
|
||||
defRev, _, err := coredef.GenerateDefinitionRevision(ctx, r.Client, def)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(defRev.Name).Should(Equal("test-policy-def-custom-version-v1.3.0"))
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
Context("Test PolicyDefinition Controller clean up", func() {
|
||||
|
||||
@@ -22,10 +22,12 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/event"
|
||||
"github.com/pkg/errors"
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
@@ -44,12 +46,20 @@ import (
|
||||
// GenerateDefinitionRevision will generate a definition revision the generated revision
|
||||
// will be compare with the last revision to see if there's any difference.
|
||||
func GenerateDefinitionRevision(ctx context.Context, cli client.Client, def runtime.Object) (*v1beta1.DefinitionRevision, bool, error) {
|
||||
isNamedRev, defRevNamespacedName, err := isNamedRevision(def)
|
||||
isSpecVersion, defRevNamespacedName, err := isSpecVersionRevision(def)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
if isSpecVersion {
|
||||
return generateDefinitionRevision(ctx, cli, def, defRevNamespacedName)
|
||||
}
|
||||
|
||||
isNamedRev, defRevNamespacedName, err := isNameAnnotationRevision(def)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
if isNamedRev {
|
||||
return generateNamedDefinitionRevision(ctx, cli, def, defRevNamespacedName)
|
||||
return generateDefinitionRevision(ctx, cli, def, defRevNamespacedName)
|
||||
}
|
||||
|
||||
defRev, lastRevision, err := GatherRevisionInfo(def)
|
||||
@@ -68,7 +78,9 @@ func GenerateDefinitionRevision(ctx context.Context, cli client.Client, def runt
|
||||
return defRev, isNewRev, nil
|
||||
}
|
||||
|
||||
func isNamedRevision(def runtime.Object) (bool, types.NamespacedName, error) {
|
||||
// isNameAnnotationRevision is for Definition Version specified in the
|
||||
// Definition's "definitionrevision.oam.dev/name" annotation.
|
||||
func isNameAnnotationRevision(def runtime.Object) (bool, types.NamespacedName, error) {
|
||||
defMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(def)
|
||||
if err != nil {
|
||||
return false, types.NamespacedName{}, err
|
||||
@@ -86,7 +98,42 @@ func isNamedRevision(def runtime.Object) (bool, types.NamespacedName, error) {
|
||||
return true, types.NamespacedName{Name: defRevName, Namespace: defNs}, nil
|
||||
}
|
||||
|
||||
func generateNamedDefinitionRevision(ctx context.Context, cli client.Client, def runtime.Object, defRevNamespacedName types.NamespacedName) (*v1beta1.DefinitionRevision, bool, error) {
|
||||
// isSpecVersionRevision is for Definition Version specified in the Definition spec.Version
|
||||
func isSpecVersionRevision(def runtime.Object) (bool, types.NamespacedName, error) {
|
||||
|
||||
var definitionVersion, definitionNamespace, definitionName string
|
||||
switch definition := def.(type) {
|
||||
case *v1beta1.ComponentDefinition:
|
||||
definitionVersion = definition.Spec.Version
|
||||
definitionNamespace = definition.Namespace
|
||||
definitionName = definition.Name
|
||||
case *v1beta1.TraitDefinition:
|
||||
definitionVersion = definition.Spec.Version
|
||||
definitionNamespace = definition.Namespace
|
||||
definitionName = definition.Name
|
||||
case *v1beta1.PolicyDefinition:
|
||||
definitionVersion = definition.Spec.Version
|
||||
definitionNamespace = definition.Namespace
|
||||
definitionName = definition.Name
|
||||
case *v1beta1.WorkflowStepDefinition:
|
||||
definitionVersion = definition.Spec.Version
|
||||
definitionNamespace = definition.Namespace
|
||||
definitionName = definition.Name
|
||||
}
|
||||
|
||||
if definitionVersion == "" {
|
||||
return false, types.NamespacedName{}, nil
|
||||
}
|
||||
semVersion, err := semver.NewVersion(definitionVersion)
|
||||
if err != nil {
|
||||
return false, types.NamespacedName{}, err
|
||||
}
|
||||
|
||||
definitionRevisionName := ConstructDefinitionRevisionName(definitionName, semVersion.String())
|
||||
return true, types.NamespacedName{Name: definitionRevisionName, Namespace: definitionNamespace}, nil
|
||||
}
|
||||
|
||||
func generateDefinitionRevision(ctx context.Context, cli client.Client, def runtime.Object, defRevNamespacedName types.NamespacedName) (*v1beta1.DefinitionRevision, bool, error) {
|
||||
oldDefRev := new(v1beta1.DefinitionRevision)
|
||||
|
||||
// definitionRevision is immutable, if the requested definitionRevision already exists, return directly.
|
||||
@@ -118,21 +165,48 @@ func GatherRevisionInfo(def runtime.Object) (*v1beta1.DefinitionRevision, *commo
|
||||
defRev.Spec.DefinitionType = common.ComponentType
|
||||
defRev.Spec.ComponentDefinition = *copiedCompDef
|
||||
LastRevision = copiedCompDef.Status.LatestRevision
|
||||
defRev.ObjectMeta.OwnerReferences = []metav1.OwnerReference{{
|
||||
APIVersion: copiedCompDef.APIVersion,
|
||||
Kind: copiedCompDef.Kind,
|
||||
Name: copiedCompDef.Name,
|
||||
UID: copiedCompDef.UID,
|
||||
}}
|
||||
case *v1beta1.TraitDefinition:
|
||||
copiedTraitDef := definition.DeepCopy()
|
||||
defRev.Spec.DefinitionType = common.TraitType
|
||||
defRev.Spec.TraitDefinition = *copiedTraitDef
|
||||
LastRevision = copiedTraitDef.Status.LatestRevision
|
||||
defRev.ObjectMeta.OwnerReferences = []metav1.OwnerReference{{
|
||||
APIVersion: copiedTraitDef.APIVersion,
|
||||
Kind: copiedTraitDef.Kind,
|
||||
Name: copiedTraitDef.Name,
|
||||
UID: copiedTraitDef.UID,
|
||||
}}
|
||||
|
||||
case *v1beta1.PolicyDefinition:
|
||||
defCopy := definition.DeepCopy()
|
||||
defRev.Spec.DefinitionType = common.PolicyType
|
||||
defRev.Spec.PolicyDefinition = *defCopy
|
||||
LastRevision = defCopy.Status.LatestRevision
|
||||
defRev.ObjectMeta.OwnerReferences = []metav1.OwnerReference{{
|
||||
APIVersion: defCopy.APIVersion,
|
||||
Kind: defCopy.Kind,
|
||||
Name: defCopy.Name,
|
||||
UID: defCopy.UID,
|
||||
}}
|
||||
|
||||
case *v1beta1.WorkflowStepDefinition:
|
||||
defCopy := definition.DeepCopy()
|
||||
defRev.Spec.DefinitionType = common.WorkflowStepType
|
||||
defRev.Spec.WorkflowStepDefinition = *defCopy
|
||||
LastRevision = defCopy.Status.LatestRevision
|
||||
defRev.ObjectMeta.OwnerReferences = []metav1.OwnerReference{{
|
||||
APIVersion: defCopy.APIVersion,
|
||||
Kind: defCopy.Kind,
|
||||
Name: defCopy.Name,
|
||||
UID: defCopy.UID,
|
||||
}}
|
||||
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("unsupported type %v", definition)
|
||||
}
|
||||
@@ -230,24 +304,27 @@ func DeepEqualDefRevision(old, new *v1beta1.DefinitionRevision) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func getDefNextRevision(defRev *v1beta1.DefinitionRevision, lastRevision *common.Revision) (string, int64) {
|
||||
func getDefNextRevision(definitionRevision *v1beta1.DefinitionRevision, lastRevision *common.Revision) (string, int64) {
|
||||
var nextRevision int64 = 1
|
||||
var definitionRevisionName string
|
||||
if lastRevision != nil {
|
||||
nextRevision = lastRevision.Revision + 1
|
||||
}
|
||||
var name string
|
||||
switch defRev.Spec.DefinitionType {
|
||||
switch definitionRevision.Spec.DefinitionType {
|
||||
case common.ComponentType:
|
||||
name = defRev.Spec.ComponentDefinition.Name
|
||||
name = definitionRevision.Spec.ComponentDefinition.Name
|
||||
case common.TraitType:
|
||||
name = defRev.Spec.TraitDefinition.Name
|
||||
name = definitionRevision.Spec.TraitDefinition.Name
|
||||
case common.PolicyType:
|
||||
name = defRev.Spec.PolicyDefinition.Name
|
||||
name = definitionRevision.Spec.PolicyDefinition.Name
|
||||
case common.WorkflowStepType:
|
||||
name = defRev.Spec.WorkflowStepDefinition.Name
|
||||
name = definitionRevision.Spec.WorkflowStepDefinition.Name
|
||||
}
|
||||
defRevName := strings.Join([]string{name, fmt.Sprintf("v%d", nextRevision)}, "-")
|
||||
return defRevName, nextRevision
|
||||
|
||||
definitionRevisionName = strings.Join([]string{name, fmt.Sprintf("v%v", nextRevision)}, "-")
|
||||
|
||||
return definitionRevisionName, nextRevision
|
||||
}
|
||||
|
||||
// ConstructDefinitionRevisionName construct the name of DefinitionRevision.
|
||||
|
||||
@@ -32,6 +32,7 @@ import (
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
coredef "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1beta1/core"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/testutil"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
@@ -128,6 +129,17 @@ var _ = Describe("Test DefinitionRevision created by TraitDefinition", func() {
|
||||
newRevKey := client.ObjectKey{Namespace: namespace, Name: newDefRevName}
|
||||
Expect(k8sClient.Get(ctx, newRevKey, &defRev)).Should(HaveOccurred())
|
||||
})
|
||||
|
||||
It("Test Trait Definition with name specified in spec.version, Should create definitaion with specified name", func() {
|
||||
td := tdWithNoTemplate.DeepCopy()
|
||||
td.Name = "test-trait-def-custom-version"
|
||||
td.Spec.Version = "1.3.0"
|
||||
td.Spec.Schematic.CUE.Template = fmt.Sprintf(tdTemplate, fmt.Sprintf("test-v%d", 1))
|
||||
defRev, _, err := coredef.GenerateDefinitionRevision(ctx, r.Client, td)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(defRev.Name).Should(Equal("test-trait-def-custom-version-v1.3.0"))
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
Context("Test TraitDefinition Controller clean up", func() {
|
||||
|
||||
@@ -32,6 +32,7 @@ import (
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
coredef "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1beta1/core"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/testutil"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
@@ -128,6 +129,16 @@ var _ = Describe("Test DefinitionRevision created by WorkflowStepDefinition", fu
|
||||
newRevKey := client.ObjectKey{Namespace: namespace, Name: newDefRevName}
|
||||
Expect(k8sClient.Get(ctx, newRevKey, &defRev)).Should(HaveOccurred())
|
||||
})
|
||||
It("Test WorkflowStep Definition with name specified in spec.version, Should create definitaion with specified name", func() {
|
||||
def := defWithNoTemplate.DeepCopy()
|
||||
def.Name = "test-workflow-def-custom-version"
|
||||
def.Spec.Version = "1.3.0"
|
||||
def.Spec.Schematic.CUE.Template = fmt.Sprintf(defTemplate, fmt.Sprintf("test-v%d", 1))
|
||||
defRev, _, err := coredef.GenerateDefinitionRevision(ctx, r.Client, def)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(defRev.Name).Should(Equal("test-workflow-def-custom-version-v1.3.0"))
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
Context("Test WorkflowStepDefinition Controller clean up", func() {
|
||||
|
||||
351
pkg/cue/cuex/compiler_test.go
Normal file
351
pkg/cue/cuex/compiler_test.go
Normal file
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
Copyright 2025 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cuex_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/kubevela/pkg/cue/cuex"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
||||
"github.com/kubevela/pkg/util/singleton"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/definition"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/process"
|
||||
)
|
||||
|
||||
var testCtx = struct {
|
||||
K8sClient client.Client
|
||||
ReturnVal string
|
||||
CueXTestPackage string
|
||||
Namespace string
|
||||
CueXPath string
|
||||
ExternalFnName string
|
||||
InputParamName string
|
||||
OutputParamName string
|
||||
}{
|
||||
ReturnVal: "external",
|
||||
CueXTestPackage: "cuex-test-package",
|
||||
Namespace: "default",
|
||||
CueXPath: "cuex/ext",
|
||||
ExternalFnName: "external",
|
||||
InputParamName: "input",
|
||||
OutputParamName: "output",
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testEnv := &envtest.Environment{
|
||||
CRDDirectoryPaths: []string{
|
||||
filepath.Join("..", "..", "..", "charts", "vela-core", "crds"),
|
||||
},
|
||||
}
|
||||
|
||||
var err error
|
||||
cfg, err := testEnv.Start()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to start envtest: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if cfg == nil {
|
||||
fmt.Fprintf(os.Stderr, "envtest config is nil")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
testCtx.K8sClient, err = createK8sClient(cfg)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to create k8s Client: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
mockServer := createMockServer()
|
||||
defer mockServer.Close()
|
||||
|
||||
singleton.KubeConfig.Set(cfg)
|
||||
|
||||
if err = createTestPackage(mockServer.URL); err != nil {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "Setup failed: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer func() {
|
||||
if err = deleteTestPackage(); err != nil {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "Teardown failed: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
|
||||
code := m.Run()
|
||||
|
||||
singleton.KubeConfig.Reload()
|
||||
|
||||
if err := testEnv.Stop(); err != nil {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "Failed to stop envtest: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
func TestWorkloadCompiler(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
cuexEnabled bool
|
||||
workloadTemplate string
|
||||
params map[string]interface{}
|
||||
expectedObj runtime.Object
|
||||
expectedAdditionalObjs map[string]runtime.Object
|
||||
hasCompileErr bool
|
||||
errorString string
|
||||
}{
|
||||
"cuex disabled with no external packages": {
|
||||
cuexEnabled: false,
|
||||
workloadTemplate: getWorkloadTemplate(false),
|
||||
params: make(map[string]interface{}),
|
||||
expectedObj: getExpectedObj(false),
|
||||
expectedAdditionalObjs: make(map[string]runtime.Object),
|
||||
hasCompileErr: false,
|
||||
errorString: "",
|
||||
},
|
||||
"cuex enabled with no external packages": {
|
||||
cuexEnabled: true,
|
||||
workloadTemplate: getWorkloadTemplate(false),
|
||||
params: make(map[string]interface{}),
|
||||
expectedObj: getExpectedObj(false),
|
||||
expectedAdditionalObjs: make(map[string]runtime.Object),
|
||||
hasCompileErr: false,
|
||||
errorString: "",
|
||||
},
|
||||
"cuex disabled with external packages": {
|
||||
cuexEnabled: false,
|
||||
workloadTemplate: getWorkloadTemplate(true),
|
||||
params: make(map[string]interface{}),
|
||||
expectedObj: getExpectedObj(true),
|
||||
expectedAdditionalObjs: make(map[string]runtime.Object),
|
||||
hasCompileErr: true,
|
||||
errorString: "builtin package \"cuex/ext\" undefined",
|
||||
},
|
||||
"cuex enabled with external packages": {
|
||||
cuexEnabled: true,
|
||||
workloadTemplate: getWorkloadTemplate(true),
|
||||
params: make(map[string]interface{}),
|
||||
expectedObj: getExpectedObj(true),
|
||||
expectedAdditionalObjs: make(map[string]runtime.Object),
|
||||
hasCompileErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
cuex.EnableExternalPackageForDefaultCompiler = tc.cuexEnabled
|
||||
cuex.DefaultCompiler.Reload()
|
||||
|
||||
ctx := process.NewContext(process.ContextData{
|
||||
AppName: "test-app",
|
||||
CompName: "test-component",
|
||||
Namespace: testCtx.Namespace,
|
||||
AppRevisionName: "test-app-v1",
|
||||
ClusterVersion: types.ClusterVersion{Minor: "19+"},
|
||||
})
|
||||
|
||||
wt := definition.NewWorkloadAbstractEngine("test-workload")
|
||||
err := wt.Complete(ctx, tc.workloadTemplate, tc.params)
|
||||
assert.Equal(t, tc.hasCompileErr, err != nil)
|
||||
if tc.hasCompileErr {
|
||||
assert.NotNil(t, err)
|
||||
assert.Contains(t, err.Error(), tc.errorString)
|
||||
} else {
|
||||
output, _ := ctx.Output()
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, output)
|
||||
outputObj, _ := output.Unstructured()
|
||||
assert.Equal(t, tc.expectedObj, outputObj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createMockServer() *httptest.Server {
|
||||
mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/"+testCtx.ExternalFnName {
|
||||
http.Error(w, fmt.Sprintf("unexpected path: %s, expected: /%s", r.URL.Path, testCtx.ExternalFnName), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := w.Write([]byte(fmt.Sprintf("{\"%s\": \"%s\"}", testCtx.OutputParamName, testCtx.ReturnVal)))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}))
|
||||
return mockServer
|
||||
}
|
||||
|
||||
func createTestPackage(url string) error {
|
||||
ctx := context.Background()
|
||||
|
||||
packageObj := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "cue.oam.dev/v1alpha1",
|
||||
"kind": "Package",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": testCtx.CueXTestPackage,
|
||||
"namespace": testCtx.Namespace,
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"path": testCtx.CueXPath,
|
||||
"provider": map[string]interface{}{
|
||||
"endpoint": url,
|
||||
"protocol": "http",
|
||||
},
|
||||
"templates": map[string]interface{}{
|
||||
"ext/cue": strings.TrimSpace(fmt.Sprintf(`
|
||||
package ext
|
||||
|
||||
#ExternalFunction: {
|
||||
#do: "%s",
|
||||
#provider: "%s",
|
||||
$params: {
|
||||
%s: string
|
||||
},
|
||||
$returns: {
|
||||
%s: string
|
||||
}
|
||||
}
|
||||
`, testCtx.ExternalFnName, testCtx.CueXTestPackage, testCtx.InputParamName, testCtx.OutputParamName)),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := testCtx.K8sClient.Create(ctx, packageObj)
|
||||
|
||||
err = wait.PollImmediate(time.Second, 10*time.Second, func() (bool, error) {
|
||||
err = testCtx.K8sClient.Get(ctx, client.ObjectKey{
|
||||
Name: testCtx.CueXTestPackage,
|
||||
Namespace: testCtx.Namespace,
|
||||
}, packageObj)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create test package: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteTestPackage() error {
|
||||
ctx := context.Background()
|
||||
|
||||
testPkg := &unstructured.Unstructured{}
|
||||
testPkg.SetGroupVersionKind(schema.GroupVersionKind{
|
||||
Group: "cue.oam.dev",
|
||||
Version: "v1alpha1",
|
||||
Kind: "Package",
|
||||
})
|
||||
testPkg.SetName(testCtx.CueXTestPackage)
|
||||
testPkg.SetNamespace(testCtx.Namespace)
|
||||
|
||||
err := testCtx.K8sClient.Delete(ctx, testPkg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete test package: %w", err)
|
||||
}
|
||||
err = wait.PollImmediate(time.Second, 10*time.Second, func() (bool, error) {
|
||||
err := testCtx.K8sClient.Get(ctx, client.ObjectKey{
|
||||
Name: testCtx.CueXTestPackage,
|
||||
Namespace: testCtx.Namespace,
|
||||
}, testPkg)
|
||||
if err != nil {
|
||||
if k8serrors.IsNotFound(err) {
|
||||
return true, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete test package: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getWorkloadTemplate(includeExt bool) string {
|
||||
tmpl := ""
|
||||
name := "test-deployment"
|
||||
if includeExt {
|
||||
name = "test-deployment-\\(external.$returns.output)"
|
||||
tmpl = tmpl + strings.TrimSpace(fmt.Sprintf(`
|
||||
import (
|
||||
"%s"
|
||||
)
|
||||
|
||||
external: ext.#ExternalFunction & {
|
||||
$params: {
|
||||
%s: "external"
|
||||
}
|
||||
}
|
||||
`, testCtx.CueXPath, testCtx.InputParamName)) + "\n"
|
||||
|
||||
}
|
||||
|
||||
tmpl = tmpl + strings.TrimSpace(fmt.Sprintf(`
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
metadata: name: "%s"
|
||||
spec: replicas: 1
|
||||
}
|
||||
`, name))
|
||||
return tmpl
|
||||
}
|
||||
|
||||
func getExpectedObj(includeExt bool) *unstructured.Unstructured {
|
||||
name := "test-deployment"
|
||||
if includeExt {
|
||||
name = fmt.Sprintf("test-deployment-%s", testCtx.ReturnVal)
|
||||
}
|
||||
return &unstructured.Unstructured{Object: map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{"name": name},
|
||||
"spec": map[string]interface{}{"replicas": int64(1)},
|
||||
}}
|
||||
}
|
||||
|
||||
func createK8sClient(config *rest.Config) (client.Client, error) {
|
||||
scheme := runtime.NewScheme()
|
||||
if err := corev1.AddToScheme(scheme); err != nil {
|
||||
return nil, fmt.Errorf("failed to add corev1 to scheme: %w", err)
|
||||
}
|
||||
return client.New(config, client.Options{Scheme: scheme})
|
||||
}
|
||||
@@ -22,6 +22,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/kubevela/pkg/cue/cuex"
|
||||
|
||||
"cuelang.org/go/cue"
|
||||
"cuelang.org/go/cue/cuecontext"
|
||||
"github.com/kubevela/pkg/multicluster"
|
||||
@@ -39,10 +41,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/cue/task"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/features"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -111,10 +109,14 @@ func (wd *workloadDef) Complete(ctx process.Context, abstractTemplate string, pa
|
||||
return err
|
||||
}
|
||||
|
||||
val := cuecontext.New().CompileString(strings.Join([]string{
|
||||
val, err := cuex.DefaultCompiler.Get().CompileString(ctx.GetCtx(), strings.Join([]string{
|
||||
renderTemplate(abstractTemplate), paramFile, c,
|
||||
}, "\n"))
|
||||
|
||||
if err != nil {
|
||||
return errors.WithMessagef(err, "failed to compile workload %s after merge parameter and context", wd.name)
|
||||
}
|
||||
|
||||
if err := val.Validate(); err != nil {
|
||||
return errors.WithMessagef(err, "invalid cue template of workload %s after merge parameter and context", wd.name)
|
||||
}
|
||||
@@ -127,14 +129,6 @@ func (wd *workloadDef) Complete(ctx process.Context, abstractTemplate string, pa
|
||||
return err
|
||||
}
|
||||
|
||||
// Strict Cue required field parameter validation
|
||||
if utilfeature.DefaultMutableFeatureGate.Enabled(features.EnableCueValidation) {
|
||||
paramCue := val.LookupPath(value.FieldPath(velaprocess.ParameterFieldName))
|
||||
if err := paramCue.Validate(cue.Concrete(true)); err != nil {
|
||||
return errors.WithMessagef(err, "parameter error for %s", wd.name)
|
||||
}
|
||||
}
|
||||
|
||||
// we will support outputs for workload composition, and it will become trait in AppConfig.
|
||||
outputs := val.LookupPath(value.FieldPath(OutputsFieldName))
|
||||
if !outputs.Exists() {
|
||||
@@ -318,10 +312,16 @@ func (td *traitDef) Complete(ctx process.Context, abstractTemplate string, param
|
||||
}
|
||||
buff += c
|
||||
|
||||
val := cuecontext.New().CompileString(buff)
|
||||
val, err := cuex.DefaultCompiler.Get().CompileString(ctx.GetCtx(), buff)
|
||||
|
||||
if err != nil {
|
||||
return errors.WithMessagef(err, "failed to compile trait %s after merge parameter and context", td.name)
|
||||
}
|
||||
|
||||
if err := val.Validate(); err != nil {
|
||||
return errors.WithMessagef(err, "invalid template of trait %s after merge with parameter and context", td.name)
|
||||
}
|
||||
|
||||
processing := val.LookupPath(value.FieldPath("processing"))
|
||||
if processing.Exists() {
|
||||
if val, err = task.Process(val); err != nil {
|
||||
@@ -386,7 +386,7 @@ func parseErrors(errs cue.Value) error {
|
||||
if it, e := errs.List(); e == nil {
|
||||
for it.Next() {
|
||||
if s, err := it.Value().String(); err == nil && s != "" {
|
||||
return errors.Errorf(s)
|
||||
return errors.Errorf("%s", s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,11 +28,6 @@ import (
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/process"
|
||||
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/features"
|
||||
)
|
||||
|
||||
func TestWorkloadTemplateComplete(t *testing.T) {
|
||||
@@ -1570,271 +1565,3 @@ parameter: {
|
||||
assert.Contains(t, err.Error(), v.err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorkloadParamsValidations(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(&testing.T{}, utilfeature.DefaultFeatureGate, features.EnableCueValidation, true)()
|
||||
testCases := map[string]struct {
|
||||
workloadTemplate string
|
||||
params map[string]interface{}
|
||||
expectObj runtime.Object
|
||||
expAssObjs map[string]runtime.Object
|
||||
category types.CapabilityCategory
|
||||
hasCompileErr bool
|
||||
errorString string
|
||||
}{
|
||||
"Missing Required Param that is used in template": {
|
||||
workloadTemplate: `
|
||||
output:{
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
metadata: name: context.name
|
||||
spec: {
|
||||
replicas: parameter.replicas
|
||||
host: parameter.requiredParam
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
replicas: *1 | int
|
||||
type: string
|
||||
requiredParam!: string
|
||||
}
|
||||
`,
|
||||
params: map[string]interface{}{
|
||||
"replicas": 2,
|
||||
"type": "ClusterIP",
|
||||
},
|
||||
expectObj: &unstructured.Unstructured{Object: map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{"name": "test"},
|
||||
"spec": map[string]interface{}{"replicas": int64(2)},
|
||||
}},
|
||||
hasCompileErr: true,
|
||||
errorString: "parameter error for testWorkload: parameter.requiredParam: field is required but not present",
|
||||
},
|
||||
// Missing Required Param that is not used in template
|
||||
"Missing Required Param that is not used in template": {
|
||||
workloadTemplate: `
|
||||
output:{
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
metadata: name: context.name
|
||||
spec: {
|
||||
replicas: parameter.replicas
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
replicas: *1 | int
|
||||
type: string
|
||||
requiredParam!: string
|
||||
}
|
||||
`,
|
||||
params: map[string]interface{}{
|
||||
"replicas": 2,
|
||||
"type": "ClusterIP",
|
||||
},
|
||||
expectObj: &unstructured.Unstructured{Object: map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{"name": "test"},
|
||||
"spec": map[string]interface{}{"replicas": int64(2)},
|
||||
}},
|
||||
hasCompileErr: true,
|
||||
errorString: "parameter error for testWorkload: parameter.requiredParam: field is required but not present",
|
||||
},
|
||||
//required param that is nested
|
||||
"required param that is nested": {
|
||||
workloadTemplate: `
|
||||
output:{
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
metadata: name: context.name
|
||||
spec: {
|
||||
replicas: parameter.replicas
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
replicas: *1 | int
|
||||
type: string
|
||||
host: requiredParam!: string
|
||||
}
|
||||
`,
|
||||
params: map[string]interface{}{
|
||||
"replicas": 2,
|
||||
"type": "ClusterIP",
|
||||
"host": map[string]string{},
|
||||
},
|
||||
expectObj: &unstructured.Unstructured{Object: map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{"name": "test"},
|
||||
"spec": map[string]interface{}{"replicas": int64(2)},
|
||||
}},
|
||||
hasCompileErr: true,
|
||||
errorString: "parameter error for testWorkload: parameter.host.requiredParam: field is required but not present",
|
||||
},
|
||||
//required params that are provided
|
||||
"required params that are provided": {
|
||||
workloadTemplate: `
|
||||
output:{
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
metadata: name: context.name
|
||||
spec: {
|
||||
replicas: parameter.replicas
|
||||
host: parameter.host.requiredParam
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
replicas: *1 | int
|
||||
type: string
|
||||
host: requiredParam!: string
|
||||
param1!: string
|
||||
}
|
||||
`,
|
||||
params: map[string]interface{}{
|
||||
"replicas": 2,
|
||||
"type": "ClusterIP",
|
||||
"host": map[string]interface{}{"requiredParam": "example.com"},
|
||||
"param1": "newparam",
|
||||
},
|
||||
expectObj: &unstructured.Unstructured{Object: map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{"name": "test"},
|
||||
"spec": map[string]interface{}{"replicas": int64(2), "host": "example.com"},
|
||||
}},
|
||||
hasCompileErr: false,
|
||||
errorString: "",
|
||||
},
|
||||
//optional and regular param with default value should not give error
|
||||
"optional and regular param with default value should not give error": {
|
||||
workloadTemplate: `
|
||||
output:{
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
metadata: name: context.name
|
||||
spec: {
|
||||
replicas: parameter.replicas
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
replicas: *1 | int
|
||||
type: string
|
||||
requiredParam!: string
|
||||
optionalParam?: string
|
||||
regularParam: string | *""
|
||||
}
|
||||
`,
|
||||
params: map[string]interface{}{
|
||||
"replicas": 2,
|
||||
"type": "ClusterIP",
|
||||
"requiredParam": "example.com",
|
||||
},
|
||||
expectObj: &unstructured.Unstructured{Object: map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{"name": "test"},
|
||||
"spec": map[string]interface{}{"replicas": int64(2)},
|
||||
}},
|
||||
hasCompileErr: false,
|
||||
errorString: "",
|
||||
},
|
||||
// regular param should give error
|
||||
"regular param should give error": {
|
||||
workloadTemplate: `
|
||||
output:{
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
metadata: name: context.name
|
||||
spec: {
|
||||
replicas: parameter.replicas
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
replicas: *1 | int
|
||||
type: string
|
||||
requiredParam!: string
|
||||
regularParam: string
|
||||
}
|
||||
`,
|
||||
params: map[string]interface{}{
|
||||
"replicas": 2,
|
||||
"type": "ClusterIP",
|
||||
"requiredParam": "example.com",
|
||||
},
|
||||
expectObj: &unstructured.Unstructured{Object: map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{"name": "test"},
|
||||
"spec": map[string]interface{}{"replicas": int64(2)},
|
||||
}},
|
||||
hasCompileErr: true,
|
||||
errorString: "parameter error for testWorkload: parameter.regularParam: incomplete value string",
|
||||
},
|
||||
|
||||
// multiple errors
|
||||
"multiple errors": {
|
||||
workloadTemplate: `
|
||||
output:{
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
metadata: name: context.name
|
||||
spec: {
|
||||
replicas: parameter.replicas
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
replicas: *1 | int
|
||||
type: string
|
||||
requiredParam!: string
|
||||
regularParam: string
|
||||
}
|
||||
`,
|
||||
params: map[string]interface{}{
|
||||
"replicas": 2,
|
||||
"type": "ClusterIP",
|
||||
},
|
||||
expectObj: &unstructured.Unstructured{Object: map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{"name": "test"},
|
||||
"spec": map[string]interface{}{"replicas": int64(2)},
|
||||
}},
|
||||
hasCompileErr: true,
|
||||
errorString: "parameter error for testWorkload: parameter.requiredParam: field is required but not present (and 1 more errors)",
|
||||
},
|
||||
}
|
||||
|
||||
for _, v := range testCases {
|
||||
ctx := process.NewContext(process.ContextData{
|
||||
AppName: "myapp",
|
||||
CompName: "test",
|
||||
Namespace: "default",
|
||||
AppRevisionName: "myapp-v1",
|
||||
ClusterVersion: types.ClusterVersion{Minor: "19+"},
|
||||
})
|
||||
wt := NewWorkloadAbstractEngine("testWorkload")
|
||||
err := wt.Complete(ctx, v.workloadTemplate, v.params)
|
||||
hasError := err != nil
|
||||
assert.Equal(t, v.hasCompileErr, hasError)
|
||||
if v.hasCompileErr {
|
||||
if err != nil {
|
||||
assert.Equal(t, err.Error(), v.errorString)
|
||||
}
|
||||
continue
|
||||
}
|
||||
base, assists := ctx.Output()
|
||||
assert.Equal(t, len(v.expAssObjs), len(assists))
|
||||
assert.NotNil(t, base)
|
||||
baseObj, err := base.Unstructured()
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, v.expectObj, baseObj)
|
||||
for _, ss := range assists {
|
||||
assert.Equal(t, AuxiliaryWorkload, ss.Type)
|
||||
got, err := ss.Ins.Unstructured()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, got, v.expAssObjs[ss.Name])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,7 +251,7 @@ func (m *GoModuleModifier) addSubGoMod() error {
|
||||
"--rm",
|
||||
"-v", m.apiDir+":/api",
|
||||
"-w", "/api",
|
||||
"golang:1.22-alpine3.18",
|
||||
"golang:1.23.8-alpine@sha256:b7486658b87d34ecf95125e5b97e8dfe86c21f712aa36fc0c702e5dc41dc63e1",
|
||||
"go", "get", fmt.Sprintf("%s@%s", m.Package, m.LangArgs.Get(mainModuleVersionKey)),
|
||||
))
|
||||
}
|
||||
@@ -261,7 +261,7 @@ func (m *GoModuleModifier) addSubGoMod() error {
|
||||
"-v", m.apiDir+":/api",
|
||||
"-w", "/api",
|
||||
"--env", "GOPROXY="+m.LangArgs.Get(goProxyKey),
|
||||
"golang:1.22-alpine3.18",
|
||||
"golang:1.23.8-alpine@sha256:b7486658b87d34ecf95125e5b97e8dfe86c21f712aa36fc0c702e5dc41dc63e1",
|
||||
"go", "mod", "tidy",
|
||||
))
|
||||
for _, cmd := range cmds {
|
||||
@@ -293,7 +293,7 @@ func (m *GoModuleModifier) tidyMainMod() error {
|
||||
"--rm",
|
||||
"-v", outDir+":/api",
|
||||
"-w", "/api",
|
||||
"golang:1.22-alpine3.18",
|
||||
"golang:1.23.8-alpine@sha256:b7486658b87d34ecf95125e5b97e8dfe86c21f712aa36fc0c702e5dc41dc63e1",
|
||||
"go", "mod", "tidy",
|
||||
)
|
||||
if m.Verbose {
|
||||
|
||||
@@ -19,7 +19,10 @@ package multicluster
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -41,6 +44,7 @@ import (
|
||||
ocmclusterv1 "open-cluster-management.io/api/cluster/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
)
|
||||
@@ -125,10 +129,20 @@ func (clusterConfig *KubeClusterConfig) createOrUpdateClusterSecret(ctx context.
|
||||
data["ca.crt"] = clusterConfig.Cluster.CertificateAuthorityData
|
||||
}
|
||||
}
|
||||
if len(clusterConfig.AuthInfo.Token) > 0 {
|
||||
switch {
|
||||
case len(clusterConfig.AuthInfo.Token) > 0:
|
||||
credentialType = clusterv1alpha1.CredentialTypeServiceAccountToken
|
||||
data["token"] = []byte(clusterConfig.AuthInfo.Token)
|
||||
} else {
|
||||
|
||||
case clusterConfig.AuthInfo.Exec != nil:
|
||||
token, err := getTokenFromExec(clusterConfig.AuthInfo.Exec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
credentialType = clusterv1alpha1.CredentialTypeServiceAccountToken
|
||||
data["token"] = []byte(token)
|
||||
|
||||
default:
|
||||
credentialType = clusterv1alpha1.CredentialTypeX509Certificate
|
||||
data["tls.crt"] = clusterConfig.AuthInfo.ClientCertificateData
|
||||
data["tls.key"] = clusterConfig.AuthInfo.ClientKeyData
|
||||
@@ -473,6 +487,9 @@ func (op DetachClusterManagedClusterKubeConfigPathOption) ApplyToArgs(args *Deta
|
||||
|
||||
// DetachCluster detach cluster by name, if cluster is using by application, it will return error
|
||||
func DetachCluster(ctx context.Context, cli client.Client, clusterName string, options ...DetachClusterOption) error {
|
||||
if err := removeClusterFromResourceTrackers(ctx, cli, clusterName); err != nil {
|
||||
return fmt.Errorf("error in removing cluster references from resourcetrackers: %w", err)
|
||||
}
|
||||
args := newDetachClusterArgs(options...)
|
||||
if clusterName == ClusterLocalName {
|
||||
return ErrReservedLocalClusterName
|
||||
@@ -598,3 +615,78 @@ func getMutableClusterSecret(ctx context.Context, c client.Client, clusterName s
|
||||
}
|
||||
return clusterSecret, nil
|
||||
}
|
||||
|
||||
// removeClusterFromResourceTrackers removes cluster references from all resource trackers.
|
||||
func removeClusterFromResourceTrackers(ctx context.Context, cli client.Client, clusterName string) error {
|
||||
rts := v1beta1.ResourceTrackerList{}
|
||||
if err := cli.List(ctx, &rts); err != nil {
|
||||
return fmt.Errorf("unable to list resourcetrackers due to error: %w", err)
|
||||
}
|
||||
for i := range rts.Items {
|
||||
managedResources := rts.Items[i].Spec.ManagedResources
|
||||
var result []v1beta1.ManagedResource
|
||||
for _, mr := range managedResources {
|
||||
if mr.ClusterObjectReference.Cluster != clusterName {
|
||||
result = append(result, mr)
|
||||
}
|
||||
}
|
||||
if len(rts.Items[i].Spec.ManagedResources) != len(result) {
|
||||
rts.Items[i].Spec.ManagedResources = result
|
||||
if err := cli.Update(ctx, &rts.Items[i]); err != nil {
|
||||
return fmt.Errorf("error in updating resourcetracker %s: %w", rts.Items[i].Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getTokenFromExec(execConfig *clientcmdapi.ExecConfig) (string, error) {
|
||||
// #nosec G204 -- This is intentionally running an exec command with user-provided input
|
||||
// The execConfig comes from the kubeconfig which should be trusted in this context
|
||||
|
||||
cmdPath := execConfig.Command
|
||||
if strings.Contains(cmdPath, "..") {
|
||||
return "", fmt.Errorf("command path must not contain '..'")
|
||||
}
|
||||
|
||||
if strings.ContainsAny(cmdPath, "$;&|<>\"'\\") {
|
||||
return "", fmt.Errorf("command must not contain shell metacharacters")
|
||||
}
|
||||
|
||||
for _, arg := range execConfig.Args {
|
||||
if strings.ContainsAny(arg, "$;&|<>\\") {
|
||||
return "", fmt.Errorf("arguments must not contain shell metacharacters")
|
||||
}
|
||||
}
|
||||
|
||||
cmd := exec.Command(cmdPath, execConfig.Args...) // #nosec G204
|
||||
|
||||
env := os.Environ()
|
||||
for _, e := range execConfig.Env {
|
||||
if strings.ContainsAny(e.Name, "=$;\n") || strings.ContainsAny(e.Value, "\n") {
|
||||
return "", fmt.Errorf("environment variable names and values must not contain control characters")
|
||||
}
|
||||
env = append(env, fmt.Sprintf("%s=%s", e.Name, e.Value))
|
||||
}
|
||||
cmd.Env = env
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to execute auth command: %w", err)
|
||||
}
|
||||
|
||||
var execCredential struct {
|
||||
Status struct {
|
||||
Token string `json:"token"`
|
||||
} `json:"status"`
|
||||
}
|
||||
if err := json.Unmarshal(output, &execCredential); err != nil {
|
||||
return "", fmt.Errorf("failed to parse exec command output: %w", err)
|
||||
}
|
||||
|
||||
if execCredential.Status.Token == "" {
|
||||
return "", fmt.Errorf("token not found in exec command output")
|
||||
}
|
||||
|
||||
return execCredential.Status.Token, nil
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"fmt"
|
||||
"hash"
|
||||
"hash/fnv"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -39,6 +40,8 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/condition"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
@@ -122,6 +125,14 @@ const (
|
||||
XDefinitionNamespace
|
||||
)
|
||||
|
||||
// DefinitionKindToNameLabel records DefinitionRevision types and labels to search its name
|
||||
var DefinitionKindToNameLabel = map[common.DefinitionType]string{
|
||||
common.ComponentType: oam.LabelComponentDefinitionName,
|
||||
common.TraitType: oam.LabelTraitDefinitionName,
|
||||
common.PolicyType: oam.LabelPolicyDefinitionName,
|
||||
common.WorkflowStepType: oam.LabelWorkflowStepDefinitionName,
|
||||
}
|
||||
|
||||
// A ConditionedObject is an Object type with condition field
|
||||
type ConditionedObject interface {
|
||||
client.Object
|
||||
@@ -192,6 +203,7 @@ func GetDefinition(ctx context.Context, cli client.Reader, definition client.Obj
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -213,12 +225,17 @@ func GetDefinitionFromNamespace(ctx context.Context, cli client.Reader, definiti
|
||||
|
||||
// GetCapabilityDefinition can get different versions of ComponentDefinition/TraitDefinition
|
||||
func GetCapabilityDefinition(ctx context.Context, cli client.Reader, definition client.Object,
|
||||
definitionName string) error {
|
||||
isLatestRevision, defRev, err := fetchDefinitionRev(ctx, cli, definitionName)
|
||||
definitionName string, annotations map[string]string) error {
|
||||
definitionType, err := getDefinitionType(definition)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
isLatestRevision, defRev, err := fetchDefinitionRevision(ctx, cli, definitionName, definitionType, annotations)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isLatestRevision {
|
||||
|
||||
return GetDefinition(ctx, cli, definition, definitionName)
|
||||
}
|
||||
switch def := definition.(type) {
|
||||
@@ -235,7 +252,24 @@ func GetCapabilityDefinition(ctx context.Context, cli client.Reader, definition
|
||||
return nil
|
||||
}
|
||||
|
||||
func fetchDefinitionRev(ctx context.Context, cli client.Reader, definitionName string) (bool, *v1beta1.DefinitionRevision, error) {
|
||||
func getDefinitionType(definition client.Object) (common.DefinitionType, error) {
|
||||
var definitionType common.DefinitionType
|
||||
switch definition.(type) {
|
||||
case *v1beta1.ComponentDefinition:
|
||||
definitionType = common.ComponentType
|
||||
case *v1beta1.TraitDefinition:
|
||||
definitionType = common.TraitType
|
||||
case *v1beta1.PolicyDefinition:
|
||||
definitionType = common.PolicyType
|
||||
case *v1beta1.WorkflowStepDefinition:
|
||||
definitionType = common.WorkflowStepType
|
||||
default:
|
||||
return definitionType, fmt.Errorf("invalid definition type for %v", definition.GetName())
|
||||
}
|
||||
return definitionType, nil
|
||||
}
|
||||
|
||||
func fetchDefinitionRevision(ctx context.Context, cli client.Reader, definitionName string, definitionType common.DefinitionType, annotations map[string]string) (bool, *v1beta1.DefinitionRevision, error) {
|
||||
// if the component's type doesn't contain '@' means user want to use the latest Definition.
|
||||
if !strings.Contains(definitionName, "@") {
|
||||
return true, nil, nil
|
||||
@@ -245,13 +279,93 @@ func fetchDefinitionRev(ctx context.Context, cli client.Reader, definitionName s
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
defName := strings.Split(definitionName, "@")[0]
|
||||
autoUpdate, ok := annotations[oam.AnnotationAutoUpdate]
|
||||
if ok && autoUpdate == "true" {
|
||||
latestRevisionName, err := GetLatestDefinitionRevisionName(ctx, cli.(client.Client), defName, defRevName, definitionType)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
defRevName = latestRevisionName
|
||||
}
|
||||
|
||||
defRev := new(v1beta1.DefinitionRevision)
|
||||
if err := GetDefinition(ctx, cli, defRev, defRevName); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
return false, defRev, nil
|
||||
}
|
||||
|
||||
// GetLatestDefinitionRevisionName returns the latest definition revision name in specified version range.
|
||||
func GetLatestDefinitionRevisionName(ctx context.Context, cli client.Client, definitionName, revisionName string, definitionType common.DefinitionType) (string, error) {
|
||||
for _, ns := range []string{GetDefinitionNamespaceWithCtx(ctx), oam.SystemDefinitionNamespace} {
|
||||
|
||||
revisionListForDefinition, err := fetchAllRevisionsForDefinitionName(ctx, cli, ns, definitionName, definitionType)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
matchedDefinitionRevision, err := getMatchingDefinitionRevision(revisionName, definitionName, revisionListForDefinition, definitionType)
|
||||
if err == nil && matchedDefinitionRevision != "" {
|
||||
return matchedDefinitionRevision, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("error finding definition revision for Name: %v, Type: %v", definitionName, definitionType)
|
||||
|
||||
}
|
||||
|
||||
func fetchAllRevisionsForDefinitionName(ctx context.Context, cli client.Client, ns, definitionName string, definitionType common.DefinitionType) (*v1beta1.DefinitionRevisionList, error) {
|
||||
var listOptions []client.ListOption
|
||||
listOptions = append(listOptions, client.InNamespace(ns),
|
||||
client.MatchingLabels{
|
||||
DefinitionKindToNameLabel[definitionType]: definitionName,
|
||||
})
|
||||
|
||||
revisionList := v1beta1.DefinitionRevisionList{}
|
||||
revisionList.SetGroupVersionKind(schema.GroupVersionKind{
|
||||
Group: v1beta1.Group,
|
||||
Version: v1beta1.Version,
|
||||
Kind: v1beta1.DefinitionRevisionKind,
|
||||
})
|
||||
|
||||
err := cli.List(ctx, &revisionList, listOptions...)
|
||||
|
||||
return &revisionList, err
|
||||
}
|
||||
|
||||
func getMatchingDefinitionRevision(exactRevisionName, definitionName string, revisionList *v1beta1.DefinitionRevisionList, definitionType common.DefinitionType) (string, error) {
|
||||
var definitionVersions []*semver.Version
|
||||
revisionPrefix := exactRevisionName + "."
|
||||
orignalVersions := make(map[string]string)
|
||||
|
||||
for _, revision := range revisionList.Items {
|
||||
if definitionType != "" && definitionType != revision.Spec.DefinitionType {
|
||||
continue
|
||||
}
|
||||
if revision.Name == exactRevisionName {
|
||||
return exactRevisionName, nil
|
||||
}
|
||||
// Only get the revisions that the user expects
|
||||
if strings.HasPrefix(revision.Name, revisionPrefix) {
|
||||
version := strings.Split(revision.Name, definitionName+"-")[1]
|
||||
v, err := semver.NewVersion(version)
|
||||
orignalVersions[v.String()] = version
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
definitionVersions = append(definitionVersions, v)
|
||||
}
|
||||
}
|
||||
if len(definitionVersions) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
sort.Sort(semver.Collection(definitionVersions))
|
||||
latestVersion := definitionVersions[len(definitionVersions)-1]
|
||||
return definitionName + "-" + orignalVersions[latestVersion.String()], nil
|
||||
}
|
||||
|
||||
// ConvertDefinitionRevName can help convert definition type defined in Application to DefinitionRevision Name
|
||||
// e.g., worker@v1.3.1 will be convert to worker-v1.3.1
|
||||
func ConvertDefinitionRevName(definitionName string) (string, error) {
|
||||
|
||||
@@ -980,3 +980,339 @@ func TestXDefinitionNamespaceInCtx(t *testing.T) {
|
||||
assert.Equal(t, tc.expectedNamespace, ns)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetLatestDefinitionRevisionName(t *testing.T) {
|
||||
componetListCli := test.MockClient{MockList: func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
|
||||
defRevisionList := getComponentDefRevisionList()
|
||||
defRevisionList.DeepCopyInto(list.(*v1beta1.DefinitionRevisionList))
|
||||
return nil
|
||||
}}
|
||||
traitListCli := test.MockClient{MockList: func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
|
||||
defRevisionList := getTraitDefRevisionList()
|
||||
defRevisionList.DeepCopyInto(list.(*v1beta1.DefinitionRevisionList))
|
||||
return nil
|
||||
}}
|
||||
|
||||
testcases := []struct {
|
||||
name string
|
||||
inputRevisionName string
|
||||
definitionName string
|
||||
definitionType string
|
||||
expectedDefRevisionName string
|
||||
revisionList *v1beta1.DefinitionRevisionList
|
||||
client client.Client
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "Complete Component version name specified",
|
||||
inputRevisionName: "configmap-component-v1.3.0",
|
||||
definitionName: "configmap-component",
|
||||
definitionType: "Component",
|
||||
expectedDefRevisionName: "configmap-component-v1.3.0",
|
||||
client: &componetListCli,
|
||||
err: nil,
|
||||
}, {
|
||||
name: "Partial Component version name specified",
|
||||
inputRevisionName: "configmap-component-v1.2",
|
||||
definitionName: "configmap-component",
|
||||
definitionType: "Component",
|
||||
expectedDefRevisionName: "configmap-component-v1.2.4",
|
||||
client: &componetListCli,
|
||||
err: nil,
|
||||
}, {
|
||||
name: "Component version not present",
|
||||
inputRevisionName: "configmap-component-v1.6",
|
||||
definitionName: "configmap-component",
|
||||
definitionType: "Component",
|
||||
expectedDefRevisionName: "",
|
||||
client: &componetListCli,
|
||||
err: fmt.Errorf("error finding definition revision for Name: configmap-component, Type: Component"),
|
||||
}, {
|
||||
name: "Complete Trait version name specified",
|
||||
inputRevisionName: "scaler-trait-v1.3.0",
|
||||
definitionName: "scaler-trait",
|
||||
definitionType: "Trait",
|
||||
expectedDefRevisionName: "scaler-trait-v1.3.0",
|
||||
client: &traitListCli,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "Partial Trait version name specified",
|
||||
inputRevisionName: "scaler-trait-v1.2",
|
||||
definitionName: "scaler-trait",
|
||||
definitionType: "Trait",
|
||||
expectedDefRevisionName: "scaler-trait-v1.2.4",
|
||||
client: &traitListCli,
|
||||
err: nil,
|
||||
}, {
|
||||
name: "Trait version name not present",
|
||||
inputRevisionName: "scaler-trait-v1.5",
|
||||
definitionName: "scaler-trait",
|
||||
definitionType: "Trait",
|
||||
expectedDefRevisionName: "",
|
||||
client: &traitListCli,
|
||||
err: fmt.Errorf("error finding definition revision for Name: scaler-trait, Type: Trait"),
|
||||
},
|
||||
}
|
||||
ctx := context.Background()
|
||||
for _, tc := range testcases {
|
||||
defRevisionName, err := util.GetLatestDefinitionRevisionName(ctx, tc.client, tc.definitionName, tc.inputRevisionName, common.DefinitionType(tc.definitionType))
|
||||
assert.Equal(t, defRevisionName, tc.expectedDefRevisionName)
|
||||
assert.Equal(t, err, tc.err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCapabilityDefinitionComponentAutoUpdateEnabled(t *testing.T) {
|
||||
cli := test.MockClient{MockList: func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
|
||||
defRevisionList := getComponentDefRevisionList()
|
||||
defRevisionList.DeepCopyInto(list.(*v1beta1.DefinitionRevisionList))
|
||||
return nil
|
||||
}, MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
componentDefinitionRevision.DeepCopyInto(obj.(*v1beta1.DefinitionRevision))
|
||||
return nil
|
||||
}}
|
||||
annotations := make(map[string]string)
|
||||
annotations[oam.AnnotationAutoUpdate] = "true"
|
||||
definitionName := "configmap-component@v1"
|
||||
ctx := context.Background()
|
||||
definition := new(v1beta1.ComponentDefinition)
|
||||
err := util.GetCapabilityDefinition(ctx, &cli, definition, definitionName, annotations)
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, definition.Spec.Version, "1.0.0")
|
||||
}
|
||||
|
||||
func TestGetCapabilityDefinitionOfTraitAutoUpdateEnabled(t *testing.T) {
|
||||
cli := test.MockClient{MockList: func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
|
||||
defRevisionList := getTraitDefRevisionList()
|
||||
defRevisionList.DeepCopyInto(list.(*v1beta1.DefinitionRevisionList))
|
||||
return nil
|
||||
}, MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
traitDefinitionRevision.DeepCopyInto(obj.(*v1beta1.DefinitionRevision))
|
||||
return nil
|
||||
}}
|
||||
annotations := make(map[string]string)
|
||||
annotations[oam.AnnotationAutoUpdate] = "true"
|
||||
definitionName := "scaler-trait@v1"
|
||||
ctx := context.Background()
|
||||
definition := new(v1beta1.TraitDefinition)
|
||||
err := util.GetCapabilityDefinition(ctx, &cli, definition, definitionName, annotations)
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, definition.Spec.Version, "1.0.0")
|
||||
|
||||
}
|
||||
|
||||
func TestGetCapabilityDefinitionComponentAutoUpdateDisabled(t *testing.T) {
|
||||
cli := test.MockClient{MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
componentDefinitionRevision.Spec.ComponentDefinition.DeepCopyInto(obj.(*v1beta1.ComponentDefinition))
|
||||
return nil
|
||||
}}
|
||||
annotations := make(map[string]string)
|
||||
annotations[oam.AnnotationAutoUpdate] = "false"
|
||||
definitionName := "configmap-component"
|
||||
ctx := context.Background()
|
||||
definition := new(v1beta1.ComponentDefinition)
|
||||
|
||||
err := util.GetCapabilityDefinition(ctx, &cli, definition, definitionName, annotations)
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, definition.Spec.Version, "1.0.0")
|
||||
}
|
||||
|
||||
func TestGetCapabilityDefinitionPolicyAutoUpdateDisabled(t *testing.T) {
|
||||
cli := test.MockClient{MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
policydefinition := &v1beta1.PolicyDefinition{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "mock-policy-definition",
|
||||
Namespace: "vela-system",
|
||||
},
|
||||
}
|
||||
policydefinition.DeepCopyInto(obj.(*v1beta1.PolicyDefinition))
|
||||
return nil
|
||||
}}
|
||||
annotations := make(map[string]string)
|
||||
annotations[oam.AnnotationAutoUpdate] = "false"
|
||||
definitionName := "mock-policy-definition"
|
||||
ctx := context.Background()
|
||||
definition := new(v1beta1.PolicyDefinition)
|
||||
|
||||
err := util.GetCapabilityDefinition(ctx, &cli, definition, definitionName, annotations)
|
||||
assert.Equal(t, err, nil)
|
||||
}
|
||||
|
||||
func TestGetCapabilityDefinitionWorkflowStepAutoUpdateDisabled(t *testing.T) {
|
||||
cli := test.MockClient{MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
workflowStepDefinition := &v1beta1.WorkflowStepDefinition{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "mock-workflow-definition",
|
||||
Namespace: "vela-system",
|
||||
},
|
||||
}
|
||||
workflowStepDefinition.DeepCopyInto(obj.(*v1beta1.WorkflowStepDefinition))
|
||||
return nil
|
||||
}}
|
||||
annotations := make(map[string]string)
|
||||
annotations[oam.AnnotationAutoUpdate] = "false"
|
||||
definitionName := "mock-workflow-definition"
|
||||
ctx := context.Background()
|
||||
definition := new(v1beta1.WorkflowStepDefinition)
|
||||
|
||||
err := util.GetCapabilityDefinition(ctx, &cli, definition, definitionName, annotations)
|
||||
assert.Equal(t, err, nil)
|
||||
}
|
||||
|
||||
func TestGetCapabilityDefinitionInvalidDefinition(t *testing.T) {
|
||||
cli := test.MockClient{MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
workflowStepDefinition := &v1beta1.WorkloadDefinition{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "mock-workload-definition",
|
||||
Namespace: "vela-system",
|
||||
},
|
||||
}
|
||||
workflowStepDefinition.DeepCopyInto(obj.(*v1beta1.WorkloadDefinition))
|
||||
return nil
|
||||
}}
|
||||
annotations := make(map[string]string)
|
||||
annotations[oam.AnnotationAutoUpdate] = "false"
|
||||
definitionName := "mock-workload-definition"
|
||||
ctx := context.Background()
|
||||
definition := new(v1beta1.WorkloadDefinition)
|
||||
definition.ObjectMeta.Name = "mock-workload-definition"
|
||||
err := util.GetCapabilityDefinition(ctx, &cli, definition, definitionName, annotations)
|
||||
assert.Equal(t, err.Error(), "invalid definition type for mock-workload-definition")
|
||||
}
|
||||
|
||||
func TestGetCapabilityDefinitionOfTraitAutoUpdateDisabled(t *testing.T) {
|
||||
cli := test.MockClient{MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
o := new(v1beta1.TraitDefinition)
|
||||
*o = traitDefinitionRevision.Spec.TraitDefinition
|
||||
return nil
|
||||
}}
|
||||
annotations := make(map[string]string)
|
||||
annotations[oam.AnnotationAutoUpdate] = "false"
|
||||
definitionName := "scaler-trait"
|
||||
ctx := context.Background()
|
||||
definition := new(v1beta1.TraitDefinition)
|
||||
err := util.GetCapabilityDefinition(ctx, &cli, definition, definitionName, annotations)
|
||||
assert.Equal(t, err, nil)
|
||||
|
||||
}
|
||||
|
||||
func getComponentDefRevisionList() v1beta1.DefinitionRevisionList {
|
||||
compDefRevision1 := componentDefinitionRevision.DeepCopy()
|
||||
compDefRevision1.Spec.ComponentDefinition.Spec.Version = "1.2.0"
|
||||
compDefRevision1.Name = "configmap-component-v1.2.0"
|
||||
|
||||
compDefRevision2 := componentDefinitionRevision.DeepCopy()
|
||||
compDefRevision2.Spec.ComponentDefinition.Spec.Version = "1.2.4"
|
||||
compDefRevision2.Name = "configmap-component-v1.2.4"
|
||||
|
||||
compDefRevision3 := componentDefinitionRevision.DeepCopy()
|
||||
compDefRevision3.Spec.ComponentDefinition.Spec.Version = "1.3.0"
|
||||
compDefRevision3.Name = "configmap-component-v1.3.0"
|
||||
|
||||
compRevisionList := v1beta1.DefinitionRevisionList{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "DefinitionRevision",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
Items: []v1beta1.DefinitionRevision{
|
||||
*compDefRevision1, *compDefRevision2, *compDefRevision3,
|
||||
},
|
||||
}
|
||||
return compRevisionList
|
||||
}
|
||||
|
||||
func getTraitDefRevisionList() v1beta1.DefinitionRevisionList {
|
||||
traitDefRevision1 := traitDefinitionRevision.DeepCopy()
|
||||
traitDefRevision1.Spec.TraitDefinition.Spec.Version = "1.2.0"
|
||||
traitDefRevision1.Name = "scaler-trait-v1.2.0"
|
||||
|
||||
traitDefRevision2 := traitDefinitionRevision.DeepCopy()
|
||||
traitDefRevision2.Spec.TraitDefinition.Spec.Version = "1.2.4"
|
||||
traitDefRevision2.Name = "scaler-trait-v1.2.4"
|
||||
|
||||
traitDefRevision3 := traitDefinitionRevision.DeepCopy()
|
||||
traitDefRevision3.Spec.TraitDefinition.Spec.Version = "1.3.0"
|
||||
traitDefRevision3.Name = "scaler-trait-v1.3.0"
|
||||
|
||||
traitRevisionList := v1beta1.DefinitionRevisionList{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "DefinitionRevision",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
Items: []v1beta1.DefinitionRevision{
|
||||
*traitDefRevision1, *traitDefRevision2, *traitDefRevision3,
|
||||
},
|
||||
}
|
||||
return traitRevisionList
|
||||
}
|
||||
|
||||
var traitDefinitionRevision = v1beta1.DefinitionRevision{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "DefinitionRevision",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "scaler-trait",
|
||||
Labels: map[string]string{
|
||||
"trait.oam.dev/name": "scaler-trait",
|
||||
},
|
||||
},
|
||||
Spec: v1beta1.DefinitionRevisionSpec{
|
||||
Revision: 1,
|
||||
RevisionHash: "5ceecfbe58dde83a",
|
||||
DefinitionType: "Trait",
|
||||
TraitDefinition: v1beta1.TraitDefinition{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "TraitDefinition",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "scaler-trait",
|
||||
},
|
||||
Spec: v1beta1.TraitDefinitionSpec{
|
||||
Version: "1.0.0",
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// debug unit tests
|
||||
var componentDefinitionRevision = v1beta1.DefinitionRevision{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "DefinitionRevision",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "configmap-component",
|
||||
Labels: map[string]string{
|
||||
"componentdefinition.oam.dev/name": "configmap-component",
|
||||
},
|
||||
},
|
||||
Spec: v1beta1.DefinitionRevisionSpec{
|
||||
Revision: 1,
|
||||
RevisionHash: "5ceecfbe58dde83a",
|
||||
DefinitionType: "Component",
|
||||
ComponentDefinition: v1beta1.ComponentDefinition{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ComponentDefinition",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "configmap-component",
|
||||
},
|
||||
Spec: v1beta1.ComponentDefinitionSpec{
|
||||
Version: "1.0.0",
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -398,18 +398,23 @@ func DeleteManagedResourceInApplication(ctx context.Context, cli client.Client,
|
||||
}
|
||||
util.RemoveAnnotations(obj, []string{oam.AnnotationAppSharedBy})
|
||||
}
|
||||
if mr.SkipGC || hasOrphanFinalizer(app) {
|
||||
|
||||
var opts []client.DeleteOption
|
||||
var isOrphan bool
|
||||
|
||||
if garbageCollectPolicy, _ := policy.ParsePolicy[v1alpha1.GarbageCollectPolicySpec](app); garbageCollectPolicy != nil {
|
||||
isOrphan, opts = garbageCollectPolicy.FindDeleteOption(obj)
|
||||
}
|
||||
|
||||
if mr.SkipGC || hasOrphanFinalizer(app) || isOrphan {
|
||||
if labels := obj.GetLabels(); labels != nil {
|
||||
delete(labels, oam.LabelAppName)
|
||||
delete(labels, oam.LabelAppNamespace)
|
||||
obj.SetLabels(labels)
|
||||
}
|
||||
return errors.Wrapf(cli.Update(_ctx, obj), "failed to remove owner labels for resource while skipping gc")
|
||||
}
|
||||
var opts []client.DeleteOption
|
||||
if garbageCollectPolicy, _ := policy.ParsePolicy[v1alpha1.GarbageCollectPolicySpec](app); garbageCollectPolicy != nil {
|
||||
opts = garbageCollectPolicy.FindDeleteOption(obj)
|
||||
return errors.Wrapf(cli.Update(_ctx, obj), "skipping deletion for resource")
|
||||
}
|
||||
|
||||
if err := cli.Delete(_ctx, obj, opts...); err != nil && !kerrors.IsNotFound(err) {
|
||||
return errors.Wrapf(err, "failed to delete resource %s", mr.ResourceKey())
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ func LoadDataFromPath(ctx context.Context, path string, pathFilter func(string)
|
||||
}
|
||||
bs, e := os.ReadFile(filepath.Clean(path))
|
||||
if e != nil {
|
||||
return nil, fmt.Errorf("failed to read file %s: %w", path, err)
|
||||
return nil, fmt.Errorf("failed to read file %s: %w", path, e)
|
||||
}
|
||||
return []FileData{{Path: path, Data: bs}}, nil
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ import (
|
||||
|
||||
"github.com/kubevela/pkg/cue/cuex"
|
||||
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
|
||||
"github.com/kubevela/workflow/pkg/cue/model/sets"
|
||||
"github.com/kubevela/workflow/pkg/cue/model/value"
|
||||
providertypes "github.com/kubevela/workflow/pkg/providers/types"
|
||||
|
||||
@@ -128,20 +127,9 @@ func ValidateView(ctx context.Context, viewStr string) error {
|
||||
|
||||
// Make sure `status` or `export` field exists
|
||||
vStatus := val.LookupPath(cue.ParsePath(DefaultExportValue))
|
||||
errStatus := vStatus.Err()
|
||||
vExport := val.LookupPath(cue.ParsePath(KeyWordExport))
|
||||
errExport := vExport.Err()
|
||||
if errStatus != nil && errExport != nil {
|
||||
return errors.Errorf("no `status` or `export` field found in view: %v, %v", errStatus, errExport)
|
||||
}
|
||||
if errStatus == nil {
|
||||
_, errStatus = sets.ToString(vStatus)
|
||||
}
|
||||
if errExport == nil {
|
||||
_, errExport = sets.ToString(vExport)
|
||||
}
|
||||
if errStatus != nil && errExport != nil {
|
||||
return errors.Errorf("connot get string from` status` or `export`: %v, %v", errStatus, errExport)
|
||||
if !vStatus.Exists() && !vExport.Exists() {
|
||||
return errors.Errorf("no `status` or `export` field found in view")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/webhook/core.oam.dev/v1beta1/componentdefinition"
|
||||
"github.com/oam-dev/kubevela/pkg/webhook/core.oam.dev/v1beta1/policydefinition"
|
||||
"github.com/oam-dev/kubevela/pkg/webhook/core.oam.dev/v1beta1/traitdefinition"
|
||||
"github.com/oam-dev/kubevela/pkg/webhook/core.oam.dev/v1beta1/workflowstepdefinition"
|
||||
)
|
||||
|
||||
// Register will be called in main and register all validation handlers
|
||||
@@ -35,6 +36,7 @@ func Register(mgr manager.Manager, args controller.Args) {
|
||||
componentdefinition.RegisterValidatingHandler(mgr)
|
||||
traitdefinition.RegisterValidatingHandler(mgr, args)
|
||||
policydefinition.RegisterValidatingHandler(mgr)
|
||||
workflowstepdefinition.RegisterValidatingHandler(mgr)
|
||||
server := mgr.GetWebhookServer()
|
||||
server.Register("/convert", conversion.NewWebhookHandler(mgr.GetScheme()))
|
||||
}
|
||||
|
||||
@@ -66,6 +66,10 @@ func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) a
|
||||
if err := h.Decoder.Decode(req, app); err != nil {
|
||||
return admission.Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
if req.Namespace != "" {
|
||||
app.Namespace = req.Namespace
|
||||
}
|
||||
|
||||
ctx = util.SetNamespaceInCtx(ctx, app.Namespace)
|
||||
switch req.Operation {
|
||||
case admissionv1.Create:
|
||||
|
||||
@@ -207,4 +207,52 @@ var _ = Describe("Test Application Validator", func() {
|
||||
resp := handler.Handle(ctx, req)
|
||||
Expect(resp.Allowed).Should(BeFalse())
|
||||
})
|
||||
|
||||
It("Test Application with PublishVersion and Autoupdate annotations", func() {
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: metav1.GroupVersionResource{Group: "core.oam.dev", Version: "v1alpha2", Resource: "applications"},
|
||||
Object: runtime.RawExtension{
|
||||
Raw: []byte(`
|
||||
{"apiVersion":"core.oam.dev/v1beta1","kind":"Application","metadata":{"name":"workflow-timeout","namespace":"default","annotations":{"app.oam.dev/publishVersion":"v1.0.0","app.oam.dev/autoUpdate":"true"}},"spec":{"components":[{"name":"comp","type":"worker","properties":{"image":"crccheck/hello-world"}}],"workflow":{"steps":[{"name":"group","type":"suspend","timeout":"1s"}]}}}
|
||||
`),
|
||||
},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(ctx, req)
|
||||
Expect(resp.Allowed).Should(BeFalse())
|
||||
})
|
||||
|
||||
It("Test Application Publishversion Annotation", func() {
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: metav1.GroupVersionResource{Group: "core.oam.dev", Version: "v1alpha2", Resource: "applications"},
|
||||
Object: runtime.RawExtension{
|
||||
Raw: []byte(`
|
||||
{"apiVersion":"core.oam.dev/v1beta1","kind":"Application","metadata":{"name":"workflow-timeout","namespace":"default","annotations":{"app.oam.dev/publishVersion":"v1.0.0"}},"spec":{"components":[{"name":"comp","type":"worker","properties":{"image":"crccheck/hello-world"}}],"workflow":{"steps":[{"name":"group","type":"suspend","timeout":"1s"}]}}}
|
||||
`),
|
||||
},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(ctx, req)
|
||||
Expect(resp.Allowed).Should(BeTrue())
|
||||
})
|
||||
|
||||
It("Test Application Autoupdate Annotation", func() {
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: metav1.GroupVersionResource{Group: "core.oam.dev", Version: "v1alpha2", Resource: "applications"},
|
||||
Object: runtime.RawExtension{
|
||||
Raw: []byte(`
|
||||
{"apiVersion":"core.oam.dev/v1beta1","kind":"Application","metadata":{"name":"workflow-timeout","namespace":"default","annotations":{"app.oam.dev/autoUpdate":"true"}},"spec":{"components":[{"name":"comp","type":"worker","properties":{"image":"crccheck/hello-world"}}],"workflow":{"steps":[{"name":"group","type":"suspend","timeout":"1s"}]}}}
|
||||
`),
|
||||
},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(ctx, req)
|
||||
Expect(resp.Allowed).Should(BeTrue())
|
||||
})
|
||||
})
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user