mirror of
https://github.com/kubevela/kubevela.git
synced 2026-03-02 09:40:51 +00:00
Compare commits
67 Commits
v1.4.0-alp
...
release-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37685430b2 | ||
|
|
978bec227c | ||
|
|
e3e6d57b2a | ||
|
|
813a7534f2 | ||
|
|
f8f75a3b64 | ||
|
|
8bad1fc055 | ||
|
|
4569850740 | ||
|
|
54477eabf5 | ||
|
|
43bbc97319 | ||
|
|
cbed2b5cb3 | ||
|
|
8be75545bc | ||
|
|
d748096f7c | ||
|
|
d4ab93c232 | ||
|
|
37a656a292 | ||
|
|
3c94ac1bc1 | ||
|
|
8499dffcd7 | ||
|
|
30a6e85023 | ||
|
|
11530e2720 | ||
|
|
f53466bc7d | ||
|
|
e8ea8ec48f | ||
|
|
6c4c9bdf7e | ||
|
|
e7930a2da0 | ||
|
|
45e1de19dc | ||
|
|
d910bb7928 | ||
|
|
a580c9a44c | ||
|
|
8f5eaefd89 | ||
|
|
7c3a35ae87 | ||
|
|
ea0003f7cb | ||
|
|
3728857c82 | ||
|
|
8e6c49cb37 | ||
|
|
4b31274bda | ||
|
|
429e62d11b | ||
|
|
841a18189a | ||
|
|
59bd066c05 | ||
|
|
efa9dedb85 | ||
|
|
fdffde4dfd | ||
|
|
d08aa7d12c | ||
|
|
f9755a405f | ||
|
|
d751d95bac | ||
|
|
e86eec07e0 | ||
|
|
4abb5c6ced | ||
|
|
32d9a9ec94 | ||
|
|
f6f9ef4ded | ||
|
|
166c93d548 | ||
|
|
8f767068bf | ||
|
|
8d9e2a71e7 | ||
|
|
58b3bca537 | ||
|
|
825f1aaa22 | ||
|
|
82075427e6 | ||
|
|
f89cf673c0 | ||
|
|
ce53f6922f | ||
|
|
b6f70d9a3c | ||
|
|
64d063ccfe | ||
|
|
a98278fb7a | ||
|
|
0553d603e6 | ||
|
|
a36e99308f | ||
|
|
947bac2d35 | ||
|
|
7644cc59cb | ||
|
|
89a441b8ce | ||
|
|
780572c68f | ||
|
|
a13cab65b2 | ||
|
|
e26104adcc | ||
|
|
26ac584655 | ||
|
|
482976990d | ||
|
|
bc4812a12e | ||
|
|
58c2208e2a | ||
|
|
f83d88cfb0 |
89
.github/workflows/chart.yaml
vendored
Normal file
89
.github/workflows/chart.yaml
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
name: Publish Chart
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
workflow_dispatch: { }
|
||||
|
||||
env:
|
||||
BUCKET: ${{ secrets.OSS_BUCKET }}
|
||||
ENDPOINT: ${{ secrets.OSS_ENDPOINT }}
|
||||
ACCESS_KEY: ${{ secrets.OSS_ACCESS_KEY }}
|
||||
ACCESS_KEY_SECRET: ${{ secrets.OSS_ACCESS_KEY_SECRET }}
|
||||
ARTIFACT_HUB_REPOSITORY_ID: ${{ secrets.ARTIFACT_HUB_REPOSITORY_ID }}
|
||||
|
||||
jobs:
|
||||
publish-charts:
|
||||
env:
|
||||
HELM_CHARTS_DIR: charts
|
||||
HELM_CHART: charts/vela-core
|
||||
MINIMAL_HELM_CHART: charts/vela-minimal
|
||||
LEGACY_HELM_CHART: legacy/charts/vela-core-legacy
|
||||
VELA_ROLLOUT_HELM_CHART: runtime/rollout/charts
|
||||
LOCAL_OSS_DIRECTORY: .oss/
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Get git revision
|
||||
id: vars
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::set-output name=git_revision::$(git rev-parse --short HEAD)"
|
||||
- name: Install Helm
|
||||
uses: azure/setup-helm@v1
|
||||
with:
|
||||
version: v3.4.0
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '14'
|
||||
- name: Generate helm doc
|
||||
run: |
|
||||
make helm-doc-gen
|
||||
- name: Prepare legacy chart
|
||||
run: |
|
||||
rsync -r $LEGACY_HELM_CHART $HELM_CHARTS_DIR
|
||||
rsync -r $HELM_CHART/* $LEGACY_HELM_CHART --exclude=Chart.yaml --exclude=crds
|
||||
- name: Prepare vela chart
|
||||
run: |
|
||||
rsync -r $VELA_ROLLOUT_HELM_CHART $HELM_CHARTS_DIR
|
||||
- name: Get the version
|
||||
id: get_version
|
||||
run: |
|
||||
VERSION=${GITHUB_REF#refs/tags/}
|
||||
echo ::set-output name=VERSION::${VERSION}
|
||||
- name: Tag helm chart image
|
||||
run: |
|
||||
image_tag=${{ steps.get_version.outputs.VERSION }}
|
||||
chart_version=${{ steps.get_version.outputs.VERSION }}
|
||||
sed -i "s/latest/${image_tag}/g" $HELM_CHART/values.yaml
|
||||
sed -i "s/latest/${image_tag}/g" $MINIMAL_HELM_CHART/values.yaml
|
||||
sed -i "s/latest/${image_tag}/g" $LEGACY_HELM_CHART/values.yaml
|
||||
sed -i "s/latest/${image_tag}/g" $VELA_ROLLOUT_HELM_CHART/values.yaml
|
||||
chart_smever=${chart_version#"v"}
|
||||
sed -i "s/0.1.0/$chart_smever/g" $HELM_CHART/Chart.yaml
|
||||
sed -i "s/0.1.0/$chart_smever/g" $MINIMAL_HELM_CHART/Chart.yaml
|
||||
sed -i "s/0.1.0/$chart_smever/g" $LEGACY_HELM_CHART/Chart.yaml
|
||||
sed -i "s/0.1.0/$chart_smever/g" $VELA_ROLLOUT_HELM_CHART/Chart.yaml
|
||||
- name: Install ossutil
|
||||
run: wget http://gosspublic.alicdn.com/ossutil/1.7.0/ossutil64 && chmod +x ossutil64 && mv ossutil64 ossutil
|
||||
- name: Configure Alibaba Cloud OSSUTIL
|
||||
run: ./ossutil --config-file .ossutilconfig config -i ${ACCESS_KEY} -k ${ACCESS_KEY_SECRET} -e ${ENDPOINT} -c .ossutilconfig
|
||||
- name: sync cloud to local
|
||||
run: ./ossutil --config-file .ossutilconfig sync oss://$BUCKET/core $LOCAL_OSS_DIRECTORY
|
||||
- name: add artifacthub stuff to the repo
|
||||
run: |
|
||||
rsync $HELM_CHART/README.md $LEGACY_HELM_CHART/README.md
|
||||
rsync $HELM_CHART/README.md $VELA_ROLLOUT_HELM_CHART/README.md
|
||||
sed -i "s/ARTIFACT_HUB_REPOSITORY_ID/$ARTIFACT_HUB_REPOSITORY_ID/g" hack/artifacthub/artifacthub-repo.yml
|
||||
rsync hack/artifacthub/artifacthub-repo.yml $LOCAL_OSS_DIRECTORY
|
||||
- name: Package helm charts
|
||||
run: |
|
||||
helm package $HELM_CHART --destination $LOCAL_OSS_DIRECTORY
|
||||
helm package $MINIMAL_HELM_CHART --destination $LOCAL_OSS_DIRECTORY
|
||||
helm package $LEGACY_HELM_CHART --destination $LOCAL_OSS_DIRECTORY
|
||||
helm package $VELA_ROLLOUT_HELM_CHART --destination $LOCAL_OSS_DIRECTORY
|
||||
helm repo index --url https://$BUCKET.$ENDPOINT/core $LOCAL_OSS_DIRECTORY
|
||||
- name: sync local to cloud
|
||||
run: ./ossutil --config-file .ossutilconfig sync $LOCAL_OSS_DIRECTORY oss://$BUCKET/core -f -u
|
||||
2
.github/workflows/go.yml
vendored
2
.github/workflows/go.yml
vendored
@@ -57,7 +57,7 @@ jobs:
|
||||
restore-keys: ${{ runner.os }}-pkg-
|
||||
|
||||
- name: Install StaticCheck
|
||||
run: GO111MODULE=off go get honnef.co/go/tools/cmd/staticcheck
|
||||
run: GO111MODULE=on go get honnef.co/go/tools/cmd/staticcheck@v0.3.0
|
||||
|
||||
- name: Static Check
|
||||
run: staticcheck ./...
|
||||
|
||||
166
.github/workflows/registry.yml
vendored
166
.github/workflows/registry.yml
vendored
@@ -8,14 +8,11 @@ on:
|
||||
workflow_dispatch: {}
|
||||
|
||||
env:
|
||||
BUCKET: ${{ secrets.OSS_BUCKET }}
|
||||
ENDPOINT: ${{ secrets.OSS_ENDPOINT }}
|
||||
ACCESS_KEY: ${{ secrets.OSS_ACCESS_KEY }}
|
||||
ACCESS_KEY_SECRET: ${{ secrets.OSS_ACCESS_KEY_SECRET }}
|
||||
ARTIFACT_HUB_REPOSITORY_ID: ${{ secrets.ARTIFACT_HUB_REPOSITORY_ID }}
|
||||
|
||||
jobs:
|
||||
publish-images:
|
||||
publish-core-images:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
@@ -47,20 +44,16 @@ jobs:
|
||||
- name: Login Alibaba Cloud ACR
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
registry: kubevela-registry.cn-hangzhou.cr.aliyuncs.com
|
||||
username: ${{ secrets.ACR_USERNAME }}@aliyun-inner.com
|
||||
registry: ${{ secrets.ACR_DOMAIN }}
|
||||
username: ${{ secrets.ACR_USERNAME }}
|
||||
password: ${{ secrets.ACR_PASSWORD }}
|
||||
- uses: docker/setup-qemu-action@v1
|
||||
- uses: docker/setup-buildx-action@v1
|
||||
with:
|
||||
driver-opts: image=moby/buildkit:master
|
||||
|
||||
- name: Build & Pushing vela-core for ACR
|
||||
run: |
|
||||
docker build --build-arg GOPROXY=https://proxy.golang.org --build-arg VERSION=${{ steps.get_version.outputs.VERSION }} --build-arg GITVERSION=git-${{ steps.vars.outputs.git_revision }} -t kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-core:${{ steps.get_version.outputs.VERSION }} .
|
||||
docker push kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-core:${{ steps.get_version.outputs.VERSION }}
|
||||
- uses: docker/build-push-action@v2
|
||||
name: Build & Pushing vela-core for Dockerhub and GHCR
|
||||
name: Build & Pushing vela-core for Dockerhub, GHCR and ACR
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile
|
||||
@@ -75,14 +68,51 @@ jobs:
|
||||
GOPROXY=https://proxy.golang.org
|
||||
tags: |-
|
||||
docker.io/oamdev/vela-core:${{ steps.get_version.outputs.VERSION }}
|
||||
ghcr.io/${{ github.repository }}/vela-core:${{ steps.get_version.outputs.VERSION }}
|
||||
ghcr.io/${{ github.repository_owner }}/oamdev/vela-core:${{ steps.get_version.outputs.VERSION }}
|
||||
${{ secrets.ACR_DOMAIN }}/oamdev/vela-core:${{ steps.get_version.outputs.VERSION }}
|
||||
|
||||
- name: Build & Pushing vela-apiserver for ACR
|
||||
publish-addon-images:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Get the version
|
||||
id: get_version
|
||||
run: |
|
||||
docker build --build-arg GOPROXY=https://proxy.golang.org --build-arg VERSION=${{ steps.get_version.outputs.VERSION }} --build-arg GITVERSION=git-${{ steps.vars.outputs.git_revision }} -t kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-apiserver:${{ steps.get_version.outputs.VERSION }} -f Dockerfile.apiserver .
|
||||
docker push kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-apiserver:${{ steps.get_version.outputs.VERSION }}
|
||||
VERSION=${GITHUB_REF#refs/tags/}
|
||||
if [[ ${GITHUB_REF} == "refs/heads/master" ]]; then
|
||||
VERSION=latest
|
||||
fi
|
||||
echo ::set-output name=VERSION::${VERSION}
|
||||
- name: Get git revision
|
||||
id: vars
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::set-output name=git_revision::$(git rev-parse --short HEAD)"
|
||||
- name: Login ghcr.io
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Login docker.io
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- name: Login Alibaba Cloud ACR
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
registry: ${{ secrets.ACR_DOMAIN }}
|
||||
username: ${{ secrets.ACR_USERNAME }}
|
||||
password: ${{ secrets.ACR_PASSWORD }}
|
||||
- uses: docker/setup-qemu-action@v1
|
||||
- uses: docker/setup-buildx-action@v1
|
||||
with:
|
||||
driver-opts: image=moby/buildkit:master
|
||||
|
||||
- uses: docker/build-push-action@v2
|
||||
name: Build & Pushing vela-apiserver for Dockerhub and GHCR
|
||||
name: Build & Pushing vela-apiserver for Dockerhub, GHCR and ACR
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile.apiserver
|
||||
@@ -97,14 +127,10 @@ jobs:
|
||||
GOPROXY=https://proxy.golang.org
|
||||
tags: |-
|
||||
docker.io/oamdev/vela-apiserver:${{ steps.get_version.outputs.VERSION }}
|
||||
ghcr.io/${{ github.repository }}/vela-apiserver:${{ steps.get_version.outputs.VERSION }}
|
||||
|
||||
- name: Build & Pushing vela runtime rollout for ACR
|
||||
run: |
|
||||
docker build --build-arg GOPROXY=https://proxy.golang.org --build-arg VERSION=${{ steps.get_version.outputs.VERSION }} --build-arg GITVERSION=git-${{ steps.vars.outputs.git_revision }} -t kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-rollout:${{ steps.get_version.outputs.VERSION }} .
|
||||
docker push kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-rollout:${{ steps.get_version.outputs.VERSION }}
|
||||
ghcr.io/${{ github.repository_owner }}/oamdev/vela-apiserver:${{ steps.get_version.outputs.VERSION }}
|
||||
${{ secrets.ACR_DOMAIN }}/oamdev/vela-apiserver:${{ steps.get_version.outputs.VERSION }}
|
||||
- uses: docker/build-push-action@v2
|
||||
name: Build & Pushing runtime rollout for Dockerhub and GHCR
|
||||
name: Build & Pushing runtime rollout Dockerhub, GHCR and ACR
|
||||
with:
|
||||
context: .
|
||||
file: runtime/rollout/Dockerfile
|
||||
@@ -119,96 +145,8 @@ jobs:
|
||||
GOPROXY=https://proxy.golang.org
|
||||
tags: |-
|
||||
docker.io/oamdev/vela-rollout:${{ steps.get_version.outputs.VERSION }}
|
||||
ghcr.io/${{ github.repository }}/vela-rollout:${{ steps.get_version.outputs.VERSION }}
|
||||
|
||||
publish-charts:
|
||||
env:
|
||||
HELM_CHARTS_DIR: charts
|
||||
HELM_CHART: charts/vela-core
|
||||
MINIMAL_HELM_CHART: charts/vela-minimal
|
||||
LEGACY_HELM_CHART: legacy/charts/vela-core-legacy
|
||||
OAM_RUNTIME_HELM_CHART: charts/oam-runtime
|
||||
VELA_ROLLOUT_HELM_CHART: runtime/rollout/charts
|
||||
LOCAL_OSS_DIRECTORY: .oss/
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Get git revision
|
||||
id: vars
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::set-output name=git_revision::$(git rev-parse --short HEAD)"
|
||||
- name: Install Helm
|
||||
uses: azure/setup-helm@v1
|
||||
with:
|
||||
version: v3.4.0
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '14'
|
||||
- name: Generate helm doc
|
||||
run: |
|
||||
make helm-doc-gen
|
||||
- name: Prepare legacy chart
|
||||
run: |
|
||||
rsync -r $LEGACY_HELM_CHART $HELM_CHARTS_DIR
|
||||
rsync -r $HELM_CHART/* $LEGACY_HELM_CHART --exclude=Chart.yaml --exclude=crds
|
||||
- name: Prepare vela chart
|
||||
run: |
|
||||
rsync -r $VELA_ROLLOUT_HELM_CHART $HELM_CHARTS_DIR
|
||||
- uses: oprypin/find-latest-tag@v1
|
||||
with:
|
||||
repository: oam-dev/kubevela
|
||||
releases-only: true
|
||||
id: latest_tag
|
||||
- name: Tag helm chart image
|
||||
run: |
|
||||
latest_repo_tag=${{ steps.latest_tag.outputs.tag }}
|
||||
sub="."
|
||||
major="$(cut -d"$sub" -f1 <<<"$latest_repo_tag")"
|
||||
minor="$(cut -d"$sub" -f2 <<<"$latest_repo_tag")"
|
||||
patch="0"
|
||||
current_repo_tag="$major.$minor.$patch"
|
||||
image_tag=${GITHUB_REF#refs/tags/}
|
||||
chart_version=$latest_repo_tag
|
||||
if [[ ${GITHUB_REF} == "refs/heads/master" ]]; then
|
||||
image_tag=latest
|
||||
chart_version=${current_repo_tag}-nightly-build
|
||||
fi
|
||||
sed -i "s/latest/${image_tag}/g" $HELM_CHART/values.yaml
|
||||
sed -i "s/latest/${image_tag}/g" $MINIMAL_HELM_CHART/values.yaml
|
||||
sed -i "s/latest/${image_tag}/g" $LEGACY_HELM_CHART/values.yaml
|
||||
sed -i "s/latest/${image_tag}/g" $OAM_RUNTIME_HELM_CHART/values.yaml
|
||||
sed -i "s/latest/${image_tag}/g" $VELA_ROLLOUT_HELM_CHART/values.yaml
|
||||
chart_smever=${chart_version#"v"}
|
||||
sed -i "s/0.1.0/$chart_smever/g" $HELM_CHART/Chart.yaml
|
||||
sed -i "s/0.1.0/$chart_smever/g" $MINIMAL_HELM_CHART/Chart.yaml
|
||||
sed -i "s/0.1.0/$chart_smever/g" $LEGACY_HELM_CHART/Chart.yaml
|
||||
sed -i "s/0.1.0/$chart_smever/g" $OAM_RUNTIME_HELM_CHART/Chart.yaml
|
||||
sed -i "s/0.1.0/$chart_smever/g" $VELA_ROLLOUT_HELM_CHART/Chart.yaml
|
||||
- name: Install ossutil
|
||||
run: wget http://gosspublic.alicdn.com/ossutil/1.7.0/ossutil64 && chmod +x ossutil64 && mv ossutil64 ossutil
|
||||
- name: Configure Alibaba Cloud OSSUTIL
|
||||
run: ./ossutil --config-file .ossutilconfig config -i ${ACCESS_KEY} -k ${ACCESS_KEY_SECRET} -e ${ENDPOINT} -c .ossutilconfig
|
||||
- name: sync cloud to local
|
||||
run: ./ossutil --config-file .ossutilconfig sync oss://$BUCKET/core $LOCAL_OSS_DIRECTORY
|
||||
- name: add artifacthub stuff to the repo
|
||||
run: |
|
||||
rsync $HELM_CHART/README.md $LEGACY_HELM_CHART/README.md
|
||||
rsync $HELM_CHART/README.md $OAM_RUNTIME_HELM_CHART/README.md
|
||||
rsync $HELM_CHART/README.md $VELA_ROLLOUT_HELM_CHART/README.md
|
||||
sed -i "s/ARTIFACT_HUB_REPOSITORY_ID/$ARTIFACT_HUB_REPOSITORY_ID/g" hack/artifacthub/artifacthub-repo.yml
|
||||
rsync hack/artifacthub/artifacthub-repo.yml $LOCAL_OSS_DIRECTORY
|
||||
- name: Package helm charts
|
||||
run: |
|
||||
helm package $HELM_CHART --destination $LOCAL_OSS_DIRECTORY
|
||||
helm package $MINIMAL_HELM_CHART --destination $LOCAL_OSS_DIRECTORY
|
||||
helm package $LEGACY_HELM_CHART --destination $LOCAL_OSS_DIRECTORY
|
||||
helm package $OAM_RUNTIME_HELM_CHART --destination $LOCAL_OSS_DIRECTORY
|
||||
helm package $VELA_ROLLOUT_HELM_CHART --destination $LOCAL_OSS_DIRECTORY
|
||||
helm repo index --url https://$BUCKET.$ENDPOINT/core $LOCAL_OSS_DIRECTORY
|
||||
- name: sync local to cloud
|
||||
run: ./ossutil --config-file .ossutilconfig sync $LOCAL_OSS_DIRECTORY oss://$BUCKET/core -f
|
||||
ghcr.io/${{ github.repository_owner }}/oamdev/vela-rollout:${{ steps.get_version.outputs.VERSION }}
|
||||
${{ secrets.ACR_DOMAIN }}/oamdev/vela-rollout:${{ steps.get_version.outputs.VERSION }}
|
||||
|
||||
publish-capabilities:
|
||||
env:
|
||||
@@ -227,4 +165,4 @@ jobs:
|
||||
- name: rsync all capabilites
|
||||
run: rsync vela-templates/registry/auto-gen/* $CAPABILITY_DIR
|
||||
- name: sync local to cloud
|
||||
run: ./ossutil --config-file .ossutilconfig sync $CAPABILITY_DIR oss://$CAPABILITY_BUCKET -f
|
||||
run: ./ossutil --config-file .ossutilconfig sync $CAPABILITY_DIR oss://$CAPABILITY_BUCKET -f -u
|
||||
21
.github/workflows/release.yml
vendored
21
.github/workflows/release.yml
vendored
@@ -8,6 +8,10 @@ on:
|
||||
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BUCKET: ${{ secrets.CLI_OSS_BUCKET }}
|
||||
ENDPOINT: ${{ secrets.CLI_OSS_ENDPOINT }}
|
||||
ACCESS_KEY: ${{ secrets.CLI_OSS_ACCESS_KEY }}
|
||||
ACCESS_KEY_SECRET: ${{ secrets.CLI_OSS_ACCESS_KEY_SECRET }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -104,6 +108,23 @@ jobs:
|
||||
name: sha256sums
|
||||
path: ./_bin/sha256-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.txt
|
||||
retention-days: 1
|
||||
- name: clear the asset
|
||||
run: |
|
||||
rm -rf ./_bin/vela/${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}
|
||||
mv ./_bin/vela/vela-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.tar.gz ./_bin/vela/vela-${{ env.VELA_VERSION }}-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.tar.gz
|
||||
mv ./_bin/vela/vela-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.zip ./_bin/vela/vela-${{ env.VELA_VERSION }}-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.zip
|
||||
- name: Install ossutil
|
||||
run: wget http://gosspublic.alicdn.com/ossutil/1.7.0/ossutil64 && chmod +x ossutil64 && mv ossutil64 ossutil
|
||||
- name: Configure Alibaba Cloud OSSUTIL
|
||||
run: ./ossutil --config-file .ossutilconfig config -i ${ACCESS_KEY} -k ${ACCESS_KEY_SECRET} -e ${ENDPOINT} -c .ossutilconfig
|
||||
- name: sync local to cloud
|
||||
run: ./ossutil --config-file .ossutilconfig sync ./_bin/vela oss://$BUCKET/binary/vela/${{ env.VELA_VERSION }}
|
||||
|
||||
- name: sync the latest version file
|
||||
run: |
|
||||
echo ${{ env.VELA_VERSION }} > ./latest_version
|
||||
./ossutil --config-file .ossutilconfig cp -u ./latest_version oss://$BUCKET/binary/vela/latest_version
|
||||
|
||||
|
||||
upload-plugin-homebrew:
|
||||
needs: build
|
||||
|
||||
@@ -10,7 +10,6 @@ Reviewers:
|
||||
- devholic
|
||||
- fourierr
|
||||
- JooKS-me
|
||||
- s4rd1nh4
|
||||
|
||||
Approvers:
|
||||
- Somefive (Multi-Cluster)
|
||||
|
||||
@@ -45,13 +45,12 @@ type GarbageCollectPolicyRule struct {
|
||||
}
|
||||
|
||||
// GarbageCollectPolicyRuleSelector select the targets of the rule
|
||||
// if both traitTypes, oamTypes and componentTypes are specified, combination logic is OR
|
||||
// if both traitTypes and componentTypes are specified, combination logic is OR
|
||||
// if one resource is specified with conflict strategies, strategy as component go first.
|
||||
type GarbageCollectPolicyRuleSelector struct {
|
||||
CompNames []string `json:"componentNames"`
|
||||
CompTypes []string `json:"componentTypes"`
|
||||
OAMResourceTypes []string `json:"oamTypes"`
|
||||
TraitTypes []string `json:"traitTypes"`
|
||||
CompNames []string `json:"componentNames"`
|
||||
CompTypes []string `json:"componentTypes"`
|
||||
TraitTypes []string `json:"traitTypes"`
|
||||
}
|
||||
|
||||
// GarbageCollectStrategy the strategy for target resource to recycle
|
||||
@@ -70,11 +69,10 @@ const (
|
||||
// FindStrategy find gc strategy for target resource
|
||||
func (in GarbageCollectPolicySpec) FindStrategy(manifest *unstructured.Unstructured) *GarbageCollectStrategy {
|
||||
for _, rule := range in.Rules {
|
||||
var compName, compType, oamType, traitType string
|
||||
var compName, compType, traitType string
|
||||
if labels := manifest.GetLabels(); labels != nil {
|
||||
compName = labels[oam.LabelAppComponent]
|
||||
compType = labels[oam.WorkloadTypeLabel]
|
||||
oamType = labels[oam.LabelOAMResourceType]
|
||||
traitType = labels[oam.TraitTypeLabel]
|
||||
}
|
||||
match := func(src []string, val string) (found bool) {
|
||||
@@ -85,7 +83,6 @@ func (in GarbageCollectPolicySpec) FindStrategy(manifest *unstructured.Unstructu
|
||||
}
|
||||
if match(rule.Selector.CompNames, compName) ||
|
||||
match(rule.Selector.CompTypes, compType) ||
|
||||
match(rule.Selector.OAMResourceTypes, oamType) ||
|
||||
match(rule.Selector.TraitTypes, traitType) {
|
||||
return &rule.Strategy
|
||||
}
|
||||
|
||||
@@ -109,18 +109,6 @@ func TestGarbageCollectPolicySpec_FindStrategy(t *testing.T) {
|
||||
}},
|
||||
expectStrategy: GarbageCollectStrategyNever,
|
||||
},
|
||||
"resource type rule match": {
|
||||
rules: []GarbageCollectPolicyRule{{
|
||||
Selector: GarbageCollectPolicyRuleSelector{OAMResourceTypes: []string{"TRAIT"}},
|
||||
Strategy: GarbageCollectStrategyNever,
|
||||
}},
|
||||
input: &unstructured.Unstructured{Object: map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]interface{}{oam.LabelOAMResourceType: "TRAIT"},
|
||||
},
|
||||
}},
|
||||
expectStrategy: GarbageCollectStrategyNever,
|
||||
},
|
||||
}
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
|
||||
@@ -291,11 +291,6 @@ func (in *GarbageCollectPolicyRuleSelector) DeepCopyInto(out *GarbageCollectPoli
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.OAMResourceTypes != nil {
|
||||
in, out := &in.OAMResourceTypes, &out.OAMResourceTypes
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.TraitTypes != nil {
|
||||
in, out := &in.TraitTypes, &out.TraitTypes
|
||||
*out = make([]string, len(*in))
|
||||
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/interfaces"
|
||||
velatypes "github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/errors"
|
||||
)
|
||||
@@ -121,7 +122,11 @@ func (in ManagedResource) NamespacedName() types.NamespacedName {
|
||||
// ResourceKey computes the key for managed resource, resources with the same key points to the same resource
|
||||
func (in ManagedResource) ResourceKey() string {
|
||||
gv, kind := in.GroupVersionKind().ToAPIVersionAndKind()
|
||||
return strings.Join([]string{gv, kind, in.Cluster, in.Namespace, in.Name}, "/")
|
||||
cluster := in.Cluster
|
||||
if cluster == "" {
|
||||
cluster = velatypes.ClusterLocalName
|
||||
}
|
||||
return strings.Join([]string{gv, kind, cluster, in.Namespace, in.Name}, "/")
|
||||
}
|
||||
|
||||
// ComponentKey computes the key for the component which managed resource belongs to
|
||||
|
||||
@@ -22,6 +22,9 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// ClusterLocalName the name for the hub cluster
|
||||
ClusterLocalName = "local"
|
||||
|
||||
// CredentialTypeInternal identifies the virtual cluster from internal kubevela system
|
||||
CredentialTypeInternal v1alpha1.CredentialType = "Internal"
|
||||
// CredentialTypeOCMManagedCluster identifies the virtual cluster from ocm
|
||||
|
||||
@@ -73,8 +73,8 @@ const (
|
||||
LabelConfigSyncToMultiCluster = "config.oam.dev/multi-cluster"
|
||||
// LabelConfigIdentifier is the label for config identifier
|
||||
LabelConfigIdentifier = "config.oam.dev/identifier"
|
||||
// LabelConfigDescription is the label for config description
|
||||
LabelConfigDescription = "config.oam.dev/description"
|
||||
// AnnotationConfigDescription is the annotation for config description
|
||||
AnnotationConfigDescription = "config.oam.dev/description"
|
||||
// AnnotationConfigAlias is the annotation for config alias
|
||||
AnnotationConfigAlias = "config.oam.dev/alias"
|
||||
)
|
||||
@@ -148,3 +148,15 @@ const (
|
||||
// HelmRepository is the config type for Helm chart repository
|
||||
HelmRepository = "config-helm-repository"
|
||||
)
|
||||
|
||||
const (
|
||||
// TerraformComponentPrefix is the prefix of component type of terraform-xxx
|
||||
TerraformComponentPrefix = "terraform-"
|
||||
|
||||
// ProviderAppPrefix is the prefix of the application to create a Terraform Provider
|
||||
ProviderAppPrefix = "config-terraform-provider"
|
||||
// ProviderNamespace is the namespace of Terraform Cloud Provider
|
||||
ProviderNamespace = "default"
|
||||
// VelaCoreConfig is to mark application, config and its secret or Terraform provider lelong to a KubeVela config
|
||||
VelaCoreConfig = "velacore-config"
|
||||
)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -106,7 +106,7 @@ spec:
|
||||
}]
|
||||
}
|
||||
}
|
||||
parameter: #PatchParams | close({
|
||||
parameter: *#PatchParams | close({
|
||||
// +usage=Specify the commands for multiple containers
|
||||
containers: [...#PatchParams]
|
||||
})
|
||||
|
||||
@@ -10,6 +10,7 @@ metadata:
|
||||
custom.definition.oam.dev/catalog.config.oam.dev: velacore-config
|
||||
custom.definition.oam.dev/multi-cluster.config.oam.dev: "true"
|
||||
custom.definition.oam.dev/type.config.oam.dev: image-registry
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: config-image-registry
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
@@ -35,20 +36,23 @@ spec:
|
||||
"config.oam.dev/sub-type": "auth"
|
||||
}
|
||||
}
|
||||
type: "kubernetes.io/dockerconfigjson"
|
||||
stringData: {
|
||||
if parameter.auth != _|_ {
|
||||
".dockerconfigjson": json.Marshal({
|
||||
auths: "\(parameter.registry)": {
|
||||
username: parameter.auth.username
|
||||
password: parameter.auth.password
|
||||
if parameter.auth.email != _|_ {
|
||||
email: parameter.auth.email
|
||||
}
|
||||
auth: base64.Encode(null, (parameter.auth.username + ":" + parameter.auth.password))
|
||||
if parameter.auth != _|_ {
|
||||
type: "kubernetes.io/dockerconfigjson"
|
||||
}
|
||||
if parameter.auth == _|_ {
|
||||
type: "Opaque"
|
||||
}
|
||||
if parameter.auth != _|_ {
|
||||
stringData: ".dockerconfigjson": json.Marshal({
|
||||
auths: "\(parameter.registry)": {
|
||||
username: parameter.auth.username
|
||||
password: parameter.auth.password
|
||||
if parameter.auth.email != _|_ {
|
||||
email: parameter.auth.email
|
||||
}
|
||||
})
|
||||
}
|
||||
auth: base64.Encode(null, (parameter.auth.username + ":" + parameter.auth.password))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
|
||||
@@ -69,7 +69,7 @@ spec:
|
||||
}]
|
||||
}
|
||||
}
|
||||
parameter: #PatchParams | close({
|
||||
parameter: *#PatchParams | close({
|
||||
// +usage=Specify the container image for multiple containers
|
||||
containers: [...#PatchParams]
|
||||
})
|
||||
|
||||
@@ -46,7 +46,7 @@ spec:
|
||||
}]
|
||||
}
|
||||
if _baseEnv != _|_ {
|
||||
_baseEnvMap: {for envVar in _baseEnv {"\(envVar.name)": envVar.value}}
|
||||
_baseEnvMap: {for envVar in _baseEnv {"\(envVar.name)": envVar}}
|
||||
// +patchStrategy=replace
|
||||
env: [ for envVar in _baseEnv if _delKeys[envVar.name] == _|_ && !_params.replace {
|
||||
name: envVar.name
|
||||
@@ -54,7 +54,12 @@ spec:
|
||||
value: _params.env[envVar.name]
|
||||
}
|
||||
if _params.env[envVar.name] == _|_ {
|
||||
value: envVar.value
|
||||
if envVar.value != _|_ {
|
||||
value: envVar.value
|
||||
}
|
||||
if envVar.valueFrom != _|_ {
|
||||
valueFrom: envVar.valueFrom
|
||||
}
|
||||
}
|
||||
}] + [ for k, v in _params.env if _delKeys[k] == _|_ && (_params.replace || _baseEnvMap[k] == _|_) {
|
||||
name: k
|
||||
@@ -92,7 +97,7 @@ spec:
|
||||
}]
|
||||
}
|
||||
}
|
||||
parameter: #PatchParams | close({
|
||||
parameter: *#PatchParams | close({
|
||||
// +usage=Specify the environment variables for multiple containers
|
||||
containers: [...#PatchParams]
|
||||
})
|
||||
|
||||
@@ -35,13 +35,6 @@ spec:
|
||||
}
|
||||
}]
|
||||
}
|
||||
if parameter["livenessProbe"] != _|_ {
|
||||
livenessProbe: parameter.livenessProbe
|
||||
}
|
||||
|
||||
if parameter["readinessProbe"] != _|_ {
|
||||
readinessProbe: parameter.readinessProbe
|
||||
}
|
||||
}]
|
||||
}
|
||||
parameter: {
|
||||
@@ -62,52 +55,5 @@ spec:
|
||||
name: string
|
||||
path: string
|
||||
}]
|
||||
|
||||
// +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
|
||||
}
|
||||
#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
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -87,17 +87,6 @@ spec:
|
||||
}
|
||||
},
|
||||
] | []
|
||||
configMountToEnvsList: *[
|
||||
for v in parameter.configMap if v.mountToEnvs != _|_ for k in v.mountToEnvs {
|
||||
{
|
||||
name: k.envName
|
||||
valueFrom: configMapKeyRef: {
|
||||
name: v.name
|
||||
key: k.configMapKey
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
secretVolumeMountsList: *[
|
||||
for v in parameter.secret if v.mountPath != _|_ {
|
||||
{
|
||||
@@ -117,17 +106,6 @@ spec:
|
||||
}
|
||||
},
|
||||
] | []
|
||||
secretMountToEnvsList: *[
|
||||
for v in parameter.secret if v.mountToEnvs != _|_ for k in v.mountToEnvs {
|
||||
{
|
||||
name: k.envName
|
||||
valueFrom: secretKeyRef: {
|
||||
name: v.name
|
||||
key: k.secretKey
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
emptyDirVolumeMountsList: *[
|
||||
for v in parameter.emptyDir {
|
||||
{
|
||||
@@ -150,7 +128,7 @@ spec:
|
||||
|
||||
containers: [{
|
||||
// +patchKey=name
|
||||
env: configMapEnvMountsList + secretEnvMountsList + configMountToEnvsList + secretMountToEnvsList
|
||||
env: configMapEnvMountsList + secretEnvMountsList
|
||||
// +patchKey=name
|
||||
volumeDevices: volumeDevicesList
|
||||
// +patchKey=name
|
||||
@@ -270,10 +248,6 @@ spec:
|
||||
envName: string
|
||||
configMapKey: string
|
||||
}
|
||||
mountToEnvs?: [...{
|
||||
envName: string
|
||||
configMapKey: string
|
||||
}]
|
||||
mountPath?: string
|
||||
defaultMode: *420 | int
|
||||
readOnly: *false | bool
|
||||
@@ -293,10 +267,6 @@ spec:
|
||||
envName: string
|
||||
secretKey: string
|
||||
}
|
||||
mountToEnvs?: [...{
|
||||
envName: string
|
||||
secretKey: string
|
||||
}]
|
||||
mountPath?: string
|
||||
defaultMode: *420 | int
|
||||
readOnly: *false | bool
|
||||
|
||||
@@ -132,10 +132,9 @@ spec:
|
||||
parameter.labels
|
||||
}
|
||||
if parameter.addRevisionLabel {
|
||||
"app.oam.dev/appRevision": context.appRevision
|
||||
"app.oam.dev/revision": context.revision
|
||||
}
|
||||
"app.oam.dev/component": context.name
|
||||
"app.oam.dev/revision": context.revision
|
||||
}
|
||||
if parameter.annotations != _|_ {
|
||||
annotations: parameter.annotations
|
||||
@@ -333,7 +332,7 @@ spec:
|
||||
exposeType: *"ClusterIP" | "NodePort" | "LoadBalancer" | "ExternalName"
|
||||
|
||||
// +ignore
|
||||
// +usage=If addRevisionLabel is true, the appRevision label will be added to the underlying pods
|
||||
// +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
|
||||
@@ -455,7 +454,7 @@ spec:
|
||||
readinessProbe?: #HealthProbe
|
||||
|
||||
// +usage=Specify the hostAliases to add
|
||||
hostAliases: [...{
|
||||
hostAliases?: [...{
|
||||
ip: string
|
||||
hostnames: [...string]
|
||||
}]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -106,7 +106,7 @@ spec:
|
||||
}]
|
||||
}
|
||||
}
|
||||
parameter: #PatchParams | close({
|
||||
parameter: *#PatchParams | close({
|
||||
// +usage=Specify the commands for multiple containers
|
||||
containers: [...#PatchParams]
|
||||
})
|
||||
|
||||
@@ -10,6 +10,7 @@ metadata:
|
||||
custom.definition.oam.dev/catalog.config.oam.dev: velacore-config
|
||||
custom.definition.oam.dev/multi-cluster.config.oam.dev: "true"
|
||||
custom.definition.oam.dev/type.config.oam.dev: image-registry
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: config-image-registry
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
@@ -35,20 +36,23 @@ spec:
|
||||
"config.oam.dev/sub-type": "auth"
|
||||
}
|
||||
}
|
||||
type: "kubernetes.io/dockerconfigjson"
|
||||
stringData: {
|
||||
if parameter.auth != _|_ {
|
||||
".dockerconfigjson": json.Marshal({
|
||||
auths: "\(parameter.registry)": {
|
||||
username: parameter.auth.username
|
||||
password: parameter.auth.password
|
||||
if parameter.auth.email != _|_ {
|
||||
email: parameter.auth.email
|
||||
}
|
||||
auth: base64.Encode(null, (parameter.auth.username + ":" + parameter.auth.password))
|
||||
if parameter.auth != _|_ {
|
||||
type: "kubernetes.io/dockerconfigjson"
|
||||
}
|
||||
if parameter.auth == _|_ {
|
||||
type: "Opaque"
|
||||
}
|
||||
if parameter.auth != _|_ {
|
||||
stringData: ".dockerconfigjson": json.Marshal({
|
||||
auths: "\(parameter.registry)": {
|
||||
username: parameter.auth.username
|
||||
password: parameter.auth.password
|
||||
if parameter.auth.email != _|_ {
|
||||
email: parameter.auth.email
|
||||
}
|
||||
})
|
||||
}
|
||||
auth: base64.Encode(null, (parameter.auth.username + ":" + parameter.auth.password))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
|
||||
@@ -69,7 +69,7 @@ spec:
|
||||
}]
|
||||
}
|
||||
}
|
||||
parameter: #PatchParams | close({
|
||||
parameter: *#PatchParams | close({
|
||||
// +usage=Specify the container image for multiple containers
|
||||
containers: [...#PatchParams]
|
||||
})
|
||||
|
||||
@@ -46,7 +46,7 @@ spec:
|
||||
}]
|
||||
}
|
||||
if _baseEnv != _|_ {
|
||||
_baseEnvMap: {for envVar in _baseEnv {"\(envVar.name)": envVar.value}}
|
||||
_baseEnvMap: {for envVar in _baseEnv {"\(envVar.name)": envVar}}
|
||||
// +patchStrategy=replace
|
||||
env: [ for envVar in _baseEnv if _delKeys[envVar.name] == _|_ && !_params.replace {
|
||||
name: envVar.name
|
||||
@@ -54,7 +54,12 @@ spec:
|
||||
value: _params.env[envVar.name]
|
||||
}
|
||||
if _params.env[envVar.name] == _|_ {
|
||||
value: envVar.value
|
||||
if envVar.value != _|_ {
|
||||
value: envVar.value
|
||||
}
|
||||
if envVar.valueFrom != _|_ {
|
||||
valueFrom: envVar.valueFrom
|
||||
}
|
||||
}
|
||||
}] + [ for k, v in _params.env if _delKeys[k] == _|_ && (_params.replace || _baseEnvMap[k] == _|_) {
|
||||
name: k
|
||||
@@ -92,7 +97,7 @@ spec:
|
||||
}]
|
||||
}
|
||||
}
|
||||
parameter: #PatchParams | close({
|
||||
parameter: *#PatchParams | close({
|
||||
// +usage=Specify the environment variables for multiple containers
|
||||
containers: [...#PatchParams]
|
||||
})
|
||||
|
||||
@@ -35,13 +35,6 @@ spec:
|
||||
}
|
||||
}]
|
||||
}
|
||||
if parameter["livenessProbe"] != _|_ {
|
||||
livenessProbe: parameter.livenessProbe
|
||||
}
|
||||
|
||||
if parameter["readinessProbe"] != _|_ {
|
||||
readinessProbe: parameter.readinessProbe
|
||||
}
|
||||
}]
|
||||
}
|
||||
parameter: {
|
||||
@@ -62,52 +55,5 @@ spec:
|
||||
name: string
|
||||
path: string
|
||||
}]
|
||||
|
||||
// +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
|
||||
}
|
||||
#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
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -87,17 +87,6 @@ spec:
|
||||
}
|
||||
},
|
||||
] | []
|
||||
configMountToEnvsList: *[
|
||||
for v in parameter.configMap if v.mountToEnvs != _|_ for k in v.mountToEnvs {
|
||||
{
|
||||
name: k.envName
|
||||
valueFrom: configMapKeyRef: {
|
||||
name: v.name
|
||||
key: k.configMapKey
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
secretVolumeMountsList: *[
|
||||
for v in parameter.secret if v.mountPath != _|_ {
|
||||
{
|
||||
@@ -117,17 +106,6 @@ spec:
|
||||
}
|
||||
},
|
||||
] | []
|
||||
secretMountToEnvsList: *[
|
||||
for v in parameter.secret if v.mountToEnvs != _|_ for k in v.mountToEnvs {
|
||||
{
|
||||
name: k.envName
|
||||
valueFrom: secretKeyRef: {
|
||||
name: v.name
|
||||
key: k.secretKey
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
emptyDirVolumeMountsList: *[
|
||||
for v in parameter.emptyDir {
|
||||
{
|
||||
@@ -150,7 +128,7 @@ spec:
|
||||
|
||||
containers: [{
|
||||
// +patchKey=name
|
||||
env: configMapEnvMountsList + secretEnvMountsList + configMountToEnvsList + secretMountToEnvsList
|
||||
env: configMapEnvMountsList + secretEnvMountsList
|
||||
// +patchKey=name
|
||||
volumeDevices: volumeDevicesList
|
||||
// +patchKey=name
|
||||
@@ -270,10 +248,6 @@ spec:
|
||||
envName: string
|
||||
configMapKey: string
|
||||
}
|
||||
mountToEnvs?: [...{
|
||||
envName: string
|
||||
configMapKey: string
|
||||
}]
|
||||
mountPath?: string
|
||||
defaultMode: *420 | int
|
||||
readOnly: *false | bool
|
||||
@@ -293,10 +267,6 @@ spec:
|
||||
envName: string
|
||||
secretKey: string
|
||||
}
|
||||
mountToEnvs?: [...{
|
||||
envName: string
|
||||
secretKey: string
|
||||
}]
|
||||
mountPath?: string
|
||||
defaultMode: *420 | int
|
||||
readOnly: *false | bool
|
||||
|
||||
@@ -132,10 +132,9 @@ spec:
|
||||
parameter.labels
|
||||
}
|
||||
if parameter.addRevisionLabel {
|
||||
"app.oam.dev/appRevision": context.appRevision
|
||||
"app.oam.dev/revision": context.revision
|
||||
}
|
||||
"app.oam.dev/component": context.name
|
||||
"app.oam.dev/revision": context.revision
|
||||
}
|
||||
if parameter.annotations != _|_ {
|
||||
annotations: parameter.annotations
|
||||
@@ -333,7 +332,7 @@ spec:
|
||||
exposeType: *"ClusterIP" | "NodePort" | "LoadBalancer" | "ExternalName"
|
||||
|
||||
// +ignore
|
||||
// +usage=If addRevisionLabel is true, the appRevision label will be added to the underlying pods
|
||||
// +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
|
||||
@@ -455,7 +454,7 @@ spec:
|
||||
readinessProbe?: #HealthProbe
|
||||
|
||||
// +usage=Specify the hostAliases to add
|
||||
hostAliases: [...{
|
||||
hostAliases?: [...{
|
||||
ip: string
|
||||
hostnames: [...string]
|
||||
}]
|
||||
|
||||
@@ -142,6 +142,7 @@ func main() {
|
||||
flag.DurationVar(&clusterMetricsInterval, "cluster-metrics-interval", 15*time.Second, "The interval that ClusterMetricsMgr will collect metrics from clusters, default value is 15 seconds.")
|
||||
flag.BoolVar(&controllerArgs.EnableCompatibility, "enable-asi-compatibility", false, "enable compatibility for asi")
|
||||
flag.BoolVar(&controllerArgs.IgnoreAppWithoutControllerRequirement, "ignore-app-without-controller-version", false, "If true, application controller will not process the app without 'app.oam.dev/controller-version-require' annotation")
|
||||
flag.BoolVar(&controllerArgs.IgnoreDefinitionWithoutControllerRequirement, "ignore-definition-without-controller-version", false, "If true, trait/component/workflowstep definition controller will not process the definition without 'definition.oam.dev/controller-version-require' annotation")
|
||||
standardcontroller.AddOptimizeFlags()
|
||||
standardcontroller.AddAdmissionFlags()
|
||||
flag.IntVar(&resourcekeeper.MaxDispatchConcurrent, "max-dispatch-concurrent", 10, "Set the max dispatch concurrent number, default is 10")
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
By leveraging the garbage-collect policy, users can persist some resources, which skip the normal garbage-collect process when application is updated.
|
||||
|
||||
### traitTypes
|
||||
|
||||
Take the following app as an example, in the garbage-collect policy, a rule is added which marks all the resources created by the `expose` trait to use the `onAppDelete` strategy. This will keep those services until application is deleted.
|
||||
```shell
|
||||
$ cat <<EOF | kubectl apply -f -
|
||||
@@ -80,8 +78,6 @@ hello-world ClusterIP 10.96.160.208 <none> 8000/TCP 5m56s
|
||||
hello-world-new ClusterIP 10.96.20.4 <none> 8000/TCP 13s
|
||||
```
|
||||
|
||||
### componentTypes
|
||||
|
||||
Users can also keep component if they are deploying job-like components. Resources dispatched by `job-like-component` type component will be kept after application is deleted.
|
||||
|
||||
```yaml
|
||||
@@ -104,8 +100,6 @@ spec:
|
||||
strategy: never
|
||||
```
|
||||
|
||||
### componentNames
|
||||
|
||||
A more straightforward way is to specify `compNames` to match specified components.
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
@@ -130,74 +124,3 @@ spec:
|
||||
- example-addon-namespace
|
||||
strategy: never
|
||||
```
|
||||
|
||||
### oamTypes
|
||||
|
||||
Users can also persist resources using `oamTypes`, where the values of `oamTypes` can be `TRAIT` and `WORKLOAD`.
|
||||
|
||||
```shell
|
||||
$ cat <<EOF | kubectl apply -f -
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: garbage-collect-app
|
||||
spec:
|
||||
components:
|
||||
- name: hello-world
|
||||
type: webservice
|
||||
properties:
|
||||
image: crccheck/hello-world
|
||||
traits:
|
||||
- type: expose
|
||||
properties:
|
||||
port: [8000]
|
||||
policies:
|
||||
- name: garbage-collect
|
||||
type: garbage-collect
|
||||
properties:
|
||||
rules:
|
||||
- selector:
|
||||
oamTypes:
|
||||
- TRAIT
|
||||
strategy: onAppDelete
|
||||
EOF
|
||||
```
|
||||
|
||||
And then, let's modify the component name.
|
||||
|
||||
```shell
|
||||
$ cat <<EOF | kubectl apply -f -
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: garbage-collect-app
|
||||
spec:
|
||||
components:
|
||||
- name: hello-world-new
|
||||
type: webservice
|
||||
properties:
|
||||
image: crccheck/hello-world
|
||||
traits:
|
||||
- type: expose
|
||||
properties:
|
||||
port: [8000]
|
||||
policies:
|
||||
- name: garbage-collect
|
||||
type: garbage-collect
|
||||
properties:
|
||||
rules:
|
||||
- selector:
|
||||
oamTypes:
|
||||
- TRAIT
|
||||
strategy: onAppDelete
|
||||
EOF
|
||||
```
|
||||
|
||||
List the service in cluster, you will find:
|
||||
|
||||
```shell
|
||||
$ kubectl get service
|
||||
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
hello-world ClusterIP 10.96.31.209 <none> 8000/TCP 31s
|
||||
hello-world-new ClusterIP 10.96.17.103 <none> 8000/TCP 5s
|
||||
```
|
||||
|
||||
@@ -32,9 +32,6 @@ spec:
|
||||
mountToEnv:
|
||||
envName: TEST_ENV
|
||||
configMapKey: key1
|
||||
mountToEnvs:
|
||||
- envName: TEST_CM_ENV
|
||||
configMapKey: key2
|
||||
data:
|
||||
key1: value1
|
||||
key2: value2
|
||||
@@ -52,15 +49,9 @@ spec:
|
||||
mountToEnv:
|
||||
envName: TEST_SECRET
|
||||
secretKey: key1
|
||||
mountToEnvs:
|
||||
- envName: TEST_SECRET_ENV_2
|
||||
secretKey: key2
|
||||
- envName: TEST_SECRET_ENV_3
|
||||
secretKey: key3
|
||||
data:
|
||||
key1: dmFsdWUx
|
||||
key2: dmFsdWUy
|
||||
key3: dmFsdWUz
|
||||
emptyDir:
|
||||
- name: test1
|
||||
mountPath: /test/mount/emptydir
|
||||
|
||||
23
e2e/addon/mock/testdata/mock-addon/metadata.yaml
vendored
Normal file
23
e2e/addon/mock/testdata/mock-addon/metadata.yaml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: mock-addon
|
||||
version: 1.0.0
|
||||
description: Extended workload to do continuous and progressive delivery
|
||||
icon: https://raw.githubusercontent.com/fluxcd/flux/master/docs/_files/weave-flux.png
|
||||
url: https://fluxcd.io
|
||||
|
||||
tags:
|
||||
- extended_workload
|
||||
- gitops
|
||||
- only_example
|
||||
|
||||
deployTo:
|
||||
control_plane: true
|
||||
runtime_cluster: false
|
||||
|
||||
dependencies: []
|
||||
#- name: addon_name
|
||||
|
||||
# set invisible means this won't be list and will be enabled when depended on
|
||||
# for example, terraform-alibaba depends on terraform which is invisible,
|
||||
# when terraform-alibaba is enabled, terraform will be enabled automatically
|
||||
# default: false
|
||||
invisible: false
|
||||
14
e2e/addon/mock/testdata/mock-addon/template.yaml
vendored
Normal file
14
e2e/addon/mock/testdata/mock-addon/template.yaml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: mock-addon
|
||||
namespace: vela-system
|
||||
spec:
|
||||
components:
|
||||
- name: ns-example-system
|
||||
type: raw
|
||||
properties:
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: mock-system
|
||||
@@ -129,7 +129,7 @@ var _ = Describe("Test Kubectl Plugin", func() {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).Should(ContainSubstring(showTdResult))
|
||||
})
|
||||
PIt("Test show componentDefinition use Helm Charts as Workload", func() {
|
||||
It("Test show componentDefinition use Helm Charts as Workload", func() {
|
||||
Eventually(func() string {
|
||||
cdName := "test-webapp-chart"
|
||||
output, _ := e2e.Exec(fmt.Sprintf("kubectl-vela show %s -n default", cdName))
|
||||
|
||||
30
go.mod
30
go.mod
@@ -63,10 +63,11 @@ require (
|
||||
github.com/wonderflow/cert-manager-api v1.0.3
|
||||
go.mongodb.org/mongo-driver v1.5.1
|
||||
go.uber.org/zap v1.18.1
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
|
||||
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||
golang.org/x/tools v0.1.6 // indirect
|
||||
golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1
|
||||
@@ -96,17 +97,7 @@ require (
|
||||
sigs.k8s.io/yaml v1.2.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/docker/distribution v2.8.0-beta.1+incompatible // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||
github.com/xanzy/go-gitlab v0.60.0
|
||||
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
||||
golang.org/x/net v0.0.0-20220325170049-de3da57026de // indirect
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
)
|
||||
require github.com/robfig/cron/v3 v3.0.1
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.81.0 // indirect
|
||||
@@ -117,7 +108,7 @@ require (
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/BurntSushi/toml v0.3.1 // indirect
|
||||
github.com/BurntSushi/toml v0.4.1 // indirect
|
||||
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
@@ -151,6 +142,7 @@ require (
|
||||
github.com/cyphar/filepath-securejoin v0.2.2 // indirect
|
||||
github.com/deislabs/oras v0.11.1 // indirect
|
||||
github.com/docker/cli v20.10.5+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.0-beta.1+incompatible // indirect
|
||||
github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.6.3 // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
@@ -179,7 +171,7 @@ require (
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.1 // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/go-querystring v1.0.0 // indirect
|
||||
github.com/google/gofuzz v1.1.0 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/googleapis/gnostic v0.5.5 // indirect
|
||||
@@ -194,6 +186,7 @@ require (
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.11 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||
github.com/klauspost/compress v1.11.0 // indirect
|
||||
github.com/kr/pretty v0.3.0 // indirect
|
||||
github.com/kr/pty v1.1.8 // indirect
|
||||
@@ -244,6 +237,7 @@ require (
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/tjfoc/gmsm v1.3.2 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.0.2 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.2 // indirect
|
||||
@@ -257,15 +251,17 @@ require (
|
||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
golang.org/x/mod v0.4.2 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect
|
||||
google.golang.org/grpc v1.38.0 // indirect
|
||||
google.golang.org/protobuf v1.26.0 // indirect
|
||||
gopkg.in/gorp.v1 v1.7.2 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||
|
||||
44
go.sum
44
go.sum
@@ -110,8 +110,9 @@ github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ
|
||||
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
|
||||
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=
|
||||
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
||||
@@ -781,9 +782,8 @@ github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II=
|
||||
github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
@@ -896,12 +896,8 @@ github.com/hashicorp/consul/sdk v0.4.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPA
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
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-getter v1.4.0/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY=
|
||||
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||
github.com/hashicorp/go-hclog v0.12.2 h1:F1fdYblUEsxKiailtkhCCG2g4bipEgaHiDc8vffNpD4=
|
||||
github.com/hashicorp/go-hclog v0.12.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
@@ -911,9 +907,6 @@ github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iP
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||
@@ -1445,6 +1438,8 @@ github.com/rancher/wrangler v0.4.0/go.mod h1:1cR91WLhZgkZ+U4fV9nVuXqKurWbgXcIReU
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
|
||||
github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc=
|
||||
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.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
@@ -1626,8 +1621,6 @@ github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgq
|
||||
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
github.com/wonderflow/cert-manager-api v1.0.3 h1:xQQMkJNQ12oYyy00jOQUlSKgdraApaURxv3PHFdVTfA=
|
||||
github.com/wonderflow/cert-manager-api v1.0.3/go.mod h1:1Se7MSg11/eNYlo4fWv6vOM55/jTBMOzg2DN1kVFiSc=
|
||||
github.com/xanzy/go-gitlab v0.60.0 h1:HaIlc14k4t9eJjAhY0Gmq2fBHgKd1MthBn3+vzDtsbA=
|
||||
github.com/xanzy/go-gitlab v0.60.0/go.mod h1:F0QEXwmqiBUxCgJm8fE9S+1veX4XC9Z4cfaAbqwk4YM=
|
||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||
github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI=
|
||||
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
|
||||
@@ -1664,7 +1657,7 @@ github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI=
|
||||
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
|
||||
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE=
|
||||
@@ -1806,8 +1799,9 @@ golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWP
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -1851,8 +1845,9 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
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=
|
||||
@@ -1917,13 +1912,11 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220325170049-de3da57026de h1:pZB1TWnKi+o4bENlbzAgLrEbY4RMYmUIRobMcSmfeYc=
|
||||
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/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-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -2060,7 +2053,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
@@ -2091,9 +2084,8 @@ golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxb
|
||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs=
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -2217,8 +2209,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.6 h1:SIasE1FVIQOWz2GEAHFOmoW7xchJcqlucjSULTL0Ag4=
|
||||
golang.org/x/tools v0.1.6/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a h1:ofrrl6c6NG5/IOSx/R1cyiQxxjqlur0h/TvbUhkH0II=
|
||||
golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
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=
|
||||
@@ -2263,7 +2255,6 @@ google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk
|
||||
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
@@ -2372,9 +2363,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
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=
|
||||
|
||||
@@ -25,7 +25,7 @@ ifeq (, $(shell which staticcheck))
|
||||
@{ \
|
||||
set -e ;\
|
||||
echo 'installing honnef.co/go/tools/cmd/staticcheck ' ;\
|
||||
GO111MODULE=off go get honnef.co/go/tools/cmd/staticcheck ;\
|
||||
GO111MODULE=on go get honnef.co/go/tools/cmd/staticcheck@v0.3.0 ;\
|
||||
}
|
||||
STATICCHECK=$(GOBIN)/staticcheck
|
||||
else
|
||||
@@ -56,7 +56,7 @@ else
|
||||
CUE=$(shell which cue)
|
||||
endif
|
||||
|
||||
KUSTOMIZE_VERSION ?= 3.8.2
|
||||
KUSTOMIZE_VERSION ?= 4.5.4
|
||||
|
||||
.PHONY: kustomize
|
||||
kustomize:
|
||||
|
||||
@@ -48,8 +48,8 @@ ADDONSERVER = $(shell pgrep vela_addon_mock_server)
|
||||
e2e-apiserver-test:
|
||||
pkill vela_addon_mock_server || true
|
||||
go run ./e2e/addon/mock/vela_addon_mock_server.go &
|
||||
sleep 15
|
||||
go test -v -coverpkg=./... -coverprofile=/tmp/e2e_apiserver_test.out ./test/e2e-apiserver-test
|
||||
sleep 15
|
||||
@$(OK) tests pass
|
||||
|
||||
.PHONY: e2e-test
|
||||
|
||||
@@ -36,7 +36,6 @@ import (
|
||||
"github.com/google/go-github/v32/github"
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/xanzy/go-gitlab"
|
||||
"golang.org/x/oauth2"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
@@ -196,6 +195,10 @@ func GetPatternFromItem(it Item, r AsyncReader, rootPath string) string {
|
||||
if strings.HasPrefix(relativePath, strings.Join([]string{rootPath, p.Value}, "/")) {
|
||||
return p.Value
|
||||
}
|
||||
if strings.HasPrefix(relativePath, filepath.Join(rootPath, p.Value)) {
|
||||
// for enable addon by load dir, compatible with linux or windows os
|
||||
return p.Value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -358,7 +361,7 @@ func readResFile(a *InstallPackage, reader AsyncReader, readPath string) error {
|
||||
if filename == "parameter.cue" {
|
||||
return nil
|
||||
}
|
||||
file := ElementFile{Data: b, Name: path.Base(readPath)}
|
||||
file := ElementFile{Data: b, Name: filepath.Base(readPath)}
|
||||
switch filepath.Ext(filename) {
|
||||
case ".cue":
|
||||
a.CUETemplates = append(a.CUETemplates, file)
|
||||
@@ -376,7 +379,7 @@ func readDefSchemaFile(a *InstallPackage, reader AsyncReader, readPath string) e
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.DefSchemas = append(a.DefSchemas, ElementFile{Data: b, Name: path.Base(readPath)})
|
||||
a.DefSchemas = append(a.DefSchemas, ElementFile{Data: b, Name: filepath.Base(readPath)})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -387,7 +390,7 @@ func readDefFile(a *UIData, reader AsyncReader, readPath string) error {
|
||||
return err
|
||||
}
|
||||
filename := path.Base(readPath)
|
||||
file := ElementFile{Data: b, Name: path.Base(readPath)}
|
||||
file := ElementFile{Data: b, Name: filepath.Base(readPath)}
|
||||
switch filepath.Ext(filename) {
|
||||
case ".cue":
|
||||
a.CUEDefinitions = append(a.CUEDefinitions, file)
|
||||
@@ -448,15 +451,6 @@ func createGiteeHelper(content *utils.Content, token string) *giteeHelper {
|
||||
}
|
||||
}
|
||||
|
||||
func createGitlabHelper(content *utils.Content, token string) (*gitlabHelper, error) {
|
||||
newClient, err := gitlab.NewClient(token, gitlab.WithBaseURL(content.GitlabContent.Host))
|
||||
|
||||
return &gitlabHelper{
|
||||
Client: newClient,
|
||||
Meta: content,
|
||||
}, err
|
||||
}
|
||||
|
||||
// readRepo will read relative path (relative to Meta.Path)
|
||||
func (h *gitHelper) readRepo(relativePath string) (*github.RepositoryContent, []*github.RepositoryContent, error) {
|
||||
file, items, _, err := h.Client.Repositories.GetContents(context.Background(), h.Meta.GithubContent.Owner, h.Meta.GithubContent.Repo, path.Join(h.Meta.GithubContent.Path, relativePath), nil)
|
||||
|
||||
@@ -21,6 +21,8 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils/apply"
|
||||
|
||||
"github.com/oam-dev/cluster-gateway/pkg/apis/cluster/v1alpha1"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -362,6 +364,21 @@ var _ = Describe("func addon update ", func() {
|
||||
})
|
||||
})
|
||||
|
||||
var _ = Describe("test enable addon in local dir", func() {
|
||||
BeforeEach(func() {
|
||||
app := v1beta1.Application{ObjectMeta: metav1.ObjectMeta{Namespace: "vela-system", Name: "addon-example"}}
|
||||
Expect(k8sClient.Delete(ctx, &app)).Should(SatisfyAny(BeNil(), util.NotFoundMatcher{}))
|
||||
})
|
||||
|
||||
It("test enable addon by local dir", func() {
|
||||
ctx := context.Background()
|
||||
err := EnableAddonByLocalDir(ctx, "example", "./testdata/example", k8sClient, dc, apply.NewAPIApplicator(k8sClient), cfg, map[string]interface{}{"example": "test"})
|
||||
Expect(err).Should(BeNil())
|
||||
app := v1beta1.Application{}
|
||||
Expect(k8sClient.Get(ctx, types2.NamespacedName{Namespace: "vela-system", Name: "addon-example"}, &app)).Should(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
const (
|
||||
appYaml = `apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
|
||||
@@ -147,7 +147,7 @@ func TestGetAddonData(t *testing.T) {
|
||||
server := httptest.NewServer(ossHandler)
|
||||
defer server.Close()
|
||||
|
||||
reader, err := NewAsyncReader(server.URL, "", "", "", "", ossType)
|
||||
reader, err := NewAsyncReader(server.URL, "", "", "", ossType)
|
||||
assert.NoError(t, err)
|
||||
testReaderFunc(t, reader)
|
||||
}
|
||||
@@ -617,9 +617,9 @@ func TestRenderApp4ObservabilityWithK8sData(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetPatternFromItem(t *testing.T) {
|
||||
ossR, err := NewAsyncReader("http://ep.beijing", "some-bucket", "", "some-sub-path", "", ossType)
|
||||
ossR, err := NewAsyncReader("http://ep.beijing", "some-bucket", "some-sub-path", "", ossType)
|
||||
assert.NoError(t, err)
|
||||
gitR, err := NewAsyncReader("https://github.com/oam-dev/catalog", "", "", "addons", "", gitType)
|
||||
gitR, err := NewAsyncReader("https://github.com/oam-dev/catalog", "", "addons", "", gitType)
|
||||
assert.NoError(t, err)
|
||||
gitItemName := "parameter.cue"
|
||||
gitItemType := FileType
|
||||
@@ -657,7 +657,7 @@ func TestGetPatternFromItem(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGitLabReaderNotPanic(t *testing.T) {
|
||||
_, err := NewAsyncReader("https://gitlab.com/test/catalog", "", "", "addons", "", gitType)
|
||||
_, err := NewAsyncReader("https://gitlab.com/test/catalog", "", "addons", "", gitType)
|
||||
assert.EqualError(t, err, "git type repository only support github for now")
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,12 @@ package addon
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/log"
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
)
|
||||
|
||||
// We have three addon layer here
|
||||
@@ -119,28 +119,27 @@ func (u *Cache) GetUIData(r Registry, addonName, version string) (*UIData, error
|
||||
// ListUIData will always list UIData from cache first, if not exist, read from source.
|
||||
func (u *Cache) ListUIData(r Registry) ([]*UIData, error) {
|
||||
var err error
|
||||
listAddons := u.listCachedUIData(r.Name)
|
||||
if listAddons != nil {
|
||||
return listAddons, nil
|
||||
}
|
||||
var listAddons []*UIData
|
||||
if !IsVersionRegistry(r) {
|
||||
addonMeta, err := u.ListAddonMeta(r)
|
||||
listAddons = u.listCachedUIData(r.Name)
|
||||
if listAddons != nil {
|
||||
return listAddons, nil
|
||||
}
|
||||
listAddons, err = u.listUIDataAndCache(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
listAddons, err = r.ListUIData(addonMeta, UIMetaOptions)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to get addons from registry %s, %w", r.Name, err)
|
||||
}
|
||||
} else {
|
||||
versionedRegistry := BuildVersionedRegistry(r.Name, r.Helm.URL)
|
||||
listAddons, err = versionedRegistry.ListAddon()
|
||||
listAddons = u.listVersionRegistryCachedUIData(r.Name)
|
||||
if listAddons != nil {
|
||||
return listAddons, nil
|
||||
}
|
||||
listAddons, err = u.listVersionRegistryUIDataAndCache(r)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("fail to get addons from registry %s for cache updating, %v", r.Name, err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
u.putAddonUIData2Cache(r.Name, listAddons)
|
||||
|
||||
return listAddons, nil
|
||||
}
|
||||
|
||||
@@ -175,6 +174,27 @@ func (u *Cache) listCachedUIData(name string) []*UIData {
|
||||
return d
|
||||
}
|
||||
|
||||
// listVersionRegistryCachedUIData will get cached addons from specified VersionRegistry in cache
|
||||
func (u *Cache) listVersionRegistryCachedUIData(name string) []*UIData {
|
||||
if u == nil {
|
||||
return nil
|
||||
}
|
||||
u.mutex.RLock()
|
||||
defer u.mutex.RUnlock()
|
||||
d, ok := u.versionedUIData[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
var uiDatas []*UIData
|
||||
for version, uiData := range d {
|
||||
if !strings.Contains(version, "-latest") {
|
||||
uiDatas = append(uiDatas, uiData)
|
||||
}
|
||||
}
|
||||
|
||||
return uiDatas
|
||||
}
|
||||
|
||||
// getCachedAddonMeta will get cached registry meta from specified registry in cache
|
||||
func (u *Cache) getCachedAddonMeta(name string) map[string]SourceMeta {
|
||||
if u == nil {
|
||||
@@ -260,35 +280,51 @@ func (u *Cache) discoverAndRefreshRegistry() {
|
||||
|
||||
for _, r := range registries {
|
||||
if !IsVersionRegistry(r) {
|
||||
registryMeta, err := r.ListAddonMeta()
|
||||
_, err = u.listUIDataAndCache(r)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("fail to list registry %s metadata, %v", r.Name, err)
|
||||
continue
|
||||
}
|
||||
u.putAddonMeta2Cache(r.Name, registryMeta)
|
||||
uiData, err := r.ListUIData(registryMeta, UIMetaOptions)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("fail to get addons from registry %s for cache updating, %v", r.Name, err)
|
||||
continue
|
||||
}
|
||||
u.putAddonUIData2Cache(r.Name, uiData)
|
||||
} else {
|
||||
versionedRegistry := BuildVersionedRegistry(r.Name, r.Helm.URL)
|
||||
uiDatas, err := versionedRegistry.ListAddon()
|
||||
_, err = u.listVersionRegistryUIDataAndCache(r)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("fail to get addons from registry %s for cache updating, %v", r.Name, err)
|
||||
continue
|
||||
}
|
||||
for _, addon := range uiDatas {
|
||||
uiData, err := versionedRegistry.GetAddonUIData(context.Background(), addon.Name, addon.Version)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("fail to get addon from registry %s, addon %s version %s for cache updating, %v", addon.Name, r.Name, err)
|
||||
continue
|
||||
}
|
||||
u.putVersionedUIData2Cache(r.Name, addon.Name, addon.Version, uiData)
|
||||
// we also no version key, if use get addonUIData without version will return this vale as latest data.
|
||||
u.putVersionedUIData2Cache(r.Name, addon.Name, "latest", uiData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (u *Cache) listUIDataAndCache(r Registry) ([]*UIData, error) {
|
||||
registryMeta, err := r.ListAddonMeta()
|
||||
if err != nil {
|
||||
log.Logger.Errorf("fail to list registry %s metadata, %v", r.Name, err)
|
||||
return nil, err
|
||||
}
|
||||
u.putAddonMeta2Cache(r.Name, registryMeta)
|
||||
uiData, err := r.ListUIData(registryMeta, UIMetaOptions)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("fail to get addons from registry %s for cache updating, %v", r.Name, err)
|
||||
return nil, err
|
||||
}
|
||||
u.putAddonUIData2Cache(r.Name, uiData)
|
||||
return uiData, nil
|
||||
}
|
||||
|
||||
func (u *Cache) listVersionRegistryUIDataAndCache(r Registry) ([]*UIData, error) {
|
||||
versionedRegistry := BuildVersionedRegistry(r.Name, r.Helm.URL)
|
||||
uiDatas, err := versionedRegistry.ListAddon()
|
||||
if err != nil {
|
||||
log.Logger.Errorf("fail to get addons from registry %s for cache updating, %v", r.Name, err)
|
||||
return nil, err
|
||||
}
|
||||
for _, addon := range uiDatas {
|
||||
uiData, err := versionedRegistry.GetAddonUIData(context.Background(), addon.Name, addon.Version)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("fail to get addon from versioned registry %s, addon %s version %s for cache updating, %v", r.Name, addon.Name, addon.Version, err)
|
||||
continue
|
||||
}
|
||||
u.putVersionedUIData2Cache(r.Name, addon.Name, addon.Version, uiData)
|
||||
// we also no version key, if use get addonUIData without version will return this vale as latest data.
|
||||
u.putVersionedUIData2Cache(r.Name, addon.Name, "latest", uiData)
|
||||
}
|
||||
return uiDatas, nil
|
||||
}
|
||||
|
||||
@@ -31,3 +31,63 @@ func TestPutVersionedUIData2cache(t *testing.T) {
|
||||
assert.NotEmpty(t, u.versionedUIData["helm-repo"]["fluxcd-1.0.0"])
|
||||
assert.Equal(t, u.versionedUIData["helm-repo"]["fluxcd-1.0.0"].Name, "fluxcd")
|
||||
}
|
||||
|
||||
func TestPutAddonUIData2Cache(t *testing.T) {
|
||||
uiData := UIData{Meta: Meta{Name: "fluxcd", Icon: "test.com/fluxcd.png", Version: "1.0.0"}}
|
||||
addons := []*UIData{&uiData}
|
||||
name := "helm-repo"
|
||||
u := NewCache(nil)
|
||||
u.putAddonUIData2Cache(name, addons)
|
||||
assert.NotEmpty(t, u.uiData)
|
||||
assert.Equal(t, u.uiData[name], addons)
|
||||
}
|
||||
|
||||
func TestListCachedUIData(t *testing.T) {
|
||||
uiData := UIData{Meta: Meta{Name: "fluxcd", Icon: "test.com/fluxcd.png", Version: "1.0.0"}}
|
||||
addons := []*UIData{&uiData}
|
||||
name := "helm-repo"
|
||||
u := NewCache(nil)
|
||||
u.putAddonUIData2Cache(name, addons)
|
||||
|
||||
assert.Equal(t, u.listCachedUIData(name), addons)
|
||||
}
|
||||
|
||||
func TestPutAddonMeta2Cache(t *testing.T) {
|
||||
addonMeta := map[string]SourceMeta{
|
||||
"fluxcd": {
|
||||
Name: "fluxcd",
|
||||
Items: []Item{
|
||||
&OSSItem{
|
||||
tp: FileType,
|
||||
path: "fluxcd/definitions/helm-release.yaml",
|
||||
name: "helm-release.yaml",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
name := "helm-repo"
|
||||
u := NewCache(nil)
|
||||
u.putAddonMeta2Cache(name, addonMeta)
|
||||
assert.NotEmpty(t, u.registryMeta)
|
||||
assert.Equal(t, u.registryMeta[name], addonMeta)
|
||||
}
|
||||
|
||||
func TestGetCachedAddonMeta(t *testing.T) {
|
||||
addonMeta := map[string]SourceMeta{
|
||||
"fluxcd": {
|
||||
Name: "fluxcd",
|
||||
Items: []Item{
|
||||
&OSSItem{
|
||||
tp: FileType,
|
||||
path: "fluxcd/definitions/helm-release.yaml",
|
||||
name: "helm-release.yaml",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
name := "helm-repo"
|
||||
u := NewCache(nil)
|
||||
u.putAddonMeta2Cache(name, addonMeta)
|
||||
|
||||
assert.Equal(t, u.getCachedAddonMeta(name), addonMeta)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/klog/v2"
|
||||
@@ -92,7 +93,11 @@ func DisableAddon(ctx context.Context, cli client.Client, name string, config *r
|
||||
|
||||
// EnableAddonByLocalDir enable an addon from local dir
|
||||
func EnableAddonByLocalDir(ctx context.Context, name string, dir string, cli client.Client, dc *discovery.DiscoveryClient, applicator apply.Applicator, config *rest.Config, args map[string]interface{}) error {
|
||||
r := localReader{dir: dir, name: name}
|
||||
absDir, err := filepath.Abs(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r := localReader{dir: absDir, name: name}
|
||||
metas, err := r.ListAddonMeta()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 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 addon
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/xanzy/go-gitlab"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
)
|
||||
|
||||
var _ AsyncReader = &gitlabReader{}
|
||||
|
||||
// gitlabReader helps get addon's file by git
|
||||
type gitlabReader struct {
|
||||
h *gitlabHelper
|
||||
}
|
||||
|
||||
// gitlabHelper helps get addon's file by git
|
||||
type gitlabHelper struct {
|
||||
Client *gitlab.Client
|
||||
Meta *utils.Content
|
||||
}
|
||||
|
||||
// GitLabItem addon's sub item
|
||||
type GitLabItem struct {
|
||||
basePath string
|
||||
tp string
|
||||
path string
|
||||
name string
|
||||
}
|
||||
|
||||
// GetType get addon's sub item type
|
||||
func (g GitLabItem) GetType() string {
|
||||
return g.tp
|
||||
}
|
||||
|
||||
// GetPath get addon's sub item path
|
||||
func (g GitLabItem) GetPath() string {
|
||||
return g.path[len(g.basePath)+1:]
|
||||
}
|
||||
|
||||
// GetName get addon's sub item name
|
||||
func (g GitLabItem) GetName() string {
|
||||
return g.name
|
||||
}
|
||||
|
||||
// GetRef ref is empty , use default branch master
|
||||
func (g *gitlabReader) GetRef() string {
|
||||
var ref = "master"
|
||||
if g.h.Meta.GitlabContent.Ref != "" {
|
||||
return g.h.Meta.GitlabContent.Ref
|
||||
}
|
||||
return ref
|
||||
}
|
||||
|
||||
// GetProjectID get gitlab project id
|
||||
func (g *gitlabReader) GetProjectID() int {
|
||||
return g.h.Meta.GitlabContent.PId
|
||||
}
|
||||
|
||||
// GetProjectPath get gitlab project path
|
||||
func (g *gitlabReader) GetProjectPath() string {
|
||||
return g.h.Meta.GitlabContent.Path
|
||||
}
|
||||
|
||||
// ListAddonMeta relative path to repoURL/basePath
|
||||
func (g *gitlabReader) ListAddonMeta() (addonCandidates map[string]SourceMeta, err error) {
|
||||
addonCandidates = make(map[string]SourceMeta)
|
||||
path := g.GetProjectPath()
|
||||
ref := g.GetRef()
|
||||
tree, _, err := g.h.Client.Repositories.ListTree(g.GetProjectID(), &gitlab.ListTreeOptions{Path: &path, Ref: &ref})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, node := range tree {
|
||||
if node.Type == TreeType {
|
||||
items, err := g.listAddonItem(make([]Item, 0), node.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addonCandidates[node.Name] = SourceMeta{
|
||||
Name: node.Name,
|
||||
Items: items,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return addonCandidates, nil
|
||||
}
|
||||
|
||||
func (g *gitlabReader) listAddonItem(item []Item, path string) ([]Item, error) {
|
||||
ref := g.GetRef()
|
||||
tree, _, err := g.h.Client.Repositories.ListTree(g.GetProjectID(), &gitlab.ListTreeOptions{Path: &path, Ref: &ref})
|
||||
if err != nil {
|
||||
return item, err
|
||||
}
|
||||
for _, node := range tree {
|
||||
switch node.Type {
|
||||
case TreeType:
|
||||
item, err = g.listAddonItem(item, node.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case BlobType:
|
||||
item = append(item, &GitLabItem{
|
||||
basePath: g.GetProjectPath(),
|
||||
tp: FileType,
|
||||
path: node.Path,
|
||||
name: node.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
return item, nil
|
||||
}
|
||||
|
||||
// ReadFile read file content from gitlab
|
||||
func (g *gitlabReader) ReadFile(path string) (content string, err error) {
|
||||
ref := g.GetRef()
|
||||
getFile, _, err := g.h.Client.RepositoryFiles.GetFile(g.GetProjectID(), g.GetProjectPath()+"/"+path, &gitlab.GetFileOptions{Ref: &ref})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
decodeString, err := base64.StdEncoding.DecodeString(getFile.Content)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(decodeString), nil
|
||||
}
|
||||
|
||||
func (g *gitlabReader) RelativePath(item Item) string {
|
||||
return item.GetPath()
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 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 addon
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/xanzy/go-gitlab"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
)
|
||||
|
||||
var baseUrl = "/api/v4"
|
||||
|
||||
func gitlabSetup() (client *gitlab.Client, mux *http.ServeMux, teardown func()) {
|
||||
// mux is the HTTP request multiplexer used with the test server.
|
||||
mux = http.NewServeMux()
|
||||
|
||||
apiHandler := http.NewServeMux()
|
||||
apiHandler.Handle(baseUrl+"/", http.StripPrefix(baseUrl, mux))
|
||||
|
||||
// server is a test HTTP server used to provide mock API responses.
|
||||
server := httptest.NewServer(apiHandler)
|
||||
|
||||
// client is the Gitlab client being tested and is
|
||||
// configured to use test server.
|
||||
client, err := gitlab.NewClient("", gitlab.WithBaseURL(server.URL+baseUrl+"/"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return client, mux, server.Close
|
||||
}
|
||||
|
||||
func TestGitlabReader(t *testing.T) {
|
||||
client, mux, teardown := gitlabSetup()
|
||||
gitlabPattern := "/projects/9999/repository/files/"
|
||||
mux.HandleFunc(gitlabPattern, func(rw http.ResponseWriter, req *http.Request) {
|
||||
queryPath := strings.TrimPrefix(req.URL.Path, gitlabPattern)
|
||||
localPath := path.Join(testdataPrefix, queryPath)
|
||||
file, err := testdata.ReadFile(localPath)
|
||||
// test if it's a file
|
||||
if err == nil {
|
||||
content := &gitlab.File{
|
||||
FilePath: localPath,
|
||||
FileName: path.Base(queryPath),
|
||||
Size: *Int(len(file)),
|
||||
Encoding: "base64",
|
||||
Ref: "master",
|
||||
Content: base64.StdEncoding.EncodeToString(file),
|
||||
}
|
||||
res, _ := json.Marshal(content)
|
||||
rw.Write(res)
|
||||
return
|
||||
}
|
||||
|
||||
// otherwise, it could be directory
|
||||
dir, err := testdata.ReadDir(localPath)
|
||||
if err == nil {
|
||||
contents := make([]*gitlab.TreeNode, 0)
|
||||
for _, item := range dir {
|
||||
tp := "file"
|
||||
if item.IsDir() {
|
||||
tp = "dir"
|
||||
}
|
||||
contents = append(contents, &gitlab.TreeNode{
|
||||
ID: "",
|
||||
Name: item.Name(),
|
||||
Type: tp,
|
||||
Path: localPath + "/" + item.Name(),
|
||||
Mode: "",
|
||||
})
|
||||
}
|
||||
dRes, _ := json.Marshal(contents)
|
||||
rw.Write(dRes)
|
||||
return
|
||||
}
|
||||
|
||||
rw.Write([]byte("invalid gitlab query"))
|
||||
})
|
||||
defer teardown()
|
||||
|
||||
gith := &gitlabHelper{
|
||||
Client: client,
|
||||
Meta: &utils.Content{GitlabContent: utils.GitlabContent{
|
||||
PId: 9999,
|
||||
}},
|
||||
}
|
||||
var r AsyncReader = &gitlabReader{gith}
|
||||
_, err := r.ReadFile("example/metadata.yaml")
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
@@ -37,8 +37,10 @@ func (l localReader) ListAddonMeta() (map[string]SourceMeta, error) {
|
||||
}
|
||||
|
||||
func (l localReader) ReadFile(path string) (string, error) {
|
||||
file := strings.TrimPrefix(path, l.name+"/")
|
||||
b, err := ioutil.ReadFile(filepath.Clean(filepath.Join(l.dir, file)))
|
||||
path = strings.TrimPrefix(path, l.name+"/")
|
||||
// for windows
|
||||
path = strings.TrimPrefix(path, l.name+"\\")
|
||||
b, err := ioutil.ReadFile(filepath.Clean(filepath.Join(l.dir, path)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -46,7 +48,8 @@ func (l localReader) ReadFile(path string) (string, error) {
|
||||
}
|
||||
|
||||
func (l localReader) RelativePath(item Item) string {
|
||||
return filepath.Join(l.name, strings.TrimPrefix(item.GetPath()+"/", l.dir))
|
||||
file := strings.TrimPrefix(item.GetPath(), filepath.Clean(l.dir))
|
||||
return filepath.Join(l.name, file)
|
||||
}
|
||||
|
||||
func recursiveFetchFiles(path string, metas *SourceMeta) error {
|
||||
@@ -60,7 +63,7 @@ func recursiveFetchFiles(path string, metas *SourceMeta) error {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
metas.Items = append(metas.Items, OSSItem{tp: "file", path: fmt.Sprintf("%s/%s", path, file.Name()), name: file.Name()})
|
||||
metas.Items = append(metas.Items, OSSItem{tp: "file", path: filepath.Join(path, file.Name()), name: file.Name()})
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -37,11 +37,10 @@ const registriesKey = "registries"
|
||||
type Registry struct {
|
||||
Name string `json:"name"`
|
||||
|
||||
Helm *HelmSource `json:"helm,omitempty"`
|
||||
Git *GitAddonSource `json:"git,omitempty"`
|
||||
OSS *OSSAddonSource `json:"oss,omitempty"`
|
||||
Gitee *GiteeAddonSource `json:"gitee,omitempty"`
|
||||
Gitlab *GitlabAddonSource `json:"gitlab,omitempty"`
|
||||
Helm *HelmSource `json:"helm,omitempty"`
|
||||
Git *GitAddonSource `json:"git,omitempty"`
|
||||
OSS *OSSAddonSource `json:"oss,omitempty"`
|
||||
Gitee *GiteeAddonSource `json:"gitee,omitempty"`
|
||||
}
|
||||
|
||||
// RegistryDataStore CRUD addon registry data in configmap
|
||||
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/xanzy/go-gitlab"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
)
|
||||
@@ -36,10 +35,6 @@ const (
|
||||
DirType = "dir"
|
||||
// FileType means a file
|
||||
FileType = "file"
|
||||
// BlobType means a blob
|
||||
BlobType = "blob"
|
||||
// TreeType means a tree
|
||||
TreeType = "tree"
|
||||
|
||||
bucketTmpl = "%s://%s.%s"
|
||||
singleOSSFileTmpl = "%s/%s"
|
||||
@@ -68,19 +63,48 @@ type GiteeAddonSource struct {
|
||||
Token string `json:"token,omitempty"`
|
||||
}
|
||||
|
||||
// GitlabAddonSource defines the information about the Gitlab as addon source
|
||||
type GitlabAddonSource struct {
|
||||
URL string `json:"url,omitempty" validate:"required"`
|
||||
Repo string `json:"repo,omitempty" validate:"required"`
|
||||
Path string `json:"path,omitempty"`
|
||||
Token string `json:"token,omitempty"`
|
||||
}
|
||||
|
||||
// HelmSource defines the information about the helm repo addon source
|
||||
type HelmSource struct {
|
||||
URL string `json:"url,omitempty" validate:"required"`
|
||||
}
|
||||
|
||||
// SafeCopier is an interface to copy Struct without sensitive fields, such as Token, Username, Password
|
||||
type SafeCopier interface {
|
||||
SafeCopy() interface{}
|
||||
}
|
||||
|
||||
// SafeCopy hides field Token
|
||||
func (g *GitAddonSource) SafeCopy() *GitAddonSource {
|
||||
if g == nil {
|
||||
return nil
|
||||
}
|
||||
return &GitAddonSource{
|
||||
URL: g.URL,
|
||||
Path: g.Path,
|
||||
}
|
||||
}
|
||||
|
||||
// SafeCopy hides field Token
|
||||
func (g *GiteeAddonSource) SafeCopy() *GiteeAddonSource {
|
||||
if g == nil {
|
||||
return nil
|
||||
}
|
||||
return &GiteeAddonSource{
|
||||
URL: g.URL,
|
||||
Path: g.Path,
|
||||
}
|
||||
}
|
||||
|
||||
// SafeCopy hides field Username, Password
|
||||
func (h *HelmSource) SafeCopy() *HelmSource {
|
||||
if h == nil {
|
||||
return nil
|
||||
}
|
||||
return &HelmSource{
|
||||
URL: h.URL,
|
||||
}
|
||||
}
|
||||
|
||||
// Item is a partial interface for github.RepositoryContent
|
||||
type Item interface {
|
||||
// GetType return "dir" or "file"
|
||||
@@ -135,16 +159,15 @@ func pathWithParent(subPath, parent string) string {
|
||||
type ReaderType string
|
||||
|
||||
const (
|
||||
gitType ReaderType = "git"
|
||||
ossType ReaderType = "oss"
|
||||
giteeType ReaderType = "gitee"
|
||||
gitlabType ReaderType = "gitlab"
|
||||
gitType ReaderType = "git"
|
||||
ossType ReaderType = "oss"
|
||||
giteeType ReaderType = "gitee"
|
||||
)
|
||||
|
||||
// NewAsyncReader create AsyncReader from
|
||||
// 1. GitHub url and directory
|
||||
// 2. OSS endpoint and bucket
|
||||
func NewAsyncReader(baseURL, bucket, repo, subPath, token string, rdType ReaderType) (AsyncReader, error) {
|
||||
func NewAsyncReader(baseURL, bucket, subPath, token string, rdType ReaderType) (AsyncReader, error) {
|
||||
|
||||
switch rdType {
|
||||
case gitType:
|
||||
@@ -196,63 +219,23 @@ func NewAsyncReader(baseURL, bucket, repo, subPath, token string, rdType ReaderT
|
||||
return &giteeReader{
|
||||
h: gitee,
|
||||
}, nil
|
||||
case gitlabType:
|
||||
baseURL = strings.TrimSuffix(baseURL, ".git")
|
||||
u, err := url.Parse(baseURL)
|
||||
if err != nil {
|
||||
return nil, errors.New("addon registry invalid")
|
||||
}
|
||||
_, content, err := utils.ParseGitlab(u.String(), repo)
|
||||
content.GitlabContent.Path = subPath
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gitlabHelper, err := createGitlabHelper(content, token)
|
||||
if err != nil {
|
||||
return nil, errors.New("addon registry connect fail")
|
||||
}
|
||||
|
||||
err = gitlabHelper.getGitlabProject(content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &gitlabReader{
|
||||
h: gitlabHelper,
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid addon registry type '%s'", rdType)
|
||||
}
|
||||
|
||||
// getGitlabProject get gitlab project , set project id
|
||||
func (h *gitlabHelper) getGitlabProject(content *utils.Content) error {
|
||||
projectURL := content.GitlabContent.Owner + "/" + content.GitlabContent.Repo
|
||||
projects, _, err := h.Client.Projects.GetProject(projectURL, &gitlab.GetProjectOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
content.GitlabContent.PId = projects.ID
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// BuildReader will build a AsyncReader from registry, AsyncReader are needed to read addon files
|
||||
func (r *Registry) BuildReader() (AsyncReader, error) {
|
||||
if r.OSS != nil {
|
||||
o := r.OSS
|
||||
return NewAsyncReader(o.Endpoint, o.Bucket, "", o.Path, "", ossType)
|
||||
return NewAsyncReader(o.Endpoint, o.Bucket, o.Path, "", ossType)
|
||||
}
|
||||
if r.Git != nil {
|
||||
g := r.Git
|
||||
return NewAsyncReader(g.URL, "", "", g.Path, g.Token, gitType)
|
||||
return NewAsyncReader(g.URL, "", g.Path, g.Token, gitType)
|
||||
}
|
||||
if r.Gitee != nil {
|
||||
g := r.Gitee
|
||||
return NewAsyncReader(g.URL, "", "", g.Path, g.Token, giteeType)
|
||||
}
|
||||
if r.Gitlab != nil {
|
||||
g := r.Gitlab
|
||||
return NewAsyncReader(g.URL, "", g.Repo, g.Path, g.Token, gitlabType)
|
||||
return NewAsyncReader(g.URL, "", g.Path, g.Token, giteeType)
|
||||
}
|
||||
return nil, errors.New("registry don't have enough info to build a reader")
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ func TestPathWithParent(t *testing.T) {
|
||||
|
||||
func TestConvert2OssItem(t *testing.T) {
|
||||
subPath := "sub-addons"
|
||||
reader, err := NewAsyncReader("ep-beijing.com", "bucket", "", subPath, "", ossType)
|
||||
reader, err := NewAsyncReader("ep-beijing.com", "bucket", subPath, "", ossType)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -115,3 +115,30 @@ func TestConvert2OssItem(t *testing.T) {
|
||||
assert.Equal(t, expectItemCase, addonMetas)
|
||||
|
||||
}
|
||||
|
||||
func TestSafeCopy(t *testing.T) {
|
||||
var git *GitAddonSource
|
||||
sgit := git.SafeCopy()
|
||||
assert.Nil(t, sgit)
|
||||
git = &GitAddonSource{URL: "http://github.com/kubevela", Path: "addons", Token: "123456"}
|
||||
sgit = git.SafeCopy()
|
||||
assert.Empty(t, sgit.Token)
|
||||
assert.Equal(t, "http://github.com/kubevela", sgit.URL)
|
||||
assert.Equal(t, "addons", sgit.Path)
|
||||
|
||||
var gitee *GiteeAddonSource
|
||||
sgitee := gitee.SafeCopy()
|
||||
assert.Nil(t, sgitee)
|
||||
gitee = &GiteeAddonSource{URL: "http://gitee.com/kubevela", Path: "addons", Token: "123456"}
|
||||
sgitee = gitee.SafeCopy()
|
||||
assert.Empty(t, sgitee.Token)
|
||||
assert.Equal(t, "http://gitee.com/kubevela", sgitee.URL)
|
||||
assert.Equal(t, "addons", sgitee.Path)
|
||||
|
||||
var helm *HelmSource
|
||||
shelm := helm.SafeCopy()
|
||||
assert.Nil(t, shelm)
|
||||
helm = &HelmSource{URL: "https://hub.vela.com/chartrepo/addons"}
|
||||
shelm = helm.SafeCopy()
|
||||
assert.Equal(t, "https://hub.vela.com/chartrepo/addons", shelm.URL)
|
||||
}
|
||||
|
||||
100
pkg/apiserver/collect/suit_test.go
Normal file
100
pkg/apiserver/collect/suit_test.go
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
Copyright 2021 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 collect
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/utils/pointer"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/clients"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/datastore"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/datastore/kubeapi"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/datastore/mongodb"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
)
|
||||
|
||||
var cfg *rest.Config
|
||||
var k8sClient client.Client
|
||||
var testEnv *envtest.Environment
|
||||
|
||||
func TestCalculateJob(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Caclculate systemInfo cronJob")
|
||||
}
|
||||
|
||||
var _ = BeforeSuite(func(done Done) {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
By("bootstrapping test environment")
|
||||
|
||||
testEnv = &envtest.Environment{
|
||||
ControlPlaneStartTimeout: time.Minute * 3,
|
||||
ControlPlaneStopTimeout: time.Minute,
|
||||
UseExistingCluster: pointer.BoolPtr(false),
|
||||
CRDDirectoryPaths: []string{"../../../charts/vela-core/crds"},
|
||||
}
|
||||
|
||||
By("start kube test env")
|
||||
var err error
|
||||
cfg, err = testEnv.Start()
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cfg).ToNot(BeNil())
|
||||
|
||||
By("new kube client")
|
||||
cfg.Timeout = time.Minute * 2
|
||||
k8sClient, err = client.New(cfg, client.Options{Scheme: common.Scheme})
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(k8sClient).ToNot(BeNil())
|
||||
By("new kube client success")
|
||||
clients.SetKubeClient(k8sClient)
|
||||
Expect(err).Should(BeNil())
|
||||
close(done)
|
||||
}, 240)
|
||||
|
||||
var _ = AfterSuite(func() {
|
||||
By("tearing down the test environment")
|
||||
err := testEnv.Stop()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
func NewDatastore(cfg datastore.Config) (ds datastore.DataStore, err error) {
|
||||
switch cfg.Type {
|
||||
case "mongodb":
|
||||
ds, err = mongodb.New(context.Background(), cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create mongodb datastore instance failure %w", err)
|
||||
}
|
||||
case "kubeapi":
|
||||
ds, err = kubeapi.New(context.Background(), cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create mongodb datastore instance failure %w", err)
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("not support datastore type %s", cfg.Type)
|
||||
}
|
||||
return ds, nil
|
||||
}
|
||||
331
pkg/apiserver/collect/system_info_collect.go
Normal file
331
pkg/apiserver/collect/system_info_collect.go
Normal file
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
Copyright 2021 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 collect
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
client2 "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"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/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/clients"
|
||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/datastore"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/log"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/model"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/util/retry"
|
||||
)
|
||||
|
||||
// TopKFrequent top frequency component or trait definition
|
||||
var TopKFrequent = 5
|
||||
|
||||
// CrontabSpec the cron spec of job running
|
||||
var CrontabSpec = "0 0 * * *"
|
||||
|
||||
// maximum tires is 5, initial duration is 1 minute
|
||||
var waitBackOff = wait.Backoff{
|
||||
Steps: 5,
|
||||
Duration: 1 * time.Minute,
|
||||
Factor: 5.0,
|
||||
Jitter: 0.1,
|
||||
}
|
||||
|
||||
// InfoCalculateCronJob is the cronJob to calculate the system info store in db
|
||||
type InfoCalculateCronJob struct {
|
||||
ds datastore.DataStore
|
||||
}
|
||||
|
||||
// StartCalculatingInfoCronJob will start the system info calculating job.
|
||||
func StartCalculatingInfoCronJob(ds datastore.DataStore) {
|
||||
i := InfoCalculateCronJob{
|
||||
ds: ds,
|
||||
}
|
||||
|
||||
// run calculate job in 0:00 of every day
|
||||
i.start(CrontabSpec)
|
||||
}
|
||||
|
||||
func (i InfoCalculateCronJob) start(cronSpec string) {
|
||||
c := cron.New(cron.WithChain(
|
||||
// don't let job panic crash whole api-server process
|
||||
cron.Recover(cron.DefaultLogger),
|
||||
))
|
||||
|
||||
// ignore the entityId and error, the cron spec is defined by hard code, mustn't generate error
|
||||
_, _ = c.AddFunc(cronSpec, func() {
|
||||
|
||||
// ExponentialBackoff retry this job
|
||||
err := retry.OnError(waitBackOff, func(err error) bool {
|
||||
// always retry
|
||||
return true
|
||||
}, func() error {
|
||||
if err := i.run(); err != nil {
|
||||
log.Logger.Errorf("Failed to calculate systemInfo, will try again after several minute error %v", err)
|
||||
return err
|
||||
}
|
||||
log.Logger.Info("Successfully to calculate systemInfo")
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Logger.Errorf("After 5 tries the calculating cronJob failed: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
c.Start()
|
||||
}
|
||||
|
||||
func (i InfoCalculateCronJob) run() error {
|
||||
ctx := context.Background()
|
||||
systemInfo := model.SystemInfo{}
|
||||
e, err := i.ds.List(ctx, &systemInfo, &datastore.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// if no systemInfo means velaux have not have not send get request,so skip calculate job
|
||||
if len(e) == 0 {
|
||||
return nil
|
||||
}
|
||||
info, ok := e[0].(*model.SystemInfo)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
// if disable collection skip calculate job
|
||||
if !info.EnableCollection {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := i.calculateAndUpdate(ctx, *info); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i InfoCalculateCronJob) calculateAndUpdate(ctx context.Context, systemInfo model.SystemInfo) error {
|
||||
|
||||
appCount, topKComp, topKTrait, topWorkflowStep, topKPolicy, err := i.calculateAppInfo(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
enabledAddon, err := i.calculateAddonInfo(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clusterCount, err := i.calculateClusterInfo(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
statisticInfo := model.StatisticInfo{
|
||||
AppCount: genCountInfo(appCount),
|
||||
TopKCompDef: topKComp,
|
||||
TopKTraitDef: topKTrait,
|
||||
TopKWorkflowStepDef: topWorkflowStep,
|
||||
TopKPolicyDef: topKPolicy,
|
||||
ClusterCount: genClusterCountInfo(clusterCount),
|
||||
EnabledAddon: enabledAddon,
|
||||
UpdateTime: time.Now(),
|
||||
}
|
||||
|
||||
systemInfo.StatisticInfo = statisticInfo
|
||||
if err := i.ds.Put(ctx, &systemInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i InfoCalculateCronJob) calculateAppInfo(ctx context.Context) (int, []string, []string, []string, []string, error) {
|
||||
var err error
|
||||
var appCount int
|
||||
compDef := map[string]int{}
|
||||
traitDef := map[string]int{}
|
||||
workflowDef := map[string]int{}
|
||||
policyDef := map[string]int{}
|
||||
|
||||
var app = model.Application{}
|
||||
entities, err := i.ds.List(ctx, &app, &datastore.ListOptions{})
|
||||
if err != nil {
|
||||
return 0, nil, nil, nil, nil, err
|
||||
}
|
||||
for _, entity := range entities {
|
||||
appModel, ok := entity.(*model.Application)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
appCount++
|
||||
comp := model.ApplicationComponent{
|
||||
AppPrimaryKey: appModel.Name,
|
||||
}
|
||||
comps, err := i.ds.List(ctx, &comp, &datastore.ListOptions{})
|
||||
if err != nil {
|
||||
return 0, nil, nil, nil, nil, err
|
||||
}
|
||||
for _, e := range comps {
|
||||
c, ok := e.(*model.ApplicationComponent)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
compDef[c.Type]++
|
||||
for _, t := range c.Traits {
|
||||
traitDef[t.Type]++
|
||||
}
|
||||
}
|
||||
|
||||
workflow := model.Workflow{
|
||||
AppPrimaryKey: app.PrimaryKey(),
|
||||
}
|
||||
workflows, err := i.ds.List(ctx, &workflow, &datastore.ListOptions{})
|
||||
if err != nil {
|
||||
return 0, nil, nil, nil, nil, err
|
||||
}
|
||||
for _, e := range workflows {
|
||||
w, ok := e.(*model.Workflow)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
for _, step := range w.Steps {
|
||||
workflowDef[step.Type]++
|
||||
}
|
||||
}
|
||||
|
||||
policy := model.ApplicationPolicy{
|
||||
AppPrimaryKey: app.PrimaryKey(),
|
||||
}
|
||||
policies, err := i.ds.List(ctx, &policy, &datastore.ListOptions{})
|
||||
if err != nil {
|
||||
return 0, nil, nil, nil, nil, err
|
||||
}
|
||||
for _, e := range policies {
|
||||
p, ok := e.(*model.ApplicationPolicy)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
policyDef[p.Type]++
|
||||
}
|
||||
}
|
||||
|
||||
return appCount, topKFrequent(compDef, TopKFrequent), topKFrequent(traitDef, TopKFrequent), topKFrequent(workflowDef, TopKFrequent), topKFrequent(policyDef, TopKFrequent), nil
|
||||
}
|
||||
|
||||
func (i InfoCalculateCronJob) calculateAddonInfo(ctx context.Context) (map[string]string, error) {
|
||||
client, err := clients.GetKubeClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
apps := &v1beta1.ApplicationList{}
|
||||
if err := client.List(ctx, apps, client2.InNamespace(types.DefaultKubeVelaNS), client2.HasLabels{oam.LabelAddonName}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := map[string]string{}
|
||||
for _, application := range apps.Items {
|
||||
if addonName := application.Labels[oam.LabelAddonName]; addonName != "" {
|
||||
var status string
|
||||
switch application.Status.Phase {
|
||||
case common.ApplicationRunning:
|
||||
status = "enabled"
|
||||
case common.ApplicationDeleting:
|
||||
status = "disabling"
|
||||
default:
|
||||
status = "enabling"
|
||||
}
|
||||
res[addonName] = status
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (i InfoCalculateCronJob) calculateClusterInfo(ctx context.Context) (int, error) {
|
||||
client, err := clients.GetKubeClient()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
cs, err := multicluster.ListVirtualClusters(ctx, client)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(cs), nil
|
||||
}
|
||||
|
||||
type defPair struct {
|
||||
name string
|
||||
count int
|
||||
}
|
||||
|
||||
func topKFrequent(defs map[string]int, k int) []string {
|
||||
var pairs []defPair
|
||||
var res []string
|
||||
for name, num := range defs {
|
||||
pairs = append(pairs, defPair{name: name, count: num})
|
||||
}
|
||||
sort.Slice(pairs, func(i, j int) bool {
|
||||
return pairs[i].count >= pairs[j].count
|
||||
})
|
||||
i := 0
|
||||
for _, pair := range pairs {
|
||||
res = append(res, pair.name)
|
||||
i++
|
||||
if i == k {
|
||||
break
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func genCountInfo(num int) string {
|
||||
switch {
|
||||
case num < 10:
|
||||
return "<10"
|
||||
case num < 50:
|
||||
return "<50"
|
||||
case num < 100:
|
||||
return "<100"
|
||||
case num < 500:
|
||||
return "<500"
|
||||
case num < 2000:
|
||||
return "<2000"
|
||||
case num < 5000:
|
||||
return "<5000"
|
||||
case num < 10000:
|
||||
return "<10000"
|
||||
default:
|
||||
return ">=10000"
|
||||
}
|
||||
}
|
||||
|
||||
func genClusterCountInfo(num int) string {
|
||||
switch {
|
||||
case num < 3:
|
||||
return "<3"
|
||||
case num < 10:
|
||||
return "<10"
|
||||
case num < 50:
|
||||
return "<50"
|
||||
default:
|
||||
return ">=50"
|
||||
}
|
||||
}
|
||||
273
pkg/apiserver/collect/system_info_collect_test.go
Normal file
273
pkg/apiserver/collect/system_info_collect_test.go
Normal file
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
Copyright 2021 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 collect
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/onsi/gomega/format"
|
||||
|
||||
"gotest.tools/assert"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"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/pkg/apiserver/datastore"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/model"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
)
|
||||
|
||||
var _ = Describe("Test calculate cronJob", func() {
|
||||
var (
|
||||
ds datastore.DataStore
|
||||
testProject string
|
||||
i InfoCalculateCronJob
|
||||
ctx = context.Background()
|
||||
)
|
||||
|
||||
mockDataInDs := func() {
|
||||
app1 := model.Application{BaseModel: model.BaseModel{CreateTime: time.Now()}, Name: "app1", Project: testProject}
|
||||
app2 := model.Application{BaseModel: model.BaseModel{CreateTime: time.Now()}, Name: "app2", Project: testProject}
|
||||
trait1 := model.ApplicationTrait{Type: "rollout"}
|
||||
trait2 := model.ApplicationTrait{Type: "expose"}
|
||||
trait3 := model.ApplicationTrait{Type: "rollout"}
|
||||
trait4 := model.ApplicationTrait{Type: "patch"}
|
||||
trait5 := model.ApplicationTrait{Type: "patch"}
|
||||
trait6 := model.ApplicationTrait{Type: "rollout"}
|
||||
appComp1 := model.ApplicationComponent{AppPrimaryKey: app1.PrimaryKey(), Name: "comp1", Type: "helm", Traits: []model.ApplicationTrait{trait1, trait4}}
|
||||
appComp2 := model.ApplicationComponent{AppPrimaryKey: app2.PrimaryKey(), Name: "comp2", Type: "webservice", Traits: []model.ApplicationTrait{trait3}}
|
||||
appComp3 := model.ApplicationComponent{AppPrimaryKey: app2.PrimaryKey(), Name: "comp3", Type: "webservice", Traits: []model.ApplicationTrait{trait2, trait5, trait6}}
|
||||
Expect(ds.Add(ctx, &app1)).Should(SatisfyAny(BeNil(), DataExistMatcher{}))
|
||||
Expect(ds.Add(ctx, &app2)).Should(SatisfyAny(BeNil(), DataExistMatcher{}))
|
||||
Expect(ds.Add(ctx, &appComp1)).Should(SatisfyAny(BeNil(), DataExistMatcher{}))
|
||||
Expect(ds.Add(ctx, &appComp2)).Should(SatisfyAny(BeNil(), DataExistMatcher{}))
|
||||
Expect(ds.Add(ctx, &appComp3)).Should(SatisfyAny(BeNil(), DataExistMatcher{}))
|
||||
Expect(k8sClient.Create(ctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "vela-system"}})).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
|
||||
Expect(k8sClient.Create(ctx, &v1beta1.Application{ObjectMeta: metav1.ObjectMeta{Namespace: "vela-system", Name: "addon-fluxcd", Labels: map[string]string{oam.LabelAddonName: "fluxcd"}}, Spec: v1beta1.ApplicationSpec{
|
||||
Components: []common.ApplicationComponent{},
|
||||
}})).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
|
||||
Expect(k8sClient.Create(ctx, &v1beta1.Application{ObjectMeta: metav1.ObjectMeta{Namespace: "vela-system", Name: "addon-rollout", Labels: map[string]string{oam.LabelAddonName: "rollout"}}, Spec: v1beta1.ApplicationSpec{
|
||||
Components: []common.ApplicationComponent{},
|
||||
}})).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
|
||||
}
|
||||
|
||||
BeforeEach(func() {
|
||||
var err error
|
||||
ds, err = NewDatastore(datastore.Config{Type: "kubeapi", Database: "target-test-kubevela"})
|
||||
Expect(ds).ShouldNot(BeNil())
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
testProject = "test-cronjob-project"
|
||||
mockDataInDs()
|
||||
i = InfoCalculateCronJob{
|
||||
ds: ds,
|
||||
}
|
||||
systemInfo := model.SystemInfo{InstallID: "test-id", EnableCollection: true}
|
||||
Expect(ds.Add(ctx, &systemInfo)).Should(SatisfyAny(BeNil(), DataExistMatcher{}))
|
||||
})
|
||||
|
||||
It("Test calculate app Info", func() {
|
||||
appNum, topKCom, topKTrait, _, _, err := i.calculateAppInfo(ctx)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(appNum).Should(BeEquivalentTo(2))
|
||||
Expect(topKCom).Should(BeEquivalentTo([]string{"webservice", "helm"}))
|
||||
Expect(topKTrait).Should(BeEquivalentTo([]string{"rollout", "patch", "expose"}))
|
||||
})
|
||||
|
||||
It("Test calculate addon Info", func() {
|
||||
enabledAddon, err := i.calculateAddonInfo(ctx)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(enabledAddon).Should(BeEquivalentTo(map[string]string{
|
||||
"fluxcd": "enabling",
|
||||
"rollout": "enabling",
|
||||
}))
|
||||
})
|
||||
|
||||
It("Test calculate cluster Info", func() {
|
||||
clusterNum, err := i.calculateClusterInfo(ctx)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(clusterNum).Should(BeEquivalentTo(1))
|
||||
})
|
||||
|
||||
It("Test calculateAndUpdate func", func() {
|
||||
systemInfo := model.SystemInfo{}
|
||||
es, err := ds.List(ctx, &systemInfo, &datastore.ListOptions{})
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(es)).Should(BeEquivalentTo(1))
|
||||
info, ok := es[0].(*model.SystemInfo)
|
||||
Expect(ok).Should(BeTrue())
|
||||
Expect(info.InstallID).Should(BeEquivalentTo("test-id"))
|
||||
|
||||
Expect(i.calculateAndUpdate(ctx, *info)).Should(BeNil())
|
||||
|
||||
systemInfo = model.SystemInfo{}
|
||||
es, err = ds.List(ctx, &systemInfo, &datastore.ListOptions{})
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(es)).Should(BeEquivalentTo(1))
|
||||
info, ok = es[0].(*model.SystemInfo)
|
||||
Expect(ok).Should(BeTrue())
|
||||
Expect(info.InstallID).Should(BeEquivalentTo("test-id"))
|
||||
Expect(info.StatisticInfo.AppCount).Should(BeEquivalentTo("<10"))
|
||||
Expect(info.StatisticInfo.ClusterCount).Should(BeEquivalentTo("<3"))
|
||||
Expect(info.StatisticInfo.TopKCompDef).Should(BeEquivalentTo([]string{"webservice", "helm"}))
|
||||
Expect(info.StatisticInfo.TopKTraitDef).Should(BeEquivalentTo([]string{"rollout", "patch", "expose"}))
|
||||
Expect(info.StatisticInfo.EnabledAddon).Should(BeEquivalentTo(map[string]string{
|
||||
"fluxcd": "enabling",
|
||||
"rollout": "enabling",
|
||||
}))
|
||||
})
|
||||
|
||||
It("Test run func", func() {
|
||||
app3 := model.Application{BaseModel: model.BaseModel{CreateTime: time.Now()}, Name: "app3", Project: testProject}
|
||||
Expect(ds.Add(ctx, &app3)).Should(BeNil())
|
||||
|
||||
systemInfo := model.SystemInfo{InstallID: "test-id", EnableCollection: false}
|
||||
Expect(ds.Put(ctx, &systemInfo)).Should(BeNil())
|
||||
Expect(i.run()).Should(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
func TestGenCountInfo(t *testing.T) {
|
||||
testcases := []struct {
|
||||
count int
|
||||
res string
|
||||
}{
|
||||
{
|
||||
count: 3,
|
||||
res: "<10",
|
||||
},
|
||||
{
|
||||
count: 14,
|
||||
res: "<50",
|
||||
},
|
||||
{
|
||||
count: 80,
|
||||
res: "<100",
|
||||
},
|
||||
{
|
||||
count: 350,
|
||||
res: "<500",
|
||||
},
|
||||
{
|
||||
count: 1800,
|
||||
res: "<2000",
|
||||
},
|
||||
{
|
||||
count: 4000,
|
||||
res: "<5000",
|
||||
},
|
||||
{
|
||||
count: 9000,
|
||||
res: "<10000",
|
||||
},
|
||||
{
|
||||
count: 30000,
|
||||
res: ">=10000",
|
||||
},
|
||||
}
|
||||
for _, testcase := range testcases {
|
||||
assert.Equal(t, genCountInfo(testcase.count), testcase.res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenClusterCountInfo(t *testing.T) {
|
||||
testcases := []struct {
|
||||
count int
|
||||
res string
|
||||
}{
|
||||
{
|
||||
count: 2,
|
||||
res: "<3",
|
||||
},
|
||||
{
|
||||
count: 7,
|
||||
res: "<10",
|
||||
},
|
||||
{
|
||||
count: 34,
|
||||
res: "<50",
|
||||
},
|
||||
{
|
||||
count: 100,
|
||||
res: ">=50",
|
||||
},
|
||||
}
|
||||
for _, testcase := range testcases {
|
||||
assert.Equal(t, genClusterCountInfo(testcase.count), testcase.res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTopKFrequent(t *testing.T) {
|
||||
testCases := []struct {
|
||||
def map[string]int
|
||||
k int
|
||||
res []string
|
||||
}{
|
||||
{
|
||||
def: map[string]int{
|
||||
"rollout": 4,
|
||||
"patch": 3,
|
||||
"expose": 6,
|
||||
},
|
||||
k: 3,
|
||||
res: []string{"expose", "rollout", "patch"},
|
||||
},
|
||||
{
|
||||
// just return top2
|
||||
def: map[string]int{
|
||||
"rollout": 4,
|
||||
"patch": 3,
|
||||
"expose": 6,
|
||||
},
|
||||
k: 2,
|
||||
res: []string{"expose", "rollout"},
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
assert.DeepEqual(t, topKFrequent(testCase.def, testCase.k), testCase.res)
|
||||
}
|
||||
}
|
||||
|
||||
type DataExistMatcher struct{}
|
||||
|
||||
// Match matches error.
|
||||
func (matcher DataExistMatcher) Match(actual interface{}) (success bool, err error) {
|
||||
if actual == nil {
|
||||
return false, nil
|
||||
}
|
||||
actualError := actual.(error)
|
||||
return errors.Is(actualError, datastore.ErrRecordExist), nil
|
||||
}
|
||||
|
||||
// FailureMessage builds an error message.
|
||||
func (matcher DataExistMatcher) FailureMessage(actual interface{}) (message string) {
|
||||
return format.Message(actual, "to be already exist")
|
||||
}
|
||||
|
||||
// NegatedFailureMessage builds an error message.
|
||||
func (matcher DataExistMatcher) NegatedFailureMessage(actual interface{}) (message string) {
|
||||
return format.Message(actual, "not to be already exist")
|
||||
}
|
||||
@@ -16,6 +16,8 @@ limitations under the License.
|
||||
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
func init() {
|
||||
RegisterModel(&SystemInfo{})
|
||||
}
|
||||
@@ -30,10 +32,11 @@ const (
|
||||
// SystemInfo systemInfo model
|
||||
type SystemInfo struct {
|
||||
BaseModel
|
||||
InstallID string `json:"installID"`
|
||||
EnableCollection bool `json:"enableCollection"`
|
||||
LoginType string `json:"loginType"`
|
||||
DexConfig DexConfig `json:"dexConfig,omitempty"`
|
||||
InstallID string `json:"installID"`
|
||||
EnableCollection bool `json:"enableCollection"`
|
||||
LoginType string `json:"loginType"`
|
||||
DexConfig DexConfig `json:"dexConfig,omitempty"`
|
||||
StatisticInfo StatisticInfo `json:"statisticInfo,omitempty"`
|
||||
}
|
||||
|
||||
// DexConfig dex config
|
||||
@@ -46,6 +49,18 @@ type DexConfig struct {
|
||||
EnablePasswordDB bool `json:"enablePasswordDB"`
|
||||
}
|
||||
|
||||
// StatisticInfo the system statistic info
|
||||
type StatisticInfo struct {
|
||||
ClusterCount string `json:"clusterCount,omitempty"`
|
||||
AppCount string `json:"appCount,omitempty"`
|
||||
EnabledAddon map[string]string `json:"enabledAddon,omitempty"`
|
||||
TopKCompDef []string `json:"topKCompDef,omitempty"`
|
||||
TopKTraitDef []string `json:"topKTraitDef,omitempty"`
|
||||
TopKWorkflowStepDef []string `json:"topKWorkflowStepDef,omitempty"`
|
||||
TopKPolicyDef []string `json:"topKPolicyDef,omitempty"`
|
||||
UpdateTime time.Time `json:"updateTime,omitempty"`
|
||||
}
|
||||
|
||||
// DexStorage dex storage
|
||||
type DexStorage struct {
|
||||
Type string `json:"type"`
|
||||
|
||||
@@ -74,31 +74,28 @@ type NameAlias struct {
|
||||
|
||||
// CreateAddonRegistryRequest defines the format for addon registry create request
|
||||
type CreateAddonRegistryRequest struct {
|
||||
Name string `json:"name" validate:"checkname"`
|
||||
Helm *addon.HelmSource `json:"helm,omitempty"`
|
||||
Git *addon.GitAddonSource `json:"git,omitempty" `
|
||||
Oss *addon.OSSAddonSource `json:"oss,omitempty"`
|
||||
Gitee *addon.GiteeAddonSource `json:"gitee,omitempty" `
|
||||
Gitlab *addon.GitlabAddonSource `json:"gitlab,omitempty" `
|
||||
Name string `json:"name" validate:"checkname"`
|
||||
Helm *addon.HelmSource `json:"helm,omitempty"`
|
||||
Git *addon.GitAddonSource `json:"git,omitempty" `
|
||||
Oss *addon.OSSAddonSource `json:"oss,omitempty"`
|
||||
Gitee *addon.GiteeAddonSource `json:"gitee,omitempty" `
|
||||
}
|
||||
|
||||
// UpdateAddonRegistryRequest defines the format for addon registry update request
|
||||
type UpdateAddonRegistryRequest struct {
|
||||
Helm *addon.HelmSource `json:"helm,omitempty"`
|
||||
Git *addon.GitAddonSource `json:"git,omitempty"`
|
||||
Oss *addon.OSSAddonSource `json:"oss,omitempty"`
|
||||
Gitee *addon.GiteeAddonSource `json:"gitee,omitempty" `
|
||||
Gitlab *addon.GitlabAddonSource `json:"gitlab,omitempty" `
|
||||
Helm *addon.HelmSource `json:"helm,omitempty"`
|
||||
Git *addon.GitAddonSource `json:"git,omitempty"`
|
||||
Oss *addon.OSSAddonSource `json:"oss,omitempty"`
|
||||
Gitee *addon.GiteeAddonSource `json:"gitee,omitempty" `
|
||||
}
|
||||
|
||||
// AddonRegistry defines the format for a single addon registry
|
||||
type AddonRegistry struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Helm *addon.HelmSource `json:"helm,omitempty"`
|
||||
Git *addon.GitAddonSource `json:"git,omitempty"`
|
||||
OSS *addon.OSSAddonSource `json:"oss,omitempty"`
|
||||
Gitee *addon.GiteeAddonSource `json:"gitee,omitempty" `
|
||||
Gitlab *addon.GitlabAddonSource `json:"gitlab,omitempty" `
|
||||
Name string `json:"name" validate:"required"`
|
||||
Helm *addon.HelmSource `json:"helm,omitempty"`
|
||||
Git *addon.GitAddonSource `json:"git,omitempty"`
|
||||
OSS *addon.OSSAddonSource `json:"oss,omitempty"`
|
||||
Gitee *addon.GiteeAddonSource `json:"gitee,omitempty" `
|
||||
}
|
||||
|
||||
// ListAddonRegistryResponse list addon registry
|
||||
@@ -202,6 +199,7 @@ type Config struct {
|
||||
Name string `json:"name"`
|
||||
Project string `json:"project"`
|
||||
Identifier string `json:"identifier"`
|
||||
Alias string `json:"alias"`
|
||||
Description string `json:"description"`
|
||||
CreatedTime *time.Time `json:"createdTime"`
|
||||
UpdatedTime *time.Time `json:"updatedTime"`
|
||||
@@ -411,6 +409,7 @@ type CreateApplicationRequest struct {
|
||||
type CreateConfigRequest struct {
|
||||
Name string `json:"name" validate:"checkname"`
|
||||
Alias string `json:"alias"`
|
||||
Description string `json:"description"`
|
||||
Project string `json:"project"`
|
||||
ComponentType string `json:"componentType" validate:"checkname"`
|
||||
Properties string `json:"properties,omitempty"`
|
||||
@@ -1117,13 +1116,27 @@ type DetailRevisionResponse struct {
|
||||
type SystemInfoResponse struct {
|
||||
SystemInfo
|
||||
SystemVersion SystemVersion `json:"systemVersion"`
|
||||
StatisticInfo StatisticInfo `json:"statisticInfo,omitempty"`
|
||||
}
|
||||
|
||||
// SystemInfo system info
|
||||
type SystemInfo struct {
|
||||
InstallID string `json:"installID"`
|
||||
EnableCollection bool `json:"enableCollection"`
|
||||
LoginType string `json:"loginType"`
|
||||
PlatformID string `json:"platformID"`
|
||||
EnableCollection bool `json:"enableCollection"`
|
||||
LoginType string `json:"loginType"`
|
||||
InstallTime time.Time `json:"installTime,omitempty"`
|
||||
}
|
||||
|
||||
// StatisticInfo generated by cronJob running in backend
|
||||
type StatisticInfo struct {
|
||||
ClusterCount string `json:"clusterCount,omitempty"`
|
||||
AppCount string `json:"appCount,omitempty"`
|
||||
EnableAddonList map[string]string `json:"enableAddonList,omitempty"`
|
||||
ComponentDefinitionTopList []string `json:"componentDefinitionTopList,omitempty"`
|
||||
TraitDefinitionTopList []string `json:"traitDefinitionTopList,omitempty"`
|
||||
WorkflowDefinitionTopList []string `json:"workflowDefinitionTopList,omitempty"`
|
||||
PolicyDefinitionTopList []string `json:"policyDefinitionTopList,omitempty"`
|
||||
UpdateTime time.Time `json:"updateTime,omitempty"`
|
||||
}
|
||||
|
||||
// SystemInfoRequest request by update SystemInfo
|
||||
|
||||
@@ -23,6 +23,8 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/collect"
|
||||
|
||||
restfulspec "github.com/emicklei/go-restful-openapi/v2"
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
"github.com/go-openapi/spec"
|
||||
@@ -60,6 +62,9 @@ type Config struct {
|
||||
|
||||
// AddonCacheTime is how long between two cache operations
|
||||
AddonCacheTime time.Duration
|
||||
|
||||
// DisableStatisticCronJob close the calculate system info cronJob
|
||||
DisableStatisticCronJob bool
|
||||
}
|
||||
|
||||
type leaderConfig struct {
|
||||
@@ -141,6 +146,10 @@ func (s *restServer) setupLeaderElection() (*leaderelection.LeaderElectionConfig
|
||||
Callbacks: leaderelection.LeaderCallbacks{
|
||||
OnStartedLeading: func(ctx context.Context) {
|
||||
go velasync.Start(ctx, s.dataStore, restCfg, s.usecases)
|
||||
if !s.cfg.DisableStatisticCronJob {
|
||||
collect.StartCalculatingInfoCronJob(s.dataStore)
|
||||
}
|
||||
// this process would block the whole process, any other handler should start before this func
|
||||
s.runWorkflowRecordSync(ctx, s.cfg.LeaderConfig.Duration)
|
||||
},
|
||||
OnStoppedLeading: func() {
|
||||
|
||||
@@ -313,12 +313,11 @@ func (u *defaultAddonHandler) CreateAddonRegistry(ctx context.Context, req apis.
|
||||
|
||||
func convertAddonRegistry(r pkgaddon.Registry) *apis.AddonRegistry {
|
||||
return &apis.AddonRegistry{
|
||||
Name: r.Name,
|
||||
Git: r.Git,
|
||||
Gitee: r.Gitee,
|
||||
OSS: r.OSS,
|
||||
Helm: r.Helm,
|
||||
Gitlab: r.Gitlab,
|
||||
Name: r.Name,
|
||||
Git: r.Git.SafeCopy(),
|
||||
Gitee: r.Gitee.SafeCopy(),
|
||||
OSS: r.OSS,
|
||||
Helm: r.Helm.SafeCopy(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,8 +343,6 @@ func (u defaultAddonHandler) UpdateAddonRegistry(ctx context.Context, name strin
|
||||
r.OSS = req.Oss
|
||||
case req.Helm != nil:
|
||||
r.Helm = req.Helm
|
||||
case req.Gitlab != nil:
|
||||
r.Gitlab = req.Gitlab
|
||||
}
|
||||
|
||||
err = u.addonRegistryDS.UpdateRegistry(ctx, r)
|
||||
@@ -479,12 +476,11 @@ func (u *defaultAddonHandler) UpdateAddon(ctx context.Context, name string, args
|
||||
|
||||
func addonRegistryModelFromCreateAddonRegistryRequest(req apis.CreateAddonRegistryRequest) pkgaddon.Registry {
|
||||
return pkgaddon.Registry{
|
||||
Name: req.Name,
|
||||
Git: req.Git,
|
||||
OSS: req.Oss,
|
||||
Gitee: req.Gitee,
|
||||
Helm: req.Helm,
|
||||
Gitlab: req.Gitlab,
|
||||
Name: req.Name,
|
||||
Git: req.Git,
|
||||
OSS: req.Oss,
|
||||
Gitee: req.Gitee,
|
||||
Helm: req.Helm,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,8 +20,10 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
set "github.com/deckarep/golang-set"
|
||||
terraformtypes "github.com/oam-dev/terraform-controller/api/types"
|
||||
"github.com/pkg/errors"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
@@ -37,13 +39,13 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/model"
|
||||
apis "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
|
||||
"github.com/oam-dev/kubevela/pkg/definition"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/config"
|
||||
)
|
||||
|
||||
const (
|
||||
definitionAlias = definition.UserPrefix + "alias.config.oam.dev"
|
||||
definitionType = definition.UserPrefix + "type.config.oam.dev"
|
||||
|
||||
velaCoreConfig = "velacore-config"
|
||||
configIsReady = "Ready"
|
||||
configIsNotReady = "Not ready"
|
||||
terraformProviderAlias = "Terraform Cloud Provider"
|
||||
@@ -81,7 +83,7 @@ type configUseCaseImpl struct {
|
||||
func (u *configUseCaseImpl) ListConfigTypes(ctx context.Context, query string) ([]*apis.ConfigType, error) {
|
||||
defs := &v1beta1.ComponentDefinitionList{}
|
||||
if err := u.kubeClient.List(ctx, defs, client.InNamespace(types.DefaultKubeVelaNS),
|
||||
client.MatchingLabels{definition.UserPrefix + "catalog.config.oam.dev": velaCoreConfig}); err != nil {
|
||||
client.MatchingLabels{definition.UserPrefix + "catalog.config.oam.dev": types.VelaCoreConfig}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -134,51 +136,59 @@ func (u *configUseCaseImpl) GetConfigType(ctx context.Context, configType string
|
||||
}
|
||||
|
||||
func (u *configUseCaseImpl) CreateConfig(ctx context.Context, req apis.CreateConfigRequest) error {
|
||||
app := v1beta1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: req.Name,
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
Annotations: map[string]string{
|
||||
types.AnnotationConfigAlias: req.Alias,
|
||||
},
|
||||
Labels: map[string]string{
|
||||
model.LabelSourceOfTruth: model.FromInner,
|
||||
types.LabelConfigCatalog: velaCoreConfig,
|
||||
types.LabelConfigType: req.ComponentType,
|
||||
types.LabelConfigProject: req.Project,
|
||||
},
|
||||
},
|
||||
Spec: v1beta1.ApplicationSpec{
|
||||
Components: []common.ApplicationComponent{
|
||||
{
|
||||
Name: req.Name,
|
||||
Type: req.ComponentType,
|
||||
Properties: &runtime.RawExtension{Raw: []byte(req.Properties)},
|
||||
},
|
||||
},
|
||||
},
|
||||
p := req.Properties
|
||||
// If the component is Terraform type, set the provider name same as the application name and the component name
|
||||
if strings.HasPrefix(req.ComponentType, types.TerraformComponentPrefix) {
|
||||
var properties map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(p), &properties); err != nil {
|
||||
return errors.Wrapf(err, "unable to process the properties of %s", req.ComponentType)
|
||||
}
|
||||
properties["name"] = req.Name
|
||||
tmp, err := json.Marshal(properties)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to process the properties of %s", req.ComponentType)
|
||||
}
|
||||
p = string(tmp)
|
||||
}
|
||||
return u.kubeClient.Create(ctx, &app)
|
||||
ui := config.UIParam{
|
||||
Alias: req.Alias,
|
||||
Description: req.Description,
|
||||
Project: req.Project,
|
||||
}
|
||||
return config.CreateApplication(ctx, u.kubeClient, req.Name, req.ComponentType, p, ui)
|
||||
}
|
||||
|
||||
func (u *configUseCaseImpl) GetConfigs(ctx context.Context, configType string) ([]*apis.Config, error) {
|
||||
switch configType {
|
||||
case types.TerraformProvider:
|
||||
defs := &v1beta1.ComponentDefinitionList{}
|
||||
if err := u.kubeClient.List(ctx, defs, client.InNamespace(types.DefaultKubeVelaNS),
|
||||
client.MatchingLabels{
|
||||
definition.UserPrefix + "catalog.config.oam.dev": velaCoreConfig,
|
||||
definition.UserPrefix + "type.config.oam.dev": types.TerraformProvider,
|
||||
}); err != nil {
|
||||
providers, err := config.ListTerraformProviders(ctx, u.kubeClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var configs []*apis.Config
|
||||
for _, d := range defs.Items {
|
||||
subConfigs, err := u.getConfigsByConfigType(ctx, d.Name)
|
||||
if err != nil {
|
||||
configs := make([]*apis.Config, len(providers))
|
||||
for i, p := range providers {
|
||||
var a v1beta1.Application
|
||||
if err := u.kubeClient.Get(ctx, client.ObjectKey{Namespace: types.DefaultKubeVelaNS, Name: p.Name}, &a); err != nil {
|
||||
if kerrors.IsNotFound(err) {
|
||||
t := p.CreationTimestamp.Time
|
||||
configs[i] = &apis.Config{
|
||||
Name: p.Name,
|
||||
CreatedTime: &t,
|
||||
}
|
||||
if p.Status.State == terraformtypes.ProviderIsReady {
|
||||
configs[i].Status = configIsReady
|
||||
} else {
|
||||
configs[i].Status = configIsNotReady
|
||||
}
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
configs = append(configs, subConfigs...)
|
||||
// If the application doesn't have any components, skip it as something wrong happened.
|
||||
if !strings.HasPrefix(a.Labels[types.LabelConfigType], types.TerraformComponentPrefix) {
|
||||
continue
|
||||
}
|
||||
configs[i] = retrieveConfigFromApplication(a, a.Labels[types.LabelConfigProject])
|
||||
}
|
||||
return configs, nil
|
||||
|
||||
@@ -193,7 +203,7 @@ func (u *configUseCaseImpl) getConfigsByConfigType(ctx context.Context, configTy
|
||||
if err := u.kubeClient.List(ctx, apps, client.InNamespace(types.DefaultKubeVelaNS),
|
||||
client.MatchingLabels{
|
||||
model.LabelSourceOfTruth: model.FromInner,
|
||||
types.LabelConfigCatalog: velaCoreConfig,
|
||||
types.LabelConfigCatalog: types.VelaCoreConfig,
|
||||
types.LabelConfigType: configType,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
@@ -201,18 +211,7 @@ func (u *configUseCaseImpl) getConfigsByConfigType(ctx context.Context, configTy
|
||||
|
||||
configs := make([]*apis.Config, len(apps.Items))
|
||||
for i, a := range apps.Items {
|
||||
configs[i] = &apis.Config{
|
||||
ConfigType: a.Labels[types.LabelConfigType],
|
||||
Name: a.Name,
|
||||
Project: a.Labels[types.LabelConfigProject],
|
||||
CreatedTime: &(a.CreationTimestamp.Time),
|
||||
}
|
||||
switch a.Status.Phase {
|
||||
case common.ApplicationRunning:
|
||||
configs[i].Status = configIsReady
|
||||
default:
|
||||
configs[i].Status = configIsNotReady
|
||||
}
|
||||
configs[i] = retrieveConfigFromApplication(a, a.Labels[types.LabelConfigProject])
|
||||
}
|
||||
return configs, nil
|
||||
}
|
||||
@@ -234,11 +233,11 @@ func (u *configUseCaseImpl) GetConfig(ctx context.Context, configType, name stri
|
||||
}
|
||||
|
||||
func (u *configUseCaseImpl) DeleteConfig(ctx context.Context, configType, name string) error {
|
||||
var a = &v1beta1.Application{}
|
||||
if err := u.kubeClient.Get(ctx, client.ObjectKey{Namespace: types.DefaultKubeVelaNS, Name: name}, a); err != nil {
|
||||
return err
|
||||
var isTerraformProvider bool
|
||||
if strings.HasPrefix(configType, types.TerraformComponentPrefix) {
|
||||
isTerraformProvider = true
|
||||
}
|
||||
return u.kubeClient.Delete(ctx, a)
|
||||
return config.DeleteApplication(ctx, u.kubeClient, name, isTerraformProvider)
|
||||
}
|
||||
|
||||
// ApplicationDeployTarget is the struct of application deploy target
|
||||
@@ -254,7 +253,7 @@ func SyncConfigs(ctx context.Context, k8sClient client.Client, project string, t
|
||||
var secrets v1.SecretList
|
||||
if err := k8sClient.List(ctx, &secrets, client.InNamespace(types.DefaultKubeVelaNS),
|
||||
client.MatchingLabels{
|
||||
types.LabelConfigCatalog: velaCoreConfig,
|
||||
types.LabelConfigCatalog: types.VelaCoreConfig,
|
||||
types.LabelConfigSyncToMultiCluster: "true",
|
||||
}); err != nil {
|
||||
return err
|
||||
@@ -313,7 +312,7 @@ func SyncConfigs(ctx context.Context, k8sClient client.Client, project string, t
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
Labels: map[string]string{
|
||||
model.LabelSourceOfTruth: model.FromInner,
|
||||
types.LabelConfigCatalog: velaCoreConfig,
|
||||
types.LabelConfigCatalog: types.VelaCoreConfig,
|
||||
types.LabelConfigProject: project,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -22,8 +22,11 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/agiledragon/gomonkey/v2"
|
||||
terraformtypes "github.com/oam-dev/terraform-controller/api/types"
|
||||
terraformapi "github.com/oam-dev/terraform-controller/api/v1beta1"
|
||||
"gotest.tools/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -32,6 +35,7 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
"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/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/model"
|
||||
@@ -53,7 +57,7 @@ func TestListConfigTypes(t *testing.T) {
|
||||
Name: "def1",
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
Labels: map[string]string{
|
||||
definition.UserPrefix + "catalog.config.oam.dev": velaCoreConfig,
|
||||
definition.UserPrefix + "catalog.config.oam.dev": types.VelaCoreConfig,
|
||||
definitionType: types.TerraformProvider,
|
||||
},
|
||||
},
|
||||
@@ -70,7 +74,7 @@ func TestListConfigTypes(t *testing.T) {
|
||||
definitionAlias: "Def2",
|
||||
},
|
||||
Labels: map[string]string{
|
||||
definition.UserPrefix + "catalog.config.oam.dev": velaCoreConfig,
|
||||
definition.UserPrefix + "catalog.config.oam.dev": types.VelaCoreConfig,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -150,7 +154,7 @@ func TestGetConfigType(t *testing.T) {
|
||||
definitionAlias: "Def2",
|
||||
},
|
||||
Labels: map[string]string{
|
||||
definition.UserPrefix + "catalog.config.oam.dev": velaCoreConfig,
|
||||
definition.UserPrefix + "catalog.config.oam.dev": types.VelaCoreConfig,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -236,6 +240,11 @@ func TestCreateConfig(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
properties, err := json.Marshal(map[string]interface{}{
|
||||
"name": "default",
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
testcases := []struct {
|
||||
name string
|
||||
args args
|
||||
@@ -252,6 +261,18 @@ func TestCreateConfig(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "create terraform-alibaba config",
|
||||
args: args{
|
||||
h: h,
|
||||
req: apis.CreateConfigRequest{
|
||||
Name: "n1",
|
||||
ComponentType: "terraform-alibaba",
|
||||
Project: "p1",
|
||||
Properties: string(properties),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
@@ -268,37 +289,53 @@ func TestGetConfigs(t *testing.T) {
|
||||
s := runtime.NewScheme()
|
||||
v1beta1.AddToScheme(s)
|
||||
corev1.AddToScheme(s)
|
||||
def1 := &v1beta1.ComponentDefinition{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ComponentDefinition",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
terraformapi.AddToScheme(s)
|
||||
createdTime, _ := time.Parse(time.UnixDate, "Wed Apr 7 11:06:39 PST 2022")
|
||||
|
||||
provider1 := &terraformapi.Provider{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "def1",
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
Labels: map[string]string{
|
||||
definition.UserPrefix + "catalog.config.oam.dev": velaCoreConfig,
|
||||
definitionType: types.TerraformProvider,
|
||||
},
|
||||
Name: "provider1",
|
||||
Namespace: "default",
|
||||
CreationTimestamp: metav1.NewTime(createdTime),
|
||||
},
|
||||
Status: terraformapi.ProviderStatus{
|
||||
State: terraformtypes.ProviderIsReady,
|
||||
},
|
||||
}
|
||||
def2 := &v1beta1.ComponentDefinition{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ComponentDefinition",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
|
||||
provider2 := &terraformapi.Provider{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "def2",
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
Annotations: map[string]string{
|
||||
definitionAlias: "Def2",
|
||||
},
|
||||
Labels: map[string]string{
|
||||
definition.UserPrefix + "catalog.config.oam.dev": velaCoreConfig,
|
||||
},
|
||||
Name: "provider2",
|
||||
Namespace: "default",
|
||||
CreationTimestamp: metav1.NewTime(createdTime),
|
||||
},
|
||||
Status: terraformapi.ProviderStatus{
|
||||
State: terraformtypes.ProviderIsNotReady,
|
||||
},
|
||||
}
|
||||
k8sClient := fake.NewClientBuilder().WithScheme(s).WithObjects(def1, def2).Build()
|
||||
|
||||
provider3 := &terraformapi.Provider{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "provider3",
|
||||
Namespace: "default",
|
||||
},
|
||||
}
|
||||
|
||||
app1 := &v1beta1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "provider3",
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
Labels: map[string]string{
|
||||
types.LabelConfigType: "terraform-alibaba",
|
||||
},
|
||||
CreationTimestamp: metav1.NewTime(createdTime),
|
||||
},
|
||||
Status: common.AppStatus{
|
||||
Phase: common.ApplicationRendering,
|
||||
},
|
||||
}
|
||||
|
||||
k8sClient := fake.NewClientBuilder().WithScheme(s).WithObjects(provider1, provider2, provider3, app1).Build()
|
||||
|
||||
h := &configUseCaseImpl{kubeClient: k8sClient}
|
||||
|
||||
@@ -326,7 +363,25 @@ func TestGetConfigs(t *testing.T) {
|
||||
h: h,
|
||||
},
|
||||
want: want{
|
||||
configs: nil,
|
||||
configs: []*apis.Config{
|
||||
{
|
||||
Name: "provider1",
|
||||
CreatedTime: &createdTime,
|
||||
Status: "Ready",
|
||||
},
|
||||
{
|
||||
Name: "provider2",
|
||||
CreatedTime: &createdTime,
|
||||
Status: "Not ready",
|
||||
},
|
||||
{
|
||||
Name: "provider3",
|
||||
CreatedTime: &createdTime,
|
||||
Status: "Not ready",
|
||||
ConfigType: "terraform-alibaba",
|
||||
ApplicationStatus: common.ApplicationRendering,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -502,7 +557,7 @@ func TestSyncConfigs(t *testing.T) {
|
||||
Name: "s1",
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
Labels: map[string]string{
|
||||
types.LabelConfigCatalog: velaCoreConfig,
|
||||
types.LabelConfigCatalog: types.VelaCoreConfig,
|
||||
types.LabelConfigProject: "p1",
|
||||
types.LabelConfigSyncToMultiCluster: "true",
|
||||
},
|
||||
@@ -587,3 +642,129 @@ func TestSyncConfigs(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteConfig(t *testing.T) {
|
||||
s := runtime.NewScheme()
|
||||
v1beta1.AddToScheme(s)
|
||||
corev1.AddToScheme(s)
|
||||
terraformapi.AddToScheme(s)
|
||||
provider1 := &terraformapi.Provider{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "p1",
|
||||
Namespace: "default",
|
||||
},
|
||||
}
|
||||
|
||||
provider2 := &terraformapi.Provider{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "p2",
|
||||
Namespace: "default",
|
||||
},
|
||||
}
|
||||
|
||||
provider3 := &terraformapi.Provider{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "p3",
|
||||
Namespace: "default",
|
||||
},
|
||||
}
|
||||
|
||||
app1 := &v1beta1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "config-terraform-provider-p1",
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
Labels: map[string]string{
|
||||
types.LabelConfigType: "terraform-alibaba",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app2 := &v1beta1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "p2",
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
Labels: map[string]string{
|
||||
types.LabelConfigType: "terraform-alibaba",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
normalApp := &v1beta1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "a9",
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
},
|
||||
}
|
||||
|
||||
k8sClient := fake.NewClientBuilder().WithScheme(s).WithObjects(provider1, provider2, provider3, app1, app2, normalApp).Build()
|
||||
|
||||
h := &configUseCaseImpl{kubeClient: k8sClient}
|
||||
|
||||
type args struct {
|
||||
configType string
|
||||
name string
|
||||
h ConfigHandler
|
||||
}
|
||||
|
||||
type want struct {
|
||||
errMsg string
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
testcases := []struct {
|
||||
name string
|
||||
args args
|
||||
want want
|
||||
}{
|
||||
{
|
||||
name: "delete a legacy terraform provider",
|
||||
args: args{
|
||||
configType: "terraform-alibaba",
|
||||
name: "p1",
|
||||
h: h,
|
||||
},
|
||||
want: want{},
|
||||
},
|
||||
{
|
||||
name: "delete a terraform provider",
|
||||
args: args{
|
||||
configType: "terraform-alibaba",
|
||||
name: "p2",
|
||||
h: h,
|
||||
},
|
||||
want: want{},
|
||||
},
|
||||
{
|
||||
name: "delete a terraform provider, but its application not found",
|
||||
args: args{
|
||||
configType: "terraform-alibaba",
|
||||
name: "p3",
|
||||
h: h,
|
||||
},
|
||||
want: want{
|
||||
errMsg: "could not be disabled because it was created by enabling a Terraform provider or was manually created",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "delete a normal config, but failed",
|
||||
args: args{
|
||||
configType: "config-image-registry",
|
||||
name: "a10",
|
||||
h: h,
|
||||
},
|
||||
want: want{
|
||||
errMsg: "not found",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := tc.args.h.DeleteConfig(ctx, tc.args.configType, tc.args.name)
|
||||
if tc.want.errMsg != "" || err != nil {
|
||||
assert.ErrorContains(t, err, tc.want.errMsg)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils/config"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/clients"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/log"
|
||||
@@ -31,7 +33,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/utils/helm"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types2 "k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
@@ -133,41 +134,20 @@ func (d defaultHelmHandler) ListChartRepo(ctx context.Context, projectName strin
|
||||
var res []*v1.ChartRepoResponse
|
||||
var err error
|
||||
|
||||
if len(projectName) != 0 {
|
||||
projectSecrets := corev1.SecretList{}
|
||||
opts := []client.ListOption{
|
||||
client.MatchingLabels{oam.LabelConfigType: "config-helm-repository", types.LabelConfigProject: projectName},
|
||||
client.InNamespace(types.DefaultKubeVelaNS),
|
||||
}
|
||||
err = d.k8sClient.List(ctx, &projectSecrets, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, item := range projectSecrets.Items {
|
||||
res = append(res, &v1.ChartRepoResponse{URL: string(item.Data["url"]), SecretName: item.Name})
|
||||
}
|
||||
projectSecrets := corev1.SecretList{}
|
||||
opts := []client.ListOption{
|
||||
client.MatchingLabels{oam.LabelConfigType: "config-helm-repository"},
|
||||
client.InNamespace(types.DefaultKubeVelaNS),
|
||||
}
|
||||
|
||||
globalSecrets := corev1.SecretList{}
|
||||
selector := metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{oam.LabelConfigType: "config-helm-repository"},
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{Key: types.LabelConfigProject, Operator: metav1.LabelSelectorOpDoesNotExist},
|
||||
},
|
||||
}
|
||||
|
||||
ls, _ := metav1.LabelSelectorAsSelector(&selector)
|
||||
err = d.k8sClient.List(ctx, &globalSecrets, &client.ListOptions{
|
||||
LabelSelector: ls,
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
})
|
||||
err = d.k8sClient.List(ctx, &projectSecrets, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, item := range globalSecrets.Items {
|
||||
res = append(res, &v1.ChartRepoResponse{URL: string(item.Data["url"]), SecretName: item.Name})
|
||||
for _, item := range projectSecrets.Items {
|
||||
if config.ProjectMatched(item.DeepCopy(), projectName) {
|
||||
res = append(res, &v1.ChartRepoResponse{URL: string(item.Data["url"]), SecretName: item.Name})
|
||||
}
|
||||
}
|
||||
|
||||
return &v1.ChartRepoResponseList{ChartRepoResponse: res}, nil
|
||||
|
||||
@@ -338,6 +338,7 @@ kind: Secret
|
||||
metadata:
|
||||
labels:
|
||||
config.oam.dev/type: config-helm-repository
|
||||
config.oam.dev/project: ""
|
||||
name: global-helm-repo
|
||||
namespace: vela-system
|
||||
type: Opaque
|
||||
|
||||
@@ -487,7 +487,7 @@ func (p *projectUsecaseImpl) GetConfigs(ctx context.Context, projectName, config
|
||||
if err := p.k8sClient.List(ctx, apps, client.InNamespace(types.DefaultKubeVelaNS),
|
||||
client.MatchingLabels{
|
||||
model.LabelSourceOfTruth: model.FromInner,
|
||||
types.LabelConfigCatalog: velaCoreConfig,
|
||||
types.LabelConfigCatalog: types.VelaCoreConfig,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -499,7 +499,7 @@ func (p *projectUsecaseImpl) GetConfigs(ctx context.Context, projectName, config
|
||||
return nil, err
|
||||
}
|
||||
for _, p := range providers.Items {
|
||||
if p.Labels[types.LabelConfigCatalog] == velaCoreConfig {
|
||||
if p.Labels[types.LabelConfigCatalog] == types.VelaCoreConfig {
|
||||
continue
|
||||
}
|
||||
t := p.CreationTimestamp.Time
|
||||
@@ -520,16 +520,10 @@ func (p *projectUsecaseImpl) GetConfigs(ctx context.Context, projectName, config
|
||||
for _, a := range apps.Items {
|
||||
appProject := a.Labels[types.LabelConfigProject]
|
||||
if a.Status.Phase != common.ApplicationRunning || (appProject != "" && appProject != projectName) ||
|
||||
!strings.Contains(a.Labels[types.LabelConfigType], "terraform-") {
|
||||
!strings.Contains(a.Labels[types.LabelConfigType], types.TerraformComponentPrefix) {
|
||||
continue
|
||||
}
|
||||
configs = append(configs, &apisv1.Config{
|
||||
ConfigType: a.Labels[types.LabelConfigType],
|
||||
Name: a.Name,
|
||||
Project: appProject,
|
||||
CreatedTime: &(a.CreationTimestamp.Time),
|
||||
ApplicationStatus: a.Status.Phase,
|
||||
})
|
||||
configs = append(configs, retrieveConfigFromApplication(a, appProject))
|
||||
}
|
||||
|
||||
configs = append(configs, legacyTerraformProviders...)
|
||||
@@ -539,13 +533,7 @@ func (p *projectUsecaseImpl) GetConfigs(ctx context.Context, projectName, config
|
||||
if appProject != "" && appProject != projectName {
|
||||
continue
|
||||
}
|
||||
configs = append(configs, &apisv1.Config{
|
||||
ConfigType: a.Labels[types.LabelConfigType],
|
||||
Name: a.Name,
|
||||
Project: appProject,
|
||||
CreatedTime: &(a.CreationTimestamp.Time),
|
||||
ApplicationStatus: a.Status.Phase,
|
||||
})
|
||||
configs = append(configs, retrieveConfigFromApplication(a, appProject))
|
||||
}
|
||||
configs = append(configs, legacyTerraformProviders...)
|
||||
case types.DexConnector, types.HelmRepository, types.ImageRegistry:
|
||||
@@ -556,13 +544,7 @@ func (p *projectUsecaseImpl) GetConfigs(ctx context.Context, projectName, config
|
||||
continue
|
||||
}
|
||||
if a.Labels[types.LabelConfigType] == t {
|
||||
configs = append(configs, &apisv1.Config{
|
||||
ConfigType: a.Labels[types.LabelConfigType],
|
||||
Name: a.Name,
|
||||
Project: appProject,
|
||||
CreatedTime: &(a.CreationTimestamp.Time),
|
||||
ApplicationStatus: a.Status.Phase,
|
||||
})
|
||||
configs = append(configs, retrieveConfigFromApplication(a, appProject))
|
||||
}
|
||||
}
|
||||
default:
|
||||
@@ -579,13 +561,6 @@ func (p *projectUsecaseImpl) GetConfigs(ctx context.Context, projectName, config
|
||||
configs[i].ConfigTypeAlias = d.Annotations[definitionAlias]
|
||||
}
|
||||
}
|
||||
if c.ApplicationStatus != "" {
|
||||
if c.ApplicationStatus == common.ApplicationRunning {
|
||||
configs[i].Status = configIsReady
|
||||
} else {
|
||||
configs[i].Status = configIsNotReady
|
||||
}
|
||||
}
|
||||
}
|
||||
return configs, nil
|
||||
}
|
||||
@@ -616,3 +591,25 @@ func ConvertProjectUserModel2Base(user *model.ProjectUser) *apisv1.ProjectUserBa
|
||||
}
|
||||
return base
|
||||
}
|
||||
|
||||
func retrieveConfigFromApplication(a v1beta1.Application, project string) *apisv1.Config {
|
||||
var (
|
||||
applicationStatus = a.Status.Phase
|
||||
status string
|
||||
)
|
||||
if applicationStatus == common.ApplicationRunning {
|
||||
status = configIsReady
|
||||
} else {
|
||||
status = configIsNotReady
|
||||
}
|
||||
return &apisv1.Config{
|
||||
ConfigType: a.Labels[types.LabelConfigType],
|
||||
Name: a.Name,
|
||||
Project: project,
|
||||
CreatedTime: &(a.CreationTimestamp.Time),
|
||||
ApplicationStatus: applicationStatus,
|
||||
Status: status,
|
||||
Alias: a.Annotations[types.AnnotationConfigAlias],
|
||||
Description: a.Annotations[types.AnnotationConfigDescription],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@ func TestProjectGetConfigs(t *testing.T) {
|
||||
Namespace: velatypes.DefaultKubeVelaNS,
|
||||
Labels: map[string]string{
|
||||
model.LabelSourceOfTruth: model.FromInner,
|
||||
velatypes.LabelConfigCatalog: velaCoreConfig,
|
||||
velatypes.LabelConfigCatalog: velatypes.VelaCoreConfig,
|
||||
velatypes.LabelConfigType: "terraform-provider",
|
||||
"config.oam.dev/project": "p1",
|
||||
},
|
||||
@@ -308,7 +308,7 @@ func TestProjectGetConfigs(t *testing.T) {
|
||||
Namespace: velatypes.DefaultKubeVelaNS,
|
||||
Labels: map[string]string{
|
||||
model.LabelSourceOfTruth: model.FromInner,
|
||||
velatypes.LabelConfigCatalog: velaCoreConfig,
|
||||
velatypes.LabelConfigCatalog: velatypes.VelaCoreConfig,
|
||||
velatypes.LabelConfigType: "terraform-provider",
|
||||
},
|
||||
CreationTimestamp: metav1.NewTime(createdTime),
|
||||
@@ -322,7 +322,7 @@ func TestProjectGetConfigs(t *testing.T) {
|
||||
Namespace: velatypes.DefaultKubeVelaNS,
|
||||
Labels: map[string]string{
|
||||
model.LabelSourceOfTruth: model.FromInner,
|
||||
velatypes.LabelConfigCatalog: velaCoreConfig,
|
||||
velatypes.LabelConfigCatalog: velatypes.VelaCoreConfig,
|
||||
velatypes.LabelConfigType: "dex-connector",
|
||||
"config.oam.dev/project": "p3",
|
||||
},
|
||||
@@ -347,7 +347,7 @@ func TestProjectGetConfigs(t *testing.T) {
|
||||
Name: "provider2",
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{
|
||||
velatypes.LabelConfigCatalog: velaCoreConfig,
|
||||
velatypes.LabelConfigCatalog: velatypes.VelaCoreConfig,
|
||||
},
|
||||
},
|
||||
Status: terraformapi.ProviderStatus{
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
@@ -81,6 +82,7 @@ func (u systemInfoUsecaseImpl) Get(ctx context.Context) (*model.SystemInfo, erro
|
||||
info.InstallID = installID
|
||||
info.EnableCollection = true
|
||||
info.LoginType = model.LoginTypeLocal
|
||||
info.BaseModel = model.BaseModel{CreateTime: time.Now()}
|
||||
err = u.ds.Add(ctx, info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -100,6 +102,16 @@ func (u systemInfoUsecaseImpl) GetSystemInfo(ctx context.Context) (*v1.SystemInf
|
||||
VelaVersion: version.VelaVersion,
|
||||
GitVersion: version.GitRevision,
|
||||
},
|
||||
StatisticInfo: v1.StatisticInfo{
|
||||
AppCount: info.StatisticInfo.AppCount,
|
||||
ClusterCount: info.StatisticInfo.ClusterCount,
|
||||
EnableAddonList: info.StatisticInfo.EnabledAddon,
|
||||
ComponentDefinitionTopList: info.StatisticInfo.TopKCompDef,
|
||||
TraitDefinitionTopList: info.StatisticInfo.TopKTraitDef,
|
||||
WorkflowDefinitionTopList: info.StatisticInfo.TopKWorkflowStepDef,
|
||||
PolicyDefinitionTopList: info.StatisticInfo.TopKPolicyDef,
|
||||
UpdateTime: info.StatisticInfo.UpdateTime,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -114,7 +126,9 @@ func (u systemInfoUsecaseImpl) UpdateSystemInfo(ctx context.Context, sysInfo v1.
|
||||
LoginType: sysInfo.LoginType,
|
||||
BaseModel: model.BaseModel{
|
||||
CreateTime: info.CreateTime,
|
||||
UpdateTime: time.Now(),
|
||||
},
|
||||
StatisticInfo: info.StatisticInfo,
|
||||
}
|
||||
|
||||
if sysInfo.LoginType == model.LoginTypeDex {
|
||||
@@ -135,9 +149,11 @@ func (u systemInfoUsecaseImpl) UpdateSystemInfo(ctx context.Context, sysInfo v1.
|
||||
}
|
||||
return &v1.SystemInfoResponse{
|
||||
SystemInfo: v1.SystemInfo{
|
||||
InstallID: modifiedInfo.InstallID,
|
||||
PlatformID: modifiedInfo.InstallID,
|
||||
EnableCollection: modifiedInfo.EnableCollection,
|
||||
LoginType: modifiedInfo.LoginType,
|
||||
// always use the initial createTime as system's installTime
|
||||
InstallTime: info.CreateTime,
|
||||
},
|
||||
SystemVersion: v1.SystemVersion{VelaVersion: version.VelaVersion, GitVersion: version.GitRevision},
|
||||
}, nil
|
||||
@@ -155,9 +171,10 @@ func (u systemInfoUsecaseImpl) Init(ctx context.Context) error {
|
||||
|
||||
func convertInfoToBase(info *model.SystemInfo) v1.SystemInfo {
|
||||
return v1.SystemInfo{
|
||||
InstallID: info.InstallID,
|
||||
PlatformID: info.InstallID,
|
||||
EnableCollection: info.EnableCollection,
|
||||
LoginType: info.LoginType,
|
||||
InstallTime: info.CreateTime,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ import (
|
||||
"cuelang.org/go/cue/format"
|
||||
json2cue "cuelang.org/go/encoding/json"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
|
||||
terraformapi "github.com/oam-dev/terraform-controller/api/v1beta1"
|
||||
terraformapi "github.com/oam-dev/terraform-controller/api/v1beta2"
|
||||
"github.com/pkg/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
@@ -63,7 +63,9 @@ const (
|
||||
// WriteConnectionSecretToRefKey is used to create a secret for cloud resource connection
|
||||
WriteConnectionSecretToRefKey = "writeConnectionSecretToRef"
|
||||
// RegionKey is the region of a Cloud Provider
|
||||
RegionKey = "region"
|
||||
// It's used to override the region of a Cloud Provider
|
||||
// Refer to https://github.com/oam-dev/terraform-controller/blob/master/api/v1beta2/configuration_types.go#L66 for details
|
||||
RegionKey = "customRegion"
|
||||
// ProviderRefKey is the reference of a Provider
|
||||
ProviderRefKey = "providerRef"
|
||||
)
|
||||
@@ -666,7 +668,7 @@ func generateTerraformConfigurationWorkload(wl *Workload, ns string) (*unstructu
|
||||
}
|
||||
|
||||
configuration := terraformapi.Configuration{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: "terraform.core.oam.dev/v1beta1", Kind: "Configuration"},
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: "terraform.core.oam.dev/v1beta2", Kind: "Configuration"},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: wl.Name,
|
||||
Namespace: ns,
|
||||
@@ -679,8 +681,6 @@ func generateTerraformConfigurationWorkload(wl *Workload, ns string) (*unstructu
|
||||
switch wl.FullTemplate.Terraform.Type {
|
||||
case "hcl":
|
||||
configuration.Spec.HCL = wl.FullTemplate.Terraform.Configuration
|
||||
case "json":
|
||||
configuration.Spec.JSON = wl.FullTemplate.Terraform.Configuration
|
||||
case "remote":
|
||||
configuration.Spec.Remote = wl.FullTemplate.Terraform.Configuration
|
||||
configuration.Spec.Path = wl.FullTemplate.Terraform.Path
|
||||
|
||||
@@ -30,7 +30,7 @@ import (
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
terraformtypes "github.com/oam-dev/terraform-controller/api/types/crossplane-runtime"
|
||||
terraformapi "github.com/oam-dev/terraform-controller/api/v1beta1"
|
||||
terraformapi "github.com/oam-dev/terraform-controller/api/v1beta2"
|
||||
"github.com/pkg/errors"
|
||||
"gotest.tools/assert"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -584,10 +584,6 @@ variable "password" {
|
||||
raw.Raw = data
|
||||
|
||||
workload := terraformapi.Configuration{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "terraform.core.oam.dev/v1beta1",
|
||||
Kind: "Configuration",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{
|
||||
"app.oam.dev/appRevision": "v1",
|
||||
@@ -902,7 +898,6 @@ func TestGenerateTerraformConfigurationWorkload(t *testing.T) {
|
||||
|
||||
type args struct {
|
||||
writeConnectionSecretToRef *terraformtypes.SecretReference
|
||||
json string
|
||||
hcl string
|
||||
remote string
|
||||
params map[string]interface{}
|
||||
@@ -917,16 +912,6 @@ func TestGenerateTerraformConfigurationWorkload(t *testing.T) {
|
||||
args args
|
||||
want want
|
||||
}{
|
||||
"json workload with secret": {
|
||||
args: args{
|
||||
|
||||
json: "abc",
|
||||
params: map[string]interface{}{"acl": "private",
|
||||
"writeConnectionSecretToRef": map[string]interface{}{"name": "oss", "namespace": ""}},
|
||||
writeConnectionSecretToRef: &terraformtypes.SecretReference{Name: "oss", Namespace: "default"},
|
||||
},
|
||||
want: want{err: nil}},
|
||||
|
||||
"valid hcl workload": {
|
||||
args: args{
|
||||
hcl: "abc",
|
||||
@@ -999,19 +984,6 @@ func TestGenerateTerraformConfigurationWorkload(t *testing.T) {
|
||||
}
|
||||
configSpec.WriteConnectionSecretToReference = tc.args.writeConnectionSecretToRef
|
||||
}
|
||||
if tc.args.json != "" {
|
||||
template = &Template{
|
||||
Terraform: &common.Terraform{
|
||||
Configuration: tc.args.json,
|
||||
Type: "json",
|
||||
},
|
||||
}
|
||||
configSpec = terraformapi.ConfigurationSpec{
|
||||
JSON: tc.args.json,
|
||||
Variable: raw,
|
||||
}
|
||||
configSpec.WriteConnectionSecretToReference = tc.args.writeConnectionSecretToRef
|
||||
}
|
||||
if tc.args.remote != "" {
|
||||
template = &Template{
|
||||
Terraform: &common.Terraform{
|
||||
@@ -1025,7 +997,7 @@ func TestGenerateTerraformConfigurationWorkload(t *testing.T) {
|
||||
}
|
||||
configSpec.WriteConnectionSecretToReference = tc.args.writeConnectionSecretToRef
|
||||
}
|
||||
if tc.args.hcl == "" && tc.args.json == "" && tc.args.remote == "" {
|
||||
if tc.args.hcl == "" && tc.args.remote == "" {
|
||||
template = &Template{
|
||||
Terraform: &common.Terraform{},
|
||||
}
|
||||
@@ -1061,7 +1033,7 @@ func TestGenerateTerraformConfigurationWorkload(t *testing.T) {
|
||||
|
||||
if err == nil {
|
||||
tfConfiguration := terraformapi.Configuration{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: "terraform.core.oam.dev/v1beta1", Kind: "Configuration"},
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: "terraform.core.oam.dev/v1beta2", Kind: "Configuration"},
|
||||
ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: ns},
|
||||
Spec: configSpec,
|
||||
}
|
||||
|
||||
@@ -288,6 +288,30 @@ func (p *Parser) GenerateAppFileFromRevision(appRev *v1beta1.ApplicationRevision
|
||||
for k, v := range appRev.Spec.WorkflowStepDefinitions {
|
||||
appfile.RelatedWorkflowStepDefinitions[k] = v.DeepCopy()
|
||||
}
|
||||
|
||||
// add compatible code for upgrading to v1.3 as the workflow steps were not recorded before v1.2
|
||||
if len(appfile.RelatedWorkflowStepDefinitions) == 0 && len(appfile.WorkflowSteps) > 0 {
|
||||
ctx := context.Background()
|
||||
for _, workflowStep := range appfile.WorkflowSteps {
|
||||
if wftypes.IsBuiltinWorkflowStepType(workflowStep.Type) {
|
||||
continue
|
||||
}
|
||||
if _, found := appfile.RelatedWorkflowStepDefinitions[workflowStep.Type]; found {
|
||||
continue
|
||||
}
|
||||
def := &v1beta1.WorkflowStepDefinition{}
|
||||
if err := util.GetCapabilityDefinition(ctx, p.client, def, workflowStep.Type); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get workflow step definition %s", workflowStep.Type)
|
||||
}
|
||||
appfile.RelatedWorkflowStepDefinitions[workflowStep.Type] = def
|
||||
}
|
||||
|
||||
appRev.Spec.WorkflowStepDefinitions = make(map[string]v1beta1.WorkflowStepDefinition)
|
||||
for name, def := range appfile.RelatedWorkflowStepDefinitions {
|
||||
appRev.Spec.WorkflowStepDefinitions[name] = *def
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range appRev.Spec.ScopeDefinitions {
|
||||
appfile.RelatedScopeDefinitions[k] = v.DeepCopy()
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
common2 "github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
@@ -506,3 +508,202 @@ var _ = Describe("Test appFile parser", func() {
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
var _ = Describe("Test application parser", func() {
|
||||
var app v1beta1.Application
|
||||
var apprev v1beta1.ApplicationRevision
|
||||
var wsd v1beta1.WorkflowStepDefinition
|
||||
var expectedExceptAppfile *Appfile
|
||||
var mockClient test.MockClient
|
||||
|
||||
BeforeEach(func() {
|
||||
// prepare WorkflowStepDefinition
|
||||
Expect(common2.ReadYamlToObject("testdata/backport-1-2/wsd.yaml", &wsd)).Should(BeNil())
|
||||
|
||||
// prepare verify data
|
||||
expectedExceptAppfile = &Appfile{
|
||||
Name: "backport-1-2-test-demo",
|
||||
Workloads: []*Workload{
|
||||
{
|
||||
Name: "backport-1-2-test-demo",
|
||||
Type: "webservice",
|
||||
Params: map[string]interface{}{
|
||||
"image": "nginx",
|
||||
},
|
||||
FullTemplate: &Template{
|
||||
TemplateStr: `
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
spec: {
|
||||
selector: matchLabels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
|
||||
template: {
|
||||
metadata: labels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
|
||||
if parameter["cmd"] != _|_ {
|
||||
command: parameter.cmd
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
selector:
|
||||
matchLabels:
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
}
|
||||
|
||||
parameter: {
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
|
||||
cmd?: [...string]
|
||||
}`,
|
||||
},
|
||||
Traits: []*Trait{
|
||||
{
|
||||
Name: "scaler",
|
||||
Params: map[string]interface{}{
|
||||
"replicas": float64(1),
|
||||
},
|
||||
Template: `
|
||||
parameter: {
|
||||
// +usage=Specify the number of workload
|
||||
replicas: *1 | int
|
||||
}
|
||||
// +patchStrategy=retainKeys
|
||||
patch: spec: replicas: parameter.replicas
|
||||
|
||||
`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
WorkflowSteps: []v1beta1.WorkflowStep{
|
||||
{
|
||||
Name: "apply",
|
||||
Type: "apply-application",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Create mock client
|
||||
mockClient = test.MockClient{
|
||||
MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
if strings.Contains(key.Name, "unknown") {
|
||||
return &errors2.StatusError{ErrStatus: metav1.Status{Reason: "NotFound", Message: "not found"}}
|
||||
}
|
||||
switch o := obj.(type) {
|
||||
case *v1beta1.ComponentDefinition:
|
||||
wd, err := util.UnMarshalStringToComponentDefinition(componenetDefinition)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*o = *wd
|
||||
case *v1beta1.TraitDefinition:
|
||||
td, err := util.UnMarshalStringToTraitDefinition(traitDefinition)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*o = *td
|
||||
case *v1beta1.WorkflowStepDefinition:
|
||||
*o = wsd
|
||||
case *v1beta1.ApplicationRevision:
|
||||
*o = apprev
|
||||
default:
|
||||
// skip
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
When("with apply-application workflowStep", func() {
|
||||
BeforeEach(func() {
|
||||
// prepare application
|
||||
Expect(common2.ReadYamlToObject("testdata/backport-1-2/app.yaml", &app)).Should(BeNil())
|
||||
// prepare application revision
|
||||
Expect(common2.ReadYamlToObject("testdata/backport-1-2/apprev1.yaml", &apprev)).Should(BeNil())
|
||||
})
|
||||
|
||||
It("Test we can parse an application revision to an appFile 1", func() {
|
||||
|
||||
appfile, err := NewApplicationParser(&mockClient, dm, pd).GenerateAppFile(context.TODO(), &app)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(equal(expectedExceptAppfile, appfile)).Should(BeTrue())
|
||||
Expect(len(appfile.WorkflowSteps) > 0 &&
|
||||
len(appfile.RelatedWorkflowStepDefinitions) == len(appfile.AppRevision.Spec.WorkflowStepDefinitions)).Should(BeTrue())
|
||||
|
||||
Expect(len(appfile.WorkflowSteps) > 0 && func() bool {
|
||||
this := appfile.RelatedWorkflowStepDefinitions
|
||||
that := appfile.AppRevision.Spec.WorkflowStepDefinitions
|
||||
for i, w := range this {
|
||||
thatW := that[i]
|
||||
if !reflect.DeepEqual(*w, thatW) {
|
||||
fmt.Printf("appfile wsd:%s apprev wsd%s", (*w).Name, thatW.Name)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}()).Should(BeTrue())
|
||||
})
|
||||
})
|
||||
|
||||
When("with apply-application and apply-component build-in workflowStep", func() {
|
||||
BeforeEach(func() {
|
||||
// prepare application
|
||||
Expect(common2.ReadYamlToObject("testdata/backport-1-2/app.yaml", &app)).Should(BeNil())
|
||||
// prepare application revision
|
||||
Expect(common2.ReadYamlToObject("testdata/backport-1-2/apprev2.yaml", &apprev)).Should(BeNil())
|
||||
})
|
||||
|
||||
It("Test we can parse an application revision to an appFile 2", func() {
|
||||
|
||||
appfile, err := NewApplicationParser(&mockClient, dm, pd).GenerateAppFile(context.TODO(), &app)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(equal(expectedExceptAppfile, appfile)).Should(BeTrue())
|
||||
Expect(len(appfile.WorkflowSteps) > 0 &&
|
||||
len(appfile.RelatedWorkflowStepDefinitions) == len(appfile.AppRevision.Spec.WorkflowStepDefinitions)).Should(BeTrue())
|
||||
|
||||
Expect(len(appfile.WorkflowSteps) > 0 && func() bool {
|
||||
this := appfile.RelatedWorkflowStepDefinitions
|
||||
that := appfile.AppRevision.Spec.WorkflowStepDefinitions
|
||||
for i, w := range this {
|
||||
thatW := that[i]
|
||||
if !reflect.DeepEqual(*w, thatW) {
|
||||
fmt.Printf("appfile wsd:%s apprev wsd%s", (*w).Name, thatW.Name)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}()).Should(BeTrue())
|
||||
})
|
||||
})
|
||||
|
||||
When("with unknown workflowStep", func() {
|
||||
BeforeEach(func() {
|
||||
// prepare application
|
||||
Expect(common2.ReadYamlToObject("testdata/backport-1-2/app.yaml", &app)).Should(BeNil())
|
||||
// prepare application revision
|
||||
Expect(common2.ReadYamlToObject("testdata/backport-1-2/apprev3.yaml", &apprev)).Should(BeNil())
|
||||
})
|
||||
|
||||
It("Test we can parse an application revision to an appFile 3", func() {
|
||||
|
||||
_, err := NewApplicationParser(&mockClient, dm, pd).GenerateAppFile(context.TODO(), &app)
|
||||
Expect(err).Should(HaveOccurred())
|
||||
Expect(err.Error() == "failed to get workflow step definition apply-application-unknown: not found").Should(BeTrue())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
26
pkg/appfile/testdata/backport-1-2/app.yaml
vendored
Normal file
26
pkg/appfile/testdata/backport-1-2/app.yaml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
annotations:
|
||||
app.oam.dev/publishVersion: workflow-default-123456
|
||||
name: backport-1-2-test-demo
|
||||
namespace: default
|
||||
spec:
|
||||
components:
|
||||
- name: backport-1-2-test-demo
|
||||
properties:
|
||||
image: nginx
|
||||
traits:
|
||||
- properties:
|
||||
replicas: 1
|
||||
type: scaler
|
||||
type: webservice
|
||||
workflow:
|
||||
steps:
|
||||
- name: apply
|
||||
type: apply-application
|
||||
status:
|
||||
latestRevision:
|
||||
name: backport-1-2-test-demo-v1
|
||||
revision: 1
|
||||
revisionHash: 38ddf4e721073703
|
||||
271
pkg/appfile/testdata/backport-1-2/apprev1.yaml
vendored
Normal file
271
pkg/appfile/testdata/backport-1-2/apprev1.yaml
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ApplicationRevision
|
||||
metadata:
|
||||
annotations:
|
||||
app.oam.dev/publishVersion: workflow-default-123456
|
||||
name: backport-1-2-test-demo-v1
|
||||
namespace: default
|
||||
spec:
|
||||
application:
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
annotations:
|
||||
app.oam.dev/publishVersion: workflow-default-123456
|
||||
name: backport-1-2-test-demo
|
||||
namespace: default
|
||||
spec:
|
||||
components:
|
||||
- name: backport-1-2-test-demo
|
||||
properties:
|
||||
image: nginx
|
||||
traits:
|
||||
- properties:
|
||||
replicas: 1
|
||||
type: scaler
|
||||
type: webservice
|
||||
workflow:
|
||||
steps:
|
||||
- name: apply
|
||||
type: apply-application
|
||||
status: {}
|
||||
componentDefinitions:
|
||||
webservice:
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Describes long-running, scalable, containerized
|
||||
services that have a stable network endpoint to receive external network
|
||||
traffic from customers.
|
||||
meta.helm.sh/release-name: kubevela
|
||||
meta.helm.sh/release-namespace: vela-system
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
name: webservice
|
||||
namespace: vela-system
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: "import (\n\t\"strconv\"\n)\n\nmountsArray: {\n\tpvc: *[\n\t\tfor
|
||||
v in parameter.volumeMounts.pvc {\n\t\t\t{\n\t\t\t\tmountPath: v.mountPath\n\t\t\t\tname:
|
||||
\ v.name\n\t\t\t}\n\t\t},\n\t] | []\n\n\tconfigMap: *[\n\t\t\tfor
|
||||
v in parameter.volumeMounts.configMap {\n\t\t\t{\n\t\t\t\tmountPath:
|
||||
v.mountPath\n\t\t\t\tname: v.name\n\t\t\t}\n\t\t},\n\t] | []\n\n\tsecret:
|
||||
*[\n\t\tfor v in parameter.volumeMounts.secret {\n\t\t\t{\n\t\t\t\tmountPath:
|
||||
v.mountPath\n\t\t\t\tname: v.name\n\t\t\t}\n\t\t},\n\t] | []\n\n\temptyDir:
|
||||
*[\n\t\t\tfor v in parameter.volumeMounts.emptyDir {\n\t\t\t{\n\t\t\t\tmountPath:
|
||||
v.mountPath\n\t\t\t\tname: v.name\n\t\t\t}\n\t\t},\n\t] | []\n\n\thostPath:
|
||||
*[\n\t\t\tfor v in parameter.volumeMounts.hostPath {\n\t\t\t{\n\t\t\t\tmountPath:
|
||||
v.mountPath\n\t\t\t\tname: v.name\n\t\t\t}\n\t\t},\n\t] | []\n}\nvolumesArray:
|
||||
{\n\tpvc: *[\n\t\tfor v in parameter.volumeMounts.pvc {\n\t\t\t{\n\t\t\t\tname:
|
||||
v.name\n\t\t\t\tpersistentVolumeClaim: claimName: v.claimName\n\t\t\t}\n\t\t},\n\t]
|
||||
| []\n\n\tconfigMap: *[\n\t\t\tfor v in parameter.volumeMounts.configMap
|
||||
{\n\t\t\t{\n\t\t\t\tname: v.name\n\t\t\t\tconfigMap: {\n\t\t\t\t\tdefaultMode:
|
||||
v.defaultMode\n\t\t\t\t\tname: v.cmName\n\t\t\t\t\tif v.items
|
||||
!= _|_ {\n\t\t\t\t\t\titems: v.items\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t]
|
||||
| []\n\n\tsecret: *[\n\t\tfor v in parameter.volumeMounts.secret {\n\t\t\t{\n\t\t\t\tname:
|
||||
v.name\n\t\t\t\tsecret: {\n\t\t\t\t\tdefaultMode: v.defaultMode\n\t\t\t\t\tsecretName:
|
||||
\ v.secretName\n\t\t\t\t\tif v.items != _|_ {\n\t\t\t\t\t\titems: v.items\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t]
|
||||
| []\n\n\temptyDir: *[\n\t\t\tfor v in parameter.volumeMounts.emptyDir
|
||||
{\n\t\t\t{\n\t\t\t\tname: v.name\n\t\t\t\temptyDir: medium: v.medium\n\t\t\t}\n\t\t},\n\t]
|
||||
| []\n\n\thostPath: *[\n\t\t\tfor v in parameter.volumeMounts.hostPath
|
||||
{\n\t\t\t{\n\t\t\t\tname: v.name\n\t\t\t\thostPath: path: v.path\n\t\t\t}\n\t\t},\n\t]
|
||||
| []\n}\noutput: {\n\tapiVersion: \"apps/v1\"\n\tkind: \"Deployment\"\n\tspec:
|
||||
{\n\t\tselector: matchLabels: \"app.oam.dev/component\": context.name\n\n\t\ttemplate:
|
||||
{\n\t\t\tmetadata: {\n\t\t\t\tlabels: {\n\t\t\t\t\tif parameter.labels
|
||||
!= _|_ {\n\t\t\t\t\t\tparameter.labels\n\t\t\t\t\t}\n\t\t\t\t\tif parameter.addRevisionLabel
|
||||
{\n\t\t\t\t\t\t\"app.oam.dev/revision\": context.revision\n\t\t\t\t\t}\n\t\t\t\t\t\"app.oam.dev/component\":
|
||||
context.name\n\t\t\t\t}\n\t\t\t\tif parameter.annotations != _|_ {\n\t\t\t\t\tannotations:
|
||||
parameter.annotations\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tspec: {\n\t\t\t\tcontainers:
|
||||
[{\n\t\t\t\t\tname: context.name\n\t\t\t\t\timage: parameter.image\n\t\t\t\t\tif
|
||||
parameter[\"port\"] != _|_ && parameter[\"ports\"] == _|_ {\n\t\t\t\t\t\tports:
|
||||
[{\n\t\t\t\t\t\t\tcontainerPort: parameter.port\n\t\t\t\t\t\t}]\n\t\t\t\t\t}\n\t\t\t\t\tif
|
||||
parameter[\"ports\"] != _|_ {\n\t\t\t\t\t\tports: [ for v in parameter.ports
|
||||
{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcontainerPort: v.port\n\t\t\t\t\t\t\t\tprotocol:
|
||||
\ v.protocol\n\t\t\t\t\t\t\t\tif v.name != _|_ {\n\t\t\t\t\t\t\t\t\tname:
|
||||
v.name\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif v.name == _|_ {\n\t\t\t\t\t\t\t\t\tname:
|
||||
\"port-\" + strconv.FormatInt(v.port, 10)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}}]\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"imagePullPolicy\"] != _|_ {\n\t\t\t\t\t\timagePullPolicy:
|
||||
parameter.imagePullPolicy\n\t\t\t\t\t}\n\n\t\t\t\t\tif parameter[\"cmd\"]
|
||||
!= _|_ {\n\t\t\t\t\t\tcommand: parameter.cmd\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"env\"] != _|_ {\n\t\t\t\t\t\tenv: parameter.env\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
context[\"config\"] != _|_ {\n\t\t\t\t\t\tenv: context.config\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"cpu\"] != _|_ {\n\t\t\t\t\t\tresources: {\n\t\t\t\t\t\t\tlimits:
|
||||
cpu: parameter.cpu\n\t\t\t\t\t\t\trequests: cpu: parameter.cpu\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"memory\"] != _|_ {\n\t\t\t\t\t\tresources: {\n\t\t\t\t\t\t\tlimits:
|
||||
memory: parameter.memory\n\t\t\t\t\t\t\trequests: memory: parameter.memory\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"volumes\"] != _|_ && parameter[\"volumeMounts\"] == _|_
|
||||
{\n\t\t\t\t\t\tvolumeMounts: [ for v in parameter.volumes {\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tmountPath:
|
||||
v.mountPath\n\t\t\t\t\t\t\t\tname: v.name\n\t\t\t\t\t\t\t}}]\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"volumeMounts\"] != _|_ {\n\t\t\t\t\t\tvolumeMounts: mountsArray.pvc
|
||||
+ mountsArray.configMap + mountsArray.secret + mountsArray.emptyDir
|
||||
+ mountsArray.hostPath\n\t\t\t\t\t}\n\n\t\t\t\t\tif parameter[\"livenessProbe\"]
|
||||
!= _|_ {\n\t\t\t\t\t\tlivenessProbe: parameter.livenessProbe\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"readinessProbe\"] != _|_ {\n\t\t\t\t\t\treadinessProbe:
|
||||
parameter.readinessProbe\n\t\t\t\t\t}\n\n\t\t\t\t}]\n\n\t\t\t\tif parameter[\"hostAliases\"]
|
||||
!= _|_ {\n\t\t\t\t\t// +patchKey=ip\n\t\t\t\t\thostAliases: parameter.hostAliases\n\t\t\t\t}\n\n\t\t\t\tif
|
||||
parameter[\"imagePullSecrets\"] != _|_ {\n\t\t\t\t\timagePullSecrets:
|
||||
[ for v in parameter.imagePullSecrets {\n\t\t\t\t\t\tname: v\n\t\t\t\t\t},\n\t\t\t\t\t]\n\t\t\t\t}\n\n\t\t\t\tif
|
||||
parameter[\"volumes\"] != _|_ && parameter[\"volumeMounts\"] == _|_
|
||||
{\n\t\t\t\t\tvolumes: [ for v in parameter.volumes {\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tname:
|
||||
v.name\n\t\t\t\t\t\t\tif v.type == \"pvc\" {\n\t\t\t\t\t\t\t\tpersistentVolumeClaim:
|
||||
claimName: v.claimName\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif v.type ==
|
||||
\"configMap\" {\n\t\t\t\t\t\t\t\tconfigMap: {\n\t\t\t\t\t\t\t\t\tdefaultMode:
|
||||
v.defaultMode\n\t\t\t\t\t\t\t\t\tname: v.cmName\n\t\t\t\t\t\t\t\t\tif
|
||||
v.items != _|_ {\n\t\t\t\t\t\t\t\t\t\titems: v.items\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif
|
||||
v.type == \"secret\" {\n\t\t\t\t\t\t\t\tsecret: {\n\t\t\t\t\t\t\t\t\tdefaultMode:
|
||||
v.defaultMode\n\t\t\t\t\t\t\t\t\tsecretName: v.secretName\n\t\t\t\t\t\t\t\t\tif
|
||||
v.items != _|_ {\n\t\t\t\t\t\t\t\t\t\titems: v.items\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif
|
||||
v.type == \"emptyDir\" {\n\t\t\t\t\t\t\t\temptyDir: medium: v.medium\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}]\n\t\t\t\t}\n\n\t\t\t\tif
|
||||
parameter[\"volumeMounts\"] != _|_ {\n\t\t\t\t\tvolumes: volumesArray.pvc
|
||||
+ volumesArray.configMap + volumesArray.secret + volumesArray.emptyDir
|
||||
+ volumesArray.hostPath\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\nexposePorts:
|
||||
[\n\tfor v in parameter.ports if v.expose == true {\n\t\tport: v.port\n\t\ttargetPort:
|
||||
v.port\n\t\tif v.name != _|_ {\n\t\t\tname: v.name\n\t\t}\n\t\tif v.name
|
||||
== _|_ {\n\t\t\tname: \"port-\" + strconv.FormatInt(v.port, 10)\n\t\t}\n\t},\n]\noutputs:
|
||||
{\n\tif len(exposePorts) != 0 {\n\t\twebserviceExpose: {\n\t\t\tapiVersion:
|
||||
\"v1\"\n\t\t\tkind: \"Service\"\n\t\t\tmetadata: name: context.name\n\t\t\tspec:
|
||||
{\n\t\t\t\tselector: \"app.oam.dev/component\": context.name\n\t\t\t\tports:
|
||||
exposePorts\n\t\t\t\ttype: parameter.exposeType\n\t\t\t}\n\t\t}\n\t}\n}\nparameter:
|
||||
{\n\t// +usage=Specify the labels in the workload\n\tlabels?: [string]:
|
||||
string\n\n\t// +usage=Specify the annotations in the workload\n\tannotations?:
|
||||
[string]: string\n\n\t// +usage=Which image would you like to use for
|
||||
your service\n\t// +short=i\n\timage: string\n\n\t// +usage=Specify
|
||||
image pull policy for your service\n\timagePullPolicy?: \"Always\" |
|
||||
\"Never\" | \"IfNotPresent\"\n\n\t// +usage=Specify image pull secrets
|
||||
for your service\n\timagePullSecrets?: [...string]\n\n\t// +ignore\n\t//
|
||||
+usage=Deprecated field, please use ports instead\n\t// +short=p\n\tport?:
|
||||
int\n\n\t// +usage=Which ports do you want customer traffic sent to,
|
||||
defaults to 80\n\tports?: [...{\n\t\t// +usage=Number of port to expose
|
||||
on the pod's IP address\n\t\tport: int\n\t\t// +usage=Name of the port\n\t\tname?:
|
||||
string\n\t\t// +usage=Protocol for port. Must be UDP, TCP, or SCTP\n\t\tprotocol:
|
||||
*\"TCP\" | \"UDP\" | \"SCTP\"\n\t\t// +usage=Specify if the port should
|
||||
be exposed\n\t\texpose: *false | bool\n\t}]\n\n\t// +ignore\n\t// +usage=Specify
|
||||
what kind of Service you want. options: \"ClusterIP\", \"NodePort\",
|
||||
\"LoadBalancer\", \"ExternalName\"\n\texposeType: *\"ClusterIP\" | \"NodePort\"
|
||||
| \"LoadBalancer\" | \"ExternalName\"\n\n\t// +ignore\n\t// +usage=If
|
||||
addRevisionLabel is true, the revision label will be added to the underlying
|
||||
pods\n\taddRevisionLabel: *false | bool\n\n\t// +usage=Commands to run
|
||||
in the container\n\tcmd?: [...string]\n\n\t// +usage=Define arguments
|
||||
by using environment variables\n\tenv?: [...{\n\t\t// +usage=Environment
|
||||
variable name\n\t\tname: string\n\t\t// +usage=The value of the environment
|
||||
variable\n\t\tvalue?: string\n\t\t// +usage=Specifies a source the value
|
||||
of this var should come from\n\t\tvalueFrom?: {\n\t\t\t// +usage=Selects
|
||||
a key of a secret in the pod's namespace\n\t\t\tsecretKeyRef?: {\n\t\t\t\t//
|
||||
+usage=The name of the secret in the pod's namespace to select from\n\t\t\t\tname:
|
||||
string\n\t\t\t\t// +usage=The key of the secret to select from. Must
|
||||
be a valid secret key\n\t\t\t\tkey: string\n\t\t\t}\n\t\t\t// +usage=Selects
|
||||
a key of a config map in the pod's namespace\n\t\t\tconfigMapKeyRef?:
|
||||
{\n\t\t\t\t// +usage=The name of the config map in the pod's namespace
|
||||
to select from\n\t\t\t\tname: string\n\t\t\t\t// +usage=The key of the
|
||||
config map to select from. Must be a valid secret key\n\t\t\t\tkey:
|
||||
string\n\t\t\t}\n\t\t}\n\t}]\n\n\t// +usage=Number of CPU units for
|
||||
the service, like \n\tcpu?: string\n\n\t//
|
||||
+usage=Specifies the attributes of the memory resource required for
|
||||
the container.\n\tmemory?: string\n\n\tvolumeMounts?: {\n\t\t// +usage=Mount
|
||||
PVC type volume\n\t\tpvc?: [...{\n\t\t\tname: string\n\t\t\tmountPath:
|
||||
string\n\t\t\t// +usage=The name of the PVC\n\t\t\tclaimName: string\n\t\t}]\n\t\t//
|
||||
+usage=Mount ConfigMap type volume\n\t\tconfigMap?: [...{\n\t\t\tname:
|
||||
\ string\n\t\t\tmountPath: string\n\t\t\tdefaultMode: *420 |
|
||||
int\n\t\t\tcmName: string\n\t\t\titems?: [...{\n\t\t\t\tkey: string\n\t\t\t\tpath:
|
||||
string\n\t\t\t\tmode: *511 | int\n\t\t\t}]\n\t\t}]\n\t\t// +usage=Mount
|
||||
Secret type volume\n\t\tsecret?: [...{\n\t\t\tname: string\n\t\t\tmountPath:
|
||||
\ string\n\t\t\tdefaultMode: *420 | int\n\t\t\tsecretName: string\n\t\t\titems?:
|
||||
[...{\n\t\t\t\tkey: string\n\t\t\t\tpath: string\n\t\t\t\tmode: *511
|
||||
| int\n\t\t\t}]\n\t\t}]\n\t\t// +usage=Mount EmptyDir type volume\n\t\temptyDir?:
|
||||
[...{\n\t\t\tname: string\n\t\t\tmountPath: string\n\t\t\tmedium:
|
||||
\ *\"\" | \"Memory\"\n\t\t}]\n\t\t// +usage=Mount HostPath type volume\n\t\thostPath?:
|
||||
[...{\n\t\t\tname: string\n\t\t\tmountPath: string\n\t\t\tpath:
|
||||
\ string\n\t\t}]\n\t}\n\n\t// +usage=Deprecated field, use volumeMounts
|
||||
instead.\n\tvolumes?: [...{\n\t\tname: string\n\t\tmountPath: string\n\t\t//
|
||||
+usage=Specify volume type, options: \"pvc\",\"configMap\",\"secret\",\"emptyDir\"\n\t\ttype:
|
||||
\"pvc\" | \"configMap\" | \"secret\" | \"emptyDir\"\n\t\tif type ==
|
||||
\"pvc\" {\n\t\t\tclaimName: string\n\t\t}\n\t\tif type == \"configMap\"
|
||||
{\n\t\t\tdefaultMode: *420 | int\n\t\t\tcmName: string\n\t\t\titems?:
|
||||
[...{\n\t\t\t\tkey: string\n\t\t\t\tpath: string\n\t\t\t\tmode: *511
|
||||
| int\n\t\t\t}]\n\t\t}\n\t\tif type == \"secret\" {\n\t\t\tdefaultMode:
|
||||
*420 | int\n\t\t\tsecretName: string\n\t\t\titems?: [...{\n\t\t\t\tkey:
|
||||
\ string\n\t\t\t\tpath: string\n\t\t\t\tmode: *511 | int\n\t\t\t}]\n\t\t}\n\t\tif
|
||||
type == \"emptyDir\" {\n\t\t\tmedium: *\"\" | \"Memory\"\n\t\t}\n\t}]\n\n\t//
|
||||
+usage=Instructions for assessing whether the container is alive.\n\tlivenessProbe?:
|
||||
#HealthProbe\n\n\t// +usage=Instructions for assessing whether the container
|
||||
is in a suitable state to serve traffic.\n\treadinessProbe?: #HealthProbe\n\n\t//
|
||||
+usage=Specify the hostAliases to add\n\thostAliases?: [...{\n\t\tip:
|
||||
string\n\t\thostnames: [...string]\n\t}]\n}\n#HealthProbe: {\n\n\t//
|
||||
+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.\n\texec?: {\n\t\t// +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.\n\t\tcommand: [...string]\n\t}\n\n\t//
|
||||
+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.\n\thttpGet?: {\n\t\t//
|
||||
+usage=The endpoint, relative to the port, to which the HTTP GET request
|
||||
should be directed.\n\t\tpath: string\n\t\t// +usage=The TCP socket
|
||||
within the container to which the HTTP GET request should be directed.\n\t\tport:
|
||||
int\n\t\thttpHeaders?: [...{\n\t\t\tname: string\n\t\t\tvalue: string\n\t\t}]\n\t}\n\n\t//
|
||||
+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.\n\ttcpSocket?: {\n\t\t// +usage=The
|
||||
TCP socket within the container that should be probed to assess container
|
||||
health.\n\t\tport: int\n\t}\n\n\t// +usage=Number of seconds after the
|
||||
container is started before the first probe is initiated.\n\tinitialDelaySeconds:
|
||||
*0 | int\n\n\t// +usage=How often, in seconds, to execute the probe.\n\tperiodSeconds:
|
||||
*10 | int\n\n\t// +usage=Number of seconds after which the probe times
|
||||
out.\n\ttimeoutSeconds: *1 | int\n\n\t// +usage=Minimum consecutive
|
||||
successes for the probe to be considered successful after having failed.\n\tsuccessThreshold:
|
||||
*1 | int\n\n\t// +usage=Number of consecutive failures required to determine
|
||||
the container is not alive (liveness probe) or not ready (readiness
|
||||
probe).\n\tfailureThreshold: *3 | int\n}\n"
|
||||
status:
|
||||
customStatus: "ready: {\n\treadyReplicas: *0 | int\n} & {\n\tif context.output.status.readyReplicas
|
||||
!= _|_ {\n\t\treadyReplicas: context.output.status.readyReplicas\n\t}\n}\nmessage:
|
||||
\"Ready:\\(ready.readyReplicas)/\\(context.output.spec.replicas)\""
|
||||
healthPolicy: "ready: {\n\tupdatedReplicas: *0 | int\n\treadyReplicas:
|
||||
\ *0 | int\n\treplicas: *0 | int\n\tobservedGeneration:
|
||||
*0 | int\n} & {\n\tif context.output.status.updatedReplicas != _|_ {\n\t\tupdatedReplicas:
|
||||
context.output.status.updatedReplicas\n\t}\n\tif context.output.status.readyReplicas
|
||||
!= _|_ {\n\t\treadyReplicas: context.output.status.readyReplicas\n\t}\n\tif
|
||||
context.output.status.replicas != _|_ {\n\t\treplicas: context.output.status.replicas\n\t}\n\tif
|
||||
context.output.status.observedGeneration != _|_ {\n\t\tobservedGeneration:
|
||||
context.output.status.observedGeneration\n\t}\n}\nisHealth: (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)"
|
||||
workload:
|
||||
definition:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
type: deployments.apps
|
||||
status: {}
|
||||
traitDefinitions:
|
||||
scaler:
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Manually scale K8s pod for your workload
|
||||
which follows the pod spec in path 'spec.template'.
|
||||
meta.helm.sh/release-name: kubevela
|
||||
meta.helm.sh/release-namespace: vela-system
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
name: scaler
|
||||
namespace: vela-system
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
definitionRef:
|
||||
name: ""
|
||||
schematic:
|
||||
cue:
|
||||
template: "parameter: {\n\t// +usage=Specify the number of workload\n\treplicas:
|
||||
*1 | int\n}\n// +patchStrategy=retainKeys\npatch: spec: replicas: parameter.replicas\n"
|
||||
status: {}
|
||||
status: {}
|
||||
277
pkg/appfile/testdata/backport-1-2/apprev2.yaml
vendored
Normal file
277
pkg/appfile/testdata/backport-1-2/apprev2.yaml
vendored
Normal file
@@ -0,0 +1,277 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ApplicationRevision
|
||||
metadata:
|
||||
annotations:
|
||||
app.oam.dev/publishVersion: workflow-default-123456
|
||||
name: backport-1-2-test-demo-v1
|
||||
namespace: default
|
||||
spec:
|
||||
application:
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
annotations:
|
||||
app.oam.dev/publishVersion: workflow-default-123456
|
||||
name: backport-1-2-test-demo
|
||||
namespace: default
|
||||
spec:
|
||||
components:
|
||||
- name: backport-1-2-test-demo
|
||||
properties:
|
||||
image: nginx
|
||||
traits:
|
||||
- properties:
|
||||
replicas: 1
|
||||
type: scaler
|
||||
type: webservice
|
||||
workflow:
|
||||
steps:
|
||||
- name: apply-component
|
||||
type: apply-component
|
||||
properties:
|
||||
name: backport-1-2-test-demo
|
||||
- name: apply1
|
||||
type: apply-application
|
||||
- name: apply2
|
||||
type: apply-application
|
||||
status: {}
|
||||
componentDefinitions:
|
||||
webservice:
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Describes long-running, scalable, containerized
|
||||
services that have a stable network endpoint to receive external network
|
||||
traffic from customers.
|
||||
meta.helm.sh/release-name: kubevela
|
||||
meta.helm.sh/release-namespace: vela-system
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
name: webservice
|
||||
namespace: vela-system
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: "import (\n\t\"strconv\"\n)\n\nmountsArray: {\n\tpvc: *[\n\t\tfor
|
||||
v in parameter.volumeMounts.pvc {\n\t\t\t{\n\t\t\t\tmountPath: v.mountPath\n\t\t\t\tname:
|
||||
\ v.name\n\t\t\t}\n\t\t},\n\t] | []\n\n\tconfigMap: *[\n\t\t\tfor
|
||||
v in parameter.volumeMounts.configMap {\n\t\t\t{\n\t\t\t\tmountPath:
|
||||
v.mountPath\n\t\t\t\tname: v.name\n\t\t\t}\n\t\t},\n\t] | []\n\n\tsecret:
|
||||
*[\n\t\tfor v in parameter.volumeMounts.secret {\n\t\t\t{\n\t\t\t\tmountPath:
|
||||
v.mountPath\n\t\t\t\tname: v.name\n\t\t\t}\n\t\t},\n\t] | []\n\n\temptyDir:
|
||||
*[\n\t\t\tfor v in parameter.volumeMounts.emptyDir {\n\t\t\t{\n\t\t\t\tmountPath:
|
||||
v.mountPath\n\t\t\t\tname: v.name\n\t\t\t}\n\t\t},\n\t] | []\n\n\thostPath:
|
||||
*[\n\t\t\tfor v in parameter.volumeMounts.hostPath {\n\t\t\t{\n\t\t\t\tmountPath:
|
||||
v.mountPath\n\t\t\t\tname: v.name\n\t\t\t}\n\t\t},\n\t] | []\n}\nvolumesArray:
|
||||
{\n\tpvc: *[\n\t\tfor v in parameter.volumeMounts.pvc {\n\t\t\t{\n\t\t\t\tname:
|
||||
v.name\n\t\t\t\tpersistentVolumeClaim: claimName: v.claimName\n\t\t\t}\n\t\t},\n\t]
|
||||
| []\n\n\tconfigMap: *[\n\t\t\tfor v in parameter.volumeMounts.configMap
|
||||
{\n\t\t\t{\n\t\t\t\tname: v.name\n\t\t\t\tconfigMap: {\n\t\t\t\t\tdefaultMode:
|
||||
v.defaultMode\n\t\t\t\t\tname: v.cmName\n\t\t\t\t\tif v.items
|
||||
!= _|_ {\n\t\t\t\t\t\titems: v.items\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t]
|
||||
| []\n\n\tsecret: *[\n\t\tfor v in parameter.volumeMounts.secret {\n\t\t\t{\n\t\t\t\tname:
|
||||
v.name\n\t\t\t\tsecret: {\n\t\t\t\t\tdefaultMode: v.defaultMode\n\t\t\t\t\tsecretName:
|
||||
\ v.secretName\n\t\t\t\t\tif v.items != _|_ {\n\t\t\t\t\t\titems: v.items\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t]
|
||||
| []\n\n\temptyDir: *[\n\t\t\tfor v in parameter.volumeMounts.emptyDir
|
||||
{\n\t\t\t{\n\t\t\t\tname: v.name\n\t\t\t\temptyDir: medium: v.medium\n\t\t\t}\n\t\t},\n\t]
|
||||
| []\n\n\thostPath: *[\n\t\t\tfor v in parameter.volumeMounts.hostPath
|
||||
{\n\t\t\t{\n\t\t\t\tname: v.name\n\t\t\t\thostPath: path: v.path\n\t\t\t}\n\t\t},\n\t]
|
||||
| []\n}\noutput: {\n\tapiVersion: \"apps/v1\"\n\tkind: \"Deployment\"\n\tspec:
|
||||
{\n\t\tselector: matchLabels: \"app.oam.dev/component\": context.name\n\n\t\ttemplate:
|
||||
{\n\t\t\tmetadata: {\n\t\t\t\tlabels: {\n\t\t\t\t\tif parameter.labels
|
||||
!= _|_ {\n\t\t\t\t\t\tparameter.labels\n\t\t\t\t\t}\n\t\t\t\t\tif parameter.addRevisionLabel
|
||||
{\n\t\t\t\t\t\t\"app.oam.dev/revision\": context.revision\n\t\t\t\t\t}\n\t\t\t\t\t\"app.oam.dev/component\":
|
||||
context.name\n\t\t\t\t}\n\t\t\t\tif parameter.annotations != _|_ {\n\t\t\t\t\tannotations:
|
||||
parameter.annotations\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tspec: {\n\t\t\t\tcontainers:
|
||||
[{\n\t\t\t\t\tname: context.name\n\t\t\t\t\timage: parameter.image\n\t\t\t\t\tif
|
||||
parameter[\"port\"] != _|_ && parameter[\"ports\"] == _|_ {\n\t\t\t\t\t\tports:
|
||||
[{\n\t\t\t\t\t\t\tcontainerPort: parameter.port\n\t\t\t\t\t\t}]\n\t\t\t\t\t}\n\t\t\t\t\tif
|
||||
parameter[\"ports\"] != _|_ {\n\t\t\t\t\t\tports: [ for v in parameter.ports
|
||||
{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcontainerPort: v.port\n\t\t\t\t\t\t\t\tprotocol:
|
||||
\ v.protocol\n\t\t\t\t\t\t\t\tif v.name != _|_ {\n\t\t\t\t\t\t\t\t\tname:
|
||||
v.name\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif v.name == _|_ {\n\t\t\t\t\t\t\t\t\tname:
|
||||
\"port-\" + strconv.FormatInt(v.port, 10)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}}]\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"imagePullPolicy\"] != _|_ {\n\t\t\t\t\t\timagePullPolicy:
|
||||
parameter.imagePullPolicy\n\t\t\t\t\t}\n\n\t\t\t\t\tif parameter[\"cmd\"]
|
||||
!= _|_ {\n\t\t\t\t\t\tcommand: parameter.cmd\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"env\"] != _|_ {\n\t\t\t\t\t\tenv: parameter.env\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
context[\"config\"] != _|_ {\n\t\t\t\t\t\tenv: context.config\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"cpu\"] != _|_ {\n\t\t\t\t\t\tresources: {\n\t\t\t\t\t\t\tlimits:
|
||||
cpu: parameter.cpu\n\t\t\t\t\t\t\trequests: cpu: parameter.cpu\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"memory\"] != _|_ {\n\t\t\t\t\t\tresources: {\n\t\t\t\t\t\t\tlimits:
|
||||
memory: parameter.memory\n\t\t\t\t\t\t\trequests: memory: parameter.memory\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"volumes\"] != _|_ && parameter[\"volumeMounts\"] == _|_
|
||||
{\n\t\t\t\t\t\tvolumeMounts: [ for v in parameter.volumes {\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tmountPath:
|
||||
v.mountPath\n\t\t\t\t\t\t\t\tname: v.name\n\t\t\t\t\t\t\t}}]\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"volumeMounts\"] != _|_ {\n\t\t\t\t\t\tvolumeMounts: mountsArray.pvc
|
||||
+ mountsArray.configMap + mountsArray.secret + mountsArray.emptyDir
|
||||
+ mountsArray.hostPath\n\t\t\t\t\t}\n\n\t\t\t\t\tif parameter[\"livenessProbe\"]
|
||||
!= _|_ {\n\t\t\t\t\t\tlivenessProbe: parameter.livenessProbe\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"readinessProbe\"] != _|_ {\n\t\t\t\t\t\treadinessProbe:
|
||||
parameter.readinessProbe\n\t\t\t\t\t}\n\n\t\t\t\t}]\n\n\t\t\t\tif parameter[\"hostAliases\"]
|
||||
!= _|_ {\n\t\t\t\t\t// +patchKey=ip\n\t\t\t\t\thostAliases: parameter.hostAliases\n\t\t\t\t}\n\n\t\t\t\tif
|
||||
parameter[\"imagePullSecrets\"] != _|_ {\n\t\t\t\t\timagePullSecrets:
|
||||
[ for v in parameter.imagePullSecrets {\n\t\t\t\t\t\tname: v\n\t\t\t\t\t},\n\t\t\t\t\t]\n\t\t\t\t}\n\n\t\t\t\tif
|
||||
parameter[\"volumes\"] != _|_ && parameter[\"volumeMounts\"] == _|_
|
||||
{\n\t\t\t\t\tvolumes: [ for v in parameter.volumes {\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tname:
|
||||
v.name\n\t\t\t\t\t\t\tif v.type == \"pvc\" {\n\t\t\t\t\t\t\t\tpersistentVolumeClaim:
|
||||
claimName: v.claimName\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif v.type ==
|
||||
\"configMap\" {\n\t\t\t\t\t\t\t\tconfigMap: {\n\t\t\t\t\t\t\t\t\tdefaultMode:
|
||||
v.defaultMode\n\t\t\t\t\t\t\t\t\tname: v.cmName\n\t\t\t\t\t\t\t\t\tif
|
||||
v.items != _|_ {\n\t\t\t\t\t\t\t\t\t\titems: v.items\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif
|
||||
v.type == \"secret\" {\n\t\t\t\t\t\t\t\tsecret: {\n\t\t\t\t\t\t\t\t\tdefaultMode:
|
||||
v.defaultMode\n\t\t\t\t\t\t\t\t\tsecretName: v.secretName\n\t\t\t\t\t\t\t\t\tif
|
||||
v.items != _|_ {\n\t\t\t\t\t\t\t\t\t\titems: v.items\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif
|
||||
v.type == \"emptyDir\" {\n\t\t\t\t\t\t\t\temptyDir: medium: v.medium\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}]\n\t\t\t\t}\n\n\t\t\t\tif
|
||||
parameter[\"volumeMounts\"] != _|_ {\n\t\t\t\t\tvolumes: volumesArray.pvc
|
||||
+ volumesArray.configMap + volumesArray.secret + volumesArray.emptyDir
|
||||
+ volumesArray.hostPath\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\nexposePorts:
|
||||
[\n\tfor v in parameter.ports if v.expose == true {\n\t\tport: v.port\n\t\ttargetPort:
|
||||
v.port\n\t\tif v.name != _|_ {\n\t\t\tname: v.name\n\t\t}\n\t\tif v.name
|
||||
== _|_ {\n\t\t\tname: \"port-\" + strconv.FormatInt(v.port, 10)\n\t\t}\n\t},\n]\noutputs:
|
||||
{\n\tif len(exposePorts) != 0 {\n\t\twebserviceExpose: {\n\t\t\tapiVersion:
|
||||
\"v1\"\n\t\t\tkind: \"Service\"\n\t\t\tmetadata: name: context.name\n\t\t\tspec:
|
||||
{\n\t\t\t\tselector: \"app.oam.dev/component\": context.name\n\t\t\t\tports:
|
||||
exposePorts\n\t\t\t\ttype: parameter.exposeType\n\t\t\t}\n\t\t}\n\t}\n}\nparameter:
|
||||
{\n\t// +usage=Specify the labels in the workload\n\tlabels?: [string]:
|
||||
string\n\n\t// +usage=Specify the annotations in the workload\n\tannotations?:
|
||||
[string]: string\n\n\t// +usage=Which image would you like to use for
|
||||
your service\n\t// +short=i\n\timage: string\n\n\t// +usage=Specify
|
||||
image pull policy for your service\n\timagePullPolicy?: \"Always\" |
|
||||
\"Never\" | \"IfNotPresent\"\n\n\t// +usage=Specify image pull secrets
|
||||
for your service\n\timagePullSecrets?: [...string]\n\n\t// +ignore\n\t//
|
||||
+usage=Deprecated field, please use ports instead\n\t// +short=p\n\tport?:
|
||||
int\n\n\t// +usage=Which ports do you want customer traffic sent to,
|
||||
defaults to 80\n\tports?: [...{\n\t\t// +usage=Number of port to expose
|
||||
on the pod's IP address\n\t\tport: int\n\t\t// +usage=Name of the port\n\t\tname?:
|
||||
string\n\t\t// +usage=Protocol for port. Must be UDP, TCP, or SCTP\n\t\tprotocol:
|
||||
*\"TCP\" | \"UDP\" | \"SCTP\"\n\t\t// +usage=Specify if the port should
|
||||
be exposed\n\t\texpose: *false | bool\n\t}]\n\n\t// +ignore\n\t// +usage=Specify
|
||||
what kind of Service you want. options: \"ClusterIP\", \"NodePort\",
|
||||
\"LoadBalancer\", \"ExternalName\"\n\texposeType: *\"ClusterIP\" | \"NodePort\"
|
||||
| \"LoadBalancer\" | \"ExternalName\"\n\n\t// +ignore\n\t// +usage=If
|
||||
addRevisionLabel is true, the revision label will be added to the underlying
|
||||
pods\n\taddRevisionLabel: *false | bool\n\n\t// +usage=Commands to run
|
||||
in the container\n\tcmd?: [...string]\n\n\t// +usage=Define arguments
|
||||
by using environment variables\n\tenv?: [...{\n\t\t// +usage=Environment
|
||||
variable name\n\t\tname: string\n\t\t// +usage=The value of the environment
|
||||
variable\n\t\tvalue?: string\n\t\t// +usage=Specifies a source the value
|
||||
of this var should come from\n\t\tvalueFrom?: {\n\t\t\t// +usage=Selects
|
||||
a key of a secret in the pod's namespace\n\t\t\tsecretKeyRef?: {\n\t\t\t\t//
|
||||
+usage=The name of the secret in the pod's namespace to select from\n\t\t\t\tname:
|
||||
string\n\t\t\t\t// +usage=The key of the secret to select from. Must
|
||||
be a valid secret key\n\t\t\t\tkey: string\n\t\t\t}\n\t\t\t// +usage=Selects
|
||||
a key of a config map in the pod's namespace\n\t\t\tconfigMapKeyRef?:
|
||||
{\n\t\t\t\t// +usage=The name of the config map in the pod's namespace
|
||||
to select from\n\t\t\t\tname: string\n\t\t\t\t// +usage=The key of the
|
||||
config map to select from. Must be a valid secret key\n\t\t\t\tkey:
|
||||
string\n\t\t\t}\n\t\t}\n\t}]\n\n\t// +usage=Number of CPU units for
|
||||
the service, like \n\tcpu?: string\n\n\t//
|
||||
+usage=Specifies the attributes of the memory resource required for
|
||||
the container.\n\tmemory?: string\n\n\tvolumeMounts?: {\n\t\t// +usage=Mount
|
||||
PVC type volume\n\t\tpvc?: [...{\n\t\t\tname: string\n\t\t\tmountPath:
|
||||
string\n\t\t\t// +usage=The name of the PVC\n\t\t\tclaimName: string\n\t\t}]\n\t\t//
|
||||
+usage=Mount ConfigMap type volume\n\t\tconfigMap?: [...{\n\t\t\tname:
|
||||
\ string\n\t\t\tmountPath: string\n\t\t\tdefaultMode: *420 |
|
||||
int\n\t\t\tcmName: string\n\t\t\titems?: [...{\n\t\t\t\tkey: string\n\t\t\t\tpath:
|
||||
string\n\t\t\t\tmode: *511 | int\n\t\t\t}]\n\t\t}]\n\t\t// +usage=Mount
|
||||
Secret type volume\n\t\tsecret?: [...{\n\t\t\tname: string\n\t\t\tmountPath:
|
||||
\ string\n\t\t\tdefaultMode: *420 | int\n\t\t\tsecretName: string\n\t\t\titems?:
|
||||
[...{\n\t\t\t\tkey: string\n\t\t\t\tpath: string\n\t\t\t\tmode: *511
|
||||
| int\n\t\t\t}]\n\t\t}]\n\t\t// +usage=Mount EmptyDir type volume\n\t\temptyDir?:
|
||||
[...{\n\t\t\tname: string\n\t\t\tmountPath: string\n\t\t\tmedium:
|
||||
\ *\"\" | \"Memory\"\n\t\t}]\n\t\t// +usage=Mount HostPath type volume\n\t\thostPath?:
|
||||
[...{\n\t\t\tname: string\n\t\t\tmountPath: string\n\t\t\tpath:
|
||||
\ string\n\t\t}]\n\t}\n\n\t// +usage=Deprecated field, use volumeMounts
|
||||
instead.\n\tvolumes?: [...{\n\t\tname: string\n\t\tmountPath: string\n\t\t//
|
||||
+usage=Specify volume type, options: \"pvc\",\"configMap\",\"secret\",\"emptyDir\"\n\t\ttype:
|
||||
\"pvc\" | \"configMap\" | \"secret\" | \"emptyDir\"\n\t\tif type ==
|
||||
\"pvc\" {\n\t\t\tclaimName: string\n\t\t}\n\t\tif type == \"configMap\"
|
||||
{\n\t\t\tdefaultMode: *420 | int\n\t\t\tcmName: string\n\t\t\titems?:
|
||||
[...{\n\t\t\t\tkey: string\n\t\t\t\tpath: string\n\t\t\t\tmode: *511
|
||||
| int\n\t\t\t}]\n\t\t}\n\t\tif type == \"secret\" {\n\t\t\tdefaultMode:
|
||||
*420 | int\n\t\t\tsecretName: string\n\t\t\titems?: [...{\n\t\t\t\tkey:
|
||||
\ string\n\t\t\t\tpath: string\n\t\t\t\tmode: *511 | int\n\t\t\t}]\n\t\t}\n\t\tif
|
||||
type == \"emptyDir\" {\n\t\t\tmedium: *\"\" | \"Memory\"\n\t\t}\n\t}]\n\n\t//
|
||||
+usage=Instructions for assessing whether the container is alive.\n\tlivenessProbe?:
|
||||
#HealthProbe\n\n\t// +usage=Instructions for assessing whether the container
|
||||
is in a suitable state to serve traffic.\n\treadinessProbe?: #HealthProbe\n\n\t//
|
||||
+usage=Specify the hostAliases to add\n\thostAliases?: [...{\n\t\tip:
|
||||
string\n\t\thostnames: [...string]\n\t}]\n}\n#HealthProbe: {\n\n\t//
|
||||
+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.\n\texec?: {\n\t\t// +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.\n\t\tcommand: [...string]\n\t}\n\n\t//
|
||||
+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.\n\thttpGet?: {\n\t\t//
|
||||
+usage=The endpoint, relative to the port, to which the HTTP GET request
|
||||
should be directed.\n\t\tpath: string\n\t\t// +usage=The TCP socket
|
||||
within the container to which the HTTP GET request should be directed.\n\t\tport:
|
||||
int\n\t\thttpHeaders?: [...{\n\t\t\tname: string\n\t\t\tvalue: string\n\t\t}]\n\t}\n\n\t//
|
||||
+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.\n\ttcpSocket?: {\n\t\t// +usage=The
|
||||
TCP socket within the container that should be probed to assess container
|
||||
health.\n\t\tport: int\n\t}\n\n\t// +usage=Number of seconds after the
|
||||
container is started before the first probe is initiated.\n\tinitialDelaySeconds:
|
||||
*0 | int\n\n\t// +usage=How often, in seconds, to execute the probe.\n\tperiodSeconds:
|
||||
*10 | int\n\n\t// +usage=Number of seconds after which the probe times
|
||||
out.\n\ttimeoutSeconds: *1 | int\n\n\t// +usage=Minimum consecutive
|
||||
successes for the probe to be considered successful after having failed.\n\tsuccessThreshold:
|
||||
*1 | int\n\n\t// +usage=Number of consecutive failures required to determine
|
||||
the container is not alive (liveness probe) or not ready (readiness
|
||||
probe).\n\tfailureThreshold: *3 | int\n}\n"
|
||||
status:
|
||||
customStatus: "ready: {\n\treadyReplicas: *0 | int\n} & {\n\tif context.output.status.readyReplicas
|
||||
!= _|_ {\n\t\treadyReplicas: context.output.status.readyReplicas\n\t}\n}\nmessage:
|
||||
\"Ready:\\(ready.readyReplicas)/\\(context.output.spec.replicas)\""
|
||||
healthPolicy: "ready: {\n\tupdatedReplicas: *0 | int\n\treadyReplicas:
|
||||
\ *0 | int\n\treplicas: *0 | int\n\tobservedGeneration:
|
||||
*0 | int\n} & {\n\tif context.output.status.updatedReplicas != _|_ {\n\t\tupdatedReplicas:
|
||||
context.output.status.updatedReplicas\n\t}\n\tif context.output.status.readyReplicas
|
||||
!= _|_ {\n\t\treadyReplicas: context.output.status.readyReplicas\n\t}\n\tif
|
||||
context.output.status.replicas != _|_ {\n\t\treplicas: context.output.status.replicas\n\t}\n\tif
|
||||
context.output.status.observedGeneration != _|_ {\n\t\tobservedGeneration:
|
||||
context.output.status.observedGeneration\n\t}\n}\nisHealth: (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)"
|
||||
workload:
|
||||
definition:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
type: deployments.apps
|
||||
status: {}
|
||||
traitDefinitions:
|
||||
scaler:
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Manually scale K8s pod for your workload
|
||||
which follows the pod spec in path 'spec.template'.
|
||||
meta.helm.sh/release-name: kubevela
|
||||
meta.helm.sh/release-namespace: vela-system
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
name: scaler
|
||||
namespace: vela-system
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
definitionRef:
|
||||
name: ""
|
||||
schematic:
|
||||
cue:
|
||||
template: "parameter: {\n\t// +usage=Specify the number of workload\n\treplicas:
|
||||
*1 | int\n}\n// +patchStrategy=retainKeys\npatch: spec: replicas: parameter.replicas\n"
|
||||
status: {}
|
||||
status: {}
|
||||
271
pkg/appfile/testdata/backport-1-2/apprev3.yaml
vendored
Normal file
271
pkg/appfile/testdata/backport-1-2/apprev3.yaml
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ApplicationRevision
|
||||
metadata:
|
||||
annotations:
|
||||
app.oam.dev/publishVersion: workflow-default-123456
|
||||
name: backport-1-2-test-demo-v1
|
||||
namespace: default
|
||||
spec:
|
||||
application:
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
annotations:
|
||||
app.oam.dev/publishVersion: workflow-default-123456
|
||||
name: backport-1-2-test-demo
|
||||
namespace: default
|
||||
spec:
|
||||
components:
|
||||
- name: backport-1-2-test-demo
|
||||
properties:
|
||||
image: nginx
|
||||
traits:
|
||||
- properties:
|
||||
replicas: 1
|
||||
type: scaler
|
||||
type: webservice
|
||||
workflow:
|
||||
steps:
|
||||
- name: apply
|
||||
type: apply-application-unknown
|
||||
status: {}
|
||||
componentDefinitions:
|
||||
webservice:
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Describes long-running, scalable, containerized
|
||||
services that have a stable network endpoint to receive external network
|
||||
traffic from customers.
|
||||
meta.helm.sh/release-name: kubevela
|
||||
meta.helm.sh/release-namespace: vela-system
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
name: webservice
|
||||
namespace: vela-system
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: "import (\n\t\"strconv\"\n)\n\nmountsArray: {\n\tpvc: *[\n\t\tfor
|
||||
v in parameter.volumeMounts.pvc {\n\t\t\t{\n\t\t\t\tmountPath: v.mountPath\n\t\t\t\tname:
|
||||
\ v.name\n\t\t\t}\n\t\t},\n\t] | []\n\n\tconfigMap: *[\n\t\t\tfor
|
||||
v in parameter.volumeMounts.configMap {\n\t\t\t{\n\t\t\t\tmountPath:
|
||||
v.mountPath\n\t\t\t\tname: v.name\n\t\t\t}\n\t\t},\n\t] | []\n\n\tsecret:
|
||||
*[\n\t\tfor v in parameter.volumeMounts.secret {\n\t\t\t{\n\t\t\t\tmountPath:
|
||||
v.mountPath\n\t\t\t\tname: v.name\n\t\t\t}\n\t\t},\n\t] | []\n\n\temptyDir:
|
||||
*[\n\t\t\tfor v in parameter.volumeMounts.emptyDir {\n\t\t\t{\n\t\t\t\tmountPath:
|
||||
v.mountPath\n\t\t\t\tname: v.name\n\t\t\t}\n\t\t},\n\t] | []\n\n\thostPath:
|
||||
*[\n\t\t\tfor v in parameter.volumeMounts.hostPath {\n\t\t\t{\n\t\t\t\tmountPath:
|
||||
v.mountPath\n\t\t\t\tname: v.name\n\t\t\t}\n\t\t},\n\t] | []\n}\nvolumesArray:
|
||||
{\n\tpvc: *[\n\t\tfor v in parameter.volumeMounts.pvc {\n\t\t\t{\n\t\t\t\tname:
|
||||
v.name\n\t\t\t\tpersistentVolumeClaim: claimName: v.claimName\n\t\t\t}\n\t\t},\n\t]
|
||||
| []\n\n\tconfigMap: *[\n\t\t\tfor v in parameter.volumeMounts.configMap
|
||||
{\n\t\t\t{\n\t\t\t\tname: v.name\n\t\t\t\tconfigMap: {\n\t\t\t\t\tdefaultMode:
|
||||
v.defaultMode\n\t\t\t\t\tname: v.cmName\n\t\t\t\t\tif v.items
|
||||
!= _|_ {\n\t\t\t\t\t\titems: v.items\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t]
|
||||
| []\n\n\tsecret: *[\n\t\tfor v in parameter.volumeMounts.secret {\n\t\t\t{\n\t\t\t\tname:
|
||||
v.name\n\t\t\t\tsecret: {\n\t\t\t\t\tdefaultMode: v.defaultMode\n\t\t\t\t\tsecretName:
|
||||
\ v.secretName\n\t\t\t\t\tif v.items != _|_ {\n\t\t\t\t\t\titems: v.items\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t]
|
||||
| []\n\n\temptyDir: *[\n\t\t\tfor v in parameter.volumeMounts.emptyDir
|
||||
{\n\t\t\t{\n\t\t\t\tname: v.name\n\t\t\t\temptyDir: medium: v.medium\n\t\t\t}\n\t\t},\n\t]
|
||||
| []\n\n\thostPath: *[\n\t\t\tfor v in parameter.volumeMounts.hostPath
|
||||
{\n\t\t\t{\n\t\t\t\tname: v.name\n\t\t\t\thostPath: path: v.path\n\t\t\t}\n\t\t},\n\t]
|
||||
| []\n}\noutput: {\n\tapiVersion: \"apps/v1\"\n\tkind: \"Deployment\"\n\tspec:
|
||||
{\n\t\tselector: matchLabels: \"app.oam.dev/component\": context.name\n\n\t\ttemplate:
|
||||
{\n\t\t\tmetadata: {\n\t\t\t\tlabels: {\n\t\t\t\t\tif parameter.labels
|
||||
!= _|_ {\n\t\t\t\t\t\tparameter.labels\n\t\t\t\t\t}\n\t\t\t\t\tif parameter.addRevisionLabel
|
||||
{\n\t\t\t\t\t\t\"app.oam.dev/revision\": context.revision\n\t\t\t\t\t}\n\t\t\t\t\t\"app.oam.dev/component\":
|
||||
context.name\n\t\t\t\t}\n\t\t\t\tif parameter.annotations != _|_ {\n\t\t\t\t\tannotations:
|
||||
parameter.annotations\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tspec: {\n\t\t\t\tcontainers:
|
||||
[{\n\t\t\t\t\tname: context.name\n\t\t\t\t\timage: parameter.image\n\t\t\t\t\tif
|
||||
parameter[\"port\"] != _|_ && parameter[\"ports\"] == _|_ {\n\t\t\t\t\t\tports:
|
||||
[{\n\t\t\t\t\t\t\tcontainerPort: parameter.port\n\t\t\t\t\t\t}]\n\t\t\t\t\t}\n\t\t\t\t\tif
|
||||
parameter[\"ports\"] != _|_ {\n\t\t\t\t\t\tports: [ for v in parameter.ports
|
||||
{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcontainerPort: v.port\n\t\t\t\t\t\t\t\tprotocol:
|
||||
\ v.protocol\n\t\t\t\t\t\t\t\tif v.name != _|_ {\n\t\t\t\t\t\t\t\t\tname:
|
||||
v.name\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif v.name == _|_ {\n\t\t\t\t\t\t\t\t\tname:
|
||||
\"port-\" + strconv.FormatInt(v.port, 10)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}}]\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"imagePullPolicy\"] != _|_ {\n\t\t\t\t\t\timagePullPolicy:
|
||||
parameter.imagePullPolicy\n\t\t\t\t\t}\n\n\t\t\t\t\tif parameter[\"cmd\"]
|
||||
!= _|_ {\n\t\t\t\t\t\tcommand: parameter.cmd\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"env\"] != _|_ {\n\t\t\t\t\t\tenv: parameter.env\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
context[\"config\"] != _|_ {\n\t\t\t\t\t\tenv: context.config\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"cpu\"] != _|_ {\n\t\t\t\t\t\tresources: {\n\t\t\t\t\t\t\tlimits:
|
||||
cpu: parameter.cpu\n\t\t\t\t\t\t\trequests: cpu: parameter.cpu\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"memory\"] != _|_ {\n\t\t\t\t\t\tresources: {\n\t\t\t\t\t\t\tlimits:
|
||||
memory: parameter.memory\n\t\t\t\t\t\t\trequests: memory: parameter.memory\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"volumes\"] != _|_ && parameter[\"volumeMounts\"] == _|_
|
||||
{\n\t\t\t\t\t\tvolumeMounts: [ for v in parameter.volumes {\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tmountPath:
|
||||
v.mountPath\n\t\t\t\t\t\t\t\tname: v.name\n\t\t\t\t\t\t\t}}]\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"volumeMounts\"] != _|_ {\n\t\t\t\t\t\tvolumeMounts: mountsArray.pvc
|
||||
+ mountsArray.configMap + mountsArray.secret + mountsArray.emptyDir
|
||||
+ mountsArray.hostPath\n\t\t\t\t\t}\n\n\t\t\t\t\tif parameter[\"livenessProbe\"]
|
||||
!= _|_ {\n\t\t\t\t\t\tlivenessProbe: parameter.livenessProbe\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"readinessProbe\"] != _|_ {\n\t\t\t\t\t\treadinessProbe:
|
||||
parameter.readinessProbe\n\t\t\t\t\t}\n\n\t\t\t\t}]\n\n\t\t\t\tif parameter[\"hostAliases\"]
|
||||
!= _|_ {\n\t\t\t\t\t// +patchKey=ip\n\t\t\t\t\thostAliases: parameter.hostAliases\n\t\t\t\t}\n\n\t\t\t\tif
|
||||
parameter[\"imagePullSecrets\"] != _|_ {\n\t\t\t\t\timagePullSecrets:
|
||||
[ for v in parameter.imagePullSecrets {\n\t\t\t\t\t\tname: v\n\t\t\t\t\t},\n\t\t\t\t\t]\n\t\t\t\t}\n\n\t\t\t\tif
|
||||
parameter[\"volumes\"] != _|_ && parameter[\"volumeMounts\"] == _|_
|
||||
{\n\t\t\t\t\tvolumes: [ for v in parameter.volumes {\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tname:
|
||||
v.name\n\t\t\t\t\t\t\tif v.type == \"pvc\" {\n\t\t\t\t\t\t\t\tpersistentVolumeClaim:
|
||||
claimName: v.claimName\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif v.type ==
|
||||
\"configMap\" {\n\t\t\t\t\t\t\t\tconfigMap: {\n\t\t\t\t\t\t\t\t\tdefaultMode:
|
||||
v.defaultMode\n\t\t\t\t\t\t\t\t\tname: v.cmName\n\t\t\t\t\t\t\t\t\tif
|
||||
v.items != _|_ {\n\t\t\t\t\t\t\t\t\t\titems: v.items\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif
|
||||
v.type == \"secret\" {\n\t\t\t\t\t\t\t\tsecret: {\n\t\t\t\t\t\t\t\t\tdefaultMode:
|
||||
v.defaultMode\n\t\t\t\t\t\t\t\t\tsecretName: v.secretName\n\t\t\t\t\t\t\t\t\tif
|
||||
v.items != _|_ {\n\t\t\t\t\t\t\t\t\t\titems: v.items\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif
|
||||
v.type == \"emptyDir\" {\n\t\t\t\t\t\t\t\temptyDir: medium: v.medium\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}]\n\t\t\t\t}\n\n\t\t\t\tif
|
||||
parameter[\"volumeMounts\"] != _|_ {\n\t\t\t\t\tvolumes: volumesArray.pvc
|
||||
+ volumesArray.configMap + volumesArray.secret + volumesArray.emptyDir
|
||||
+ volumesArray.hostPath\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\nexposePorts:
|
||||
[\n\tfor v in parameter.ports if v.expose == true {\n\t\tport: v.port\n\t\ttargetPort:
|
||||
v.port\n\t\tif v.name != _|_ {\n\t\t\tname: v.name\n\t\t}\n\t\tif v.name
|
||||
== _|_ {\n\t\t\tname: \"port-\" + strconv.FormatInt(v.port, 10)\n\t\t}\n\t},\n]\noutputs:
|
||||
{\n\tif len(exposePorts) != 0 {\n\t\twebserviceExpose: {\n\t\t\tapiVersion:
|
||||
\"v1\"\n\t\t\tkind: \"Service\"\n\t\t\tmetadata: name: context.name\n\t\t\tspec:
|
||||
{\n\t\t\t\tselector: \"app.oam.dev/component\": context.name\n\t\t\t\tports:
|
||||
exposePorts\n\t\t\t\ttype: parameter.exposeType\n\t\t\t}\n\t\t}\n\t}\n}\nparameter:
|
||||
{\n\t// +usage=Specify the labels in the workload\n\tlabels?: [string]:
|
||||
string\n\n\t// +usage=Specify the annotations in the workload\n\tannotations?:
|
||||
[string]: string\n\n\t// +usage=Which image would you like to use for
|
||||
your service\n\t// +short=i\n\timage: string\n\n\t// +usage=Specify
|
||||
image pull policy for your service\n\timagePullPolicy?: \"Always\" |
|
||||
\"Never\" | \"IfNotPresent\"\n\n\t// +usage=Specify image pull secrets
|
||||
for your service\n\timagePullSecrets?: [...string]\n\n\t// +ignore\n\t//
|
||||
+usage=Deprecated field, please use ports instead\n\t// +short=p\n\tport?:
|
||||
int\n\n\t// +usage=Which ports do you want customer traffic sent to,
|
||||
defaults to 80\n\tports?: [...{\n\t\t// +usage=Number of port to expose
|
||||
on the pod's IP address\n\t\tport: int\n\t\t// +usage=Name of the port\n\t\tname?:
|
||||
string\n\t\t// +usage=Protocol for port. Must be UDP, TCP, or SCTP\n\t\tprotocol:
|
||||
*\"TCP\" | \"UDP\" | \"SCTP\"\n\t\t// +usage=Specify if the port should
|
||||
be exposed\n\t\texpose: *false | bool\n\t}]\n\n\t// +ignore\n\t// +usage=Specify
|
||||
what kind of Service you want. options: \"ClusterIP\", \"NodePort\",
|
||||
\"LoadBalancer\", \"ExternalName\"\n\texposeType: *\"ClusterIP\" | \"NodePort\"
|
||||
| \"LoadBalancer\" | \"ExternalName\"\n\n\t// +ignore\n\t// +usage=If
|
||||
addRevisionLabel is true, the revision label will be added to the underlying
|
||||
pods\n\taddRevisionLabel: *false | bool\n\n\t// +usage=Commands to run
|
||||
in the container\n\tcmd?: [...string]\n\n\t// +usage=Define arguments
|
||||
by using environment variables\n\tenv?: [...{\n\t\t// +usage=Environment
|
||||
variable name\n\t\tname: string\n\t\t// +usage=The value of the environment
|
||||
variable\n\t\tvalue?: string\n\t\t// +usage=Specifies a source the value
|
||||
of this var should come from\n\t\tvalueFrom?: {\n\t\t\t// +usage=Selects
|
||||
a key of a secret in the pod's namespace\n\t\t\tsecretKeyRef?: {\n\t\t\t\t//
|
||||
+usage=The name of the secret in the pod's namespace to select from\n\t\t\t\tname:
|
||||
string\n\t\t\t\t// +usage=The key of the secret to select from. Must
|
||||
be a valid secret key\n\t\t\t\tkey: string\n\t\t\t}\n\t\t\t// +usage=Selects
|
||||
a key of a config map in the pod's namespace\n\t\t\tconfigMapKeyRef?:
|
||||
{\n\t\t\t\t// +usage=The name of the config map in the pod's namespace
|
||||
to select from\n\t\t\t\tname: string\n\t\t\t\t// +usage=The key of the
|
||||
config map to select from. Must be a valid secret key\n\t\t\t\tkey:
|
||||
string\n\t\t\t}\n\t\t}\n\t}]\n\n\t// +usage=Number of CPU units for
|
||||
the service, like \n\tcpu?: string\n\n\t//
|
||||
+usage=Specifies the attributes of the memory resource required for
|
||||
the container.\n\tmemory?: string\n\n\tvolumeMounts?: {\n\t\t// +usage=Mount
|
||||
PVC type volume\n\t\tpvc?: [...{\n\t\t\tname: string\n\t\t\tmountPath:
|
||||
string\n\t\t\t// +usage=The name of the PVC\n\t\t\tclaimName: string\n\t\t}]\n\t\t//
|
||||
+usage=Mount ConfigMap type volume\n\t\tconfigMap?: [...{\n\t\t\tname:
|
||||
\ string\n\t\t\tmountPath: string\n\t\t\tdefaultMode: *420 |
|
||||
int\n\t\t\tcmName: string\n\t\t\titems?: [...{\n\t\t\t\tkey: string\n\t\t\t\tpath:
|
||||
string\n\t\t\t\tmode: *511 | int\n\t\t\t}]\n\t\t}]\n\t\t// +usage=Mount
|
||||
Secret type volume\n\t\tsecret?: [...{\n\t\t\tname: string\n\t\t\tmountPath:
|
||||
\ string\n\t\t\tdefaultMode: *420 | int\n\t\t\tsecretName: string\n\t\t\titems?:
|
||||
[...{\n\t\t\t\tkey: string\n\t\t\t\tpath: string\n\t\t\t\tmode: *511
|
||||
| int\n\t\t\t}]\n\t\t}]\n\t\t// +usage=Mount EmptyDir type volume\n\t\temptyDir?:
|
||||
[...{\n\t\t\tname: string\n\t\t\tmountPath: string\n\t\t\tmedium:
|
||||
\ *\"\" | \"Memory\"\n\t\t}]\n\t\t// +usage=Mount HostPath type volume\n\t\thostPath?:
|
||||
[...{\n\t\t\tname: string\n\t\t\tmountPath: string\n\t\t\tpath:
|
||||
\ string\n\t\t}]\n\t}\n\n\t// +usage=Deprecated field, use volumeMounts
|
||||
instead.\n\tvolumes?: [...{\n\t\tname: string\n\t\tmountPath: string\n\t\t//
|
||||
+usage=Specify volume type, options: \"pvc\",\"configMap\",\"secret\",\"emptyDir\"\n\t\ttype:
|
||||
\"pvc\" | \"configMap\" | \"secret\" | \"emptyDir\"\n\t\tif type ==
|
||||
\"pvc\" {\n\t\t\tclaimName: string\n\t\t}\n\t\tif type == \"configMap\"
|
||||
{\n\t\t\tdefaultMode: *420 | int\n\t\t\tcmName: string\n\t\t\titems?:
|
||||
[...{\n\t\t\t\tkey: string\n\t\t\t\tpath: string\n\t\t\t\tmode: *511
|
||||
| int\n\t\t\t}]\n\t\t}\n\t\tif type == \"secret\" {\n\t\t\tdefaultMode:
|
||||
*420 | int\n\t\t\tsecretName: string\n\t\t\titems?: [...{\n\t\t\t\tkey:
|
||||
\ string\n\t\t\t\tpath: string\n\t\t\t\tmode: *511 | int\n\t\t\t}]\n\t\t}\n\t\tif
|
||||
type == \"emptyDir\" {\n\t\t\tmedium: *\"\" | \"Memory\"\n\t\t}\n\t}]\n\n\t//
|
||||
+usage=Instructions for assessing whether the container is alive.\n\tlivenessProbe?:
|
||||
#HealthProbe\n\n\t// +usage=Instructions for assessing whether the container
|
||||
is in a suitable state to serve traffic.\n\treadinessProbe?: #HealthProbe\n\n\t//
|
||||
+usage=Specify the hostAliases to add\n\thostAliases?: [...{\n\t\tip:
|
||||
string\n\t\thostnames: [...string]\n\t}]\n}\n#HealthProbe: {\n\n\t//
|
||||
+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.\n\texec?: {\n\t\t// +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.\n\t\tcommand: [...string]\n\t}\n\n\t//
|
||||
+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.\n\thttpGet?: {\n\t\t//
|
||||
+usage=The endpoint, relative to the port, to which the HTTP GET request
|
||||
should be directed.\n\t\tpath: string\n\t\t// +usage=The TCP socket
|
||||
within the container to which the HTTP GET request should be directed.\n\t\tport:
|
||||
int\n\t\thttpHeaders?: [...{\n\t\t\tname: string\n\t\t\tvalue: string\n\t\t}]\n\t}\n\n\t//
|
||||
+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.\n\ttcpSocket?: {\n\t\t// +usage=The
|
||||
TCP socket within the container that should be probed to assess container
|
||||
health.\n\t\tport: int\n\t}\n\n\t// +usage=Number of seconds after the
|
||||
container is started before the first probe is initiated.\n\tinitialDelaySeconds:
|
||||
*0 | int\n\n\t// +usage=How often, in seconds, to execute the probe.\n\tperiodSeconds:
|
||||
*10 | int\n\n\t// +usage=Number of seconds after which the probe times
|
||||
out.\n\ttimeoutSeconds: *1 | int\n\n\t// +usage=Minimum consecutive
|
||||
successes for the probe to be considered successful after having failed.\n\tsuccessThreshold:
|
||||
*1 | int\n\n\t// +usage=Number of consecutive failures required to determine
|
||||
the container is not alive (liveness probe) or not ready (readiness
|
||||
probe).\n\tfailureThreshold: *3 | int\n}\n"
|
||||
status:
|
||||
customStatus: "ready: {\n\treadyReplicas: *0 | int\n} & {\n\tif context.output.status.readyReplicas
|
||||
!= _|_ {\n\t\treadyReplicas: context.output.status.readyReplicas\n\t}\n}\nmessage:
|
||||
\"Ready:\\(ready.readyReplicas)/\\(context.output.spec.replicas)\""
|
||||
healthPolicy: "ready: {\n\tupdatedReplicas: *0 | int\n\treadyReplicas:
|
||||
\ *0 | int\n\treplicas: *0 | int\n\tobservedGeneration:
|
||||
*0 | int\n} & {\n\tif context.output.status.updatedReplicas != _|_ {\n\t\tupdatedReplicas:
|
||||
context.output.status.updatedReplicas\n\t}\n\tif context.output.status.readyReplicas
|
||||
!= _|_ {\n\t\treadyReplicas: context.output.status.readyReplicas\n\t}\n\tif
|
||||
context.output.status.replicas != _|_ {\n\t\treplicas: context.output.status.replicas\n\t}\n\tif
|
||||
context.output.status.observedGeneration != _|_ {\n\t\tobservedGeneration:
|
||||
context.output.status.observedGeneration\n\t}\n}\nisHealth: (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)"
|
||||
workload:
|
||||
definition:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
type: deployments.apps
|
||||
status: {}
|
||||
traitDefinitions:
|
||||
scaler:
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Manually scale K8s pod for your workload
|
||||
which follows the pod spec in path 'spec.template'.
|
||||
meta.helm.sh/release-name: kubevela
|
||||
meta.helm.sh/release-namespace: vela-system
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
name: scaler
|
||||
namespace: vela-system
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
definitionRef:
|
||||
name: ""
|
||||
schematic:
|
||||
cue:
|
||||
template: "parameter: {\n\t// +usage=Specify the number of workload\n\treplicas:
|
||||
*1 | int\n}\n// +patchStrategy=retainKeys\npatch: spec: replicas: parameter.replicas\n"
|
||||
status: {}
|
||||
status: {}
|
||||
19
pkg/appfile/testdata/backport-1-2/wsd.yaml
vendored
Normal file
19
pkg/appfile/testdata/backport-1-2/wsd.yaml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: WorkflowStepDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Apply application for your workflow steps
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: apply-application
|
||||
namespace: vela-system
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
import (
|
||||
"vela/op"
|
||||
)
|
||||
|
||||
// apply application
|
||||
output: op.#ApplyApplication & {}
|
||||
@@ -51,7 +51,7 @@ func (c *HTTPCmd) Run(meta *registry.Meta) (res interface{}, err error) {
|
||||
var (
|
||||
r io.Reader
|
||||
client = &http.Client{
|
||||
Transport: &http.Transport{},
|
||||
Transport: http.DefaultTransport,
|
||||
Timeout: time.Second * 3,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
openapi "github.com/alibabacloud-go/darabonba-openapi/client"
|
||||
"github.com/alibabacloud-go/tea/tea"
|
||||
types "github.com/oam-dev/terraform-controller/api/types/crossplane-runtime"
|
||||
v1beta12 "github.com/oam-dev/terraform-controller/api/v1beta1"
|
||||
v1beta12 "github.com/oam-dev/terraform-controller/api/v1beta2"
|
||||
"github.com/pkg/errors"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
@@ -18,8 +18,9 @@ package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
"k8s.io/kubectl/pkg/util/term"
|
||||
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/cmd/util"
|
||||
)
|
||||
|
||||
// Builder build command with factory
|
||||
|
||||
@@ -17,8 +17,9 @@ limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/cmd/util"
|
||||
)
|
||||
|
||||
// Factory client factory for running command
|
||||
|
||||
32
pkg/cmd/util/helpers.go
Normal file
32
pkg/cmd/util/helpers.go
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
Copyright 2022 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 util
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
)
|
||||
|
||||
// CheckErr wraps the kubectl CheckErr func by preventing inappropriate type conversion and panic
|
||||
func CheckErr(err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
cmdutil.CheckErr(errors.New(err.Error()))
|
||||
}
|
||||
}()
|
||||
cmdutil.CheckErr(err)
|
||||
}
|
||||
@@ -18,9 +18,9 @@ package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/cmd/util"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/env"
|
||||
)
|
||||
|
||||
@@ -86,4 +86,7 @@ type Args struct {
|
||||
|
||||
// IgnoreAppWithoutControllerRequirement indicates that application controller will not process the app without 'app.oam.dev/controller-version-require' annotation.
|
||||
IgnoreAppWithoutControllerRequirement bool
|
||||
|
||||
// IgnoreDefinitionWithoutControllerRequirement indicates that trait/component/workflowstep definition controller will not process the definition without 'definition.oam.dev/controller-version-require' annotation.
|
||||
IgnoreDefinitionWithoutControllerRequirement bool
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
|
||||
if annotations := app.GetAnnotations(); annotations == nil || annotations[oam.AnnotationKubeVelaVersion] == "" {
|
||||
metav1.SetMetaDataAnnotation(&app.ObjectMeta, oam.AnnotationKubeVelaVersion, version.VelaVersion)
|
||||
}
|
||||
logCtx.AddTag("publish_version", app.GetAnnotations()[oam.AnnotationKubeVelaVersion])
|
||||
logCtx.AddTag("publish_version", app.GetAnnotations()[oam.AnnotationPublishVersion])
|
||||
|
||||
appParser := appfile.NewApplicationParser(r.Client, r.dm, r.pd)
|
||||
handler, err := NewAppHandler(logCtx, r, app, appParser)
|
||||
|
||||
@@ -292,35 +292,6 @@ var _ = Describe("Test Application Controller", func() {
|
||||
},
|
||||
}
|
||||
|
||||
appWithMountToEnvs := &v1beta1.Application{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Application",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app-with-mount-to-envs",
|
||||
},
|
||||
Spec: v1beta1.ApplicationSpec{
|
||||
Components: []common.ApplicationComponent{
|
||||
{
|
||||
Name: "myweb",
|
||||
Type: "worker",
|
||||
Properties: &runtime.RawExtension{Raw: []byte("{\"cmd\":[\"sleep\",\"1000\"],\"image\":\"busybox\"}")},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
appWithMountToEnvs.Spec.Components[0].Traits = []common.ApplicationTrait{
|
||||
{
|
||||
Type: "storage",
|
||||
Properties: &runtime.RawExtension{Raw: []byte("{\"secret\": [{\"name\": \"myweb-secret\",\"mountToEnv\": {\"envName\": \"firstEnv\",\"secretKey\": \"firstKey\"},\"mountToEnvs\": [{\"envName\": \"secondEnv\",\"secretKey\": \"secondKey\"}],\"data\": {\"firstKey\": \"dmFsdWUwMQo=\",\"secondKey\": \"dmFsdWUwMgo=\"}}]}")},
|
||||
},
|
||||
{
|
||||
Type: "storage",
|
||||
Properties: &runtime.RawExtension{Raw: []byte("{\"configMap\": [{\"name\": \"myweb-cm\",\"mountToEnvs\": [{\"envName\":\"thirdEnv\",\"configMapKey\":\"thirdKey\"},{\"envName\":\"fourthEnv\",\"configMapKey\":\"fourthKey\"}],\"data\": {\"thirdKey\": \"Value03\",\"fourthKey\": \"Value04\"}}]}")},
|
||||
},
|
||||
}
|
||||
|
||||
cd := &v1beta1.ComponentDefinition{}
|
||||
cDDefJson, _ := yaml.YAMLToJSON([]byte(componentDefYaml))
|
||||
k8sObjectsCDJson, _ := yaml.YAMLToJSON([]byte(k8sObjectsComponentDefinitionYaml))
|
||||
@@ -2597,66 +2568,6 @@ var _ = Describe("Test Application Controller", func() {
|
||||
Expect(k8sClient.Delete(ctx, secret)).Should(BeNil())
|
||||
Expect(k8sClient.Delete(ctx, app)).Should(BeNil())
|
||||
})
|
||||
|
||||
It("test application with multi-mountToEnv will create application", func() {
|
||||
|
||||
ns := &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app-with-mount-to-envs",
|
||||
},
|
||||
}
|
||||
Expect(k8sClient.Create(ctx, ns)).Should(BeNil())
|
||||
|
||||
appWithMountToEnvs.SetNamespace(ns.Name)
|
||||
app := appWithMountToEnvs.DeepCopy()
|
||||
Expect(k8sClient.Create(ctx, app)).Should(BeNil())
|
||||
|
||||
appKey := client.ObjectKey{
|
||||
Name: app.Name,
|
||||
Namespace: app.Namespace,
|
||||
}
|
||||
testutil.ReconcileOnceAfterFinalizer(reconciler, reconcile.Request{NamespacedName: appKey})
|
||||
|
||||
By("Check App running successfully")
|
||||
curApp := &v1beta1.Application{}
|
||||
Expect(k8sClient.Get(ctx, appKey, curApp)).Should(BeNil())
|
||||
Expect(curApp.Status.Phase).Should(Equal(common.ApplicationRunning))
|
||||
|
||||
appRevision := &v1beta1.ApplicationRevision{}
|
||||
Expect(k8sClient.Get(ctx, client.ObjectKey{
|
||||
Namespace: app.Namespace,
|
||||
Name: curApp.Status.LatestRevision.Name,
|
||||
}, appRevision)).Should(BeNil())
|
||||
By("Check affiliated resource tracker is created")
|
||||
expectRTName := fmt.Sprintf("%s-%s", appRevision.GetName(), appRevision.GetNamespace())
|
||||
Eventually(func() error {
|
||||
return k8sClient.Get(ctx, client.ObjectKey{Name: expectRTName}, &v1beta1.ResourceTracker{})
|
||||
}, 10*time.Second, 500*time.Millisecond).Should(Succeed())
|
||||
|
||||
By("Check AppRevision Created with the expected workload spec")
|
||||
appRev := &v1beta1.ApplicationRevision{}
|
||||
Eventually(func() error {
|
||||
return k8sClient.Get(ctx, client.ObjectKey{Name: app.Name + "-v1", Namespace: app.GetNamespace()}, appRev)
|
||||
}, 10*time.Second, 500*time.Millisecond).Should(Succeed())
|
||||
|
||||
By("Check secret Created with the expected trait-storage spec")
|
||||
secret := &corev1.Secret{}
|
||||
Expect(k8sClient.Get(ctx, client.ObjectKey{
|
||||
Namespace: ns.Name,
|
||||
Name: app.Spec.Components[0].Name + "-secret",
|
||||
}, secret)).Should(BeNil())
|
||||
|
||||
By("Check configMap Created with the expected trait-storage spec")
|
||||
cm := &corev1.ConfigMap{}
|
||||
Expect(k8sClient.Get(ctx, client.ObjectKey{
|
||||
Namespace: ns.Name,
|
||||
Name: app.Spec.Components[0].Name + "-cm",
|
||||
}, cm)).Should(BeNil())
|
||||
|
||||
Expect(k8sClient.Delete(ctx, cm)).Should(BeNil())
|
||||
Expect(k8sClient.Delete(ctx, secret)).Should(BeNil())
|
||||
Expect(k8sClient.Delete(ctx, app)).Should(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
const (
|
||||
@@ -3693,17 +3604,6 @@ spec:
|
||||
}
|
||||
},
|
||||
] | []
|
||||
configMapMountToEnvsList: *[
|
||||
for v in parameter.configMap if v.mountToEnvs != _|_ for k in v.mountToEnvs {
|
||||
{
|
||||
name: k.envName
|
||||
valueFrom: configMapKeyRef: {
|
||||
name: v.name
|
||||
key: k.configMapKey
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
secretVolumeMountsList: *[
|
||||
for v in parameter.secret if v.mountPath != _|_ {
|
||||
{
|
||||
@@ -3723,17 +3623,6 @@ spec:
|
||||
}
|
||||
},
|
||||
] | []
|
||||
secretMountToEnvsList: *[
|
||||
for v in parameter.secret if v.mountToEnvs != _|_ for k in v.mountToEnvs {
|
||||
{
|
||||
name: k.envName
|
||||
valueFrom: secretKeyRef: {
|
||||
name: v.name
|
||||
key: k.secretKey
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
emptyDirVolumeMountsList: *[
|
||||
for v in parameter.emptyDir {
|
||||
{
|
||||
@@ -3756,7 +3645,7 @@ spec:
|
||||
|
||||
containers: [{
|
||||
// +patchKey=name
|
||||
env: configMapEnvMountsList + secretEnvMountsList + configMapMountToEnvsList + secretMountToEnvsList
|
||||
env: configMapEnvMountsList + secretEnvMountsList
|
||||
// +patchKey=name
|
||||
volumeDevices: volumeDevicesList
|
||||
// +patchKey=name
|
||||
@@ -3876,10 +3765,6 @@ spec:
|
||||
envName: string
|
||||
configMapKey: string
|
||||
}
|
||||
mountToEnvs?: [...{
|
||||
envName: string
|
||||
configMapKey: string
|
||||
}]
|
||||
mountPath?: string
|
||||
defaultMode: *420 | int
|
||||
readOnly: *false | bool
|
||||
@@ -3899,10 +3784,6 @@ spec:
|
||||
envName: string
|
||||
secretKey: string
|
||||
}
|
||||
mountToEnvs?: [...{
|
||||
envName: string
|
||||
secretKey: string
|
||||
}]
|
||||
mountPath?: string
|
||||
defaultMode: *420 | int
|
||||
readOnly: *false | bool
|
||||
@@ -4016,7 +3897,7 @@ spec:
|
||||
}]
|
||||
}
|
||||
}
|
||||
parameter: #PatchParams | close({
|
||||
parameter: *#PatchParams | close({
|
||||
// +usage=Specify the environment variables for multiple containers
|
||||
containers: [...#PatchParams]
|
||||
})
|
||||
|
||||
@@ -21,9 +21,11 @@ import (
|
||||
"sync"
|
||||
|
||||
terraformtypes "github.com/oam-dev/terraform-controller/api/types"
|
||||
terraformapi "github.com/oam-dev/terraform-controller/api/v1beta1"
|
||||
terraforv1beta1 "github.com/oam-dev/terraform-controller/api/v1beta1"
|
||||
terraforv1beta2 "github.com/oam-dev/terraform-controller/api/v1beta2"
|
||||
"github.com/pkg/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
@@ -32,11 +34,10 @@ import (
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/appfile"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
|
||||
monitorContext "github.com/oam-dev/kubevela/pkg/monitor/context"
|
||||
"github.com/oam-dev/kubevela/pkg/monitor/metrics"
|
||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/resourcekeeper"
|
||||
)
|
||||
|
||||
@@ -229,34 +230,22 @@ func (h *AppHandler) collectHealthStatus(ctx context.Context, wl *appfile.Worklo
|
||||
)
|
||||
|
||||
if wl.CapabilityCategory == types.TerraformCategory {
|
||||
var configuration terraformapi.Configuration
|
||||
var configuration terraforv1beta2.Configuration
|
||||
if err := h.r.Client.Get(ctx, client.ObjectKey{Name: wl.Name, Namespace: namespace}, &configuration); err != nil {
|
||||
return nil, false, errors.WithMessagef(err, "app=%s, comp=%s, check health error", appName, wl.Name)
|
||||
}
|
||||
|
||||
isLatest := func() bool {
|
||||
if configuration.Status.ObservedGeneration != 0 {
|
||||
if configuration.Status.ObservedGeneration != configuration.Generation {
|
||||
return false
|
||||
if kerrors.IsNotFound(err) {
|
||||
var legacyConfiguration terraforv1beta1.Configuration
|
||||
if err := h.r.Client.Get(ctx, client.ObjectKey{Name: wl.Name, Namespace: namespace}, &legacyConfiguration); err != nil {
|
||||
return nil, false, errors.WithMessagef(err, "app=%s, comp=%s, check health error", appName, wl.Name)
|
||||
}
|
||||
isHealth = setStatus(&status, legacyConfiguration.Status.ObservedGeneration, legacyConfiguration.Generation,
|
||||
legacyConfiguration.GetLabels(), appRev.Name, legacyConfiguration.Status.Apply.State, legacyConfiguration.Status.Apply.Message)
|
||||
} else {
|
||||
return nil, false, errors.WithMessagef(err, "app=%s, comp=%s, check health error", appName, wl.Name)
|
||||
}
|
||||
// Use AppRevision to avoid getting the configuration before the patch.
|
||||
if v, ok := configuration.GetLabels()[oam.LabelAppRevision]; ok {
|
||||
if v != appRev.Name {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
if !isLatest() || configuration.Status.Apply.State != terraformtypes.Available {
|
||||
status.Healthy = false
|
||||
isHealth = false
|
||||
} else {
|
||||
status.Healthy = true
|
||||
isHealth = true
|
||||
isHealth = setStatus(&status, configuration.Status.ObservedGeneration, configuration.Generation, configuration.GetLabels(),
|
||||
appRev.Name, configuration.Status.Apply.State, configuration.Status.Apply.Message)
|
||||
}
|
||||
status.Message = configuration.Status.Apply.Message
|
||||
} else {
|
||||
if ok, err := wl.EvalHealth(wl.Ctx, h.r.Client, namespace); !ok || err != nil {
|
||||
isHealth = false
|
||||
@@ -292,6 +281,29 @@ func (h *AppHandler) collectHealthStatus(ctx context.Context, wl *appfile.Worklo
|
||||
return &status, isHealth, nil
|
||||
}
|
||||
|
||||
func setStatus(status *common.ApplicationComponentStatus, observedGeneration, generation int64, labels map[string]string,
|
||||
appRevName string, state terraformtypes.ConfigurationState, message string) bool {
|
||||
isLatest := func() bool {
|
||||
if observedGeneration != 0 && observedGeneration != generation {
|
||||
return false
|
||||
}
|
||||
// Use AppRevision to avoid getting the configuration before the patch.
|
||||
if v, ok := labels[oam.LabelAppRevision]; ok {
|
||||
if v != appRevName {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
if !isLatest() || state != terraformtypes.Available {
|
||||
status.Healthy = false
|
||||
return false
|
||||
}
|
||||
status.Healthy = true
|
||||
status.Message = message
|
||||
return true
|
||||
}
|
||||
|
||||
func generateScopeReference(scopes []appfile.Scope) []corev1.ObjectReference {
|
||||
var references []corev1.ObjectReference
|
||||
for _, scope := range scopes {
|
||||
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/oam/testutil"
|
||||
|
||||
terraformtypes "github.com/oam-dev/terraform-controller/api/types"
|
||||
terraformapi "github.com/oam-dev/terraform-controller/api/v1beta1"
|
||||
terraformapi "github.com/oam-dev/terraform-controller/api/v1beta2"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
@@ -343,7 +343,7 @@ var _ = Describe("Test Application health check", func() {
|
||||
Spec: v1beta1.ComponentDefinitionSpec{
|
||||
Workload: common.WorkloadTypeDescriptor{
|
||||
Definition: common.WorkloadGVK{
|
||||
APIVersion: "terraform.core.oam.dev/v1beta1",
|
||||
APIVersion: "terraform.core.oam.dev/v1beta2",
|
||||
Kind: "Configuration",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -117,8 +117,16 @@ func convertStepProperties(step *v1beta1.WorkflowStep, app *v1beta1.Application)
|
||||
return err
|
||||
}
|
||||
|
||||
var componentNames []string
|
||||
for _, c := range app.Spec.Components {
|
||||
componentNames = append(componentNames, c.Name)
|
||||
}
|
||||
|
||||
for _, c := range app.Spec.Components {
|
||||
if c.Name == o.Component {
|
||||
if dcName, ok := checkDependsOnValidComponent(c.DependsOn, componentNames); !ok {
|
||||
return errors.Errorf("component %s not found, which is depended by %s", dcName, c.Name)
|
||||
}
|
||||
step.Inputs = append(step.Inputs, c.Inputs...)
|
||||
for index := range step.Inputs {
|
||||
parameterKey := strings.TrimSpace(step.Inputs[index].ParameterKey)
|
||||
@@ -135,11 +143,23 @@ func convertStepProperties(step *v1beta1.WorkflowStep, app *v1beta1.Application)
|
||||
step.Properties = util.Object2RawExtension(c)
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
return errors.Errorf("component %s not found", o.Component)
|
||||
}
|
||||
|
||||
func checkDependsOnValidComponent(dependsOnComponentNames, allComponentNames []string) (string, bool) {
|
||||
// does not depends on other components
|
||||
if dependsOnComponentNames == nil {
|
||||
return "", true
|
||||
}
|
||||
for _, dc := range dependsOnComponentNames {
|
||||
if !utils.StringsContain(allComponentNames, dc) {
|
||||
return dc, false
|
||||
}
|
||||
}
|
||||
return "", true
|
||||
}
|
||||
|
||||
func (h *AppHandler) renderComponentFunc(appParser *appfile.Parser, appRev *v1beta1.ApplicationRevision, af *appfile.Appfile) oamProvider.ComponentRender {
|
||||
return func(comp common.ApplicationComponent, patcher *value.Value, clusterName string, overrideNamespace string, env string) (*unstructured.Unstructured, []*unstructured.Unstructured, error) {
|
||||
ctx := multicluster.ContextWithClusterName(context.Background(), clusterName)
|
||||
|
||||
@@ -240,4 +240,118 @@ var _ = Describe("Test Application workflow generator", func() {
|
||||
_, _, err = renderFunc(comp, nil, "", "", "")
|
||||
Expect(err).Should(BeNil())
|
||||
})
|
||||
|
||||
It("Test generate application workflow with dependsOn", func() {
|
||||
app := &oamcore.Application{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Application",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app-with-input-output",
|
||||
Namespace: namespaceName,
|
||||
},
|
||||
Spec: oamcore.ApplicationSpec{
|
||||
Components: []common.ApplicationComponent{
|
||||
{
|
||||
Name: "myweb1",
|
||||
Type: "worker-with-health",
|
||||
Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)},
|
||||
},
|
||||
{
|
||||
Name: "myweb2",
|
||||
Type: "worker-with-health",
|
||||
DependsOn: []string{"myweb1"},
|
||||
Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox","lives": "i am lives","enemies": "empty"}`)},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
af, err := appParser.GenerateAppFile(ctx, app)
|
||||
Expect(err).Should(BeNil())
|
||||
appRev := &oamcore.ApplicationRevision{}
|
||||
|
||||
handler, err := NewAppHandler(ctx, reconciler, app, appParser)
|
||||
Expect(err).Should(Succeed())
|
||||
|
||||
taskRunner, err := handler.GenerateApplicationSteps(ctx, app, appParser, af, appRev)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(len(taskRunner)).Should(BeEquivalentTo(2))
|
||||
Expect(taskRunner[0].Name()).Should(BeEquivalentTo("myweb1"))
|
||||
Expect(taskRunner[1].Name()).Should(BeEquivalentTo("myweb2"))
|
||||
})
|
||||
|
||||
It("Test generate application workflow with invalid dependsOn", func() {
|
||||
app := &oamcore.Application{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Application",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app-with-input-output",
|
||||
Namespace: namespaceName,
|
||||
},
|
||||
Spec: oamcore.ApplicationSpec{
|
||||
Components: []common.ApplicationComponent{
|
||||
{
|
||||
Name: "myweb1",
|
||||
Type: "worker-with-health",
|
||||
Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)},
|
||||
},
|
||||
{
|
||||
Name: "myweb2",
|
||||
Type: "worker-with-health",
|
||||
DependsOn: []string{"myweb0"},
|
||||
Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox","lives": "i am lives","enemies": "empty"}`)},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
af, err := appParser.GenerateAppFile(ctx, app)
|
||||
Expect(err).Should(BeNil())
|
||||
appRev := &oamcore.ApplicationRevision{}
|
||||
|
||||
handler, err := NewAppHandler(ctx, reconciler, app, appParser)
|
||||
Expect(err).Should(Succeed())
|
||||
|
||||
_, err = handler.GenerateApplicationSteps(ctx, app, appParser, af, appRev)
|
||||
Expect(err).NotTo(BeNil())
|
||||
})
|
||||
|
||||
It("Test generate application workflow with multiple invalid dependsOn", func() {
|
||||
app := &oamcore.Application{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Application",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app-with-input-output",
|
||||
Namespace: namespaceName,
|
||||
},
|
||||
Spec: oamcore.ApplicationSpec{
|
||||
Components: []common.ApplicationComponent{
|
||||
{
|
||||
Name: "myweb1",
|
||||
Type: "worker-with-health",
|
||||
Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)},
|
||||
},
|
||||
{
|
||||
Name: "myweb2",
|
||||
Type: "worker-with-health",
|
||||
DependsOn: []string{"myweb1", "myweb0", "myweb3"},
|
||||
Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox","lives": "i am lives","enemies": "empty"}`)},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
af, err := appParser.GenerateAppFile(ctx, app)
|
||||
Expect(err).Should(BeNil())
|
||||
appRev := &oamcore.ApplicationRevision{}
|
||||
|
||||
handler, err := NewAppHandler(ctx, reconciler, app, appParser)
|
||||
Expect(err).Should(Succeed())
|
||||
|
||||
_, err = handler.GenerateApplicationSteps(ctx, app, appParser, af, appRev)
|
||||
Expect(err).NotTo(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
@@ -410,10 +410,12 @@ func (h *AppHandler) currentAppRevIsNew(ctx context.Context) (bool, bool, error)
|
||||
if isLatestRev {
|
||||
appSpec := h.currentAppRev.Spec.Application.Spec
|
||||
traitDef := h.currentAppRev.Spec.TraitDefinitions
|
||||
workflowStepDef := h.currentAppRev.Spec.WorkflowStepDefinitions
|
||||
h.currentAppRev = h.latestAppRev.DeepCopy()
|
||||
h.currentRevHash = h.app.Status.LatestRevision.RevisionHash
|
||||
h.currentAppRev.Spec.Application.Spec = appSpec
|
||||
h.currentAppRev.Spec.TraitDefinitions = traitDef
|
||||
h.currentAppRev.Spec.WorkflowStepDefinitions = workflowStepDef
|
||||
return false, false, nil
|
||||
}
|
||||
|
||||
@@ -755,6 +757,7 @@ func (h *AppHandler) FinalizeAndApplyAppRevision(ctx context.Context) error {
|
||||
appRev.SetGroupVersionKind(v1beta1.ApplicationRevisionGroupVersionKind)
|
||||
// pass application's annotations & labels to app revision
|
||||
appRev.SetAnnotations(h.app.GetAnnotations())
|
||||
delete(appRev.Annotations, oam.AnnotationLastAppliedConfiguration)
|
||||
appRev.SetLabels(h.app.GetLabels())
|
||||
util.AddLabels(appRev, map[string]string{
|
||||
oam.LabelAppName: h.app.GetName(),
|
||||
|
||||
@@ -19,6 +19,8 @@ package application
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@@ -825,3 +827,347 @@ var _ = Describe("Test remove SkipAppRev func", func() {
|
||||
Expect(res.Components[0].Traits[1].Type).Should(BeEquivalentTo("service"))
|
||||
})
|
||||
})
|
||||
|
||||
var _ = Describe("Test PrepareCurrentAppRevision", func() {
|
||||
var app v1beta1.Application
|
||||
var apprev v1beta1.ApplicationRevision
|
||||
ctx := context.Background()
|
||||
var handler *AppHandler
|
||||
|
||||
BeforeEach(func() {
|
||||
// prepare ComponentDefinition
|
||||
var compd v1beta1.ComponentDefinition
|
||||
Expect(yaml.Unmarshal([]byte(componentDefYaml), &compd)).To(Succeed())
|
||||
Expect(k8sClient.Create(ctx, &compd)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
|
||||
|
||||
// prepare WorkflowStepDefinition
|
||||
wsdYaml := `
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: WorkflowStepDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Apply application for your workflow steps
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: apply-application
|
||||
namespace: vela-system
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
import (
|
||||
"vela/op"
|
||||
)
|
||||
|
||||
// apply application
|
||||
output: op.#ApplyApplication & {}
|
||||
`
|
||||
var wsd v1beta1.WorkflowStepDefinition
|
||||
Expect(yaml.Unmarshal([]byte(wsdYaml), &wsd)).To(Succeed())
|
||||
Expect(k8sClient.Create(ctx, &wsd)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
|
||||
|
||||
// prepare application and application revision
|
||||
appYaml := `
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: backport-1-2-test-demo
|
||||
namespace: default
|
||||
spec:
|
||||
components:
|
||||
- name: backport-1-2-test-demo
|
||||
properties:
|
||||
image: nginx
|
||||
type: worker
|
||||
workflow:
|
||||
steps:
|
||||
- name: apply
|
||||
type: apply-application
|
||||
status:
|
||||
latestRevision:
|
||||
name: backport-1-2-test-demo-v1
|
||||
revision: 1
|
||||
revisionHash: 38ddf4e721073703
|
||||
`
|
||||
Expect(yaml.Unmarshal([]byte(appYaml), &app)).To(Succeed())
|
||||
Expect(k8sClient.Create(ctx, &app)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
|
||||
|
||||
// prepare application revision
|
||||
apprevYaml := `
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ApplicationRevision
|
||||
metadata:
|
||||
name: backport-1-2-test-demo-v1
|
||||
namespace: default
|
||||
ownerReferences:
|
||||
- apiVersion: core.oam.dev/v1beta1
|
||||
controller: true
|
||||
kind: Application
|
||||
name: backport-1-2-test-demo
|
||||
uid: b69fab34-7058-412b-994d-1465a9421f06
|
||||
spec:
|
||||
application:
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: backport-1-2-test-demo
|
||||
namespace: default
|
||||
spec:
|
||||
components:
|
||||
- name: backport-1-2-test-demo
|
||||
properties:
|
||||
image: nginx
|
||||
type: worker
|
||||
status: {}
|
||||
componentDefinitions:
|
||||
webservice:
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Describes long-running, scalable, containerized
|
||||
services that have a stable network endpoint to receive external network
|
||||
traffic from customers.
|
||||
meta.helm.sh/release-name: kubevela
|
||||
meta.helm.sh/release-namespace: vela-system
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
name: webservice
|
||||
namespace: vela-system
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: "import (\n\t\"strconv\"\n)\n\nmountsArray: {\n\tpvc: *[\n\t\tfor
|
||||
v in parameter.volumeMounts.pvc {\n\t\t\t{\n\t\t\t\tmountPath: v.mountPath\n\t\t\t\tname:
|
||||
\ v.name\n\t\t\t}\n\t\t},\n\t] | []\n\n\tconfigMap: *[\n\t\t\tfor
|
||||
v in parameter.volumeMounts.configMap {\n\t\t\t{\n\t\t\t\tmountPath:
|
||||
v.mountPath\n\t\t\t\tname: v.name\n\t\t\t}\n\t\t},\n\t] | []\n\n\tsecret:
|
||||
*[\n\t\tfor v in parameter.volumeMounts.secret {\n\t\t\t{\n\t\t\t\tmountPath:
|
||||
v.mountPath\n\t\t\t\tname: v.name\n\t\t\t}\n\t\t},\n\t] | []\n\n\temptyDir:
|
||||
*[\n\t\t\tfor v in parameter.volumeMounts.emptyDir {\n\t\t\t{\n\t\t\t\tmountPath:
|
||||
v.mountPath\n\t\t\t\tname: v.name\n\t\t\t}\n\t\t},\n\t] | []\n\n\thostPath:
|
||||
*[\n\t\t\tfor v in parameter.volumeMounts.hostPath {\n\t\t\t{\n\t\t\t\tmountPath:
|
||||
v.mountPath\n\t\t\t\tname: v.name\n\t\t\t}\n\t\t},\n\t] | []\n}\nvolumesArray:
|
||||
{\n\tpvc: *[\n\t\tfor v in parameter.volumeMounts.pvc {\n\t\t\t{\n\t\t\t\tname:
|
||||
v.name\n\t\t\t\tpersistentVolumeClaim: claimName: v.claimName\n\t\t\t}\n\t\t},\n\t]
|
||||
| []\n\n\tconfigMap: *[\n\t\t\tfor v in parameter.volumeMounts.configMap
|
||||
{\n\t\t\t{\n\t\t\t\tname: v.name\n\t\t\t\tconfigMap: {\n\t\t\t\t\tdefaultMode:
|
||||
v.defaultMode\n\t\t\t\t\tname: v.cmName\n\t\t\t\t\tif v.items
|
||||
!= _|_ {\n\t\t\t\t\t\titems: v.items\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t]
|
||||
| []\n\n\tsecret: *[\n\t\tfor v in parameter.volumeMounts.secret {\n\t\t\t{\n\t\t\t\tname:
|
||||
v.name\n\t\t\t\tsecret: {\n\t\t\t\t\tdefaultMode: v.defaultMode\n\t\t\t\t\tsecretName:
|
||||
\ v.secretName\n\t\t\t\t\tif v.items != _|_ {\n\t\t\t\t\t\titems: v.items\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t]
|
||||
| []\n\n\temptyDir: *[\n\t\t\tfor v in parameter.volumeMounts.emptyDir
|
||||
{\n\t\t\t{\n\t\t\t\tname: v.name\n\t\t\t\temptyDir: medium: v.medium\n\t\t\t}\n\t\t},\n\t]
|
||||
| []\n\n\thostPath: *[\n\t\t\tfor v in parameter.volumeMounts.hostPath
|
||||
{\n\t\t\t{\n\t\t\t\tname: v.name\n\t\t\t\thostPath: path: v.path\n\t\t\t}\n\t\t},\n\t]
|
||||
| []\n}\noutput: {\n\tapiVersion: \"apps/v1\"\n\tkind: \"Deployment\"\n\tspec:
|
||||
{\n\t\tselector: matchLabels: \"app.oam.dev/component\": context.name\n\n\t\ttemplate:
|
||||
{\n\t\t\tmetadata: {\n\t\t\t\tlabels: {\n\t\t\t\t\tif parameter.labels
|
||||
!= _|_ {\n\t\t\t\t\t\tparameter.labels\n\t\t\t\t\t}\n\t\t\t\t\tif parameter.addRevisionLabel
|
||||
{\n\t\t\t\t\t\t\"app.oam.dev/revision\": context.revision\n\t\t\t\t\t}\n\t\t\t\t\t\"app.oam.dev/component\":
|
||||
context.name\n\t\t\t\t}\n\t\t\t\tif parameter.annotations != _|_ {\n\t\t\t\t\tannotations:
|
||||
parameter.annotations\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tspec: {\n\t\t\t\tcontainers:
|
||||
[{\n\t\t\t\t\tname: context.name\n\t\t\t\t\timage: parameter.image\n\t\t\t\t\tif
|
||||
parameter[\"port\"] != _|_ && parameter[\"ports\"] == _|_ {\n\t\t\t\t\t\tports:
|
||||
[{\n\t\t\t\t\t\t\tcontainerPort: parameter.port\n\t\t\t\t\t\t}]\n\t\t\t\t\t}\n\t\t\t\t\tif
|
||||
parameter[\"ports\"] != _|_ {\n\t\t\t\t\t\tports: [ for v in parameter.ports
|
||||
{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcontainerPort: v.port\n\t\t\t\t\t\t\t\tprotocol:
|
||||
\ v.protocol\n\t\t\t\t\t\t\t\tif v.name != _|_ {\n\t\t\t\t\t\t\t\t\tname:
|
||||
v.name\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif v.name == _|_ {\n\t\t\t\t\t\t\t\t\tname:
|
||||
\"port-\" + strconv.FormatInt(v.port, 10)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}}]\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"imagePullPolicy\"] != _|_ {\n\t\t\t\t\t\timagePullPolicy:
|
||||
parameter.imagePullPolicy\n\t\t\t\t\t}\n\n\t\t\t\t\tif parameter[\"cmd\"]
|
||||
!= _|_ {\n\t\t\t\t\t\tcommand: parameter.cmd\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"env\"] != _|_ {\n\t\t\t\t\t\tenv: parameter.env\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
context[\"config\"] != _|_ {\n\t\t\t\t\t\tenv: context.config\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"cpu\"] != _|_ {\n\t\t\t\t\t\tresources: {\n\t\t\t\t\t\t\tlimits:
|
||||
cpu: parameter.cpu\n\t\t\t\t\t\t\trequests: cpu: parameter.cpu\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"memory\"] != _|_ {\n\t\t\t\t\t\tresources: {\n\t\t\t\t\t\t\tlimits:
|
||||
memory: parameter.memory\n\t\t\t\t\t\t\trequests: memory: parameter.memory\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"volumes\"] != _|_ && parameter[\"volumeMounts\"] == _|_
|
||||
{\n\t\t\t\t\t\tvolumeMounts: [ for v in parameter.volumes {\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tmountPath:
|
||||
v.mountPath\n\t\t\t\t\t\t\t\tname: v.name\n\t\t\t\t\t\t\t}}]\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"volumeMounts\"] != _|_ {\n\t\t\t\t\t\tvolumeMounts: mountsArray.pvc
|
||||
+ mountsArray.configMap + mountsArray.secret + mountsArray.emptyDir
|
||||
+ mountsArray.hostPath\n\t\t\t\t\t}\n\n\t\t\t\t\tif parameter[\"livenessProbe\"]
|
||||
!= _|_ {\n\t\t\t\t\t\tlivenessProbe: parameter.livenessProbe\n\t\t\t\t\t}\n\n\t\t\t\t\tif
|
||||
parameter[\"readinessProbe\"] != _|_ {\n\t\t\t\t\t\treadinessProbe:
|
||||
parameter.readinessProbe\n\t\t\t\t\t}\n\n\t\t\t\t}]\n\n\t\t\t\tif parameter[\"hostAliases\"]
|
||||
!= _|_ {\n\t\t\t\t\t// +patchKey=ip\n\t\t\t\t\thostAliases: parameter.hostAliases\n\t\t\t\t}\n\n\t\t\t\tif
|
||||
parameter[\"imagePullSecrets\"] != _|_ {\n\t\t\t\t\timagePullSecrets:
|
||||
[ for v in parameter.imagePullSecrets {\n\t\t\t\t\t\tname: v\n\t\t\t\t\t},\n\t\t\t\t\t]\n\t\t\t\t}\n\n\t\t\t\tif
|
||||
parameter[\"volumes\"] != _|_ && parameter[\"volumeMounts\"] == _|_
|
||||
{\n\t\t\t\t\tvolumes: [ for v in parameter.volumes {\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tname:
|
||||
v.name\n\t\t\t\t\t\t\tif v.type == \"pvc\" {\n\t\t\t\t\t\t\t\tpersistentVolumeClaim:
|
||||
claimName: v.claimName\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif v.type ==
|
||||
\"configMap\" {\n\t\t\t\t\t\t\t\tconfigMap: {\n\t\t\t\t\t\t\t\t\tdefaultMode:
|
||||
v.defaultMode\n\t\t\t\t\t\t\t\t\tname: v.cmName\n\t\t\t\t\t\t\t\t\tif
|
||||
v.items != _|_ {\n\t\t\t\t\t\t\t\t\t\titems: v.items\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif
|
||||
v.type == \"secret\" {\n\t\t\t\t\t\t\t\tsecret: {\n\t\t\t\t\t\t\t\t\tdefaultMode:
|
||||
v.defaultMode\n\t\t\t\t\t\t\t\t\tsecretName: v.secretName\n\t\t\t\t\t\t\t\t\tif
|
||||
v.items != _|_ {\n\t\t\t\t\t\t\t\t\t\titems: v.items\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif
|
||||
v.type == \"emptyDir\" {\n\t\t\t\t\t\t\t\temptyDir: medium: v.medium\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}]\n\t\t\t\t}\n\n\t\t\t\tif
|
||||
parameter[\"volumeMounts\"] != _|_ {\n\t\t\t\t\tvolumes: volumesArray.pvc
|
||||
+ volumesArray.configMap + volumesArray.secret + volumesArray.emptyDir
|
||||
+ volumesArray.hostPath\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\nexposePorts:
|
||||
[\n\tfor v in parameter.ports if v.expose == true {\n\t\tport: v.port\n\t\ttargetPort:
|
||||
v.port\n\t\tif v.name != _|_ {\n\t\t\tname: v.name\n\t\t}\n\t\tif v.name
|
||||
== _|_ {\n\t\t\tname: \"port-\" + strconv.FormatInt(v.port, 10)\n\t\t}\n\t},\n]\noutputs:
|
||||
{\n\tif len(exposePorts) != 0 {\n\t\twebserviceExpose: {\n\t\t\tapiVersion:
|
||||
\"v1\"\n\t\t\tkind: \"Service\"\n\t\t\tmetadata: name: context.name\n\t\t\tspec:
|
||||
{\n\t\t\t\tselector: \"app.oam.dev/component\": context.name\n\t\t\t\tports:
|
||||
exposePorts\n\t\t\t\ttype: parameter.exposeType\n\t\t\t}\n\t\t}\n\t}\n}\nparameter:
|
||||
{\n\t// +usage=Specify the labels in the workload\n\tlabels?: [string]:
|
||||
string\n\n\t// +usage=Specify the annotations in the workload\n\tannotations?:
|
||||
[string]: string\n\n\t// +usage=Which image would you like to use for
|
||||
your service\n\t// +short=i\n\timage: string\n\n\t// +usage=Specify
|
||||
image pull policy for your service\n\timagePullPolicy?: \"Always\" |
|
||||
\"Never\" | \"IfNotPresent\"\n\n\t// +usage=Specify image pull secrets
|
||||
for your service\n\timagePullSecrets?: [...string]\n\n\t// +ignore\n\t//
|
||||
+usage=Deprecated field, please use ports instead\n\t// +short=p\n\tport?:
|
||||
int\n\n\t// +usage=Which ports do you want customer traffic sent to,
|
||||
defaults to 80\n\tports?: [...{\n\t\t// +usage=Number of port to expose
|
||||
on the pod's IP address\n\t\tport: int\n\t\t// +usage=Name of the port\n\t\tname?:
|
||||
string\n\t\t// +usage=Protocol for port. Must be UDP, TCP, or SCTP\n\t\tprotocol:
|
||||
*\"TCP\" | \"UDP\" | \"SCTP\"\n\t\t// +usage=Specify if the port should
|
||||
be exposed\n\t\texpose: *false | bool\n\t}]\n\n\t// +ignore\n\t// +usage=Specify
|
||||
what kind of Service you want. options: \"ClusterIP\", \"NodePort\",
|
||||
\"LoadBalancer\", \"ExternalName\"\n\texposeType: *\"ClusterIP\" | \"NodePort\"
|
||||
| \"LoadBalancer\" | \"ExternalName\"\n\n\t// +ignore\n\t// +usage=If
|
||||
addRevisionLabel is true, the revision label will be added to the underlying
|
||||
pods\n\taddRevisionLabel: *false | bool\n\n\t// +usage=Commands to run
|
||||
in the container\n\tcmd?: [...string]\n\n\t// +usage=Define arguments
|
||||
by using environment variables\n\tenv?: [...{\n\t\t// +usage=Environment
|
||||
variable name\n\t\tname: string\n\t\t// +usage=The value of the environment
|
||||
variable\n\t\tvalue?: string\n\t\t// +usage=Specifies a source the value
|
||||
of this var should come from\n\t\tvalueFrom?: {\n\t\t\t// +usage=Selects
|
||||
a key of a secret in the pod's namespace\n\t\t\tsecretKeyRef?: {\n\t\t\t\t//
|
||||
+usage=The name of the secret in the pod's namespace to select from\n\t\t\t\tname:
|
||||
string\n\t\t\t\t// +usage=The key of the secret to select from. Must
|
||||
be a valid secret key\n\t\t\t\tkey: string\n\t\t\t}\n\t\t\t// +usage=Selects
|
||||
a key of a config map in the pod's namespace\n\t\t\tconfigMapKeyRef?:
|
||||
{\n\t\t\t\t// +usage=The name of the config map in the pod's namespace
|
||||
to select from\n\t\t\t\tname: string\n\t\t\t\t// +usage=The key of the
|
||||
config map to select from. Must be a valid secret key\n\t\t\t\tkey:
|
||||
string\n\t\t\t}\n\t\t}\n\t}]\n\n\t// +usage=Number of CPU units for
|
||||
the service, like \n\tcpu?: string\n\n\t//
|
||||
+usage=Specifies the attributes of the memory resource required for
|
||||
the container.\n\tmemory?: string\n\n\tvolumeMounts?: {\n\t\t// +usage=Mount
|
||||
PVC type volume\n\t\tpvc?: [...{\n\t\t\tname: string\n\t\t\tmountPath:
|
||||
string\n\t\t\t// +usage=The name of the PVC\n\t\t\tclaimName: string\n\t\t}]\n\t\t//
|
||||
+usage=Mount ConfigMap type volume\n\t\tconfigMap?: [...{\n\t\t\tname:
|
||||
\ string\n\t\t\tmountPath: string\n\t\t\tdefaultMode: *420 |
|
||||
int\n\t\t\tcmName: string\n\t\t\titems?: [...{\n\t\t\t\tkey: string\n\t\t\t\tpath:
|
||||
string\n\t\t\t\tmode: *511 | int\n\t\t\t}]\n\t\t}]\n\t\t// +usage=Mount
|
||||
Secret type volume\n\t\tsecret?: [...{\n\t\t\tname: string\n\t\t\tmountPath:
|
||||
\ string\n\t\t\tdefaultMode: *420 | int\n\t\t\tsecretName: string\n\t\t\titems?:
|
||||
[...{\n\t\t\t\tkey: string\n\t\t\t\tpath: string\n\t\t\t\tmode: *511
|
||||
| int\n\t\t\t}]\n\t\t}]\n\t\t// +usage=Mount EmptyDir type volume\n\t\temptyDir?:
|
||||
[...{\n\t\t\tname: string\n\t\t\tmountPath: string\n\t\t\tmedium:
|
||||
\ *\"\" | \"Memory\"\n\t\t}]\n\t\t// +usage=Mount HostPath type volume\n\t\thostPath?:
|
||||
[...{\n\t\t\tname: string\n\t\t\tmountPath: string\n\t\t\tpath:
|
||||
\ string\n\t\t}]\n\t}\n\n\t// +usage=Deprecated field, use volumeMounts
|
||||
instead.\n\tvolumes?: [...{\n\t\tname: string\n\t\tmountPath: string\n\t\t//
|
||||
+usage=Specify volume type, options: \"pvc\",\"configMap\",\"secret\",\"emptyDir\"\n\t\ttype:
|
||||
\"pvc\" | \"configMap\" | \"secret\" | \"emptyDir\"\n\t\tif type ==
|
||||
\"pvc\" {\n\t\t\tclaimName: string\n\t\t}\n\t\tif type == \"configMap\"
|
||||
{\n\t\t\tdefaultMode: *420 | int\n\t\t\tcmName: string\n\t\t\titems?:
|
||||
[...{\n\t\t\t\tkey: string\n\t\t\t\tpath: string\n\t\t\t\tmode: *511
|
||||
| int\n\t\t\t}]\n\t\t}\n\t\tif type == \"secret\" {\n\t\t\tdefaultMode:
|
||||
*420 | int\n\t\t\tsecretName: string\n\t\t\titems?: [...{\n\t\t\t\tkey:
|
||||
\ string\n\t\t\t\tpath: string\n\t\t\t\tmode: *511 | int\n\t\t\t}]\n\t\t}\n\t\tif
|
||||
type == \"emptyDir\" {\n\t\t\tmedium: *\"\" | \"Memory\"\n\t\t}\n\t}]\n\n\t//
|
||||
+usage=Instructions for assessing whether the container is alive.\n\tlivenessProbe?:
|
||||
#HealthProbe\n\n\t// +usage=Instructions for assessing whether the container
|
||||
is in a suitable state to serve traffic.\n\treadinessProbe?: #HealthProbe\n\n\t//
|
||||
+usage=Specify the hostAliases to add\n\thostAliases?: [...{\n\t\tip:
|
||||
string\n\t\thostnames: [...string]\n\t}]\n}\n#HealthProbe: {\n\n\t//
|
||||
+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.\n\texec?: {\n\t\t// +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.\n\t\tcommand: [...string]\n\t}\n\n\t//
|
||||
+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.\n\thttpGet?: {\n\t\t//
|
||||
+usage=The endpoint, relative to the port, to which the HTTP GET request
|
||||
should be directed.\n\t\tpath: string\n\t\t// +usage=The TCP socket
|
||||
within the container to which the HTTP GET request should be directed.\n\t\tport:
|
||||
int\n\t\thttpHeaders?: [...{\n\t\t\tname: string\n\t\t\tvalue: string\n\t\t}]\n\t}\n\n\t//
|
||||
+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.\n\ttcpSocket?: {\n\t\t// +usage=The
|
||||
TCP socket within the container that should be probed to assess container
|
||||
health.\n\t\tport: int\n\t}\n\n\t// +usage=Number of seconds after the
|
||||
container is started before the first probe is initiated.\n\tinitialDelaySeconds:
|
||||
*0 | int\n\n\t// +usage=How often, in seconds, to execute the probe.\n\tperiodSeconds:
|
||||
*10 | int\n\n\t// +usage=Number of seconds after which the probe times
|
||||
out.\n\ttimeoutSeconds: *1 | int\n\n\t// +usage=Minimum consecutive
|
||||
successes for the probe to be considered successful after having failed.\n\tsuccessThreshold:
|
||||
*1 | int\n\n\t// +usage=Number of consecutive failures required to determine
|
||||
the container is not alive (liveness probe) or not ready (readiness
|
||||
probe).\n\tfailureThreshold: *3 | int\n}\n"
|
||||
status:
|
||||
customStatus: "ready: {\n\treadyReplicas: *0 | int\n} & {\n\tif context.output.status.readyReplicas
|
||||
!= _|_ {\n\t\treadyReplicas: context.output.status.readyReplicas\n\t}\n}\nmessage:
|
||||
\"Ready:\\(ready.readyReplicas)/\\(context.output.spec.replicas)\""
|
||||
healthPolicy: "ready: {\n\tupdatedReplicas: *0 | int\n\treadyReplicas:
|
||||
\ *0 | int\n\treplicas: *0 | int\n\tobservedGeneration:
|
||||
*0 | int\n} & {\n\tif context.output.status.updatedReplicas != _|_ {\n\t\tupdatedReplicas:
|
||||
context.output.status.updatedReplicas\n\t}\n\tif context.output.status.readyReplicas
|
||||
!= _|_ {\n\t\treadyReplicas: context.output.status.readyReplicas\n\t}\n\tif
|
||||
context.output.status.replicas != _|_ {\n\t\treplicas: context.output.status.replicas\n\t}\n\tif
|
||||
context.output.status.observedGeneration != _|_ {\n\t\tobservedGeneration:
|
||||
context.output.status.observedGeneration\n\t}\n}\nisHealth: (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)"
|
||||
workload:
|
||||
definition:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
type: deployments.apps
|
||||
status: {}
|
||||
status: {}
|
||||
`
|
||||
Expect(yaml.Unmarshal([]byte(apprevYaml), &apprev)).To(Succeed())
|
||||
// simulate 1.2 version that WorkflowStepDefinitions are not patched in appliacation revision
|
||||
apprev.ObjectMeta.OwnerReferences[0].UID = app.ObjectMeta.UID
|
||||
Expect(k8sClient.Create(ctx, &apprev)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
|
||||
|
||||
// prepare handler
|
||||
_handler, err := NewAppHandler(ctx, reconciler, &app, nil)
|
||||
Expect(err).Should(Succeed())
|
||||
handler = _handler
|
||||
|
||||
})
|
||||
|
||||
It("Test currentAppRevIsNew func", func() {
|
||||
By("Backport 1.2 version that WorkflowStepDefinitions are not patched to application revision")
|
||||
// generate appfile
|
||||
appfile, err := appfile.NewApplicationParser(reconciler.Client, reconciler.dm, reconciler.pd).GenerateAppFile(ctx, &app)
|
||||
ctx = util.SetNamespaceInCtx(ctx, app.Namespace)
|
||||
Expect(err).To(Succeed())
|
||||
Expect(handler.PrepareCurrentAppRevision(ctx, appfile)).Should(Succeed())
|
||||
|
||||
// prepare apprev
|
||||
thisWSD := handler.currentAppRev.Spec.WorkflowStepDefinitions
|
||||
Expect(len(thisWSD) > 0 && func() bool {
|
||||
expected := appfile.RelatedWorkflowStepDefinitions
|
||||
for i, w := range thisWSD {
|
||||
expW := *(expected[i])
|
||||
if !reflect.DeepEqual(w, expW) {
|
||||
fmt.Printf("appfile wsd:%s apprev wsd%s", w.Name, expW.Name)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}()).Should(BeTrue())
|
||||
})
|
||||
})
|
||||
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/event"
|
||||
"github.com/go-logr/logr"
|
||||
terraformv1beta1 "github.com/oam-dev/terraform-controller/api/v1beta1"
|
||||
terraformv1beta2 "github.com/oam-dev/terraform-controller/api/v1beta2"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/pkg/errors"
|
||||
@@ -121,7 +121,7 @@ var _ = BeforeSuite(func(done Done) {
|
||||
err = scheme.AddToScheme(testScheme)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
terraformv1beta1.AddToScheme(testScheme)
|
||||
terraformv1beta2.AddToScheme(testScheme)
|
||||
|
||||
crdv1.AddToScheme(testScheme)
|
||||
|
||||
|
||||
@@ -1,20 +1,11 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.2.5
|
||||
controller-gen.kubebuilder.io/version: v0.6.0
|
||||
creationTimestamp: null
|
||||
name: configurations.terraform.core.oam.dev
|
||||
spec:
|
||||
additionalPrinterColumns:
|
||||
- JSONPath: .status.state
|
||||
name: STATE
|
||||
type: string
|
||||
- JSONPath: .metadata.creationTimestamp
|
||||
name: AGE
|
||||
type: date
|
||||
group: terraform.core.oam.dev
|
||||
names:
|
||||
kind: Configuration
|
||||
@@ -22,96 +13,294 @@ spec:
|
||||
plural: configurations
|
||||
singular: configuration
|
||||
scope: Namespaced
|
||||
subresources:
|
||||
status: {}
|
||||
validation:
|
||||
openAPIV3Schema:
|
||||
description: Configuration is the Schema for the configurations API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: ConfigurationSpec defines the desired state of Configuration
|
||||
properties:
|
||||
JSON:
|
||||
description: JSON is the Terraform JSON syntax configuration
|
||||
type: string
|
||||
backend:
|
||||
description: Backend stores the state in a Kubernetes secret with locking
|
||||
done using a Lease resource. TODO(zzxwill) If a backend exists in
|
||||
HCL/JSON, this can be optional. Currently, if Backend is not set by
|
||||
users, it still will set by the controller, ignoring the settings
|
||||
in HCL/JSON backend
|
||||
properties:
|
||||
inClusterConfig:
|
||||
description: InClusterConfig Used to authenticate to the cluster
|
||||
from inside a pod. Only `true` is allowed
|
||||
type: boolean
|
||||
secretSuffix:
|
||||
description: 'SecretSuffix used when creating secrets. Secrets will
|
||||
be named in the format: tfstate-{workspace}-{secretSuffix}'
|
||||
type: string
|
||||
type: object
|
||||
hcl:
|
||||
description: HCL is the Terraform HCL type configuration
|
||||
type: string
|
||||
variable:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
writeConnectionSecretToRef:
|
||||
description: WriteConnectionSecretToReference specifies the namespace
|
||||
and name of a Secret to which any connection details for this managed
|
||||
resource should be written. Connection details frequently include
|
||||
the endpoint, username, and password required to connect to the managed
|
||||
resource.
|
||||
properties:
|
||||
name:
|
||||
description: Name of the secret.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace of the secret.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
type: object
|
||||
status:
|
||||
description: ConfigurationStatus defines the observed state of Configuration
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
outputs:
|
||||
additionalProperties:
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
value:
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
state:
|
||||
description: A ResourceState represents the status of a resource
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
version: v1beta1
|
||||
versions:
|
||||
- name: v1beta1
|
||||
served: true
|
||||
storage: true
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .status.apply.state
|
||||
name: STATE
|
||||
type: string
|
||||
- jsonPath: .metadata.creationTimestamp
|
||||
name: AGE
|
||||
type: date
|
||||
name: v1beta1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: Configuration is the Schema for the configurations API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: ConfigurationSpec defines the desired state of Configuration
|
||||
properties:
|
||||
JSON:
|
||||
description: 'JSON is the Terraform JSON syntax configuration. Deprecated:
|
||||
after v0.3.1, use HCL instead.'
|
||||
type: string
|
||||
backend:
|
||||
description: Backend stores the state in a Kubernetes secret with
|
||||
locking done using a Lease resource. TODO(zzxwill) If a backend
|
||||
exists in HCL/JSON, this can be optional. Currently, if Backend
|
||||
is not set by users, it still will set by the controller, ignoring
|
||||
the settings in HCL/JSON backend
|
||||
properties:
|
||||
inClusterConfig:
|
||||
description: InClusterConfig Used to authenticate to the cluster
|
||||
from inside a pod. Only `true` is allowed
|
||||
type: boolean
|
||||
secretSuffix:
|
||||
description: 'SecretSuffix used when creating secrets. Secrets
|
||||
will be named in the format: tfstate-{workspace}-{secretSuffix}'
|
||||
type: string
|
||||
type: object
|
||||
deleteResource:
|
||||
default: true
|
||||
description: DeleteResource will determine whether provisioned cloud
|
||||
resources will be deleted when CR is deleted
|
||||
type: boolean
|
||||
hcl:
|
||||
description: HCL is the Terraform HCL type configuration
|
||||
type: string
|
||||
path:
|
||||
description: Path is the sub-directory of remote git repository.
|
||||
type: string
|
||||
providerRef:
|
||||
description: ProviderReference specifies the reference to Provider
|
||||
properties:
|
||||
name:
|
||||
description: Name of the referenced object.
|
||||
type: string
|
||||
namespace:
|
||||
default: default
|
||||
description: Namespace of the referenced object.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
region:
|
||||
description: Region is cloud provider's region. It will override the
|
||||
region in the region field of ProviderReference
|
||||
type: string
|
||||
remote:
|
||||
description: Remote is a git repo which contains hcl files. Currently,
|
||||
only public git repos are supported.
|
||||
type: string
|
||||
variable:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
writeConnectionSecretToRef:
|
||||
description: WriteConnectionSecretToReference specifies the namespace
|
||||
and name of a Secret to which any connection details for this managed
|
||||
resource should be written. Connection details frequently include
|
||||
the endpoint, username, and password required to connect to the
|
||||
managed resource.
|
||||
properties:
|
||||
name:
|
||||
description: Name of the secret.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace of the secret.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
type: object
|
||||
status:
|
||||
description: ConfigurationStatus defines the observed state of Configuration
|
||||
properties:
|
||||
apply:
|
||||
description: ConfigurationApplyStatus is the status for Configuration
|
||||
apply
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
outputs:
|
||||
additionalProperties:
|
||||
description: Property is the property for an output
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
value:
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
state:
|
||||
description: A ConfigurationState represents the status of a resource
|
||||
type: string
|
||||
type: object
|
||||
destroy:
|
||||
description: ConfigurationDestroyStatus is the status for Configuration
|
||||
destroy
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
state:
|
||||
description: A ConfigurationState represents the status of a resource
|
||||
type: string
|
||||
type: object
|
||||
observedGeneration:
|
||||
description: observedGeneration is the most recent generation observed
|
||||
for this Configuration. It corresponds to the Configuration's generation,
|
||||
which is updated on mutation by the API Server.
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: false
|
||||
subresources:
|
||||
status: {}
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .status.apply.state
|
||||
name: STATE
|
||||
type: string
|
||||
- jsonPath: .metadata.creationTimestamp
|
||||
name: AGE
|
||||
type: date
|
||||
name: v1beta2
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: Configuration is the Schema for the configurations API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: ConfigurationSpec defines the desired state of Configuration
|
||||
properties:
|
||||
backend:
|
||||
description: Backend stores the state in a Kubernetes secret with
|
||||
locking done using a Lease resource. TODO(zzxwill) If a backend
|
||||
exists in HCL/JSON, this can be optional. Currently, if Backend
|
||||
is not set by users, it still will set by the controller, ignoring
|
||||
the settings in HCL/JSON backend
|
||||
properties:
|
||||
inClusterConfig:
|
||||
description: InClusterConfig Used to authenticate to the cluster
|
||||
from inside a pod. Only `true` is allowed
|
||||
type: boolean
|
||||
secretSuffix:
|
||||
description: 'SecretSuffix used when creating secrets. Secrets
|
||||
will be named in the format: tfstate-{workspace}-{secretSuffix}'
|
||||
type: string
|
||||
type: object
|
||||
customRegion:
|
||||
description: Region is cloud provider's region. It will override the
|
||||
region in the region field of ProviderReference
|
||||
type: string
|
||||
deleteResource:
|
||||
default: true
|
||||
description: DeleteResource will determine whether provisioned cloud
|
||||
resources will be deleted when CR is deleted
|
||||
type: boolean
|
||||
hcl:
|
||||
description: HCL is the Terraform HCL type configuration
|
||||
type: string
|
||||
path:
|
||||
description: Path is the sub-directory of remote git repository.
|
||||
type: string
|
||||
providerRef:
|
||||
description: ProviderReference specifies the reference to Provider
|
||||
properties:
|
||||
name:
|
||||
description: Name of the referenced object.
|
||||
type: string
|
||||
namespace:
|
||||
default: default
|
||||
description: Namespace of the referenced object.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
remote:
|
||||
description: Remote is a git repo which contains hcl files. Currently,
|
||||
only public git repos are supported.
|
||||
type: string
|
||||
variable:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
writeConnectionSecretToRef:
|
||||
description: WriteConnectionSecretToReference specifies the namespace
|
||||
and name of a Secret to which any connection details for this managed
|
||||
resource should be written. Connection details frequently include
|
||||
the endpoint, username, and password required to connect to the
|
||||
managed resource.
|
||||
properties:
|
||||
name:
|
||||
description: Name of the secret.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace of the secret.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
type: object
|
||||
status:
|
||||
description: ConfigurationStatus defines the observed state of Configuration
|
||||
properties:
|
||||
apply:
|
||||
description: ConfigurationApplyStatus is the status for Configuration
|
||||
apply
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
outputs:
|
||||
additionalProperties:
|
||||
description: Property is the property for an output
|
||||
properties:
|
||||
value:
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
state:
|
||||
description: A ConfigurationState represents the status of a resource
|
||||
type: string
|
||||
type: object
|
||||
destroy:
|
||||
description: ConfigurationDestroyStatus is the status for Configuration
|
||||
destroy
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
state:
|
||||
description: A ConfigurationState represents the status of a resource
|
||||
type: string
|
||||
type: object
|
||||
observedGeneration:
|
||||
description: observedGeneration is the most recent generation observed
|
||||
for this Configuration. It corresponds to the Configuration's generation,
|
||||
which is updated on mutation by the API Server. If ObservedGeneration
|
||||
equals Generation, and State is Available, the value of Outputs
|
||||
is latest
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
storedVersions: []
|
||||
@@ -43,17 +43,24 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
"github.com/oam-dev/kubevela/version"
|
||||
)
|
||||
|
||||
// Reconciler reconciles a ComponentDefinition object
|
||||
type Reconciler struct {
|
||||
client.Client
|
||||
dm discoverymapper.DiscoveryMapper
|
||||
pd *packages.PackageDiscover
|
||||
Scheme *runtime.Scheme
|
||||
record event.Recorder
|
||||
dm discoverymapper.DiscoveryMapper
|
||||
pd *packages.PackageDiscover
|
||||
Scheme *runtime.Scheme
|
||||
record event.Recorder
|
||||
options
|
||||
}
|
||||
|
||||
type options struct {
|
||||
defRevLimit int
|
||||
concurrentReconciles int
|
||||
ignoreDefNoCtrlReq bool
|
||||
controllerVersion string
|
||||
}
|
||||
|
||||
// Reconcile is the main logic for ComponentDefinition controller
|
||||
@@ -68,6 +75,11 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
|
||||
if !r.matchControllerRequirement(&componentDefinition) {
|
||||
klog.InfoS("skip componentDefinition: not match the controller requirement of componentDefinition", "componentDefinition", klog.KObj(&componentDefinition))
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
// refresh package discover when componentDefinition is registered
|
||||
if componentDefinition.Spec.Workload.Type != types.AutoDetectWorkloadDefinition {
|
||||
err := utils.RefreshPackageDiscover(ctx, r.Client, r.dm, r.pd, &componentDefinition)
|
||||
@@ -187,12 +199,32 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
// Setup adds a controller that reconciles ComponentDefinition.
|
||||
func Setup(mgr ctrl.Manager, args oamctrl.Args) error {
|
||||
r := Reconciler{
|
||||
Client: mgr.GetClient(),
|
||||
Scheme: mgr.GetScheme(),
|
||||
dm: args.DiscoveryMapper,
|
||||
pd: args.PackageDiscover,
|
||||
defRevLimit: args.DefRevisionLimit,
|
||||
concurrentReconciles: args.ConcurrentReconciles,
|
||||
Client: mgr.GetClient(),
|
||||
Scheme: mgr.GetScheme(),
|
||||
dm: args.DiscoveryMapper,
|
||||
pd: args.PackageDiscover,
|
||||
options: parseOptions(args),
|
||||
}
|
||||
return r.SetupWithManager(mgr)
|
||||
}
|
||||
|
||||
func parseOptions(args oamctrl.Args) options {
|
||||
return options{
|
||||
defRevLimit: args.DefRevisionLimit,
|
||||
concurrentReconciles: args.ConcurrentReconciles,
|
||||
ignoreDefNoCtrlReq: args.IgnoreDefinitionWithoutControllerRequirement,
|
||||
controllerVersion: version.VelaVersion,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Reconciler) matchControllerRequirement(componentDefinition *v1beta1.ComponentDefinition) bool {
|
||||
if componentDefinition.Annotations != nil {
|
||||
if requireVersion, ok := componentDefinition.Annotations[oam.AnnotationControllerRequirement]; ok {
|
||||
return requireVersion == r.controllerVersion
|
||||
}
|
||||
}
|
||||
if r.ignoreDefNoCtrlReq {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -90,11 +90,13 @@ var _ = BeforeSuite(func(done Done) {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
r = Reconciler{
|
||||
Client: mgr.GetClient(),
|
||||
Scheme: mgr.GetScheme(),
|
||||
dm: dm,
|
||||
pd: pd,
|
||||
defRevLimit: defRevisionLimit,
|
||||
Client: mgr.GetClient(),
|
||||
Scheme: mgr.GetScheme(),
|
||||
dm: dm,
|
||||
pd: pd,
|
||||
options: options{
|
||||
defRevLimit: defRevisionLimit,
|
||||
},
|
||||
}
|
||||
Expect(r.SetupWithManager(mgr)).ToNot(HaveOccurred())
|
||||
var ctx context.Context
|
||||
|
||||
@@ -37,7 +37,7 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
terraformtypes "github.com/oam-dev/terraform-controller/api/types"
|
||||
terraformapi "github.com/oam-dev/terraform-controller/api/v1beta1"
|
||||
terraformapi "github.com/oam-dev/terraform-controller/api/v1beta2"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
|
||||
oamtypes "github.com/oam-dev/kubevela/apis/types"
|
||||
|
||||
@@ -42,17 +42,24 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
"github.com/oam-dev/kubevela/version"
|
||||
)
|
||||
|
||||
// Reconciler reconciles a TraitDefinition object
|
||||
type Reconciler struct {
|
||||
client.Client
|
||||
dm discoverymapper.DiscoveryMapper
|
||||
pd *packages.PackageDiscover
|
||||
Scheme *runtime.Scheme
|
||||
record event.Recorder
|
||||
dm discoverymapper.DiscoveryMapper
|
||||
pd *packages.PackageDiscover
|
||||
Scheme *runtime.Scheme
|
||||
record event.Recorder
|
||||
options
|
||||
}
|
||||
|
||||
type options struct {
|
||||
defRevLimit int
|
||||
concurrentReconciles int
|
||||
ignoreDefNoCtrlReq bool
|
||||
controllerVersion string
|
||||
}
|
||||
|
||||
// Reconcile is the main logic for TraitDefinition controller
|
||||
@@ -67,6 +74,11 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
|
||||
if !r.matchControllerRequirement(&traitdefinition) {
|
||||
klog.InfoS("skip traitDefinition: not match the controller requirement of traitDefinition", "traitDefinition", klog.KObj(&traitdefinition))
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
// this is a placeholder for finalizer here in the future
|
||||
if traitdefinition.DeletionTimestamp != nil {
|
||||
klog.InfoS("The TraitDefinition is being deleted", "traitDefinition", klog.KRef(req.Namespace, req.Name))
|
||||
@@ -193,12 +205,32 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
// Setup adds a controller that reconciles TraitDefinition.
|
||||
func Setup(mgr ctrl.Manager, args oamctrl.Args) error {
|
||||
r := Reconciler{
|
||||
Client: mgr.GetClient(),
|
||||
Scheme: mgr.GetScheme(),
|
||||
dm: args.DiscoveryMapper,
|
||||
pd: args.PackageDiscover,
|
||||
defRevLimit: args.DefRevisionLimit,
|
||||
concurrentReconciles: args.ConcurrentReconciles,
|
||||
Client: mgr.GetClient(),
|
||||
Scheme: mgr.GetScheme(),
|
||||
dm: args.DiscoveryMapper,
|
||||
pd: args.PackageDiscover,
|
||||
options: parseOptions(args),
|
||||
}
|
||||
return r.SetupWithManager(mgr)
|
||||
}
|
||||
|
||||
func parseOptions(args oamctrl.Args) options {
|
||||
return options{
|
||||
defRevLimit: args.DefRevisionLimit,
|
||||
concurrentReconciles: args.ConcurrentReconciles,
|
||||
ignoreDefNoCtrlReq: args.IgnoreDefinitionWithoutControllerRequirement,
|
||||
controllerVersion: version.VelaVersion,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Reconciler) matchControllerRequirement(traitDefinition *v1beta1.TraitDefinition) bool {
|
||||
if traitDefinition.Annotations != nil {
|
||||
if requireVersion, ok := traitDefinition.Annotations[oam.AnnotationControllerRequirement]; ok {
|
||||
return requireVersion == r.controllerVersion
|
||||
}
|
||||
}
|
||||
if r.ignoreDefNoCtrlReq {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -90,11 +90,13 @@ var _ = BeforeSuite(func(done Done) {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
r = Reconciler{
|
||||
Client: mgr.GetClient(),
|
||||
Scheme: mgr.GetScheme(),
|
||||
dm: dm,
|
||||
pd: pd,
|
||||
defRevLimit: defRevisionLimit,
|
||||
Client: mgr.GetClient(),
|
||||
Scheme: mgr.GetScheme(),
|
||||
dm: dm,
|
||||
pd: pd,
|
||||
options: options{
|
||||
defRevLimit: defRevisionLimit,
|
||||
},
|
||||
}
|
||||
Expect(r.SetupWithManager(mgr)).ToNot(HaveOccurred())
|
||||
var ctx context.Context
|
||||
|
||||
@@ -90,11 +90,13 @@ var _ = BeforeSuite(func(done Done) {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
r = Reconciler{
|
||||
Client: mgr.GetClient(),
|
||||
Scheme: mgr.GetScheme(),
|
||||
dm: dm,
|
||||
pd: pd,
|
||||
defRevLimit: defRevisionLimit,
|
||||
Client: mgr.GetClient(),
|
||||
Scheme: mgr.GetScheme(),
|
||||
dm: dm,
|
||||
pd: pd,
|
||||
options: options{
|
||||
defRevLimit: defRevisionLimit,
|
||||
},
|
||||
}
|
||||
Expect(r.SetupWithManager(mgr)).ToNot(HaveOccurred())
|
||||
var ctx context.Context
|
||||
|
||||
@@ -42,17 +42,24 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
"github.com/oam-dev/kubevela/version"
|
||||
)
|
||||
|
||||
// Reconciler reconciles a WorkflowStepDefinition object
|
||||
type Reconciler struct {
|
||||
client.Client
|
||||
dm discoverymapper.DiscoveryMapper
|
||||
pd *packages.PackageDiscover
|
||||
Scheme *runtime.Scheme
|
||||
record event.Recorder
|
||||
dm discoverymapper.DiscoveryMapper
|
||||
pd *packages.PackageDiscover
|
||||
Scheme *runtime.Scheme
|
||||
record event.Recorder
|
||||
options
|
||||
}
|
||||
|
||||
type options struct {
|
||||
defRevLimit int
|
||||
concurrentReconciles int
|
||||
ignoreDefNoCtrlReq bool
|
||||
controllerVersion string
|
||||
}
|
||||
|
||||
// Reconcile is the main logic for WorkflowStepDefinition controller
|
||||
@@ -68,6 +75,11 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
|
||||
if !r.matchControllerRequirement(&wfstepdefinition) {
|
||||
klog.InfoS("skip workflowStepDefinition: not match the controller requirement of workflowStepDefinition", "workflowStepDefinition", klog.KObj(&wfstepdefinition))
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
// this is a placeholder for finalizer here in the future
|
||||
if wfstepdefinition.DeletionTimestamp != nil {
|
||||
return ctrl.Result{}, nil
|
||||
@@ -192,11 +204,32 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
// Setup adds a controller that reconciles WorkflowStepDefinition.
|
||||
func Setup(mgr ctrl.Manager, args oamctrl.Args) error {
|
||||
r := Reconciler{
|
||||
Client: mgr.GetClient(),
|
||||
Scheme: mgr.GetScheme(),
|
||||
dm: args.DiscoveryMapper,
|
||||
pd: args.PackageDiscover,
|
||||
defRevLimit: args.DefRevisionLimit,
|
||||
Client: mgr.GetClient(),
|
||||
Scheme: mgr.GetScheme(),
|
||||
dm: args.DiscoveryMapper,
|
||||
pd: args.PackageDiscover,
|
||||
options: parseOptions(args),
|
||||
}
|
||||
return r.SetupWithManager(mgr)
|
||||
}
|
||||
|
||||
func parseOptions(args oamctrl.Args) options {
|
||||
return options{
|
||||
defRevLimit: args.DefRevisionLimit,
|
||||
concurrentReconciles: args.ConcurrentReconciles,
|
||||
ignoreDefNoCtrlReq: args.IgnoreDefinitionWithoutControllerRequirement,
|
||||
controllerVersion: version.VelaVersion,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Reconciler) matchControllerRequirement(wfstepdefinition *v1beta1.WorkflowStepDefinition) bool {
|
||||
if wfstepdefinition.Annotations != nil {
|
||||
if requireVersion, ok := wfstepdefinition.Annotations[oam.AnnotationControllerRequirement]; ok {
|
||||
return requireVersion == r.controllerVersion
|
||||
}
|
||||
}
|
||||
if r.ignoreDefNoCtrlReq {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -317,7 +317,7 @@ func (val *Value) LookupValue(paths ...string) (*Value, error) {
|
||||
func (val *Value) LookupByScript(script string) (*Value, error) {
|
||||
var outputKey = "zz_output__"
|
||||
script = strings.TrimSpace(script)
|
||||
scriptFile, err := parser.ParseFile("-", script)
|
||||
scriptFile, err := parser.ParseFile("-", script, parser.ParseComments)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessage(err, "parse script")
|
||||
}
|
||||
@@ -327,7 +327,7 @@ func (val *Value) LookupByScript(script string) (*Value, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rawFile, err := parser.ParseFile("-", raw)
|
||||
rawFile, err := parser.ParseFile("-", raw, parser.ParseComments)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessage(err, "parse script")
|
||||
}
|
||||
|
||||
@@ -597,6 +597,23 @@ func TestLookupByScript(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
src: `
|
||||
traits: {
|
||||
ingress: {
|
||||
// +patchKey=name
|
||||
test: [{name: "main", image: "busybox"}]
|
||||
}
|
||||
}
|
||||
`,
|
||||
script: `traits["ingress"]`,
|
||||
expect: `// +patchKey=name
|
||||
test: [{
|
||||
name: "main"
|
||||
image: "busybox"
|
||||
}]
|
||||
`,
|
||||
},
|
||||
{
|
||||
src: `
|
||||
apply: containers: [{name: "main", image: "busybox"}]
|
||||
`,
|
||||
script: `apply.containers[0].image`,
|
||||
|
||||
@@ -29,12 +29,15 @@ const (
|
||||
LegacyObjectTypeIdentifier featuregate.Feature = "LegacyObjectTypeIdentifier"
|
||||
// DeprecatedObjectLabelSelector enable the use of deprecated object label selector for selecting ref-object
|
||||
DeprecatedObjectLabelSelector featuregate.Feature = "DeprecatedObjectLabelSelector"
|
||||
// LegacyResourceTrackerGC enable the gc of legacy resource tracker in managed clusters
|
||||
LegacyResourceTrackerGC featuregate.Feature = "LegacyResourceTrackerGC"
|
||||
)
|
||||
|
||||
var defaultFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
|
||||
DeprecatedPolicySpec: {Default: false, PreRelease: featuregate.Alpha},
|
||||
LegacyObjectTypeIdentifier: {Default: false, PreRelease: featuregate.Alpha},
|
||||
DeprecatedObjectLabelSelector: {Default: false, PreRelease: featuregate.Alpha},
|
||||
LegacyResourceTrackerGC: {Default: true, PreRelease: featuregate.Alpha},
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/config"
|
||||
|
||||
velatypes "github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
errors3 "github.com/oam-dev/kubevela/pkg/utils/errors"
|
||||
@@ -46,7 +47,7 @@ const (
|
||||
// ClusterContextKey is the name of cluster using in client http context
|
||||
ClusterContextKey = contextKey("ClusterName")
|
||||
// ClusterLocalName specifies the local cluster
|
||||
ClusterLocalName = "local"
|
||||
ClusterLocalName = velatypes.ClusterLocalName
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user