mirror of
https://github.com/kubevela/kubevela.git
synced 2026-02-27 00:04:07 +00:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c2df10299 | ||
|
|
918ed9727b | ||
|
|
fa78cb7632 | ||
|
|
f3cdbcf203 | ||
|
|
7bd2cf4dbc | ||
|
|
969babdd9e | ||
|
|
94c46a179b | ||
|
|
bec288c6b4 | ||
|
|
9a44be9788 | ||
|
|
9c7f4b7e03 | ||
|
|
539f1ed02b | ||
|
|
9e95122387 | ||
|
|
f49f11dd72 | ||
|
|
191d9038f1 | ||
|
|
e10e43b6c8 | ||
|
|
b9cc523267 | ||
|
|
7f1743ef58 | ||
|
|
dd39c38cf1 | ||
|
|
0851454c6f | ||
|
|
cd3577db53 | ||
|
|
d578adfe6e | ||
|
|
4b88cd201e | ||
|
|
492e7d7f0d | ||
|
|
0742ca9ee5 | ||
|
|
1cf4ae3fc3 | ||
|
|
444d315143 | ||
|
|
2e3a89f6b1 | ||
|
|
d94293ac59 | ||
|
|
cc604cfadb |
2
.github/workflows/apiserver-test.yml
vendored
2
.github/workflows/apiserver-test.yml
vendored
@@ -186,7 +186,7 @@ jobs:
|
||||
uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
files: /tmp/e2e_apiserver_test.out
|
||||
files: /tmp/e2e-profile.out, /tmp/e2e_apiserver_test.out
|
||||
flags: apiserver-e2etests
|
||||
name: codecov-umbrella
|
||||
|
||||
|
||||
133
.github/workflows/release.yml
vendored
133
.github/workflows/release.yml
vendored
@@ -7,7 +7,6 @@ on:
|
||||
workflow_dispatch: { }
|
||||
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BUCKET: ${{ secrets.CLI_OSS_BUCKET }}
|
||||
ENDPOINT: ${{ secrets.CLI_OSS_ENDPOINT }}
|
||||
ACCESS_KEY: ${{ secrets.CLI_OSS_ACCESS_KEY }}
|
||||
@@ -28,105 +27,36 @@ jobs:
|
||||
repository-projects: read
|
||||
statuses: read
|
||||
runs-on: ubuntu-latest
|
||||
name: build
|
||||
strategy:
|
||||
matrix:
|
||||
TARGETS: [ linux/amd64, darwin/amd64, windows/amd64, linux/arm64, darwin/arm64 ]
|
||||
env:
|
||||
VELA_VERSION_KEY: github.com/oam-dev/kubevela/version.VelaVersion
|
||||
VELA_GITVERSION_KEY: github.com/oam-dev/kubevela/version.GitRevision
|
||||
GO_BUILD_ENV: GO111MODULE=on CGO_ENABLED=0
|
||||
DIST_DIRS: find * -type d -exec
|
||||
name: goreleaser
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: git fetch --force --tags
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568
|
||||
with:
|
||||
go-version: 1.19
|
||||
- name: Get release
|
||||
id: get_release
|
||||
uses: bruceadams/get-release@74c3d60f5a28f358ccf241a00c9021ea16f0569f # v1.3.2
|
||||
cache: true
|
||||
- uses: goreleaser/goreleaser-action@9754a253a8673b0ea869c2e863b4e975497efd0c # v4.1.1
|
||||
with:
|
||||
distribution: goreleaser
|
||||
version: 1.14.1
|
||||
args: release --rm-dist --timeout 60m
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Since goreleaser haven't supported aliyun OSS, we need to upload the release manually
|
||||
- name: Get version
|
||||
run: echo "VELA_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
||||
- name: Get matrix
|
||||
id: get_matrix
|
||||
run: |
|
||||
TARGETS=${{matrix.TARGETS}}
|
||||
echo "OS=${TARGETS%/*}" >> $GITHUB_OUTPUT
|
||||
echo "ARCH=${TARGETS#*/}" >> $GITHUB_OUTPUT
|
||||
- name: Get ldflags
|
||||
id: get_ldflags
|
||||
run: |
|
||||
LDFLAGS="-s -w -X ${{ env.VELA_VERSION_KEY }}=${{ env.VELA_VERSION }} -X ${{ env.VELA_GITVERSION_KEY }}=git-$(git rev-parse --short HEAD)"
|
||||
echo "LDFLAGS=${LDFLAGS}" >> $GITHUB_ENV
|
||||
- name: Build
|
||||
run: |
|
||||
${{ env.GO_BUILD_ENV }} GOOS=${{ steps.get_matrix.outputs.OS }} GOARCH=${{ steps.get_matrix.outputs.ARCH }} \
|
||||
go build -ldflags "${{ env.LDFLAGS }}" \
|
||||
-o _bin/vela/${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}/vela -v \
|
||||
./references/cmd/cli/main.go
|
||||
${{ env.GO_BUILD_ENV }} GOOS=${{ steps.get_matrix.outputs.OS }} GOARCH=${{ steps.get_matrix.outputs.ARCH }} \
|
||||
go build -ldflags "${{ env.LDFLAGS }}" \
|
||||
-o _bin/kubectl-vela/${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}/kubectl-vela -v \
|
||||
./cmd/plugin/main.go
|
||||
- name: Compress
|
||||
run: |
|
||||
echo "\n## Release Info\nVERSION: ${{ env.VELA_VERSION }}" >> README.md && \
|
||||
echo "GIT_COMMIT: ${GITHUB_SHA}\n" >> README.md && \
|
||||
cd _bin/vela && \
|
||||
${{ env.DIST_DIRS }} cp ../../LICENSE {} \; && \
|
||||
${{ env.DIST_DIRS }} cp ../../README.md {} \; && \
|
||||
${{ env.DIST_DIRS }} tar -zcf vela-{}.tar.gz {} \; && \
|
||||
${{ env.DIST_DIRS }} zip -r vela-{}.zip {} \; && \
|
||||
cd ../kubectl-vela && \
|
||||
${{ env.DIST_DIRS }} cp ../../LICENSE {} \; && \
|
||||
${{ env.DIST_DIRS }} cp ../../README.md {} \; && \
|
||||
${{ env.DIST_DIRS }} tar -zcf kubectl-vela-{}.tar.gz {} \; && \
|
||||
${{ env.DIST_DIRS }} zip -r kubectl-vela-{}.zip {} \; && \
|
||||
cd .. && \
|
||||
sha256sum vela/vela-* kubectl-vela/kubectl-vela-* >> sha256-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.txt \
|
||||
- name: Upload Vela tar.gz
|
||||
uses: kubevela/vela-upload-release-asset@9b3858e67d3205e056d6220e5972abb32fc47289 # v1.0.0
|
||||
with:
|
||||
release_id: ${{ steps.get_release.outputs.id }}
|
||||
asset_path: ./_bin/vela/vela-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.tar.gz
|
||||
asset_name: vela-${{ env.VELA_VERSION }}-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.tar.gz
|
||||
- name: Upload Vela zip
|
||||
uses: kubevela/vela-upload-release-asset@9b3858e67d3205e056d6220e5972abb32fc47289 # v1.0.0
|
||||
with:
|
||||
release_id: ${{ steps.get_release.outputs.id }}
|
||||
asset_path: ./_bin/vela/vela-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.zip
|
||||
asset_name: vela-${{ env.VELA_VERSION }}-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.zip
|
||||
- name: Upload Kubectl-Vela tar.gz
|
||||
uses: kubevela/vela-upload-release-asset@9b3858e67d3205e056d6220e5972abb32fc47289 # v1.0.0
|
||||
with:
|
||||
release_id: ${{ steps.get_release.outputs.id }}
|
||||
asset_path: ./_bin/kubectl-vela/kubectl-vela-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.tar.gz
|
||||
asset_name: kubectl-vela-${{ env.VELA_VERSION }}-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.tar.gz
|
||||
- name: Upload Kubectl-Vela zip
|
||||
uses: kubevela/vela-upload-release-asset@9b3858e67d3205e056d6220e5972abb32fc47289 # v1.0.0
|
||||
with:
|
||||
release_id: ${{ steps.get_release.outputs.id }}
|
||||
asset_path: ./_bin/kubectl-vela/kubectl-vela-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.zip
|
||||
asset_name: kubectl-vela-${{ env.VELA_VERSION }}-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.zip
|
||||
- name: Post sha256
|
||||
uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # v3.1.1
|
||||
with:
|
||||
name: sha256sums
|
||||
path: ./_bin/sha256-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.txt
|
||||
retention-days: 1
|
||||
- name: clear the asset
|
||||
run: |
|
||||
rm -rf ./_bin/vela/${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}
|
||||
mv ./_bin/vela/vela-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.tar.gz ./_bin/vela/vela-${{ env.VELA_VERSION }}-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.tar.gz
|
||||
mv ./_bin/vela/vela-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.zip ./_bin/vela/vela-${{ env.VELA_VERSION }}-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.zip
|
||||
- name: Install ossutil
|
||||
run: wget http://gosspublic.alicdn.com/ossutil/1.7.0/ossutil64 && chmod +x ossutil64 && mv ossutil64 ossutil
|
||||
- name: Configure Alibaba Cloud OSSUTIL
|
||||
run: ./ossutil --config-file .ossutilconfig config -i ${ACCESS_KEY} -k ${ACCESS_KEY_SECRET} -e ${ENDPOINT} -c .ossutilconfig
|
||||
run: ./ossutil --config-file .ossutilconfig config -i ${ACCESS_KEY} -k ${ACCESS_KEY_SECRET} -e ${ENDPOINT}
|
||||
- name: split files to be upload
|
||||
run: mkdir -p ./dist/files_upload && mv ./dist/*.tar.gz ./dist/files_upload && mv ./dist/*.zip ./dist/files_upload
|
||||
- name: sync local to cloud
|
||||
run: ./ossutil --config-file .ossutilconfig sync ./_bin/vela oss://$BUCKET/binary/vela/${{ env.VELA_VERSION }}
|
||||
run: ./ossutil --config-file .ossutilconfig sync ./dist/files_upload oss://$BUCKET/binary/vela/${{ env.VELA_VERSION }}
|
||||
- name: sync the latest version file
|
||||
if: ${{ !contains(env.VELA_VERSION,'alpha') && !contains(env.VELA_VERSION,'beta') }}
|
||||
run: |
|
||||
@@ -137,7 +67,6 @@ jobs:
|
||||
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
|
||||
|
||||
upload-plugin-homebrew:
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -154,34 +83,6 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b
|
||||
- name: Get release
|
||||
id: get_release
|
||||
uses: bruceadams/get-release@74c3d60f5a28f358ccf241a00c9021ea16f0569f # v1.3.2
|
||||
- name: Download sha256sums
|
||||
uses: actions/download-artifact@9782bd6a9848b53b110e712e20e42d89988822b7 # v3.0.1
|
||||
with:
|
||||
name: sha256sums
|
||||
path: cli-artifacts
|
||||
- name: Display structure of downloaded files
|
||||
run: ls -R
|
||||
working-directory: cli-artifacts
|
||||
- name: Get version
|
||||
run: echo "VELA_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
||||
- shell: bash
|
||||
working-directory: cli-artifacts
|
||||
run: |
|
||||
for file in *
|
||||
do
|
||||
sed -i "s/\/vela/-${{ env.VELA_VERSION }}/g" ${file}
|
||||
sed -i "s/\/kubectl-vela/-${{ env.VELA_VERSION }}/g" ${file}
|
||||
cat ${file} >> sha256sums.txt
|
||||
done
|
||||
- name: Upload Checksums
|
||||
uses: kubevela/vela-upload-release-asset@9b3858e67d3205e056d6220e5972abb32fc47289 # v1.0.0
|
||||
with:
|
||||
release_id: ${{ steps.get_release.outputs.id }}
|
||||
asset_path: cli-artifacts/sha256sums.txt
|
||||
asset_name: sha256sums.txt
|
||||
- name: Update kubectl plugin version in krew-index
|
||||
uses: rajatjindal/krew-release-bot@3320c0b546b5d2320613c46762bd3f73e2801bdc # v0.0.38
|
||||
- name: Update Homebrew formula
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -53,3 +53,5 @@ git-page/
|
||||
# e2e rollout runtime image build
|
||||
runtime/rollout/e2e/tmp
|
||||
vela.json
|
||||
|
||||
dist/
|
||||
|
||||
76
.goreleaser.yaml
Normal file
76
.goreleaser.yaml
Normal file
@@ -0,0 +1,76 @@
|
||||
# This is an example .goreleaser.yml file with some sensible defaults.
|
||||
# Make sure to check the documentation at https://goreleaser.com
|
||||
builds:
|
||||
- id: vela-cli
|
||||
binary: vela
|
||||
goos:
|
||||
- linux
|
||||
- windows
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
- arm64
|
||||
main: ./references/cmd/cli/main.go
|
||||
ldflags:
|
||||
- -s -w -X github.com/oam-dev/kubevela/version.VelaVersion={{ .Version }} -X github.com/oam-dev/kubevela/version.GitRevision=git-{{.ShortCommit}}
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
|
||||
- id: kubectl-vela
|
||||
binary: kubectl-vela
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- linux
|
||||
- windows
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
- arm64
|
||||
main: ./cmd/plugin/main.go
|
||||
ldflags:
|
||||
- -s -w -X github.com/oam-dev/kubevela/version.VelaVersion={{ .Version }} -X github.com/oam-dev/kubevela/version.GitRevision=git-{{.ShortCommit}}
|
||||
|
||||
archives:
|
||||
- format: tar.gz
|
||||
id: vela-cli-tgz
|
||||
wrap_in_directory: '{{ .Os }}-{{ .Arch }}'
|
||||
builds:
|
||||
- vela-cli
|
||||
name_template: '{{ trimsuffix .ArtifactName ".exe" }}-{{ .Tag }}-{{ .Os }}-{{ .Arch }}'
|
||||
files: [ LICENSE, README.md ]
|
||||
- format: zip
|
||||
id: vela-cli-zip
|
||||
builds:
|
||||
- vela-cli
|
||||
wrap_in_directory: '{{ .Os }}-{{ .Arch }}'
|
||||
name_template: '{{ trimsuffix .ArtifactName ".exe" }}-{{ .Tag }}-{{ .Os }}-{{ .Arch }}'
|
||||
files: [ LICENSE, README.md ]
|
||||
- format: tar.gz
|
||||
id: plugin-tgz
|
||||
builds:
|
||||
- kubectl-vela
|
||||
wrap_in_directory: '{{ .Os }}-{{ .Arch }}'
|
||||
name_template: '{{ trimsuffix .ArtifactName ".exe" }}-{{ .Tag }}-{{ .Os }}-{{ .Arch }}'
|
||||
files: [ LICENSE, README.md ]
|
||||
- format: zip
|
||||
id: plugin-zip
|
||||
builds:
|
||||
- kubectl-vela
|
||||
wrap_in_directory: '{{ .Os }}-{{ .Arch }}'
|
||||
name_template: '{{ trimsuffix .ArtifactName ".exe" }}-{{ .Tag }}-{{ .Os }}-{{ .Arch }}'
|
||||
files: [ LICENSE, README.md ]
|
||||
|
||||
checksum:
|
||||
name_template: 'sha256sums.txt'
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- '^docs:'
|
||||
- '^test:'
|
||||
|
||||
# The lines beneath this are called `modelines`. See `:help modeline`
|
||||
# Feel free to remove those if you don't want/use them.
|
||||
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
|
||||
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
|
||||
@@ -33,8 +33,8 @@ spec:
|
||||
arch: amd64
|
||||
{{addURIAndSha "https://github.com/oam-dev/kubevela/releases/download/{{ .TagName }}/kubectl-vela-{{ .TagName }}-windows-amd64.zip" .TagName }}
|
||||
files:
|
||||
- from: "*/kubectl-vela"
|
||||
to: "kubectl-vela.exe"
|
||||
- from: "*/kubectl-vela.exe"
|
||||
to: "."
|
||||
- from: "*/LICENSE"
|
||||
to: "."
|
||||
bin: "kubectl-vela.exe"
|
||||
|
||||
@@ -111,7 +111,7 @@ helm install --create-namespace -n vela-system kubevela kubevela/vela-core --wai
|
||||
| `multicluster.clusterGateway.replicaCount` | ClusterGateway replica count | `1` |
|
||||
| `multicluster.clusterGateway.port` | ClusterGateway port | `9443` |
|
||||
| `multicluster.clusterGateway.image.repository` | ClusterGateway image repository | `oamdev/cluster-gateway` |
|
||||
| `multicluster.clusterGateway.image.tag` | ClusterGateway image tag | `v1.7.0-alpha.3` |
|
||||
| `multicluster.clusterGateway.image.tag` | ClusterGateway image tag | `v1.7.0` |
|
||||
| `multicluster.clusterGateway.image.pullPolicy` | ClusterGateway image pull policy | `IfNotPresent` |
|
||||
| `multicluster.clusterGateway.resources.limits.cpu` | ClusterGateway cpu limit | `100m` |
|
||||
| `multicluster.clusterGateway.resources.limits.memory` | ClusterGateway memory limit | `200Mi` |
|
||||
|
||||
@@ -116,7 +116,7 @@ spec:
|
||||
#ECProvider: {
|
||||
type: "ec"
|
||||
apiKey: *"" | string
|
||||
name: "ec-provider" | string
|
||||
name: *"ec-provider" | string
|
||||
}
|
||||
#GCPProvider: {
|
||||
credentials: string
|
||||
|
||||
@@ -72,7 +72,7 @@ spec:
|
||||
}]
|
||||
}
|
||||
}
|
||||
parameter: *#PatchParams | close({
|
||||
parameter: #PatchParams | close({
|
||||
// +usage=Specify the container image for multiple containers
|
||||
containers: [...#PatchParams]
|
||||
})
|
||||
|
||||
@@ -53,7 +53,10 @@ spec:
|
||||
}
|
||||
if service.spec.type == "LoadBalancer" {
|
||||
status: service.status
|
||||
isHealth: status != _|_ && status.loadBalancer != _|_ && status.loadBalancer.ingress != _|_ && len(status.loadBalancer.ingress) > 0
|
||||
isHealth: *false | bool
|
||||
if status != _|_ if status.loadBalancer != _|_ if status.loadBalancer.ingress != _|_ if len(status.loadBalancer.ingress) > 0 if status.loadBalancer.ingress[0].ip != _|_ {
|
||||
isHealth: true
|
||||
}
|
||||
if !isHealth {
|
||||
message: "ExternalIP: Pending"
|
||||
}
|
||||
@@ -62,10 +65,15 @@ spec:
|
||||
}
|
||||
}
|
||||
healthPolicy: |-
|
||||
isHealth: *true | bool
|
||||
service: context.outputs.service
|
||||
if service.spec.type == "LoadBalancer" {
|
||||
status: service.status
|
||||
isHealth: status != _|_ && status.loadBalancer != _|_ && status.loadBalancer.ingress != _|_ && len(status.loadBalancer.ingress) > 0
|
||||
isHealth: *false | bool
|
||||
if status != _|_ if status.loadBalancer != _|_ if status.loadBalancer.ingress != _|_ if len(status.loadBalancer.ingress) > 0 if status.loadBalancer.ingress[0].ip != _|_ {
|
||||
isHealth: true
|
||||
}
|
||||
}
|
||||
if service.spec.type != "LoadBalancer" {
|
||||
isHealth: true
|
||||
}
|
||||
|
||||
|
||||
@@ -56,44 +56,41 @@ spec:
|
||||
// +usage=Specify the message that you want to sent, refer to [dingtalk messaging](https://developers.dingtalk.com/document/robots/custom-robot-access/title-72m-8ag-pqw)
|
||||
message: {
|
||||
// +usage=Specify the message content of dingtalk notification
|
||||
text?: *null | close({
|
||||
text?: close({
|
||||
content: string
|
||||
})
|
||||
// +usage=msgType can be text, link, mardown, actionCard, feedCard
|
||||
msgtype: *"text" | "link" | "markdown" | "actionCard" | "feedCard"
|
||||
link?: *null | close({
|
||||
#link: {
|
||||
text?: string
|
||||
title?: string
|
||||
messageUrl?: string
|
||||
picUrl?: string
|
||||
})
|
||||
markdown?: *null | close({
|
||||
}
|
||||
|
||||
link?: #link
|
||||
markdown?: close({
|
||||
text: string
|
||||
title: string
|
||||
})
|
||||
at?: *null | close({
|
||||
atMobiles?: *null | [...string]
|
||||
isAtAll?: bool
|
||||
at?: close({
|
||||
atMobiles?: [...string]
|
||||
isAtAll?: bool
|
||||
})
|
||||
actionCard?: *null | close({
|
||||
actionCard?: close({
|
||||
text: string
|
||||
title: string
|
||||
hideAvatar: string
|
||||
btnOrientation: string
|
||||
singleTitle: string
|
||||
singleURL: string
|
||||
btns: *null | close([...*null | close({
|
||||
btns?: [...close({
|
||||
title: string
|
||||
actionURL: string
|
||||
})])
|
||||
})]
|
||||
})
|
||||
feedCard?: *null | close({
|
||||
links: *null | close([...*null | close({
|
||||
text?: string
|
||||
title?: string
|
||||
messageUrl?: string
|
||||
picUrl?: string
|
||||
})])
|
||||
feedCard?: close({
|
||||
links: [...#link]
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -114,11 +111,11 @@ spec:
|
||||
// +usage=Specify the message that you want to sent, refer to [slack messaging](https://api.slack.com/reference/messaging/payload)
|
||||
message: {
|
||||
// +usage=Specify the message text for slack notification
|
||||
text: string
|
||||
blocks?: *null | close([...block])
|
||||
attachments?: *null | close({
|
||||
blocks?: *null | close([...block])
|
||||
color?: string
|
||||
text: string
|
||||
blocks?: [...block]
|
||||
attachments?: close({
|
||||
blocks?: [...block]
|
||||
color?: string
|
||||
})
|
||||
thread_ts?: string
|
||||
// +usage=Specify the message text format in markdown for slack notification
|
||||
|
||||
@@ -13,7 +13,7 @@ spec:
|
||||
template: |
|
||||
#PolicyRule: {
|
||||
// +usage=Specify how to select the targets of the rule
|
||||
selector: [...#RuleSelector]
|
||||
selector: #RuleSelector
|
||||
}
|
||||
#RuleSelector: {
|
||||
// +usage=Select resources by component names
|
||||
|
||||
@@ -272,8 +272,8 @@ spec:
|
||||
- "--feature-gates=ZstdResourceTracker={{- .Values.featureGates.zstdResourceTracker | toString -}}"
|
||||
- "--feature-gates=ApplyOnce={{- .Values.featureGates.applyOnce | toString -}}"
|
||||
- "--feature-gates=MultiStageComponentApply= {{- .Values.featureGates.multiStageComponentApply | toString -}}"
|
||||
- "--feature-gates=GzipApplicationRevision={{- .Values.featureGates.gzipResourceTracker | toString -}}"
|
||||
- "--feature-gates=ZstdApplicationRevision={{- .Values.featureGates.zstdResourceTracker | toString -}}"
|
||||
- "--feature-gates=GzipApplicationRevision={{- .Values.featureGates.gzipApplicationRevision | toString -}}"
|
||||
- "--feature-gates=ZstdApplicationRevision={{- .Values.featureGates.zstdApplicationRevision | toString -}}"
|
||||
- "--feature-gates=PreDispatchDryRun={{- .Values.featureGates.preDispatchDryRun | toString -}}"
|
||||
{{ if .Values.authentication.enabled }}
|
||||
{{ if .Values.authentication.withUser }}
|
||||
|
||||
@@ -2,7 +2,7 @@ apiVersion: v1
|
||||
data:
|
||||
template: |
|
||||
import (
|
||||
"vela/ql"
|
||||
"vela/ql"
|
||||
)
|
||||
|
||||
parameter: {
|
||||
@@ -55,9 +55,15 @@ data:
|
||||
phase: pod.object.status.phase
|
||||
// refer to https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
|
||||
if phase != "Pending" && phase != "Unknown" {
|
||||
podIP: pod.object.status.podIP
|
||||
hostIP: pod.object.status.hostIP
|
||||
nodeName: pod.object.spec.nodeName
|
||||
if pod.object.podIP != _|_ {
|
||||
podIP: pod.object.status.podIP
|
||||
}
|
||||
if pod.object.hostIP != _|_ {
|
||||
hostIP: pod.object.status.hostIP
|
||||
}
|
||||
if pod.object.nodeName != _|_ {
|
||||
nodeName: pod.object.spec.nodeName
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
|
||||
@@ -148,7 +148,7 @@ multicluster:
|
||||
port: 9443
|
||||
image:
|
||||
repository: oamdev/cluster-gateway
|
||||
tag: v1.7.0-alpha.3
|
||||
tag: v1.7.0
|
||||
pullPolicy: IfNotPresent
|
||||
resources:
|
||||
limits:
|
||||
|
||||
@@ -105,7 +105,7 @@ helm install --create-namespace -n vela-system kubevela kubevela/vela-minimal --
|
||||
| `multicluster.clusterGateway.replicaCount` | ClusterGateway replica count | `1` |
|
||||
| `multicluster.clusterGateway.port` | ClusterGateway port | `9443` |
|
||||
| `multicluster.clusterGateway.image.repository` | ClusterGateway image repository | `oamdev/cluster-gateway` |
|
||||
| `multicluster.clusterGateway.image.tag` | ClusterGateway image tag | `v1.4.0` |
|
||||
| `multicluster.clusterGateway.image.tag` | ClusterGateway image tag | `v1.7.0` |
|
||||
| `multicluster.clusterGateway.image.pullPolicy` | ClusterGateway image pull policy | `IfNotPresent` |
|
||||
| `multicluster.clusterGateway.resources.limits.cpu` | ClusterGateway cpu limit | `100m` |
|
||||
| `multicluster.clusterGateway.resources.limits.memory` | ClusterGateway memory limit | `200Mi` |
|
||||
|
||||
@@ -116,7 +116,7 @@ spec:
|
||||
#ECProvider: {
|
||||
type: "ec"
|
||||
apiKey: *"" | string
|
||||
name: "ec-provider" | string
|
||||
name: *"ec-provider" | string
|
||||
}
|
||||
#GCPProvider: {
|
||||
credentials: string
|
||||
|
||||
@@ -72,7 +72,7 @@ spec:
|
||||
}]
|
||||
}
|
||||
}
|
||||
parameter: *#PatchParams | close({
|
||||
parameter: #PatchParams | close({
|
||||
// +usage=Specify the container image for multiple containers
|
||||
containers: [...#PatchParams]
|
||||
})
|
||||
|
||||
@@ -53,7 +53,10 @@ spec:
|
||||
}
|
||||
if service.spec.type == "LoadBalancer" {
|
||||
status: service.status
|
||||
isHealth: status != _|_ && status.loadBalancer != _|_ && status.loadBalancer.ingress != _|_ && len(status.loadBalancer.ingress) > 0
|
||||
isHealth: *false | bool
|
||||
if status != _|_ if status.loadBalancer != _|_ if status.loadBalancer.ingress != _|_ if len(status.loadBalancer.ingress) > 0 if status.loadBalancer.ingress[0].ip != _|_ {
|
||||
isHealth: true
|
||||
}
|
||||
if !isHealth {
|
||||
message: "ExternalIP: Pending"
|
||||
}
|
||||
@@ -62,10 +65,15 @@ spec:
|
||||
}
|
||||
}
|
||||
healthPolicy: |-
|
||||
isHealth: *true | bool
|
||||
service: context.outputs.service
|
||||
if service.spec.type == "LoadBalancer" {
|
||||
status: service.status
|
||||
isHealth: status != _|_ && status.loadBalancer != _|_ && status.loadBalancer.ingress != _|_ && len(status.loadBalancer.ingress) > 0
|
||||
isHealth: *false | bool
|
||||
if status != _|_ if status.loadBalancer != _|_ if status.loadBalancer.ingress != _|_ if len(status.loadBalancer.ingress) > 0 if status.loadBalancer.ingress[0].ip != _|_ {
|
||||
isHealth: true
|
||||
}
|
||||
}
|
||||
if service.spec.type != "LoadBalancer" {
|
||||
isHealth: true
|
||||
}
|
||||
|
||||
|
||||
@@ -56,44 +56,41 @@ spec:
|
||||
// +usage=Specify the message that you want to sent, refer to [dingtalk messaging](https://developers.dingtalk.com/document/robots/custom-robot-access/title-72m-8ag-pqw)
|
||||
message: {
|
||||
// +usage=Specify the message content of dingtalk notification
|
||||
text?: *null | close({
|
||||
text?: close({
|
||||
content: string
|
||||
})
|
||||
// +usage=msgType can be text, link, mardown, actionCard, feedCard
|
||||
msgtype: *"text" | "link" | "markdown" | "actionCard" | "feedCard"
|
||||
link?: *null | close({
|
||||
#link: {
|
||||
text?: string
|
||||
title?: string
|
||||
messageUrl?: string
|
||||
picUrl?: string
|
||||
})
|
||||
markdown?: *null | close({
|
||||
}
|
||||
|
||||
link?: #link
|
||||
markdown?: close({
|
||||
text: string
|
||||
title: string
|
||||
})
|
||||
at?: *null | close({
|
||||
atMobiles?: *null | [...string]
|
||||
isAtAll?: bool
|
||||
at?: close({
|
||||
atMobiles?: [...string]
|
||||
isAtAll?: bool
|
||||
})
|
||||
actionCard?: *null | close({
|
||||
actionCard?: close({
|
||||
text: string
|
||||
title: string
|
||||
hideAvatar: string
|
||||
btnOrientation: string
|
||||
singleTitle: string
|
||||
singleURL: string
|
||||
btns: *null | close([...*null | close({
|
||||
btns?: [...close({
|
||||
title: string
|
||||
actionURL: string
|
||||
})])
|
||||
})]
|
||||
})
|
||||
feedCard?: *null | close({
|
||||
links: *null | close([...*null | close({
|
||||
text?: string
|
||||
title?: string
|
||||
messageUrl?: string
|
||||
picUrl?: string
|
||||
})])
|
||||
feedCard?: close({
|
||||
links: [...#link]
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -114,11 +111,11 @@ spec:
|
||||
// +usage=Specify the message that you want to sent, refer to [slack messaging](https://api.slack.com/reference/messaging/payload)
|
||||
message: {
|
||||
// +usage=Specify the message text for slack notification
|
||||
text: string
|
||||
blocks?: *null | close([...block])
|
||||
attachments?: *null | close({
|
||||
blocks?: *null | close([...block])
|
||||
color?: string
|
||||
text: string
|
||||
blocks?: [...block]
|
||||
attachments?: close({
|
||||
blocks?: [...block]
|
||||
color?: string
|
||||
})
|
||||
thread_ts?: string
|
||||
// +usage=Specify the message text format in markdown for slack notification
|
||||
|
||||
@@ -13,7 +13,7 @@ spec:
|
||||
template: |
|
||||
#PolicyRule: {
|
||||
// +usage=Specify how to select the targets of the rule
|
||||
selector: [...#RuleSelector]
|
||||
selector: #RuleSelector
|
||||
}
|
||||
#RuleSelector: {
|
||||
// +usage=Select resources by component names
|
||||
|
||||
@@ -106,7 +106,7 @@ multicluster:
|
||||
port: 9443
|
||||
image:
|
||||
repository: oamdev/cluster-gateway
|
||||
tag: v1.4.0
|
||||
tag: v1.7.0
|
||||
pullPolicy: IfNotPresent
|
||||
resources:
|
||||
limits:
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
pkgclient "github.com/kubevela/pkg/controller/client"
|
||||
ctrlrec "github.com/kubevela/pkg/controller/reconciler"
|
||||
pkgmulticluster "github.com/kubevela/pkg/multicluster"
|
||||
wfTypes "github.com/kubevela/workflow/pkg/types"
|
||||
@@ -171,6 +172,7 @@ func (s *CoreOptions) Flags() cliflag.NamedFlagSets {
|
||||
local := flag.NewFlagSet("klog", flag.ExitOnError)
|
||||
klog.InitFlags(local)
|
||||
kfs.AddGoFlagSet(local)
|
||||
pkgclient.AddTimeoutControllerClientFlags(fss.FlagSet("controllerclient"))
|
||||
|
||||
if s.LogDebug {
|
||||
_ = kfs.Set("v", strconv.Itoa(int(commonconfig.LogDebug)))
|
||||
|
||||
@@ -2086,7 +2086,7 @@
|
||||
"tags": [
|
||||
"application"
|
||||
],
|
||||
"summary": "list application triggers",
|
||||
"summary": "List the application triggers",
|
||||
"operationId": "listApplicationTriggers",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -2124,7 +2124,7 @@
|
||||
"tags": [
|
||||
"application"
|
||||
],
|
||||
"summary": "create one application trigger",
|
||||
"summary": "Create an application trigger",
|
||||
"operationId": "createApplicationTrigger",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -2160,6 +2160,51 @@
|
||||
}
|
||||
},
|
||||
"/api/v1/applications/{appName}/triggers/{token}": {
|
||||
"put": {
|
||||
"consumes": [
|
||||
"application/xml",
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"tags": [
|
||||
"application"
|
||||
],
|
||||
"summary": "Update an application trigger",
|
||||
"operationId": "updateApplicationTrigger",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "identifier of the application ",
|
||||
"name": "appName",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "identifier of the trigger",
|
||||
"name": "token",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v1.ApplicationTriggerBase"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/bcode.Bcode"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"consumes": [
|
||||
"application/xml",
|
||||
@@ -2172,7 +2217,7 @@
|
||||
"tags": [
|
||||
"application"
|
||||
],
|
||||
"summary": "delete one application trigger",
|
||||
"summary": "Delete an application trigger",
|
||||
"operationId": "deleteApplicationTrigger",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -8964,8 +9009,8 @@
|
||||
},
|
||||
"model.ApplicationRevision": {
|
||||
"required": [
|
||||
"createTime",
|
||||
"updateTime",
|
||||
"createTime",
|
||||
"appPrimaryKey",
|
||||
"version",
|
||||
"revisionCRName",
|
||||
@@ -9347,11 +9392,11 @@
|
||||
},
|
||||
"model.WorkflowStep": {
|
||||
"required": [
|
||||
"alias",
|
||||
"name",
|
||||
"dependsOn",
|
||||
"description",
|
||||
"orderIndex",
|
||||
"dependsOn",
|
||||
"name",
|
||||
"alias",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
@@ -9469,9 +9514,9 @@
|
||||
},
|
||||
"model.WorkflowStepStatus": {
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"alias"
|
||||
"alias",
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"alias": {
|
||||
@@ -10055,11 +10100,11 @@
|
||||
"v1.ApplicationDeployResponse": {
|
||||
"required": [
|
||||
"version",
|
||||
"status",
|
||||
"triggerType",
|
||||
"createTime",
|
||||
"status",
|
||||
"note",
|
||||
"envName",
|
||||
"triggerType",
|
||||
"record"
|
||||
],
|
||||
"properties": {
|
||||
@@ -10338,6 +10383,7 @@
|
||||
"type",
|
||||
"payloadType",
|
||||
"token",
|
||||
"registry",
|
||||
"createTime",
|
||||
"updateTime"
|
||||
],
|
||||
@@ -10361,6 +10407,9 @@
|
||||
"payloadType": {
|
||||
"type": "string"
|
||||
},
|
||||
"registry": {
|
||||
"type": "string"
|
||||
},
|
||||
"token": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -10833,13 +10882,13 @@
|
||||
},
|
||||
"v1.ConfigTemplateDetail": {
|
||||
"required": [
|
||||
"sensitive",
|
||||
"createTime",
|
||||
"alias",
|
||||
"name",
|
||||
"namespace",
|
||||
"description",
|
||||
"scope",
|
||||
"sensitive",
|
||||
"createTime",
|
||||
"alias",
|
||||
"schema",
|
||||
"uiSchema"
|
||||
],
|
||||
@@ -11669,11 +11718,11 @@
|
||||
},
|
||||
"v1.DetailAddonResponse": {
|
||||
"required": [
|
||||
"invisible",
|
||||
"name",
|
||||
"version",
|
||||
"description",
|
||||
"icon",
|
||||
"invisible",
|
||||
"description",
|
||||
"schema",
|
||||
"uiSchema",
|
||||
"definitions",
|
||||
@@ -11753,12 +11802,12 @@
|
||||
},
|
||||
"v1.DetailApplicationResponse": {
|
||||
"required": [
|
||||
"project",
|
||||
"createTime",
|
||||
"updateTime",
|
||||
"name",
|
||||
"alias",
|
||||
"project",
|
||||
"description",
|
||||
"createTime",
|
||||
"updateTime",
|
||||
"icon",
|
||||
"policies",
|
||||
"envBindings",
|
||||
@@ -11816,20 +11865,20 @@
|
||||
},
|
||||
"v1.DetailClusterResponse": {
|
||||
"required": [
|
||||
"status",
|
||||
"provider",
|
||||
"dashboardURL",
|
||||
"description",
|
||||
"icon",
|
||||
"labels",
|
||||
"reason",
|
||||
"apiServerURL",
|
||||
"kubeConfigSecret",
|
||||
"alias",
|
||||
"status",
|
||||
"dashboardURL",
|
||||
"icon",
|
||||
"description",
|
||||
"reason",
|
||||
"createTime",
|
||||
"updateTime",
|
||||
"name",
|
||||
"kubeConfig",
|
||||
"labels",
|
||||
"provider",
|
||||
"apiServerURL",
|
||||
"createTime",
|
||||
"resourceInfo"
|
||||
],
|
||||
"properties": {
|
||||
@@ -11887,13 +11936,13 @@
|
||||
},
|
||||
"v1.DetailComponentResponse": {
|
||||
"required": [
|
||||
"name",
|
||||
"main",
|
||||
"alias",
|
||||
"createTime",
|
||||
"updateTime",
|
||||
"appPrimaryKey",
|
||||
"creator",
|
||||
"name",
|
||||
"main",
|
||||
"createTime",
|
||||
"updateTime",
|
||||
"alias",
|
||||
"type",
|
||||
"definition"
|
||||
],
|
||||
@@ -11982,12 +12031,12 @@
|
||||
},
|
||||
"v1.DetailDefinitionResponse": {
|
||||
"required": [
|
||||
"alias",
|
||||
"labels",
|
||||
"ownerAddon",
|
||||
"name",
|
||||
"alias",
|
||||
"icon",
|
||||
"labels",
|
||||
"description",
|
||||
"icon",
|
||||
"status",
|
||||
"schema",
|
||||
"uiSchema"
|
||||
@@ -12045,15 +12094,15 @@
|
||||
},
|
||||
"v1.DetailPolicyResponse": {
|
||||
"required": [
|
||||
"description",
|
||||
"creator",
|
||||
"envName",
|
||||
"name",
|
||||
"alias",
|
||||
"type",
|
||||
"description",
|
||||
"createTime",
|
||||
"updateTime",
|
||||
"type",
|
||||
"properties"
|
||||
"alias",
|
||||
"creator",
|
||||
"properties",
|
||||
"envName"
|
||||
],
|
||||
"properties": {
|
||||
"alias": {
|
||||
@@ -12095,18 +12144,18 @@
|
||||
},
|
||||
"v1.DetailRevisionResponse": {
|
||||
"required": [
|
||||
"appPrimaryKey",
|
||||
"revisionCRName",
|
||||
"triggerType",
|
||||
"workflowName",
|
||||
"version",
|
||||
"status",
|
||||
"deployUser",
|
||||
"note",
|
||||
"createTime",
|
||||
"appPrimaryKey",
|
||||
"deployUser",
|
||||
"triggerType",
|
||||
"updateTime",
|
||||
"revisionCRName",
|
||||
"reason",
|
||||
"envName"
|
||||
"envName",
|
||||
"version",
|
||||
"workflowName",
|
||||
"createTime"
|
||||
],
|
||||
"properties": {
|
||||
"appPrimaryKey": {
|
||||
@@ -12163,10 +12212,10 @@
|
||||
},
|
||||
"v1.DetailTargetResponse": {
|
||||
"required": [
|
||||
"updateTime",
|
||||
"name",
|
||||
"project",
|
||||
"createTime",
|
||||
"updateTime"
|
||||
"project"
|
||||
],
|
||||
"properties": {
|
||||
"alias": {
|
||||
@@ -12206,11 +12255,11 @@
|
||||
},
|
||||
"v1.DetailUserResponse": {
|
||||
"required": [
|
||||
"email",
|
||||
"disabled",
|
||||
"createTime",
|
||||
"lastLoginTime",
|
||||
"name",
|
||||
"email",
|
||||
"projects",
|
||||
"roles"
|
||||
],
|
||||
@@ -12252,12 +12301,12 @@
|
||||
"v1.DetailWorkflowRecordResponse": {
|
||||
"required": [
|
||||
"status",
|
||||
"mode",
|
||||
"workflowAlias",
|
||||
"applicationRevision",
|
||||
"namespace",
|
||||
"message",
|
||||
"mode",
|
||||
"name",
|
||||
"namespace",
|
||||
"workflowName",
|
||||
"deployTime",
|
||||
"deployUser",
|
||||
@@ -12321,15 +12370,15 @@
|
||||
"v1.DetailWorkflowResponse": {
|
||||
"required": [
|
||||
"name",
|
||||
"enable",
|
||||
"envName",
|
||||
"alias",
|
||||
"description",
|
||||
"default",
|
||||
"createTime",
|
||||
"updateTime",
|
||||
"subMode",
|
||||
"alias",
|
||||
"enable",
|
||||
"default",
|
||||
"envName",
|
||||
"mode"
|
||||
"mode",
|
||||
"subMode"
|
||||
],
|
||||
"properties": {
|
||||
"alias": {
|
||||
@@ -12537,8 +12586,8 @@
|
||||
},
|
||||
"v1.EnvBindingTarget": {
|
||||
"required": [
|
||||
"name",
|
||||
"alias"
|
||||
"alias",
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"alias": {
|
||||
@@ -12565,11 +12614,11 @@
|
||||
"v1.GetPipelineResponse": {
|
||||
"required": [
|
||||
"spec",
|
||||
"description",
|
||||
"createTime",
|
||||
"name",
|
||||
"alias",
|
||||
"project",
|
||||
"description",
|
||||
"info"
|
||||
],
|
||||
"properties": {
|
||||
@@ -12612,10 +12661,10 @@
|
||||
},
|
||||
"v1.GetPipelineRunLogResponse": {
|
||||
"required": [
|
||||
"phase",
|
||||
"id",
|
||||
"name",
|
||||
"type",
|
||||
"phase",
|
||||
"source",
|
||||
"log"
|
||||
],
|
||||
@@ -13269,11 +13318,11 @@
|
||||
},
|
||||
"v1.LoginUserInfoResponse": {
|
||||
"required": [
|
||||
"createTime",
|
||||
"lastLoginTime",
|
||||
"name",
|
||||
"email",
|
||||
"disabled",
|
||||
"createTime",
|
||||
"lastLoginTime",
|
||||
"projects",
|
||||
"platformPermissions",
|
||||
"projectPermissions"
|
||||
@@ -13475,11 +13524,11 @@
|
||||
},
|
||||
"v1.PipelineBase": {
|
||||
"required": [
|
||||
"description",
|
||||
"createTime",
|
||||
"name",
|
||||
"alias",
|
||||
"project",
|
||||
"description",
|
||||
"spec"
|
||||
],
|
||||
"properties": {
|
||||
@@ -13578,11 +13627,11 @@
|
||||
},
|
||||
"v1.PipelineMetaResponse": {
|
||||
"required": [
|
||||
"name",
|
||||
"alias",
|
||||
"project",
|
||||
"description",
|
||||
"createTime",
|
||||
"name",
|
||||
"alias"
|
||||
"createTime"
|
||||
],
|
||||
"properties": {
|
||||
"alias": {
|
||||
@@ -13605,13 +13654,13 @@
|
||||
},
|
||||
"v1.PipelineRun": {
|
||||
"required": [
|
||||
"contextName",
|
||||
"contextValues",
|
||||
"spec",
|
||||
"pipelineName",
|
||||
"project",
|
||||
"pipelineRunName",
|
||||
"record",
|
||||
"contextName",
|
||||
"contextValues",
|
||||
"spec",
|
||||
"status"
|
||||
],
|
||||
"properties": {
|
||||
@@ -14208,9 +14257,9 @@
|
||||
},
|
||||
"v1.SystemInfoResponse": {
|
||||
"required": [
|
||||
"loginType",
|
||||
"platformID",
|
||||
"enableCollection",
|
||||
"loginType",
|
||||
"systemVersion"
|
||||
],
|
||||
"properties": {
|
||||
@@ -14734,14 +14783,14 @@
|
||||
},
|
||||
"v1.WorkflowRecord": {
|
||||
"required": [
|
||||
"namespace",
|
||||
"message",
|
||||
"status",
|
||||
"mode",
|
||||
"name",
|
||||
"namespace",
|
||||
"workflowName",
|
||||
"workflowAlias",
|
||||
"applicationRevision"
|
||||
"applicationRevision",
|
||||
"mode",
|
||||
"message"
|
||||
],
|
||||
"properties": {
|
||||
"applicationRevision": {
|
||||
@@ -14832,8 +14881,8 @@
|
||||
},
|
||||
"v1.WorkflowStep": {
|
||||
"required": [
|
||||
"type",
|
||||
"name"
|
||||
"name",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"alias": {
|
||||
|
||||
@@ -74,6 +74,12 @@ var _ = Describe("Addon Test", func() {
|
||||
Expect(output).To(ContainSubstring("enabled successfully."))
|
||||
})
|
||||
|
||||
It("Enable addon with specified registry ", func() {
|
||||
output, err := e2e.LongTimeExec("vela addon enable KubeVela/test-addon", 300*time.Second)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(ContainSubstring("enabled successfully."))
|
||||
})
|
||||
|
||||
It("Disable addon test-addon", func() {
|
||||
output, err := e2e.LongTimeExec("vela addon disable test-addon", 600*time.Second)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
5
go.mod
5
go.mod
@@ -3,7 +3,7 @@ module github.com/oam-dev/kubevela
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
cuelang.org/go v0.5.0-alpha.1
|
||||
cuelang.org/go v0.5.0-beta.5
|
||||
github.com/AlecAivazis/survey/v2 v2.1.1
|
||||
github.com/FogDong/uitable v0.0.5
|
||||
github.com/Masterminds/semver/v3 v3.1.1
|
||||
@@ -57,7 +57,7 @@ require (
|
||||
github.com/koding/websocketproxy v0.0.0-20181220232114-7ed82d81a28c
|
||||
github.com/kubevela/pkg v0.0.0-20230105054759-263dc191bf51
|
||||
github.com/kubevela/prism v1.7.0-alpha.1
|
||||
github.com/kubevela/workflow v0.4.0
|
||||
github.com/kubevela/workflow v0.4.1
|
||||
github.com/kyokomi/emoji v2.2.4+incompatible
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.1
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
|
||||
@@ -348,7 +348,6 @@ require (
|
||||
|
||||
replace (
|
||||
cloud.google.com/go => cloud.google.com/go v0.100.2
|
||||
cuelang.org/go => github.com/kubevela/cue v0.4.4-0.20221107123854-a976b0e340be
|
||||
github.com/docker/cli => github.com/docker/cli v20.10.9+incompatible
|
||||
github.com/docker/docker => github.com/moby/moby v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible
|
||||
github.com/wercker/stern => github.com/oam-dev/stern v1.13.2
|
||||
|
||||
8
go.sum
8
go.sum
@@ -34,6 +34,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
|
||||
collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=
|
||||
contrib.go.opencensus.io/exporter/ocagent v0.6.0/go.mod h1:zmKjrJcdo0aYcVS7bmEeSEBLPA9YJp5bjrofdU3pIXs=
|
||||
contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc=
|
||||
cuelang.org/go v0.5.0-beta.5 h1:TAV4ZjXw2M6xf6jI8XyAAXCqWJ82Y0oxhlf9w3l544A=
|
||||
cuelang.org/go v0.5.0-beta.5/go.mod h1:okjJBHFQFer+a41sAe2SaGm1glWS8oEb6CmJvn5Zdws=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/AlecAivazis/survey/v2 v2.1.1 h1:LEMbHE0pLj75faaVEKClEX1TM4AJmmnOh9eimREzLWI=
|
||||
github.com/AlecAivazis/survey/v2 v2.1.1/go.mod h1:9FJRdMdDm8rnT+zHVbvQT2RTSTLq0Ttd6q3Vl2fahjk=
|
||||
@@ -1283,14 +1285,12 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kubevela/cue v0.4.4-0.20221107123854-a976b0e340be h1:0xj/Rh4yVy54mUD2nLmAuN1AYgBkkHxBh4PoLGbIg5g=
|
||||
github.com/kubevela/cue v0.4.4-0.20221107123854-a976b0e340be/go.mod h1:Ya12qn7FZc+LSN0qgEhzEpnzQsvnGHVgoDrqe9i3eNg=
|
||||
github.com/kubevela/pkg v0.0.0-20230105054759-263dc191bf51 h1:xrcNNaAjqC6tr1leSYcjLFgrXKpZ8u87jpB5TolhUIc=
|
||||
github.com/kubevela/pkg v0.0.0-20230105054759-263dc191bf51/go.mod h1:ZRnxY/gOcg/8FilZA+eYr+rtVXb1ijT5HFTe8zrv9zo=
|
||||
github.com/kubevela/prism v1.7.0-alpha.1 h1:oeZFn1Oy6gxSSFzMTfsWjLOCKaaooMVm1JGNK4j4Mlo=
|
||||
github.com/kubevela/prism v1.7.0-alpha.1/go.mod h1:AJSDfdA+RkRSnWx3xEcogbmOTpX+l7RSIwqVHxwUtaI=
|
||||
github.com/kubevela/workflow v0.4.0 h1:Zzb9wPOvLUGEArdnC6EsfNM5j3VNJj0/v2iDKq1JT3k=
|
||||
github.com/kubevela/workflow v0.4.0/go.mod h1:AX/WL3G/YBkpmNpA/SKKm9M3Y0T9y95gZA8mFWylkyM=
|
||||
github.com/kubevela/workflow v0.4.1 h1:lYeWE9KgSSkb368u8G7cGfyzCz41Am8MdxgViRFJxXE=
|
||||
github.com/kubevela/workflow v0.4.1/go.mod h1:AX/WL3G/YBkpmNpA/SKKm9M3Y0T9y95gZA8mFWylkyM=
|
||||
github.com/kulti/thelper v0.4.0/go.mod h1:vMu2Cizjy/grP+jmsvOFDx1kYP6+PD1lqg4Yu5exl2U=
|
||||
github.com/kunwardeep/paralleltest v1.0.3/go.mod h1:vLydzomDFpk7yu5UX02RmP0H8QfRPOV/oFhWN85Mjb4=
|
||||
github.com/kylelemons/godebug v0.0.0-20160406211939-eadb3ce320cb/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
|
||||
|
||||
@@ -99,6 +99,7 @@ type ApplicationService interface {
|
||||
CreateApplicationTrigger(ctx context.Context, app *model.Application, req apisv1.CreateApplicationTriggerRequest) (*apisv1.ApplicationTriggerBase, error)
|
||||
ListApplicationTriggers(ctx context.Context, app *model.Application) ([]*apisv1.ApplicationTriggerBase, error)
|
||||
DeleteApplicationTrigger(ctx context.Context, app *model.Application, triggerName string) error
|
||||
UpdateApplicationTrigger(ctx context.Context, app *model.Application, token string, req apisv1.UpdateApplicationTriggerRequest) (*apisv1.ApplicationTriggerBase, error)
|
||||
}
|
||||
|
||||
type applicationServiceImpl struct {
|
||||
@@ -410,6 +411,18 @@ func (c *applicationServiceImpl) CreateApplication(ctx context.Context, req apis
|
||||
|
||||
// CreateApplicationTrigger create application trigger
|
||||
func (c *applicationServiceImpl) CreateApplicationTrigger(ctx context.Context, app *model.Application, req apisv1.CreateApplicationTriggerRequest) (*apisv1.ApplicationTriggerBase, error) {
|
||||
// checking the workflow
|
||||
_, err := c.WorkflowService.GetWorkflow(ctx, app, req.WorkflowName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if req.ComponentName != "" {
|
||||
_, err := c.GetApplicationComponent(ctx, app, req.ComponentName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
trigger := &model.ApplicationTrigger{
|
||||
AppPrimaryKey: app.Name,
|
||||
WorkflowName: req.WorkflowName,
|
||||
@@ -427,18 +440,7 @@ func (c *applicationServiceImpl) CreateApplicationTrigger(ctx context.Context, a
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &apisv1.ApplicationTriggerBase{
|
||||
WorkflowName: req.WorkflowName,
|
||||
Name: req.Name,
|
||||
Alias: req.Alias,
|
||||
Description: req.Description,
|
||||
Type: req.Type,
|
||||
PayloadType: req.PayloadType,
|
||||
Token: trigger.Token,
|
||||
ComponentName: trigger.ComponentName,
|
||||
CreateTime: trigger.CreateTime,
|
||||
UpdateTime: trigger.UpdateTime,
|
||||
}, nil
|
||||
return assembler.ConvertTrigger2DTO(*trigger), nil
|
||||
}
|
||||
|
||||
// DeleteApplicationTrigger delete application trigger
|
||||
@@ -457,6 +459,42 @@ func (c *applicationServiceImpl) DeleteApplicationTrigger(ctx context.Context, a
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateApplicationTrigger update application trigger
|
||||
func (c *applicationServiceImpl) UpdateApplicationTrigger(ctx context.Context, app *model.Application, token string, req apisv1.UpdateApplicationTriggerRequest) (*apisv1.ApplicationTriggerBase, error) {
|
||||
trigger := model.ApplicationTrigger{
|
||||
AppPrimaryKey: app.PrimaryKey(),
|
||||
Token: token,
|
||||
}
|
||||
if err := c.Store.Get(ctx, &trigger); err != nil {
|
||||
if errors.Is(err, datastore.ErrRecordNotExist) {
|
||||
return nil, bcode.ErrApplicationTriggerNotExist
|
||||
}
|
||||
klog.Warningf("get app trigger failure %s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
// checking the workflow
|
||||
_, err := c.WorkflowService.GetWorkflow(ctx, app, req.WorkflowName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if req.ComponentName != "" {
|
||||
_, err := c.GetApplicationComponent(ctx, app, req.ComponentName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
trigger.Alias = req.Alias
|
||||
trigger.ComponentName = req.ComponentName
|
||||
trigger.Description = req.Description
|
||||
trigger.WorkflowName = req.WorkflowName
|
||||
trigger.Registry = req.Registry
|
||||
trigger.PayloadType = req.PayloadType
|
||||
if err := c.Store.Put(ctx, &trigger); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return assembler.ConvertTrigger2DTO(trigger), nil
|
||||
}
|
||||
|
||||
// ListApplicationTrigger list application triggers
|
||||
func (c *applicationServiceImpl) ListApplicationTriggers(ctx context.Context, app *model.Application) ([]*apisv1.ApplicationTriggerBase, error) {
|
||||
trigger := &model.ApplicationTrigger{
|
||||
@@ -1715,6 +1753,10 @@ func (c *applicationServiceImpl) RollbackWithRevision(ctx context.Context, appli
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// The deploy version is the primary key of the revision
|
||||
if rollbackApplication.Annotations[oam.AnnotationDeployVersion] == "" {
|
||||
rollbackApplication.Annotations[oam.AnnotationDeployVersion] = publishVersion
|
||||
}
|
||||
record, err := c.WorkflowService.CreateWorkflowRecord(ctx, application, rollbackApplication, &work)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create workflow record failure %w", err)
|
||||
|
||||
@@ -208,15 +208,17 @@ var _ = Describe("Test application service function", func() {
|
||||
appModel, err := appService.GetApplication(context.TODO(), testApp)
|
||||
Expect(err).Should(BeNil())
|
||||
_, err = appService.CreateApplicationTrigger(context.TODO(), appModel, v1.CreateApplicationTriggerRequest{
|
||||
Name: "trigger-name",
|
||||
Name: "trigger-name",
|
||||
WorkflowName: repository.ConvertWorkflowName("app-dev"),
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
base, err := appService.CreateApplicationTrigger(context.TODO(), appModel, v1.CreateApplicationTriggerRequest{
|
||||
Name: "trigger-name-2",
|
||||
ComponentName: "trigger-component",
|
||||
ComponentName: "component-name",
|
||||
WorkflowName: repository.ConvertWorkflowName("app-dev"),
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(base.ComponentName).Should(Equal("trigger-component"))
|
||||
Expect(base.ComponentName).Should(Equal("component-name"))
|
||||
})
|
||||
|
||||
It("Test ListTriggers function", func() {
|
||||
@@ -299,6 +301,33 @@ var _ = Describe("Test application service function", func() {
|
||||
Expect(cmp.Diff(len(detailResponse.Traits), 2)).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("Test UpdateTrigger function", func() {
|
||||
appModel, err := appService.GetApplication(context.TODO(), testApp)
|
||||
Expect(err).Should(BeNil())
|
||||
triggers, err := appService.ListApplicationTriggers(context.TODO(), appModel)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(triggers)).Should(Equal(2))
|
||||
_, err = appService.UpdateApplicationTrigger(context.TODO(), appModel, triggers[1].Token, v1.UpdateApplicationTriggerRequest{
|
||||
ComponentName: "notfound",
|
||||
WorkflowName: repository.ConvertWorkflowName("app-dev"),
|
||||
})
|
||||
Expect(err).Should(Equal(bcode.ErrApplicationComponentNotExist))
|
||||
_, err = appService.UpdateApplicationTrigger(context.TODO(), appModel, triggers[1].Token, v1.UpdateApplicationTriggerRequest{
|
||||
WorkflowName: "notfound",
|
||||
})
|
||||
Expect(err).Should(Equal(bcode.ErrWorkflowNotExist))
|
||||
base, err := appService.UpdateApplicationTrigger(context.TODO(), appModel, triggers[1].Token, v1.UpdateApplicationTriggerRequest{
|
||||
Alias: triggers[1].Alias,
|
||||
Description: triggers[1].Description,
|
||||
ComponentName: "test2",
|
||||
WorkflowName: repository.ConvertWorkflowName("app-dev"),
|
||||
PayloadType: triggers[1].PayloadType,
|
||||
Registry: triggers[1].Registry,
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(base.ComponentName, "test2")).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("Test DetailComponent function", func() {
|
||||
appModel, err := appService.GetApplication(context.TODO(), testApp)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
@@ -387,7 +387,10 @@ func (c *clusterServiceImpl) DeleteKubeCluster(ctx context.Context, clusterName
|
||||
cluster, err := c.getClusterFromDataStore(ctx, clusterName)
|
||||
if err != nil {
|
||||
if errors.Is(err, datastore.ErrRecordNotExist) {
|
||||
return nil, bcode.ErrClusterNotFoundInDataStore
|
||||
if err = multicluster.DetachCluster(ctx, c.K8sClient, clusterName); err != nil {
|
||||
return nil, bcode.ErrClusterNotFoundInDataStore
|
||||
}
|
||||
return &apis.ClusterBase{Name: clusterName}, nil
|
||||
}
|
||||
return nil, errors.Wrapf(err, "failed to found cluster %s in data store", clusterName)
|
||||
}
|
||||
|
||||
@@ -98,6 +98,27 @@ var _ = Describe("Test cluster service function", func() {
|
||||
Expect(err).Should(Equal(bcode.ErrClusterNotFoundInDataStore))
|
||||
})
|
||||
|
||||
It("Test delete kube cluster", func() {
|
||||
service := clusterServiceImpl{
|
||||
Store: ds,
|
||||
caches: cache,
|
||||
K8sClient: k8sClient,
|
||||
}
|
||||
Expect(createClusterSecret("prism-cluster", "prism-alias")).Should(Succeed())
|
||||
Expect(ds.Add(ctx, &model.Cluster{Name: "prism-cluster", Alias: "prism-alias", Icon: "prism-icon"})).Should(Succeed())
|
||||
resp, err := service.DeleteKubeCluster(ctx, "prism-cluster")
|
||||
Expect(err).Should(Succeed())
|
||||
Expect(resp.Name).Should(Equal("prism-cluster"))
|
||||
Expect(resp.Alias).Should(Equal("prism-alias"))
|
||||
Expect(resp.Icon).Should(Equal("prism-icon"))
|
||||
_, err = service.DeleteKubeCluster(ctx, "non-exist-cluster")
|
||||
Expect(err).Should(Equal(bcode.ErrClusterNotFoundInDataStore))
|
||||
Expect(createClusterSecret("secret-exist-cm-non-exist-cluster", "secret-exist-cm-non-exist-cluster")).Should(Succeed())
|
||||
resp, err = service.DeleteKubeCluster(ctx, "secret-exist-cm-non-exist-cluster")
|
||||
Expect(err).Should(Succeed())
|
||||
Expect(resp.Name).Should(Equal("secret-exist-cm-non-exist-cluster"))
|
||||
})
|
||||
|
||||
It("Test list kube clusters", func() {
|
||||
service := clusterServiceImpl{
|
||||
Store: ds,
|
||||
|
||||
@@ -91,7 +91,7 @@ template: {
|
||||
|
||||
parameter: {
|
||||
//+usage=The name of Terraform Provider for Alibaba Cloud
|
||||
name: *"default" | string
|
||||
name: string
|
||||
//+usage=Get ALICLOUD_ACCESS_KEY per this guide https://help.aliyun.com/knowledge_detail/38738.html
|
||||
ALICLOUD_ACCESS_KEY: string
|
||||
//+usage=Get ALICLOUD_SECRET_KEY per this guide https://help.aliyun.com/knowledge_detail/38738.html
|
||||
@@ -144,7 +144,7 @@ var _ = Describe("Test config service", func() {
|
||||
Expect(err).ToNot(BeNil())
|
||||
var paramErr = &script.ParameterError{}
|
||||
Expect(errors.As(err, ¶mErr)).To(Equal(true))
|
||||
Expect(paramErr.Name).To(Equal("ALICLOUD_ACCESS_KEY"))
|
||||
Expect(paramErr.Name).To(Equal("name"))
|
||||
Expect(paramErr.Message).To(Equal("This parameter is required"))
|
||||
|
||||
config, err := configService.CreateConfig(context.TODO(), "", v1.CreateConfigRequest{
|
||||
|
||||
@@ -45,8 +45,9 @@ func NewHelmService() HelmService {
|
||||
type HelmService interface {
|
||||
ListChartNames(ctx context.Context, url string, secretName string, skipCache bool) ([]string, error)
|
||||
ListChartVersions(ctx context.Context, url string, chartName string, secretName string, skipCache bool) (repo.ChartVersions, error)
|
||||
GetChartValues(ctx context.Context, url string, chartName string, version string, secretName string, skipCache bool) (map[string]interface{}, error)
|
||||
ListChartValuesFiles(ctx context.Context, url string, chartName string, version string, secretName string, repoType string, skipCache bool) (map[string]string, error)
|
||||
ListChartRepo(ctx context.Context, projectName string) (*v1.ChartRepoResponseList, error)
|
||||
GetChartValues(ctx context.Context, repoURL string, chartName string, version string, secretName string, repoType string, skipCache bool) (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
type defaultHelmImpl struct {
|
||||
@@ -99,7 +100,7 @@ func (d defaultHelmImpl) ListChartVersions(ctx context.Context, repoURL string,
|
||||
return chartVersions, nil
|
||||
}
|
||||
|
||||
func (d defaultHelmImpl) GetChartValues(ctx context.Context, repoURL string, chartName string, version string, secretName string, skipCache bool) (map[string]interface{}, error) {
|
||||
func (d defaultHelmImpl) ListChartValuesFiles(ctx context.Context, repoURL string, chartName string, version string, secretName string, repoType string, skipCache bool) (map[string]string, error) {
|
||||
if !utils.IsValidURL(repoURL) {
|
||||
return nil, bcode.ErrRepoInvalidURL
|
||||
}
|
||||
@@ -111,13 +112,33 @@ func (d defaultHelmImpl) GetChartValues(ctx context.Context, repoURL string, cha
|
||||
return nil, bcode.ErrRepoBasicAuth
|
||||
}
|
||||
}
|
||||
v, err := d.helper.GetValuesFromChart(repoURL, chartName, version, skipCache, opts)
|
||||
v, err := d.helper.GetValuesFromChart(repoURL, chartName, version, skipCache, repoType, opts)
|
||||
if err != nil {
|
||||
klog.Errorf("cannot fetch chart values repo: %s, chart: %s, version: %s, error: %s", utils.Sanitize(repoURL), utils.Sanitize(chartName), utils.Sanitize(version), err.Error())
|
||||
return nil, bcode.ErrGetChartValues
|
||||
}
|
||||
res := make(map[string]interface{}, len(v))
|
||||
flattenKey("", v, res)
|
||||
return v.Data, nil
|
||||
}
|
||||
|
||||
func (d defaultHelmImpl) GetChartValues(ctx context.Context, repoURL string, chartName string, version string, secretName string, repoType string, skipCache bool) (map[string]interface{}, error) {
|
||||
if !utils.IsValidURL(repoURL) {
|
||||
return nil, bcode.ErrRepoInvalidURL
|
||||
}
|
||||
var opts *common.HTTPOption
|
||||
var err error
|
||||
if len(secretName) != 0 {
|
||||
opts, err = helm.SetHTTPOption(ctx, d.K8sClient, types2.NamespacedName{Namespace: types.DefaultKubeVelaNS, Name: secretName})
|
||||
if err != nil {
|
||||
return nil, bcode.ErrRepoBasicAuth
|
||||
}
|
||||
}
|
||||
v, err := d.helper.GetValuesFromChart(repoURL, chartName, version, skipCache, repoType, opts)
|
||||
if err != nil {
|
||||
klog.Errorf("cannot fetch chart values repo: %s, chart: %s, version: %s, error: %s", utils.Sanitize(repoURL), utils.Sanitize(chartName), utils.Sanitize(version), err.Error())
|
||||
return nil, bcode.ErrGetChartValues
|
||||
}
|
||||
res := make(map[string]interface{}, len(v.Values))
|
||||
flattenKey("", v.Values, res)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -213,7 +213,7 @@ var _ = Describe("test helm usecasae", func() {
|
||||
Expect(len(versions)).Should(BeEquivalentTo(1))
|
||||
Expect(versions[0].Version).Should(BeEquivalentTo("8.8.23"))
|
||||
|
||||
values, err := u.GetChartValues(ctx, mockServer.URL, "mysql", "8.8.23", "repo-secret", false)
|
||||
values, err := u.ListChartValuesFiles(ctx, mockServer.URL, "mysql", "8.8.23", "repo-secret", "helm", false)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(values).ShouldNot(BeNil())
|
||||
Expect(len(values)).ShouldNot(BeEquivalentTo(0))
|
||||
@@ -228,7 +228,7 @@ var _ = Describe("test helm usecasae", func() {
|
||||
_, err = u.ListChartVersions(ctx, "http://127.0.0.1:8080", "mysql", "repo-secret-notExist", false)
|
||||
Expect(err).ShouldNot(BeNil())
|
||||
|
||||
_, err = u.GetChartValues(ctx, "http://127.0.0.1:8080", "mysql", "8.8.23", "repo-secret-notExist", false)
|
||||
_, err = u.ListChartValuesFiles(ctx, "http://127.0.0.1:8080", "mysql", "8.8.23", "repo-secret-notExist", "helm", false)
|
||||
Expect(err).ShouldNot(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
@@ -259,7 +259,9 @@ func managePrivilegesForTarget(ctx context.Context, cli client.Client, target *m
|
||||
f, msg = auth.RevokePrivileges, "RevokePrivileges"
|
||||
}
|
||||
if err := f(ctx, cli, []auth.PrivilegeDescription{p}, identity, writer); err != nil {
|
||||
return err
|
||||
klog.Warningf("error encountered for %s: %s", msg, err.Error())
|
||||
// for some cluster, authn/authz is not supported, ignore errors
|
||||
return client.IgnoreNotFound(err)
|
||||
}
|
||||
klog.Infof("%s: %s", msg, writer.String())
|
||||
return nil
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/domain/model"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/domain/repository"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/infrastructure/datastore"
|
||||
apisv1 "github.com/oam-dev/kubevela/pkg/apiserver/interfaces/api/dto/v1"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/bcode"
|
||||
@@ -168,6 +169,7 @@ var _ = Describe("Test application service function", func() {
|
||||
Name: "test-acr",
|
||||
PayloadType: "acr",
|
||||
Type: "webhook",
|
||||
WorkflowName: repository.ConvertWorkflowName("webhook-dev"),
|
||||
ComponentName: "component-name-webhook",
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
@@ -202,6 +204,7 @@ var _ = Describe("Test application service function", func() {
|
||||
PayloadType: "acr",
|
||||
Type: "webhook",
|
||||
ComponentName: "component-name-webhook",
|
||||
WorkflowName: repository.ConvertWorkflowName("webhook-dev"),
|
||||
Registry: "test-enterprise-registry.test-region.cr.aliyuncs.com",
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
@@ -236,6 +239,7 @@ var _ = Describe("Test application service function", func() {
|
||||
PayloadType: "harbor",
|
||||
Type: "webhook",
|
||||
ComponentName: "component-name-webhook",
|
||||
WorkflowName: repository.ConvertWorkflowName("webhook-dev"),
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
@@ -274,6 +278,7 @@ var _ = Describe("Test application service function", func() {
|
||||
PayloadType: "dockerhub",
|
||||
Type: "webhook",
|
||||
ComponentName: "component-name-webhook",
|
||||
WorkflowName: repository.ConvertWorkflowName("webhook-dev"),
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
@@ -306,6 +311,7 @@ var _ = Describe("Test application service function", func() {
|
||||
PayloadType: "jfrog",
|
||||
Type: "webhook",
|
||||
ComponentName: "component-name-webhook",
|
||||
WorkflowName: repository.ConvertWorkflowName("webhook-dev"),
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
jfrogBody := apisv1.HandleApplicationTriggerJFrogRequest{
|
||||
|
||||
@@ -48,6 +48,7 @@ var _ = Describe("Test workflow service functions", func() {
|
||||
projectService *projectServiceImpl
|
||||
envService *envServiceImpl
|
||||
envBinding *envBindingServiceImpl
|
||||
targetService *targetServiceImpl
|
||||
testProject = "workflow-project"
|
||||
ds datastore.DataStore
|
||||
)
|
||||
@@ -60,6 +61,7 @@ var _ = Describe("Test workflow service functions", func() {
|
||||
rbacService := &rbacServiceImpl{Store: ds}
|
||||
projectService = &projectServiceImpl{Store: ds, RbacService: rbacService, K8sClient: k8sClient}
|
||||
envService = &envServiceImpl{Store: ds, KubeClient: k8sClient, ProjectService: projectService}
|
||||
targetService = &targetServiceImpl{Store: ds, K8sClient: k8sClient}
|
||||
envBinding = &envBindingServiceImpl{
|
||||
Store: ds,
|
||||
WorkflowService: workflowService,
|
||||
@@ -77,11 +79,20 @@ var _ = Describe("Test workflow service functions", func() {
|
||||
ProjectService: projectService,
|
||||
EnvService: envService,
|
||||
EnvBindingService: envBinding,
|
||||
WorkflowService: workflowService,
|
||||
}
|
||||
})
|
||||
It("Test CreateWorkflow function", func() {
|
||||
|
||||
_, err := projectService.CreateProject(context.TODO(), apisv1.CreateProjectRequest{Name: testProject})
|
||||
Expect(err).Should(BeNil())
|
||||
_, err = targetService.CreateTarget(context.TODO(), apisv1.CreateTargetRequest{
|
||||
Name: "dev-1", Project: testProject, Cluster: &apisv1.ClusterTarget{ClusterName: "local", Namespace: "dev-1"}})
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
_, err = envService.CreateEnv(context.TODO(), apisv1.CreateEnvRequest{Name: "dev", Namespace: "dev-1", Targets: []string{"dev-1"}, Project: testProject})
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
reqApp := apisv1.CreateApplicationRequest{
|
||||
Name: appName,
|
||||
Project: testProject,
|
||||
|
||||
@@ -190,7 +190,7 @@ func (c *CR2UX) generateEnv(ctx context.Context, defaultProject string, envNames
|
||||
env.Targets = append(env.Targets, name)
|
||||
}
|
||||
}
|
||||
return env, "", nil
|
||||
return env, env.Project, nil
|
||||
}
|
||||
|
||||
// generate new environment
|
||||
|
||||
@@ -217,6 +217,47 @@ var _ = Describe("Test CR convert to ux", func() {
|
||||
Expect(count).Should(Equal(int64(2)))
|
||||
})
|
||||
|
||||
It("Test to sync the project which existed env belongs", func() {
|
||||
dbNamespace := "update-app-db-ns1-test"
|
||||
ds, err := NewDatastore(datastore.Config{Type: "kubeapi", Database: dbNamespace})
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
cr2ux := newCR2UX(ds)
|
||||
|
||||
projectName := "project-test"
|
||||
|
||||
_, err = cr2ux.projectService.CreateProject(context.TODO(), v1.CreateProjectRequest{
|
||||
Name: projectName,
|
||||
Owner: "admin",
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
_, err = cr2ux.targetService.CreateTarget(context.TODO(), v1.CreateTargetRequest{
|
||||
Name: "target-test1",
|
||||
Project: projectName,
|
||||
Cluster: &v1.ClusterTarget{
|
||||
ClusterName: "local",
|
||||
Namespace: "target-test1",
|
||||
},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
_, err = cr2ux.envService.CreateEnv(context.TODO(), v1.CreateEnvRequest{
|
||||
Name: "env-test1",
|
||||
Project: projectName,
|
||||
Namespace: "env-test1",
|
||||
Targets: []string{"target-test1"},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
app5 := &v1beta1.Application{}
|
||||
Expect(common2.ReadYamlToObject("testdata/test-app5.yaml", app5)).Should(BeNil())
|
||||
app5.Namespace = "env-test1"
|
||||
Expect(cr2ux.AddOrUpdate(context.Background(), app5)).Should(BeNil())
|
||||
|
||||
app, err := cr2ux.applicationService.GetApplication(context.TODO(), app5.Name)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(app.Project).Should(Equal("project-test"))
|
||||
})
|
||||
})
|
||||
|
||||
func newCR2UX(ds datastore.DataStore) *CR2UX {
|
||||
|
||||
16
pkg/apiserver/event/sync/testdata/test-app5.yaml
vendored
Normal file
16
pkg/apiserver/event/sync/testdata/test-app5.yaml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: example-sync-project
|
||||
spec:
|
||||
components:
|
||||
- name: example-exist-env
|
||||
type: webservice
|
||||
properties:
|
||||
image: wordpress
|
||||
traits:
|
||||
- type: gateway
|
||||
properties:
|
||||
domain: testsvc.example.com
|
||||
http:
|
||||
"/": 8000
|
||||
@@ -118,7 +118,7 @@ func (c *application) GetWebServiceRoute() *restful.WebService {
|
||||
Writes(apis.ApplicationStatisticsResponse{}))
|
||||
|
||||
ws.Route(ws.POST("/{appName}/triggers").To(c.createApplicationTrigger).
|
||||
Doc("create one application trigger").
|
||||
Doc("Create an application trigger").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(c.RbacService.CheckPerm("trigger", "create")).
|
||||
Filter(c.appCheckFilter).
|
||||
@@ -129,7 +129,7 @@ func (c *application) GetWebServiceRoute() *restful.WebService {
|
||||
Writes(apis.ApplicationTriggerBase{}))
|
||||
|
||||
ws.Route(ws.DELETE("/{appName}/triggers/{token}").To(c.deleteApplicationTrigger).
|
||||
Doc("delete one application trigger").
|
||||
Doc("Delete an application trigger").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(c.RbacService.CheckPerm("trigger", "delete")).
|
||||
Filter(c.appCheckFilter).
|
||||
@@ -139,8 +139,19 @@ func (c *application) GetWebServiceRoute() *restful.WebService {
|
||||
Returns(400, "Bad Request", bcode.Bcode{}).
|
||||
Writes([]*apis.EmptyResponse{}))
|
||||
|
||||
ws.Route(ws.PUT("/{appName}/triggers/{token}").To(c.updateApplicationTrigger).
|
||||
Doc("Update an application trigger").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(c.RbacService.CheckPerm("trigger", "update")).
|
||||
Filter(c.appCheckFilter).
|
||||
Param(ws.PathParameter("appName", "identifier of the application ").DataType("string")).
|
||||
Param(ws.PathParameter("token", "identifier of the trigger").DataType("string")).
|
||||
Returns(200, "OK", apis.ApplicationTriggerBase{}).
|
||||
Returns(400, "Bad Request", bcode.Bcode{}).
|
||||
Writes([]*apis.ApplicationTriggerBase{}))
|
||||
|
||||
ws.Route(ws.GET("/{appName}/triggers").To(c.listApplicationTriggers).
|
||||
Doc("list application triggers").
|
||||
Doc("List the application triggers").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(c.RbacService.CheckPerm("trigger", "list")).
|
||||
Filter(c.appCheckFilter).
|
||||
@@ -747,6 +758,24 @@ func (c *application) deleteApplicationTrigger(req *restful.Request, res *restfu
|
||||
}
|
||||
}
|
||||
|
||||
func (c *application) updateApplicationTrigger(req *restful.Request, res *restful.Response) {
|
||||
var updateReq apis.UpdateApplicationTriggerRequest
|
||||
if err := req.ReadEntity(&updateReq); err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
app := req.Request.Context().Value(&apis.CtxKeyApplication).(*model.Application)
|
||||
trigger, err := c.ApplicationService.UpdateApplicationTrigger(req.Request.Context(), app, req.PathParameter("token"), updateReq)
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
if err := res.WriteEntity(trigger); err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (c *application) publishApplicationTemplate(req *restful.Request, res *restful.Response) {
|
||||
app := req.Request.Context().Value(&apis.CtxKeyApplication).(*model.Application)
|
||||
base, err := c.ApplicationService.PublishApplicationTemplate(req.Request.Context(), app)
|
||||
|
||||
@@ -274,6 +274,23 @@ func ConvertPermission2DTO(permission *model.Permission) *apisv1.PermissionBase
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertTrigger2DTO convert trigger model to the DTO
|
||||
func ConvertTrigger2DTO(trigger model.ApplicationTrigger) *apisv1.ApplicationTriggerBase {
|
||||
return &apisv1.ApplicationTriggerBase{
|
||||
WorkflowName: trigger.WorkflowName,
|
||||
Name: trigger.Name,
|
||||
Alias: trigger.Alias,
|
||||
Description: trigger.Description,
|
||||
Type: trigger.Type,
|
||||
PayloadType: trigger.PayloadType,
|
||||
Token: trigger.Token,
|
||||
Registry: trigger.Registry,
|
||||
ComponentName: trigger.ComponentName,
|
||||
CreateTime: trigger.CreateTime,
|
||||
UpdateTime: trigger.UpdateTime,
|
||||
}
|
||||
}
|
||||
|
||||
func convertBool(b *bool) bool {
|
||||
if b == nil {
|
||||
return false
|
||||
|
||||
@@ -512,6 +512,16 @@ type CreateApplicationTriggerRequest struct {
|
||||
Registry string `json:"registry,omitempty" optional:"true"`
|
||||
}
|
||||
|
||||
// UpdateApplicationTriggerRequest update application trigger
|
||||
type UpdateApplicationTriggerRequest struct {
|
||||
Alias string `json:"alias" validate:"checkalias" optional:"true"`
|
||||
Description string `json:"description" optional:"true"`
|
||||
WorkflowName string `json:"workflowName"`
|
||||
PayloadType string `json:"payloadType" validate:"checkpayloadtype"`
|
||||
ComponentName string `json:"componentName,omitempty" optional:"true"`
|
||||
Registry string `json:"registry,omitempty" optional:"true"`
|
||||
}
|
||||
|
||||
// ApplicationTriggerBase application trigger base model
|
||||
type ApplicationTriggerBase struct {
|
||||
Name string `json:"name"`
|
||||
@@ -522,6 +532,7 @@ type ApplicationTriggerBase struct {
|
||||
PayloadType string `json:"payloadType"`
|
||||
Token string `json:"token"`
|
||||
ComponentName string `json:"componentName,omitempty"`
|
||||
Registry string `json:"registry"`
|
||||
CreateTime time.Time `json:"createTime"`
|
||||
UpdateTime time.Time `json:"updateTime"`
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ func (n *pipeline) GetWebServiceRoute() *restful.WebService {
|
||||
Doc("list pipelines").
|
||||
Param(ws.QueryParameter("query", "Fuzzy search based on name or description").DataType("string")).
|
||||
Param(ws.QueryParameter("projectName", "query pipelines within a project").DataType("string")).
|
||||
Param(ws.QueryParameter("detailed", "query pipelines with detail").DataType("bool").DefaultValue("true")).
|
||||
Param(ws.QueryParameter("detailed", "query pipelines with detail").DataType("boolean").DefaultValue("true")).
|
||||
Returns(200, "OK", apis.ListPipelineResponse{}).
|
||||
Returns(400, "Bad Request", bcode.Bcode{}).
|
||||
Writes(apis.ListPipelineResponse{}).Do(meta))
|
||||
|
||||
@@ -69,9 +69,19 @@ func (h repository) GetWebServiceRoute() *restful.WebService {
|
||||
Writes([]string{}))
|
||||
|
||||
// List available chart versions
|
||||
ws.Route(ws.GET("/charts/{chart}/versions").To(h.listVersions).
|
||||
ws.Route(ws.GET("/chart/versions").To(h.listVersionsFromQuery).
|
||||
Doc("list versions").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Param(ws.QueryParameter("chart", "helm chart").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("repoUrl", "helm repository url").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("secretName", "secret of the repo").DataType("string")).
|
||||
Returns(200, "OK", v1.ChartVersionListResponse{}).
|
||||
Returns(400, "Bad Request", bcode.Bcode{}).
|
||||
Writes([]string{}))
|
||||
|
||||
ws.Route(ws.GET("/charts/{chart}/versions").To(h.listChartVersions).
|
||||
Doc("list versions").Deprecate().
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Param(ws.QueryParameter("repoUrl", "helm repository url").DataType("string")).
|
||||
Param(ws.QueryParameter("secretName", "secret of the repo").DataType("string")).
|
||||
Returns(200, "OK", v1.ChartVersionListResponse{}).
|
||||
@@ -79,14 +89,26 @@ func (h repository) GetWebServiceRoute() *restful.WebService {
|
||||
Writes([]string{}))
|
||||
|
||||
// List available chart versions
|
||||
ws.Route(ws.GET("/charts/{chart}/versions/{version}/values").To(h.chartValues).
|
||||
ws.Route(ws.GET("/chart/values").To(h.chartValues).
|
||||
Doc("get chart value").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Param(ws.QueryParameter("chart", "helm chart").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("version", "helm chart version").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("repoUrl", "helm repository url").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("repoType", "helm repository type").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("secretName", "secret of the repo").DataType("string")).
|
||||
Returns(200, "OK", "").
|
||||
Returns(400, "Bad Request", bcode.Bcode{}).
|
||||
Writes(map[string]string{}))
|
||||
|
||||
ws.Route(ws.GET("/charts/{chart}/versions/{version}/values").To(h.getChartValues).
|
||||
Doc("get chart value").Deprecate().
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Param(ws.QueryParameter("repoUrl", "helm repository url").DataType("string")).
|
||||
Param(ws.QueryParameter("secretName", "secret of the repo").DataType("string")).
|
||||
Returns(200, "OK", map[string]interface{}{}).
|
||||
Returns(400, "Bad Request", bcode.Bcode{}).
|
||||
Writes([]string{}))
|
||||
Writes(map[string]interface{}{}))
|
||||
|
||||
ws.Route(ws.GET("/image/repos").To(h.getImageRepos).
|
||||
Doc("get the oci repos").
|
||||
@@ -132,9 +154,9 @@ func (h repository) listCharts(req *restful.Request, res *restful.Response) {
|
||||
}
|
||||
}
|
||||
|
||||
func (h repository) listVersions(req *restful.Request, res *restful.Response) {
|
||||
func (h repository) listVersionsFromQuery(req *restful.Request, res *restful.Response) {
|
||||
url := req.QueryParameter("repoUrl")
|
||||
chartName := req.PathParameter("chart")
|
||||
chartName := req.QueryParameter("chart")
|
||||
secName := req.QueryParameter("secretName")
|
||||
skipCache, err := isSkipCache(req)
|
||||
if err != nil {
|
||||
@@ -154,7 +176,7 @@ func (h repository) listVersions(req *restful.Request, res *restful.Response) {
|
||||
}
|
||||
}
|
||||
|
||||
func (h repository) chartValues(req *restful.Request, res *restful.Response) {
|
||||
func (h repository) getChartValues(req *restful.Request, res *restful.Response) {
|
||||
url := req.QueryParameter("repoUrl")
|
||||
secName := req.QueryParameter("secretName")
|
||||
chartName := req.PathParameter("chart")
|
||||
@@ -165,12 +187,57 @@ func (h repository) chartValues(req *restful.Request, res *restful.Response) {
|
||||
return
|
||||
}
|
||||
|
||||
versions, err := h.HelmService.GetChartValues(req.Request.Context(), url, chartName, version, secName, skipCache)
|
||||
values, err := h.HelmService.GetChartValues(req.Request.Context(), url, chartName, version, secName, "helm", skipCache)
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
err = res.WriteEntity(versions)
|
||||
err = res.WriteEntity(values)
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (h repository) listChartVersions(req *restful.Request, res *restful.Response) {
|
||||
url := req.QueryParameter("repoUrl")
|
||||
chartName := req.PathParameter("chart")
|
||||
secName := req.QueryParameter("secretName")
|
||||
skipCache, err := isSkipCache(req)
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, bcode.ErrSkipCacheParameter)
|
||||
return
|
||||
}
|
||||
versions, err := h.HelmService.ListChartVersions(req.Request.Context(), url, chartName, secName, skipCache)
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
err = res.WriteEntity(v1.ChartVersionListResponse{Versions: versions})
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (h repository) chartValues(req *restful.Request, res *restful.Response) {
|
||||
url := req.QueryParameter("repoUrl")
|
||||
secName := req.QueryParameter("secretName")
|
||||
chartName := req.QueryParameter("chart")
|
||||
version := req.QueryParameter("version")
|
||||
repoType := req.QueryParameter("repoType")
|
||||
skipCache, err := isSkipCache(req)
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, bcode.ErrSkipCacheParameter)
|
||||
return
|
||||
}
|
||||
|
||||
values, err := h.HelmService.ListChartValuesFiles(req.Request.Context(), url, chartName, version, secName, repoType, skipCache)
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
err = res.WriteEntity(values)
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
|
||||
@@ -23,21 +23,21 @@ var (
|
||||
// ErrNoConfigOrTarget means there is no target or config when creating the distribution.
|
||||
ErrNoConfigOrTarget = NewBcode(400, 16002, "you must specify the config name and destination to distribute")
|
||||
|
||||
// ErrConfigExist means the config is exist
|
||||
ErrConfigExist = NewBcode(400, 16003, "the config name is exist")
|
||||
// ErrConfigExist means the config does exist
|
||||
ErrConfigExist = NewBcode(400, 16003, "the config name does exist")
|
||||
|
||||
// ErrChangeTemplate the template of the config can not be change
|
||||
ErrChangeTemplate = NewBcode(400, 16004, "the template of the config can not be change")
|
||||
// ErrChangeTemplate the template of the config can not be changed
|
||||
ErrChangeTemplate = NewBcode(400, 16004, "the template of the config can not be changed")
|
||||
|
||||
// ErrTemplateNotFound means the template is not exist
|
||||
ErrTemplateNotFound = NewBcode(404, 16005, "the template is not exist")
|
||||
// ErrTemplateNotFound means the template does not exist
|
||||
ErrTemplateNotFound = NewBcode(404, 16005, "the template does not exist")
|
||||
|
||||
// ErrConfigNotFound means the config is not exist
|
||||
ErrConfigNotFound = NewBcode(404, 16006, "the config is not exist")
|
||||
// ErrConfigNotFound means the config does not exist
|
||||
ErrConfigNotFound = NewBcode(404, 16006, "the config does not exist")
|
||||
|
||||
// ErrNotFoundDistribution means the distribution is not exist
|
||||
ErrNotFoundDistribution = NewBcode(404, 16007, "the distribution is not exist")
|
||||
// ErrNotFoundDistribution means the distribution does not exist
|
||||
ErrNotFoundDistribution = NewBcode(404, 16007, "the distribution does not exist")
|
||||
|
||||
// ErrChangeSecretType the secret type of the config can not be change
|
||||
ErrChangeSecretType = NewBcode(400, 16008, "the secret type of the config can not be change")
|
||||
// ErrChangeSecretType the secret type of the config can not be changed
|
||||
ErrChangeSecretType = NewBcode(400, 16008, "the secret type of the config can not be changed")
|
||||
)
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
|
||||
"github.com/kubevela/workflow/pkg/cue/process"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
velaprocess "github.com/oam-dev/kubevela/pkg/cue/process"
|
||||
)
|
||||
@@ -32,7 +33,7 @@ func (p *Parser) ValidateCUESchematicAppfile(a *Appfile) error {
|
||||
for _, wl := range a.Workloads {
|
||||
// because helm & kube schematic has no CUE template
|
||||
// it only validates CUE schematic workload
|
||||
if wl.CapabilityCategory != types.CUECategory {
|
||||
if wl.CapabilityCategory != types.CUECategory || wl.Type == v1alpha1.RefObjectsComponentType {
|
||||
continue
|
||||
}
|
||||
ctxData := GenerateContextDataFromAppFile(a, wl.Name)
|
||||
|
||||
@@ -76,23 +76,23 @@ var ErrSensitiveConfig = errors.New("the config is sensitive")
|
||||
// ErrNoConfigOrTarget means the config or the target is empty.
|
||||
var ErrNoConfigOrTarget = errors.New("you must specify the config name and destination to distribute")
|
||||
|
||||
// ErrNotFoundDistribution means the app of the distribution is not exist.
|
||||
var ErrNotFoundDistribution = errors.New("the distribution is not found")
|
||||
// ErrNotFoundDistribution means the app of the distribution does not exist.
|
||||
var ErrNotFoundDistribution = errors.New("the distribution does not found")
|
||||
|
||||
// ErrConfigExist means the config is exist.
|
||||
var ErrConfigExist = errors.New("the config is exist")
|
||||
// ErrConfigExist means the config does exist.
|
||||
var ErrConfigExist = errors.New("the config does exist")
|
||||
|
||||
// ErrConfigNotFound means the config is not exist
|
||||
var ErrConfigNotFound = errors.New("the config is not exist")
|
||||
// ErrConfigNotFound means the config does not exist
|
||||
var ErrConfigNotFound = errors.New("the config does not exist")
|
||||
|
||||
// ErrTemplateNotFound means the template is not exist
|
||||
var ErrTemplateNotFound = errors.New("the template is not exist")
|
||||
// ErrTemplateNotFound means the template does not exist
|
||||
var ErrTemplateNotFound = errors.New("the template does not exist")
|
||||
|
||||
// ErrChangeTemplate means the template of the config can not be change
|
||||
var ErrChangeTemplate = errors.New("the template of the config can not be change")
|
||||
// ErrChangeTemplate means the template of the config can not be changed
|
||||
var ErrChangeTemplate = errors.New("the template of the config can not be changed")
|
||||
|
||||
// ErrChangeSecretType means the secret type of the config can not be change
|
||||
var ErrChangeSecretType = errors.New("the secret type of the config can not be change")
|
||||
// ErrChangeSecretType means the secret type of the config can not be changed
|
||||
var ErrChangeSecretType = errors.New("the secret type of the config can not be changed")
|
||||
|
||||
// NamespacedName the namespace and name model
|
||||
type NamespacedName struct {
|
||||
@@ -206,14 +206,37 @@ type Factory interface {
|
||||
MergeDistributionStatus(ctx context.Context, config *Config, namespace string) error
|
||||
}
|
||||
|
||||
// Dispatcher is a client for apply resources.
|
||||
type Dispatcher func(context.Context, []*unstructured.Unstructured, []apply.ApplyOption) error
|
||||
|
||||
// NewConfigFactory create a config factory instance
|
||||
func NewConfigFactory(cli client.Client) Factory {
|
||||
return &kubeConfigFactory{cli: cli, apiApply: apply.NewAPIApplicator(cli)}
|
||||
return &kubeConfigFactory{cli: cli, apiApply: defaultDispatcher(cli)}
|
||||
}
|
||||
|
||||
// NewConfigFactoryWithDispatcher create a config factory instance with a specified dispatcher
|
||||
func NewConfigFactoryWithDispatcher(cli client.Client, ds Dispatcher) Factory {
|
||||
if ds == nil {
|
||||
ds = defaultDispatcher(cli)
|
||||
}
|
||||
return &kubeConfigFactory{cli: cli, apiApply: ds}
|
||||
}
|
||||
|
||||
func defaultDispatcher(cli client.Client) Dispatcher {
|
||||
api := apply.NewAPIApplicator(cli)
|
||||
return func(ctx context.Context, manifests []*unstructured.Unstructured, ao []apply.ApplyOption) error {
|
||||
for _, m := range manifests {
|
||||
if err := api.Apply(ctx, m, ao...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
type kubeConfigFactory struct {
|
||||
cli client.Client
|
||||
apiApply *apply.APIApplicator
|
||||
apiApply Dispatcher
|
||||
}
|
||||
|
||||
// ParseTemplate parse a config template instance form the cue script
|
||||
@@ -307,7 +330,14 @@ func (k *kubeConfigFactory) CreateOrUpdateConfigTemplate(ctx context.Context, ns
|
||||
if ns != "" {
|
||||
it.ConfigMap.Namespace = ns
|
||||
}
|
||||
return k.apiApply.Apply(ctx, it.ConfigMap, apply.DisableUpdateAnnotation(), apply.Quiet())
|
||||
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(it.ConfigMap)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fail to convert configmap to unstructured: %w", err)
|
||||
}
|
||||
us := &unstructured.Unstructured{Object: obj}
|
||||
us.SetAPIVersion("v1")
|
||||
us.SetKind("ConfigMap")
|
||||
return k.apiApply(ctx, []*unstructured.Unstructured{us}, []apply.ApplyOption{apply.DisableUpdateAnnotation(), apply.Quiet()})
|
||||
}
|
||||
|
||||
func convertConfigMap2Template(cm v1.ConfigMap) (*Template, error) {
|
||||
@@ -562,11 +592,20 @@ func (k *kubeConfigFactory) CreateOrUpdateConfig(ctx context.Context, i *Config,
|
||||
return ErrChangeSecretType
|
||||
}
|
||||
}
|
||||
if err := k.apiApply.Apply(ctx, i.Secret, apply.Quiet()); err != nil {
|
||||
|
||||
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(i.Secret)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fail to convert secret to unstructured: %w", err)
|
||||
}
|
||||
us := &unstructured.Unstructured{Object: obj}
|
||||
us.SetAPIVersion("v1")
|
||||
us.SetKind("Secret")
|
||||
|
||||
if err := k.apiApply(ctx, []*unstructured.Unstructured{us}, []apply.ApplyOption{apply.DisableUpdateAnnotation(), apply.Quiet()}); err != nil {
|
||||
return fmt.Errorf("fail to apply the secret: %w", err)
|
||||
}
|
||||
for key, obj := range i.OutputObjects {
|
||||
if err := k.apiApply.Apply(ctx, obj, apply.Quiet()); err != nil {
|
||||
if err := k.apiApply(ctx, []*unstructured.Unstructured{obj}, []apply.ApplyOption{apply.DisableUpdateAnnotation(), apply.Quiet()}); err != nil {
|
||||
return fmt.Errorf("fail to apply the object %s: %w", key, err)
|
||||
}
|
||||
}
|
||||
@@ -768,7 +807,15 @@ func (k *kubeConfigFactory) CreateOrUpdateDistribution(ctx context.Context, ns,
|
||||
Policies: policies,
|
||||
},
|
||||
}
|
||||
return k.apiApply.Apply(ctx, distribution, apply.Quiet())
|
||||
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(distribution)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fail to convert application to unstructured: %w", err)
|
||||
}
|
||||
us := &unstructured.Unstructured{Object: obj}
|
||||
us.SetAPIVersion(v1beta1.SchemeGroupVersion.String())
|
||||
us.SetKind(v1beta1.ApplicationKind)
|
||||
|
||||
return k.apiApply(ctx, []*unstructured.Unstructured{us}, []apply.ApplyOption{apply.DisableUpdateAnnotation(), apply.Quiet()})
|
||||
}
|
||||
|
||||
func (k *kubeConfigFactory) ListDistributions(ctx context.Context, ns string) ([]*Distribution, error) {
|
||||
|
||||
147
pkg/config/provider/provider.go
Normal file
147
pkg/config/provider/provider.go
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
Copyright 2023 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 provider
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
monitorContext "github.com/kubevela/pkg/monitor/context"
|
||||
wfContext "github.com/kubevela/workflow/pkg/context"
|
||||
"github.com/kubevela/workflow/pkg/cue/model/value"
|
||||
"github.com/kubevela/workflow/pkg/types"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/config"
|
||||
)
|
||||
|
||||
const (
|
||||
// ProviderName is provider name
|
||||
ProviderName = "config"
|
||||
)
|
||||
|
||||
// ErrRequestInvalid means the request is invalid
|
||||
var ErrRequestInvalid = errors.New("the request is in valid")
|
||||
|
||||
type provider struct {
|
||||
factory config.Factory
|
||||
}
|
||||
|
||||
// CreateConfigProperties the request body for creating a config
|
||||
type CreateConfigProperties struct {
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
Template string `json:"template,omitempty"`
|
||||
Config map[string]interface{} `json:"config"`
|
||||
}
|
||||
|
||||
// Response the response body
|
||||
type Response struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (p *provider) Create(ctx monitorContext.Context, wfCtx wfContext.Context, v *value.Value, act types.Action) error {
|
||||
var ccp CreateConfigProperties
|
||||
if err := v.UnmarshalTo(&ccp); err != nil {
|
||||
return ErrRequestInvalid
|
||||
}
|
||||
name := ccp.Template
|
||||
namespace := "vela-system"
|
||||
if strings.Contains(ccp.Template, "/") {
|
||||
namespacedName := strings.SplitN(ccp.Template, "/", 2)
|
||||
namespace = namespacedName[0]
|
||||
name = namespacedName[1]
|
||||
}
|
||||
configItem, err := p.factory.ParseConfig(ctx.GetContext(), config.NamespacedName{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
}, config.Metadata{
|
||||
NamespacedName: config.NamespacedName{
|
||||
Name: ccp.Name,
|
||||
Namespace: ccp.Namespace,
|
||||
},
|
||||
Properties: ccp.Config,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.factory.CreateOrUpdateConfig(ctx.GetContext(), configItem, ccp.Namespace)
|
||||
}
|
||||
|
||||
func (p *provider) Read(ctx monitorContext.Context, wfCtx wfContext.Context, v *value.Value, act types.Action) error {
|
||||
var nn config.NamespacedName
|
||||
if err := v.UnmarshalTo(&nn); err != nil {
|
||||
return ErrRequestInvalid
|
||||
}
|
||||
content, err := p.factory.ReadConfig(ctx.GetContext(), nn.Namespace, nn.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return v.FillObject(content, "config")
|
||||
}
|
||||
|
||||
func (p *provider) List(ctx monitorContext.Context, wfCtx wfContext.Context, v *value.Value, act types.Action) error {
|
||||
template, err := v.GetString("template")
|
||||
if err != nil {
|
||||
return ErrRequestInvalid
|
||||
}
|
||||
namespace, err := v.GetString("namespace")
|
||||
if err != nil {
|
||||
return ErrRequestInvalid
|
||||
}
|
||||
if strings.Contains(template, "/") {
|
||||
namespacedName := strings.SplitN(template, "/", 2)
|
||||
template = namespacedName[1]
|
||||
}
|
||||
configs, err := p.factory.ListConfigs(ctx.GetContext(), namespace, template, "", false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var contents = []map[string]interface{}{}
|
||||
for _, config := range configs {
|
||||
contents = append(contents, map[string]interface{}{
|
||||
"name": config.Name,
|
||||
"alias": config.Alias,
|
||||
"description": config.Description,
|
||||
"config": config.Properties,
|
||||
})
|
||||
}
|
||||
return v.FillObject(contents, "configs")
|
||||
}
|
||||
|
||||
func (p *provider) Delete(ctx monitorContext.Context, wfCtx wfContext.Context, v *value.Value, act types.Action) error {
|
||||
var nn config.NamespacedName
|
||||
if err := v.UnmarshalTo(&nn); err != nil {
|
||||
return errors.New("the request is in valid")
|
||||
}
|
||||
return p.factory.DeleteConfig(ctx.GetContext(), nn.Namespace, nn.Name)
|
||||
}
|
||||
|
||||
// Install register handlers to provider discover.
|
||||
func Install(p types.Providers, cli client.Client, apply config.Dispatcher) {
|
||||
prd := &provider{
|
||||
factory: config.NewConfigFactoryWithDispatcher(cli, apply),
|
||||
}
|
||||
p.Register(ProviderName, map[string]types.Handler{
|
||||
"create": prd.Create,
|
||||
"read": prd.Read,
|
||||
"list": prd.List,
|
||||
"delete": prd.Delete,
|
||||
})
|
||||
}
|
||||
237
pkg/config/provider/provider_test.go
Normal file
237
pkg/config/provider/provider_test.go
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
Copyright 2023 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 provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
monitorContext "github.com/kubevela/pkg/monitor/context"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/utils/pointer"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
|
||||
wfContext "github.com/kubevela/workflow/pkg/context"
|
||||
"github.com/kubevela/workflow/pkg/cue/model/value"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/config"
|
||||
)
|
||||
|
||||
var cfg *rest.Config
|
||||
var k8sClient client.Client
|
||||
var testEnv *envtest.Environment
|
||||
var scheme = runtime.NewScheme()
|
||||
var p *provider
|
||||
|
||||
func TestProvider(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
|
||||
RunSpecs(t, "Test Config Suite")
|
||||
}
|
||||
|
||||
var _ = BeforeSuite(func(done Done) {
|
||||
By("Bootstrapping test environment")
|
||||
testEnv = &envtest.Environment{
|
||||
ControlPlaneStartTimeout: time.Minute,
|
||||
ControlPlaneStopTimeout: time.Minute,
|
||||
UseExistingCluster: pointer.BoolPtr(false),
|
||||
}
|
||||
var err error
|
||||
cfg, err = testEnv.Start()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(cfg).ToNot(BeNil())
|
||||
Expect(clientgoscheme.AddToScheme(scheme)).Should(BeNil())
|
||||
// +kubebuilder:scaffold:scheme
|
||||
By("Create the k8s client")
|
||||
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(k8sClient).ToNot(BeNil())
|
||||
|
||||
p = &provider{
|
||||
factory: config.NewConfigFactory(k8sClient),
|
||||
}
|
||||
close(done)
|
||||
}, 120)
|
||||
|
||||
var _ = AfterSuite(func() {
|
||||
By("Tearing down the test environment")
|
||||
err := testEnv.Stop()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
var _ = Describe("Test the config provider", func() {
|
||||
|
||||
It("test creating a config", func() {
|
||||
mCtx := monitorContext.NewTraceContext(context.Background(), "")
|
||||
v, err := value.NewValue(`
|
||||
name: "hub-kubevela"
|
||||
namespace: "default"
|
||||
template: "default/test-image-registry"
|
||||
config: {
|
||||
registry: "hub.kubevela.net"
|
||||
}
|
||||
`, nil, "")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = p.Create(mCtx, new(wfContext.WorkflowContext), v, nil)
|
||||
Expect(strings.Contains(err.Error(), "the template does not exist")).Should(BeTrue())
|
||||
|
||||
template, err := p.factory.ParseTemplate("test-image-registry", []byte(templateContent))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(p.factory.CreateOrUpdateConfigTemplate(context.TODO(), "default", template)).ToNot(HaveOccurred())
|
||||
|
||||
Expect(p.Create(mCtx, new(wfContext.WorkflowContext), v, nil)).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("test creating a config without the template", func() {
|
||||
mCtx := monitorContext.NewTraceContext(context.Background(), "")
|
||||
v, err := value.NewValue(`
|
||||
name: "www-kubevela"
|
||||
namespace: "default"
|
||||
config: {
|
||||
url: "kubevela.net"
|
||||
}
|
||||
`, nil, "")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(p.Create(mCtx, new(wfContext.WorkflowContext), v, nil)).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("test listing the config", func() {
|
||||
mCtx := monitorContext.NewTraceContext(context.Background(), "")
|
||||
v, err := value.NewValue(`
|
||||
namespace: "default"
|
||||
template: "test-image-registry"
|
||||
`, nil, "")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(p.List(mCtx, new(wfContext.WorkflowContext), v, nil)).ToNot(HaveOccurred())
|
||||
configs, err := v.LookupValue("configs")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
var contents []map[string]interface{}
|
||||
Expect(configs.UnmarshalTo(&contents)).ToNot(HaveOccurred())
|
||||
Expect(len(contents)).To(Equal(1))
|
||||
Expect(contents[0]["config"].(map[string]interface{})["registry"]).To(Equal("hub.kubevela.net"))
|
||||
})
|
||||
|
||||
It("test reading the config", func() {
|
||||
mCtx := monitorContext.NewTraceContext(context.Background(), "")
|
||||
v, err := value.NewValue(`
|
||||
name: "hub-kubevela"
|
||||
namespace: "default"
|
||||
`, nil, "")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(p.Read(mCtx, new(wfContext.WorkflowContext), v, nil)).ToNot(HaveOccurred())
|
||||
registry, err := v.GetString("config", "registry")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(registry).To(Equal("hub.kubevela.net"))
|
||||
})
|
||||
|
||||
It("test deleting the config", func() {
|
||||
mCtx := monitorContext.NewTraceContext(context.Background(), "")
|
||||
v, err := value.NewValue(`
|
||||
name: "hub-kubevela"
|
||||
namespace: "default"
|
||||
`, nil, "")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(p.Delete(mCtx, new(wfContext.WorkflowContext), v, nil)).ToNot(HaveOccurred())
|
||||
|
||||
configs, err := p.factory.ListConfigs(context.Background(), "default", "", "", false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(configs)).To(Equal(1))
|
||||
Expect(configs[0].Properties["url"]).To(Equal("kubevela.net"))
|
||||
})
|
||||
})
|
||||
|
||||
var templateContent = `
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
metadata: {
|
||||
name: "image-registry"
|
||||
alias: "Image Registry"
|
||||
scope: "project"
|
||||
description: "Config information to authenticate image registry"
|
||||
sensitive: false
|
||||
}
|
||||
|
||||
template: {
|
||||
output: {
|
||||
apiVersion: "v1"
|
||||
kind: "Secret"
|
||||
metadata: {
|
||||
name: context.name
|
||||
namespace: context.namespace
|
||||
labels: {
|
||||
"config.oam.dev/catalog": "velacore-config"
|
||||
"config.oam.dev/type": "image-registry"
|
||||
}
|
||||
}
|
||||
if parameter.auth != _|_ {
|
||||
type: "kubernetes.io/dockerconfigjson"
|
||||
}
|
||||
if parameter.auth == _|_ {
|
||||
type: "Opaque"
|
||||
}
|
||||
stringData: {
|
||||
if parameter.auth != _|_ && parameter.auth.username != _|_ {
|
||||
".dockerconfigjson": json.Marshal({
|
||||
"auths": (parameter.registry): {
|
||||
"username": parameter.auth.username
|
||||
"password": parameter.auth.password
|
||||
if parameter.auth.email != _|_ {
|
||||
"email": parameter.auth.email
|
||||
}
|
||||
"auth": base64.Encode(null, (parameter.auth.username + ":" + parameter.auth.password))
|
||||
}
|
||||
})
|
||||
}
|
||||
if parameter.insecure != _|_ {
|
||||
"insecure-skip-verify": strconv.FormatBool(parameter.insecure)
|
||||
}
|
||||
if parameter.useHTTP != _|_ {
|
||||
"protocol-use-http": strconv.FormatBool(parameter.useHTTP)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parameter: {
|
||||
// +usage=Image registry FQDN, such as: index.docker.io
|
||||
registry: *"index.docker.io" | string
|
||||
// +usage=Authenticate the image registry
|
||||
auth?: {
|
||||
// +usage=Private Image registry username
|
||||
username: string
|
||||
// +usage=Private Image registry password
|
||||
password: string
|
||||
// +usage=Private Image registry email
|
||||
email?: string
|
||||
}
|
||||
// +usage=For the registry server that uses the self-signed certificate
|
||||
insecure?: bool
|
||||
// +usage=For the registry server that uses the HTTP protocol
|
||||
useHTTP?: bool
|
||||
}
|
||||
}
|
||||
`
|
||||
@@ -25,7 +25,9 @@ import (
|
||||
pkgmulticluster "github.com/kubevela/pkg/multicluster"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
|
||||
configprovider "github.com/oam-dev/kubevela/pkg/config/provider"
|
||||
"github.com/oam-dev/kubevela/pkg/features"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/apply"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/meta"
|
||||
"github.com/pkg/errors"
|
||||
@@ -86,15 +88,21 @@ func (h *AppHandler) GenerateApplicationSteps(ctx monitorContext.Context,
|
||||
af *appfile.Appfile,
|
||||
appRev *v1beta1.ApplicationRevision) (*wfTypes.WorkflowInstance, []wfTypes.TaskRunner, error) {
|
||||
|
||||
appLabels := map[string]string{
|
||||
oam.LabelAppName: app.Name,
|
||||
oam.LabelAppNamespace: app.Namespace,
|
||||
}
|
||||
handlerProviders := providers.NewProviders()
|
||||
kube.Install(handlerProviders, h.r.Client,
|
||||
map[string]string{
|
||||
oam.LabelAppName: app.Name,
|
||||
oam.LabelAppNamespace: app.Namespace,
|
||||
}, &kube.Handlers{
|
||||
Apply: h.Dispatch,
|
||||
Delete: h.Delete,
|
||||
})
|
||||
kube.Install(handlerProviders, h.r.Client, appLabels, &kube.Handlers{
|
||||
Apply: h.Dispatch,
|
||||
Delete: h.Delete,
|
||||
})
|
||||
configprovider.Install(handlerProviders, h.r.Client, func(ctx context.Context, resources []*unstructured.Unstructured, applyOptions []apply.ApplyOption) error {
|
||||
for _, res := range resources {
|
||||
res.SetLabels(util.MergeMapOverrideWithDst(res.GetLabels(), appLabels))
|
||||
}
|
||||
return h.resourceKeeper.Dispatch(ctx, resources, applyOptions)
|
||||
})
|
||||
oamProvider.Install(handlerProviders, app, af, h.r.Client, h.applyComponentFunc(
|
||||
appParser, appRev, af), h.renderComponentFunc(appParser, appRev, af))
|
||||
pCtx := velaprocess.NewContext(generateContextDataFromApp(app, appRev.Name))
|
||||
|
||||
@@ -121,8 +121,8 @@ func loggingApply(msg string, desired client.Object, quiet bool) {
|
||||
klog.InfoS(msg, "name", d.GetName(), "resource", desired.GetObjectKind().GroupVersionKind().String())
|
||||
}
|
||||
|
||||
// filterRecordForSpecial will filter special object that can reduce the record for "app.oam.dev/last-applied-configuration" annotation.
|
||||
func filterRecordForSpecial(desired client.Object) bool {
|
||||
// trimLastAppliedConfigurationForSpecialResources will filter special object that can reduce the record for "app.oam.dev/last-applied-configuration" annotation.
|
||||
func trimLastAppliedConfigurationForSpecialResources(desired client.Object) bool {
|
||||
if desired == nil {
|
||||
return false
|
||||
}
|
||||
@@ -159,7 +159,7 @@ func (a *APIApplicator) Apply(ctx context.Context, desired client.Object, ao ...
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
applyAct := &applyAction{updateAnnotation: filterRecordForSpecial(desired)}
|
||||
applyAct := &applyAction{updateAnnotation: trimLastAppliedConfigurationForSpecialResources(desired)}
|
||||
existing, err := a.createOrGetExisting(ctx, applyAct, a.c, desired, ao...)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -574,15 +574,15 @@ func TestFilterSpecialAnn(t *testing.T) {
|
||||
var sc = &corev1.Secret{}
|
||||
var dp = &appsv1.Deployment{}
|
||||
var crd = &v1.CustomResourceDefinition{}
|
||||
assert.Equal(t, false, filterRecordForSpecial(cm))
|
||||
assert.Equal(t, false, filterRecordForSpecial(sc))
|
||||
assert.Equal(t, false, filterRecordForSpecial(crd))
|
||||
assert.Equal(t, true, filterRecordForSpecial(dp))
|
||||
assert.Equal(t, false, trimLastAppliedConfigurationForSpecialResources(cm))
|
||||
assert.Equal(t, false, trimLastAppliedConfigurationForSpecialResources(sc))
|
||||
assert.Equal(t, false, trimLastAppliedConfigurationForSpecialResources(crd))
|
||||
assert.Equal(t, true, trimLastAppliedConfigurationForSpecialResources(dp))
|
||||
|
||||
dp.Annotations = map[string]string{oam.AnnotationLastAppliedConfig: "-"}
|
||||
assert.Equal(t, false, filterRecordForSpecial(dp))
|
||||
assert.Equal(t, false, trimLastAppliedConfigurationForSpecialResources(dp))
|
||||
dp.Annotations = map[string]string{oam.AnnotationLastAppliedConfig: "skip"}
|
||||
assert.Equal(t, false, filterRecordForSpecial(dp))
|
||||
assert.Equal(t, false, trimLastAppliedConfigurationForSpecialResources(dp))
|
||||
dp.Annotations = map[string]string{oam.AnnotationLastAppliedConfig: "xxx"}
|
||||
assert.Equal(t, true, filterRecordForSpecial(dp))
|
||||
assert.Equal(t, true, trimLastAppliedConfigurationForSpecialResources(dp))
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ func getOriginalConfiguration(obj runtime.Object) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
original, ok := annots[oam.AnnotationLastAppliedConfig]
|
||||
if !ok {
|
||||
if !ok || original == "-" || original == "skip" {
|
||||
return nil, nil
|
||||
}
|
||||
return []byte(original), nil
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -32,6 +33,9 @@ import (
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
"helm.sh/helm/v3/pkg/chartutil"
|
||||
"helm.sh/helm/v3/pkg/cli"
|
||||
"helm.sh/helm/v3/pkg/downloader"
|
||||
"helm.sh/helm/v3/pkg/getter"
|
||||
"helm.sh/helm/v3/pkg/kube"
|
||||
"helm.sh/helm/v3/pkg/release"
|
||||
relutil "helm.sh/helm/v3/pkg/releaseutil"
|
||||
@@ -56,6 +60,12 @@ const (
|
||||
valuesPatten = "repoUrl: %s, chart: %s, version: %s"
|
||||
)
|
||||
|
||||
// ChartValues contain all values files in chart and default chart values
|
||||
type ChartValues struct {
|
||||
Data map[string]string
|
||||
Values map[string]interface{}
|
||||
}
|
||||
|
||||
// Helper provides helper functions for common Helm operations
|
||||
type Helper struct {
|
||||
cache *utils2.MemoryCacheStore
|
||||
@@ -309,12 +319,22 @@ func (h *Helper) ListChartsFromRepo(repoURL string, skipCache bool, opts *common
|
||||
}
|
||||
|
||||
// GetValuesFromChart will extract the parameter from a helm chart
|
||||
func (h *Helper) GetValuesFromChart(repoURL string, chartName string, version string, skipCache bool, opts *common.HTTPOption) (map[string]interface{}, error) {
|
||||
func (h *Helper) GetValuesFromChart(repoURL string, chartName string, version string, skipCache bool, repoType string, opts *common.HTTPOption) (*ChartValues, error) {
|
||||
if h.cache != nil && !skipCache {
|
||||
if v := h.cache.Get(fmt.Sprintf(valuesPatten, repoURL, chartName, version)); v != nil {
|
||||
return v.(map[string]interface{}), nil
|
||||
return v.(*ChartValues), nil
|
||||
}
|
||||
}
|
||||
if repoType == "oci" {
|
||||
v, err := fetchChartValuesFromOciRepo(repoURL, chartName, version, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if h.cache != nil {
|
||||
h.cache.Put(fmt.Sprintf(valuesPatten, repoURL, chartName, version), v, 20*time.Minute)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
i, err := h.GetIndexInfo(repoURL, skipCache, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -334,10 +354,17 @@ func (h *Helper) GetValuesFromChart(repoURL string, chartName string, version st
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if h.cache != nil {
|
||||
h.cache.Put(fmt.Sprintf(valuesPatten, repoURL, chartName, version), c.Values, calculateCacheTimeFromIndex(len(i.Entries)))
|
||||
v := &ChartValues{
|
||||
Data: loadValuesYamlFile(c),
|
||||
Values: c.Values,
|
||||
}
|
||||
return c.Values, nil
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if h.cache != nil {
|
||||
h.cache.Put(fmt.Sprintf(valuesPatten, repoURL, chartName, version), v, calculateCacheTimeFromIndex(len(i.Entries)))
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
return nil, fmt.Errorf("cannot load chart from chart repo")
|
||||
}
|
||||
@@ -351,3 +378,49 @@ func calculateCacheTimeFromIndex(length int) time.Duration {
|
||||
}
|
||||
return cacheTime
|
||||
}
|
||||
|
||||
// nolint
|
||||
func fetchChartValuesFromOciRepo(repoURL string, chartName string, version string, opts *common.HTTPOption) (*ChartValues, error) {
|
||||
d := downloader.ChartDownloader{
|
||||
Verify: downloader.VerifyNever,
|
||||
Getters: getter.All(cli.New()),
|
||||
}
|
||||
|
||||
if opts != nil {
|
||||
d.Options = append(d.Options, getter.WithInsecureSkipVerifyTLS(opts.InsecureSkipTLS),
|
||||
getter.WithTLSClientConfig(opts.CertFile, opts.KeyFile, opts.CaFile),
|
||||
getter.WithBasicAuth(opts.Username, opts.Password))
|
||||
}
|
||||
|
||||
var err error
|
||||
dest, err := os.MkdirTemp("", "helm-")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to fetch values file")
|
||||
}
|
||||
defer os.RemoveAll(dest)
|
||||
|
||||
chartRef := fmt.Sprintf("%s/%s", repoURL, chartName)
|
||||
saved, _, err := d.DownloadTo(chartRef, version, dest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c, err := loader.Load(saved)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to fetch values file")
|
||||
}
|
||||
return &ChartValues{
|
||||
Data: loadValuesYamlFile(c),
|
||||
Values: c.Values,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func loadValuesYamlFile(chart *chart.Chart) map[string]string {
|
||||
result := map[string]string{}
|
||||
re := regexp.MustCompile(`.*yaml$`)
|
||||
for _, f := range chart.Raw {
|
||||
if re.MatchString(f.Name) && !strings.Contains(f.Name, "/") && f.Name != "Chart.yaml" {
|
||||
result[f.Name] = string(f.Data)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -114,9 +114,9 @@ var _ = Describe("Test helm helper", func() {
|
||||
|
||||
It("Test getValues from chart", func() {
|
||||
helper := NewHelper()
|
||||
values, err := helper.GetValuesFromChart("./testdata", "autoscalertrait", "0.2.0", true, nil)
|
||||
values, err := helper.GetValuesFromChart("./testdata", "autoscalertrait", "0.2.0", true, "helm", nil)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(values).ShouldNot(BeEmpty())
|
||||
Expect(values).ShouldNot(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -92,12 +92,26 @@ func MergeNoConflictLabels(labels map[string]string) MutateOption {
|
||||
// CreateOrUpdateNamespace will create a namespace if not exist, it will also update a namespace if exists
|
||||
// It will report an error if the labels conflict while it will override the annotations
|
||||
func CreateOrUpdateNamespace(ctx context.Context, kubeClient client.Client, name string, options ...MutateOption) error {
|
||||
err := CreateNamespace(ctx, kubeClient, name, options...)
|
||||
// only if namespace don't have the env label that we need to update it
|
||||
if apierrors.IsAlreadyExists(err) {
|
||||
return UpdateNamespace(ctx, kubeClient, name, options...)
|
||||
ns, err := GetNamespace(ctx, kubeClient, name)
|
||||
switch {
|
||||
case err == nil:
|
||||
return PatchNamespace(ctx, kubeClient, ns, options...)
|
||||
case apierrors.IsNotFound(err):
|
||||
return CreateNamespace(ctx, kubeClient, name, options...)
|
||||
default:
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// PatchNamespace will patch a namespace
|
||||
func PatchNamespace(ctx context.Context, kubeClient client.Client, ns *corev1.Namespace, options ...MutateOption) error {
|
||||
original := ns.DeepCopy()
|
||||
for _, op := range options {
|
||||
if err := op(ns); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return kubeClient.Patch(ctx, ns, client.MergeFrom(original))
|
||||
}
|
||||
|
||||
// CreateNamespace will create a namespace with mutate option
|
||||
|
||||
@@ -167,7 +167,7 @@ func NewAddonEnableCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Com
|
||||
addonArgs[pkgaddon.InstallerRuntimeOption] = map[string]interface{}{
|
||||
"upgrade": false,
|
||||
}
|
||||
|
||||
var addonName string
|
||||
if file, err := os.Stat(addonOrDir); err == nil {
|
||||
if !file.IsDir() {
|
||||
return fmt.Errorf("%s is not addon dir", addonOrDir)
|
||||
@@ -178,13 +178,13 @@ func NewAddonEnableCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Com
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "directory %s is invalid", addonOrDir)
|
||||
}
|
||||
name = filepath.Base(abs)
|
||||
addonName = filepath.Base(abs)
|
||||
if !yes2all {
|
||||
if err := checkUninstallFromClusters(ctx, k8sClient, name, addonArgs); err != nil {
|
||||
if err := checkUninstallFromClusters(ctx, k8sClient, addonName, addonArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
additionalInfo, err = enableAddonByLocal(ctx, name, addonOrDir, k8sClient, dc, config, addonArgs)
|
||||
additionalInfo, err = enableAddonByLocal(ctx, addonName, addonOrDir, k8sClient, dc, config, addonArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -192,8 +192,12 @@ func NewAddonEnableCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Com
|
||||
if filepath.IsAbs(addonOrDir) || strings.HasPrefix(addonOrDir, ".") || strings.HasSuffix(addonOrDir, "/") {
|
||||
return fmt.Errorf("addon directory %s not found in local file system", addonOrDir)
|
||||
}
|
||||
_, addonName, err = splitSpecifyRegistry(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to split addonName and addonRegistry: %w", err)
|
||||
}
|
||||
if !yes2all {
|
||||
if err := checkUninstallFromClusters(ctx, k8sClient, name, addonArgs); err != nil {
|
||||
if err := checkUninstallFromClusters(ctx, k8sClient, addonName, addonArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -205,8 +209,8 @@ func NewAddonEnableCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Com
|
||||
if dryRun {
|
||||
return nil
|
||||
}
|
||||
fmt.Printf("Addon %s enabled successfully.\n", name)
|
||||
AdditionalEndpointPrinter(ctx, c, k8sClient, name, additionalInfo, false)
|
||||
fmt.Printf("Addon %s enabled successfully.\n", addonName)
|
||||
AdditionalEndpointPrinter(ctx, c, k8sClient, addonName, additionalInfo, false)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -52,6 +53,7 @@ import (
|
||||
velacmd "github.com/oam-dev/kubevela/pkg/cmd"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/cmd/util"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/apply"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/env"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
)
|
||||
|
||||
@@ -98,6 +100,7 @@ type AdoptOptions struct {
|
||||
|
||||
Apply bool
|
||||
Recycle bool
|
||||
Yes bool
|
||||
|
||||
AdoptTemplateFile string
|
||||
AdoptTemplate string
|
||||
@@ -133,6 +136,9 @@ func (opt *AdoptOptions) parseResourceRef(f velacmd.Factory, cmd *cobra.Command,
|
||||
or.Name = parts[1]
|
||||
if mapping.Scope.Name() == meta.RESTScopeNameNamespace {
|
||||
or.Namespace = velacmd.GetNamespace(f, cmd)
|
||||
if or.Namespace == "" {
|
||||
or.Namespace = env.DefaultEnvNamespace
|
||||
}
|
||||
}
|
||||
case 3:
|
||||
or.Namespace = parts[1]
|
||||
@@ -160,6 +166,9 @@ func (opt *AdoptOptions) Complete(f velacmd.Factory, cmd *cobra.Command, args []
|
||||
}) {
|
||||
opt.AppName = opt.NativeResourceRefs[0].Name
|
||||
}
|
||||
if opt.AppNamespace == "" {
|
||||
opt.AppNamespace = opt.NativeResourceRefs[0].Namespace
|
||||
}
|
||||
case adoptTypeHelm:
|
||||
if len(args) > 0 {
|
||||
opt.HelmReleaseName = args[0]
|
||||
@@ -188,6 +197,20 @@ func (opt *AdoptOptions) Complete(f velacmd.Factory, cmd *cobra.Command, args []
|
||||
} else {
|
||||
opt.AdoptTemplate = defaultAdoptTemplate
|
||||
}
|
||||
if opt.AppName != "" {
|
||||
var ctx = context.Background()
|
||||
app := &v1beta1.Application{}
|
||||
err := f.Client().Get(ctx, apitypes.NamespacedName{Namespace: opt.AppNamespace, Name: opt.AppName}, app)
|
||||
if err == nil && app != nil {
|
||||
if !opt.Yes {
|
||||
userInput := NewUserInput()
|
||||
confirm := userInput.AskBool("Application '%s' already exists, apply will override the existing app with the adopted one, please confirm [Y/n]: "+opt.AppName, &UserInputOptions{AssumeYes: false})
|
||||
if !confirm {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
opt.AdoptTemplateCUEValue = cuecontext.New().CompileString(fmt.Sprintf("%s\n\n%s: %s", opt.AdoptTemplate, adoptCUETempVal, adoptCUETempFunc))
|
||||
return nil
|
||||
}
|
||||
@@ -278,6 +301,12 @@ func (opt *AdoptOptions) render() (*v1beta1.Application, error) {
|
||||
if err = json.Unmarshal(bs, app); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse template $returns into application: %w", err)
|
||||
}
|
||||
if app.Name == "" {
|
||||
app.Name = opt.AppName
|
||||
}
|
||||
if app.Namespace == "" {
|
||||
app.Namespace = opt.AppNamespace
|
||||
}
|
||||
return app, nil
|
||||
}
|
||||
|
||||
@@ -450,6 +479,7 @@ func NewAdoptCommand(f velacmd.Factory, streams util.IOStreams) *cobra.Command {
|
||||
cmd.Flags().StringVarP(&o.HelmDriver, "driver", "d", o.HelmDriver, "The storage backend of helm adoption. Only take effect when --type=helm.")
|
||||
cmd.Flags().BoolVarP(&o.Apply, "apply", "", o.Apply, "If true, the application for adoption will be applied. Otherwise, it will only be printed.")
|
||||
cmd.Flags().BoolVarP(&o.Recycle, "recycle", "", o.Recycle, "If true, when the adoption application is successfully applied, the old storage (like Helm secret) will be recycled.")
|
||||
cmd.Flags().BoolVarP(&o.Yes, "yes", "y", o.Yes, "Skip confirmation prompt")
|
||||
return velacmd.NewCommandBuilder(f, cmd).
|
||||
WithNamespaceFlag().
|
||||
WithResponsiveWriter().
|
||||
|
||||
58
references/cli/adopt_test.go
Normal file
58
references/cli/adopt_test.go
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
Copyright 2021 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/config"
|
||||
|
||||
velacmd "github.com/oam-dev/kubevela/pkg/cmd"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
)
|
||||
|
||||
func TestDefaultNamespace(t *testing.T) {
|
||||
testcase := []struct {
|
||||
namespace string
|
||||
args []string
|
||||
}{
|
||||
{
|
||||
namespace: "kube-system",
|
||||
args: []string{"deployment/kube-system/metrics-server"},
|
||||
},
|
||||
{
|
||||
namespace: "default",
|
||||
args: []string{"deployment/metrics-server"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range testcase {
|
||||
opt := &AdoptOptions{
|
||||
Type: adoptTypeNative,
|
||||
Mode: adoptModeReadOnly,
|
||||
}
|
||||
f := velacmd.NewDeferredFactory(config.GetConfig)
|
||||
ioStream := util.IOStreams{}
|
||||
cmd := NewAdoptCommand(f, ioStream)
|
||||
err := opt.Complete(f, cmd, c.args)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse resourceRef: %v", err)
|
||||
}
|
||||
assert.Equal(t, opt.AppNamespace, c.namespace)
|
||||
}
|
||||
}
|
||||
@@ -307,7 +307,7 @@ func (opt *DeleteOptions) Run(f velacmd.Factory, cmd *cobra.Command) error {
|
||||
app := &v1beta1.Application{}
|
||||
if err := f.Client().Get(cmd.Context(), apitypes.NamespacedName{Namespace: opt.Namespace, Name: appName}, app); err != nil {
|
||||
if kerrors.IsNotFound(err) {
|
||||
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "application %s/%s already deleted", opt.Namespace, appName)
|
||||
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "application %s/%s already deleted\n", opt.Namespace, appName)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("failed to get application %s/%s: %w", opt.Namespace, appName, err)
|
||||
|
||||
@@ -19,7 +19,10 @@ package cli
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/klog/v2"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
@@ -50,6 +53,7 @@ func NewTopCommand(c common.Args, order string, ioStreams cmdutil.IOStreams) *co
|
||||
if AllNamespace {
|
||||
namespace = ""
|
||||
}
|
||||
klog.SetLogger(logr.New(log.NullLogSink{}))
|
||||
return launchUI(c, namespace)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
|
||||
@@ -34,9 +34,33 @@ import (
|
||||
var appName = "app-e2e"
|
||||
var appProject = "test-app-project"
|
||||
|
||||
func prepareEnv(envName string) {
|
||||
var targetName = testNSprefix + strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||
// create target
|
||||
var createTarget = apisv1.CreateTargetRequest{
|
||||
Name: targetName,
|
||||
Project: appProject,
|
||||
Cluster: &apisv1.ClusterTarget{
|
||||
ClusterName: "local",
|
||||
Namespace: targetName,
|
||||
},
|
||||
}
|
||||
res := post("/targets", createTarget)
|
||||
Expect(decodeResponseBody(res, nil)).Should(Succeed())
|
||||
|
||||
// create env
|
||||
var createEnvReq = apisv1.CreateEnvRequest{
|
||||
Name: envName,
|
||||
Targets: []string{targetName},
|
||||
}
|
||||
res = post("/envs", createEnvReq)
|
||||
Expect(decodeResponseBody(res, nil)).Should(Succeed())
|
||||
}
|
||||
|
||||
var _ = Describe("Test application rest api", func() {
|
||||
It("Test create app", func() {
|
||||
defer GinkgoRecover()
|
||||
prepareEnv("dev-env")
|
||||
var req = apisv1.CreateApplicationRequest{
|
||||
Name: appName,
|
||||
Project: appProject,
|
||||
@@ -58,7 +82,7 @@ var _ = Describe("Test application rest api", func() {
|
||||
Expect(cmp.Diff(appBase.Labels["test"], req.Labels["test"])).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("Test list components", func() {
|
||||
It("Test listing components", func() {
|
||||
defer GinkgoRecover()
|
||||
res := get("/applications/" + appName + "/components")
|
||||
var components apisv1.ComponentListResponse
|
||||
@@ -66,37 +90,42 @@ var _ = Describe("Test application rest api", func() {
|
||||
Expect(cmp.Diff(len(components.Components), 1)).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("Test updating a trigger", func() {
|
||||
defer GinkgoRecover()
|
||||
res := get("/applications/" + appName + "/triggers")
|
||||
var triggers apisv1.ListApplicationTriggerResponse
|
||||
Expect(decodeResponseBody(res, &triggers)).Should(Succeed())
|
||||
Expect(cmp.Diff(len(triggers.Triggers), 1)).Should(BeEmpty())
|
||||
|
||||
old := triggers.Triggers[0]
|
||||
var req = apisv1.UpdateApplicationTriggerRequest{
|
||||
Alias: "Update",
|
||||
Description: "Update the description",
|
||||
WorkflowName: old.WorkflowName,
|
||||
PayloadType: old.PayloadType,
|
||||
ComponentName: old.ComponentName,
|
||||
Registry: old.Registry,
|
||||
}
|
||||
res = put("/applications/"+appName+"/triggers/"+old.Token, req)
|
||||
var base apisv1.ApplicationTriggerBase
|
||||
Expect(decodeResponseBody(res, &base)).Should(Succeed())
|
||||
Expect(cmp.Diff(base.Alias, req.Alias)).Should(BeEmpty())
|
||||
Expect(cmp.Diff(base.Description, req.Description)).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("Test detail application", func() {
|
||||
defer GinkgoRecover()
|
||||
res := get("/applications/" + appName)
|
||||
var detail apisv1.DetailApplicationResponse
|
||||
Expect(decodeResponseBody(res, &detail)).Should(Succeed())
|
||||
Expect(cmp.Diff(len(detail.Policies), 0)).Should(BeEmpty())
|
||||
// The policy for the dev-env environment
|
||||
Expect(cmp.Diff(len(detail.Policies), 1)).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("Test deploy application", func() {
|
||||
defer GinkgoRecover()
|
||||
var targetName = testNSprefix + strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||
var envName = "dev"
|
||||
// create target
|
||||
var createTarget = apisv1.CreateTargetRequest{
|
||||
Name: targetName,
|
||||
Project: appProject,
|
||||
Cluster: &apisv1.ClusterTarget{
|
||||
ClusterName: "local",
|
||||
Namespace: targetName,
|
||||
},
|
||||
}
|
||||
res := post("/targets", createTarget)
|
||||
Expect(decodeResponseBody(res, nil)).Should(Succeed())
|
||||
|
||||
// create env
|
||||
var createEnvReq = apisv1.CreateEnvRequest{
|
||||
Name: envName,
|
||||
Targets: []string{targetName},
|
||||
}
|
||||
res = post("/envs", createEnvReq)
|
||||
Expect(decodeResponseBody(res, nil)).Should(Succeed())
|
||||
prepareEnv(envName)
|
||||
|
||||
// create envbinding
|
||||
var createEnvbindingReq = apisv1.CreateApplicationEnvbindingRequest{
|
||||
@@ -104,7 +133,7 @@ var _ = Describe("Test application rest api", func() {
|
||||
Name: envName,
|
||||
},
|
||||
}
|
||||
res = post("/applications/"+appName+"/envs", createEnvbindingReq)
|
||||
res := post("/applications/"+appName+"/envs", createEnvbindingReq)
|
||||
Expect(decodeResponseBody(res, nil)).Should(Succeed())
|
||||
|
||||
// deploy app
|
||||
|
||||
@@ -153,7 +153,7 @@ var _ = Describe("Test the rest api about the config", func() {
|
||||
Expect(config.Secret).Should(BeNil())
|
||||
Expect(config.Properties["registry"]).Should(Equal("kubevela.test.com"))
|
||||
|
||||
By("the config name is exist")
|
||||
By("the config name does exist")
|
||||
req = v1.CreateConfigRequest{
|
||||
Name: "test-registry",
|
||||
Alias: "Test Registry",
|
||||
@@ -164,7 +164,7 @@ var _ = Describe("Test the rest api about the config", func() {
|
||||
res = post("/configs", req)
|
||||
Expect(res.StatusCode).Should(Equal(400))
|
||||
|
||||
By("the template is not exist")
|
||||
By("the template does not exist")
|
||||
req = v1.CreateConfigRequest{
|
||||
Name: "test-registry2",
|
||||
Alias: "Test Registry",
|
||||
|
||||
42
test/e2e-apiserver-test/repository_test.go
Normal file
42
test/e2e-apiserver-test/repository_test.go
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
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 e2e_apiserver_test
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Helm rest api test", func() {
|
||||
|
||||
Describe("helm repo api test", func() {
|
||||
It("test fetching chart values in OCI registry", func() {
|
||||
resp := getWithQuery("/repository/chart/values", map[string]string{
|
||||
"repoUrl": "oci://ghcr.io",
|
||||
"chart": "stefanprodan/charts/podinfo",
|
||||
"repoType": "oci",
|
||||
"version": "6.1.0",
|
||||
})
|
||||
defer resp.Body.Close()
|
||||
values, err := io.ReadAll(resp.Body)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(values)).ShouldNot(BeEquivalentTo(0))
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -191,6 +191,26 @@ func get(path string) *http.Response {
|
||||
return response
|
||||
}
|
||||
|
||||
func getWithQuery(path string, params map[string]string) *http.Response {
|
||||
client := &http.Client{}
|
||||
if !strings.HasPrefix(path, "/v1") {
|
||||
path = baseURL + path
|
||||
} else {
|
||||
path = baseDomain + path
|
||||
}
|
||||
req, err := http.NewRequest(http.MethodGet, path, nil)
|
||||
Expect(err).Should(BeNil())
|
||||
req.Header.Add("Authorization", token)
|
||||
query := req.URL.Query()
|
||||
for k, v := range params {
|
||||
query.Set(k, v)
|
||||
}
|
||||
req.URL.RawQuery = query.Encode()
|
||||
response, err := client.Do(req)
|
||||
Expect(err).Should(BeNil())
|
||||
return response
|
||||
}
|
||||
|
||||
func delete(path string) *http.Response {
|
||||
client := &http.Client{}
|
||||
if !strings.HasPrefix(path, "/v1") {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
template: {
|
||||
#PolicyRule: {
|
||||
// +usage=Specify how to select the targets of the rule
|
||||
selector: [...#RuleSelector]
|
||||
selector: #RuleSelector
|
||||
}
|
||||
|
||||
#RuleSelector: {
|
||||
|
||||
@@ -64,7 +64,7 @@ template: {
|
||||
}
|
||||
}
|
||||
|
||||
parameter: *#PatchParams | close({
|
||||
parameter: #PatchParams | close({
|
||||
// +usage=Specify the container image for multiple containers
|
||||
containers: [...#PatchParams]
|
||||
})
|
||||
|
||||
@@ -18,7 +18,10 @@ expose: {
|
||||
}
|
||||
if service.spec.type == "LoadBalancer" {
|
||||
status: service.status
|
||||
isHealth: status != _|_ && status.loadBalancer != _|_ && status.loadBalancer.ingress != _|_ && len(status.loadBalancer.ingress) > 0
|
||||
isHealth: *false | bool
|
||||
if status != _|_ if status.loadBalancer != _|_ if status.loadBalancer.ingress != _|_ if len(status.loadBalancer.ingress) > 0 if status.loadBalancer.ingress[0].ip != _|_ {
|
||||
isHealth: true
|
||||
}
|
||||
if !isHealth {
|
||||
message: "ExternalIP: Pending"
|
||||
}
|
||||
@@ -28,11 +31,16 @@ expose: {
|
||||
}
|
||||
"""#
|
||||
healthPolicy: #"""
|
||||
isHealth: *true | bool
|
||||
service: context.outputs.service
|
||||
if service.spec.type == "LoadBalancer" {
|
||||
status: service.status
|
||||
isHealth: status != _|_ && status.loadBalancer != _|_ && status.loadBalancer.ingress != _|_ && len(status.loadBalancer.ingress) > 0
|
||||
isHealth: *false | bool
|
||||
if status != _|_ if status.loadBalancer != _|_ if status.loadBalancer.ingress != _|_ if len(status.loadBalancer.ingress) > 0 if status.loadBalancer.ingress[0].ip != _|_ {
|
||||
isHealth: true
|
||||
}
|
||||
}
|
||||
if service.spec.type != "LoadBalancer" {
|
||||
isHealth: true
|
||||
}
|
||||
"""#
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ template: {
|
||||
#ECProvider: {
|
||||
type: "ec"
|
||||
apiKey: *"" | string
|
||||
name: "ec-provider" | string
|
||||
name: *"ec-provider" | string
|
||||
}
|
||||
#GCPProvider: {
|
||||
credentials: string
|
||||
|
||||
@@ -51,44 +51,41 @@ template: {
|
||||
// +usage=Specify the message that you want to sent, refer to [dingtalk messaging](https://developers.dingtalk.com/document/robots/custom-robot-access/title-72m-8ag-pqw)
|
||||
message: {
|
||||
// +usage=Specify the message content of dingtalk notification
|
||||
text?: *null | close({
|
||||
text?: close({
|
||||
content: string
|
||||
})
|
||||
// +usage=msgType can be text, link, mardown, actionCard, feedCard
|
||||
msgtype: *"text" | "link" | "markdown" | "actionCard" | "feedCard"
|
||||
link?: *null | close({
|
||||
#link: {
|
||||
text?: string
|
||||
title?: string
|
||||
messageUrl?: string
|
||||
picUrl?: string
|
||||
})
|
||||
markdown?: *null | close({
|
||||
}
|
||||
|
||||
link?: #link
|
||||
markdown?: close({
|
||||
text: string
|
||||
title: string
|
||||
})
|
||||
at?: *null | close({
|
||||
atMobiles?: *null | [...string]
|
||||
isAtAll?: bool
|
||||
at?: close({
|
||||
atMobiles?: [...string]
|
||||
isAtAll?: bool
|
||||
})
|
||||
actionCard?: *null | close({
|
||||
actionCard?: close({
|
||||
text: string
|
||||
title: string
|
||||
hideAvatar: string
|
||||
btnOrientation: string
|
||||
singleTitle: string
|
||||
singleURL: string
|
||||
btns: *null | close([...*null | close({
|
||||
btns?: [...close({
|
||||
title: string
|
||||
actionURL: string
|
||||
})])
|
||||
})]
|
||||
})
|
||||
feedCard?: *null | close({
|
||||
links: *null | close([...*null | close({
|
||||
text?: string
|
||||
title?: string
|
||||
messageUrl?: string
|
||||
picUrl?: string
|
||||
})])
|
||||
feedCard?: close({
|
||||
links: [...#link]
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -109,11 +106,11 @@ template: {
|
||||
// +usage=Specify the message that you want to sent, refer to [slack messaging](https://api.slack.com/reference/messaging/payload)
|
||||
message: {
|
||||
// +usage=Specify the message text for slack notification
|
||||
text: string
|
||||
blocks?: *null | close([...block])
|
||||
attachments?: *null | close({
|
||||
blocks?: *null | close([...block])
|
||||
color?: string
|
||||
text: string
|
||||
blocks?: [...block]
|
||||
attachments?: close({
|
||||
blocks?: [...block]
|
||||
color?: string
|
||||
})
|
||||
thread_ts?: string
|
||||
// +usage=Specify the message text format in markdown for slack notification
|
||||
|
||||
Reference in New Issue
Block a user