mirror of
https://github.com/kubevela/kubevela.git
synced 2026-03-01 09:10:43 +00:00
Compare commits
90 Commits
v1.5.0-alp
...
v1.4.7-pat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b596b70ebe | ||
|
|
0cd370e867 | ||
|
|
d9adc73e5c | ||
|
|
4a2d9807c8 | ||
|
|
840cb8ce58 | ||
|
|
5a64fec916 | ||
|
|
657a374ded | ||
|
|
dfe12cd9ca | ||
|
|
cd42f67848 | ||
|
|
61d2c588e3 | ||
|
|
b3dad698a5 | ||
|
|
ec5159c2ca | ||
|
|
a7b2b221e0 | ||
|
|
caa495a5d9 | ||
|
|
15bea4fb64 | ||
|
|
1a094a4eea | ||
|
|
65b6f47330 | ||
|
|
3a4cd2dca6 | ||
|
|
9fabd950e5 | ||
|
|
0a012b4d34 | ||
|
|
7c231e6c48 | ||
|
|
36b6c3e7b5 | ||
|
|
4cc019722c | ||
|
|
b040ae65da | ||
|
|
f0fb4ed099 | ||
|
|
7f89d12059 | ||
|
|
3c61bcb8f0 | ||
|
|
a14b536fd1 | ||
|
|
ba5a726854 | ||
|
|
ffb9d06427 | ||
|
|
819dc26ace | ||
|
|
5e3ab732df | ||
|
|
62d5507499 | ||
|
|
c0daf688a6 | ||
|
|
48d19a2427 | ||
|
|
4da8d49e60 | ||
|
|
4db9e89816 | ||
|
|
667053409d | ||
|
|
eb9ddaabd3 | ||
|
|
f11a94612f | ||
|
|
56f9d7cb9c | ||
|
|
fbbc666019 | ||
|
|
d0788254cb | ||
|
|
c72a6aef87 | ||
|
|
195b7fe0c7 | ||
|
|
33c9e3b170 | ||
|
|
ea0508a634 | ||
|
|
23e29aa62a | ||
|
|
ed2cb80219 | ||
|
|
1a3d5debd5 | ||
|
|
d4a82fe292 | ||
|
|
963ae400fa | ||
|
|
8f7a8258fe | ||
|
|
70bc306678 | ||
|
|
57428bbc8d | ||
|
|
e08541ca5c | ||
|
|
521a4edc10 | ||
|
|
82b330710c | ||
|
|
4a649f2cf1 | ||
|
|
f6664106a2 | ||
|
|
bbe2a2dec6 | ||
|
|
404c7f6975 | ||
|
|
2edfbabdab | ||
|
|
e7b304de3b | ||
|
|
b8b54baf26 | ||
|
|
87b6c9416e | ||
|
|
cd171d27db | ||
|
|
6d8be8b061 | ||
|
|
e93912acff | ||
|
|
e48e39987f | ||
|
|
6264a66021 | ||
|
|
9191127e01 | ||
|
|
1b047c10ba | ||
|
|
02a1d390c4 | ||
|
|
62866e19d8 | ||
|
|
3dc645ed52 | ||
|
|
e20ef02a6a | ||
|
|
371affb389 | ||
|
|
b35145be82 | ||
|
|
d92c8844ba | ||
|
|
82aaf5098b | ||
|
|
7399666275 | ||
|
|
0b394e766b | ||
|
|
eb386ce9f7 | ||
|
|
e4fa5a5cf1 | ||
|
|
165e011bd0 | ||
|
|
9489b8d511 | ||
|
|
d95942c992 | ||
|
|
c6aa8ddbbc | ||
|
|
c370ef04f3 |
24
.github/CODEOWNERS
vendored
24
.github/CODEOWNERS
vendored
@@ -1,14 +1,14 @@
|
||||
# This file is a github code protect rule follow the codeowners https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-code-owners#example-of-a-codeowners-file
|
||||
|
||||
* @barnettZQG @wonderflow @leejanee @Somefive
|
||||
design/ @barnettZQG @leejanee @wonderflow @Somefive
|
||||
* @barnettZQG @wonderflow @leejanee
|
||||
design/ @barnettZQG @leejanee @wonderflow
|
||||
|
||||
# Owner of CUE
|
||||
pkg/cue @leejanee @FogDong @Somefive
|
||||
pkg/stdlib @leejanee @FogDong @Somefive
|
||||
pkg/cue @leejanee @FogDong
|
||||
pkg/stdlib @leejanee @FogDong
|
||||
|
||||
# Owner of Workflow
|
||||
pkg/workflow @leejanee @FogDong @Somefive
|
||||
pkg/workflow @leejanee @FogDong
|
||||
|
||||
# Owner of rollout
|
||||
pkg/controller/common/rollout/ @wangyikewxgm @wonderflow
|
||||
@@ -17,20 +17,20 @@ pkg/controller/standard.oam.dev/v1alpha1/rollout @wangyikewxgm @wonde
|
||||
runtime/rollout @wangyikewxgm @wonderflow
|
||||
|
||||
# Owner of definition controller
|
||||
pkg/controller/core.oam.dev/v1alpha2/core/workflow/workflowstepdefinition @yangsoon @Somefive @FogDong
|
||||
pkg/controller/core.oam.dev/v1alpha2/core/policies/policydefinition @yangsoon @Somefive @FogDong
|
||||
pkg/controller/core.oam.dev/v1alpha2/core/components/componentdefinition @yangsoon @zzxwill @Somefive
|
||||
pkg/controller/core.oam.dev/v1alpha2/core/traits/traitdefinition @yangsoon @zzxwill @Somefive
|
||||
pkg/controller/core.oam.dev/v1alpha2/core/workflow/workflowstepdefinition @yangsoon @Somefive
|
||||
pkg/controller/core.oam.dev/v1alpha2/core/policies/policydefinition @yangsoon @Somefive
|
||||
pkg/controller/core.oam.dev/v1alpha2/core/components/componentdefinition @yangsoon @zzxwill
|
||||
pkg/controller/core.oam.dev/v1alpha2/core/traits/traitdefinition @yangsoon @zzxwill
|
||||
|
||||
# Owner of health scope controller
|
||||
pkg/controller/core.oam.dev/v1alpha2/core/scopes/healthscope @captainroy-hy @zzxwill @yangsoon
|
||||
pkg/controller/core.oam.dev/v1alpha2/core/scopes/healthscope @captainroy-hy @zzxwill
|
||||
|
||||
# Owner of vela templates
|
||||
vela-templates/ @Somefive @barnettZQG @wonderflow
|
||||
|
||||
# Owner of vela CLI
|
||||
references/cli/ @Somefive @zzxwill @StevenLeiZhang
|
||||
references/cli/ @Somefive @zzxwill
|
||||
|
||||
# Owner of vela APIServer
|
||||
pkg/apiserver/ @barnettZQG @yangsoon @FogDong
|
||||
pkg/apiserver/ @barnettZQG @yangsoon
|
||||
|
||||
|
||||
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
|
||||
10
.github/workflows/issue-commands.yml
vendored
10
.github/workflows/issue-commands.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
|
||||
jobs:
|
||||
bot:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Actions
|
||||
uses: actions/checkout@v2
|
||||
@@ -15,13 +15,7 @@ jobs:
|
||||
repository: "oam-dev/kubevela-github-actions"
|
||||
path: ./actions
|
||||
ref: v0.4.2
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '14'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: ./actions/package-lock.json
|
||||
- name: Install Dependencies
|
||||
- name: Install Actions
|
||||
run: npm ci --production --prefix ./actions
|
||||
- name: Run Commands
|
||||
uses: ./actions/commands
|
||||
|
||||
87
.github/workflows/registry.yml
vendored
87
.github/workflows/registry.yml
vendored
@@ -8,11 +8,8 @@ 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-core-images:
|
||||
@@ -171,90 +168,6 @@ jobs:
|
||||
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-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
|
||||
- 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" $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
|
||||
|
||||
publish-capabilities:
|
||||
env:
|
||||
CAPABILITY_BUCKET: kubevela-registry
|
||||
|
||||
5
.github/workflows/release.yml
vendored
5
.github/workflows/release.yml
vendored
@@ -123,6 +123,11 @@ jobs:
|
||||
- name: sync the latest version file
|
||||
if: ${{ !contains(env.VELA_VERSION,'alpha') && !contains(env.VELA_VERSION,'beta') }}
|
||||
run: |
|
||||
LATEST_VERSION=$(curl -fsSl https://static.kubevela.net/binary/vela/latest_version)
|
||||
verlte() {
|
||||
[ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ]
|
||||
}
|
||||
verlte ${{ env.VELA_VERSION }} $LATEST_VERSION && echo "${{ env.VELA_VERSION }} <= $LATEST_VERSION, skip update" && exit 0
|
||||
echo ${{ env.VELA_VERSION }} > ./latest_version
|
||||
./ossutil --config-file .ossutilconfig cp -u ./latest_version oss://$BUCKET/binary/vela/latest_version
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ This is a minor fix for release-1.0, please refer to release-1.1.x for the lates
|
||||
# v1.0.5
|
||||
|
||||
1. Fix Terraform application status issue (#1611)
|
||||
2. application supports specifying different versions of Definition (#1597)
|
||||
2. applicaiton supports specifying different versions of Definition (#1597)
|
||||
3. Enable Dynamic Admission Control for Application (#1619)
|
||||
4. Update inner samples for "vela show xxx --web" (#1616)
|
||||
5. fix empty rolloutBatch will panic whole controller bug (#1646)
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
## What's Changed
|
||||
|
||||
* Fix: can't query data from the MongoDB by @barnettZQG in https://github.com/oam-dev/kubevela/pull/3095
|
||||
* Fix: use personal token of vela-bot instead of github token for homebrew update by @wonderflow in https://github.com/oam-dev/kubevela/pull/3096
|
||||
* Fix: use personel token of vela-bot instead of github token for homebrew update by @wonderflow in https://github.com/oam-dev/kubevela/pull/3096
|
||||
* Fix: acr image no version by @wangyikewxgm in https://github.com/oam-dev/kubevela/pull/3100
|
||||
* Fix: support generate cloud resource docs in Chinese by @zzxwill in https://github.com/oam-dev/kubevela/pull/3079
|
||||
* Fix: clear old data in mongodb unit test case by @barnettZQG in https://github.com/oam-dev/kubevela/pull/3103
|
||||
|
||||
22
README.md
22
README.md
@@ -21,29 +21,23 @@
|
||||
|
||||
KubeVela is a modern application delivery platform that makes deploying and operating applications across today's hybrid, multi-cloud environments easier, faster and more reliable.
|
||||
|
||||

|
||||

|
||||
|
||||
## Highlights
|
||||
|
||||
KubeVela practices the "render, orchestrate, deploy" workflow with below highlighted values added to existing ecosystem:
|
||||
|
||||
* Deployment as Code
|
||||
- *Application Centric* - KubeVela introduces [Open Application Model (OAM)](https://oam.dev/) as the consistent yet higher level API to capture and render a full deployment of microservices on top of hybrid environments. Placement strategy, traffic shifting and rolling update are declared at application level. No infrastructure level concern, simply deploy.
|
||||
|
||||
Declare your deployment plan as workflow, run it automatically with any CI/CD or GitOps system, extend or re-program the workflow steps with CUE. No add-hoc scripts, no dirty glue code, just deploy. The deployment workflow in KubeVela is powered by [Open Application Model](https://oam.dev/).
|
||||
- *Programmable Workflow* - KubeVela models application delivery as DAG (Directed Acyclic Graph) and expresses it with [CUE](https://cuelang.org/) - a modern data configuration language. This allows you to design application deployment steps per needs and orchestrate them in programmable approach. No restrictions, natively extensible.
|
||||
|
||||
* Built-in security and compliance building blocks
|
||||
|
||||
Choose from the wide range of LDAP integrations we provided out-of-box, enjoy multi-cluster authorization that is fully automated, pick and apply fine-grained RBAC modules and customize them per your own supply chain requirements.
|
||||
|
||||
* Multi-cloud/hybrid-environments app delivery as first-class citizen
|
||||
|
||||
Progressive rollout across test/staging/production environments, automatic canary, blue-green and continuous verification, rich placement strategy across clusters and clouds, fully managed cloud environments provision.
|
||||
- *Infrastructure Agnostic* - KubeVela works as an application delivery control plane that is fully decoupled from runtime infrastructure. It can deploy any workload types including containers, cloud services, databases, or even VM instances to any cloud or Kubernetes cluster, following the workflow designed by you.
|
||||
|
||||
## Getting Started
|
||||
|
||||
* [Introduction](https://kubevela.io/docs)
|
||||
* [Installation](https://kubevela.io/docs/install)
|
||||
* [Deploy Your Application](https://kubevela.io/docs/quick-start)
|
||||
- [Introduction](https://kubevela.io/docs)
|
||||
- [Installation](https://kubevela.io/docs/install)
|
||||
- [Design Your First Deployment Plan](https://kubevela.io/docs/quick-start)
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -55,7 +49,7 @@ Official blog is available on [KubeVela blog](https://kubevela.io/blog).
|
||||
|
||||
## Community
|
||||
|
||||
We want your contributions and suggestions!
|
||||
We want your contributions and suggestions!
|
||||
One of the easiest ways to contribute is to participate in discussions on the Github Issues/Discussion, chat on IM or the bi-weekly community calls.
|
||||
For more information on the community engagement, developer and contributing guidelines and more, head over to the [KubeVela community repo](https://github.com/kubevela/community).
|
||||
|
||||
|
||||
@@ -216,19 +216,19 @@ type WorkflowState string
|
||||
|
||||
const (
|
||||
// WorkflowStateInitializing means the workflow is in initial state
|
||||
WorkflowStateInitializing WorkflowState = "Initializing"
|
||||
WorkflowStateInitializing WorkflowState = "initializing"
|
||||
// WorkflowStateTerminated means workflow is terminated manually, and it won't be started unless the spec changed.
|
||||
WorkflowStateTerminated WorkflowState = "Terminated"
|
||||
WorkflowStateTerminated WorkflowState = "terminated"
|
||||
// WorkflowStateSuspended means workflow is suspended manually, and it can be resumed.
|
||||
WorkflowStateSuspended WorkflowState = "Suspended"
|
||||
WorkflowStateSuspended WorkflowState = "suspended"
|
||||
// WorkflowStateSucceeded means workflow is running successfully, all steps finished.
|
||||
WorkflowStateSucceeded WorkflowState = "Succeeded"
|
||||
// WorkflowStateFinished means workflow is end.
|
||||
WorkflowStateFinished WorkflowState = "Finished"
|
||||
WorkflowStateFinished WorkflowState = "finished"
|
||||
// WorkflowStateExecuting means workflow is still running or waiting some steps.
|
||||
WorkflowStateExecuting WorkflowState = "Executing"
|
||||
WorkflowStateExecuting WorkflowState = "executing"
|
||||
// WorkflowStateSkipping means it will skip this reconcile and let next reconcile to handle it.
|
||||
WorkflowStateSkipping WorkflowState = "Skipping"
|
||||
WorkflowStateSkipping WorkflowState = "skipping"
|
||||
)
|
||||
|
||||
// ApplicationComponentStatus record the health status of App component
|
||||
@@ -342,8 +342,6 @@ type WorkflowStep struct {
|
||||
|
||||
Type string `json:"type"`
|
||||
|
||||
Meta *WorkflowStepMeta `json:"meta,omitempty"`
|
||||
|
||||
// +kubebuilder:pruning:PreserveUnknownFields
|
||||
Properties *runtime.RawExtension `json:"properties,omitempty"`
|
||||
|
||||
@@ -351,8 +349,6 @@ type WorkflowStep struct {
|
||||
|
||||
If string `json:"if,omitempty"`
|
||||
|
||||
Timeout string `json:"timeout,omitempty"`
|
||||
|
||||
DependsOn []string `json:"dependsOn,omitempty"`
|
||||
|
||||
Inputs StepInputs `json:"inputs,omitempty"`
|
||||
@@ -360,11 +356,6 @@ type WorkflowStep struct {
|
||||
Outputs StepOutputs `json:"outputs,omitempty"`
|
||||
}
|
||||
|
||||
// WorkflowStepMeta contains the meta data of a workflow step
|
||||
type WorkflowStepMeta struct {
|
||||
Alias string `json:"alias,omitempty"`
|
||||
}
|
||||
|
||||
// WorkflowSubStep defines how to execute a workflow subStep.
|
||||
type WorkflowSubStep struct {
|
||||
// Name is the unique name of the workflow step.
|
||||
@@ -372,15 +363,11 @@ type WorkflowSubStep struct {
|
||||
|
||||
Type string `json:"type"`
|
||||
|
||||
Meta *WorkflowStepMeta `json:"meta,omitempty"`
|
||||
|
||||
// +kubebuilder:pruning:PreserveUnknownFields
|
||||
Properties *runtime.RawExtension `json:"properties,omitempty"`
|
||||
|
||||
If string `json:"if,omitempty"`
|
||||
|
||||
Timeout string `json:"timeout,omitempty"`
|
||||
|
||||
DependsOn []string `json:"dependsOn,omitempty"`
|
||||
|
||||
Inputs StepInputs `json:"inputs,omitempty"`
|
||||
|
||||
@@ -684,11 +684,6 @@ func (in *WorkflowStatus) DeepCopy() *WorkflowStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WorkflowStep) DeepCopyInto(out *WorkflowStep) {
|
||||
*out = *in
|
||||
if in.Meta != nil {
|
||||
in, out := &in.Meta, &out.Meta
|
||||
*out = new(WorkflowStepMeta)
|
||||
**out = **in
|
||||
}
|
||||
if in.Properties != nil {
|
||||
in, out := &in.Properties, &out.Properties
|
||||
*out = new(runtime.RawExtension)
|
||||
@@ -728,21 +723,6 @@ func (in *WorkflowStep) DeepCopy() *WorkflowStep {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WorkflowStepMeta) DeepCopyInto(out *WorkflowStepMeta) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowStepMeta.
|
||||
func (in *WorkflowStepMeta) DeepCopy() *WorkflowStepMeta {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(WorkflowStepMeta)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WorkflowStepStatus) DeepCopyInto(out *WorkflowStepStatus) {
|
||||
*out = *in
|
||||
@@ -769,11 +749,6 @@ func (in *WorkflowStepStatus) DeepCopy() *WorkflowStepStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WorkflowSubStep) DeepCopyInto(out *WorkflowSubStep) {
|
||||
*out = *in
|
||||
if in.Meta != nil {
|
||||
in, out := &in.Meta, &out.Meta
|
||||
*out = new(WorkflowStepMeta)
|
||||
**out = **in
|
||||
}
|
||||
if in.Properties != nil {
|
||||
in, out := &in.Properties, &out.Properties
|
||||
*out = new(runtime.RawExtension)
|
||||
|
||||
@@ -25,8 +25,6 @@ const (
|
||||
type RefObjectsComponentSpec struct {
|
||||
// Objects the referrers to the Kubernetes objects
|
||||
Objects []ObjectReferrer `json:"objects,omitempty"`
|
||||
// URLs are the links that stores the referred objects
|
||||
URLs []string `json:"urls,omitempty"`
|
||||
}
|
||||
|
||||
// ObjectReferrer selects Kubernetes objects
|
||||
|
||||
@@ -18,7 +18,6 @@ package v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/utils/strings/slices"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
)
|
||||
@@ -67,29 +66,6 @@ type ResourcePolicyRuleSelector struct {
|
||||
OAMResourceTypes []string `json:"oamTypes"`
|
||||
TraitTypes []string `json:"traitTypes"`
|
||||
ResourceTypes []string `json:"resourceTypes"`
|
||||
ResourceNames []string `json:"resourceNames"`
|
||||
}
|
||||
|
||||
// Match check if current rule selector match the target resource
|
||||
func (in *ResourcePolicyRuleSelector) Match(manifest *unstructured.Unstructured) bool {
|
||||
var compName, compType, oamType, traitType, resourceType, resourceName string
|
||||
if labels := manifest.GetLabels(); labels != nil {
|
||||
compName = labels[oam.LabelAppComponent]
|
||||
compType = labels[oam.WorkloadTypeLabel]
|
||||
oamType = labels[oam.LabelOAMResourceType]
|
||||
traitType = labels[oam.TraitTypeLabel]
|
||||
}
|
||||
resourceType = manifest.GetKind()
|
||||
resourceName = manifest.GetName()
|
||||
match := func(src []string, val string) (found bool) {
|
||||
return val != "" && slices.Contains(src, val)
|
||||
}
|
||||
return match(in.CompNames, compName) ||
|
||||
match(in.CompTypes, compType) ||
|
||||
match(in.OAMResourceTypes, oamType) ||
|
||||
match(in.TraitTypes, traitType) ||
|
||||
match(in.ResourceTypes, resourceType) ||
|
||||
match(in.ResourceNames, resourceName)
|
||||
}
|
||||
|
||||
// GarbageCollectStrategy the strategy for target resource to recycle
|
||||
@@ -108,7 +84,23 @@ const (
|
||||
// FindStrategy find gc strategy for target resource
|
||||
func (in GarbageCollectPolicySpec) FindStrategy(manifest *unstructured.Unstructured) *GarbageCollectStrategy {
|
||||
for _, rule := range in.Rules {
|
||||
if rule.Selector.Match(manifest) {
|
||||
var compName, compType, oamType, 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) {
|
||||
for _, _val := range src {
|
||||
found = found || _val == val
|
||||
}
|
||||
return val != "" && found
|
||||
}
|
||||
if match(rule.Selector.CompNames, compName) ||
|
||||
match(rule.Selector.CompTypes, compType) ||
|
||||
match(rule.Selector.OAMResourceTypes, oamType) ||
|
||||
match(rule.Selector.TraitTypes, traitType) {
|
||||
return &rule.Strategy
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@ limitations under the License.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
const (
|
||||
// TopologyPolicyType refers to the type of topology policy
|
||||
TopologyPolicyType = "topology"
|
||||
@@ -25,8 +23,6 @@ const (
|
||||
OverridePolicyType = "override"
|
||||
// DebugPolicyType refers to the type of debug policy
|
||||
DebugPolicyType = "debug"
|
||||
// SharedResourcePolicyType refers to the type of shared resource policy
|
||||
SharedResourcePolicyType = "shared-resource"
|
||||
)
|
||||
|
||||
// TopologyPolicySpec defines the spec of topology policy
|
||||
@@ -57,23 +53,3 @@ type OverridePolicySpec struct {
|
||||
Components []EnvComponentPatch `json:"components,omitempty"`
|
||||
Selector []string `json:"selector,omitempty"`
|
||||
}
|
||||
|
||||
// SharedResourcePolicySpec defines the spec of shared-resource policy
|
||||
type SharedResourcePolicySpec struct {
|
||||
Rules []SharedResourcePolicyRule `json:"rules"`
|
||||
}
|
||||
|
||||
// SharedResourcePolicyRule defines the rule for sharing resources
|
||||
type SharedResourcePolicyRule struct {
|
||||
Selector ResourcePolicyRuleSelector `json:"selector"`
|
||||
}
|
||||
|
||||
// FindStrategy return if the target resource should be shared
|
||||
func (in SharedResourcePolicySpec) FindStrategy(manifest *unstructured.Unstructured) bool {
|
||||
for _, rule := range in.Rules {
|
||||
if rule.Selector.Match(manifest) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
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 v1alpha1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func TestSharedResourcePolicySpec_FindStrategy(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
rules []SharedResourcePolicyRule
|
||||
input *unstructured.Unstructured
|
||||
matched bool
|
||||
}{
|
||||
"shared resource rule resourceName match": {
|
||||
rules: []SharedResourcePolicyRule{{
|
||||
Selector: ResourcePolicyRuleSelector{ResourceNames: []string{"example"}},
|
||||
}},
|
||||
input: &unstructured.Unstructured{Object: map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "example",
|
||||
},
|
||||
}},
|
||||
matched: true,
|
||||
},
|
||||
"shared resource rule resourceType match": {
|
||||
rules: []SharedResourcePolicyRule{{
|
||||
Selector: ResourcePolicyRuleSelector{ResourceTypes: []string{"ConfigMap", "Namespace"}},
|
||||
}},
|
||||
input: &unstructured.Unstructured{Object: map[string]interface{}{
|
||||
"kind": "Namespace",
|
||||
}},
|
||||
matched: true,
|
||||
},
|
||||
"shared resource rule mismatch": {
|
||||
rules: []SharedResourcePolicyRule{{
|
||||
Selector: ResourcePolicyRuleSelector{ResourceNames: []string{"mismatch"}},
|
||||
}},
|
||||
input: &unstructured.Unstructured{Object: map[string]interface{}{
|
||||
"kind": "Namespace",
|
||||
}},
|
||||
matched: false,
|
||||
},
|
||||
}
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
r := require.New(t)
|
||||
spec := SharedResourcePolicySpec{Rules: tc.rules}
|
||||
r.Equal(tc.matched, spec.FindStrategy(tc.input))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -595,11 +595,6 @@ func (in *RefObjectsComponentSpec) DeepCopyInto(out *RefObjectsComponentSpec) {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.URLs != nil {
|
||||
in, out := &in.URLs, &out.URLs
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RefObjectsComponentSpec.
|
||||
@@ -640,11 +635,6 @@ func (in *ResourcePolicyRuleSelector) DeepCopyInto(out *ResourcePolicyRuleSelect
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.ResourceNames != nil {
|
||||
in, out := &in.ResourceNames, &out.ResourceNames
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourcePolicyRuleSelector.
|
||||
@@ -657,44 +647,6 @@ func (in *ResourcePolicyRuleSelector) DeepCopy() *ResourcePolicyRuleSelector {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SharedResourcePolicyRule) DeepCopyInto(out *SharedResourcePolicyRule) {
|
||||
*out = *in
|
||||
in.Selector.DeepCopyInto(&out.Selector)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SharedResourcePolicyRule.
|
||||
func (in *SharedResourcePolicyRule) DeepCopy() *SharedResourcePolicyRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SharedResourcePolicyRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SharedResourcePolicySpec) DeepCopyInto(out *SharedResourcePolicySpec) {
|
||||
*out = *in
|
||||
if in.Rules != nil {
|
||||
in, out := &in.Rules, &out.Rules
|
||||
*out = make([]SharedResourcePolicyRule, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SharedResourcePolicySpec.
|
||||
func (in *SharedResourcePolicySpec) DeepCopy() *SharedResourcePolicySpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SharedResourcePolicySpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TopologyPolicySpec) DeepCopyInto(out *TopologyPolicySpec) {
|
||||
*out = *in
|
||||
|
||||
@@ -54,15 +54,8 @@ type WorkflowStep common.WorkflowStep
|
||||
|
||||
// Workflow defines workflow steps and other attributes
|
||||
type Workflow struct {
|
||||
Ref string `json:"ref,omitempty"`
|
||||
Mode *WorkflowExecuteMode `json:"mode,omitempty"`
|
||||
Steps []WorkflowStep `json:"steps,omitempty"`
|
||||
}
|
||||
|
||||
// WorkflowExecuteMode defines the mode of workflow execution
|
||||
type WorkflowExecuteMode struct {
|
||||
Steps common.WorkflowMode `json:"steps,omitempty"`
|
||||
SubSteps common.WorkflowMode `json:"subSteps,omitempty"`
|
||||
Ref string `json:"ref,omitempty"`
|
||||
Steps []WorkflowStep `json:"steps,omitempty"`
|
||||
}
|
||||
|
||||
// ApplicationSpec is the spec of Application
|
||||
|
||||
@@ -927,11 +927,6 @@ func (in *TraitDefinitionStatus) DeepCopy() *TraitDefinitionStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Workflow) DeepCopyInto(out *Workflow) {
|
||||
*out = *in
|
||||
if in.Mode != nil {
|
||||
in, out := &in.Mode, &out.Mode
|
||||
*out = new(WorkflowExecuteMode)
|
||||
**out = **in
|
||||
}
|
||||
if in.Steps != nil {
|
||||
in, out := &in.Steps, &out.Steps
|
||||
*out = make([]WorkflowStep, len(*in))
|
||||
@@ -951,29 +946,9 @@ func (in *Workflow) DeepCopy() *Workflow {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WorkflowExecuteMode) DeepCopyInto(out *WorkflowExecuteMode) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowExecuteMode.
|
||||
func (in *WorkflowExecuteMode) DeepCopy() *WorkflowExecuteMode {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(WorkflowExecuteMode)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WorkflowStep) DeepCopyInto(out *WorkflowStep) {
|
||||
*out = *in
|
||||
if in.Meta != nil {
|
||||
in, out := &in.Meta, &out.Meta
|
||||
*out = new(common.WorkflowStepMeta)
|
||||
**out = **in
|
||||
}
|
||||
if in.Properties != nil {
|
||||
in, out := &in.Properties, &out.Properties
|
||||
*out = new(runtime.RawExtension)
|
||||
|
||||
@@ -80,8 +80,6 @@ const (
|
||||
OpenapiV3JSONSchema string = "openapi-v3-json-schema"
|
||||
// UISchema is the key to store ui custom schema
|
||||
UISchema string = "ui-schema"
|
||||
// VelaQLConfigmapKey is the key to store velaql view
|
||||
VelaQLConfigmapKey string = "template"
|
||||
)
|
||||
|
||||
// CapabilityCategory defines the category of a capability
|
||||
|
||||
@@ -2198,17 +2198,6 @@ spec:
|
||||
a context in annotation. - should mark "finish" phase in
|
||||
status.conditions.'
|
||||
properties:
|
||||
mode:
|
||||
description: WorkflowExecuteMode defines the mode of workflow
|
||||
execution
|
||||
properties:
|
||||
steps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
subSteps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
type: object
|
||||
ref:
|
||||
type: string
|
||||
steps:
|
||||
@@ -2236,13 +2225,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta
|
||||
data of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow
|
||||
step.
|
||||
@@ -2289,13 +2271,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the
|
||||
meta data of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the
|
||||
workflow step.
|
||||
@@ -2317,8 +2292,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -2326,8 +2299,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -4002,13 +3973,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of
|
||||
a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -4053,13 +4017,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data
|
||||
of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow
|
||||
step.
|
||||
@@ -4081,8 +4038,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -4090,8 +4045,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
|
||||
@@ -1009,17 +1009,6 @@ spec:
|
||||
order, and each step: - will have a context in annotation. - should
|
||||
mark "finish" phase in status.conditions.'
|
||||
properties:
|
||||
mode:
|
||||
description: WorkflowExecuteMode defines the mode of workflow
|
||||
execution
|
||||
properties:
|
||||
steps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
subSteps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
type: object
|
||||
ref:
|
||||
type: string
|
||||
steps:
|
||||
@@ -1046,13 +1035,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of
|
||||
a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -1097,13 +1079,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data
|
||||
of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow
|
||||
step.
|
||||
@@ -1125,8 +1100,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -1134,8 +1107,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
|
||||
@@ -57,13 +57,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of a workflow
|
||||
step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -107,13 +100,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of a
|
||||
workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -133,8 +119,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -142,8 +126,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -159,16 +141,6 @@ spec:
|
||||
openAPIV3Schema:
|
||||
description: Workflow defines workflow steps and other attributes
|
||||
properties:
|
||||
mode:
|
||||
description: WorkflowExecuteMode defines the mode of workflow execution
|
||||
properties:
|
||||
steps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
subSteps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
type: object
|
||||
ref:
|
||||
type: string
|
||||
steps:
|
||||
@@ -194,13 +166,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of a workflow
|
||||
step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -244,13 +209,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of a
|
||||
workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -270,8 +228,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -279,8 +235,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
|
||||
@@ -196,14 +196,14 @@ spec:
|
||||
// +usage=Specifies a source the value of this var should come from
|
||||
valueFrom?: {
|
||||
// +usage=Selects a key of a secret in the pod's namespace
|
||||
secretKeyRef: {
|
||||
secretKeyRef?: {
|
||||
// +usage=The name of the secret in the pod's namespace to select from
|
||||
name: string
|
||||
// +usage=The key of the secret to select from. Must be a valid secret key
|
||||
key: string
|
||||
}
|
||||
// +usage=Selects a key of a config map in the pod's namespace
|
||||
configMapKeyRef: {
|
||||
configMapKeyRef?: {
|
||||
// +usage=The name of the config map in the pod's namespace to select from
|
||||
name: string
|
||||
// +usage=The key of the config map to select from. Must be a valid secret key
|
||||
|
||||
@@ -43,7 +43,7 @@ spec:
|
||||
volumeMounts: [{
|
||||
name: parameter.mountName
|
||||
mountPath: parameter.initMountPath
|
||||
}]
|
||||
}] + parameter.extraVolumeMounts
|
||||
}]
|
||||
// +patchKey=name
|
||||
volumes: [{
|
||||
@@ -97,5 +97,13 @@ spec:
|
||||
|
||||
// +usage=Specify the mount path of init container
|
||||
initMountPath: string
|
||||
|
||||
// +usage=Specify the extra volume mounts for the init container
|
||||
extraVolumeMounts: [...{
|
||||
// +usage=The name of the volume to be mounted
|
||||
name: string
|
||||
// +usage=The mountPath for mount in the init container
|
||||
mountPath: string
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
@@ -14,20 +14,21 @@ spec:
|
||||
cue:
|
||||
template: |
|
||||
#K8sObject: {
|
||||
apiVersion: string
|
||||
kind: string
|
||||
metadata: {
|
||||
name: string
|
||||
...
|
||||
}
|
||||
...
|
||||
}
|
||||
output: {
|
||||
if len(parameter.objects) > 0 {
|
||||
parameter.objects[0]
|
||||
}
|
||||
// +usage=The resource type for the Kubernetes objects
|
||||
resource?: string
|
||||
// +usage=The group name for the Kubernetes objects
|
||||
group?: string
|
||||
// +usage=If specified, fetch the Kubernetes objects with the name, exclusive to labelSelector
|
||||
name?: string
|
||||
// +usage=If specified, fetch the Kubernetes objects from the namespace. Otherwise, fetch from the application's namespace.
|
||||
namespace?: string
|
||||
// +usage=If specified, fetch the Kubernetes objects from the cluster. Otherwise, fetch from the local cluster.
|
||||
cluster?: string
|
||||
// +usage=If specified, fetch the Kubernetes objects according to the label selector, exclusive to name
|
||||
labelSelector?: [string]: string
|
||||
...
|
||||
}
|
||||
output: parameter.objects[0]
|
||||
outputs: {
|
||||
for i, v in parameter.objects {
|
||||
if i > 0 {
|
||||
@@ -35,7 +36,12 @@ spec:
|
||||
}
|
||||
}
|
||||
}
|
||||
parameter: objects: [...#K8sObject]
|
||||
parameter: {
|
||||
// +usage=If specified, application will fetch native Kubernetes objects according to the object description
|
||||
objects?: [...#K8sObject]
|
||||
// +usage=If specified, the objects in the urls will be loaded.
|
||||
urls?: [...string]
|
||||
}
|
||||
status:
|
||||
customStatus: |-
|
||||
if context.output.apiVersion == "apps/v1" && context.output.kind == "Deployment" {
|
||||
|
||||
@@ -14,10 +14,114 @@ spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
#Privileges: {
|
||||
// +usage=Specify the verbs to be allowed for the resource
|
||||
verbs: [...string]
|
||||
// +usage=Specify the apiGroups of the resource
|
||||
apiGroups?: [...string]
|
||||
// +usage=Specify the resources to be allowed
|
||||
resources?: [...string]
|
||||
// +usage=Specify the resourceNames to be allowed
|
||||
resourceNames?: [...string]
|
||||
// +usage=Specify the resource url to be allowed
|
||||
nonResourceURLs?: [...string]
|
||||
// +usage=Specify the scope of the privileges, default to be namespace scope
|
||||
scope: *"namespace" | "cluster"
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Specify the name of ServiceAccount
|
||||
name: string
|
||||
// +usage=Specify whether to create new ServiceAccount or not
|
||||
create: *false | bool
|
||||
// +usage=Specify the privileges of the ServiceAccount, if not empty, RoleBindings(ClusterRoleBindings) will be created
|
||||
privileges?: [...#Privileges]
|
||||
}
|
||||
// +patchStrategy=retainKeys
|
||||
patch: spec: template: spec: serviceAccountName: parameter.name
|
||||
_clusterPrivileges: [ for p in parameter.privileges if p.scope == "cluster" {p}]
|
||||
_namespacePrivileges: [ for p in parameter.privileges if p.scope == "namespace" {p}]
|
||||
outputs: {
|
||||
if parameter.create {
|
||||
"service-account": {
|
||||
apiVersion: "v1"
|
||||
kind: "ServiceAccount"
|
||||
metadata: name: parameter.name
|
||||
}
|
||||
}
|
||||
if parameter.privileges != _|_ {
|
||||
if len(_clusterPrivileges) > 0 {
|
||||
"cluster-role": {
|
||||
apiVersion: "rbac.authorization.k8s.io/v1"
|
||||
kind: "ClusterRole"
|
||||
metadata: name: "\(context.namespace):\(parameter.name)"
|
||||
rules: [ for p in _clusterPrivileges {
|
||||
verbs: p.verbs
|
||||
if p.apiGroups != _|_ {
|
||||
apiGroups: p.apiGroups
|
||||
}
|
||||
if p.resources != _|_ {
|
||||
resources: p.resources
|
||||
}
|
||||
if p.resourceNames != _|_ {
|
||||
resourceNames: p.resourceNames
|
||||
}
|
||||
if p.nonResourceURLs != _|_ {
|
||||
nonResourceURLs: p.nonResourceURLs
|
||||
}
|
||||
}]
|
||||
}
|
||||
"cluster-role-binding": {
|
||||
apiVersion: "rbac.authorization.k8s.io/v1"
|
||||
kind: "ClusterRoleBinding"
|
||||
metadata: name: "\(context.namespace):\(parameter.name)"
|
||||
roleRef: {
|
||||
apiGroup: "rbac.authorization.k8s.io"
|
||||
kind: "ClusterRole"
|
||||
name: "\(context.namespace):\(parameter.name)"
|
||||
}
|
||||
subjects: [{
|
||||
kind: "ServiceAccount"
|
||||
name: parameter.name
|
||||
namespace: "\(context.namespace)"
|
||||
}]
|
||||
}
|
||||
}
|
||||
if len(_namespacePrivileges) > 0 {
|
||||
role: {
|
||||
apiVersion: "rbac.authorization.k8s.io/v1"
|
||||
kind: "Role"
|
||||
metadata: name: parameter.name
|
||||
rules: [ for p in _namespacePrivileges {
|
||||
verbs: p.verbs
|
||||
if p.apiGroups != _|_ {
|
||||
apiGroups: p.apiGroups
|
||||
}
|
||||
if p.resources != _|_ {
|
||||
resources: p.resources
|
||||
}
|
||||
if p.resourceNames != _|_ {
|
||||
resourceNames: p.resourceNames
|
||||
}
|
||||
if p.nonResourceURLs != _|_ {
|
||||
nonResourceURLs: p.nonResourceURLs
|
||||
}
|
||||
}]
|
||||
}
|
||||
"role-binding": {
|
||||
apiVersion: "rbac.authorization.k8s.io/v1"
|
||||
kind: "RoleBinding"
|
||||
metadata: name: parameter.name
|
||||
roleRef: {
|
||||
apiGroup: "rbac.authorization.k8s.io"
|
||||
kind: "Role"
|
||||
name: parameter.name
|
||||
}
|
||||
subjects: [{
|
||||
kind: "ServiceAccount"
|
||||
name: parameter.name
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,11 @@ spec:
|
||||
// +usage=The key of the config map to select from. Must be a valid secret key
|
||||
key: string
|
||||
}
|
||||
// +usage=Specify the field reference for env
|
||||
fieldRef?: {
|
||||
// +usage=Specify the field path for env
|
||||
fieldPath: string
|
||||
}
|
||||
}
|
||||
}]
|
||||
|
||||
|
||||
@@ -64,6 +64,9 @@ spec:
|
||||
{
|
||||
name: "pvc-" + v.name
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -73,6 +76,9 @@ spec:
|
||||
{
|
||||
name: "configmap-" + v.name
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -103,6 +109,9 @@ spec:
|
||||
{
|
||||
name: "secret-" + v.name
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -133,6 +142,9 @@ spec:
|
||||
{
|
||||
name: "emptydir-" + v.name
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -141,12 +153,28 @@ spec:
|
||||
{
|
||||
name: "pvc-" + v.name
|
||||
devicePath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
volumesList: pvcVolumesList + configMapVolumesList + secretVolumesList + emptyDirVolumesList
|
||||
deDupVolumesArray: [
|
||||
for val in [
|
||||
for i, vi in volumesList {
|
||||
for j, vj in volumesList if j < i && vi.name == vj.name {
|
||||
_ignore: true
|
||||
}
|
||||
vi
|
||||
},
|
||||
] if val._ignore == _|_ {
|
||||
val
|
||||
},
|
||||
]
|
||||
patch: spec: template: spec: {
|
||||
// +patchKey=name
|
||||
volumes: pvcVolumesList + configMapVolumesList + secretVolumesList + emptyDirVolumesList
|
||||
volumes: deDupVolumesArray
|
||||
|
||||
containers: [{
|
||||
// +patchKey=name
|
||||
@@ -234,6 +262,7 @@ spec:
|
||||
name: string
|
||||
mountOnly: *false | bool
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
volumeMode: *"Filesystem" | string
|
||||
volumeName?: string
|
||||
accessModes: *["ReadWriteOnce"] | [...string]
|
||||
@@ -275,6 +304,7 @@ spec:
|
||||
configMapKey: string
|
||||
}]
|
||||
mountPath?: string
|
||||
subPath?: string
|
||||
defaultMode: *420 | int
|
||||
readOnly: *false | bool
|
||||
data?: {...}
|
||||
@@ -298,6 +328,7 @@ spec:
|
||||
secretKey: string
|
||||
}]
|
||||
mountPath?: string
|
||||
subPath?: string
|
||||
defaultMode: *420 | int
|
||||
readOnly: *false | bool
|
||||
stringData?: {...}
|
||||
@@ -313,6 +344,7 @@ spec:
|
||||
emptyDir?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
medium: *"" | "Memory"
|
||||
}]
|
||||
}
|
||||
|
||||
@@ -149,14 +149,14 @@ spec:
|
||||
// +usage=Specifies a source the value of this var should come from
|
||||
valueFrom?: {
|
||||
// +usage=Selects a key of a secret in the pod's namespace
|
||||
secretKeyRef: {
|
||||
secretKeyRef?: {
|
||||
// +usage=The name of the secret in the pod's namespace to select from
|
||||
name: string
|
||||
// +usage=The key of the secret to select from. Must be a valid secret key
|
||||
key: string
|
||||
}
|
||||
// +usage=Selects a key of a config map in the pod's namespace
|
||||
configMapKeyRef: {
|
||||
configMapKeyRef?: {
|
||||
// +usage=The name of the config map in the pod's namespace to select from
|
||||
name: string
|
||||
// +usage=The key of the config map to select from. Must be a valid secret key
|
||||
|
||||
@@ -20,7 +20,10 @@ spec:
|
||||
for v in parameter.volumeMounts.pvc {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -29,7 +32,10 @@ spec:
|
||||
for v in parameter.volumeMounts.configMap {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -38,7 +44,10 @@ spec:
|
||||
for v in parameter.volumeMounts.secret {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -47,7 +56,10 @@ spec:
|
||||
for v in parameter.volumeMounts.emptyDir {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -56,7 +68,10 @@ spec:
|
||||
for v in parameter.volumeMounts.hostPath {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -119,6 +134,19 @@ spec:
|
||||
},
|
||||
] | []
|
||||
}
|
||||
volumesList: volumesArray.pvc + volumesArray.configMap + volumesArray.secret + volumesArray.emptyDir + volumesArray.hostPath
|
||||
deDupVolumesArray: [
|
||||
for val in [
|
||||
for i, vi in volumesList {
|
||||
for j, vj in volumesList if j < i && vi.name == vj.name {
|
||||
_ignore: true
|
||||
}
|
||||
vi
|
||||
},
|
||||
] if val._ignore == _|_ {
|
||||
val
|
||||
},
|
||||
]
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
@@ -262,7 +290,7 @@ spec:
|
||||
}
|
||||
|
||||
if parameter["volumeMounts"] != _|_ {
|
||||
volumes: volumesArray.pvc + volumesArray.configMap + volumesArray.secret + volumesArray.emptyDir + volumesArray.hostPath
|
||||
volumes: deDupVolumesArray
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -375,6 +403,7 @@ spec:
|
||||
pvc?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
// +usage=The name of the PVC
|
||||
claimName: string
|
||||
}]
|
||||
@@ -382,6 +411,7 @@ spec:
|
||||
configMap?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
defaultMode: *420 | int
|
||||
cmName: string
|
||||
items?: [...{
|
||||
@@ -394,6 +424,7 @@ spec:
|
||||
secret?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
defaultMode: *420 | int
|
||||
secretName: string
|
||||
items?: [...{
|
||||
@@ -406,12 +437,14 @@ spec:
|
||||
emptyDir?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
medium: *"" | "Memory"
|
||||
}]
|
||||
// +usage=Mount HostPath type volume
|
||||
hostPath?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
path: string
|
||||
}]
|
||||
}
|
||||
|
||||
@@ -2198,17 +2198,6 @@ spec:
|
||||
a context in annotation. - should mark "finish" phase in
|
||||
status.conditions.'
|
||||
properties:
|
||||
mode:
|
||||
description: WorkflowExecuteMode defines the mode of workflow
|
||||
execution
|
||||
properties:
|
||||
steps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
subSteps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
type: object
|
||||
ref:
|
||||
type: string
|
||||
steps:
|
||||
@@ -2236,13 +2225,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta
|
||||
data of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow
|
||||
step.
|
||||
@@ -2289,13 +2271,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the
|
||||
meta data of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the
|
||||
workflow step.
|
||||
@@ -2317,8 +2292,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -2326,8 +2299,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -4002,13 +3973,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of
|
||||
a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -4053,13 +4017,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data
|
||||
of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow
|
||||
step.
|
||||
@@ -4081,8 +4038,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -4090,8 +4045,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
|
||||
@@ -1009,17 +1009,6 @@ spec:
|
||||
order, and each step: - will have a context in annotation. - should
|
||||
mark "finish" phase in status.conditions.'
|
||||
properties:
|
||||
mode:
|
||||
description: WorkflowExecuteMode defines the mode of workflow
|
||||
execution
|
||||
properties:
|
||||
steps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
subSteps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
type: object
|
||||
ref:
|
||||
type: string
|
||||
steps:
|
||||
@@ -1046,13 +1035,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of
|
||||
a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -1097,13 +1079,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data
|
||||
of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow
|
||||
step.
|
||||
@@ -1125,8 +1100,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -1134,8 +1107,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
|
||||
@@ -196,14 +196,14 @@ spec:
|
||||
// +usage=Specifies a source the value of this var should come from
|
||||
valueFrom?: {
|
||||
// +usage=Selects a key of a secret in the pod's namespace
|
||||
secretKeyRef: {
|
||||
secretKeyRef?: {
|
||||
// +usage=The name of the secret in the pod's namespace to select from
|
||||
name: string
|
||||
// +usage=The key of the secret to select from. Must be a valid secret key
|
||||
key: string
|
||||
}
|
||||
// +usage=Selects a key of a config map in the pod's namespace
|
||||
configMapKeyRef: {
|
||||
configMapKeyRef?: {
|
||||
// +usage=The name of the config map in the pod's namespace to select from
|
||||
name: string
|
||||
// +usage=The key of the config map to select from. Must be a valid secret key
|
||||
|
||||
@@ -43,7 +43,7 @@ spec:
|
||||
volumeMounts: [{
|
||||
name: parameter.mountName
|
||||
mountPath: parameter.initMountPath
|
||||
}]
|
||||
}] + parameter.extraVolumeMounts
|
||||
}]
|
||||
// +patchKey=name
|
||||
volumes: [{
|
||||
@@ -97,5 +97,13 @@ spec:
|
||||
|
||||
// +usage=Specify the mount path of init container
|
||||
initMountPath: string
|
||||
|
||||
// +usage=Specify the extra volume mounts for the init container
|
||||
extraVolumeMounts: [...{
|
||||
// +usage=The name of the volume to be mounted
|
||||
name: string
|
||||
// +usage=The mountPath for mount in the init container
|
||||
mountPath: string
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
@@ -14,20 +14,21 @@ spec:
|
||||
cue:
|
||||
template: |
|
||||
#K8sObject: {
|
||||
apiVersion: string
|
||||
kind: string
|
||||
metadata: {
|
||||
name: string
|
||||
...
|
||||
}
|
||||
...
|
||||
}
|
||||
output: {
|
||||
if len(parameter.objects) > 0 {
|
||||
parameter.objects[0]
|
||||
}
|
||||
// +usage=The resource type for the Kubernetes objects
|
||||
resource?: string
|
||||
// +usage=The group name for the Kubernetes objects
|
||||
group?: string
|
||||
// +usage=If specified, fetch the Kubernetes objects with the name, exclusive to labelSelector
|
||||
name?: string
|
||||
// +usage=If specified, fetch the Kubernetes objects from the namespace. Otherwise, fetch from the application's namespace.
|
||||
namespace?: string
|
||||
// +usage=If specified, fetch the Kubernetes objects from the cluster. Otherwise, fetch from the local cluster.
|
||||
cluster?: string
|
||||
// +usage=If specified, fetch the Kubernetes objects according to the label selector, exclusive to name
|
||||
labelSelector?: [string]: string
|
||||
...
|
||||
}
|
||||
output: parameter.objects[0]
|
||||
outputs: {
|
||||
for i, v in parameter.objects {
|
||||
if i > 0 {
|
||||
@@ -35,7 +36,12 @@ spec:
|
||||
}
|
||||
}
|
||||
}
|
||||
parameter: objects: [...#K8sObject]
|
||||
parameter: {
|
||||
// +usage=If specified, application will fetch native Kubernetes objects according to the object description
|
||||
objects?: [...#K8sObject]
|
||||
// +usage=If specified, the objects in the urls will be loaded.
|
||||
urls?: [...string]
|
||||
}
|
||||
status:
|
||||
customStatus: |-
|
||||
if context.output.apiVersion == "apps/v1" && context.output.kind == "Deployment" {
|
||||
|
||||
@@ -14,10 +14,114 @@ spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
#Privileges: {
|
||||
// +usage=Specify the verbs to be allowed for the resource
|
||||
verbs: [...string]
|
||||
// +usage=Specify the apiGroups of the resource
|
||||
apiGroups?: [...string]
|
||||
// +usage=Specify the resources to be allowed
|
||||
resources?: [...string]
|
||||
// +usage=Specify the resourceNames to be allowed
|
||||
resourceNames?: [...string]
|
||||
// +usage=Specify the resource url to be allowed
|
||||
nonResourceURLs?: [...string]
|
||||
// +usage=Specify the scope of the privileges, default to be namespace scope
|
||||
scope: *"namespace" | "cluster"
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Specify the name of ServiceAccount
|
||||
name: string
|
||||
// +usage=Specify whether to create new ServiceAccount or not
|
||||
create: *false | bool
|
||||
// +usage=Specify the privileges of the ServiceAccount, if not empty, RoleBindings(ClusterRoleBindings) will be created
|
||||
privileges?: [...#Privileges]
|
||||
}
|
||||
// +patchStrategy=retainKeys
|
||||
patch: spec: template: spec: serviceAccountName: parameter.name
|
||||
_clusterPrivileges: [ for p in parameter.privileges if p.scope == "cluster" {p}]
|
||||
_namespacePrivileges: [ for p in parameter.privileges if p.scope == "namespace" {p}]
|
||||
outputs: {
|
||||
if parameter.create {
|
||||
"service-account": {
|
||||
apiVersion: "v1"
|
||||
kind: "ServiceAccount"
|
||||
metadata: name: parameter.name
|
||||
}
|
||||
}
|
||||
if parameter.privileges != _|_ {
|
||||
if len(_clusterPrivileges) > 0 {
|
||||
"cluster-role": {
|
||||
apiVersion: "rbac.authorization.k8s.io/v1"
|
||||
kind: "ClusterRole"
|
||||
metadata: name: "\(context.namespace):\(parameter.name)"
|
||||
rules: [ for p in _clusterPrivileges {
|
||||
verbs: p.verbs
|
||||
if p.apiGroups != _|_ {
|
||||
apiGroups: p.apiGroups
|
||||
}
|
||||
if p.resources != _|_ {
|
||||
resources: p.resources
|
||||
}
|
||||
if p.resourceNames != _|_ {
|
||||
resourceNames: p.resourceNames
|
||||
}
|
||||
if p.nonResourceURLs != _|_ {
|
||||
nonResourceURLs: p.nonResourceURLs
|
||||
}
|
||||
}]
|
||||
}
|
||||
"cluster-role-binding": {
|
||||
apiVersion: "rbac.authorization.k8s.io/v1"
|
||||
kind: "ClusterRoleBinding"
|
||||
metadata: name: "\(context.namespace):\(parameter.name)"
|
||||
roleRef: {
|
||||
apiGroup: "rbac.authorization.k8s.io"
|
||||
kind: "ClusterRole"
|
||||
name: "\(context.namespace):\(parameter.name)"
|
||||
}
|
||||
subjects: [{
|
||||
kind: "ServiceAccount"
|
||||
name: parameter.name
|
||||
namespace: "\(context.namespace)"
|
||||
}]
|
||||
}
|
||||
}
|
||||
if len(_namespacePrivileges) > 0 {
|
||||
role: {
|
||||
apiVersion: "rbac.authorization.k8s.io/v1"
|
||||
kind: "Role"
|
||||
metadata: name: parameter.name
|
||||
rules: [ for p in _namespacePrivileges {
|
||||
verbs: p.verbs
|
||||
if p.apiGroups != _|_ {
|
||||
apiGroups: p.apiGroups
|
||||
}
|
||||
if p.resources != _|_ {
|
||||
resources: p.resources
|
||||
}
|
||||
if p.resourceNames != _|_ {
|
||||
resourceNames: p.resourceNames
|
||||
}
|
||||
if p.nonResourceURLs != _|_ {
|
||||
nonResourceURLs: p.nonResourceURLs
|
||||
}
|
||||
}]
|
||||
}
|
||||
"role-binding": {
|
||||
apiVersion: "rbac.authorization.k8s.io/v1"
|
||||
kind: "RoleBinding"
|
||||
metadata: name: parameter.name
|
||||
roleRef: {
|
||||
apiGroup: "rbac.authorization.k8s.io"
|
||||
kind: "Role"
|
||||
name: parameter.name
|
||||
}
|
||||
subjects: [{
|
||||
kind: "ServiceAccount"
|
||||
name: parameter.name
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,11 @@ spec:
|
||||
// +usage=The key of the config map to select from. Must be a valid secret key
|
||||
key: string
|
||||
}
|
||||
// +usage=Specify the field reference for env
|
||||
fieldRef?: {
|
||||
// +usage=Specify the field path for env
|
||||
fieldPath: string
|
||||
}
|
||||
}
|
||||
}]
|
||||
|
||||
|
||||
@@ -64,6 +64,9 @@ spec:
|
||||
{
|
||||
name: "pvc-" + v.name
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -73,6 +76,9 @@ spec:
|
||||
{
|
||||
name: "configmap-" + v.name
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -103,6 +109,9 @@ spec:
|
||||
{
|
||||
name: "secret-" + v.name
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -133,6 +142,9 @@ spec:
|
||||
{
|
||||
name: "emptydir-" + v.name
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -141,12 +153,28 @@ spec:
|
||||
{
|
||||
name: "pvc-" + v.name
|
||||
devicePath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
volumesList: pvcVolumesList + configMapVolumesList + secretVolumesList + emptyDirVolumesList
|
||||
deDupVolumesArray: [
|
||||
for val in [
|
||||
for i, vi in volumesList {
|
||||
for j, vj in volumesList if j < i && vi.name == vj.name {
|
||||
_ignore: true
|
||||
}
|
||||
vi
|
||||
},
|
||||
] if val._ignore == _|_ {
|
||||
val
|
||||
},
|
||||
]
|
||||
patch: spec: template: spec: {
|
||||
// +patchKey=name
|
||||
volumes: pvcVolumesList + configMapVolumesList + secretVolumesList + emptyDirVolumesList
|
||||
volumes: deDupVolumesArray
|
||||
|
||||
containers: [{
|
||||
// +patchKey=name
|
||||
@@ -234,6 +262,7 @@ spec:
|
||||
name: string
|
||||
mountOnly: *false | bool
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
volumeMode: *"Filesystem" | string
|
||||
volumeName?: string
|
||||
accessModes: *["ReadWriteOnce"] | [...string]
|
||||
@@ -275,6 +304,7 @@ spec:
|
||||
configMapKey: string
|
||||
}]
|
||||
mountPath?: string
|
||||
subPath?: string
|
||||
defaultMode: *420 | int
|
||||
readOnly: *false | bool
|
||||
data?: {...}
|
||||
@@ -298,6 +328,7 @@ spec:
|
||||
secretKey: string
|
||||
}]
|
||||
mountPath?: string
|
||||
subPath?: string
|
||||
defaultMode: *420 | int
|
||||
readOnly: *false | bool
|
||||
stringData?: {...}
|
||||
@@ -313,6 +344,7 @@ spec:
|
||||
emptyDir?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
medium: *"" | "Memory"
|
||||
}]
|
||||
}
|
||||
|
||||
@@ -149,14 +149,14 @@ spec:
|
||||
// +usage=Specifies a source the value of this var should come from
|
||||
valueFrom?: {
|
||||
// +usage=Selects a key of a secret in the pod's namespace
|
||||
secretKeyRef: {
|
||||
secretKeyRef?: {
|
||||
// +usage=The name of the secret in the pod's namespace to select from
|
||||
name: string
|
||||
// +usage=The key of the secret to select from. Must be a valid secret key
|
||||
key: string
|
||||
}
|
||||
// +usage=Selects a key of a config map in the pod's namespace
|
||||
configMapKeyRef: {
|
||||
configMapKeyRef?: {
|
||||
// +usage=The name of the config map in the pod's namespace to select from
|
||||
name: string
|
||||
// +usage=The key of the config map to select from. Must be a valid secret key
|
||||
|
||||
@@ -20,7 +20,10 @@ spec:
|
||||
for v in parameter.volumeMounts.pvc {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -29,7 +32,10 @@ spec:
|
||||
for v in parameter.volumeMounts.configMap {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -38,7 +44,10 @@ spec:
|
||||
for v in parameter.volumeMounts.secret {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -47,7 +56,10 @@ spec:
|
||||
for v in parameter.volumeMounts.emptyDir {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -56,7 +68,10 @@ spec:
|
||||
for v in parameter.volumeMounts.hostPath {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -119,6 +134,19 @@ spec:
|
||||
},
|
||||
] | []
|
||||
}
|
||||
volumesList: volumesArray.pvc + volumesArray.configMap + volumesArray.secret + volumesArray.emptyDir + volumesArray.hostPath
|
||||
deDupVolumesArray: [
|
||||
for val in [
|
||||
for i, vi in volumesList {
|
||||
for j, vj in volumesList if j < i && vi.name == vj.name {
|
||||
_ignore: true
|
||||
}
|
||||
vi
|
||||
},
|
||||
] if val._ignore == _|_ {
|
||||
val
|
||||
},
|
||||
]
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
@@ -262,7 +290,7 @@ spec:
|
||||
}
|
||||
|
||||
if parameter["volumeMounts"] != _|_ {
|
||||
volumes: volumesArray.pvc + volumesArray.configMap + volumesArray.secret + volumesArray.emptyDir + volumesArray.hostPath
|
||||
volumes: deDupVolumesArray
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -375,6 +403,7 @@ spec:
|
||||
pvc?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
// +usage=The name of the PVC
|
||||
claimName: string
|
||||
}]
|
||||
@@ -382,6 +411,7 @@ spec:
|
||||
configMap?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
defaultMode: *420 | int
|
||||
cmName: string
|
||||
items?: [...{
|
||||
@@ -394,6 +424,7 @@ spec:
|
||||
secret?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
defaultMode: *420 | int
|
||||
secretName: string
|
||||
items?: [...{
|
||||
@@ -406,12 +437,14 @@ spec:
|
||||
emptyDir?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
medium: *"" | "Memory"
|
||||
}]
|
||||
// +usage=Mount HostPath type volume
|
||||
hostPath?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
path: string
|
||||
}]
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/controller/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/packages"
|
||||
_ "github.com/oam-dev/kubevela/pkg/monitor/metrics"
|
||||
"github.com/oam-dev/kubevela/pkg/monitor/watcher"
|
||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
|
||||
@@ -55,7 +54,8 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/utils/system"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
oamwebhook "github.com/oam-dev/kubevela/pkg/webhook/core.oam.dev"
|
||||
wfTypes "github.com/oam-dev/kubevela/pkg/workflow/types"
|
||||
"github.com/oam-dev/kubevela/pkg/workflow"
|
||||
"github.com/oam-dev/kubevela/pkg/workflow/tasks/custom"
|
||||
"github.com/oam-dev/kubevela/version"
|
||||
)
|
||||
|
||||
@@ -141,9 +141,9 @@ func main() {
|
||||
standardcontroller.AddOptimizeFlags()
|
||||
standardcontroller.AddAdmissionFlags()
|
||||
flag.IntVar(&resourcekeeper.MaxDispatchConcurrent, "max-dispatch-concurrent", 10, "Set the max dispatch concurrent number, default is 10")
|
||||
flag.IntVar(&wfTypes.MaxWorkflowWaitBackoffTime, "max-workflow-wait-backoff-time", 60, "Set the max workflow wait backoff time, default is 60")
|
||||
flag.IntVar(&wfTypes.MaxWorkflowFailedBackoffTime, "max-workflow-failed-backoff-time", 300, "Set the max workflow wait backoff time, default is 300")
|
||||
flag.IntVar(&wfTypes.MaxWorkflowStepErrorRetryTimes, "max-workflow-step-error-retry-times", 10, "Set the max workflow step error retry times, default is 10")
|
||||
flag.IntVar(&workflow.MaxWorkflowWaitBackoffTime, "max-workflow-wait-backoff-time", 60, "Set the max workflow wait backoff time, default is 60")
|
||||
flag.IntVar(&workflow.MaxWorkflowFailedBackoffTime, "max-workflow-failed-backoff-time", 300, "Set the max workflow wait backoff time, default is 300")
|
||||
flag.IntVar(&custom.MaxWorkflowStepErrorRetryTimes, "max-workflow-step-error-retry-times", 10, "Set the max workflow step error retry times, default is 10")
|
||||
utilfeature.DefaultMutableFeatureGate.AddFlag(flag.CommandLine)
|
||||
|
||||
flag.Parse()
|
||||
@@ -323,12 +323,6 @@ func main() {
|
||||
}
|
||||
klog.InfoS("Use storage driver", "storageDriver", os.Getenv(system.StorageDriverEnv))
|
||||
|
||||
klog.Info("Start the vela application monitor")
|
||||
if err := watcher.StartApplicationMetricsWatcher(restConfig); err != nil {
|
||||
klog.ErrorS(err, "Unable to start application metrics watcher")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
klog.Info("Start the vela controller manager")
|
||||
|
||||
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 154 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 113 KiB |
@@ -1,47 +0,0 @@
|
||||
# Shared Resource
|
||||
|
||||
### Background
|
||||
|
||||
In KubeVela, by default, application **owns** resources.
|
||||
It means that resources create by the application should only be controlled by the application that creates it.
|
||||
|
||||
So there are basically two requirements for application creating resources:
|
||||
1. The resource must not exist before the application creating it. It exists, there will be a resource conflict error.
|
||||
2. The resource is expected to be only manageable through its creator. "Others" should not be able to modify it or edit it.
|
||||
|
||||
While dispatching resources, the application will
|
||||
1. Check if resource exists. If exists, check its labels.
|
||||
If "app.oam.dev/name" and "app.oam.dev/namespace" equals to the application's name and namespace, it means this resource is previously created by the same application and the dispatching operation now will become an update operation.
|
||||
The two labels identify the owner of the resource.
|
||||
2. If resource exists, but no label found, then this resource is created before this application. At this time, the application will report a resource conflict error.
|
||||
3. If resource exists, and the labels point to another application, then this resource is managed by other applications. At this time, the current application will also report a resource conflict error.
|
||||
|
||||
With these checks, different applications cannot manage the same resource.
|
||||
|
||||
### Usage
|
||||
|
||||
However, there are scenarios that these two requirements are not met. One of the scenarios is sharing across different Applications.
|
||||
For example, each application wants to create a ConfigMap, but their ConfigMaps are the same.
|
||||
|
||||
To achieve that, KubeVela application could utilize the `shared-resource` policy to make it possible.
|
||||
|
||||
#### create
|
||||
|
||||
When one resource is created as sharing resource, one special annotation `app.oam.dev/shared-by` will be added to the resource.
|
||||
It will record the "sharer" of the resource in time order. The application that firstly creates the resource will set its owner labels to itself.
|
||||
Then it will add itself to the sharer annotation.
|
||||
|
||||
#### share
|
||||
|
||||
When another application comes and wants to share the resource, it will check if the resource is sharable, aka there is at least one sharer in the sharer annotation.
|
||||
If it is sharable, it will add itself to the sharer annotation, but not modify the content of the resource.
|
||||
|
||||
#### delete
|
||||
|
||||
With this mechanism, only the owner of the resource can modify the resource (including updating and state-keeping). Other sharer can only see that resource.
|
||||
When the owner of the resource is gone (application is deleted or do not use this resource anymore), it will give the owner of the application to the next sharer. If no sharer exists, it will finally delete that resource.
|
||||
|
||||
See the following figures for details.
|
||||
|
||||

|
||||

|
||||
@@ -1,91 +0,0 @@
|
||||
## How to share resources across applications
|
||||
|
||||
Sometimes, you may want different applications to share the same resource.
|
||||
For example, you might have various applications that needs the same namespace to exist.
|
||||
In this case, you can use the `shared-resource` policy to declare which resources should be shared.
|
||||
|
||||
### Usage
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: app1
|
||||
spec:
|
||||
components:
|
||||
- name: ns1
|
||||
type: k8s-objects
|
||||
properties:
|
||||
objects:
|
||||
- apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: example
|
||||
- name: cm1
|
||||
type: k8s-objects
|
||||
properties:
|
||||
objects:
|
||||
- apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm1
|
||||
namespace: example
|
||||
data:
|
||||
key: value1
|
||||
policies:
|
||||
- name: shared-resource
|
||||
type: shared-resource
|
||||
properties:
|
||||
rules:
|
||||
- selector:
|
||||
resourceTypes: ["Namespace"]
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: app2
|
||||
spec:
|
||||
components:
|
||||
- name: ns2
|
||||
type: k8s-objects
|
||||
properties:
|
||||
objects:
|
||||
- apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: example
|
||||
- name: cm2
|
||||
type: k8s-objects
|
||||
properties:
|
||||
objects:
|
||||
- apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm2
|
||||
namespace: example
|
||||
data:
|
||||
key: value2
|
||||
policies:
|
||||
- name: shared-resource
|
||||
type: shared-resource
|
||||
properties:
|
||||
rules:
|
||||
- selector:
|
||||
resourceTypes: ["Namespace"]
|
||||
```
|
||||
|
||||
The above two applications will dispatch the same namespace "example".
|
||||
They will create two different ConfigMap inside namespace "example" respectively.
|
||||
|
||||
Both application use the `shared-resource` policy and declared the namespace resource as shared.
|
||||
In this way, there will be no conflict for creating the same namespace.
|
||||
If the `shared-resource` policy is not used, the second application will report error after it finds that the namespace "example" is managed by the first application.
|
||||
|
||||
The namespace will only be recycled when both applications are removed.
|
||||
|
||||
### Working Detail
|
||||
|
||||
One of the problem for sharing resource is that what will happen if different application holds different configuration for the shared resource.
|
||||
In the `shared-resource` policy, all sharers will be recorded by time order. The first sharer will be able to write the resource while other sharers can only read it. After the first sharer is deleted, it will give the control of the resource to the next sharer. If no sharer is handling it, the resource will be finally removed.
|
||||
@@ -25,3 +25,7 @@ spec:
|
||||
- name: my-mount
|
||||
mountPath: /test
|
||||
claimName: myclaim
|
||||
- name: my-mount
|
||||
mountPath: /test2
|
||||
subPath: /sub
|
||||
claimName: myclaim
|
||||
|
||||
@@ -16,8 +16,9 @@ spec:
|
||||
pvc:
|
||||
- name: test1
|
||||
mountPath: /test/mount/pvc
|
||||
- name: test2
|
||||
- name: test1
|
||||
mountPath: /test/mount2/pvc
|
||||
subPath: /sub
|
||||
configMap:
|
||||
- name: test1
|
||||
mountPath: /test/mount/cm
|
||||
|
||||
@@ -83,7 +83,7 @@ component-pod-view{appName=demo,appNs=default,cluster=prod,clusterNs=default,nam
|
||||
|
||||
#### describe
|
||||
|
||||
Query the pods detail information
|
||||
Query the pods detail infomation
|
||||
|
||||
#### parameter
|
||||
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
# Steps with if
|
||||
|
||||
Every step can specify a `if`, you can use the `if` to determine whether the step should be executed or not.
|
||||
|
||||
## Always
|
||||
|
||||
If you want to execute the step no matter what, for example, send a notification after the component is deployed even it's failed, you can use the `if` with the value `always` like:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: if-always-with-err
|
||||
namespace: default
|
||||
spec:
|
||||
components:
|
||||
- name: err-component
|
||||
type: k8s-objects
|
||||
properties:
|
||||
objects:
|
||||
- err: "error case"
|
||||
workflow:
|
||||
steps:
|
||||
- name: apply-err-comp
|
||||
type: apply-component
|
||||
properties:
|
||||
component: err-component
|
||||
- name: notification
|
||||
type: notification
|
||||
if: always
|
||||
properties:
|
||||
slack:
|
||||
url:
|
||||
value: <your slack webhook url>
|
||||
message:
|
||||
text: always
|
||||
```
|
||||
|
||||
## Custom Judgement
|
||||
|
||||
You can also write your own judgement logic to determine whether the step should be executed or not, note that the values of `if` will be executed as cue code. We support some built-in variables to use in `if`, they are:
|
||||
|
||||
* `status`: in this value, you can get the status of the step for judgement like `status.<step-name>.phase == "succeeded"`, or you can use the simplify way `status.<step-name>.succeeded`.
|
||||
* `inputs`: in this value, you can get the inputs of the step for judgement like `inputs.<input-name> == "value"`.
|
||||
|
||||
### Status Example
|
||||
|
||||
If you want to control the step by the status of another step, you can follow the example:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: if-timeout
|
||||
namespace: default
|
||||
spec:
|
||||
components:
|
||||
- name: comp-custom-timeout
|
||||
type: webservice
|
||||
properties:
|
||||
image: crccheck/hello-world
|
||||
port: 8000
|
||||
workflow:
|
||||
steps:
|
||||
- name: suspend
|
||||
timeout: 5s
|
||||
type: suspend
|
||||
- name: suspend2
|
||||
# or `status.suspend.reason == "Timeout"`
|
||||
if: status.suspend.timeout
|
||||
type: suspend
|
||||
timeout: 5s
|
||||
- name: notification-1
|
||||
type: notification
|
||||
if: suspend.timeout
|
||||
properties:
|
||||
slack:
|
||||
url:
|
||||
value: <your slack webhook url>
|
||||
message:
|
||||
text: suspend is timeout
|
||||
- name: notification-2
|
||||
type: notification
|
||||
if: status["notification-1"].succeeded
|
||||
properties:
|
||||
slack:
|
||||
url:
|
||||
value: <your slack webhook url>
|
||||
message:
|
||||
text: notification-1 is succeeded
|
||||
```
|
||||
|
||||
### Inputs example
|
||||
|
||||
If you want to control the step by the inputs of another step, you can follow the example:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: if-input
|
||||
namespace: default
|
||||
spec:
|
||||
components:
|
||||
- name: comp-custom-timeout
|
||||
type: webservice
|
||||
properties:
|
||||
image: crccheck/hello-world
|
||||
port: 8000
|
||||
workflow:
|
||||
steps:
|
||||
- name: suspend
|
||||
type: suspend
|
||||
timeout: 5s
|
||||
outputs:
|
||||
- name: test
|
||||
valueFrom: context.name + " message"
|
||||
- name: notification
|
||||
type: notification
|
||||
inputs:
|
||||
- from: test
|
||||
parameterKey: slack.message.text
|
||||
if: inputs.test == "if-input message"
|
||||
properties:
|
||||
slack:
|
||||
url:
|
||||
value: <your slack webhook url>
|
||||
message:
|
||||
text: from input
|
||||
```
|
||||
@@ -1,62 +0,0 @@
|
||||
# Timeout steps
|
||||
|
||||
Every step can specify a `timeout`, if the timeout expires and the step has not succeeded, the step will fail with the reason `Timeout`.
|
||||
|
||||
Here is an example:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: app-with-timeout
|
||||
namespace: default
|
||||
spec:
|
||||
components:
|
||||
- name: comp
|
||||
type: webservice
|
||||
properties:
|
||||
image: crccheck/hello-world
|
||||
port: 8000
|
||||
traits:
|
||||
- type: scaler
|
||||
properties:
|
||||
replicas: 10
|
||||
workflow:
|
||||
steps:
|
||||
- name: apply
|
||||
timeout: 1m
|
||||
type: apply-component
|
||||
properties:
|
||||
component: comp
|
||||
- name: suspend
|
||||
type: suspend
|
||||
timeout: 5s
|
||||
```
|
||||
|
||||
If the first step is succeeded in the time of `1m`, the second step will be executed. If the second step is not resumed in the time of `5s`, the suspend step will be failed with the reason `Timeout`, and the application will end up with the status of `WorkflowTerminated` like:
|
||||
|
||||
```yaml
|
||||
status:
|
||||
status: workflowTerminated
|
||||
workflow:
|
||||
...
|
||||
finished: true
|
||||
message: Terminated
|
||||
mode: StepByStep
|
||||
steps:
|
||||
- firstExecuteTime: "2022-06-22T09:19:42Z"
|
||||
id: gdcwh929ih
|
||||
lastExecuteTime: "2022-06-22T09:20:08Z"
|
||||
name: apply
|
||||
phase: succeeded
|
||||
type: apply-component
|
||||
- firstExecuteTime: "2022-06-22T09:20:08Z"
|
||||
id: rloz8axnju
|
||||
lastExecuteTime: "2022-06-22T09:20:13Z"
|
||||
name: suspend
|
||||
phase: failed
|
||||
reason: Timeout
|
||||
type: suspend
|
||||
suspend: false
|
||||
terminated: true
|
||||
```
|
||||
@@ -14,3 +14,10 @@ Edit a yaml file as `example.yaml`, then execute it with `vela up` command.
|
||||
|
||||
When executing the `step-group` step, the subSteps in the step group are executed in dag mode. The step group will only complete when all subSteps have been executed to completion.
|
||||
SubStep has the same execution behavior as a normal step.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -49,13 +49,13 @@ var _ = Describe("Addon Test", func() {
|
||||
It("Enable addon test-addon", func() {
|
||||
output, err := e2e.Exec("vela addon enable test-addon")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(ContainSubstring("enabled successfully."))
|
||||
Expect(output).To(ContainSubstring("enabled Successfully."))
|
||||
})
|
||||
|
||||
It("Upgrade addon test-addon", func() {
|
||||
output, err := e2e.Exec("vela addon upgrade test-addon")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(ContainSubstring("enabled successfully."))
|
||||
Expect(output).To(ContainSubstring("enabled Successfully."))
|
||||
})
|
||||
|
||||
It("Disable addon test-addon", func() {
|
||||
@@ -71,7 +71,7 @@ var _ = Describe("Addon Test", func() {
|
||||
It("Enable addon with input", func() {
|
||||
output, err := e2e.LongTimeExec("vela addon enable test-addon example=redis", 300*time.Second)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(ContainSubstring("enabled successfully."))
|
||||
Expect(output).To(ContainSubstring("enabled Successfully."))
|
||||
})
|
||||
|
||||
It("Disable addon test-addon", func() {
|
||||
@@ -83,12 +83,6 @@ var _ = Describe("Addon Test", func() {
|
||||
}, 60*time.Second).Should(Succeed())
|
||||
})
|
||||
|
||||
It("Enable local addon with . as path", func() {
|
||||
output, err := e2e.LongTimeExec("vela addon enable ../../e2e/addon/mock/testdata/sample/.", 600*time.Second)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(ContainSubstring("sample enabled successfully."))
|
||||
})
|
||||
|
||||
It("Test Change default namespace can work", func() {
|
||||
output, err := e2e.LongTimeExecWithEnv("vela addon list", 600*time.Second, []string{"DEFAULT_VELA_NS=test-vela"})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
@@ -97,7 +91,7 @@ var _ = Describe("Addon Test", func() {
|
||||
|
||||
output, err = e2e.LongTimeExecWithEnv("vela addon enable test-addon", 600*time.Second, []string{"DEFAULT_VELA_NS=test-vela"})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(ContainSubstring("enabled successfully."))
|
||||
Expect(output).To(ContainSubstring("enabled Successfully."))
|
||||
|
||||
Eventually(func(g Gomega) {
|
||||
g.Expect(k8sClient.Get(context.Background(), types.NamespacedName{Name: "addon-test-addon", Namespace: "test-vela"}, &v1beta1.Application{})).Should(BeNil())
|
||||
|
||||
15
e2e/addon/mock/testdata/sample/metadata.yaml
vendored
15
e2e/addon/mock/testdata/sample/metadata.yaml
vendored
@@ -1,15 +0,0 @@
|
||||
name: sample
|
||||
version: 1.0.1
|
||||
description: This is a test sample addon
|
||||
icon: https://www.terraform.io/assets/images/logo-text-8c3ba8a6.svg
|
||||
url: https://terraform.io/
|
||||
|
||||
tags: []
|
||||
|
||||
deployTo:
|
||||
control_plane: true
|
||||
runtime_cluster: false
|
||||
|
||||
dependencies: []
|
||||
|
||||
invisible: false
|
||||
@@ -1,3 +0,0 @@
|
||||
parameter: {
|
||||
example: *"default" | string
|
||||
}
|
||||
@@ -190,7 +190,7 @@ var ApplicationInitIntercativeCliContext = func(context string, appName string,
|
||||
var ApplicationDeleteWithWaitOptions = func(context string, appName string) bool {
|
||||
return ginkgo.Context(context, func() {
|
||||
ginkgo.It("should print successful deletion information", func() {
|
||||
cli := fmt.Sprintf("vela delete %s --wait -y", appName)
|
||||
cli := fmt.Sprintf("vela delete %s --wait", appName)
|
||||
output, err := e2e.ExecAndTerminate(cli)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(output).To(gomega.ContainSubstring("deleted"))
|
||||
@@ -218,7 +218,7 @@ var ApplicationDeleteWithForceOptions = func(context string, appName string) boo
|
||||
return k8sClient.Update(ctx, app)
|
||||
}, time.Second*3, time.Millisecond*300).Should(gomega.BeNil())
|
||||
|
||||
cli := fmt.Sprintf("vela delete %s --force -y", appName)
|
||||
cli := fmt.Sprintf("vela delete %s --force", appName)
|
||||
output, err := e2e.LongTimeExec(cli, 3*time.Minute)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(output).To(gomega.ContainSubstring("timed out"))
|
||||
@@ -230,7 +230,7 @@ var ApplicationDeleteWithForceOptions = func(context string, appName string) boo
|
||||
g.Expect(k8sClient.Update(ctx, app)).Should(gomega.Succeed())
|
||||
}, time.Second*5, time.Millisecond*300).Should(gomega.Succeed())
|
||||
|
||||
cli = fmt.Sprintf("vela delete %s --force -y", appName)
|
||||
cli = fmt.Sprintf("vela delete %s --force", appName)
|
||||
output, err = e2e.ExecAndTerminate(cli)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(output).To(gomega.ContainSubstring("deleted"))
|
||||
|
||||
@@ -133,7 +133,7 @@ var (
|
||||
WorkloadDeleteContext = func(context string, applicationName string) bool {
|
||||
return ginkgo.Context(context, func() {
|
||||
ginkgo.It("should print successful deletion information", func() {
|
||||
cli := fmt.Sprintf("vela delete %s -y", applicationName)
|
||||
cli := fmt.Sprintf("vela delete %s", applicationName)
|
||||
output, err := Exec(cli)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(output).To(gomega.ContainSubstring("deleted from namespace"))
|
||||
|
||||
26
go.mod
26
go.mod
@@ -23,7 +23,7 @@ require (
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/deckarep/golang-set v1.7.1
|
||||
github.com/emicklei/go-restful-openapi/v2 v2.3.0
|
||||
github.com/emicklei/go-restful/v3 v3.8.0
|
||||
github.com/emicklei/go-restful/v3 v3.0.0-rc2
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible
|
||||
github.com/fatih/camelcase v1.0.0
|
||||
github.com/fatih/color v1.13.0
|
||||
@@ -56,7 +56,7 @@ require (
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/onsi/ginkgo v1.16.5
|
||||
github.com/onsi/gomega v1.19.0
|
||||
github.com/opencontainers/runc v1.1.3 // indirect
|
||||
github.com/opencontainers/runc v1.0.3 // indirect
|
||||
github.com/openkruise/kruise-api v1.1.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.11.0
|
||||
@@ -105,18 +105,6 @@ require (
|
||||
sigs.k8s.io/yaml v1.3.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/docker/distribution v2.8.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/openkruise/rollouts v0.1.1-0.20220622054609-149e5a48da5e
|
||||
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
||||
golang.org/x/net v0.0.0-20220516155154-20f960328961 // indirect
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute v1.6.1 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
@@ -158,8 +146,9 @@ require (
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/creack/pty v1.1.11 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.2 // indirect
|
||||
github.com/docker/cli v20.10.16+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||
github.com/docker/docker v20.10.16+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.6.4 // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
@@ -201,6 +190,8 @@ require (
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/huandu/xstrings v1.3.2 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
@@ -210,6 +201,7 @@ require (
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||
github.com/klauspost/compress v1.15.4 // indirect
|
||||
github.com/kr/pretty v0.3.0 // indirect
|
||||
github.com/kr/pty v1.1.8 // indirect
|
||||
@@ -262,6 +254,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
|
||||
@@ -288,13 +281,16 @@ require (
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||
golang.org/x/net v0.0.0-20220516155154-20f960328961 // indirect
|
||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect
|
||||
golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3 // indirect
|
||||
google.golang.org/grpc v1.45.0 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
gopkg.in/gorp.v1 v1.7.2 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.63.2 // indirect
|
||||
|
||||
55
go.sum
55
go.sum
@@ -369,7 +369,6 @@ github.com/charithe/durationcheck v0.0.9/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6pr
|
||||
github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af/go.mod h1:Qjyv4H3//PWVzTeCezG2b9IRn6myJxJSr4TD/xo6ojU=
|
||||
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
|
||||
github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
|
||||
github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
|
||||
github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
@@ -379,7 +378,6 @@ github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLI
|
||||
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
|
||||
github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
|
||||
github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
|
||||
github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=
|
||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
|
||||
@@ -422,7 +420,6 @@ github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on
|
||||
github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
|
||||
github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw=
|
||||
github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ=
|
||||
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
||||
github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
@@ -534,9 +531,8 @@ github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/crossplane/crossplane-runtime v0.14.1-0.20210722005935-0b469fcc77cd h1:2ZdR/HyjXFIo6KxmM08jBLeiJs7GRdGmb6qPKQANGvI=
|
||||
github.com/crossplane/crossplane-runtime v0.14.1-0.20210722005935-0b469fcc77cd/go.mod h1:0sB8XOV2zy1GdZvSMY0/5QzKQJUiNSek08wbAYHJbws=
|
||||
github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg=
|
||||
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
|
||||
github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI=
|
||||
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
|
||||
github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
|
||||
github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
|
||||
@@ -617,9 +613,8 @@ github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao
|
||||
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emicklei/go-restful-openapi/v2 v2.3.0 h1:tDgSCzQrkk4N+Isos0zGBYX/GTINjmQuP9BvITbEe38=
|
||||
github.com/emicklei/go-restful-openapi/v2 v2.3.0/go.mod h1:bs67E3SEVgSmB3qDuRLqpS0NcpheqtsCCMhW2/jml1E=
|
||||
github.com/emicklei/go-restful/v3 v3.0.0-rc2 h1:UkWzdUozgtjQzYuqSNQy+PuYxD4/DCzYucakgzWKolU=
|
||||
github.com/emicklei/go-restful/v3 v3.0.0-rc2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw=
|
||||
github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/proto v1.6.15 h1:XbpwxmuOPrdES97FrSfpyy67SSCV/wBIKXqgJzh6hNw=
|
||||
github.com/emicklei/proto v1.6.15/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
|
||||
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||
@@ -901,7 +896,6 @@ github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblf
|
||||
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
|
||||
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godror/godror v0.24.2/go.mod h1:wZv/9vPiUib6tkoDl+AZ/QLf5YZgMravZ7jxH2eQWAE=
|
||||
github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
@@ -1511,9 +1505,8 @@ github.com/moby/moby v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible/
|
||||
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
|
||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||
github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
|
||||
github.com/moby/sys/mountinfo v0.4.1 h1:1O+1cHA1aujwEwwVMa2Xm2l+gIpUHyd3+D+d7LZh1kM=
|
||||
github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
|
||||
github.com/moby/sys/mountinfo v0.5.0 h1:2Ks8/r6lopsxWi9m58nlwjaeSzUX9iiL1vj5qB/9ObI=
|
||||
github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
|
||||
github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ=
|
||||
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
|
||||
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
|
||||
@@ -1608,8 +1601,6 @@ github.com/onsi/ginkgo v1.16.1/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvw
|
||||
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||
github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY=
|
||||
@@ -1629,7 +1620,6 @@ github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDs
|
||||
github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg=
|
||||
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
|
||||
github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
|
||||
github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
|
||||
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
|
||||
@@ -1652,8 +1642,8 @@ github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h
|
||||
github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
|
||||
github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
|
||||
github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w=
|
||||
github.com/opencontainers/runc v1.1.3/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg=
|
||||
github.com/opencontainers/runc v1.0.3 h1:1hbqejyQWCJBvtKAfdO0b1FmaEf2z/bxnjqbARass5k=
|
||||
github.com/opencontainers/runc v1.0.3/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
|
||||
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
@@ -1664,12 +1654,8 @@ github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mo
|
||||
github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
|
||||
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
|
||||
github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
|
||||
github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
|
||||
github.com/openkruise/kruise-api v1.0.0/go.mod h1:kxV/UA/vrf/hz3z+kL21c0NOawC6K1ZjaKcJFgiOwsE=
|
||||
github.com/openkruise/kruise-api v1.1.0 h1:ZRhV0FnxUp4XHc60YPkUqj2LJD4GRFB92qhtdgU6Zhc=
|
||||
github.com/openkruise/kruise-api v1.1.0/go.mod h1:kxV/UA/vrf/hz3z+kL21c0NOawC6K1ZjaKcJFgiOwsE=
|
||||
github.com/openkruise/rollouts v0.1.1-0.20220622054609-149e5a48da5e h1:jUMEDsA0OOpp0262pK8MV8M2glac+jIjx+q5Aydn6G0=
|
||||
github.com/openkruise/rollouts v0.1.1-0.20220622054609-149e5a48da5e/go.mod h1:SORsT96ssCqMJYSVA90v6Z52utlV2jxPlyGh4czRfHA=
|
||||
github.com/openshift/api v0.0.0-20210915110300-3cd8091317c4/go.mod h1:RsQCVJu4qhUawxxDP7pGlwU3IA4F01wYm3qKEu29Su8=
|
||||
github.com/openshift/api v0.0.0-20211209135129-c58d9f695577/go.mod h1:DoslCwtqUpr3d/gsbq4ZlkaMEdYqKxuypsDjorcHhME=
|
||||
github.com/openshift/build-machinery-go v0.0.0-20210115170933-e575b44a7a94/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE=
|
||||
@@ -1862,7 +1848,6 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh
|
||||
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||
github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
|
||||
github.com/securego/gosec/v2 v2.8.0/go.mod h1:hJZ6NT5TqoY+jmOsaxAV4cXoEdrMRLVaNPnSpUCvCZs=
|
||||
github.com/securego/gosec/v2 v2.9.1/go.mod h1:oDcDLcatOJxkCGaCaq8lua1jTnYf6Sou4wdiJ1n4iHc=
|
||||
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||
@@ -2205,7 +2190,6 @@ go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI=
|
||||
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
||||
golang.org/x/arch v0.0.0-20180920145803-b19384d3c130/go.mod h1:cYlCBUl1MsqxdiKgmc4uh7TxZfWSFLOGSRR090WDxt8=
|
||||
@@ -2382,7 +2366,6 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211215060638-4ddde0e984e9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
@@ -2555,20 +2538,16 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
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-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/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-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -3082,10 +3061,7 @@ k8s.io/api v0.21.1/go.mod h1:FstGROTmsSHBarKc8bylzXih8BLNYTiS3TZcsoEDg2s=
|
||||
k8s.io/api v0.21.2/go.mod h1:Lv6UGJZ1rlMI1qusN8ruAp9PUBFyBwpEHAdG24vIsiU=
|
||||
k8s.io/api v0.21.3/go.mod h1:hUgeYHUbBp23Ue4qdX9tR8/ANi/g3ehylAqDn9NWVOg=
|
||||
k8s.io/api v0.22.1/go.mod h1:bh13rkTp3F1XEaLGykbyRD2QaTTzPm0e/BMd8ptFONY=
|
||||
k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8=
|
||||
k8s.io/api v0.22.4/go.mod h1:Rgs+9gIGYC5laXQSZZ9JqT5NevNgoGiOdVWi1BAB3qk=
|
||||
k8s.io/api v0.22.4/go.mod h1:Rgs+9gIGYC5laXQSZZ9JqT5NevNgoGiOdVWi1BAB3qk=
|
||||
k8s.io/api v0.22.6/go.mod h1:q1F7IfaNrbi/83ebLy3YFQYLjPSNyunZ/IXQxMmbwCg=
|
||||
k8s.io/api v0.23.0/go.mod h1:8wmDdLBHBNxtOIytwLstXt5E9PddnZb0GaMcqsvDBpg=
|
||||
k8s.io/api v0.23.1/go.mod h1:WfXnOnwSqNtG62Y1CdjoMxh7r7u9QXGCkA1u0na2jgo=
|
||||
k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8=
|
||||
@@ -3101,9 +3077,7 @@ k8s.io/apiextensions-apiserver v0.18.6/go.mod h1:lv89S7fUysXjLZO7ke783xOwVTm6lKi
|
||||
k8s.io/apiextensions-apiserver v0.21.2/go.mod h1:+Axoz5/l3AYpGLlhJDfcVQzCerVYq3K3CvDMvw6X1RA=
|
||||
k8s.io/apiextensions-apiserver v0.21.3/go.mod h1:kl6dap3Gd45+21Jnh6utCx8Z2xxLm8LGDkprcd+KbsE=
|
||||
k8s.io/apiextensions-apiserver v0.22.1/go.mod h1:HeGmorjtRmRLE+Q8dJu6AYRoZccvCMsghwS8XTUYb2c=
|
||||
k8s.io/apiextensions-apiserver v0.22.2/go.mod h1:2E0Ve/isxNl7tWLSUDgi6+cmwHi5fQRdwGVCxbC+KFA=
|
||||
k8s.io/apiextensions-apiserver v0.22.4/go.mod h1:kH9lxD8dbJ+k0ZizGET55lFgdGjO8t45fgZnCVdZEpw=
|
||||
k8s.io/apiextensions-apiserver v0.22.6/go.mod h1:wNsLwy8mfIkGThiv4Qq/Hy4qRazViKXqmH5pfYiRKyY=
|
||||
k8s.io/apiextensions-apiserver v0.23.0/go.mod h1:xIFAEEDlAZgpVBl/1VSjGDmLoXAWRG40+GsWhKhAxY4=
|
||||
k8s.io/apiextensions-apiserver v0.23.5/go.mod h1:ntcPWNXS8ZPKN+zTXuzYMeg731CP0heCTl6gYBxLcuQ=
|
||||
k8s.io/apiextensions-apiserver v0.23.6 h1:v58cQ6Z0/GK1IXYr+oW0fnYl52o9LTY0WgoWvI8uv5Q=
|
||||
@@ -3133,9 +3107,7 @@ k8s.io/apimachinery v0.21.1/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswP
|
||||
k8s.io/apimachinery v0.21.2/go.mod h1:CdTY8fU/BlvAbJ2z/8kBwimGki5Zp8/fbVuLY8gJumM=
|
||||
k8s.io/apimachinery v0.21.3/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI=
|
||||
k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0=
|
||||
k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0=
|
||||
k8s.io/apimachinery v0.22.4/go.mod h1:yU6oA6Gnax9RrxGzVvPFFJ+mpnW6PBSqp0sx0I0HHW0=
|
||||
k8s.io/apimachinery v0.22.6/go.mod h1:ZvVLP5iLhwVFg2Yx9Gh5W0um0DUauExbRhe+2Z8I1EU=
|
||||
k8s.io/apimachinery v0.23.0/go.mod h1:fFCTTBKvKcwTPFzjlcxp91uPFZr+JA0FubU4fLzzFYc=
|
||||
k8s.io/apimachinery v0.23.1/go.mod h1:SADt2Kl8/sttJ62RRsi9MIV4o8f5S3coArm0Iu3fBno=
|
||||
k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM=
|
||||
@@ -3155,10 +3127,7 @@ k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q=
|
||||
k8s.io/apiserver v0.21.2/go.mod h1:lN4yBoGyiNT7SC1dmNk0ue6a5Wi6O3SWOIw91TsucQw=
|
||||
k8s.io/apiserver v0.21.3/go.mod h1:eDPWlZG6/cCCMj/JBcEpDoK+I+6i3r9GsChYBHSbAzU=
|
||||
k8s.io/apiserver v0.22.1/go.mod h1:2mcM6dzSt+XndzVQJX21Gx0/Klo7Aen7i0Ai6tIa400=
|
||||
k8s.io/apiserver v0.22.2/go.mod h1:vrpMmbyjWrgdyOvZTSpsusQq5iigKNWv9o9KlDAbBHI=
|
||||
k8s.io/apiserver v0.22.4/go.mod h1:38WmcUZiiy41A7Aty8/VorWRa8vDGqoUzDf2XYlku0E=
|
||||
k8s.io/apiserver v0.22.4/go.mod h1:38WmcUZiiy41A7Aty8/VorWRa8vDGqoUzDf2XYlku0E=
|
||||
k8s.io/apiserver v0.22.6/go.mod h1:OlL1rGa2kKWGj2JEXnwBcul/BwC9Twe95gm4ohtiIIs=
|
||||
k8s.io/apiserver v0.23.0/go.mod h1:Cec35u/9zAepDPPFyT+UMrgqOCjgJ5qtfVJDxjZYmt4=
|
||||
k8s.io/apiserver v0.23.1/go.mod h1:Bqt0gWbeM2NefS8CjWswwd2VNAKN6lUKR85Ft4gippY=
|
||||
k8s.io/apiserver v0.23.5/go.mod h1:7wvMtGJ42VRxzgVI7jkbKvMbuCbVbgsWFT7RyXiRNTw=
|
||||
@@ -3192,9 +3161,7 @@ k8s.io/client-go v0.21.1/go.mod h1:/kEw4RgW+3xnBGzvp9IWxKSNA+lXn3A7AuH3gdOAzLs=
|
||||
k8s.io/client-go v0.21.2/go.mod h1:HdJ9iknWpbl3vMGtib6T2PyI/VYxiZfq936WNVHBRrA=
|
||||
k8s.io/client-go v0.21.3/go.mod h1:+VPhCgTsaFmGILxR/7E1N0S+ryO010QBeNCv5JwRGYU=
|
||||
k8s.io/client-go v0.22.1/go.mod h1:BquC5A4UOo4qVDUtoc04/+Nxp1MeHcVc1HJm1KmG8kk=
|
||||
k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U=
|
||||
k8s.io/client-go v0.22.4/go.mod h1:Yzw4e5e7h1LNHA4uqnMVrpEpUs1hJOiuBsJKIlRCHDA=
|
||||
k8s.io/client-go v0.22.6/go.mod h1:TffU4AV2idZGeP+g3kdFZP+oHVHWPL1JYFySOALriw0=
|
||||
k8s.io/client-go v0.23.0/go.mod h1:hrDnpnK1mSr65lHHcUuIZIXDgEbzc7/683c6hyG4jTA=
|
||||
k8s.io/client-go v0.23.1/go.mod h1:6QSI8fEuqD4zgFK0xbdwfB/PthBsIxCJMa3s17WlcO0=
|
||||
k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4=
|
||||
@@ -3210,13 +3177,10 @@ k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRV
|
||||
k8s.io/code-generator v0.18.6/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c=
|
||||
k8s.io/code-generator v0.20.0/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg=
|
||||
k8s.io/code-generator v0.20.10/go.mod h1:i6FmG+QxaLxvJsezvZp0q/gAEzzOz3U53KFibghWToU=
|
||||
k8s.io/code-generator v0.20.10/go.mod h1:i6FmG+QxaLxvJsezvZp0q/gAEzzOz3U53KFibghWToU=
|
||||
k8s.io/code-generator v0.21.2/go.mod h1:8mXJDCB7HcRo1xiEQstcguZkbxZaqeUOrO9SsicWs3U=
|
||||
k8s.io/code-generator v0.21.3/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo=
|
||||
k8s.io/code-generator v0.22.1/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o=
|
||||
k8s.io/code-generator v0.22.2/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o=
|
||||
k8s.io/code-generator v0.22.4/go.mod h1:qjYl54pQ/emhkT0UxbufbREYJMWsHNNV/jSVwhYZQGw=
|
||||
k8s.io/code-generator v0.22.6/go.mod h1:iOZwYADSgFPNGWfqHFfg1V0TNJnl1t0WyZluQp4baqU=
|
||||
k8s.io/code-generator v0.23.0/go.mod h1:vQvOhDXhuzqiVfM/YHp+dmg10WDZCchJVObc9MvowsE=
|
||||
k8s.io/code-generator v0.23.1/go.mod h1:V7yn6VNTCWW8GqodYCESVo95fuiEg713S8B7WacWZDA=
|
||||
k8s.io/code-generator v0.23.5/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk=
|
||||
@@ -3237,9 +3201,7 @@ k8s.io/component-base v0.20.10/go.mod h1:ZKOEin1xu68aJzxgzl5DZSp5J1IrjAOPlPN90/t
|
||||
k8s.io/component-base v0.21.2/go.mod h1:9lvmIThzdlrJj5Hp8Z/TOgIkdfsNARQ1pT+3PByuiuc=
|
||||
k8s.io/component-base v0.21.3/go.mod h1:kkuhtfEHeZM6LkX0saqSK8PbdO7A0HigUngmhhrwfGQ=
|
||||
k8s.io/component-base v0.22.1/go.mod h1:0D+Bl8rrnsPN9v0dyYvkqFfBeAd4u7n77ze+p8CMiPo=
|
||||
k8s.io/component-base v0.22.2/go.mod h1:5Br2QhI9OTe79p+TzPe9JKNQYvEKbq9rTJDWllunGug=
|
||||
k8s.io/component-base v0.22.4/go.mod h1:MrSaQy4a3tFVViff8TZL6JHYSewNCLshZCwHYM58v5A=
|
||||
k8s.io/component-base v0.22.6/go.mod h1:ngHLefY4J5fq2fApNdbWyj4yh0lvw36do4aAjNN8rc8=
|
||||
k8s.io/component-base v0.23.0/go.mod h1:DHH5uiFvLC1edCpvcTDV++NKULdYYU6pR9Tt3HIKMKI=
|
||||
k8s.io/component-base v0.23.1/go.mod h1:6llmap8QtJIXGDd4uIWJhAq0Op8AtQo6bDW2RrNMTeo=
|
||||
k8s.io/component-base v0.23.5/go.mod h1:c5Nq44KZyt1aLl0IpHX82fhsn84Sb0jjzwjpcA42bY0=
|
||||
@@ -3288,7 +3250,6 @@ k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAG
|
||||
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE=
|
||||
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
|
||||
k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
|
||||
k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
|
||||
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4=
|
||||
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
|
||||
k8s.io/kubectl v0.0.0-20191219154910-1528d4eea6dd/go.mod h1:9ehGcuUGjXVZh0qbYSB0vvofQw2JQe6c6cO0k4wu/Oo=
|
||||
@@ -3314,7 +3275,6 @@ k8s.io/utils v0.0.0-20210707171843-4b05e18ac7d9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/
|
||||
k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20211208161948-7d6a63dca704/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
@@ -3358,7 +3318,6 @@ sigs.k8s.io/controller-runtime v0.6.0/go.mod h1:CpYf5pdNY/B352A1TFLAS2JVSlnGQ5O2
|
||||
sigs.k8s.io/controller-runtime v0.6.2/go.mod h1:vhcq/rlnENJ09SIRp3EveTaZ0yqH526hjf9iJdbUJ/E=
|
||||
sigs.k8s.io/controller-runtime v0.9.2/go.mod h1:TxzMCHyEUpaeuOiZx/bIdc2T81vfs/aKdvJt9wuu0zk=
|
||||
sigs.k8s.io/controller-runtime v0.9.5/go.mod h1:q6PpkM5vqQubEKUKOM6qr06oXGzOBcCby1DA9FbyZeA=
|
||||
sigs.k8s.io/controller-runtime v0.10.3/go.mod h1:CQp8eyUQZ/Q7PJvnIrB6/hgfTC1kBkGylwsLgOQi1WY=
|
||||
sigs.k8s.io/controller-runtime v0.11.0/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA=
|
||||
sigs.k8s.io/controller-runtime v0.11.1/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA=
|
||||
sigs.k8s.io/controller-runtime v0.11.2 h1:H5GTxQl0Mc9UjRJhORusqfJCIjBO8UtUxGggCwL1rLA=
|
||||
@@ -3399,11 +3358,7 @@ sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.0/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
sigs.k8s.io/testing_frameworks v0.1.2/go.mod h1:ToQrwSC3s8Xf/lADdZp3Mktcql9CG0UAmdJG9th5i0w=
|
||||
sigs.k8s.io/testing_frameworks v0.1.2/go.mod h1:ToQrwSC3s8Xf/lADdZp3Mktcql9CG0UAmdJG9th5i0w=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
|
||||
@@ -2198,17 +2198,6 @@ spec:
|
||||
a context in annotation. - should mark "finish" phase in
|
||||
status.conditions.'
|
||||
properties:
|
||||
mode:
|
||||
description: WorkflowExecuteMode defines the mode of workflow
|
||||
execution
|
||||
properties:
|
||||
steps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
subSteps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
type: object
|
||||
ref:
|
||||
type: string
|
||||
steps:
|
||||
@@ -2236,13 +2225,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta
|
||||
data of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow
|
||||
step.
|
||||
@@ -2289,13 +2271,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the
|
||||
meta data of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the
|
||||
workflow step.
|
||||
@@ -2317,8 +2292,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -2326,8 +2299,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -4002,13 +3973,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of
|
||||
a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -4053,13 +4017,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data
|
||||
of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow
|
||||
step.
|
||||
@@ -4081,8 +4038,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -4090,8 +4045,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
|
||||
@@ -1010,17 +1010,6 @@ spec:
|
||||
order, and each step: - will have a context in annotation. - should
|
||||
mark "finish" phase in status.conditions.'
|
||||
properties:
|
||||
mode:
|
||||
description: WorkflowExecuteMode defines the mode of workflow
|
||||
execution
|
||||
properties:
|
||||
steps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
subSteps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
type: object
|
||||
ref:
|
||||
type: string
|
||||
steps:
|
||||
@@ -1047,13 +1036,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of
|
||||
a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -1098,13 +1080,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data
|
||||
of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow
|
||||
step.
|
||||
@@ -1126,8 +1101,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -1135,8 +1108,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
|
||||
@@ -57,13 +57,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of a workflow
|
||||
step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -107,13 +100,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of a
|
||||
workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -133,8 +119,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -142,8 +126,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -159,16 +141,6 @@ spec:
|
||||
openAPIV3Schema:
|
||||
description: Workflow defines workflow steps and other attributes
|
||||
properties:
|
||||
mode:
|
||||
description: WorkflowExecuteMode defines the mode of workflow execution
|
||||
properties:
|
||||
steps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
subSteps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
type: object
|
||||
ref:
|
||||
type: string
|
||||
steps:
|
||||
@@ -194,13 +166,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of a workflow
|
||||
step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -244,13 +209,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of a
|
||||
workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -270,8 +228,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -279,8 +235,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
|
||||
@@ -60,10 +60,7 @@ KUSTOMIZE_VERSION ?= 4.5.4
|
||||
KUSTOMIZE = $(shell pwd)/bin/kustomize
|
||||
.PHONY: kustomize
|
||||
kustomize:
|
||||
ifneq (, $(shell kustomize version | grep $(KUSTOMIZE_VERSION)))
|
||||
KUSTOMIZE=$(shell which kustomize)
|
||||
else ifneq (, $(shell $(KUSTOMIZE) version | grep $(KUSTOMIZE_VERSION)))
|
||||
else
|
||||
ifeq (, $(shell $(KUSTOMIZE) version | grep $(KUSTOMIZE_VERSION)))
|
||||
@{ \
|
||||
set -eo pipefail ;\
|
||||
echo "installing kustomize-v$(KUSTOMIZE_VERSION) into $(shell pwd)/bin" ;\
|
||||
|
||||
@@ -94,9 +94,6 @@ const (
|
||||
// DefSchemaName is the addon definition schemas dir name
|
||||
DefSchemaName string = "schemas"
|
||||
|
||||
// ViewDirName is the addon views dir name
|
||||
ViewDirName string = "views"
|
||||
|
||||
// AddonParameterDataKey is the key of parameter in addon args secrets
|
||||
AddonParameterDataKey string = "addonParameterDataKey"
|
||||
|
||||
@@ -194,7 +191,7 @@ type Pattern struct {
|
||||
}
|
||||
|
||||
// Patterns is the file pattern that the addon should be in
|
||||
var Patterns = []Pattern{{Value: ReadmeFileName}, {Value: MetadataFileName}, {Value: TemplateFileName}, {Value: ParameterFileName}, {IsDir: true, Value: ResourcesDirName}, {IsDir: true, Value: DefinitionsDirName}, {IsDir: true, Value: DefSchemaName}, {IsDir: true, Value: ViewDirName}}
|
||||
var Patterns = []Pattern{{Value: ReadmeFileName}, {Value: MetadataFileName}, {Value: TemplateFileName}, {Value: ParameterFileName}, {IsDir: true, Value: ResourcesDirName}, {IsDir: true, Value: DefinitionsDirName}, {IsDir: true, Value: DefSchemaName}}
|
||||
|
||||
// GetPatternFromItem will check if the file path has a valid pattern, return empty string if it's invalid.
|
||||
// AsyncReader is needed to calculate relative path
|
||||
@@ -309,7 +306,6 @@ func GetInstallPackageFromReader(r AsyncReader, meta *SourceMeta, uiData *UIData
|
||||
TemplateFileName: readTemplate,
|
||||
ResourcesDirName: readResFile,
|
||||
DefSchemaName: readDefSchemaFile,
|
||||
ViewDirName: readViewFile,
|
||||
}
|
||||
ptItems := ClassifyItemByPattern(meta, r)
|
||||
|
||||
@@ -412,24 +408,6 @@ func readDefFile(a *UIData, reader AsyncReader, readPath string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// readViewFile read single view file
|
||||
func readViewFile(a *InstallPackage, reader AsyncReader, readPath string) error {
|
||||
b, err := reader.ReadFile(readPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
filename := path.Base(readPath)
|
||||
switch filepath.Ext(filename) {
|
||||
case ".cue":
|
||||
a.CUEViews = append(a.CUEViews, ElementFile{Data: b, Name: filepath.Base(readPath)})
|
||||
case ".yaml", ".yml":
|
||||
a.YAMLViews = append(a.YAMLViews, ElementFile{Data: b, Name: filepath.Base(readPath)})
|
||||
default:
|
||||
// skip other file formats
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readMetadata(a *UIData, reader AsyncReader, readPath string) error {
|
||||
b, err := reader.ReadFile(readPath)
|
||||
if err != nil {
|
||||
@@ -734,10 +712,7 @@ func RenderApp(ctx context.Context, addon *InstallPackage, k8sClient client.Clie
|
||||
if app.Spec.Policies == nil {
|
||||
app.Spec.Policies = []v1beta1.AppPolicy{}
|
||||
}
|
||||
body, err := json.Marshal(map[string][]string{types.ClustersArg: deployClusters})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
body, _ := json.Marshal(map[string][]string{types.ClustersArg: deployClusters})
|
||||
app.Spec.Policies = append(app.Spec.Policies, v1beta1.AppPolicy{
|
||||
Name: "specified-addon-clusters",
|
||||
Type: v1alpha1.TopologyPolicyType,
|
||||
@@ -831,26 +806,6 @@ func RenderDefinitionSchema(addon *InstallPackage) ([]*unstructured.Unstructured
|
||||
return schemaConfigmaps, nil
|
||||
}
|
||||
|
||||
// RenderViews will render views in addons.
|
||||
func RenderViews(addon *InstallPackage) ([]*unstructured.Unstructured, error) {
|
||||
views := make([]*unstructured.Unstructured, 0)
|
||||
for _, view := range addon.YAMLViews {
|
||||
obj, err := renderObject(view)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
views = append(views, obj)
|
||||
}
|
||||
for _, view := range addon.CUEViews {
|
||||
obj, err := renderCUEView(view)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
views = append(views, obj)
|
||||
}
|
||||
return views, nil
|
||||
}
|
||||
|
||||
func allocateDomainForAddon(ctx context.Context, k8sClient client.Client) ([]ObservabilityEnvironment, error) {
|
||||
secrets, err := multicluster.ListExistingClusterSecrets(ctx, k8sClient)
|
||||
if err != nil {
|
||||
@@ -995,16 +950,6 @@ func renderSchemaConfigmap(elem ElementFile) (*unstructured.Unstructured, error)
|
||||
return util.Object2Unstructured(cm)
|
||||
}
|
||||
|
||||
func renderCUEView(elem ElementFile) (*unstructured.Unstructured, error) {
|
||||
cm := v1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"},
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: types.DefaultKubeVelaNS, Name: strings.Split(elem.Name, ".")[0]},
|
||||
Data: map[string]string{
|
||||
types.VelaQLConfigmapKey: elem.Data,
|
||||
}}
|
||||
return util.Object2Unstructured(cm)
|
||||
}
|
||||
|
||||
// renderCUETemplate will return a component from cue template
|
||||
func renderCUETemplate(elem ElementFile, parameters string, args map[string]interface{}, metadata Meta) (*common2.ApplicationComponent, error) {
|
||||
bt, err := json.Marshal(args)
|
||||
@@ -1308,11 +1253,6 @@ func (h *Installer) dispatchAddonResource(addon *InstallPackage) error {
|
||||
return errors.Wrap(err, "render addon definitions' schema fail")
|
||||
}
|
||||
|
||||
views, err := RenderViews(addon)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "render addon views fail")
|
||||
}
|
||||
|
||||
if err := passDefInAppAnnotation(defs, app); err != nil {
|
||||
return errors.Wrapf(err, "cannot pass definition to addon app's annotation")
|
||||
}
|
||||
@@ -1337,14 +1277,6 @@ func (h *Installer) dispatchAddonResource(addon *InstallPackage) error {
|
||||
}
|
||||
}
|
||||
|
||||
for _, view := range views {
|
||||
addOwner(view, app)
|
||||
err = h.apply.Apply(h.ctx, view, apply.DisableUpdateAnnotation())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if h.args != nil && len(h.args) > 0 {
|
||||
sec := RenderArgsSecret(addon, h.args)
|
||||
addOwner(sec, app)
|
||||
|
||||
@@ -378,23 +378,6 @@ var _ = Describe("test enable addon in local dir", func() {
|
||||
})
|
||||
})
|
||||
|
||||
var _ = Describe("test enable addon which applies the views independently", func() {
|
||||
BeforeEach(func() {
|
||||
app := v1beta1.Application{ObjectMeta: metav1.ObjectMeta{Namespace: "vela-system", Name: "addon-test-view"}}
|
||||
Expect(k8sClient.Delete(ctx, &app)).Should(SatisfyAny(BeNil(), util.NotFoundMatcher{}))
|
||||
})
|
||||
|
||||
It("test enable addon which applies the views independently", func() {
|
||||
ctx := context.Background()
|
||||
err := EnableAddonByLocalDir(ctx, "test-view", "./testdata/test-view", 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-test-view"}, &app)).Should(BeNil())
|
||||
configMap := v1.ConfigMap{}
|
||||
Expect(k8sClient.Get(ctx, types2.NamespacedName{Namespace: "vela-system", Name: "pod-view"}, &configMap)).Should(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
const (
|
||||
appYaml = `apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
|
||||
@@ -290,30 +290,6 @@ func TestRenderDefinitions(t *testing.T) {
|
||||
assert.Nil(t, app.Spec.Workflow)
|
||||
}
|
||||
|
||||
func TestRenderViews(t *testing.T) {
|
||||
addonDeployToRuntime := viewAddon
|
||||
addonDeployToRuntime.Meta.DeployTo = &DeployTo{
|
||||
DisableControlPlane: false,
|
||||
RuntimeCluster: false,
|
||||
}
|
||||
views, err := RenderViews(&addonDeployToRuntime)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(views), 2)
|
||||
|
||||
view := views[0]
|
||||
assert.Equal(t, view.GetKind(), "ConfigMap")
|
||||
assert.Equal(t, view.GetAPIVersion(), "v1")
|
||||
assert.Equal(t, view.GetNamespace(), types.DefaultKubeVelaNS)
|
||||
assert.Equal(t, view.GetName(), "cloud-resource-view")
|
||||
|
||||
view = views[1]
|
||||
assert.Equal(t, view.GetKind(), "ConfigMap")
|
||||
assert.Equal(t, view.GetAPIVersion(), "v1")
|
||||
assert.Equal(t, view.GetNamespace(), types.DefaultKubeVelaNS)
|
||||
assert.Equal(t, view.GetName(), "pod-view")
|
||||
|
||||
}
|
||||
|
||||
func TestRenderK8sObjects(t *testing.T) {
|
||||
addonMultiYaml := multiYamlAddon
|
||||
addonMultiYaml.Meta.DeployTo = &DeployTo{
|
||||
@@ -501,24 +477,6 @@ var multiYamlAddon = InstallPackage{
|
||||
},
|
||||
}
|
||||
|
||||
var viewAddon = InstallPackage{
|
||||
Meta: Meta{
|
||||
Name: "test-render-view-addon",
|
||||
},
|
||||
YAMLViews: []ElementFile{
|
||||
{
|
||||
Data: testYAMLView,
|
||||
Name: "cloud-resource-view",
|
||||
},
|
||||
},
|
||||
CUEViews: []ElementFile{
|
||||
{
|
||||
Data: testCUEView,
|
||||
Name: "pod-view",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var testCueDef = `annotations: {
|
||||
type: "trait"
|
||||
annotations: {}
|
||||
@@ -597,125 +555,6 @@ spec:
|
||||
- containerPort: 80
|
||||
`
|
||||
|
||||
var testYAMLView = `
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata:
|
||||
name: "cloud-resource-view"
|
||||
namespace: "vela-system"
|
||||
data:
|
||||
template: |
|
||||
import (
|
||||
"vela/ql"
|
||||
)
|
||||
|
||||
parameter: {
|
||||
appName: string
|
||||
appNs: string
|
||||
}
|
||||
resources: ql.#ListResourcesInApp & {
|
||||
app: {
|
||||
name: parameter.appName
|
||||
namespace: parameter.appNs
|
||||
filter: {
|
||||
"apiVersion": "terraform.core.oam.dev/v1beta1"
|
||||
"kind": "Configuration"
|
||||
}
|
||||
withStatus: true
|
||||
}
|
||||
}
|
||||
status: {
|
||||
if resources.err == _|_ {
|
||||
"cloud-resources": [ for i, resource in resources.list {
|
||||
resource.object
|
||||
}]
|
||||
}
|
||||
if resources.err != _|_ {
|
||||
error: resources.err
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
`
|
||||
var testCUEView = `
|
||||
import (
|
||||
"vela/ql"
|
||||
)
|
||||
|
||||
parameter: {
|
||||
name: string
|
||||
namespace: string
|
||||
cluster: *"" | string
|
||||
}
|
||||
pod: ql.#Read & {
|
||||
value: {
|
||||
apiVersion: "v1"
|
||||
kind: "Pod"
|
||||
metadata: {
|
||||
name: parameter.name
|
||||
namespace: parameter.namespace
|
||||
}
|
||||
}
|
||||
cluster: parameter.cluster
|
||||
}
|
||||
eventList: ql.#SearchEvents & {
|
||||
value: {
|
||||
apiVersion: "v1"
|
||||
kind: "Pod"
|
||||
metadata: pod.value.metadata
|
||||
}
|
||||
cluster: parameter.cluster
|
||||
}
|
||||
podMetrics: ql.#Read & {
|
||||
cluster: parameter.cluster
|
||||
value: {
|
||||
apiVersion: "metrics.k8s.io/v1beta1"
|
||||
kind: "PodMetrics"
|
||||
metadata: {
|
||||
name: parameter.name
|
||||
namespace: parameter.namespace
|
||||
}
|
||||
}
|
||||
}
|
||||
status: {
|
||||
if pod.err == _|_ {
|
||||
containers: [ for container in pod.value.spec.containers {
|
||||
name: container.name
|
||||
image: container.image
|
||||
resources: {
|
||||
if container.resources.limits != _|_ {
|
||||
limits: container.resources.limits
|
||||
}
|
||||
if container.resources.requests != _|_ {
|
||||
requests: container.resources.requests
|
||||
}
|
||||
if podMetrics.err == _|_ {
|
||||
usage: {for containerUsage in podMetrics.value.containers {
|
||||
if containerUsage.name == container.name {
|
||||
cpu: containerUsage.usage.cpu
|
||||
memory: containerUsage.usage.memory
|
||||
}
|
||||
}}
|
||||
}
|
||||
}
|
||||
if pod.value.status.containerStatuses != _|_ {
|
||||
status: {for containerStatus in pod.value.status.containerStatuses if containerStatus.name == container.name {
|
||||
state: containerStatus.state
|
||||
restartCount: containerStatus.restartCount
|
||||
}}
|
||||
}
|
||||
}]
|
||||
if eventList.err == _|_ {
|
||||
events: eventList.list
|
||||
}
|
||||
}
|
||||
if pod.err != _|_ {
|
||||
error: pod.err
|
||||
}
|
||||
}
|
||||
|
||||
`
|
||||
|
||||
func TestRenderApp4Observability(t *testing.T) {
|
||||
k8sClient := fake.NewClientBuilder().Build()
|
||||
testcases := []struct {
|
||||
@@ -802,13 +641,6 @@ func TestGetPatternFromItem(t *testing.T) {
|
||||
gitItemName := "parameter.cue"
|
||||
gitItemType := FileType
|
||||
gitItemPath := "addons/terraform/resources/parameter.cue"
|
||||
|
||||
viewOSSR := localReader{
|
||||
dir: "./testdata/test-view",
|
||||
name: "test-view",
|
||||
}
|
||||
viewPath := filepath.Join("./testdata/test-view/views/pod-view.cue", "pod-view.cue")
|
||||
|
||||
testCases := []struct {
|
||||
caseName string
|
||||
item Item
|
||||
@@ -834,17 +666,6 @@ func TestGetPatternFromItem(t *testing.T) {
|
||||
meetPattern: "resources/parameter.cue",
|
||||
r: gitR,
|
||||
},
|
||||
{
|
||||
caseName: "views case",
|
||||
item: OSSItem{
|
||||
tp: FileType,
|
||||
path: viewPath,
|
||||
name: "pod-view.cue",
|
||||
},
|
||||
root: "test-view",
|
||||
meetPattern: "views",
|
||||
r: viewOSSR,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
res := GetPatternFromItem(tc.item, tc.r, tc.root)
|
||||
@@ -1125,36 +946,6 @@ func TestReadDefFile(t *testing.T) {
|
||||
assert.True(t, len(uiData.Definitions) == 1)
|
||||
}
|
||||
|
||||
// Test readDefFile only accept .cue
|
||||
func TestReadViewFile(t *testing.T) {
|
||||
|
||||
// setup test data
|
||||
testAddonName := "test-view"
|
||||
testAddonDir := fmt.Sprintf("./testdata/%s", testAddonName)
|
||||
reader := localReader{dir: testAddonDir, name: testAddonName}
|
||||
metas, err := reader.ListAddonMeta()
|
||||
testAddonMeta := metas[testAddonName]
|
||||
assert.NoError(t, err)
|
||||
|
||||
// run test
|
||||
var addon = &InstallPackage{}
|
||||
ptItems := ClassifyItemByPattern(&testAddonMeta, reader)
|
||||
items := ptItems[ViewDirName]
|
||||
|
||||
for _, it := range items {
|
||||
err := readViewFile(addon, reader, reader.RelativePath(it))
|
||||
if err != nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
notExistErr := readViewFile(addon, reader, "not-exist.cue")
|
||||
assert.Error(t, notExistErr)
|
||||
|
||||
// verify
|
||||
assert.True(t, len(addon.CUEViews) == 1)
|
||||
assert.True(t, len(addon.YAMLViews) == 1)
|
||||
}
|
||||
|
||||
func TestRenderCUETemplate(t *testing.T) {
|
||||
fileDate, err := os.ReadFile("./testdata/example/resources/configmap.cue")
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -1,378 +0,0 @@
|
||||
/*
|
||||
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 addon
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
|
||||
"cuelang.org/go/cue"
|
||||
"cuelang.org/go/cue/format"
|
||||
"cuelang.org/go/encoding/gocode/gocodec"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
)
|
||||
|
||||
// CreateAddonFromHelmChart creates an addon scaffold from a Helm Chart, with a Helm component inside
|
||||
func CreateAddonFromHelmChart(addonName, addonPath, helmRepoURL, chartName, chartVersion string) error {
|
||||
if len(addonName) == 0 || len(helmRepoURL) == 0 || len(chartName) == 0 || len(chartVersion) == 0 {
|
||||
return fmt.Errorf("addon addonPath, helm URL, chart name, and chart verion should not be empty")
|
||||
}
|
||||
|
||||
// Currently, we do not check whether the Helm Chart actually exists, because it is just a scaffold.
|
||||
// The user can still edit it after creation.
|
||||
// Also, if the user is offline, we cannot check whether the Helm Chart exists.
|
||||
// TODO(charlie0129): check whether the Helm Chart exists (if the user wants)
|
||||
|
||||
// Make sure url is valid
|
||||
isValidURL := utils.IsValidURL(helmRepoURL)
|
||||
if !isValidURL {
|
||||
return fmt.Errorf("invalid helm repo url %s", helmRepoURL)
|
||||
}
|
||||
|
||||
err := preAddonCreation(addonName, addonPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create files like template.yaml, README.md, and etc.
|
||||
err = createFilesFromHelmChart(addonName, addonPath, helmRepoURL, chartName, chartVersion)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot create addon files: %w", err)
|
||||
}
|
||||
|
||||
postAddonCreation(addonPath)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateAddonSample creates an empty addon scaffold, with some required files
|
||||
func CreateAddonSample(addonName, addonPath string) error {
|
||||
if len(addonName) == 0 || len(addonPath) == 0 {
|
||||
return fmt.Errorf("addon name and addon path should not be empty")
|
||||
}
|
||||
|
||||
err := preAddonCreation(addonName, addonPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = createSampleFiles(addonName, addonPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
postAddonCreation(addonPath)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// preAddonCreation is executed before creating an addon scaffold
|
||||
// It makes sure that user-provided info is valid.
|
||||
func preAddonCreation(addonName, addonPath string) error {
|
||||
if len(addonName) == 0 || len(addonPath) == 0 {
|
||||
return fmt.Errorf("addon name and addonPath should not be empty")
|
||||
}
|
||||
|
||||
// Make sure addon name is valid
|
||||
err := CheckAddonName(addonName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create dirs
|
||||
err = createAddonDirs(addonPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot create addon structure: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// postAddonCreation is after before creating an addon scaffold
|
||||
// It prints some instructions to get started.
|
||||
func postAddonCreation(addonPath string) {
|
||||
fmt.Println("Scaffold created in directory " +
|
||||
color.New(color.Bold).Sprint(addonPath) + ". What to do next:\n" +
|
||||
"- Check out our guide on how to build your own addon: " +
|
||||
color.BlueString("https://kubevela.io/docs/platform-engineers/addon/intro") + "\n" +
|
||||
"- Review and edit what we have generated in " + color.New(color.Bold).Sprint(addonPath) + "\n" +
|
||||
"- To enable the addon, run: " +
|
||||
color.New(color.FgGreen).Sprint("vela") + color.GreenString(" addon enable ") + color.New(color.Bold, color.FgGreen).Sprint(addonPath))
|
||||
}
|
||||
|
||||
// CheckAddonName checks if an addon name is valid
|
||||
func CheckAddonName(addonName string) error {
|
||||
if len(addonName) == 0 {
|
||||
return fmt.Errorf("addon name should not be empty")
|
||||
}
|
||||
|
||||
// Make sure addonName only contains lowercase letters, dashes, and numbers, e.g. some-addon
|
||||
re := regexp.MustCompile(`^[a-z\d]+(-[a-z\d]+)*$`)
|
||||
if !re.MatchString(addonName) {
|
||||
return fmt.Errorf("addon name should only cocntain lowercase letters, dashes, and numbers, e.g. some-addon")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// createFilesFromHelmChart creates the file structure for a Helm Chart addon,
|
||||
// including template.yaml, readme.md, metadata.yaml, and <addon-nam>.cue.
|
||||
func createFilesFromHelmChart(addonName, addonPath, helmRepoURL, chartName, chartVersion string) error {
|
||||
// Generate template.yaml with an empty Application
|
||||
applicationTemplate := v1beta1.Application{
|
||||
TypeMeta: v1.TypeMeta{
|
||||
APIVersion: v1beta1.SchemeGroupVersion.String(),
|
||||
Kind: "Application",
|
||||
},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: addonName,
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
},
|
||||
}
|
||||
|
||||
applicationTemplateBytes, err := yaml.Marshal(applicationTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Generate metadata.yaml with `fluxcd` as a dependency because we are using helm.
|
||||
// However, this may change in the future, possibly with `argocd`.
|
||||
metadataTemplate := Meta{
|
||||
Name: addonName,
|
||||
Version: chartVersion,
|
||||
Description: "An addon for KubeVela.",
|
||||
Tags: []string{chartVersion},
|
||||
Dependencies: []*Dependency{{Name: "fluxcd"}},
|
||||
}
|
||||
metadataTemplateBytes, err := yaml.Marshal(metadataTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write template.yaml, readme.md, and metadata.yaml
|
||||
err = writeRequiredFiles(addonPath,
|
||||
applicationTemplateBytes,
|
||||
[]byte(strings.ReplaceAll(readmeTemplate, "ADDON_NAME", addonName)),
|
||||
metadataTemplateBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write addonName.cue, containing the helm chart
|
||||
addonResourcePath := path.Join(addonPath, ResourcesDirName, addonName+".cue")
|
||||
resourceTmpl := HelmCUETemplate{}
|
||||
resourceTmpl.Output.Type = "helm"
|
||||
resourceTmpl.Output.Properties.RepoType = "helm"
|
||||
resourceTmpl.Output.Properties.URL = helmRepoURL
|
||||
resourceTmpl.Output.Properties.Chart = chartName
|
||||
resourceTmpl.Output.Properties.Version = chartVersion
|
||||
err = writeHelmCUETemplate(resourceTmpl, addonResourcePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// createSampleFiles creates the file structure for an empty addon
|
||||
func createSampleFiles(addonName, addonPath string) error {
|
||||
// Generate metadata.yaml
|
||||
metadataTemplate := Meta{
|
||||
Name: addonName,
|
||||
Version: "1.0.0",
|
||||
Description: "An addon for KubeVela.",
|
||||
Tags: []string{},
|
||||
Dependencies: []*Dependency{},
|
||||
}
|
||||
metadataTemplateBytes, err := yaml.Marshal(metadataTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Generate template.yaml
|
||||
applicationTemplate := v1beta1.Application{
|
||||
TypeMeta: v1.TypeMeta{
|
||||
APIVersion: v1beta1.SchemeGroupVersion.String(),
|
||||
Kind: "Application",
|
||||
},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: addonName,
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
},
|
||||
}
|
||||
applicationTemplateBytes, err := yaml.Marshal(applicationTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = writeRequiredFiles(addonPath,
|
||||
applicationTemplateBytes,
|
||||
[]byte(strings.ReplaceAll(readmeTemplate, "ADDON_NAME", addonName)),
|
||||
metadataTemplateBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeRequiredFiles creates required files for an addon,
|
||||
// including template.yaml, readme.md, and metadata.yaml
|
||||
func writeRequiredFiles(addonPath string, tmplContent, readmeContent, metadataContent []byte) error {
|
||||
// Write template.yaml
|
||||
templateFilePath := path.Join(addonPath, TemplateFileName)
|
||||
err := os.WriteFile(templateFilePath,
|
||||
tmplContent,
|
||||
0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot write %s: %w", templateFilePath, err)
|
||||
}
|
||||
|
||||
// Write README.md
|
||||
readmeFilePath := path.Join(addonPath, ReadmeFileName)
|
||||
err = os.WriteFile(readmeFilePath,
|
||||
readmeContent,
|
||||
0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot write %s: %w", readmeFilePath, err)
|
||||
}
|
||||
|
||||
// Write metadata.yaml
|
||||
metadataFilePath := path.Join(addonPath, MetadataFileName)
|
||||
err = os.WriteFile(metadataFilePath,
|
||||
metadataContent,
|
||||
0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot write %s: %w", metadataFilePath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// createAddonDirs creates the directory structure for an addon
|
||||
func createAddonDirs(addonDir string) error {
|
||||
// Make sure addonDir is pointing to an empty directory, or does not exist at all
|
||||
// so that we can create it later
|
||||
_, err := os.Stat(addonDir)
|
||||
if !os.IsNotExist(err) {
|
||||
emptyDir, err := utils.IsEmptyDir(addonDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("we can't create directory %s. Make sure the name has not already been taken and you have the proper rights to write to it", addonDir)
|
||||
}
|
||||
|
||||
if !emptyDir {
|
||||
return fmt.Errorf("directory %s is not empty. To avoid any data loss, please manually delete it first, then try again", addonDir)
|
||||
}
|
||||
|
||||
// Now we are sure addonPath is en empty dir, delete it
|
||||
err = os.Remove(addonDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// nolint:gosec
|
||||
err = os.MkdirAll(addonDir, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dirs := []string{
|
||||
path.Join(addonDir, ResourcesDirName),
|
||||
path.Join(addonDir, DefinitionsDirName),
|
||||
path.Join(addonDir, DefSchemaName),
|
||||
}
|
||||
|
||||
for _, dir := range dirs {
|
||||
// nolint:gosec
|
||||
err = os.MkdirAll(dir, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeHelmCUETemplate writes a cue, with a helm component inside, intended as addon resource
|
||||
func writeHelmCUETemplate(tmpl HelmCUETemplate, filePath string) error {
|
||||
r := cue.Runtime{}
|
||||
v, err := gocodec.New(&r, nil).Decode(tmpl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Use `output` value
|
||||
v = v.Lookup("output")
|
||||
// Format output
|
||||
bs, err := format.Node(v.Syntax())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Append "output: " to the beginning of the string, like "output: {}"
|
||||
bs = append([]byte("output: "), bs...)
|
||||
err = os.WriteFile(filePath, bs, 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot write %s: %w", filePath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HelmCUETemplate is a template for a helm component .cue in an addon
|
||||
type HelmCUETemplate struct {
|
||||
Output struct {
|
||||
Type string `json:"type"`
|
||||
Properties struct {
|
||||
RepoType string `json:"repoType"`
|
||||
URL string `json:"url"`
|
||||
Chart string `json:"chart"`
|
||||
Version string `json:"version"`
|
||||
} `json:"properties"`
|
||||
} `json:"output"`
|
||||
}
|
||||
|
||||
const (
|
||||
readmeTemplate = "# ADDON_NAME\n" +
|
||||
"\n" +
|
||||
"This is an addon template. Check how to build your own addon: https://kubevela.net/docs/platform-engineers/addon/intro\n" +
|
||||
"\n" +
|
||||
"## Directory Structure\n" +
|
||||
"\n" +
|
||||
"- `template.yaml`: contains the basic app, you can add some component and workflow to meet your requirements. Other files in `resources/` and `definitions/` will be rendered as Components and appended in `spec.components`\n" +
|
||||
"- `metadata.yaml`: contains addon metadata information.\n" +
|
||||
"- `definitions/`: contains the X-Definition yaml/cue files. These file will be rendered as KubeVela Component in `template.yaml`\n" +
|
||||
"- `resources/`:\n" +
|
||||
" - `parameter.cue` to expose parameters. It will be converted to JSON schema and rendered in UI forms.\n" +
|
||||
" - All other files will be rendered as KubeVela Components. It can be one of the two types:\n" +
|
||||
" - YAML file that contains only one resource. This will be rendered as a `raw` component\n" +
|
||||
" - CUE template file that can read user input as `parameter.XXX` as defined `parameter.cue`.\n" +
|
||||
" Basically the CUE template file will be combined with `parameter.cue` to render a resource.\n" +
|
||||
" **You can specify the type and trait in this format**\n" +
|
||||
""
|
||||
)
|
||||
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
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 addon
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
func TestCheckAddonName(t *testing.T) {
|
||||
var err error
|
||||
|
||||
err = CheckAddonName("")
|
||||
assert.ErrorContains(t, err, "should not be empty")
|
||||
|
||||
invalidNames := []string{
|
||||
"-addon",
|
||||
"addon-",
|
||||
"Caps",
|
||||
"=",
|
||||
".",
|
||||
}
|
||||
for _, name := range invalidNames {
|
||||
err = CheckAddonName(name)
|
||||
assert.ErrorContains(t, err, "should only")
|
||||
}
|
||||
|
||||
validNames := []string{
|
||||
"addon-name",
|
||||
"3-addon-name",
|
||||
"addon-name-3",
|
||||
"addon",
|
||||
}
|
||||
for _, name := range validNames {
|
||||
err = CheckAddonName(name)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteHelmCUETemplate(t *testing.T) {
|
||||
resourceTmpl := HelmCUETemplate{}
|
||||
resourceTmpl.Output.Type = "helm"
|
||||
resourceTmpl.Output.Properties.RepoType = "helm"
|
||||
resourceTmpl.Output.Properties.URL = "https://charts.bitnami.com/bitnami"
|
||||
resourceTmpl.Output.Properties.Chart = "bitnami/nginx"
|
||||
resourceTmpl.Output.Properties.Version = "12.0.4"
|
||||
err := writeHelmCUETemplate(resourceTmpl, "test.cue")
|
||||
assert.NilError(t, err)
|
||||
defer func() {
|
||||
_ = os.Remove("test.cue")
|
||||
}()
|
||||
data, err := os.ReadFile("test.cue")
|
||||
assert.NilError(t, err)
|
||||
expected := `output: {
|
||||
type: "helm"
|
||||
properties: {
|
||||
url: "https://charts.bitnami.com/bitnami"
|
||||
repoType: "helm"
|
||||
chart: "bitnami/nginx"
|
||||
version: "12.0.4"
|
||||
}
|
||||
}`
|
||||
assert.Equal(t, string(data), expected)
|
||||
}
|
||||
|
||||
func TestCreateAddonFromHelmChart(t *testing.T) {
|
||||
err := CreateAddonFromHelmChart("", "", "", "bitnami/nginx", "12.0.4")
|
||||
assert.ErrorContains(t, err, "should not be empty")
|
||||
|
||||
checkFiles := func(base string) {
|
||||
fileList := []string{
|
||||
"definitions",
|
||||
path.Join("resources", base+".cue"),
|
||||
"schemas",
|
||||
MetadataFileName,
|
||||
ReadmeFileName,
|
||||
TemplateFileName,
|
||||
}
|
||||
for _, file := range fileList {
|
||||
_, err = os.Stat(path.Join(base, file))
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Empty dir already exists
|
||||
_ = os.MkdirAll("test-addon", 0755)
|
||||
err = CreateAddonFromHelmChart("test-addon", "./test-addon", "https://charts.bitnami.com/bitnami", "bitnami/nginx", "12.0.4")
|
||||
checkFiles("test-addon")
|
||||
defer func() {
|
||||
_ = os.RemoveAll("test-addon")
|
||||
}()
|
||||
|
||||
// Non-empty dir already exists
|
||||
err = CreateAddonFromHelmChart("test-addon", "test-addon", "https://charts.bitnami.com/bitnami", "bitnami/nginx", "12.0.4")
|
||||
assert.ErrorContains(t, err, "not empty")
|
||||
|
||||
// Name already taken
|
||||
err = os.WriteFile("already-taken", []byte{}, 0644)
|
||||
assert.NilError(t, err)
|
||||
defer func() {
|
||||
_ = os.Remove("already-taken")
|
||||
}()
|
||||
err = CreateAddonFromHelmChart("already-taken", "already-taken", "https://charts.bitnami.com/bitnami", "bitnami/nginx", "12.0.4")
|
||||
assert.ErrorContains(t, err, "can't create")
|
||||
|
||||
// Invalid addon name
|
||||
err = CreateAddonFromHelmChart("/", "./a", "https://charts.bitnami.com/bitnami", "bitnami/nginx", "12.0.4")
|
||||
assert.ErrorContains(t, err, "should only")
|
||||
|
||||
// Invalid URL
|
||||
err = CreateAddonFromHelmChart("invalid-url", "invalid-url", "invalid-url", "bitnami/nginx", "12.0.4")
|
||||
assert.ErrorContains(t, err, "invalid helm repo url")
|
||||
}
|
||||
|
||||
func TestCreateAddonSample(t *testing.T) {
|
||||
checkFiles := func(base string) {
|
||||
fileList := []string{
|
||||
"definitions",
|
||||
"resources",
|
||||
"schemas",
|
||||
MetadataFileName,
|
||||
ReadmeFileName,
|
||||
TemplateFileName,
|
||||
}
|
||||
for _, file := range fileList {
|
||||
_, err := os.Stat(path.Join(base, file))
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Normal creation
|
||||
err := CreateAddonSample("test-addon", "test-addon")
|
||||
assert.NilError(t, err)
|
||||
checkFiles("test-addon")
|
||||
|
||||
// Non-empty dir already exists
|
||||
err = CreateAddonSample("test-addon", "test-addon")
|
||||
assert.ErrorContains(t, err, "directory")
|
||||
|
||||
defer func() {
|
||||
_ = os.RemoveAll("test-addon")
|
||||
}()
|
||||
|
||||
err = CreateAddonSample("", "")
|
||||
assert.ErrorContains(t, err, "empty")
|
||||
}
|
||||
|
||||
func TestPreAddonCreation(t *testing.T) {
|
||||
err := preAddonCreation("", "")
|
||||
assert.ErrorContains(t, err, "empty")
|
||||
|
||||
err = preAddonCreation("=", "a")
|
||||
assert.ErrorContains(t, err, "name")
|
||||
}
|
||||
15
pkg/addon/testdata/test-view/metadata.yaml
vendored
15
pkg/addon/testdata/test-view/metadata.yaml
vendored
@@ -1,15 +0,0 @@
|
||||
name: test-view
|
||||
version: 1.0.0
|
||||
description: test
|
||||
icon: https://www.terraform.io/assets/images/logo-text-8c3ba8a6.svg
|
||||
url: https://terraform.io/
|
||||
|
||||
tags: []
|
||||
|
||||
deployTo:
|
||||
controlPlane: true
|
||||
runtimeCluster: false
|
||||
|
||||
dependencies: []
|
||||
|
||||
invisible: false
|
||||
@@ -1,37 +0,0 @@
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata:
|
||||
name: "cloud-resource-view"
|
||||
namespace: "vela-system"
|
||||
data:
|
||||
template: |
|
||||
import (
|
||||
"vela/ql"
|
||||
)
|
||||
|
||||
parameter: {
|
||||
appName: string
|
||||
appNs: string
|
||||
}
|
||||
resources: ql.#ListResourcesInApp & {
|
||||
app: {
|
||||
name: parameter.appName
|
||||
namespace: parameter.appNs
|
||||
filter: {
|
||||
"apiVersion": "terraform.core.oam.dev/v1beta1"
|
||||
"kind": "Configuration"
|
||||
}
|
||||
withStatus: true
|
||||
}
|
||||
}
|
||||
status: {
|
||||
if resources.err == _|_ {
|
||||
"cloud-resources": [ for i, resource in resources.list {
|
||||
resource.object
|
||||
}]
|
||||
}
|
||||
if resources.err != _|_ {
|
||||
error: resources.err
|
||||
}
|
||||
}
|
||||
|
||||
75
pkg/addon/testdata/test-view/views/pod-view.cue
vendored
75
pkg/addon/testdata/test-view/views/pod-view.cue
vendored
@@ -1,75 +0,0 @@
|
||||
import (
|
||||
"vela/ql"
|
||||
)
|
||||
|
||||
parameter: {
|
||||
name: string
|
||||
namespace: string
|
||||
cluster: *"" | string
|
||||
}
|
||||
pod: ql.#Read & {
|
||||
value: {
|
||||
apiVersion: "v1"
|
||||
kind: "Pod"
|
||||
metadata: {
|
||||
name: parameter.name
|
||||
namespace: parameter.namespace
|
||||
}
|
||||
}
|
||||
cluster: parameter.cluster
|
||||
}
|
||||
eventList: ql.#SearchEvents & {
|
||||
value: {
|
||||
apiVersion: "v1"
|
||||
kind: "Pod"
|
||||
metadata: pod.value.metadata
|
||||
}
|
||||
cluster: parameter.cluster
|
||||
}
|
||||
podMetrics: ql.#Read & {
|
||||
cluster: parameter.cluster
|
||||
value: {
|
||||
apiVersion: "metrics.k8s.io/v1beta1"
|
||||
kind: "PodMetrics"
|
||||
metadata: {
|
||||
name: parameter.name
|
||||
namespace: parameter.namespace
|
||||
}
|
||||
}
|
||||
}
|
||||
status: {
|
||||
if pod.err == _|_ {
|
||||
containers: [ for container in pod.value.spec.containers {
|
||||
name: container.name
|
||||
image: container.image
|
||||
resources: {
|
||||
if container.resources.limits != _|_ {
|
||||
limits: container.resources.limits
|
||||
}
|
||||
if container.resources.requests != _|_ {
|
||||
requests: container.resources.requests
|
||||
}
|
||||
if podMetrics.err == _|_ {
|
||||
usage: {for containerUsage in podMetrics.value.containers {
|
||||
if containerUsage.name == container.name {
|
||||
cpu: containerUsage.usage.cpu
|
||||
memory: containerUsage.usage.memory
|
||||
}
|
||||
}}
|
||||
}
|
||||
}
|
||||
if pod.value.status.containerStatuses != _|_ {
|
||||
status: {for containerStatus in pod.value.status.containerStatuses if containerStatus.name == container.name {
|
||||
state: containerStatus.state
|
||||
restartCount: containerStatus.restartCount
|
||||
}}
|
||||
}
|
||||
}]
|
||||
if eventList.err == _|_ {
|
||||
events: eventList.list
|
||||
}
|
||||
}
|
||||
if pod.err != _|_ {
|
||||
error: pod.err
|
||||
}
|
||||
}
|
||||
@@ -48,9 +48,6 @@ type InstallPackage struct {
|
||||
// Definitions and CUEDefinitions are converted as OAM X-Definitions, they will only in control plane cluster
|
||||
Definitions []ElementFile `json:"definitions"`
|
||||
CUEDefinitions []ElementFile `json:"CUEDefinitions"`
|
||||
// YAMLViews and CUEViews are the instances of velaql, they will only in control plane cluster
|
||||
YAMLViews []ElementFile `json:"YAMLViews"`
|
||||
CUEViews []ElementFile `json:"CUEViews"`
|
||||
// DefSchemas are UI schemas read by VelaUX, it will only be installed in control plane clusters
|
||||
DefSchemas []ElementFile `json:"defSchemas,omitempty"`
|
||||
|
||||
|
||||
@@ -101,16 +101,6 @@ func (a *Application) IsSynced() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsReadOnly is readonly app
|
||||
// Only the source is inner, the app is readonly
|
||||
func (a *Application) IsReadOnly() bool {
|
||||
if a.Labels == nil {
|
||||
return false
|
||||
}
|
||||
sot := a.Labels[LabelSourceOfTruth]
|
||||
return sot == FromInner
|
||||
}
|
||||
|
||||
// ClusterSelector cluster selector
|
||||
type ClusterSelector struct {
|
||||
Name string `json:"name"`
|
||||
|
||||
@@ -50,9 +50,7 @@ const (
|
||||
FromCR = "from-k8s-resource"
|
||||
// FromUX means the data source of truth is from velaux data store
|
||||
FromUX = "from-velaux"
|
||||
// FromInner means the data source of truth is from KubeVela inner usage
|
||||
// the configuration that don't want to be synced
|
||||
// the addon application should be synced, but set to readonly mode
|
||||
// FromInner means the data source of truth is from KubeVela inner usage, such as addon or configuration that don't want to be synced
|
||||
FromInner = "from-inner-system"
|
||||
)
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
@@ -789,10 +790,6 @@ func (c *applicationServiceImpl) renderOAMApplication(ctx context.Context, appMo
|
||||
if workflow == nil || workflow.EnvName == "" {
|
||||
return nil, bcode.ErrWorkflowNotExist
|
||||
}
|
||||
envbinding, err := c.EnvBindingService.GetEnvBinding(ctx, appModel, workflow.EnvName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
env, err := c.EnvService.GetEnv(ctx, workflow.EnvName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -802,20 +799,14 @@ func (c *applicationServiceImpl) renderOAMApplication(ctx context.Context, appMo
|
||||
labels[key] = value
|
||||
}
|
||||
labels[oam.AnnotationAppName] = appModel.Name
|
||||
// To take over the application
|
||||
labels[model.LabelSourceOfTruth] = model.FromUX
|
||||
|
||||
deployAppName := envbinding.AppDeployName
|
||||
if deployAppName == "" {
|
||||
deployAppName = appModel.Name
|
||||
}
|
||||
var app = &v1beta1.Application{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Application",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: deployAppName,
|
||||
Name: appModel.Name,
|
||||
Namespace: env.Namespace,
|
||||
Labels: labels,
|
||||
Annotations: map[string]string{
|
||||
@@ -1583,21 +1574,38 @@ func dryRunApplication(ctx context.Context, c common2.Args, app *v1beta1.Applica
|
||||
return buff, err
|
||||
}
|
||||
dryRunOpt := dryrun.NewDryRunOption(newClient, config, dm, pd, objects)
|
||||
comps, policies, err := dryRunOpt.ExecuteDryRun(ctx, app)
|
||||
comps, err := dryRunOpt.ExecuteDryRun(ctx, app)
|
||||
if err != nil {
|
||||
return buff, fmt.Errorf("generate OAM objects %w", err)
|
||||
}
|
||||
if _, err = fmt.Fprintf(&buff, "---\n# Application(%s) \n---\n\n", app.Name); err != nil {
|
||||
return buff, fmt.Errorf("fail to write to buff %w", err)
|
||||
var components = make(map[string]*unstructured.Unstructured)
|
||||
for _, comp := range comps {
|
||||
components[comp.Name] = comp.StandardWorkload
|
||||
}
|
||||
buff.Write([]byte(fmt.Sprintf("---\n# Application(%s) \n---\n\n", app.Name)))
|
||||
result, err := yaml.Marshal(app)
|
||||
if err != nil {
|
||||
return buff, fmt.Errorf("marshal app: %w", err)
|
||||
return buff, errors.New("marshal app error")
|
||||
}
|
||||
buff.Write(result)
|
||||
buff.WriteString("\n---\n")
|
||||
if err = dryRunOpt.PrintDryRun(&buff, app.Name, comps, policies); err != nil {
|
||||
return buff, err
|
||||
buff.Write([]byte("\n---\n"))
|
||||
for _, c := range comps {
|
||||
buff.Write([]byte(fmt.Sprintf("---\n# Application(%s) -- Component(%s) \n---\n\n", app.Name, c.Name)))
|
||||
result, err := yaml.Marshal(components[c.Name])
|
||||
if err != nil {
|
||||
return buff, errors.New("marshal result for component " + c.Name + " object in yaml format")
|
||||
}
|
||||
buff.Write(result)
|
||||
buff.Write([]byte("\n---\n"))
|
||||
for _, t := range c.Traits {
|
||||
result, err := yaml.Marshal(t)
|
||||
if err != nil {
|
||||
return buff, errors.New("marshal result for component " + c.Name + " object in yaml format")
|
||||
}
|
||||
buff.Write(result)
|
||||
buff.Write([]byte("\n---\n"))
|
||||
}
|
||||
buff.Write([]byte("\n"))
|
||||
}
|
||||
return buff, nil
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"strings"
|
||||
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
@@ -79,5 +81,9 @@ func (v *velaQLServiceImpl) QueryView(ctx context.Context, velaQL string) (*apis
|
||||
log.Logger.Errorf("decode the velaQL response to json failure %s", err.Error())
|
||||
return nil, bcode.ErrParseQuery2Json
|
||||
}
|
||||
if strings.Contains(velaQL, "collect-logs") {
|
||||
enc, _ := base64.StdEncoding.DecodeString(resp["logs"].(string))
|
||||
resp["logs"] = string(enc)
|
||||
}
|
||||
return &resp, err
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
@@ -426,6 +427,11 @@ func (j *jfrogHandlerImpl) handle(ctx context.Context, webhookTrigger *model.App
|
||||
return nil, err
|
||||
}
|
||||
image := fmt.Sprintf("%s/%s:%s", jfrogReq.Data.RepoKey, jfrogReq.Data.ImageName, jfrogReq.Data.Tag)
|
||||
pathArray := strings.Split(jfrogReq.Data.Path, "/")
|
||||
if len(pathArray) > 2 {
|
||||
image = fmt.Sprintf("%s/%s:%s", jfrogReq.Data.RepoKey, strings.Join(pathArray[:len(pathArray)-2], "/"), jfrogReq.Data.Tag)
|
||||
}
|
||||
|
||||
if jfrogReq.Data.URL != "" {
|
||||
image = fmt.Sprintf("%s/%s", jfrogReq.Data.URL, image)
|
||||
}
|
||||
@@ -441,7 +447,7 @@ func (j *jfrogHandlerImpl) handle(ctx context.Context, webhookTrigger *model.App
|
||||
TriggerType: apisv1.TriggerTypeWebhook,
|
||||
Force: true,
|
||||
ImageInfo: &model.ImageInfo{
|
||||
Type: model.PayloadTypeHarbor,
|
||||
Type: model.PayloadTypeJFrog,
|
||||
Resource: &model.ImageResource{
|
||||
Digest: jfrogReq.Data.Digest,
|
||||
Tag: jfrogReq.Data.Tag,
|
||||
|
||||
@@ -43,7 +43,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
utils2 "github.com/oam-dev/kubevela/pkg/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/apply"
|
||||
wfTypes "github.com/oam-dev/kubevela/pkg/workflow/types"
|
||||
"github.com/oam-dev/kubevela/pkg/workflow/tasks/custom"
|
||||
)
|
||||
|
||||
// WorkflowService workflow manage api
|
||||
@@ -72,11 +72,10 @@ func NewWorkflowService() WorkflowService {
|
||||
}
|
||||
|
||||
type workflowServiceImpl struct {
|
||||
Store datastore.DataStore `inject:"datastore"`
|
||||
KubeClient client.Client `inject:"kubeClient"`
|
||||
Apply apply.Applicator `inject:"apply"`
|
||||
EnvService EnvService `inject:""`
|
||||
EnvBindingService EnvBindingService `inject:""`
|
||||
Store datastore.DataStore `inject:"datastore"`
|
||||
KubeClient client.Client `inject:"kubeClient"`
|
||||
Apply apply.Applicator `inject:"apply"`
|
||||
EnvService EnvService `inject:""`
|
||||
}
|
||||
|
||||
// DeleteWorkflow delete application workflow
|
||||
@@ -343,17 +342,7 @@ func (w *workflowServiceImpl) SyncWorkflowRecord(ctx context.Context) error {
|
||||
klog.ErrorS(err, "failed to get workflow", "app name", record.AppPrimaryKey, "workflow name", record.WorkflowName, "record name", record.Name)
|
||||
continue
|
||||
}
|
||||
envbinding, err := w.EnvBindingService.GetEnvBinding(ctx, &model.Application{Name: record.AppPrimaryKey}, workflow.EnvName)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "failed to get envbinding", "app name", record.AppPrimaryKey, "workflow name", record.WorkflowName, "record name", record.Name)
|
||||
}
|
||||
var appName string
|
||||
if envbinding != nil {
|
||||
appName = envbinding.AppDeployName
|
||||
}
|
||||
if appName == "" {
|
||||
appName = record.AppPrimaryKey
|
||||
}
|
||||
appName := record.AppPrimaryKey
|
||||
if err := w.KubeClient.Get(ctx, types.NamespacedName{
|
||||
Name: appName,
|
||||
Namespace: record.Namespace,
|
||||
@@ -572,7 +561,8 @@ func (w *workflowServiceImpl) ResumeRecord(ctx context.Context, appModel *model.
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ResumeWorkflow(ctx, w.KubeClient, oamApp); err != nil {
|
||||
oamApp.Status.Workflow.Suspend = false
|
||||
if err := w.KubeClient.Status().Patch(ctx, oamApp, client.Merge); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := w.syncWorkflowStatus(ctx, oamApp, recordName, oamApp.Name); err != nil {
|
||||
@@ -598,53 +588,31 @@ func (w *workflowServiceImpl) TerminateRecord(ctx context.Context, appModel *mod
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResumeWorkflow resume workflow
|
||||
func ResumeWorkflow(ctx context.Context, kubecli client.Client, app *v1beta1.Application) error {
|
||||
app.Status.Workflow.Suspend = false
|
||||
steps := app.Status.Workflow.Steps
|
||||
for i, step := range steps {
|
||||
if step.Type == wfTypes.WorkflowStepTypeSuspend && step.Phase == common.WorkflowStepPhaseRunning {
|
||||
steps[i].Phase = common.WorkflowStepPhaseSucceeded
|
||||
}
|
||||
for j, sub := range step.SubStepsStatus {
|
||||
if sub.Type == wfTypes.WorkflowStepTypeSuspend && sub.Phase == common.WorkflowStepPhaseRunning {
|
||||
steps[i].SubStepsStatus[j].Phase = common.WorkflowStepPhaseSucceeded
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := kubecli.Status().Patch(ctx, app, client.Merge); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TerminateWorkflow terminate workflow
|
||||
func TerminateWorkflow(ctx context.Context, kubecli client.Client, app *v1beta1.Application) error {
|
||||
// set the workflow terminated to true
|
||||
app.Status.Workflow.Terminated = true
|
||||
// set the workflow suspend to false
|
||||
app.Status.Workflow.Suspend = false
|
||||
steps := app.Status.Workflow.Steps
|
||||
for i, step := range steps {
|
||||
switch step.Phase {
|
||||
case common.WorkflowStepPhaseFailed:
|
||||
if step.Reason != wfTypes.StatusReasonFailedAfterRetries && step.Reason != wfTypes.StatusReasonTimeout {
|
||||
steps[i].Reason = wfTypes.StatusReasonTerminate
|
||||
if step.Reason != custom.StatusReasonFailedAfterRetries {
|
||||
steps[i].Reason = custom.StatusReasonTerminate
|
||||
}
|
||||
case common.WorkflowStepPhaseRunning:
|
||||
steps[i].Phase = common.WorkflowStepPhaseFailed
|
||||
steps[i].Reason = wfTypes.StatusReasonTerminate
|
||||
steps[i].Reason = custom.StatusReasonTerminate
|
||||
default:
|
||||
}
|
||||
for j, sub := range step.SubStepsStatus {
|
||||
switch sub.Phase {
|
||||
case common.WorkflowStepPhaseFailed:
|
||||
if sub.Reason != wfTypes.StatusReasonFailedAfterRetries && sub.Reason != wfTypes.StatusReasonTimeout {
|
||||
steps[i].SubStepsStatus[j].Phase = wfTypes.StatusReasonTerminate
|
||||
if sub.Reason != custom.StatusReasonFailedAfterRetries {
|
||||
steps[i].SubStepsStatus[j].Phase = custom.StatusReasonTerminate
|
||||
}
|
||||
case common.WorkflowStepPhaseRunning:
|
||||
steps[i].SubStepsStatus[j].Phase = common.WorkflowStepPhaseFailed
|
||||
steps[i].SubStepsStatus[j].Reason = wfTypes.StatusReasonTerminate
|
||||
steps[i].SubStepsStatus[j].Reason = custom.StatusReasonTerminate
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,24 +60,20 @@ var _ = Describe("Test workflow service functions", func() {
|
||||
rbacService := &rbacServiceImpl{Store: ds}
|
||||
projectService = &projectServiceImpl{Store: ds, RbacService: rbacService}
|
||||
envService = &envServiceImpl{Store: ds, KubeClient: k8sClient, ProjectService: projectService}
|
||||
envBinding := &envBindingServiceImpl{
|
||||
Store: ds,
|
||||
WorkflowService: workflowService,
|
||||
EnvService: envService,
|
||||
}
|
||||
workflowService = &workflowServiceImpl{
|
||||
Store: ds,
|
||||
KubeClient: k8sClient,
|
||||
Apply: apply.NewAPIApplicator(k8sClient),
|
||||
EnvService: envService,
|
||||
EnvBindingService: envBinding,
|
||||
}
|
||||
Store: ds,
|
||||
KubeClient: k8sClient,
|
||||
Apply: apply.NewAPIApplicator(k8sClient),
|
||||
EnvService: envService}
|
||||
appService = &applicationServiceImpl{Store: ds, KubeClient: k8sClient,
|
||||
Apply: apply.NewAPIApplicator(k8sClient),
|
||||
ProjectService: projectService,
|
||||
EnvService: envService,
|
||||
EnvBindingService: envBinding,
|
||||
}
|
||||
Apply: apply.NewAPIApplicator(k8sClient),
|
||||
ProjectService: projectService,
|
||||
EnvService: envService,
|
||||
EnvBindingService: &envBindingServiceImpl{
|
||||
Store: ds,
|
||||
WorkflowService: workflowService,
|
||||
EnvService: envService,
|
||||
}}
|
||||
})
|
||||
It("Test CreateWorkflow function", func() {
|
||||
_, err := projectService.CreateProject(context.TODO(), apisv1.CreateProjectRequest{Name: testProject})
|
||||
|
||||
@@ -322,7 +322,17 @@ func genClusterCountInfo(num int) string {
|
||||
return "<10"
|
||||
case num < 50:
|
||||
return "<50"
|
||||
case num < 100:
|
||||
return "<100"
|
||||
case num < 150:
|
||||
return "<150"
|
||||
case num < 200:
|
||||
return "<200"
|
||||
case num < 300:
|
||||
return "<300"
|
||||
case num < 500:
|
||||
return "<500"
|
||||
default:
|
||||
return ">=50"
|
||||
return ">=500"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,8 +211,28 @@ func TestGenClusterCountInfo(t *testing.T) {
|
||||
res: "<50",
|
||||
},
|
||||
{
|
||||
count: 100,
|
||||
res: ">=50",
|
||||
count: 90,
|
||||
res: "<100",
|
||||
},
|
||||
{
|
||||
count: 137,
|
||||
res: "<150",
|
||||
},
|
||||
{
|
||||
count: 170,
|
||||
res: "<200",
|
||||
},
|
||||
{
|
||||
count: 270,
|
||||
res: "<300",
|
||||
},
|
||||
{
|
||||
count: 400,
|
||||
res: "<500",
|
||||
},
|
||||
{
|
||||
count: 520,
|
||||
res: ">=500",
|
||||
},
|
||||
}
|
||||
for _, testcase := range testcases {
|
||||
|
||||
@@ -19,8 +19,6 @@ package event
|
||||
import (
|
||||
"context"
|
||||
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/config"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/event/collect"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/event/sync"
|
||||
@@ -38,9 +36,7 @@ func InitEvent(cfg config.Config) []interface{} {
|
||||
workflow := &sync.WorkflowRecordSync{
|
||||
Duration: cfg.LeaderConfig.Duration,
|
||||
}
|
||||
application := &sync.ApplicationSync{
|
||||
Queue: workqueue.New(),
|
||||
}
|
||||
application := &sync.ApplicationSync{}
|
||||
collect := &collect.InfoCalculateCronJob{}
|
||||
workers = append(workers, workflow, application, collect)
|
||||
return []interface{}{workflow, application, collect}
|
||||
|
||||
@@ -27,7 +27,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/domain/model"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/infrastructure/datastore"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
)
|
||||
|
||||
type cached struct {
|
||||
@@ -67,21 +66,18 @@ func (c *CR2UX) initCache(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (c *CR2UX) shouldSync(ctx context.Context, targetApp *v1beta1.Application, del bool) bool {
|
||||
if targetApp != nil && targetApp.Labels != nil {
|
||||
// the source is inner and is not the addon application, ignore it.
|
||||
if targetApp.Labels[model.LabelSourceOfTruth] == model.FromInner && targetApp.Labels[oam.LabelAddonName] == "" {
|
||||
return false
|
||||
}
|
||||
// the source is UX, ignore it
|
||||
if targetApp.Labels[model.LabelSourceOfTruth] == model.FromUX {
|
||||
return false
|
||||
}
|
||||
|
||||
if targetApp != nil && targetApp.Labels != nil && targetApp.Labels[model.LabelSourceOfTruth] == model.FromInner {
|
||||
return false
|
||||
}
|
||||
|
||||
key := formatAppComposedName(targetApp.Name, targetApp.Namespace)
|
||||
cachedData, ok := c.cache.Load(key)
|
||||
if ok {
|
||||
cd := cachedData.(*cached)
|
||||
|
||||
// TODO(wonderflow): we should check targets if we sync that, it can avoid missing the status changed for targets updated in multi-cluster deploy, e.g. resumed suspend case.
|
||||
|
||||
// if app meta not exist, we should ignore the cache
|
||||
_, _, err := c.getApp(ctx, targetApp.Name, targetApp.Namespace)
|
||||
if del || err != nil {
|
||||
@@ -92,6 +88,18 @@ func (c *CR2UX) shouldSync(ctx context.Context, targetApp *v1beta1.Application,
|
||||
}
|
||||
}
|
||||
|
||||
// This is a double check to make sure the app not be converted and un-deployed
|
||||
sot := c.CheckSoTFromAppMeta(ctx, targetApp.Name, targetApp.Namespace, CheckSoTFromCR(targetApp))
|
||||
switch sot {
|
||||
case model.FromUX:
|
||||
// we don't sync if the application is not created from CR
|
||||
return false
|
||||
case model.FromInner:
|
||||
// we don't sync if the application is not created from CR
|
||||
return false
|
||||
case model.FromCR:
|
||||
default:
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -82,11 +82,6 @@ var _ = Describe("Test Cache", func() {
|
||||
app3.Name = "app3"
|
||||
app3.Namespace = "app3-ns"
|
||||
app3.Generation = 3
|
||||
app3.Labels = map[string]string{
|
||||
model.LabelSyncGeneration: "1",
|
||||
model.LabelSyncNamespace: "app3-ns",
|
||||
model.LabelSourceOfTruth: model.FromUX,
|
||||
}
|
||||
|
||||
Expect(cr2ux.shouldSync(ctx, app3, false)).Should(BeEquivalentTo(false))
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ package sync
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -26,7 +25,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/domain/model"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/event/sync/convert"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/workflow/step"
|
||||
)
|
||||
@@ -38,12 +36,9 @@ func (c *CR2UX) ConvertApp2DatastoreApp(ctx context.Context, targetApp *v1beta1.
|
||||
appName := c.getAppMetaName(ctx, targetApp.Name, targetApp.Namespace)
|
||||
|
||||
project := model.DefaultInitName
|
||||
sourceOfTruth := model.FromCR
|
||||
if _, ok := targetApp.Labels[oam.LabelAddonName]; ok && strings.HasPrefix(targetApp.Name, "addon-") {
|
||||
project = model.DefaultAddonProject
|
||||
sourceOfTruth = model.FromInner
|
||||
}
|
||||
|
||||
appMeta := &model.Application{
|
||||
Name: appName,
|
||||
Description: model.AutoGenDesc,
|
||||
@@ -52,7 +47,7 @@ func (c *CR2UX) ConvertApp2DatastoreApp(ctx context.Context, targetApp *v1beta1.
|
||||
Labels: map[string]string{
|
||||
model.LabelSyncNamespace: targetApp.Namespace,
|
||||
model.LabelSyncGeneration: strconv.FormatInt(targetApp.Generation, 10),
|
||||
model.LabelSourceOfTruth: sourceOfTruth,
|
||||
model.LabelSourceOfTruth: model.FromCR,
|
||||
},
|
||||
}
|
||||
appMeta.CreateTime = targetApp.CreationTimestamp.Time
|
||||
@@ -60,50 +55,21 @@ func (c *CR2UX) ConvertApp2DatastoreApp(ctx context.Context, targetApp *v1beta1.
|
||||
// 1. convert app meta and env
|
||||
dsApp := &model.DataStoreApp{
|
||||
AppMeta: appMeta,
|
||||
}
|
||||
|
||||
// 1. convert the target
|
||||
|
||||
existTarget := &model.Target{Project: project}
|
||||
existTargets, err := c.ds.List(ctx, existTarget, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to list the targets, %w", err)
|
||||
}
|
||||
var envTargetNames []string
|
||||
dsApp.Targets, envTargetNames = convert.FromCRTargets(ctx, c.cli, targetApp, existTargets, project)
|
||||
|
||||
// 2. convert the environment
|
||||
existEnv := &model.Env{Namespace: targetApp.Namespace, Project: project}
|
||||
existEnvs, err := c.ds.List(ctx, existEnv, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to list the env, %w", err)
|
||||
}
|
||||
if len(existEnvs) > 0 {
|
||||
env := existEnvs[0].(*model.Env)
|
||||
for _, name := range envTargetNames {
|
||||
if !utils.StringsContain(env.Targets, name) {
|
||||
env.Targets = append(env.Targets, name)
|
||||
}
|
||||
}
|
||||
dsApp.Env = env
|
||||
}
|
||||
if dsApp.Env == nil {
|
||||
dsApp.Env = &model.Env{
|
||||
Env: &model.Env{
|
||||
Name: model.AutoGenEnvNamePrefix + targetApp.Namespace,
|
||||
Namespace: targetApp.Namespace,
|
||||
Description: model.AutoGenDesc,
|
||||
Project: project,
|
||||
Alias: model.AutoGenEnvNamePrefix + targetApp.Namespace,
|
||||
Targets: envTargetNames,
|
||||
}
|
||||
}
|
||||
dsApp.Eb = &model.EnvBinding{
|
||||
AppPrimaryKey: appMeta.PrimaryKey(),
|
||||
Name: dsApp.Env.Name,
|
||||
AppDeployName: appMeta.GetAppNameForSynced(),
|
||||
},
|
||||
Eb: &model.EnvBinding{
|
||||
AppPrimaryKey: appMeta.PrimaryKey(),
|
||||
Name: model.AutoGenEnvNamePrefix + targetApp.Namespace,
|
||||
AppDeployName: appMeta.GetAppNameForSynced(),
|
||||
},
|
||||
}
|
||||
|
||||
// 3. convert component and trait
|
||||
// 2. convert component and trait
|
||||
for _, cmp := range targetApp.Spec.Components {
|
||||
compModel, err := convert.FromCRComponent(appMeta.PrimaryKey(), cmp)
|
||||
if err != nil {
|
||||
@@ -112,15 +78,14 @@ func (c *CR2UX) ConvertApp2DatastoreApp(ctx context.Context, targetApp *v1beta1.
|
||||
dsApp.Comps = append(dsApp.Comps, &compModel)
|
||||
}
|
||||
|
||||
// 4. convert workflow
|
||||
// 3. convert workflow
|
||||
wf, steps, err := convert.FromCRWorkflow(ctx, cli, appMeta.PrimaryKey(), targetApp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wf.EnvName = dsApp.Env.Name
|
||||
dsApp.Workflow = &wf
|
||||
|
||||
// 5. convert policy, some policies are references in workflow step, we need to sync all the outside policy to make that work
|
||||
// 4. convert policy, some policies are references in workflow step, we need to sync all the outside policy to make that work
|
||||
var innerPlc = make(map[string]struct{})
|
||||
for _, plc := range targetApp.Spec.Policies {
|
||||
innerPlc[plc.Name] = struct{}{}
|
||||
@@ -137,8 +102,16 @@ func (c *CR2UX) ConvertApp2DatastoreApp(ctx context.Context, targetApp *v1beta1.
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
plcModel.EnvName = dsApp.Env.Name
|
||||
dsApp.Policies = append(dsApp.Policies, &plcModel)
|
||||
}
|
||||
|
||||
// TODO(wonderflow): we don't sync targets as it can't be judged well in velaux env
|
||||
// if we want to sync, we can extract targets from status, like below:
|
||||
/*
|
||||
dsApp.Targets = ConvertFromCRTargets(targetApp)
|
||||
for _, t := range dsApp.Targets {
|
||||
dsApp.Env.Targets = append(dsApp.Env.Targets, t.Name)
|
||||
}
|
||||
*/
|
||||
return dsApp, nil
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package convert
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
@@ -28,10 +27,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/domain/model"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/infrastructure/datastore"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
|
||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||
"github.com/oam-dev/kubevela/pkg/policy"
|
||||
"github.com/oam-dev/kubevela/pkg/workflow/step"
|
||||
)
|
||||
|
||||
@@ -109,69 +105,46 @@ func FromCRWorkflow(ctx context.Context, cli client.Client, appPrimaryKey string
|
||||
steps = app.Spec.Workflow.Steps
|
||||
}
|
||||
for _, s := range steps {
|
||||
ws := model.WorkflowStep{
|
||||
Name: s.Name,
|
||||
Type: s.Type,
|
||||
Inputs: s.Inputs,
|
||||
Outputs: s.Outputs,
|
||||
DependsOn: s.DependsOn,
|
||||
if s.Properties == nil {
|
||||
continue
|
||||
}
|
||||
if s.Properties != nil {
|
||||
properties, err := model.NewJSONStruct(s.Properties)
|
||||
if err != nil {
|
||||
return dataWf, nil, err
|
||||
}
|
||||
ws.Properties = properties
|
||||
properties, err := model.NewJSONStruct(s.Properties)
|
||||
if err != nil {
|
||||
return dataWf, nil, err
|
||||
}
|
||||
dataWf.Steps = append(dataWf.Steps, ws)
|
||||
dataWf.Steps = append(dataWf.Steps, model.WorkflowStep{
|
||||
Name: s.Name,
|
||||
Type: s.Type,
|
||||
Inputs: s.Inputs,
|
||||
Outputs: s.Outputs,
|
||||
DependsOn: s.DependsOn,
|
||||
Properties: properties,
|
||||
})
|
||||
}
|
||||
return dataWf, steps, nil
|
||||
}
|
||||
|
||||
// FromCRTargets converts deployed Cluster/Namespace from Application CR Status into velaux data store
|
||||
func FromCRTargets(ctx context.Context, cli client.Client, targetApp *v1beta1.Application, existTargets []datastore.Entity, project string) ([]*model.Target, []string) {
|
||||
existTarget := make(map[string]*model.Target)
|
||||
for i := range existTargets {
|
||||
t := existTargets[i].(*model.Target)
|
||||
existTarget[fmt.Sprintf("%s-%s", t.Cluster.ClusterName, t.Cluster.Namespace)] = t
|
||||
}
|
||||
func FromCRTargets(targetApp *v1beta1.Application) []*model.Target {
|
||||
var targets []*model.Target
|
||||
var targetNames []string
|
||||
nc := make(map[string]struct{})
|
||||
// read the target from the topology policies
|
||||
placements, err := policy.GetPlacementsFromTopologyPolicies(ctx, cli, targetApp.Namespace, targetApp.Spec.Policies, true)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("fail to get placements from topology policies %s", err.Error())
|
||||
return targets, targetNames
|
||||
}
|
||||
for _, placement := range placements {
|
||||
if placement.Cluster == "" {
|
||||
placement.Cluster = multicluster.ClusterLocalName
|
||||
for _, v := range targetApp.Status.AppliedResources {
|
||||
var cluster = v.Cluster
|
||||
if cluster == "" {
|
||||
cluster = multicluster.ClusterLocalName
|
||||
}
|
||||
if placement.Namespace == "" {
|
||||
placement.Namespace = targetApp.Namespace
|
||||
}
|
||||
if placement.Namespace == "" {
|
||||
placement.Namespace = "default"
|
||||
}
|
||||
name := model.AutoGenTargetNamePrefix + placement.Cluster + "-" + placement.Namespace
|
||||
name := model.AutoGenTargetNamePrefix + cluster + "-" + v.Namespace
|
||||
if _, ok := nc[name]; ok {
|
||||
continue
|
||||
}
|
||||
nc[name] = struct{}{}
|
||||
if target, ok := existTarget[fmt.Sprintf("%s-%s", placement.Cluster, placement.Namespace)]; ok {
|
||||
targetNames = append(targetNames, target.Name)
|
||||
} else {
|
||||
targetNames = append(targetNames, name)
|
||||
targets = append(targets, &model.Target{
|
||||
Name: name,
|
||||
Project: project,
|
||||
Cluster: &model.ClusterTarget{
|
||||
ClusterName: placement.Cluster,
|
||||
Namespace: placement.Namespace,
|
||||
},
|
||||
})
|
||||
}
|
||||
targets = append(targets, &model.Target{
|
||||
Name: name,
|
||||
Cluster: &model.ClusterTarget{
|
||||
ClusterName: cluster,
|
||||
Namespace: v.Namespace,
|
||||
},
|
||||
})
|
||||
}
|
||||
return targets, targetNames
|
||||
return targets
|
||||
}
|
||||
|
||||
@@ -80,11 +80,10 @@ func (c *CR2UX) getApp(ctx context.Context, name, namespace string) (*model.Appl
|
||||
|
||||
// CR2UX provides the Add/Update/Delete method
|
||||
type CR2UX struct {
|
||||
ds datastore.DataStore
|
||||
cli client.Client
|
||||
cache sync.Map
|
||||
projectService service.ProjectService
|
||||
applicationService service.ApplicationService
|
||||
ds datastore.DataStore
|
||||
cli client.Client
|
||||
cache sync.Map
|
||||
projectService service.ProjectService
|
||||
}
|
||||
|
||||
func formatAppComposedName(name, namespace string) string {
|
||||
@@ -114,11 +113,6 @@ func (c *CR2UX) AddOrUpdate(ctx context.Context, targetApp *v1beta1.Application)
|
||||
return err
|
||||
}
|
||||
|
||||
if err = StoreTargets(ctx, dsApp, ds); err != nil {
|
||||
log.Logger.Errorf("Store targets to data store err %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err = StoreEnv(ctx, dsApp, ds); err != nil {
|
||||
log.Logger.Errorf("Store Env Metadata to data store err %v", err)
|
||||
return err
|
||||
@@ -139,6 +133,13 @@ func (c *CR2UX) AddOrUpdate(ctx context.Context, targetApp *v1beta1.Application)
|
||||
log.Logger.Errorf("Store Workflow Metadata to data store err %v", err)
|
||||
return err
|
||||
}
|
||||
/*
|
||||
if err = StoreTargets(ctx, dsApp, ds); err != nil {
|
||||
log.Logger.Errorf("Store targets to data store err %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
if err = StoreAppMeta(ctx, dsApp, ds); err != nil {
|
||||
log.Logger.Errorf("Store App Metadata to data store err %v", err)
|
||||
@@ -152,16 +153,38 @@ func (c *CR2UX) AddOrUpdate(ctx context.Context, targetApp *v1beta1.Application)
|
||||
|
||||
// DeleteApp will delete the application as the CR was deleted
|
||||
func (c *CR2UX) DeleteApp(ctx context.Context, targetApp *v1beta1.Application) error {
|
||||
ds := c.ds
|
||||
|
||||
if !c.shouldSync(ctx, targetApp, true) {
|
||||
return nil
|
||||
}
|
||||
app, appName, err := c.getApp(ctx, targetApp.Name, targetApp.Namespace)
|
||||
appName := c.getAppMetaName(ctx, targetApp.Name, targetApp.Namespace)
|
||||
|
||||
_ = ds.Delete(ctx, &model.Application{Name: appName})
|
||||
|
||||
cmps, err := ds.List(ctx, &model.ApplicationComponent{AppPrimaryKey: appName}, &datastore.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Only for the unit test scenario
|
||||
if c.applicationService == nil {
|
||||
return c.ds.Delete(ctx, &model.Application{Name: appName})
|
||||
for _, entity := range cmps {
|
||||
comp := entity.(*model.ApplicationComponent)
|
||||
if comp.Creator == model.AutoGenComp {
|
||||
_ = ds.Delete(ctx, comp)
|
||||
}
|
||||
}
|
||||
return c.applicationService.DeleteApplication(ctx, app)
|
||||
|
||||
plcs, err := ds.List(ctx, &model.ApplicationPolicy{AppPrimaryKey: appName}, &datastore.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, entity := range plcs {
|
||||
comp := entity.(*model.ApplicationPolicy)
|
||||
if comp.Creator == model.AutoGenPolicy {
|
||||
_ = ds.Delete(ctx, comp)
|
||||
}
|
||||
}
|
||||
|
||||
_ = ds.Delete(ctx, &model.Workflow{Name: model.AutoGenWorkflowNamePrefix + appName})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -86,8 +86,8 @@ var _ = Describe("Test CR convert to ux", func() {
|
||||
Expect(gotApp.Labels[model.LabelSourceOfTruth]).Should(BeEquivalentTo(model.FromCR))
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(gotApp.IsSynced()).Should(BeEquivalentTo(true))
|
||||
})
|
||||
|
||||
})
|
||||
It("Test app updated and delete app", func() {
|
||||
ctx := context.Background()
|
||||
By("Preparing database")
|
||||
@@ -107,11 +107,7 @@ var _ = Describe("Test CR convert to ux", func() {
|
||||
err = k8sClient.Create(context.TODO(), &ns)
|
||||
Expect(err).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
|
||||
|
||||
cr2ux := CR2UX{
|
||||
ds: ds,
|
||||
cli: k8sClient,
|
||||
cache: sync.Map{},
|
||||
}
|
||||
cr2ux := CR2UX{ds: ds, cli: k8sClient, cache: sync.Map{}}
|
||||
|
||||
By("create test app1 and check the syncing results")
|
||||
app1 := &v1beta1.Application{}
|
||||
@@ -128,8 +124,12 @@ var _ = Describe("Test CR convert to ux", func() {
|
||||
|
||||
appPlc1 := model.ApplicationPolicy{AppPrimaryKey: app1.Name, Name: "topology-beijing-demo"}
|
||||
Expect(ds.Get(ctx, &appPlc1)).Should(BeNil())
|
||||
Expect(appPlc1.Properties).Should(BeEquivalentTo(&model.JSONStruct{"namespace": "demo", "clusterLabelSelector": map[string]interface{}{"region": "beijing"}}))
|
||||
|
||||
appPlc2 := model.ApplicationPolicy{AppPrimaryKey: app1.Name, Name: "topology-local"}
|
||||
Expect(ds.Get(ctx, &appPlc2)).Should(BeNil())
|
||||
Expect(appPlc2.Properties).Should(BeEquivalentTo(&model.JSONStruct{"targets": []interface{}{"local/demo", "local/ackone-demo"}}))
|
||||
|
||||
appwf1 := model.Workflow{AppPrimaryKey: app1.Name, Name: model.AutoGenWorkflowNamePrefix + app1.Name}
|
||||
Expect(ds.Get(ctx, &appwf1)).Should(BeNil())
|
||||
Expect(len(appwf1.Steps)).Should(BeEquivalentTo(1))
|
||||
@@ -150,7 +150,12 @@ var _ = Describe("Test CR convert to ux", func() {
|
||||
Expect(ds.Get(ctx, &appPlc2)).Should(BeEquivalentTo(datastore.ErrRecordNotExist), fmt.Sprintf("plc name %s, creator %s", appPlc2.Name, appPlc2.Creator))
|
||||
appwf2 := &model.Workflow{AppPrimaryKey: apName1, Name: appwf1.Name}
|
||||
Expect(ds.Get(ctx, appwf2)).Should(BeNil())
|
||||
|
||||
Expect(len(appwf2.Steps)).Should(BeEquivalentTo(0))
|
||||
|
||||
Expect(cr2ux.DeleteApp(ctx, app1)).Should(BeNil())
|
||||
Expect(ds.Get(context.Background(), &comp3)).Should(BeEquivalentTo(datastore.ErrRecordNotExist))
|
||||
Expect(ds.Get(context.Background(), &model.Application{Name: apName1})).Should(BeEquivalentTo(datastore.ErrRecordNotExist))
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
@@ -22,13 +22,13 @@ spec:
|
||||
- name: topology-beijing-demo
|
||||
type: topology
|
||||
properties:
|
||||
clusters: ["local"]
|
||||
namespace: beijing-demo
|
||||
clusterLabelSelector:
|
||||
region: beijing
|
||||
namespace: demo
|
||||
- name: topology-local
|
||||
type: topology
|
||||
properties:
|
||||
clusters: ["local"]
|
||||
namespace: demo
|
||||
targets: ["local/demo", "local/ackone-demo"]
|
||||
workflow:
|
||||
steps:
|
||||
- type: deploy
|
||||
|
||||
@@ -27,7 +27,6 @@ import (
|
||||
dynamicInformer "k8s.io/client-go/dynamic/dynamicinformer"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
"k8s.io/klog/v2"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
@@ -39,12 +38,10 @@ import (
|
||||
|
||||
// ApplicationSync sync application from cluster to database
|
||||
type ApplicationSync struct {
|
||||
KubeClient client.Client `inject:"kubeClient"`
|
||||
KubeConfig *rest.Config `inject:"kubeConfig"`
|
||||
Store datastore.DataStore `inject:"datastore"`
|
||||
ProjectService service.ProjectService `inject:""`
|
||||
ApplicationService service.ApplicationService `inject:""`
|
||||
Queue workqueue.Interface
|
||||
KubeClient client.Client `inject:"kubeClient"`
|
||||
KubeConfig *rest.Config `inject:"kubeConfig"`
|
||||
Store datastore.DataStore `inject:"datastore"`
|
||||
ProjectService service.ProjectService `inject:""`
|
||||
}
|
||||
|
||||
// Start prepares watchers and run their controllers, then waits for process termination signals
|
||||
@@ -67,38 +64,31 @@ func (a *ApplicationSync) Start(ctx context.Context, errorChan chan error) {
|
||||
return app
|
||||
}
|
||||
cu := &CR2UX{
|
||||
ds: a.Store,
|
||||
cli: a.KubeClient,
|
||||
cache: sync.Map{},
|
||||
projectService: a.ProjectService,
|
||||
applicationService: a.ApplicationService,
|
||||
ds: a.Store,
|
||||
cli: a.KubeClient,
|
||||
cache: sync.Map{},
|
||||
projectService: a.ProjectService,
|
||||
}
|
||||
if err = cu.initCache(ctx); err != nil {
|
||||
errorChan <- err
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
app, down := a.Queue.Get()
|
||||
if down {
|
||||
break
|
||||
}
|
||||
if err := cu.AddOrUpdate(ctx, app.(*v1beta1.Application)); err != nil {
|
||||
log.Logger.Errorf("fail to add or update application %s", err.Error())
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
handlers := cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
app := getApp(obj)
|
||||
klog.Infof("watched add app event, namespace: %s, name: %s", app.Namespace, app.Name)
|
||||
a.Queue.Add(app)
|
||||
err = cu.AddOrUpdate(ctx, app)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("Application %-30s Create Sync to db err %v", color.WhiteString(app.Namespace+"/"+app.Name), err)
|
||||
}
|
||||
},
|
||||
UpdateFunc: func(oldObj, obj interface{}) {
|
||||
app := getApp(obj)
|
||||
klog.Infof("watched update app event, namespace: %s, name: %s", app.Namespace, app.Name)
|
||||
a.Queue.Add(app)
|
||||
err = cu.AddOrUpdate(ctx, app)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("Application %-30s Update Sync to db err %v", color.WhiteString(app.Namespace+"/"+app.Name), err)
|
||||
}
|
||||
},
|
||||
DeleteFunc: func(obj interface{}) {
|
||||
app := getApp(obj)
|
||||
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/domain/model"
|
||||
@@ -62,11 +61,11 @@ var _ = Describe("Test Worker CR sync to datastore", func() {
|
||||
By("Start syncing")
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
appSync := &ApplicationSync{
|
||||
KubeClient: k8sClient,
|
||||
KubeConfig: cfg,
|
||||
Store: ds,
|
||||
Queue: workqueue.New(),
|
||||
}
|
||||
go appSync.Start(ctx, make(chan error))
|
||||
|
||||
@@ -89,14 +88,14 @@ var _ = Describe("Test Worker CR sync to datastore", func() {
|
||||
Expect(ds.Get(ctx, &comp2)).Should(BeNil())
|
||||
Expect(comp2.Properties).Should(BeEquivalentTo(&model.JSONStruct{"image": "nginx2"}))
|
||||
|
||||
env := model.Env{Project: appNS1, Name: model.AutoGenEnvNamePrefix + appNS1}
|
||||
Expect(ds.Get(ctx, &env)).Should(BeNil())
|
||||
Expect(len(env.Targets)).Should(Equal(2))
|
||||
|
||||
appPlc1 := model.ApplicationPolicy{AppPrimaryKey: app1.Name, Name: "topology-beijing-demo"}
|
||||
Expect(ds.Get(ctx, &appPlc1)).Should(BeNil())
|
||||
Expect(appPlc1.Properties).Should(BeEquivalentTo(&model.JSONStruct{"namespace": "demo", "clusterLabelSelector": map[string]interface{}{"region": "beijing"}}))
|
||||
|
||||
appPlc2 := model.ApplicationPolicy{AppPrimaryKey: app1.Name, Name: "topology-local"}
|
||||
Expect(ds.Get(ctx, &appPlc2)).Should(BeNil())
|
||||
Expect(appPlc2.Properties).Should(BeEquivalentTo(&model.JSONStruct{"targets": []interface{}{"local/demo", "local/ackone-demo"}}))
|
||||
|
||||
appwf1 := model.Workflow{AppPrimaryKey: app1.Name, Name: model.AutoGenWorkflowNamePrefix + app1.Name}
|
||||
Expect(ds.Get(ctx, &appwf1)).Should(BeNil())
|
||||
|
||||
|
||||
@@ -68,9 +68,10 @@ func ConvertAppModelToBase(app *model.Application, projects []*apisv1.ProjectBas
|
||||
Icon: app.Icon,
|
||||
Labels: app.Labels,
|
||||
Project: &apisv1.ProjectBase{Name: app.Project},
|
||||
ReadOnly: app.IsReadOnly(),
|
||||
}
|
||||
|
||||
if app.IsSynced() {
|
||||
appBase.ReadOnly = true
|
||||
}
|
||||
for _, project := range projects {
|
||||
if project.Name == app.Project {
|
||||
appBase.Project = project
|
||||
|
||||
@@ -51,7 +51,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/cue/process"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
utilscommon "github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
)
|
||||
|
||||
// constant error information
|
||||
@@ -98,21 +97,21 @@ func (wl *Workload) EvalContext(ctx process.Context) error {
|
||||
}
|
||||
|
||||
// EvalStatus eval workload status
|
||||
func (wl *Workload) EvalStatus(ctx process.Context, cli client.Client, ns string) (string, error) {
|
||||
func (wl *Workload) EvalStatus(ctx process.Context, cli client.Client, accessor util.NamespaceAccessor) (string, error) {
|
||||
// if the standard workload is managed by trait always return empty message
|
||||
if wl.SkipApplyWorkload {
|
||||
return "", nil
|
||||
}
|
||||
return wl.engine.Status(ctx, cli, ns, wl.FullTemplate.CustomStatus, wl.Params)
|
||||
return wl.engine.Status(ctx, cli, accessor, wl.FullTemplate.CustomStatus, wl.Params)
|
||||
}
|
||||
|
||||
// EvalHealth eval workload health check
|
||||
func (wl *Workload) EvalHealth(ctx process.Context, client client.Client, namespace string) (bool, error) {
|
||||
func (wl *Workload) EvalHealth(ctx process.Context, client client.Client, accessor util.NamespaceAccessor) (bool, error) {
|
||||
// if health of template is not set or standard workload is managed by trait always return true
|
||||
if wl.FullTemplate.Health == "" || wl.SkipApplyWorkload {
|
||||
return true, nil
|
||||
}
|
||||
return wl.engine.HealthCheck(ctx, client, namespace, wl.FullTemplate.Health)
|
||||
return wl.engine.HealthCheck(ctx, client, accessor, wl.FullTemplate.Health)
|
||||
}
|
||||
|
||||
// Scope defines the scope of workload
|
||||
@@ -146,16 +145,16 @@ func (trait *Trait) EvalContext(ctx process.Context) error {
|
||||
}
|
||||
|
||||
// EvalStatus eval trait status
|
||||
func (trait *Trait) EvalStatus(ctx process.Context, cli client.Client, ns string) (string, error) {
|
||||
return trait.engine.Status(ctx, cli, ns, trait.CustomStatusFormat, trait.Params)
|
||||
func (trait *Trait) EvalStatus(ctx process.Context, cli client.Client, accessor util.NamespaceAccessor) (string, error) {
|
||||
return trait.engine.Status(ctx, cli, accessor, trait.CustomStatusFormat, trait.Params)
|
||||
}
|
||||
|
||||
// EvalHealth eval trait health check
|
||||
func (trait *Trait) EvalHealth(ctx process.Context, client client.Client, namespace string) (bool, error) {
|
||||
func (trait *Trait) EvalHealth(ctx process.Context, client client.Client, accessor util.NamespaceAccessor) (bool, error) {
|
||||
if trait.FullTemplate.Health == "" {
|
||||
return true, nil
|
||||
}
|
||||
return trait.engine.HealthCheck(ctx, client, namespace, trait.HealthCheckPolicy)
|
||||
return trait.engine.HealthCheck(ctx, client, accessor, trait.HealthCheckPolicy)
|
||||
}
|
||||
|
||||
// Appfile describes application
|
||||
@@ -932,13 +931,6 @@ func (af *Appfile) LoadDynamicComponent(ctx context.Context, cli client.Client,
|
||||
}
|
||||
uns = component.AppendUnstructuredObjects(uns, objs...)
|
||||
}
|
||||
// nolint
|
||||
for _, url := range spec.URLs {
|
||||
objs := utilscommon.FilterObjectsByCondition(af.ReferredObjects, func(obj *unstructured.Unstructured) bool {
|
||||
return obj.GetAnnotations() != nil && obj.GetAnnotations()[oam.AnnotationResourceURL] == url
|
||||
})
|
||||
uns = component.AppendUnstructuredObjects(uns, objs...)
|
||||
}
|
||||
refObjs, err := component.ConvertUnstructuredsToReferredObjects(uns)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to marshal referred object")
|
||||
|
||||
@@ -232,9 +232,8 @@ func (l *LiveDiffOption) diffManifest(base, comparor *manifest) *DiffEntry {
|
||||
|
||||
// Diff does three phases, dry-run on input app, preparing manifest for diff, and
|
||||
// calculating diff on manifests.
|
||||
// TODO(wonderflow): vela live-diff don't diff for policies now.
|
||||
func (l *LiveDiffOption) Diff(ctx context.Context, app *v1beta1.Application, appRevision *v1beta1.ApplicationRevision) (*DiffEntry, error) {
|
||||
comps, _, err := l.ExecuteDryRun(ctx, app)
|
||||
comps, err := l.ExecuteDryRun(ctx, app)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessagef(err, "cannot dry-run for app %q", app.Name)
|
||||
}
|
||||
@@ -255,9 +254,8 @@ func (l *LiveDiffOption) Diff(ctx context.Context, app *v1beta1.Application, app
|
||||
|
||||
// DiffApps does three phases, dry-run on input app, preparing manifest for diff, and
|
||||
// calculating diff on manifests.
|
||||
// TODO(wonderflow): vela live-diff don't diff for policies now.
|
||||
func (l *LiveDiffOption) DiffApps(ctx context.Context, app *v1beta1.Application, oldApp *v1beta1.Application) (*DiffEntry, error) {
|
||||
comps, _, err := l.ExecuteDryRun(ctx, app)
|
||||
comps, err := l.ExecuteDryRun(ctx, app)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessagef(err, "cannot dry-run for app %q", app.Name)
|
||||
}
|
||||
@@ -267,7 +265,7 @@ func (l *LiveDiffOption) DiffApps(ctx context.Context, app *v1beta1.Application,
|
||||
return nil, errors.WithMessagef(err, "cannot generate diff manifest for app %q", app.Name)
|
||||
}
|
||||
|
||||
oldComps, _, err := l.ExecuteDryRun(ctx, oldApp)
|
||||
oldComps, err := l.ExecuteDryRun(ctx, oldApp)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessagef(err, "cannot dry-run for app %q", oldApp.Name)
|
||||
}
|
||||
|
||||
@@ -17,10 +17,8 @@ limitations under the License.
|
||||
package dryrun
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
@@ -46,7 +44,7 @@ import (
|
||||
|
||||
// DryRun executes dry-run on an application
|
||||
type DryRun interface {
|
||||
ExecuteDryRun(ctx context.Context, app *v1beta1.Application) ([]*types.ComponentManifest, []*unstructured.Unstructured, error)
|
||||
ExecuteDryRun(ctx context.Context, app *v1beta1.Application) ([]*types.ComponentManifest, error)
|
||||
}
|
||||
|
||||
// NewDryRunOption creates a dry-run option
|
||||
@@ -122,65 +120,22 @@ func (d *Option) ValidateApp(ctx context.Context, filename string) error {
|
||||
|
||||
// ExecuteDryRun simulates applying an application into cluster and returns rendered
|
||||
// resources but not persist them into cluster.
|
||||
func (d *Option) ExecuteDryRun(ctx context.Context, app *v1beta1.Application) ([]*types.ComponentManifest, []*unstructured.Unstructured, error) {
|
||||
func (d *Option) ExecuteDryRun(ctx context.Context, app *v1beta1.Application) ([]*types.ComponentManifest, error) {
|
||||
parser := appfile.NewDryRunApplicationParser(d.Client, d.DiscoveryMapper, d.PackageDiscover, d.Auxiliaries)
|
||||
if app.Namespace != "" {
|
||||
ctx = oamutil.SetNamespaceInCtx(ctx, app.Namespace)
|
||||
}
|
||||
appFile, err := parser.GenerateAppFileFromApp(ctx, app)
|
||||
if err != nil {
|
||||
return nil, nil, errors.WithMessage(err, "cannot generate appFile from application")
|
||||
return nil, errors.WithMessage(err, "cannot generate appFile from application")
|
||||
}
|
||||
if appFile.Namespace == "" {
|
||||
appFile.Namespace = corev1.NamespaceDefault
|
||||
}
|
||||
comps, err := appFile.GenerateComponentManifests()
|
||||
if err != nil {
|
||||
return nil, nil, errors.WithMessage(err, "cannot generate manifests from components and traits")
|
||||
return nil, errors.WithMessage(err, "cannot generate AppConfig and Components")
|
||||
}
|
||||
objs, err := appFile.GeneratePolicyManifests(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, errors.WithMessage(err, "cannot generate manifests from policies")
|
||||
}
|
||||
return comps, objs, nil
|
||||
}
|
||||
|
||||
// PrintDryRun will print the result of dry-run
|
||||
func (d *Option) PrintDryRun(buff *bytes.Buffer, appName string, comps []*types.ComponentManifest, policies []*unstructured.Unstructured) error {
|
||||
var components = make(map[string]*unstructured.Unstructured)
|
||||
for _, comp := range comps {
|
||||
components[comp.Name] = comp.StandardWorkload
|
||||
}
|
||||
for _, c := range comps {
|
||||
if _, err := fmt.Fprintf(buff, "---\n# Application(%s) -- Component(%s) \n---\n\n", appName, c.Name); err != nil {
|
||||
return errors.Wrap(err, "fail to write buff")
|
||||
}
|
||||
result, err := yaml.Marshal(components[c.Name])
|
||||
if err != nil {
|
||||
return errors.New("marshal result for component " + c.Name + " object in yaml format")
|
||||
}
|
||||
buff.Write(result)
|
||||
buff.WriteString("\n---\n")
|
||||
for _, t := range c.Traits {
|
||||
result, err := yaml.Marshal(t)
|
||||
if err != nil {
|
||||
return errors.New("marshal result for Component " + c.Name + " trait " + t.GetName() + " object in yaml format")
|
||||
}
|
||||
buff.Write(result)
|
||||
buff.WriteString("\n---\n")
|
||||
}
|
||||
buff.WriteString("\n")
|
||||
}
|
||||
for _, plc := range policies {
|
||||
if _, err := fmt.Fprintf(buff, "---\n# Application(%s) -- Policy(%s) \n---\n\n", appName, plc.GetName()); err != nil {
|
||||
return errors.Wrap(err, "fail to write buff")
|
||||
}
|
||||
result, err := yaml.Marshal(plc)
|
||||
if err != nil {
|
||||
return errors.New("marshal result for policy " + plc.GetName() + " object in yaml format")
|
||||
}
|
||||
buff.Write(result)
|
||||
buff.WriteString("\n---\n")
|
||||
}
|
||||
return nil
|
||||
return comps, nil
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ var _ = Describe("Test DryRun", func() {
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
By("Execute DryRun")
|
||||
comps, _, err := dryrunOpt.ExecuteDryRun(context.Background(), app)
|
||||
comps, err := dryrunOpt.ExecuteDryRun(context.Background(), app)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
expectCompYAML := readDataFromFile("./testdata/dryrun-exp-comp.yaml")
|
||||
|
||||
@@ -45,7 +45,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
policypkg "github.com/oam-dev/kubevela/pkg/policy"
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
utilscommon "github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/workflow/step"
|
||||
wftypes "github.com/oam-dev/kubevela/pkg/workflow/types"
|
||||
)
|
||||
@@ -350,16 +349,6 @@ func (p *Parser) parseReferredObjects(ctx context.Context, af *Appfile) error {
|
||||
}
|
||||
af.ReferredObjects = component.AppendUnstructuredObjects(af.ReferredObjects, objs...)
|
||||
}
|
||||
for _, url := range spec.URLs {
|
||||
objs, err := utilscommon.HTTPGetKubernetesObjects(ctx, url)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load Kubernetes objects from url %s: %w", url, err)
|
||||
}
|
||||
for _, obj := range objs {
|
||||
util.AddAnnotations(obj, map[string]string{oam.AnnotationResourceURL: url})
|
||||
}
|
||||
af.ReferredObjects = component.AppendUnstructuredObjects(af.ReferredObjects, objs...)
|
||||
}
|
||||
}
|
||||
sort.Slice(af.ReferredObjects, func(i, j int) bool {
|
||||
a, b := af.ReferredObjects[i], af.ReferredObjects[j]
|
||||
@@ -379,7 +368,6 @@ func (p *Parser) parsePoliciesFromRevision(ctx context.Context, af *Appfile) (er
|
||||
switch policy.Type {
|
||||
case v1alpha1.GarbageCollectPolicyType:
|
||||
case v1alpha1.ApplyOncePolicyType:
|
||||
case v1alpha1.SharedResourcePolicyType:
|
||||
case v1alpha1.EnvBindingPolicyType:
|
||||
case v1alpha1.TopologyPolicyType:
|
||||
case v1alpha1.OverridePolicyType:
|
||||
@@ -405,7 +393,6 @@ func (p *Parser) parsePolicies(ctx context.Context, af *Appfile) (err error) {
|
||||
switch policy.Type {
|
||||
case v1alpha1.GarbageCollectPolicyType:
|
||||
case v1alpha1.ApplyOncePolicyType:
|
||||
case v1alpha1.SharedResourcePolicyType:
|
||||
case v1alpha1.EnvBindingPolicyType:
|
||||
case v1alpha1.TopologyPolicyType:
|
||||
case v1alpha1.DebugPolicyType:
|
||||
@@ -437,12 +424,8 @@ func (p *Parser) loadWorkflowToAppfile(ctx context.Context, af *Appfile) error {
|
||||
// parse workflow steps
|
||||
af.WorkflowMode = common.WorkflowModeDAG
|
||||
if wfSpec := af.app.Spec.Workflow; wfSpec != nil && len(wfSpec.Steps) > 0 {
|
||||
af.WorkflowMode = common.WorkflowModeStep
|
||||
af.WorkflowSteps = wfSpec.Steps
|
||||
if wfSpec.Mode != nil && wfSpec.Mode.Steps == common.WorkflowModeDAG {
|
||||
af.WorkflowMode = common.WorkflowModeDAG
|
||||
} else {
|
||||
af.WorkflowMode = common.WorkflowModeStep
|
||||
}
|
||||
}
|
||||
af.WorkflowSteps, err = step.NewChainWorkflowStepGenerator(
|
||||
&step.RefWorkflowStepGenerator{Client: af.WorkflowClient(p.client), Context: ctx},
|
||||
|
||||
@@ -47,6 +47,11 @@ func ContextWithUserInfo(ctx context.Context, app *v1beta1.Application) context.
|
||||
return request.WithUser(ctx, GetUserInfoInAnnotation(&app.ObjectMeta))
|
||||
}
|
||||
|
||||
// ContextClearUserInfo clear user info in context
|
||||
func ContextClearUserInfo(ctx context.Context) context.Context {
|
||||
return request.WithUser(ctx, nil)
|
||||
}
|
||||
|
||||
// SetUserInfoInAnnotation set username and group from userInfo into annotations
|
||||
// it will clear the existing service account annotation in avoid of permission leak
|
||||
func SetUserInfoInAnnotation(obj *metav1.ObjectMeta, userInfo authv1.UserInfo) {
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -37,8 +37,6 @@ import (
|
||||
velaclient "github.com/oam-dev/kubevela/pkg/client"
|
||||
"github.com/oam-dev/kubevela/pkg/features"
|
||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
utilscommon "github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -170,9 +168,6 @@ func SelectRefObjectsForDispatch(ctx context.Context, cli client.Client, appNs s
|
||||
|
||||
// ReferredObjectsDelegatingClient delegate client get/list function by retrieving ref-objects from existing objects
|
||||
func ReferredObjectsDelegatingClient(cli client.Client, objs []*unstructured.Unstructured) client.Client {
|
||||
objs = utilscommon.FilterObjectsByCondition(objs, func(obj *unstructured.Unstructured) bool {
|
||||
return obj.GetAnnotations() == nil || obj.GetAnnotations()[oam.AnnotationResourceURL] == ""
|
||||
})
|
||||
return velaclient.DelegatingHandlerClient{
|
||||
Client: cli,
|
||||
Getter: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
|
||||
@@ -213,15 +213,23 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
|
||||
app.Status.Services = handler.services
|
||||
switch workflowState {
|
||||
case common.WorkflowStateInitializing:
|
||||
metrics.WorkflowInitializedCounter.WithLabelValues().Inc()
|
||||
logCtx.Info("Workflow return state=Initializing")
|
||||
handler.UpdateApplicationRevisionStatus(logCtx, handler.currentAppRev, false, app.Status.Workflow)
|
||||
return r.gcResourceTrackers(logCtx, handler, common.ApplicationRendering, false, false)
|
||||
case common.WorkflowStateSuspended:
|
||||
logCtx.Info("Workflow return state=Suspend")
|
||||
if duration := wf.GetSuspendBackoffWaitTime(); duration > 0 {
|
||||
_, err = r.gcResourceTrackers(logCtx, handler, common.ApplicationWorkflowSuspending, false, true)
|
||||
return r.result(err).requeue(duration).ret()
|
||||
doWaiting, durationWaiting, err := wf.HandleSuspendWait(logCtx)
|
||||
if err != nil {
|
||||
return r.endWithNegativeCondition(logCtx, app, condition.ErrorCondition(common.WorkflowCondition.String(), err), common.ApplicationRunningWorkflow)
|
||||
}
|
||||
if doWaiting {
|
||||
if durationWaiting > 0 {
|
||||
_, err = r.gcResourceTrackers(logCtx, handler, common.ApplicationWorkflowSuspending, false, true)
|
||||
return r.result(err).requeue(durationWaiting).ret()
|
||||
}
|
||||
handler.app.Status.Workflow.Suspend = false
|
||||
handler.app.Status.Workflow.SuspendState = ""
|
||||
return r.gcResourceTrackers(logCtx, handler, common.ApplicationRunningWorkflow, false, false)
|
||||
}
|
||||
if !workflow.IsFailedAfterRetry(app) || !feature.DefaultMutableFeatureGate.Enabled(features.EnableSuspendOnFailure) {
|
||||
r.stateKeep(logCtx, handler, app)
|
||||
@@ -230,7 +238,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
|
||||
case common.WorkflowStateTerminated:
|
||||
logCtx.Info("Workflow return state=Terminated")
|
||||
handler.UpdateApplicationRevisionStatus(logCtx, handler.latestAppRev, false, app.Status.Workflow)
|
||||
if err := r.doWorkflowFinish(app, wf, workflowState); err != nil {
|
||||
if err := r.doWorkflowFinish(app, wf); err != nil {
|
||||
return r.endWithNegativeCondition(ctx, app, condition.ErrorCondition(common.WorkflowCondition.String(), errors.WithMessage(err, "DoWorkflowFinish")), common.ApplicationRunningWorkflow)
|
||||
}
|
||||
return r.gcResourceTrackers(logCtx, handler, common.ApplicationWorkflowTerminated, false, true)
|
||||
@@ -241,7 +249,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
|
||||
case common.WorkflowStateSucceeded:
|
||||
logCtx.Info("Workflow return state=Succeeded")
|
||||
handler.UpdateApplicationRevisionStatus(logCtx, handler.currentAppRev, true, app.Status.Workflow)
|
||||
if err := r.doWorkflowFinish(app, wf, workflowState); err != nil {
|
||||
if err := r.doWorkflowFinish(app, wf); err != nil {
|
||||
return r.endWithNegativeCondition(logCtx, app, condition.ErrorCondition(common.WorkflowCondition.String(), errors.WithMessage(err, "DoWorkflowFinish")), common.ApplicationRunningWorkflow)
|
||||
}
|
||||
app.Status.SetConditions(condition.ReadyCondition(common.WorkflowCondition.String()))
|
||||
@@ -433,13 +441,11 @@ func (r *Reconciler) updateStatus(ctx context.Context, app *v1beta1.Application,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Reconciler) doWorkflowFinish(app *v1beta1.Application, wf workflow.Workflow, state common.WorkflowState) error {
|
||||
func (r *Reconciler) doWorkflowFinish(app *v1beta1.Application, wf workflow.Workflow) error {
|
||||
app.Status.Workflow.Finished = true
|
||||
if err := wf.Trace(); err != nil {
|
||||
return errors.WithMessage(err, "record workflow state")
|
||||
}
|
||||
t := time.Since(app.Status.Workflow.StartTime.Time).Seconds()
|
||||
metrics.WorkflowFinishedTimeHistogram.WithLabelValues(string(state)).Observe(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user